From 1f42e4f5beb600c30dedfb067549b217c9ca9f75 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Thu, 2 Jun 2022 09:48:36 +0200 Subject: [PATCH 001/143] Add prototype for advection-diffusion elixir for TreeMesh2D --- .../dgmulti_2d/elixir_advection_diffusion.jl | 2 +- .../elixir_advection_diffusion.jl | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 examples/tree_2d_dgsem/elixir_advection_diffusion.jl diff --git a/examples/dgmulti_2d/elixir_advection_diffusion.jl b/examples/dgmulti_2d/elixir_advection_diffusion.jl index 21effda986e..1273e25859e 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion.jl @@ -5,7 +5,7 @@ dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial( volume_integral = VolumeIntegralWeakForm()) equations = LinearScalarAdvectionEquation2D(1.5, 1.0) -equations_parabolic = LaplaceDiffusion2D(5e-2, equations) +equations_parabolic = LaplaceDiffusion2D(5.0e-2, equations) initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVector(0.0) initial_condition = initial_condition_zero diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl new file mode 100644 index 00000000000..592cd8cf4c0 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -0,0 +1,86 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +advection_velocity = (1.5, 1.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +equations_parabolic = LaplaceDiffusion2D(5.0e-2, equations) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Define initial conditions +initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVector(0.0) +initial_condition = initial_condition_zero + +# BC types +boundary_condition_left = BoundaryConditionDirichlet((x, t, equations) -> SVector(1 + 0.1 * x[2])) +boundary_condition_zero = BoundaryConditionDirichlet((x, t, equations) -> SVector(0.0)) +boundary_condition_neumann_zero = BoundaryConditionNeumann((x, t, equations) -> SVector(0.0)) + +# define inviscid boundary conditions +boundary_conditions = ( + x_neg=boundary_condition_left, + y_neg=boundary_condition_zero, + y_pos=boundary_condition_do_nothing, + x_pos=boundary_condition_do_nothing, + ) + +# define viscous boundary conditions +boundary_conditions_parabolic = ( + x_neg=boundary_condition_left, + y_neg=boundary_condition_zero, + y_pos=boundary_condition_zero, + x_pos=boundary_condition_neumann_zero, + ) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, dg; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.0 +ode = semidiscretize(semi, (0.0, 1.5)); + +# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup +# and resets the timers +summary_callback = SummaryCallback() + +# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results +analysis_interval = 100 +# analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +# callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) +callbacks = CallbackSet(summary_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1e-6 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) + +# Print the timer summary +summary_callback() From 2cc327bfa5a688f06a1a98375642938470c2798f Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Jun 2022 16:27:00 +0200 Subject: [PATCH 002/143] Initial implementation of `calc_gradient!` for TreeMesh{2} --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 247 ++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 src/solvers/dgsem_tree/dg_2d_parabolic.jl diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl new file mode 100644 index 00000000000..79e49528be5 --- /dev/null +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -0,0 +1,247 @@ +# This file collects all methods that have been updated to work with parabolic systems of equations +# +# assumptions: parabolic terms are of the form div(f(u, grad(u))) and +# will be discretized first order form as follows: +# 1. compute grad(u) +# 2. compute f(u, grad(u)) +# 3. compute div(u) +# boundary conditions will be applied to both grad(u) and div(u). +function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + initial_condition, boundary_conditions, source_terms, + dg::DG, dg_parabolic, cache, cache_parabolic) + + # Reset du + @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) + + + @unpack u_transformed, u_grad, viscous_flux = cache_parabolic + @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, + equations_parabolic) + + calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, + boundary_conditions, dg, cache, cache_parabolic) + + calc_viscous_fluxes!(viscous_flux, u_transformed, u_grad, + mesh, equations_parabolic, dg, cache, cache_parabolic) + + calc_divergence!(du, u_transformed, t, viscous_flux, mesh, equations_parabolic, + boundary_conditions, dg, dg_parabolic, cache, cache_parabolic) + + return nothing + +end + + +function calc_gradient!(u_grad, u, t, + mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, + boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) + # Reset du + @trixi_timeit timer() "reset ∂u/∂t" begin + reset_du!(u_grad[1], dg, cache) + reset_du!(u_grad[2], dg, cache) + end + + # Calculate volume integral + @trixi_timeit timer() "volume integral" begin + @unpack derivative_dhat = dg.basis + @threaded for element in eachelement(dg, cache) + + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + + for ii in eachnode(dg) + multiply_add_to_node_vars!(u_grad[1], derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) + end + + for jj in eachnode(dg) + multiply_add_to_node_vars!(u_grad[2], derivative_dhat[jj, j], u_node, equations_parabolic, dg, i, jj, element) + end + end + end + end + + # Prolong solution to interfaces + @trixi_timeit timer() "prolong2interfaces" begin + @unpack interfaces = cache_parabolic + @unpack orientations = interfaces + + @threaded for interface in eachinterface(dg, cache) + left_element = interfaces.neighbor_ids[1, interface] + right_element = interfaces.neighbor_ids[2, interface] + + if orientations[interface] == 1 + # interface in x-direction + for j in eachnode(dg), v in eachvariable(equations) + interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] + end + else # if orientations[interface] == 2 + # interface in y-direction + for i in eachnode(dg), v in eachvariable(equations) + interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] + end + end + end + end + + # Calculate interface fluxes + @trixi_timeit timer() "interface flux" begin + @unpack surface_flux_values = cache_parabolic.elements + @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + + @threaded for interface in eachinterface(dg, cache_parabolic) + # Get neighboring elements + left_id = neighbor_ids[1, interface] + right_id = neighbor_ids[2, interface] + + # Determine interface direction with respect to elements: + # orientation = 1: left -> 2, right -> 1 + # orientation = 2: left -> 4, right -> 3 + left_direction = 2 * orientations[interface] + right_direction = 2 * orientations[interface] - 1 + + for i in eachnode(dg) + # Call pointwise Riemann solver + u_ll, u_rr = get_surface_node_vars(u, equations, dg, i, interface) + flux = 0.5 * (u_ll + u_rr) + + # Copy flux to left and right element storage + for v in eachvariable(equations) + surface_flux_values[v, i, left_direction, left_id] = flux[v] + surface_flux_values[v, i, right_direction, right_id] = flux[v] + end + end + end + end + + # Prolong solution to boundaries + @trixi_timeit timer() "prolong2boundaries" begin + @unpack boundaries = cache_parabolic + @unpack orientations, neighbor_sides = boundaries + + @threaded for boundary in eachboundary(dg, cache_parabolic) + element = boundaries.neighbor_ids[boundary] + + if orientations[boundary] == 1 + # boundary in x-direction + if neighbor_sides[boundary] == 1 + # element in -x direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] + end + else # Element in +x direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[2, v, l, boundary] = u[v, 1, l, element] + end + end + else # if orientations[boundary] == 2 + # boundary in y-direction + if neighbor_sides[boundary] == 1 + # element in -y direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] + end + else + # element in +y direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[2, v, l, boundary] = u[v, l, 1, element] + end + end + end + end + end + + # Calculate boundary fluxes + @trixi_timeit timer() "boundary flux" begin + @assert boundary_conditions_parabolic == boundary_conditions_periodic + end + + # Prolong solution to mortars + # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( + # cache, u, mesh, equations, dg.mortar, dg.surface_integral, dg) + + # Calculate mortar fluxes + # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( + # cache.elements.surface_flux_values, mesh, + # have_nonconservative_terms(equations), equations, + # dg.mortar, dg.surface_integral, dg, cache) + + # Calculate surface integrals + @trixi_timeit timer() "surface integral" begin + @unpack boundary_interpolation = dg.basis + @unpack surface_flux_values = cache_parabolic.elements + + # Note that all fluxes have been computed with outward-pointing normal vectors. + # Access the factors only once before beginning the loop to increase performance. + # We also use explicit assignments instead of `+=` to let `@muladd` turn these + # into FMAs (see comment at the top of the file). + factor_1 = boundary_interpolation[1, 1] + factor_2 = boundary_interpolation[nnodes(dg), 2] + @threaded for element in eachelement(dg, cache) + for l in eachnode(dg) + for v in eachvariable(equations) + let du = u_grad[1] + # surface at -x + du[v, 1, l, element] = ( + du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) + + # surface at +x + du[v, nnodes(dg), l, element] = ( + du[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) + end + + let du = u_grad[2] + # surface at -y + du[v, l, 1, element] = ( + du[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) + + # surface at +y + du[v, l, nnodes(dg), element] = ( + du[v, l, nnodes(dg), element] + surface_flux_values[v, l, 4, element] * factor_2) + end + end + end + end + end + + # Apply Jacobian from mapping to reference element + @trixi_timeit timer() "Jacobian" begin + apply_jacobian!(u_grad[1], mesh, equations_parabolic, dg, cache_parabolic) + apply_jacobian!(u_grad[2], mesh, equations_parabolic, dg, cache_parabolic) + end + + return nothing +end + + +# This method is called when a SemidiscretizationHyperbolic is constructed. +# It constructs the basic `cache` used throughout the simulation to compute +# the RHS etc. +function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, + dg::DG, dg_parabolic, RealT, uEltype) + # Get cells for which an element needs to be created (i.e. all leaf cells) + leaf_cell_ids = local_leaf_cells(mesh.tree) + + elements = init_elements(leaf_cell_ids, mesh, equations_parabolic, dg.basis, RealT, uEltype) + + n_vars = nvariables(equations_parabolic) + n_nodes = nnodes(elements) + n_elements = nelements(elements) + u_grad = ntuple(_ -> Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements), ndims(mesh)) + + interfaces = init_interfaces(leaf_cell_ids, mesh, elements) + + boundaries = init_boundaries(leaf_cell_ids, mesh, elements) + + # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) + + # cache = (; elements, interfaces, boundaries, mortars) + cache = (; elements, interfaces, boundaries) + + # Add specialized parts of the cache required to compute the mortars etc. + # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) + + return cache +end From ed13d724830018be3f6347d6fe54289a976e3831 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Jun 2022 17:00:13 +0200 Subject: [PATCH 003/143] First complete implementation of the parabolic rhs operator for TreeMesh --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 278 +++++++++++++++++++++- 1 file changed, 272 insertions(+), 6 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 79e49528be5..d2f884d2bac 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -18,17 +18,265 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, equations_parabolic) - calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, - boundary_conditions, dg, cache, cache_parabolic) + @trixi_timeit timer() "calculate gradient" calc_gradient!(u_grad, u_transformed, t, mesh, + equations_parabolic, + boundary_conditions, dg, + cache, cache_parabolic) + + # TODO: Do not misuse u_grad to store fluxes? + @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(u_grad, u_transformed, + mesh, equations_parabolic, + dg, cache, cache_parabolic) + + @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, u_grad, mesh, + equations_parabolic, + boundary_conditions, dg, + dg_parabolic, cache, + cache_parabolic) - calc_viscous_fluxes!(viscous_flux, u_transformed, u_grad, - mesh, equations_parabolic, dg, cache, cache_parabolic) + return nothing + +end + + +function calc_divergence!(du, u, t, viscous_flux, + mesh::TreeMesh{2}, equations_parabolic, + boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) + # Reset du + @trixi_timeit timer() "reset ∂u/∂t" begin + reset_du!(du, dg, cache) + end - calc_divergence!(du, u_transformed, t, viscous_flux, mesh, equations_parabolic, - boundary_conditions, dg, dg_parabolic, cache, cache_parabolic) + # Calculate volume integral + @trixi_timeit timer() "volume integral" begin + @unpack derivative_dhat = dg.basis + @threaded for element in eachelement(dg, cache) + + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + flux_1_node = get_node_vars(viscous_flux[1], equations_parabolic, dg, i, j, element) + flux_2_node = get_node_vars(viscous_flux[2], equations_parabolic, dg, i, j, element) + + for ii in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[ii, i], flux_1_node, equations_parabolic, dg, ii, j, element) + end + + for jj in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[jj, j], flux_2_node, equations_parabolic, dg, i, jj, element) + end + end + end + end + + # Prolong solution to interfaces + @trixi_timeit timer() "prolong2interfaces" begin + @unpack interfaces = cache_parabolic + @unpack orientations = interfaces + + @threaded for interface in eachinterface(dg, cache) + left_element = interfaces.neighbor_ids[1, interface] + right_element = interfaces.neighbor_ids[2, interface] + + if orientations[interface] == 1 + # TODO Make this cleaner (remove the let) + let u = viscous_flux[1] + # interface in x-direction + for j in eachnode(dg), v in eachvariable(equations) + interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] + end + end + else # if orientations[interface] == 2 + # TODO Make this cleaner (remove the let) + let u = viscous_flux[2] + # interface in y-direction + for i in eachnode(dg), v in eachvariable(equations) + interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] + end + end + end + end + end + + # Calculate interface fluxes + @trixi_timeit timer() "interface flux" begin + @unpack surface_flux_values = cache_parabolic.elements + @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + + @threaded for interface in eachinterface(dg, cache_parabolic) + # Get neighboring elements + left_id = neighbor_ids[1, interface] + right_id = neighbor_ids[2, interface] + + # Determine interface direction with respect to elements: + # orientation = 1: left -> 2, right -> 1 + # orientation = 2: left -> 4, right -> 3 + left_direction = 2 * orientations[interface] + right_direction = 2 * orientations[interface] - 1 + + for i in eachnode(dg) + # Call pointwise Riemann solver + u_ll, u_rr = get_surface_node_vars(u, equations, dg, i, interface) + flux = 0.5 * (u_ll + u_rr) + + # Copy flux to left and right element storage + for v in eachvariable(equations) + surface_flux_values[v, i, left_direction, left_id] = flux[v] + surface_flux_values[v, i, right_direction, right_id] = flux[v] + end + end + end + end + + # Prolong solution to boundaries + @trixi_timeit timer() "prolong2boundaries" begin + @unpack boundaries = cache_parabolic + @unpack orientations, neighbor_sides = boundaries + + @threaded for boundary in eachboundary(dg, cache_parabolic) + element = boundaries.neighbor_ids[boundary] + + if orientations[boundary] == 1 + # TODO Make this cleaner (remove the let) + let u = viscous_flux[1] + # boundary in x-direction + if neighbor_sides[boundary] == 1 + # element in -x direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] + end + else # Element in +x direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[2, v, l, boundary] = u[v, 1, l, element] + end + end + end + else # if orientations[boundary] == 2 + # TODO Make this cleaner (remove the let) + let u = viscous_flux[2] + # boundary in y-direction + if neighbor_sides[boundary] == 1 + # element in -y direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] + end + else + # element in +y direction of boundary + for l in eachnode(dg), v in eachvariable(equations) + boundaries.u[2, v, l, boundary] = u[v, l, 1, element] + end + end + end + end + end + end + + # Calculate boundary fluxes + @trixi_timeit timer() "boundary flux" begin + @assert boundary_conditions_parabolic == boundary_conditions_periodic + end + + # Prolong solution to mortars + # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( + # cache, u, mesh, equations, dg.mortar, dg.surface_integral, dg) + + # Calculate mortar fluxes + # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( + # cache.elements.surface_flux_values, mesh, + # have_nonconservative_terms(equations), equations, + # dg.mortar, dg.surface_integral, dg, cache) + + # Calculate surface integrals + @trixi_timeit timer() "surface integral" begin + @unpack boundary_interpolation = dg.basis + @unpack surface_flux_values = cache_parabolic.elements + + # Note that all fluxes have been computed with outward-pointing normal vectors. + # Access the factors only once before beginning the loop to increase performance. + # We also use explicit assignments instead of `+=` to let `@muladd` turn these + # into FMAs (see comment at the top of the file). + factor_1 = boundary_interpolation[1, 1] + factor_2 = boundary_interpolation[nnodes(dg), 2] + @threaded for element in eachelement(dg, cache) + for l in eachnode(dg) + for v in eachvariable(equations) + # surface at -x + du[v, 1, l, element] = ( + du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) + + # surface at +x + du[v, nnodes(dg), l, element] = ( + du[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) + + # surface at -y + du[v, l, 1, element] = ( + du[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) + + # surface at +y + du[v, l, nnodes(dg), element] = ( + du[v, l, nnodes(dg), element] + surface_flux_values[v, l, 4, element] * factor_2) + end + end + end + end + + # Apply Jacobian from mapping to reference element + @trixi_timeit timer() "Jacobian" begin + apply_jacobian!(du, mesh, equations_parabolic, dg, cache_parabolic) + end return nothing +end + +# This method is called when a SemidiscretizationHyperbolic is constructed. +# It constructs the basic `cache` used throughout the simulation to compute +# the RHS etc. +function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, + dg::DG, dg_parabolic, RealT, uEltype) + # Get cells for which an element needs to be created (i.e. all leaf cells) + leaf_cell_ids = local_leaf_cells(mesh.tree) + + elements = init_elements(leaf_cell_ids, mesh, equations_parabolic, dg.basis, RealT, uEltype) + + n_vars = nvariables(equations_parabolic) + n_nodes = nnodes(elements) + n_elements = nelements(elements) + u_grad = ntuple(_ -> Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements), ndims(mesh)) + + interfaces = init_interfaces(leaf_cell_ids, mesh, elements) + + boundaries = init_boundaries(leaf_cell_ids, mesh, elements) + + # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) + + # cache = (; elements, interfaces, boundaries, mortars) + cache = (; elements, interfaces, boundaries) + + # Add specialized parts of the cache required to compute the mortars etc. + # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) + + return cache +end + + +function calc_viscous_fluxes!(u_grad, u, u_grad, mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + dg::DG, cache, cache_parabolic) + @threaded for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + # Get solution and gradients + u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_grad_1_node = get_node_vars(u_grad[1], equations_parabolic, dg, i, j, element) + u_grad_2_node = get_node_vars(u_grad[2], equations_parabolic, dg, i, j, element) + + # Calculate viscous flux and store each component for later use + viscous_flux_node = flux(u_node, (u_grad_1_node, u_grad_2_node), equations_parabolic) + set_node_vars!(u_grad[1], viscous_flux_node[1], equations_parabolic, dg, i, j) + set_node_vars!(u_grad[2], viscous_flux_node[2], equations_parabolic, dg, i, j) + end + end end @@ -245,3 +493,21 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, return cache end + + +# Needed to *not* flip the sign of the inverse Jacobian +function apply_jacobian!(du, mesh::TreeMesh{2}, + equations::AbstractEquationsParabolic, dg::DG, cache) + + @threaded for element in eachelement(dg, cache) + factor = cache.elements.inverse_jacobian[element] + + for j in eachnode(dg), i in eachnode(dg) + for v in eachvariable(equations) + du[v, i, j, element] *= factor + end + end + end + + return nothing +end From f83374eea893c4338948fbe92f986496cd612403 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Jun 2022 17:35:54 +0200 Subject: [PATCH 004/143] Make it work --- src/solvers/dgsem_tree/dg.jl | 1 + src/solvers/dgsem_tree/dg_2d_parabolic.jl | 104 ++++++++-------------- 2 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/solvers/dgsem_tree/dg.jl b/src/solvers/dgsem_tree/dg.jl index 2b947e15944..0ffaec2eced 100644 --- a/src/solvers/dgsem_tree/dg.jl +++ b/src/solvers/dgsem_tree/dg.jl @@ -60,6 +60,7 @@ include("dg_1d.jl") # 2D DG implementation include("dg_2d.jl") include("dg_2d_parallel.jl") +include("dg_2d_parabolic.jl") # 3D DG implementation include("dg_3d.jl") diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index d2f884d2bac..01f0ead469f 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -14,7 +14,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - @unpack u_transformed, u_grad, viscous_flux = cache_parabolic + @unpack u_transformed, u_grad = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, equations_parabolic) @@ -28,7 +28,8 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra mesh, equations_parabolic, dg, cache, cache_parabolic) - @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, u_grad, mesh, + @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, u_grad, + mesh, equations_parabolic, boundary_conditions, dg, dg_parabolic, cache, @@ -41,7 +42,8 @@ end function calc_divergence!(du, u, t, viscous_flux, mesh::TreeMesh{2}, equations_parabolic, - boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) + boundary_conditions_parabolic, dg::DG, dg_parabolic, + cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" begin reset_du!(du, dg, cache) @@ -81,7 +83,7 @@ function calc_divergence!(du, u, t, viscous_flux, # TODO Make this cleaner (remove the let) let u = viscous_flux[1] # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations) + for j in eachnode(dg), v in eachvariable(equations_parabolic) interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] end @@ -90,7 +92,7 @@ function calc_divergence!(du, u, t, viscous_flux, # TODO Make this cleaner (remove the let) let u = viscous_flux[2] # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations) + for i in eachnode(dg), v in eachvariable(equations_parabolic) interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] end @@ -117,11 +119,11 @@ function calc_divergence!(du, u, t, viscous_flux, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations, dg, i, interface) + u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage - for v in eachvariable(equations) + for v in eachvariable(equations_parabolic) surface_flux_values[v, i, left_direction, left_id] = flux[v] surface_flux_values[v, i, right_direction, right_id] = flux[v] end @@ -143,11 +145,11 @@ function calc_divergence!(du, u, t, viscous_flux, # boundary in x-direction if neighbor_sides[boundary] == 1 # element in -x direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] end else # Element in +x direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[2, v, l, boundary] = u[v, 1, l, element] end end @@ -158,12 +160,12 @@ function calc_divergence!(du, u, t, viscous_flux, # boundary in y-direction if neighbor_sides[boundary] == 1 # element in -y direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] end else # element in +y direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[2, v, l, boundary] = u[v, l, 1, element] end end @@ -174,17 +176,17 @@ function calc_divergence!(du, u, t, viscous_flux, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_conditions_periodic + @assert boundary_conditions_parabolic == boundary_condition_periodic end # Prolong solution to mortars # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( - # cache, u, mesh, equations, dg.mortar, dg.surface_integral, dg) + # cache, u, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) # Calculate mortar fluxes # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( # cache.elements.surface_flux_values, mesh, - # have_nonconservative_terms(equations), equations, + # have_nonconservative_terms(equations_parabolic), equations_parabolic, # dg.mortar, dg.surface_integral, dg, cache) # Calculate surface integrals @@ -200,7 +202,7 @@ function calc_divergence!(du, u, t, viscous_flux, factor_2 = boundary_interpolation[nnodes(dg), 2] @threaded for element in eachelement(dg, cache) for l in eachnode(dg) - for v in eachvariable(equations) + for v in eachvariable(equations_parabolic) # surface at -x du[v, 1, l, element] = ( du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) @@ -230,51 +232,20 @@ function calc_divergence!(du, u, t, viscous_flux, end -# This method is called when a SemidiscretizationHyperbolic is constructed. -# It constructs the basic `cache` used throughout the simulation to compute -# the RHS etc. -function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, - dg::DG, dg_parabolic, RealT, uEltype) - # Get cells for which an element needs to be created (i.e. all leaf cells) - leaf_cell_ids = local_leaf_cells(mesh.tree) - - elements = init_elements(leaf_cell_ids, mesh, equations_parabolic, dg.basis, RealT, uEltype) - - n_vars = nvariables(equations_parabolic) - n_nodes = nnodes(elements) - n_elements = nelements(elements) - u_grad = ntuple(_ -> Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements), ndims(mesh)) - - interfaces = init_interfaces(leaf_cell_ids, mesh, elements) - - boundaries = init_boundaries(leaf_cell_ids, mesh, elements) - - # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) - - # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries) - - # Add specialized parts of the cache required to compute the mortars etc. - # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) - - return cache -end - - -function calc_viscous_fluxes!(u_grad, u, u_grad, mesh::TreeMesh{2}, +function calc_viscous_fluxes!(viscous_flux, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_grad_1_node = get_node_vars(u_grad[1], equations_parabolic, dg, i, j, element) - u_grad_2_node = get_node_vars(u_grad[2], equations_parabolic, dg, i, j, element) + u_grad_1_node = get_node_vars(viscous_flux[1], equations_parabolic, dg, i, j, element) + u_grad_2_node = get_node_vars(viscous_flux[2], equations_parabolic, dg, i, j, element) # Calculate viscous flux and store each component for later use viscous_flux_node = flux(u_node, (u_grad_1_node, u_grad_2_node), equations_parabolic) - set_node_vars!(u_grad[1], viscous_flux_node[1], equations_parabolic, dg, i, j) - set_node_vars!(u_grad[2], viscous_flux_node[2], equations_parabolic, dg, i, j) + set_node_vars!(viscous_flux[1], viscous_flux_node[1], equations_parabolic, dg, i, j, element) + set_node_vars!(viscous_flux[2], viscous_flux_node[2], equations_parabolic, dg, i, j, element) end end end @@ -320,13 +291,13 @@ function calc_gradient!(u_grad, u, t, if orientations[interface] == 1 # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations) + for j in eachnode(dg), v in eachvariable(equations_parabolic) interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] end else # if orientations[interface] == 2 # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations) + for i in eachnode(dg), v in eachvariable(equations_parabolic) interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] end @@ -352,11 +323,11 @@ function calc_gradient!(u_grad, u, t, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations, dg, i, interface) + u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage - for v in eachvariable(equations) + for v in eachvariable(equations_parabolic) surface_flux_values[v, i, left_direction, left_id] = flux[v] surface_flux_values[v, i, right_direction, right_id] = flux[v] end @@ -376,11 +347,11 @@ function calc_gradient!(u_grad, u, t, # boundary in x-direction if neighbor_sides[boundary] == 1 # element in -x direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] end else # Element in +x direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[2, v, l, boundary] = u[v, 1, l, element] end end @@ -388,12 +359,12 @@ function calc_gradient!(u_grad, u, t, # boundary in y-direction if neighbor_sides[boundary] == 1 # element in -y direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] end else # element in +y direction of boundary - for l in eachnode(dg), v in eachvariable(equations) + for l in eachnode(dg), v in eachvariable(equations_parabolic) boundaries.u[2, v, l, boundary] = u[v, l, 1, element] end end @@ -403,17 +374,17 @@ function calc_gradient!(u_grad, u, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_conditions_periodic + @assert boundary_conditions_parabolic == boundary_condition_periodic end # Prolong solution to mortars # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( - # cache, u, mesh, equations, dg.mortar, dg.surface_integral, dg) + # cache, u, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) # Calculate mortar fluxes # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( # cache.elements.surface_flux_values, mesh, - # have_nonconservative_terms(equations), equations, + # have_nonconservative_terms(equations_parabolic), equations_parabolic, # dg.mortar, dg.surface_integral, dg, cache) # Calculate surface integrals @@ -429,7 +400,7 @@ function calc_gradient!(u_grad, u, t, factor_2 = boundary_interpolation[nnodes(dg), 2] @threaded for element in eachelement(dg, cache) for l in eachnode(dg) - for v in eachvariable(equations) + for v in eachvariable(equations_parabolic) let du = u_grad[1] # surface at -x du[v, 1, l, element] = ( @@ -467,7 +438,7 @@ end # This method is called when a SemidiscretizationHyperbolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, +function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, dg_parabolic, RealT, uEltype) # Get cells for which an element needs to be created (i.e. all leaf cells) leaf_cell_ids = local_leaf_cells(mesh.tree) @@ -477,7 +448,8 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, n_vars = nvariables(equations_parabolic) n_nodes = nnodes(elements) n_elements = nelements(elements) - u_grad = ntuple(_ -> Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements), ndims(mesh)) + u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) + u_grad = ntuple(_ -> similar(u_transformed), ndims(mesh)) interfaces = init_interfaces(leaf_cell_ids, mesh, elements) @@ -486,7 +458,7 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic, # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries) + cache = (; elements, interfaces, boundaries, u_grad, u_transformed) # Add specialized parts of the cache required to compute the mortars etc. # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) From 12c59eb433e1f05d2579062d0a53d853e3488b7b Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Jun 2022 17:36:27 +0200 Subject: [PATCH 005/143] Add first elixir that works --- .../elixir_advection_diffusion.jl | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index 592cd8cf4c0..15a51c168f0 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -20,9 +20,25 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max=30_000) # set maximum capacity of tree data structure # Define initial conditions -initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVector(0.0) +initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVector(0.7) initial_condition = initial_condition_zero +function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + # @unpack nu = equation + nu = 5.0e-2 + c = 1.0 + A = 0.5 + L = 2 + f = 1/L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) +end +initial_condition = initial_condition_diffusive_convergence_test + # BC types boundary_condition_left = BoundaryConditionDirichlet((x, t, equations) -> SVector(1 + 0.1 * x[2])) boundary_condition_zero = BoundaryConditionDirichlet((x, t, equations) -> SVector(0.0)) @@ -43,11 +59,13 @@ boundary_conditions_parabolic = ( y_pos=boundary_condition_zero, x_pos=boundary_condition_neumann_zero, ) +boundary_conditions = boundary_condition_periodic +boundary_conditions_parabolic = boundary_condition_periodic # A semidiscretization collects data structures and functions for the spatial discretization semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), - initial_condition, dg; + initial_condition, solver; boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) @@ -55,8 +73,9 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.0 -ode = semidiscretize(semi, (0.0, 1.5)); +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan); # At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup # and resets the timers @@ -64,14 +83,14 @@ summary_callback = SummaryCallback() # The AnalysisCallback allows to analyse the solution in regular intervals and prints the results analysis_interval = 100 -# analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) # The AliveCallback prints short status information in regular intervals alive_callback = AliveCallback(analysis_interval=analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -# callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) -callbacks = CallbackSet(summary_callback, alive_callback) +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) +# callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### @@ -79,8 +98,10 @@ callbacks = CallbackSet(summary_callback, alive_callback) # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks time_int_tol = 1e-6 +# sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, +# save_everystep=false, callback=callbacks) sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, - save_everystep=false, callback=callbacks) + save_everystep=false, callback=callbacks, adaptive=false, dt=1.0e-3) # Print the timer summary summary_callback() From 03a1a60b40f2e702dccb2cd71ed00424c98ef0ca Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 3 Jun 2022 18:03:53 +0200 Subject: [PATCH 006/143] Clean up elixir --- .../elixir_advection_diffusion.jl | 36 ++++--------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index 15a51c168f0..1706d4d4184 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -6,6 +6,7 @@ using Trixi advection_velocity = (1.5, 1.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) +# Note: If you change the diffusion parameter here, also change it in the initial condition equations_parabolic = LaplaceDiffusion2D(5.0e-2, equations) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -17,12 +18,11 @@ coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) # Create a uniformly refined mesh with periodic boundaries mesh = TreeMesh(coordinates_min, coordinates_max, initial_refinement_level=4, + periodicity=true, n_cells_max=30_000) # set maximum capacity of tree data structure -# Define initial conditions -initial_condition_zero(x, t, equations::LinearScalarAdvectionEquation2D) = SVector(0.7) -initial_condition = initial_condition_zero - +# Define initial condition +# Note: If you change the diffusion parameter here, also change it in the parabolic equation definition function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) # Store translated coordinate for easy use of exact solution x_trans = x - equation.advection_velocity * t @@ -39,26 +39,7 @@ function initial_condition_diffusive_convergence_test(x, t, equation::LinearScal end initial_condition = initial_condition_diffusive_convergence_test -# BC types -boundary_condition_left = BoundaryConditionDirichlet((x, t, equations) -> SVector(1 + 0.1 * x[2])) -boundary_condition_zero = BoundaryConditionDirichlet((x, t, equations) -> SVector(0.0)) -boundary_condition_neumann_zero = BoundaryConditionNeumann((x, t, equations) -> SVector(0.0)) - -# define inviscid boundary conditions -boundary_conditions = ( - x_neg=boundary_condition_left, - y_neg=boundary_condition_zero, - y_pos=boundary_condition_do_nothing, - x_pos=boundary_condition_do_nothing, - ) - -# define viscous boundary conditions -boundary_conditions_parabolic = ( - x_neg=boundary_condition_left, - y_neg=boundary_condition_zero, - y_pos=boundary_condition_zero, - x_pos=boundary_condition_neumann_zero, - ) +# define periodic boundary conditions everywhere boundary_conditions = boundary_condition_periodic boundary_conditions_parabolic = boundary_condition_periodic @@ -90,18 +71,15 @@ alive_callback = AliveCallback(analysis_interval=analysis_interval) # Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) -# callbacks = CallbackSet(summary_callback, alive_callback) ############################################################################### # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1e-6 -# sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, -# save_everystep=false, callback=callbacks) +time_int_tol = 1.0e-8 sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, - save_everystep=false, callback=callbacks, adaptive=false, dt=1.0e-3) + save_everystep=false, callback=callbacks) # Print the timer summary summary_callback() From 60cce54c37a1adfae896acb89ba3c254f78f5580 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 7 Jun 2022 21:02:19 +0200 Subject: [PATCH 007/143] first draft of container for Navier-Stokes constants and fluxes --- .../compressible_navier_stokes_2d.jl | 228 ++++++++++++++++++ src/equations/equations_parabolic.jl | 4 + 2 files changed, 232 insertions(+) create mode 100644 src/equations/compressible_navier_stokes_2d.jl diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl new file mode 100644 index 00000000000..cf8a8b17fc7 --- /dev/null +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -0,0 +1,228 @@ +@doc raw""" + CompressibleNaiverStokes2D(gamma, + Re, + Pr, + Ma_inf, + kappa, + equations) + +`CompressibleNaiverStokes2D` represents the diffusion (i.e. parabolic) terms applied +to mass, momenta, and total energy together with the advective from +the `CompressibleEulerEquations2D`. + +gamma: adiabatic constant, +Re: Reynolds number, +Pr: Prandtl number, +Ma_inf: free-stream Mach number +kappa: thermal diffusivity for Fick's law + +For the particular scaling the vicosity is set internally to be μ = 1/Re. +Further, the nondimensionalization takes the density-temperature-sound speed as +the principle quantities such that +rho_inf = 1.0 +T_ref = 1.0 +c_inf = 1.0 +p_inf = 1.0 / gamma +u_inf = Ma_inf +R = 1.0 / gamma + +Other normalization strategies exist, see the reference below for details. +- Marc Montagnac (2013) + Variable Normalization (nondimensionalization and scaling) for Navier-Stokes + equations: a practical guide + [CERFACS Technical report](https://www.cerfacs.fr/~montagna/TR-CFD-13-77.pdf) +The scaling used herein is Section 4.5 of the reference. + +In two spatial dimensions we require gradients for three quantities, e.g., +primitive quantities + grad(u), grad(v), and grad(T) +or the entropy variables + grad(w_2), grad(w_3), grad(w_4) +where + w_2 = rho v_1 / p, w_3 = rho v_2 / p, w_4 = -rho / p +""" +# TODO: +# 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from +# the Euler equations +# 2) Add more here and probably some equations +struct CompressibleNaiverStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} + gamma::RealT # ratio of specific heats + inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications + Re::RealT # Reynolds number + Pr::RealT # Prandtl number + Ma_inf::RealT # free-stream Mach number + kappa::RealT # thermal diffusivity for Fick's law + + p_inf::RealT # free-stream pressure + u_inf::RealT # free-stream velocity + R::RealT # gas constant (depends on nondimensional scaling!) + + equations::E # CompressibleEulerEquations2D +end + +function CompressibleNaiverStokes2D(gamma, Reynolds, Prandtl, Mach_frestream, kappa, equations) + γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) + + # From the nondimensionalization discussed above set the remaining free-stream + # quantities + p_inf = 1.0 / γ + u_inf = Mach_frestream + R = 1.0 / γ + CompressibleNaiverStokes2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, + Reynolds, Prandtl, Mach_freestream, + kappa, p_inf, u_inf, R, + equations) +end + +# I was not sure what to do here to allow flexibility of selecting primitive or entropy +# grandient variables +varnames(variable_mapping, equations_parabolic::CompressibleNaiverStokes2D) = + varnames(variable_mapping, equations_parabolic.equations) + + +# no orientation specified since the flux is vector-valued +# This form of the difussive Navier-Stokes fluxes is taken from Section 2 +# of the paper by Svärd, Carpenter and Nordström +# "A stable high-order finite difference scheme for the compressible Navier–Stokes +# equations, far-field boundary conditions" +# Note, could be generalized to use Sutherland's law to get the molecular and thermal +# diffusivity +function flux(u, grad_u, equations::CompressibleNaiverStokes2D) + # Here grad_u is assumed to contain the gradients of the primitive variables (v1,v2,T) + # either computed directly or reverse engineered from the gradient of the entropy vairables + # by way of the `convert_gradient_variables` function + rho, rho_v1, rho_v2, _ = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + T = temperature(u, equations) + + # I was not sure what shape this array has or or if it was a tuple + # or how to properly "unpack" it. So I just guessed... + dv1dx, dv1dy, dv2dx, dv2dy, dTdx, dTdy = grad_u + + # Components of viscous stress tensor + + # (4/3*(v1)_x - 2/3*(v2)_y) + tau_xx = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) + # ((v1)_y + (v2)_x) + tau_xy = ( dv1dy + dv2dx ) + tau_yx = tau_xy + # (4/3*(v2)_y - 2/3*(v1)_x) + tau_yy = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) + + # Fick's law q = -kappa*grad(T); constant is kappa*gamma/(Pr*(gamma-1)) + # Important note! Due to nondimensional scaling R = 1/gamma, so the + # temperature T in the gradient computation already contains a factor of gamma + q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr + q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr + + # viscous flux components in the x-direction + f1 = zero(rho) + f2 = tau_xx / equations.Re + f3 = tau_xy / equations.Re + f4 = ( v1 * tau_xx + v2 * tau_xy + q1) / equations.Re + + # viscous flux components in y-direction + g1 = zero(rho) + g2 = tau_yx / equations.Re + g3 = tau_yy / equations.Re + g4 = ( v1 * tau_yx + v2 * tau_yy + q2) / equations.Re + + # TODO: I was not sure how to return this properly. Right now it is a vector of vectors + return SVector( SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4) ) +end + + +# Convert conservative variables to primitive +@inline function cons2prim(u, equations::CompressibleNaiverStokes2D) + rho, rho_v1, rho_v2, _ = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + T = temperature(u, equations) + + return SVector(v1, v2, T) +end + + +# Convert conservative variables to entropy +@inline function cons2entropy(u, equations::CompressibleNaiverStokes2D) + rho, rho_v1, rho_v2, rho_e = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v_square = v1^2 + v2^2 + p = (equations.gamma - 1) * (rho_e - 0.5 * rho * v_square) + + rho_p = rho / p + + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = -rho_p + + return SVector(w2, w3, w4) +end + + +@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNaiverStokes2D) +# Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and +# reverse engineers the gradients to be terms of the primitive vairables (u, v, T). +# Helpful because then the diffusive fluxes have the same form as on paper. + rho, rho_v1, rho_v2, _ = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + T = temperature(u, equations) + + return SVector(equations.R * T * (grad_entropy_vars(1) + v1 * grad_entropy_vars(3)), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) + equations.R * T * (grad_entropy_vars(2) + v2 * grad_entropy_vars(3)), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) + equations.R * T * T * grad_entropy_vars(3) # grad(T) = R*T^2*grad(w_4)) + ) +end + + +@inline function temperature(u, equations::CompressibleNaiverStokes2D) + rho, rho_v1, rho_v2, rho_e = u + + p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2) / rho) + T = p / (equations.R * rho) + return T +end + + +# +# All this boundary conditions stuff I did not touch +# + +# TODO: should this remain in the equations file, be moved to solvers, or live in the elixir? +# The penalization depends on the solver, but also depends explicitly on physical parameters, +# and would probably need to be specialized for every different equation. +# function penalty(u_outer, u_inner, inv_h, equations::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) +# return dg.penalty_parameter * (u_outer - u_inner) * equations.diffusivity * inv_h +# end + +# # Dirichlet-type boundary condition for use with a parabolic solver in weak form +# @inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +# x, t, operator_type::Gradient, +# equations::LaplaceDiffusion2D) +# return boundary_condition.boundary_value_function(x, t, equations) +# end + +# @inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +# x, t, operator_type::Divergence, +# equations::LaplaceDiffusion2D) +# return u_inner +# end + +# @inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +# x, t, operator_type::Divergence, +# equations::LaplaceDiffusion2D) +# return boundary_condition.boundary_normal_flux_function(x, t, equations) +# end + +# @inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +# x, t, operator_type::Gradient, +# equations::LaplaceDiffusion2D) +# return flux_inner +# end diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index fec0eed6f63..df5f7077ad1 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -1,3 +1,7 @@ # Linear scalar diffusion for use in linear scalar advection-diffusion problems abstract type AbstractLaplaceDiffusionEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("laplace_diffusion_2d.jl") + +# Compressible Navier-Stokes equations +abstract type AbstractCompressibleNavierStokesEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end +include("compressible_navier_stokes_2d.jl") From 46ae5fb558fa96acc6a0cec1e4356ec60b765034 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 7 Jun 2022 21:03:33 +0200 Subject: [PATCH 008/143] remove unneeded temperature computation --- src/equations/compressible_navier_stokes_2d.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index cf8a8b17fc7..b695ea02361 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -95,7 +95,6 @@ function flux(u, grad_u, equations::CompressibleNaiverStokes2D) v1 = rho_v1 / rho v2 = rho_v2 / rho - T = temperature(u, equations) # I was not sure what shape this array has or or if it was a tuple # or how to properly "unpack" it. So I just guessed... From 4f6558fa778f47c1ea104957fcad3fe4612fc4e1 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 7 Jun 2022 21:47:45 +0200 Subject: [PATCH 009/143] draft of elixir with possible boundary condition structure --- .../elixir_navier_stokes_source_terms.jl | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl new file mode 100644 index 00000000000..7d8c2397272 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -0,0 +1,153 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNaiverStokes2D(1.4, # gamma + 1000, # Reynolds number + 0.72, # Prandtl number + 0.5, # free-stream Mach number + 1.0, # thermal diffusivity + equations) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Define initial condition +# Note: If you change the diffusion parameter here, also change it in the parabolic equation definition +function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) + # Store translated coordinate for easy use of exact solution + x_trans = x - equation.advection_velocity * t + + # @unpack nu = equation + nu = 5.0e-2 + c = 1.0 + A = 0.5 + L = 2 + f = 1/L + omega = 2 * pi * f + scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) + return SVector(scalar) +end + +initial_condition = initial_condition_diffusive_convergence_test + + + +# TODO: Wasn't sure of the call structure, but this should be what we need +function boundary_condition_no_slip_adiabatic_wall(u_inner, orientation, direction, + x, t, surface_flux_function, + equations::CompressibleEulerEquations2D) + u_boundary = SVector(u_inner[1], -u_inner[2], -u_inner[3], u_inner[4]) + + # Calculate boundary flux + if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary + flux = surface_flux_function(u_inner, u_boundary, orientation, equations) + else # u_boundary is "left" of boundary, u_inner is "right" of boundary + flux = surface_flux_function(u_boundary, u_inner, orientation, equations) + end + + return flux +end + + +# TODO: Wasn't sure of the call structure, but this should be what we need +function boundary_condition_no_slip_adiabatic_wall_neumann(grad_u_inner, orientation, direction, + x, t, surface_flux_function, + equations::CompressibleNaiverStokes2D) + # Copy the inner gradients to an external state array + grad_u_boundary .= grad_u_inner + + # Project out the appropriate temperature gradient pieces. Wasn't sure of array shape + if orientation == 1 + grad_u_norm = grad_u[1,3] # temperature gradient in x-direction + u_x_tangent = grad_u[1,3] - grad_u_norm + u_y_tangent = grad_u[2,3] + + # Update the external state gradients + grad_u_boundary[1,3] = u_x_tangent - grad_u_norm + grad_u_boundary[2,3] = u_y_tangent + else # orientation == 2 + grad_u_norm = grad_u[2,3] # temperature gradient in y-direction + u_x_tangent = grad_u[1,3] + u_y_tangent = grad_u[2,3] - grad_u_norm + + # Update the external state gradients + grad_u_boundary[1,3] = u_x_tangent + grad_u_boundary[2,3] = u_y_tangent - grad_u_norm + end + + # Calculate boundary flux (just averages so has no orientation I think) + flux = surface_flux_function(grad_u_inner, grad_u_boundary, orientation, equations) + + return flux +end + + +# Below is my best guess as to how to set periodic in x direction and walls +# in the y direcitons +boundary_condition= ( + x_neg=boundary_condition_periodic, + x_pos=boundary_condition_periodic, + y_neg=boundary_condition_no_slip_adiabatic_wall, + y_pos=boundary_condition_no_slip_adiabatic_wall, + ) +boundary_conditions_parabolic = ( + x_neg=boundary_condition_periodic, + x_pos=boundary_condition_periodic, + y_neg=boundary_condition_no_slip_adiabatic_wall_neumann, + y_pos=boundary_condition_no_slip_adiabatic_wall_neumann, + ) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan); + +# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup +# and resets the timers +summary_callback = SummaryCallback() + +# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) + +# Print the timer summary +summary_callback() From dde54d318fe10da4ef8157d1291218a770cbc0d0 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 7 Jun 2022 22:40:05 +0200 Subject: [PATCH 010/143] added manufactured solution and source term --- .../elixir_navier_stokes_source_terms.jl | 149 ++++++++++++++++-- 1 file changed, 134 insertions(+), 15 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index 7d8c2397272..f8cf3782759 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -26,24 +26,143 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max=30_000) # set maximum capacity of tree data structure # Define initial condition -# Note: If you change the diffusion parameter here, also change it in the parabolic equation definition -function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) - # Store translated coordinate for easy use of exact solution - x_trans = x - equation.advection_velocity * t - - # @unpack nu = equation - nu = 5.0e-2 - c = 1.0 - A = 0.5 - L = 2 - f = 1/L - omega = 2 * pi * f - scalar = c + A * sin(omega * sum(x_trans)) * exp(-2 * nu * omega^2 * t) - return SVector(scalar) +# Note: If you change the parameters here, also change it in the corresponding source terms +function initial_condition_navier_stokes_convergence_test(x, t, equation::CompressibleEulerEquations2D) + + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) end -initial_condition = initial_condition_diffusive_convergence_test +initial_condition = initial_condition_navier_stokes_convergence_test + + +@inline function initial_condition_navier_stokes_convergence_test(u, x, t, + equations::CompressibleNaiverStokes2D) + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * equations.inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * equations.inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * equations.inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * equations.inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * equations.inv_gamma_minus_one * equations.kappa / equations.Pr + inv_Re = 1.0 / equations.Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end # TODO: Wasn't sure of the call structure, but this should be what we need From daaeac3a35539f6de9d1bf35b7150f19aeee288f Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 7 Jun 2022 22:46:22 +0200 Subject: [PATCH 011/143] fix typo in function name for MMS --- examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index f8cf3782759..adbff3101aa 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -50,8 +50,8 @@ end initial_condition = initial_condition_navier_stokes_convergence_test -@inline function initial_condition_navier_stokes_convergence_test(u, x, t, - equations::CompressibleNaiverStokes2D) +@inline function source_terms_navier_stokes_convergence_test(u, x, t, + equations::CompressibleNaiverStokes2D) # Same settings as in `initial_condition` # Amplitude and shift A = 0.5 From 4a39883f81e3adf47f16dbf7c8008bca6061b925 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 8 Jun 2022 06:59:52 +0200 Subject: [PATCH 012/143] update variable names for consistency. improve comments --- .../compressible_navier_stokes_2d.jl | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index b695ea02361..6433eabf0c7 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -81,10 +81,13 @@ varnames(variable_mapping, equations_parabolic::CompressibleNaiverStokes2D) = # no orientation specified since the flux is vector-valued -# This form of the difussive Navier-Stokes fluxes is taken from Section 2 +# Explicit formulas for the diffussive Navier-Stokes fluxes are avilable, e.g. in Section 2 # of the paper by Svärd, Carpenter and Nordström # "A stable high-order finite difference scheme for the compressible Navier–Stokes # equations, far-field boundary conditions" +# Although these authors use a different nondimensionalization so some constants are different +# particularly for Fick's law. +# # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity function flux(u, grad_u, equations::CompressibleNaiverStokes2D) @@ -103,12 +106,12 @@ function flux(u, grad_u, equations::CompressibleNaiverStokes2D) # Components of viscous stress tensor # (4/3*(v1)_x - 2/3*(v2)_y) - tau_xx = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) + tau_11 = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) # ((v1)_y + (v2)_x) - tau_xy = ( dv1dy + dv2dx ) - tau_yx = tau_xy + tau_12 = ( dv1dy + dv2dx ) + tau_21 = tau_12 # (4/3*(v2)_y - 2/3*(v1)_x) - tau_yy = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) + tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) # Fick's law q = -kappa*grad(T); constant is kappa*gamma/(Pr*(gamma-1)) # Important note! Due to nondimensional scaling R = 1/gamma, so the @@ -116,17 +119,20 @@ function flux(u, grad_u, equations::CompressibleNaiverStokes2D) q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr + # molecular diffusivity is simply 1/Re for this nondimensionalization + mu = 1.0 / equations.Re + # viscous flux components in the x-direction f1 = zero(rho) - f2 = tau_xx / equations.Re - f3 = tau_xy / equations.Re - f4 = ( v1 * tau_xx + v2 * tau_xy + q1) / equations.Re + f2 = tau_11 * mu + f3 = tau_12 * mu + f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * mu # viscous flux components in y-direction g1 = zero(rho) - g2 = tau_yx / equations.Re - g3 = tau_yy / equations.Re - g4 = ( v1 * tau_yx + v2 * tau_yy + q2) / equations.Re + g2 = tau_21 * mu + g3 = tau_22 * mu + g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * mu # TODO: I was not sure how to return this properly. Right now it is a vector of vectors return SVector( SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4) ) @@ -166,7 +172,7 @@ end @inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNaiverStokes2D) # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and -# reverse engineers the gradients to be terms of the primitive vairables (u, v, T). +# reverse engineers the gradients to be terms of the primitive vairables (v1, v2, T). # Helpful because then the diffusive fluxes have the same form as on paper. rho, rho_v1, rho_v2, _ = u @@ -174,9 +180,9 @@ end v2 = rho_v2 / rho T = temperature(u, equations) - return SVector(equations.R * T * (grad_entropy_vars(1) + v1 * grad_entropy_vars(3)), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) - equations.R * T * (grad_entropy_vars(2) + v2 * grad_entropy_vars(3)), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) - equations.R * T * T * grad_entropy_vars(3) # grad(T) = R*T^2*grad(w_4)) + return SVector(equations.R * T * (grad_entropy_vars[1] + v1 * grad_entropy_vars[3]), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) + equations.R * T * (grad_entropy_vars[2] + v2 * grad_entropy_vars[3]), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) + equations.R * T * T * grad_entropy_vars[3] # grad(T) = R*T^2*grad(w_4)) ) end From 3879a3fc65e4c30097842b49b831f48472be7b64 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 8 Jun 2022 13:41:40 +0200 Subject: [PATCH 013/143] fix dumb typos in new equation system name --- .../elixir_navier_stokes_source_terms.jl | 6 ++--- .../compressible_navier_stokes_2d.jl | 24 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index adbff3101aa..7203c321e2a 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -7,7 +7,7 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNaiverStokes2D(1.4, # gamma +equations_parabolic = CompressibleNavierStokes2D(1.4, # gamma 1000, # Reynolds number 0.72, # Prandtl number 0.5, # free-stream Mach number @@ -51,7 +51,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test @inline function source_terms_navier_stokes_convergence_test(u, x, t, - equations::CompressibleNaiverStokes2D) + equations::CompressibleNavierStokes2D) # Same settings as in `initial_condition` # Amplitude and shift A = 0.5 @@ -185,7 +185,7 @@ end # TODO: Wasn't sure of the call structure, but this should be what we need function boundary_condition_no_slip_adiabatic_wall_neumann(grad_u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleNaiverStokes2D) + equations::CompressibleNavierStokes2D) # Copy the inner gradients to an external state array grad_u_boundary .= grad_u_inner diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 6433eabf0c7..6ee74893c01 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -1,12 +1,12 @@ @doc raw""" - CompressibleNaiverStokes2D(gamma, + CompressibleNavierStokes2D(gamma, Re, Pr, Ma_inf, kappa, equations) -`CompressibleNaiverStokes2D` represents the diffusion (i.e. parabolic) terms applied +`CompressibleNavierStokes2D` represents the diffusion (i.e. parabolic) terms applied to mass, momenta, and total energy together with the advective from the `CompressibleEulerEquations2D`. @@ -45,7 +45,7 @@ where # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations # 2) Add more here and probably some equations -struct CompressibleNaiverStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} +struct CompressibleNavierStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number @@ -60,15 +60,15 @@ struct CompressibleNaiverStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierS equations::E # CompressibleEulerEquations2D end -function CompressibleNaiverStokes2D(gamma, Reynolds, Prandtl, Mach_frestream, kappa, equations) +function CompressibleNavierStokes2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations) γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) # From the nondimensionalization discussed above set the remaining free-stream # quantities p_inf = 1.0 / γ - u_inf = Mach_frestream + u_inf = Mach_freestream R = 1.0 / γ - CompressibleNaiverStokes2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, + CompressibleNavierStokes2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, Reynolds, Prandtl, Mach_freestream, kappa, p_inf, u_inf, R, equations) @@ -76,7 +76,7 @@ end # I was not sure what to do here to allow flexibility of selecting primitive or entropy # grandient variables -varnames(variable_mapping, equations_parabolic::CompressibleNaiverStokes2D) = +varnames(variable_mapping, equations_parabolic::CompressibleNavierStokes2D) = varnames(variable_mapping, equations_parabolic.equations) @@ -90,7 +90,7 @@ varnames(variable_mapping, equations_parabolic::CompressibleNaiverStokes2D) = # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, grad_u, equations::CompressibleNaiverStokes2D) +function flux(u, grad_u, equations::CompressibleNavierStokes2D) # Here grad_u is assumed to contain the gradients of the primitive variables (v1,v2,T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function @@ -140,7 +140,7 @@ end # Convert conservative variables to primitive -@inline function cons2prim(u, equations::CompressibleNaiverStokes2D) +@inline function cons2prim(u, equations::CompressibleNavierStokes2D) rho, rho_v1, rho_v2, _ = u v1 = rho_v1 / rho @@ -152,7 +152,7 @@ end # Convert conservative variables to entropy -@inline function cons2entropy(u, equations::CompressibleNaiverStokes2D) +@inline function cons2entropy(u, equations::CompressibleNavierStokes2D) rho, rho_v1, rho_v2, rho_e = u v1 = rho_v1 / rho @@ -170,7 +170,7 @@ end end -@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNaiverStokes2D) +@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokes2D) # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and # reverse engineers the gradients to be terms of the primitive vairables (v1, v2, T). # Helpful because then the diffusive fluxes have the same form as on paper. @@ -187,7 +187,7 @@ end end -@inline function temperature(u, equations::CompressibleNaiverStokes2D) +@inline function temperature(u, equations::CompressibleNavierStokes2D) rho, rho_v1, rho_v2, rho_e = u p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2) / rho) From 435e081ee11a2c9c1f0e2620d823f82f2e96bbca Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 8 Jun 2022 13:41:52 +0200 Subject: [PATCH 014/143] actually export new equations --- src/Trixi.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Trixi.jl b/src/Trixi.jl index e78a1bd9dc5..c176593e64a 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -133,6 +133,7 @@ export AcousticPerturbationEquations2D, InviscidBurgersEquation1D, LaplaceDiffusion2D, LatticeBoltzmannEquations2D, LatticeBoltzmannEquations3D, + CompressibleNavierStokes2D, ShallowWaterEquations1D, ShallowWaterEquations2D export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, From 7b59fef47ef5cc6df80a194918af6ecf5dae9d5d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 8 Jun 2022 13:54:47 +0200 Subject: [PATCH 015/143] add comment near variable_mapping declaration. --- src/equations/compressible_navier_stokes_2d.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 6ee74893c01..4a364a3e9ab 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -74,8 +74,14 @@ function CompressibleNavierStokes2D(gamma, Reynolds, Prandtl, Mach_freestream, k equations) end + # I was not sure what to do here to allow flexibility of selecting primitive or entropy -# grandient variables +# gradient variables. I see that `transform_variables!` just copies data at the moment. + +# This is the flexibility a user should have to select the different gradient variable types +# varnames(::typeof(cons2prim) , ::CompressibleNavierStokes2D) = ("v1", "v2", "T") +# varnames(::typeof(cons2entropy), ::CompressibleNavierStokes2D) = ("w2", "w3", "w4") + varnames(variable_mapping, equations_parabolic::CompressibleNavierStokes2D) = varnames(variable_mapping, equations_parabolic.equations) From 5dc830154b2ae77b4c1c456c7b5be9f1c2e65c05 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 9 Jun 2022 08:33:58 +0200 Subject: [PATCH 016/143] Apply suggestions from code review Co-authored-by: Hendrik Ranocha --- examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl | 2 +- src/equations/compressible_navier_stokes_2d.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index 7203c321e2a..b8796315f4d 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -2,7 +2,7 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the linear advection-diffusion equation +# semidiscretization of the ideal compressible Navier-Stokes equations equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 4a364a3e9ab..e19a4eadded 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -65,9 +65,9 @@ function CompressibleNavierStokes2D(gamma, Reynolds, Prandtl, Mach_freestream, k # From the nondimensionalization discussed above set the remaining free-stream # quantities - p_inf = 1.0 / γ + p_inf = 1 / γ u_inf = Mach_freestream - R = 1.0 / γ + R = 1 / γ CompressibleNavierStokes2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, Reynolds, Prandtl, Mach_freestream, kappa, p_inf, u_inf, R, @@ -141,7 +141,7 @@ function flux(u, grad_u, equations::CompressibleNavierStokes2D) g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * mu # TODO: I was not sure how to return this properly. Right now it is a vector of vectors - return SVector( SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4) ) + return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) end From f316684fefa6d1da10fcecde4e6eb739d432a557 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 9 Jun 2022 08:28:13 +0200 Subject: [PATCH 017/143] parabolic equations now exported separately --- src/Trixi.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index c176593e64a..4037d41961c 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -131,11 +131,12 @@ export AcousticPerturbationEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, LinearScalarAdvectionEquation3D, InviscidBurgersEquation1D, - LaplaceDiffusion2D, LatticeBoltzmannEquations2D, LatticeBoltzmannEquations3D, - CompressibleNavierStokes2D, ShallowWaterEquations1D, ShallowWaterEquations2D +export LaplaceDiffusion2D, + CompressibleNavierStokes2D + export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, flux_nonconservative_powell, From 02c14e1ed9ff78c94f451cec23a308424b830a11 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 9 Jun 2022 08:30:52 +0200 Subject: [PATCH 018/143] change name to CompressibleNavierStokesEquations2D --- .../elixir_navier_stokes_source_terms.jl | 6 +-- .../compressible_navier_stokes_2d.jl | 44 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index b8796315f4d..6dcf22b41fa 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -7,7 +7,7 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokes2D(1.4, # gamma +equations_parabolic = CompressibleNavierStokesEquations2D(1.4, # gamma 1000, # Reynolds number 0.72, # Prandtl number 0.5, # free-stream Mach number @@ -51,7 +51,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test @inline function source_terms_navier_stokes_convergence_test(u, x, t, - equations::CompressibleNavierStokes2D) + equations::CompressibleNavierStokesEquations2D) # Same settings as in `initial_condition` # Amplitude and shift A = 0.5 @@ -185,7 +185,7 @@ end # TODO: Wasn't sure of the call structure, but this should be what we need function boundary_condition_no_slip_adiabatic_wall_neumann(grad_u_inner, orientation, direction, x, t, surface_flux_function, - equations::CompressibleNavierStokes2D) + equations::CompressibleNavierStokesEquations2D) # Copy the inner gradients to an external state array grad_u_boundary .= grad_u_inner diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index e19a4eadded..ffe6cf1d95b 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -1,12 +1,12 @@ @doc raw""" - CompressibleNavierStokes2D(gamma, - Re, - Pr, - Ma_inf, - kappa, - equations) - -`CompressibleNavierStokes2D` represents the diffusion (i.e. parabolic) terms applied + CompressibleNavierStokesEquations2D(gamma, + Re, + Pr, + Ma_inf, + kappa, + equations) + +`CompressibleNavierStokesEquations2D` represents the diffusion (i.e. parabolic) terms applied to mass, momenta, and total energy together with the advective from the `CompressibleEulerEquations2D`. @@ -45,7 +45,7 @@ where # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations # 2) Add more here and probably some equations -struct CompressibleNavierStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} +struct CompressibleNavierStokesEquations2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number @@ -60,7 +60,7 @@ struct CompressibleNavierStokes2D{RealT<:Real, E} <: AbstractCompressibleNavierS equations::E # CompressibleEulerEquations2D end -function CompressibleNavierStokes2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations) +function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations) γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) # From the nondimensionalization discussed above set the remaining free-stream @@ -68,10 +68,10 @@ function CompressibleNavierStokes2D(gamma, Reynolds, Prandtl, Mach_freestream, k p_inf = 1 / γ u_inf = Mach_freestream R = 1 / γ - CompressibleNavierStokes2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, - Reynolds, Prandtl, Mach_freestream, - kappa, p_inf, u_inf, R, - equations) + CompressibleNavierStokesEquations2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, + Reynolds, Prandtl, Mach_freestream, + kappa, p_inf, u_inf, R, + equations) end @@ -79,10 +79,10 @@ end # gradient variables. I see that `transform_variables!` just copies data at the moment. # This is the flexibility a user should have to select the different gradient variable types -# varnames(::typeof(cons2prim) , ::CompressibleNavierStokes2D) = ("v1", "v2", "T") -# varnames(::typeof(cons2entropy), ::CompressibleNavierStokes2D) = ("w2", "w3", "w4") +# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesEquations2D) = ("v1", "v2", "T") +# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") -varnames(variable_mapping, equations_parabolic::CompressibleNavierStokes2D) = +varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = varnames(variable_mapping, equations_parabolic.equations) @@ -96,7 +96,7 @@ varnames(variable_mapping, equations_parabolic::CompressibleNavierStokes2D) = # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, grad_u, equations::CompressibleNavierStokes2D) +function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # Here grad_u is assumed to contain the gradients of the primitive variables (v1,v2,T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function @@ -146,7 +146,7 @@ end # Convert conservative variables to primitive -@inline function cons2prim(u, equations::CompressibleNavierStokes2D) +@inline function cons2prim(u, equations::CompressibleNavierStokesEquations2D) rho, rho_v1, rho_v2, _ = u v1 = rho_v1 / rho @@ -158,7 +158,7 @@ end # Convert conservative variables to entropy -@inline function cons2entropy(u, equations::CompressibleNavierStokes2D) +@inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) rho, rho_v1, rho_v2, rho_e = u v1 = rho_v1 / rho @@ -176,7 +176,7 @@ end end -@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokes2D) +@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokesEquations2D) # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and # reverse engineers the gradients to be terms of the primitive vairables (v1, v2, T). # Helpful because then the diffusive fluxes have the same form as on paper. @@ -193,7 +193,7 @@ end end -@inline function temperature(u, equations::CompressibleNavierStokes2D) +@inline function temperature(u, equations::CompressibleNavierStokesEquations2D) rho, rho_v1, rho_v2, rho_e = u p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2) / rho) From dd733bb4d05b69813bb2ed342465e388dc480c67 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 9 Jun 2022 08:37:36 +0200 Subject: [PATCH 019/143] export NS with proper name --- src/Trixi.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 4037d41961c..2b4ac68d1f5 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -135,7 +135,7 @@ export AcousticPerturbationEquations2D, ShallowWaterEquations1D, ShallowWaterEquations2D export LaplaceDiffusion2D, - CompressibleNavierStokes2D + CompressibleNavierStokesEquations2D export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, From a1a48fe2b0627c55c2d7487997e540c7283639d3 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 10:17:27 +0200 Subject: [PATCH 020/143] explicitly require compressible Euler in the type parameter --- src/equations/compressible_navier_stokes_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index ffe6cf1d95b..291fdcf8dfe 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -45,7 +45,7 @@ where # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations # 2) Add more here and probably some equations -struct CompressibleNavierStokesEquations2D{RealT<:Real, E} <: AbstractCompressibleNavierStokesEquations{2, 3} +struct CompressibleNavierStokesEquations2D{RealT<:Real, E<:AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 3} gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number @@ -60,7 +60,7 @@ struct CompressibleNavierStokesEquations2D{RealT<:Real, E} <: AbstractCompressib equations::E # CompressibleEulerEquations2D end -function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations) +function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations::CompressibleEulerEquations2D) γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) # From the nondimensionalization discussed above set the remaining free-stream From d8db2030d94f8aecf6af97d8a9d3825d77c5e5e4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 10:19:58 +0200 Subject: [PATCH 021/143] name kinematic viscosity nu for consistency with Lattice-Boltzmann --- src/equations/compressible_navier_stokes_2d.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 291fdcf8dfe..dc11d84a82e 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -125,22 +125,21 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr - # molecular diffusivity is simply 1/Re for this nondimensionalization - mu = 1.0 / equations.Re + # kinematic viscosity is simply 1/Re for this nondimensionalization + nu = 1.0 / equations.Re # viscous flux components in the x-direction f1 = zero(rho) - f2 = tau_11 * mu - f3 = tau_12 * mu - f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * mu + f2 = tau_11 * nu + f3 = tau_12 * nu + f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * nu # viscous flux components in y-direction g1 = zero(rho) - g2 = tau_21 * mu - g3 = tau_22 * mu - g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * mu + g2 = tau_21 * nu + g3 = tau_22 * nu + g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * nu - # TODO: I was not sure how to return this properly. Right now it is a vector of vectors return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) end From 06e69b869ec215ed6a314f5d07442e12de051982 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 10:23:43 +0200 Subject: [PATCH 022/143] add promotion in constructor --- src/equations/compressible_navier_stokes_2d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index dc11d84a82e..236fa9298cf 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -61,7 +61,7 @@ struct CompressibleNavierStokesEquations2D{RealT<:Real, E<:AbstractCompressibleE end function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations::CompressibleEulerEquations2D) - γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1)) + γ, inv_gamma_minus_one, Re, Pr, Ma, κ = promote(gamma, inv(gamma - 1), Reynolds, Prandtl, Mach_freestream, kappa) # From the nondimensionalization discussed above set the remaining free-stream # quantities @@ -69,8 +69,8 @@ function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_free u_inf = Mach_freestream R = 1 / γ CompressibleNavierStokesEquations2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, - Reynolds, Prandtl, Mach_freestream, - kappa, p_inf, u_inf, R, + Re, Pr, Ma, κ, + p_inf, u_inf, R, equations) end From eda9737f042b05fe7a4461d4027630c84095ff66 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 10:38:11 +0200 Subject: [PATCH 023/143] make Reynolds, Prandtl, Mach, and kappa keyword arguments --- src/equations/compressible_navier_stokes_2d.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 236fa9298cf..73e5ad55c2d 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -60,8 +60,10 @@ struct CompressibleNavierStokesEquations2D{RealT<:Real, E<:AbstractCompressibleE equations::E # CompressibleEulerEquations2D end -function CompressibleNavierStokesEquations2D(gamma, Reynolds, Prandtl, Mach_freestream, kappa, equations::CompressibleEulerEquations2D) - γ, inv_gamma_minus_one, Re, Pr, Ma, κ = promote(gamma, inv(gamma - 1), Reynolds, Prandtl, Mach_freestream, kappa) +function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream, kappa) + γ = equations.gamma + inv_gamma_minus_one = equations.inv_gamma_minus_one + Re, Pr, Ma, κ = promote(Reynolds, Prandtl, Mach_freestream, kappa) # From the nondimensionalization discussed above set the remaining free-stream # quantities From b469bcea07e6f7403d58a24bbccdcf0090e512b6 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 10:38:38 +0200 Subject: [PATCH 024/143] update constructor call in elixir --- .../elixir_navier_stokes_source_terms.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl index 6dcf22b41fa..bd85946f1b3 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl @@ -7,12 +7,12 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(1.4, # gamma - 1000, # Reynolds number - 0.72, # Prandtl number - 0.5, # free-stream Mach number - 1.0, # thermal diffusivity - equations) +equations_parabolic = CompressibleNavierStokesEquations2D(equations, + Reynolds=1000, + Prandtl=0.72, + Mach_freestream=0.5, + kappa=1.0 # thermal diffusivity + ) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) From fb646b0e765a4667a3b4da246eff463388e15a33 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 10 Jun 2022 12:07:30 +0200 Subject: [PATCH 025/143] reduce computation by exploiting stress tensor symmetry --- src/equations/compressible_navier_stokes_2d.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 73e5ad55c2d..4683d7d01ea 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -116,8 +116,8 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # (4/3*(v1)_x - 2/3*(v2)_y) tau_11 = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) # ((v1)_y + (v2)_x) - tau_12 = ( dv1dy + dv2dx ) - tau_21 = tau_12 + # stress tensor is symmetric + tau_12 = ( dv1dy + dv2dx ) # = tau_21 # (4/3*(v2)_y - 2/3*(v1)_x) tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) @@ -136,11 +136,13 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) f3 = tau_12 * nu f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * nu - # viscous flux components in y-direction + # viscous flux components in the y-direction + # Note, symmetry is exploited for tau_12 = tau_21 g1 = zero(rho) - g2 = tau_21 * nu + g2 = f3 # tau_21 * nu g3 = tau_22 * nu - g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * nu + # g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * nu + g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * nu return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) end From f6bca767de53032723ccbece8558c4d1892ccedc Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 11:58:42 -0500 Subject: [PATCH 026/143] fix unpacking of flux --- src/equations/compressible_navier_stokes_2d.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 4683d7d01ea..9adf98dc1b2 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -109,7 +109,8 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # I was not sure what shape this array has or or if it was a tuple # or how to properly "unpack" it. So I just guessed... - dv1dx, dv1dy, dv2dx, dv2dy, dTdx, dTdy = grad_u + dv1dx, dv2dx, dTdx = grad_u[1] + dv1dy, dv2dy, dTdy = grad_u[2] # Components of viscous stress tensor From 9b5dd3596167dbc93463dfea76b7c8abec83f354 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 12:04:29 -0500 Subject: [PATCH 027/143] modifying parabolic cache creation in cache, we assume we take the gradient of all hyperbolic variables. since the number of parabolic variables can differ from the number of hyperbolic variables, we pass in the hyperbolic equations to `create_cache_parabolic` now --- .../semidiscretization_hyperbolic_parabolic.jl | 3 ++- src/solvers/dgmulti/dg_parabolic.jl | 7 +++++-- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 7 ++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index ea96aa5c363..52a48d7aa03 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -102,7 +102,8 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabo _boundary_conditions = digest_boundary_conditions(boundary_conditions, mesh, solver, cache) _boundary_conditions_parabolic = digest_boundary_conditions(boundary_conditions_parabolic, mesh, solver, cache) - cache_parabolic = (; create_cache_parabolic(mesh, equations_parabolic, solver, solver_parabolic, RealT, uEltype)..., + cache_parabolic = (; create_cache_parabolic(mesh, equations, equations_parabolic, + solver, solver_parabolic, RealT, uEltype)..., initial_cache_parabolic...) SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 9578e3f9eff..cfb92fd1b4f 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -1,6 +1,9 @@ -function create_cache_parabolic(mesh::DGMultiMesh, equations::AbstractEquationsParabolic, +function create_cache_parabolic(mesh::DGMultiMesh, equations_hyperbolic::AbstractEquations, + equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, dg_parabolic, RealT, uEltype) - nvars = nvariables(equations) + # default to taking derivatives of all hyperbolic terms + # TODO: utilize "differentiated" parabolic variables in `equations_parabolic` + nvars = nvariables(equations_hyperbolic) @unpack M, Drst = dg.basis weak_differentiation_matrices = map(A -> -M \ (A' * M), Drst) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 01f0ead469f..1c332fc6f2e 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -438,14 +438,15 @@ end # This method is called when a SemidiscretizationHyperbolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, +function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::AbstractEquations, + equations_parabolic::AbstractEquationsParabolic, dg::DG, dg_parabolic, RealT, uEltype) # Get cells for which an element needs to be created (i.e. all leaf cells) leaf_cell_ids = local_leaf_cells(mesh.tree) - elements = init_elements(leaf_cell_ids, mesh, equations_parabolic, dg.basis, RealT, uEltype) + elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - n_vars = nvariables(equations_parabolic) + n_vars = nvariables(equations_hyperbolic) n_nodes = nnodes(elements) n_elements = nelements(elements) u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) From 21e1c998e3b3c4f5cfc914bbeb45fade3b82cefb Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:29:21 -0500 Subject: [PATCH 028/143] comments --- src/solvers/dgmulti/dg_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index cfb92fd1b4f..561dfd2f1a4 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -248,7 +248,7 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh end # interpolates from solution coefficients to face quadrature points - viscous_flux_face_values = cache_parabolic.grad_u_face_values + viscous_flux_face_values = cache_parabolic.grad_u_face_values # reuse storage for dim in eachdim(mesh) prolong2interfaces!(viscous_flux_face_values[dim], viscous_flux[dim], mesh, equations, dg.surface_integral, dg, cache) From 19f004e6de741a921c1adb4716bf593168de09bd Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:29:32 -0500 Subject: [PATCH 029/143] comments --- src/solvers/dgmulti/dg_parabolic.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 561dfd2f1a4..3ad91627f63 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -1,8 +1,9 @@ -function create_cache_parabolic(mesh::DGMultiMesh, equations_hyperbolic::AbstractEquations, +function create_cache_parabolic(mesh::DGMultiMesh, + equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, dg_parabolic, RealT, uEltype) # default to taking derivatives of all hyperbolic terms - # TODO: utilize "differentiated" parabolic variables in `equations_parabolic` + # TODO: utilize the parabolic variables in `equations_parabolic` to reduce memory usage in the parabolic cache nvars = nvariables(equations_hyperbolic) @unpack M, Drst = dg.basis From de442bf8e830b46007eca3283a1033fcedfabbf9 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:30:57 -0500 Subject: [PATCH 030/143] formatting and renaming equations to equations_hyperbolic formatting comments --- src/equations/compressible_navier_stokes_2d.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 9adf98dc1b2..e5c34687f19 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -45,7 +45,7 @@ where # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations # 2) Add more here and probably some equations -struct CompressibleNavierStokesEquations2D{RealT<:Real, E<:AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 3} +struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 3} gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number @@ -57,7 +57,7 @@ struct CompressibleNavierStokesEquations2D{RealT<:Real, E<:AbstractCompressibleE u_inf::RealT # free-stream velocity R::RealT # gas constant (depends on nondimensional scaling!) - equations::E # CompressibleEulerEquations2D + equations_hyperbolic::E # CompressibleEulerEquations2D end function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream, kappa) @@ -85,11 +85,11 @@ end # varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = - varnames(variable_mapping, equations_parabolic.equations) + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -# Explicit formulas for the diffussive Navier-Stokes fluxes are avilable, e.g. in Section 2 +# Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 # of the paper by Svärd, Carpenter and Nordström # "A stable high-order finite difference scheme for the compressible Navier–Stokes # equations, far-field boundary conditions" @@ -99,7 +99,7 @@ varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquation # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) - # Here grad_u is assumed to contain the gradients of the primitive variables (v1,v2,T) + # Here grad_u is assumed to contain the gradients of the primitive variables (v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function rho, rho_v1, rho_v2, _ = u From 298b726ad601e44079e7b85ce6b8feb7f15b2840 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:31:11 -0500 Subject: [PATCH 031/143] fix unpacking of gradients in flux --- src/equations/compressible_navier_stokes_2d.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index e5c34687f19..170a6de5acb 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -107,10 +107,9 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) v1 = rho_v1 / rho v2 = rho_v2 / rho - # I was not sure what shape this array has or or if it was a tuple - # or how to properly "unpack" it. So I just guessed... - dv1dx, dv2dx, dTdx = grad_u[1] - dv1dy, dv2dy, dTdy = grad_u[2] + # grad_u contains derivatives of each hyperbolic variable + _, dv1dx, dv2dx, dTdx = grad_u[1] + _, dv1dy, dv2dy, dTdy = grad_u[2] # Components of viscous stress tensor From 01f832517e90cd0358dbfc441dedce8ac9d54483 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:31:28 -0500 Subject: [PATCH 032/143] adding CNS BCs --- src/Trixi.jl | 3 +- .../compressible_navier_stokes_2d.jl | 65 +++++++++---------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 2b4ac68d1f5..76482b841c1 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -163,7 +163,8 @@ export boundary_condition_do_nothing, BoundaryConditionNeumann, boundary_condition_noslip_wall, boundary_condition_slip_wall, - boundary_condition_wall + boundary_condition_wall, + BoundaryConditionViscousWall, NoSlip, Adiabatic export initial_condition_convergence_test, source_terms_convergence_test export source_terms_harmonic diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 170a6de5acb..6e302221fa9 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -204,39 +204,36 @@ end return T end +# abstract container for wall-type boundary conditions +struct BoundaryConditionViscousWall{V, H} + boundary_condition_velocity::V + boundary_condition_heat_flux::H +end -# -# All this boundary conditions stuff I did not touch -# +# no slip velocity BC +struct NoSlip{F} + boundary_value_function::F # value of the velocity vector on the boundary +end -# TODO: should this remain in the equations file, be moved to solvers, or live in the elixir? -# The penalization depends on the solver, but also depends explicitly on physical parameters, -# and would probably need to be specialized for every different equation. -# function penalty(u_outer, u_inner, inv_h, equations::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) -# return dg.penalty_parameter * (u_outer - u_inner) * equations.diffusivity * inv_h -# end - -# # Dirichlet-type boundary condition for use with a parabolic solver in weak form -# @inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, -# x, t, operator_type::Gradient, -# equations::LaplaceDiffusion2D) -# return boundary_condition.boundary_value_function(x, t, equations) -# end - -# @inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, -# x, t, operator_type::Divergence, -# equations::LaplaceDiffusion2D) -# return u_inner -# end - -# @inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, -# x, t, operator_type::Divergence, -# equations::LaplaceDiffusion2D) -# return boundary_condition.boundary_normal_flux_function(x, t, equations) -# end - -# @inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, -# x, t, operator_type::Gradient, -# equations::LaplaceDiffusion2D) -# return flux_inner -# end +# adiabatic temperature BC +struct Adiabatic{F} + boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(u_inner, normal::AbstractVector, + x, t, operator_type::Gradient, + equations::CompressibleNavierStokesEquations2D) + rho = u_inner[1] # should not matter since the viscous terms don't depend on rho + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + return SVector(rho, v1, v2, u_inner[4]) +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, normal::AbstractVector, + x, t, operator_type::Divergence, + equations::CompressibleNavierStokesEquations2D) + normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + tau_1n, tau_2n = flux_inner[2:3] + normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux + return SVector(flux_inner[1:3]..., normal_energy_flux) +end From 3f04e7148ec1cd48b5f2c5b8364b3f8fc28978ae Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 22:31:35 -0500 Subject: [PATCH 033/143] adding lid-driven cavity elixir --- .../elixir_navier_stokes_lid_driven_cavity.jl | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl new file mode 100644 index 00000000000..63bb1ce29f8 --- /dev/null +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -0,0 +1,70 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=100, Prandtl=0.72, + Mach_freestream=0.1, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +top(x, tol=50*eps()) = abs(x[2] - 1) < tol +rest_of_boundary(x, tol=50*eps()) = !top(x, tol) +is_on_boundary = Dict(:top => top, :rest_of_boundary => rest_of_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); is_on_boundary) + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0, 0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) + +# define inviscid boundary conditions +boundary_conditions = (; :top => boundary_condition_slip_wall, + :rest_of_boundary => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :top => boundary_condition_lid, + :rest_of_boundary => boundary_condition_cavity) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, 25.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary From 36e3b68708eefdea12b8f6b59930111a90ba18c6 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 14 Jun 2022 23:26:39 -0500 Subject: [PATCH 034/143] adding variable transform, editing cons2prim for CNS --- src/equations/compressible_navier_stokes_2d.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 6e302221fa9..18005104387 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -87,6 +87,13 @@ end varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) +# transform to primitive variables +# TODO: should we have this call a "gradient transformation" field? +function transform_variables!(u_transformed, u, equations_parabolic::CompressibleNavierStokesEquations2D) + @threaded for i in eachindex(u) + u_transformed[i] = cons2prim(u[i], equations_parabolic) + end +end # no orientation specified since the flux is vector-valued # Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 @@ -156,7 +163,7 @@ end v2 = rho_v2 / rho T = temperature(u, equations) - return SVector(v1, v2, T) + return SVector(rho, v1, v2, T) end From 6bf91eb80eaf66642b1c1d283de29cbc2ad96e1f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 15 Jun 2022 10:18:38 -0500 Subject: [PATCH 035/143] add prim2cons for NS (inconsistent right now) --- src/equations/compressible_navier_stokes_2d.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 18005104387..ea360b11f19 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -166,6 +166,11 @@ end return SVector(rho, v1, v2, T) end +# TODO: make this consistent with cons2prim above and cons2prim for Euler! +@inline prim2cons(u, equations::CompressibleNavierStokesEquations2D) = + prim2cons(u, equations.equations_hyperbolic) + + # Convert conservative variables to entropy @inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) From a0ea3f0958abb2eb8d1ddc7160a08199dcf5044b Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 15 Jun 2022 10:18:55 -0500 Subject: [PATCH 036/143] add draft of DGMulti Navier Stokes convergence elixir --- .../elixir_navier_stokes_convergence.jl | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 examples/dgmulti_2d/elixir_navier_stokes_convergence.jl diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl new file mode 100644 index 00000000000..21ab09aac06 --- /dev/null +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -0,0 +1,203 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, + Mach_freestream=0.5, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +is_on_boundary = Dict(:top_bottom => top_bottom) +mesh = DGMultiMesh(dg, cells_per_dimension=(8, 8); periodicity=(true, false), is_on_boundary) + +# Define initial condition +# Note: If you change the parameters here, also change it in the corresponding source terms +function initial_condition_navier_stokes_convergence_test(x, t, equations) + + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + + y = x[2] + + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + kappa = 1 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = 0.72 + Re = 100 + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, .50) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary From c103e2ee7c6488f39d67122d35acb0a4e92d8476 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 10:10:07 -0500 Subject: [PATCH 037/143] converging solution using elixir for TreeMesh with BCs --- .../elixir_advection_diffusion_nonperiodic.jl | 88 +++++++++++ src/solvers/dgsem_tree/dg_2d_parabolic.jl | 145 +++++++++++++++++- 2 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl new file mode 100644 index 00000000000..2dce083330e --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -0,0 +1,88 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +get_diffusivity() = 5.0e-2 +advection_velocity = (1.0, 0.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +# Note: If you change the diffusion parameter here, also change it in the initial condition +equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -0.5) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 0.0, 0.5) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# from "Robust DPG methods for transient convection-diffusion." +# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. +# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +function initial_condition_erikkson_johnson(x, t, equations) + l = 4 + epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_erikkson_johnson + +# define periodic boundary conditions everywhere +boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), + y_neg = BoundaryConditionDirichlet(initial_condition), + y_pos = BoundaryConditionDirichlet(initial_condition), + x_pos = boundary_condition_do_nothing) + +boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan); + +# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup +# and resets the timers +summary_callback = SummaryCallback() + +# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-10 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) + +# Print the timer summary +summary_callback() diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 1c332fc6f2e..fabc79ff46e 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -39,7 +39,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra end - +# TODO: dg_parabolic is not a DG type; it contains solver-specific information such as an LDG penalty parameter. function calc_divergence!(du, u, t, viscous_flux, mesh::TreeMesh{2}, equations_parabolic, boundary_conditions_parabolic, dg::DG, dg_parabolic, @@ -176,7 +176,8 @@ function calc_divergence!(du, u, t, viscous_flux, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_condition_periodic + calc_divergence_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + mesh, equations_parabolic, dg.surface_integral, dg) end # Prolong solution to mortars @@ -250,6 +251,143 @@ function calc_viscous_fluxes!(viscous_flux, u, mesh::TreeMesh{2}, end end +# TODO: decide if we should keep this, and if so, extend to 3D. +function get_unsigned_normal_vector_2d(direction) + if direction > 4 + @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." + end + if direction==1 || direction==2 + return SVector(1.0, 0.0) + else + return SVector(0.0, 1.0) + end +end + +function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + @unpack surface_flux_values = cache.elements + @unpack n_boundaries_per_direction = cache.boundaries + + # Calculate indices + lasts = accumulate(+, n_boundaries_per_direction) + firsts = lasts - n_boundaries_per_direction .+ 1 + + # Calc boundary fluxes in each direction + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[1], + equations_parabolic, surface_integral, dg, cache, + 1, firsts[1], lasts[1]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[2], + equations_parabolic, surface_integral, dg, cache, + 2, firsts[2], lasts[2]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[3], + equations_parabolic, surface_integral, dg, cache, + 3, firsts[3], lasts[3]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[4], + equations_parabolic, surface_integral, dg, cache, + 4, firsts[4], lasts[4]) +end +function calc_gradient_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:Any,4}, t, + boundary_condition, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + direction, first_boundary, last_boundary) + @unpack surface_flux = surface_integral + @unpack u, neighbor_ids, neighbor_sides, node_coordinates, orientations = cache.boundaries + + @threaded for boundary in first_boundary:last_boundary + # Get neighboring element + neighbor = neighbor_ids[boundary] + + for i in eachnode(dg) + # Get boundary flux + u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, boundary) + if neighbor_sides[boundary] == 1 # Element is on the left, boundary on the right + u_inner = u_ll + else # Element is on the right, boundary on the left + u_inner = u_rr + end + flux_inner = u_inner # TODO: revisit if we want to generalize beyond BR1, LDG. + + x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) + flux = boundary_condition(flux_inner, u_inner, get_unsigned_normal_vector_2d(direction), + x, t, Gradient(), equations_parabolic) + + # Copy flux to left and right element storage + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, direction, neighbor] = flux[v] + end + end + end + + return nothing +end + +function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + @unpack surface_flux_values = cache.elements + @unpack n_boundaries_per_direction = cache.boundaries + + # Calculate indices + lasts = accumulate(+, n_boundaries_per_direction) + firsts = lasts - n_boundaries_per_direction .+ 1 + + # Calc boundary fluxes in each direction + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[1], + equations_parabolic, surface_integral, dg, cache, + 1, firsts[1], lasts[1]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[2], + equations_parabolic, surface_integral, dg, cache, + 2, firsts[2], lasts[2]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[3], + equations_parabolic, surface_integral, dg, cache, + 3, firsts[3], lasts[3]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[4], + equations_parabolic, surface_integral, dg, cache, + 4, firsts[4], lasts[4]) +end +function calc_divergence_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:Any,4}, t, + boundary_condition, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + direction, first_boundary, last_boundary) + @unpack surface_flux = surface_integral + + # Note: cache.boundaries.u contains the unsigned normal component (using "orientation", not "direction") + # of the viscous flux, as computed in `prolong2boundaries` of `calc_divergence!`` + @unpack u, neighbor_ids, neighbor_sides, node_coordinates, orientations = cache.boundaries + + @threaded for boundary in first_boundary:last_boundary + # Get neighboring element + neighbor = neighbor_ids[boundary] + + for i in eachnode(dg) + # Get viscous boundary fluxes + flux_ll, flux_rr = get_surface_node_vars(u, equations_parabolic, dg, i, boundary) + if neighbor_sides[boundary] == 1 # Element is on the left, boundary on the right + flux_inner = flux_ll + else # Element is on the right, boundary on the left + flux_inner = flux_rr + end + + x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) + + # TODO: we are passing in `u_inner = nothing` since we overwrite cache.boundaries.u with gradient information. + # This currently works with Dirichlet/Neuman boundary conditions for LaplaceDiffusion2D and NoSlipWall and Adiabatic + # boundary conditions for CompressibleNavierStokesEquations2D as of 2022-6-27. It may not work with future implementations. + flux = boundary_condition(flux_inner, nothing, get_unsigned_normal_vector_2d(direction), + x, t, Divergence(), equations_parabolic) + + # Copy flux to left and right element storage + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, direction, neighbor] = flux[v] + end + end + end + + return nothing +end function calc_gradient!(u_grad, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, @@ -374,7 +512,8 @@ function calc_gradient!(u_grad, u, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_condition_periodic + calc_gradient_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + mesh, equations_parabolic, dg.surface_integral, dg) end # Prolong solution to mortars From 3d717a679bc49852b7f62ab41102c4e53ca630ba Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:07:20 -0500 Subject: [PATCH 038/143] fixing DGMulti advection diffusion elixir convergence --- .../elixir_advection_diffusion_nonperiodic.jl | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl new file mode 100644 index 00000000000..086c3a995b7 --- /dev/null +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -0,0 +1,75 @@ +using Trixi, OrdinaryDiffEq + +polydeg = 3 +r1D, w1D = StartUpDG.gauss_lobatto_quad(0, 0, polydeg) +rq, sq = vec.(StartUpDG.NodesAndModes.meshgrid(r1D, r1D)) +wq = (x->x[1] .* x[2])(vec.(StartUpDG.NodesAndModes.meshgrid(w1D, w1D))) + +dg = DGMulti(polydeg = polydeg, element_type = Quad(), approximation_type = Polynomial(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm(); + quad_rule_vol=(rq,sq,wq), quad_rule_face=(r1D,w1D)) + +get_diffusivity() = 5.0e-2 + +equations = LinearScalarAdvectionEquation2D(1.0, 0.0) +equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) + +# from "Robust DPG methods for transient convection-diffusion." +# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. +# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +function initial_condition_erikkson_johnson(x, t, equations) + l = 4 + epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_erikkson_johnson + +# tag different boundary segments +left(x, tol=50*eps()) = abs(x[1] + 1) < tol +right(x, tol=50*eps()) = abs(x[1]) < tol +bottom(x, tol=50*eps()) = abs(x[2] + .5) < tol +top(x, tol=50*eps()) = abs(x[2] - .5) < tol +entire_boundary(x, tol=50*eps()) = true +is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom, + :entire_boundary => entire_boundary) +mesh = DGMultiMesh(dg; coordinates_min=(-1.0, -0.5), coordinates_max=(0.0, 0.5), + cells_per_dimension=(16, 16), is_on_boundary) + +# BC types +boundary_condition = BoundaryConditionDirichlet(initial_condition) + +# define inviscid boundary conditions +boundary_conditions = (; :left => boundary_condition, + :top => boundary_condition, + :bottom => boundary_condition, + :right => boundary_condition_do_nothing) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :entire_boundary => boundary_condition) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) + +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary From 8471273b6a96bad5317e5d412bc25ca637970804 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:08:30 -0500 Subject: [PATCH 039/143] naming equations as parabolic/hyperbolic --- src/equations/laplace_diffusion_2d.jl | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index c171741716b..1baa08c8199 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -6,49 +6,49 @@ with diffusivity ``\kappa`` applied to each solution component defined by `equat """ struct LaplaceDiffusion2D{E, N, T} <: AbstractLaplaceDiffusionEquations{2, N} diffusivity::T - equations::E + equations_hyperbolic::E end -LaplaceDiffusion2D(diffusivity, equations) = - LaplaceDiffusion2D{typeof(equations), nvariables(equations), typeof(diffusivity)}(diffusivity, equations) +LaplaceDiffusion2D(diffusivity, equations_hyperbolic) = + LaplaceDiffusion2D{typeof(equations_hyperbolic), nvariables(equations_hyperbolic), typeof(diffusivity)}(diffusivity, equations_hyperbolic) varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) = - varnames(variable_mapping, equations_parabolic.equations) + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -function flux(u, grad_u, equations::LaplaceDiffusion2D) +function flux(u, grad_u, equations_parabolic::LaplaceDiffusion2D) dudx, dudy = grad_u - return SVector(equations.diffusivity * dudx, equations.diffusivity * dudy) + return SVector(equations_parabolic.diffusivity * dudx, equations_parabolic.diffusivity * dudy) end # TODO: should this remain in the equations file, be moved to solvers, or live in the elixir? # The penalization depends on the solver, but also depends explicitly on physical parameters, # and would probably need to be specialized for every different equation. -function penalty(u_outer, u_inner, inv_h, equations::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) - return dg.penalty_parameter * (u_outer - u_inner) * equations.diffusivity * inv_h +function penalty(u_outer, u_inner, inv_h, equations_parabolic::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) + return dg.penalty_parameter * (u_outer - u_inner) * equations_parabolic.diffusivity * inv_h end # Dirichlet-type boundary condition for use with a parabolic solver in weak form -@inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::LaplaceDiffusion2D) - return boundary_condition.boundary_value_function(x, t, equations) + equations_parabolic::LaplaceDiffusion2D) + return boundary_condition.boundary_value_function(x, t, equations_parabolic) end -@inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::LaplaceDiffusion2D) - return u_inner + equations_parabolic::LaplaceDiffusion2D) + return flux_inner end -@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::LaplaceDiffusion2D) - return boundary_condition.boundary_normal_flux_function(x, t, equations) + equations_parabolic::LaplaceDiffusion2D) + return boundary_condition.boundary_normal_flux_function(x, t, equations_parabolic) end -@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::LaplaceDiffusion2D) + equations_parabolic::LaplaceDiffusion2D) return flux_inner end From 96667e655695b3b6f3694845ff4ad8941e7f7c06 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:08:51 -0500 Subject: [PATCH 040/143] generalizing transform_variables --- src/solvers/dgmulti/dg_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 3ad91627f63..a9279dde599 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -41,7 +41,7 @@ end # Transform solution variables prior to taking the gradient # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? -function transform_variables!(u_transformed, u, equations) +function transform_variables!(u_transformed, u, extra_args...) @threaded for i in eachindex(u) u_transformed[i] = u[i] end From 73e4740c50c9940e926ef7bd8fbc365bc1b10785 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:10:32 -0500 Subject: [PATCH 041/143] add TODO more todos --- src/equations/compressible_navier_stokes_2d.jl | 5 ++++- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index ea360b11f19..68337c860ca 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -41,11 +41,14 @@ or the entropy variables where w_2 = rho v_1 / p, w_3 = rho v_2 / p, w_4 = -rho / p """ + # TODO: # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations # 2) Add more here and probably some equations -struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 3} + +# TODO: Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function +struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index fabc79ff46e..3d92cfa5744 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -307,7 +307,11 @@ function calc_gradient_boundary_flux_by_direction!(surface_flux_values::Abstract else # Element is on the right, boundary on the left u_inner = u_rr end - flux_inner = u_inner # TODO: revisit if we want to generalize beyond BR1, LDG. + + # TODO: revisit if we want more general boundary treatments. + # This assumes the gradient numerical flux at the boundary is the gradient variable, + # which is consistent with BR1, LDG. + flux_inner = u_inner x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) flux = boundary_condition(flux_inner, u_inner, get_unsigned_normal_vector_2d(direction), @@ -373,9 +377,11 @@ function calc_divergence_boundary_flux_by_direction!(surface_flux_values::Abstra x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) - # TODO: we are passing in `u_inner = nothing` since we overwrite cache.boundaries.u with gradient information. - # This currently works with Dirichlet/Neuman boundary conditions for LaplaceDiffusion2D and NoSlipWall and Adiabatic - # boundary conditions for CompressibleNavierStokesEquations2D as of 2022-6-27. It may not work with future implementations. + # TODO: add a field in `cache.boundaries` for gradient information. + # Here, we pass in `u_inner = nothing` since we overwrite cache.boundaries.u with gradient information. + # This currently works with Dirichlet/Neuman boundary conditions for LaplaceDiffusion2D and + # NoSlipWall/Adiabatic boundary conditions for CompressibleNavierStokesEquations2D as of 2022-6-27. + # It will not work with implementations which utilize `u_inner` to impose boundary conditions. flux = boundary_condition(flux_inner, nothing, get_unsigned_normal_vector_2d(direction), x, t, Divergence(), equations_parabolic) From 2c05f6645fbb39a8b3fb046fb3b6de0695ea3b7f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:10:15 -0500 Subject: [PATCH 042/143] additional checks on get_unsigned_normal --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 3d92cfa5744..89461342ca5 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -253,7 +253,7 @@ end # TODO: decide if we should keep this, and if so, extend to 3D. function get_unsigned_normal_vector_2d(direction) - if direction > 4 + if direction > 4 || direction < 1 @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." end if direction==1 || direction==2 From d5e7f9e9f30ad122dd1d329c0f2d77cfa95ac921 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:11:21 -0500 Subject: [PATCH 043/143] adding isothermal BC --- src/Trixi.jl | 2 +- .../compressible_navier_stokes_2d.jl | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 76482b841c1..75507ec1fc4 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -164,7 +164,7 @@ export boundary_condition_do_nothing, boundary_condition_noslip_wall, boundary_condition_slip_wall, boundary_condition_wall, - BoundaryConditionViscousWall, NoSlip, Adiabatic + BoundaryConditionViscousWall, NoSlip, Adiabatic, Isothermal export initial_condition_convergence_test, source_terms_convergence_test export source_terms_harmonic diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 68337c860ca..1078c759d7e 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -230,25 +230,45 @@ struct NoSlip{F} boundary_value_function::F # value of the velocity vector on the boundary end +# isothermal temperature BC +struct Isothermal{F} + boundary_value_function::F # value of the temperature on the boundary +end + # adiabatic temperature BC struct Adiabatic{F} boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, equations::CompressibleNavierStokesEquations2D) - rho = u_inner[1] # should not matter since the viscous terms don't depend on rho v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) - return SVector(rho, v1, v2, u_inner[4]) + return SVector(zero(eltype(u_inner)), v1, v2, u_inner[4]) end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, equations::CompressibleNavierStokesEquations2D) + # rho, v1, v2, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) - tau_1n, tau_2n = flux_inner[2:3] + tau_1n, tau_2n = flux_inner[2:3] # extract fluxes for 2nd and 3rd equations normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux return SVector(flux_inner[1:3]..., normal_energy_flux) end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Gradient, + equations::CompressibleNavierStokesEquations2D) + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) + return SVector(zero(eltype(flux_inner)), v1, v2, T) +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Divergence, + equations::CompressibleNavierStokesEquations2D) + return flux_inner +end + From 89acae836971f9aa9819b0be78c55d9a8e775c58 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:11:36 -0500 Subject: [PATCH 044/143] commenting out unused CNS functions for now --- .../compressible_navier_stokes_2d.jl | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 1078c759d7e..48477e754d0 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -175,40 +175,40 @@ end -# Convert conservative variables to entropy -@inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) - rho, rho_v1, rho_v2, rho_e = u +# # Convert conservative variables to entropy +# @inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) +# rho, rho_v1, rho_v2, rho_e = u - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v_square = v1^2 + v2^2 - p = (equations.gamma - 1) * (rho_e - 0.5 * rho * v_square) +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# v_square = v1^2 + v2^2 +# p = (equations.gamma - 1) * (rho_e - 0.5 * rho * v_square) - rho_p = rho / p +# rho_p = rho / p - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = -rho_p +# w2 = rho_p * v1 +# w3 = rho_p * v2 +# w4 = -rho_p - return SVector(w2, w3, w4) -end +# return SVector(w2, w3, w4) +# end -@inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokesEquations2D) -# Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and -# reverse engineers the gradients to be terms of the primitive vairables (v1, v2, T). -# Helpful because then the diffusive fluxes have the same form as on paper. - rho, rho_v1, rho_v2, _ = u +# @inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokesEquations2D) +# # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and +# # reverse engineers the gradients to be terms of the primitive variables (v1, v2, T). +# # Helpful because then the diffusive fluxes have the same form as on paper. +# rho, rho_v1, rho_v2, _ = u - v1 = rho_v1 / rho - v2 = rho_v2 / rho - T = temperature(u, equations) +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# T = temperature(u, equations) - return SVector(equations.R * T * (grad_entropy_vars[1] + v1 * grad_entropy_vars[3]), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) - equations.R * T * (grad_entropy_vars[2] + v2 * grad_entropy_vars[3]), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) - equations.R * T * T * grad_entropy_vars[3] # grad(T) = R*T^2*grad(w_4)) - ) -end +# return SVector(equations.R * T * (grad_entropy_vars[1] + v1 * grad_entropy_vars[3]), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) +# equations.R * T * (grad_entropy_vars[2] + v2 * grad_entropy_vars[3]), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) +# equations.R * T * T * grad_entropy_vars[3] # grad(T) = R*T^2*grad(w_4)) +# ) +# end @inline function temperature(u, equations::CompressibleNavierStokesEquations2D) From f503b85b4693f51e3c79a75de710a3bd6efe927e Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:12:46 -0500 Subject: [PATCH 045/143] fix call to transform_variables --- src/solvers/dgmulti/dg_parabolic.jl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index a9279dde599..be6fc066f73 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -101,7 +101,7 @@ function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, scalar_flux_face_values[idM] = 0.5 * (uP + uM) # TODO: use strong/weak formulation for curved meshes? end - calc_boundary_flux!(scalar_flux_face_values, nothing, t, Gradient(), boundary_conditions, + calc_boundary_flux!(scalar_flux_face_values, u_face_values, t, Gradient(), boundary_conditions, mesh, equations, dg, cache, cache_parabolic) # compute surface contributions @@ -158,10 +158,9 @@ function calc_single_boundary_flux!(flux_face_values, u_face_values, t, # for both the gradient and the divergence, the boundary flux is scalar valued. # for the gradient, it is the solution; for divergence, it is the normal flux. - u_boundary = boundary_condition(flux_face_values[fid,e], - face_normal, face_coordinates, t, - operator_type, equations) - flux_face_values[fid,e] = u_boundary + flux_face_values[fid,e] = boundary_condition(flux_face_values[fid,e], u_face_values[fid,e], + face_normal, face_coordinates, t, + operator_type, equations) end end return nothing @@ -299,7 +298,7 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra reset_du!(du, dg) @unpack u_transformed, u_grad, viscous_flux = cache_parabolic - transform_variables!(u_transformed, u, equations_parabolic) + transform_variables!(u_transformed, u, mesh, dg, dg_parabolic, equations_parabolic) calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) From 41b41a9f37bb7c1f521dab7b9fbbf9734a41d9dc Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:17:08 -0500 Subject: [PATCH 046/143] comments and cleanup --- src/solvers/dgmulti/dg_parabolic.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index be6fc066f73..54f8c6e9924 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -265,14 +265,14 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh for dim in eachdim(mesh) uM = viscous_flux_face_values[dim][idM] uP = viscous_flux_face_values[dim][idP] - # TODO: use strong/weak formulation? + # TODO: use strong/weak formulation to ensure stability on curved meshes? flux_face_value = flux_face_value + 0.5 * (uP + uM) * nxyzJ[dim][face_node_index] end scalar_flux_face_values[idM] = flux_face_value end # TODO: decide what to pass in - calc_boundary_flux!(scalar_flux_face_values, nothing, t, Divergence(), + calc_boundary_flux!(scalar_flux_face_values, cache_parabolic.u_face_values, t, Divergence(), boundary_conditions, mesh, equations, dg, cache, cache_parabolic) calc_viscous_penalty!(scalar_flux_face_values, cache_parabolic.u_face_values, t, From 1107def502cf1f39233a1105b5a1c96c8b39011a Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 15:58:20 -0500 Subject: [PATCH 047/143] changing default solver and Re for cavity --- .../dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index 63bb1ce29f8..d93cff55c5f 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -7,13 +7,13 @@ using Trixi equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=100, Prandtl=0.72, +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, Mach_freestream=0.1, kappa=1.0) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux -dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), - volume_integral = VolumeIntegralWeakForm()) + volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) top(x, tol=50*eps()) = abs(x[2] - 1) < tol rest_of_boundary(x, tol=50*eps()) = !top(x, tol) @@ -52,7 +52,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol # ODE solvers, callbacks etc. # Create ODE problem with time span from 0.0 to 1.5 -tspan = (0.0, 25.0) +tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() From f90afb97e3d783404998f355bca9ff26d794b749 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 16:47:37 -0500 Subject: [PATCH 048/143] adding more advection diffusion tests --- test/test_parabolic_2d.jl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 4a792af4840..8ac13d581ce 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -78,11 +78,19 @@ isdir(outdir) && rm(outdir, recursive=true) ) end - @trixi_testset "elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion.jl"), + @trixi_testset "elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_nonperiodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.2485803335154642], - linf = [1.079606969242132] + l2 = [0.012561479036088107], + linf = [0.10067620068384618] + ) + end + + @trixi_testset "elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + l2 = [0.0076468006081234705], + linf = [0.10067621027072088] ) end From 2e7019feb07b8a2b064c2151c3bb757df3c13aec Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 19:38:39 -0500 Subject: [PATCH 049/143] label tests --- test/test_parabolic_2d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 8ac13d581ce..a9d208b8fbc 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -70,7 +70,7 @@ isdir(outdir) && rm(outdir, recursive=true) @test getindex.(du, 1) ≈ 2 * y end - @trixi_testset "elixir_advection_diffusion_periodic.jl" begin + @trixi_testset "DGMulti: elixir_advection_diffusion_periodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_periodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), l2 = [0.03180371984888462], @@ -78,7 +78,7 @@ isdir(outdir) && rm(outdir, recursive=true) ) end - @trixi_testset "elixir_advection_diffusion_nonperiodic.jl" begin + @trixi_testset "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_nonperiodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), l2 = [0.012561479036088107], @@ -86,7 +86,7 @@ isdir(outdir) && rm(outdir, recursive=true) ) end - @trixi_testset "elixir_advection_diffusion_nonperiodic.jl" begin + @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), l2 = [0.0076468006081234705], From 063b602ebdb06a09be0f1cb34d5f24cdc86c6a83 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 19:39:27 -0500 Subject: [PATCH 050/143] add gradient_variables field to SemidiscretizationHyperbolicParabolic --- ...semidiscretization_hyperbolic_parabolic.jl | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index 52a48d7aa03..4c960066cf6 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -11,7 +11,7 @@ A struct containing everything needed to describe a spatial semidiscretization of a mixed hyperbolic-parabolic conservation law. """ -struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, InitialCondition, +struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} <: AbstractSemidiscretization @@ -20,6 +20,8 @@ struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic equations::Equations equations_parabolic::EquationsParabolic + gradient_variables::GradientVariables + # This guy is a bit messy since we abuse it as some kind of "exact solution" # although this doesn't really exist... initial_condition::InitialCondition @@ -37,17 +39,18 @@ struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic performance_counter::PerformanceCounter - function SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic}( - mesh::Mesh, equations::Equations, equations_parabolic::EquationsParabolic, initial_condition::InitialCondition, + function SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic}( + mesh::Mesh, equations::Equations, equations_parabolic::EquationsParabolic, + gradient_variables::GradientVariables, initial_condition::InitialCondition, boundary_conditions::BoundaryConditions, boundary_conditions_parabolic::BoundaryConditionsParabolic, - source_terms::SourceTerms, solver::Solver, solver_parabolic::SolverParabolic, cache::Cache, cache_parabolic::CacheParabolic) where {Mesh, Equations, EquationsParabolic, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} + source_terms::SourceTerms, solver::Solver, solver_parabolic::SolverParabolic, cache::Cache, cache_parabolic::CacheParabolic) where {Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} @assert ndims(mesh) == ndims(equations) # Todo: assert nvariables(equations)==nvariables(equations_parabolic) performance_counter = PerformanceCounter() - new(mesh, equations, equations_parabolic, initial_condition, + new(mesh, equations, equations_parabolic, gradient_variables, initial_condition, boundary_conditions, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic, performance_counter) end @@ -55,6 +58,7 @@ end """ SemidiscretizationHyperbolicParabolic(mesh, both_equations, initial_condition, solver; + gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, both_boundary_conditions=(boundary_condition_periodic, boundary_condition_periodic), @@ -66,6 +70,7 @@ Construct a semidiscretization of a hyperbolic-parabolic PDE. """ function SemidiscretizationHyperbolicParabolic(mesh, equations::Tuple, initial_condition, solver; + gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, boundary_conditions=(boundary_condition_periodic, boundary_condition_periodic), @@ -79,7 +84,8 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations::Tuple, initial_hyperbolic_cache, initial_cache_parabolic = initial_caches return SemidiscretizationHyperbolicParabolic(mesh, equations_hyperbolic, equations_parabolic, - initial_condition, solver; solver_parabolic, source_terms, + initial_condition, solver; + gradient_variables, solver_parabolic, source_terms, boundary_conditions=boundary_conditions_hyperbolic, boundary_conditions_parabolic=boundary_conditions_parabolic, RealT, uEltype, initial_cache=initial_hyperbolic_cache, @@ -88,6 +94,7 @@ end function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabolic, initial_condition, solver; + gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, boundary_conditions=boundary_condition_periodic, @@ -106,10 +113,10 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabo solver, solver_parabolic, RealT, uEltype)..., initial_cache_parabolic...) - SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), + SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), typeof(gradient_variables), typeof(initial_condition), typeof(_boundary_conditions), typeof(_boundary_conditions_parabolic), typeof(source_terms), typeof(solver), typeof(solver_parabolic), typeof(cache), typeof(cache_parabolic)}( - mesh, equations, equations_parabolic, initial_condition, + mesh, equations, equations_parabolic, gradient_variables, initial_condition, _boundary_conditions, _boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic) end @@ -124,6 +131,7 @@ function remake(semi::SemidiscretizationHyperbolicParabolic; uEltype=real(semi.s mesh=semi.mesh, equations=semi.equations, equations_parabolic=semi.equations_parabolic, + gradient_variables=semi.gradient_variables, initial_condition=semi.initial_condition, solver=semi.solver, solver_parabolic=semi.solver_parabolic, @@ -135,7 +143,7 @@ function remake(semi::SemidiscretizationHyperbolicParabolic; uEltype=real(semi.s # special care if shock-capturing volume integrals are used (because of # the indicators and their own caches...). SemidiscretizationHyperbolicParabolic( - mesh, equations, equations_parabolic, initial_condition, solver; solver_parabolic, source_terms, boundary_conditions, boundary_conditions_parabolic, uEltype) + mesh, equations, equations_parabolic, gradient_variables, initial_condition, solver; solver_parabolic, source_terms, boundary_conditions, boundary_conditions_parabolic, uEltype) end function Base.show(io::IO, semi::SemidiscretizationHyperbolicParabolic) @@ -145,6 +153,7 @@ function Base.show(io::IO, semi::SemidiscretizationHyperbolicParabolic) print(io, semi.mesh) print(io, ", ", semi.equations) print(io, ", ", semi.equations_parabolic) + print(io, ", ", semi.gradient_variables) print(io, ", ", semi.initial_condition) print(io, ", ", semi.boundary_conditions) print(io, ", ", semi.boundary_conditions_parabolic) @@ -170,6 +179,7 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationHyperboli summary_line(io, "mesh", semi.mesh) summary_line(io, "hyperbolic equations", semi.equations |> typeof |> nameof) summary_line(io, "parabolic equations", semi.equations_parabolic |> typeof |> nameof) + summary_line(io, "gradient variables", semi.gradient_variables |> typeof |> nameof) summary_line(io, "initial condition", semi.initial_condition) # print_boundary_conditions(io, semi) @@ -243,8 +253,11 @@ function rhs!(du_ode, u_ode, semi::SemidiscretizationHyperbolicParabolic, t) end function rhs_parabolic!(du_ode, u_ode, semi::SemidiscretizationHyperbolicParabolic, t) - @unpack mesh, equations_parabolic, initial_condition, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic = semi + @unpack mesh, equations, equations_parabolic, initial_condition, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic = semi + # TODO: clean up. We wrap_array using `equations` and not `equations_parabolic`. + # This is because `u` is a hyperbolic solution and `equations_parabolic` can have a + # different number of variables for something like CompressibleNavierStokesEquations2D u = wrap_array(u_ode, mesh, equations_parabolic, solver, cache_parabolic) du = wrap_array(du_ode, mesh, equations_parabolic, solver, cache_parabolic) From 50d76df032bbf9c3c7614e81ebb823a4968a40be Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 27 Jun 2022 19:39:27 -0500 Subject: [PATCH 051/143] Revert "add gradient_variables field to SemidiscretizationHyperbolicParabolic" This reverts commit 063b602ebdb06a09be0f1cb34d5f24cdc86c6a83. --- ...semidiscretization_hyperbolic_parabolic.jl | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index 4c960066cf6..52a48d7aa03 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -11,7 +11,7 @@ A struct containing everything needed to describe a spatial semidiscretization of a mixed hyperbolic-parabolic conservation law. """ -struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, +struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} <: AbstractSemidiscretization @@ -20,8 +20,6 @@ struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic equations::Equations equations_parabolic::EquationsParabolic - gradient_variables::GradientVariables - # This guy is a bit messy since we abuse it as some kind of "exact solution" # although this doesn't really exist... initial_condition::InitialCondition @@ -39,18 +37,17 @@ struct SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic performance_counter::PerformanceCounter - function SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic}( - mesh::Mesh, equations::Equations, equations_parabolic::EquationsParabolic, - gradient_variables::GradientVariables, initial_condition::InitialCondition, + function SemidiscretizationHyperbolicParabolic{Mesh, Equations, EquationsParabolic, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic}( + mesh::Mesh, equations::Equations, equations_parabolic::EquationsParabolic, initial_condition::InitialCondition, boundary_conditions::BoundaryConditions, boundary_conditions_parabolic::BoundaryConditionsParabolic, - source_terms::SourceTerms, solver::Solver, solver_parabolic::SolverParabolic, cache::Cache, cache_parabolic::CacheParabolic) where {Mesh, Equations, EquationsParabolic, GradientVariables, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} + source_terms::SourceTerms, solver::Solver, solver_parabolic::SolverParabolic, cache::Cache, cache_parabolic::CacheParabolic) where {Mesh, Equations, EquationsParabolic, InitialCondition, BoundaryConditions, BoundaryConditionsParabolic, SourceTerms, Solver, SolverParabolic, Cache, CacheParabolic} @assert ndims(mesh) == ndims(equations) # Todo: assert nvariables(equations)==nvariables(equations_parabolic) performance_counter = PerformanceCounter() - new(mesh, equations, equations_parabolic, gradient_variables, initial_condition, + new(mesh, equations, equations_parabolic, initial_condition, boundary_conditions, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic, performance_counter) end @@ -58,7 +55,6 @@ end """ SemidiscretizationHyperbolicParabolic(mesh, both_equations, initial_condition, solver; - gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, both_boundary_conditions=(boundary_condition_periodic, boundary_condition_periodic), @@ -70,7 +66,6 @@ Construct a semidiscretization of a hyperbolic-parabolic PDE. """ function SemidiscretizationHyperbolicParabolic(mesh, equations::Tuple, initial_condition, solver; - gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, boundary_conditions=(boundary_condition_periodic, boundary_condition_periodic), @@ -84,8 +79,7 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations::Tuple, initial_hyperbolic_cache, initial_cache_parabolic = initial_caches return SemidiscretizationHyperbolicParabolic(mesh, equations_hyperbolic, equations_parabolic, - initial_condition, solver; - gradient_variables, solver_parabolic, source_terms, + initial_condition, solver; solver_parabolic, source_terms, boundary_conditions=boundary_conditions_hyperbolic, boundary_conditions_parabolic=boundary_conditions_parabolic, RealT, uEltype, initial_cache=initial_hyperbolic_cache, @@ -94,7 +88,6 @@ end function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabolic, initial_condition, solver; - gradient_variables=cons2cons, solver_parabolic=default_parabolic_solver(), source_terms=nothing, boundary_conditions=boundary_condition_periodic, @@ -113,10 +106,10 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabo solver, solver_parabolic, RealT, uEltype)..., initial_cache_parabolic...) - SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), typeof(gradient_variables), + SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), typeof(initial_condition), typeof(_boundary_conditions), typeof(_boundary_conditions_parabolic), typeof(source_terms), typeof(solver), typeof(solver_parabolic), typeof(cache), typeof(cache_parabolic)}( - mesh, equations, equations_parabolic, gradient_variables, initial_condition, + mesh, equations, equations_parabolic, initial_condition, _boundary_conditions, _boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic) end @@ -131,7 +124,6 @@ function remake(semi::SemidiscretizationHyperbolicParabolic; uEltype=real(semi.s mesh=semi.mesh, equations=semi.equations, equations_parabolic=semi.equations_parabolic, - gradient_variables=semi.gradient_variables, initial_condition=semi.initial_condition, solver=semi.solver, solver_parabolic=semi.solver_parabolic, @@ -143,7 +135,7 @@ function remake(semi::SemidiscretizationHyperbolicParabolic; uEltype=real(semi.s # special care if shock-capturing volume integrals are used (because of # the indicators and their own caches...). SemidiscretizationHyperbolicParabolic( - mesh, equations, equations_parabolic, gradient_variables, initial_condition, solver; solver_parabolic, source_terms, boundary_conditions, boundary_conditions_parabolic, uEltype) + mesh, equations, equations_parabolic, initial_condition, solver; solver_parabolic, source_terms, boundary_conditions, boundary_conditions_parabolic, uEltype) end function Base.show(io::IO, semi::SemidiscretizationHyperbolicParabolic) @@ -153,7 +145,6 @@ function Base.show(io::IO, semi::SemidiscretizationHyperbolicParabolic) print(io, semi.mesh) print(io, ", ", semi.equations) print(io, ", ", semi.equations_parabolic) - print(io, ", ", semi.gradient_variables) print(io, ", ", semi.initial_condition) print(io, ", ", semi.boundary_conditions) print(io, ", ", semi.boundary_conditions_parabolic) @@ -179,7 +170,6 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationHyperboli summary_line(io, "mesh", semi.mesh) summary_line(io, "hyperbolic equations", semi.equations |> typeof |> nameof) summary_line(io, "parabolic equations", semi.equations_parabolic |> typeof |> nameof) - summary_line(io, "gradient variables", semi.gradient_variables |> typeof |> nameof) summary_line(io, "initial condition", semi.initial_condition) # print_boundary_conditions(io, semi) @@ -253,11 +243,8 @@ function rhs!(du_ode, u_ode, semi::SemidiscretizationHyperbolicParabolic, t) end function rhs_parabolic!(du_ode, u_ode, semi::SemidiscretizationHyperbolicParabolic, t) - @unpack mesh, equations, equations_parabolic, initial_condition, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic = semi + @unpack mesh, equations_parabolic, initial_condition, boundary_conditions_parabolic, source_terms, solver, solver_parabolic, cache, cache_parabolic = semi - # TODO: clean up. We wrap_array using `equations` and not `equations_parabolic`. - # This is because `u` is a hyperbolic solution and `equations_parabolic` can have a - # different number of variables for something like CompressibleNavierStokesEquations2D u = wrap_array(u_ode, mesh, equations_parabolic, solver, cache_parabolic) du = wrap_array(du_ode, mesh, equations_parabolic, solver, cache_parabolic) From 549793ca9dbe0aaaddfab42e2a1c5816ec9e07fe Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 12:12:17 -0500 Subject: [PATCH 052/143] allowing for specialization in transform_variables adding a function `gradient_variable_transformation` which should get specialized if the gradient variables are not conservative variables --- .../compressible_navier_stokes_2d.jl | 13 +++--------- src/equations/equations_parabolic.jl | 4 ++++ src/solvers/dgmulti/dg_parabolic.jl | 8 +++++--- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 20 ++++++++++++++++++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 48477e754d0..217c3810d60 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -80,9 +80,6 @@ function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquatio end -# I was not sure what to do here to allow flexibility of selecting primitive or entropy -# gradient variables. I see that `transform_variables!` just copies data at the moment. - # This is the flexibility a user should have to select the different gradient variable types # varnames(::typeof(cons2prim) , ::CompressibleNavierStokesEquations2D) = ("v1", "v2", "T") # varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") @@ -90,13 +87,9 @@ end varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) -# transform to primitive variables -# TODO: should we have this call a "gradient transformation" field? -function transform_variables!(u_transformed, u, equations_parabolic::CompressibleNavierStokesEquations2D) - @threaded for i in eachindex(u) - u_transformed[i] = cons2prim(u[i], equations_parabolic) - end -end +# we specialize this function to compute gradients of primitive variables instead of +# conservative variables. +gradient_variable_transformation(::CompressibleNavierStokesEquations2D, dg_parabolic) = cons2prim # no orientation specified since the flux is vector-valued # Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index df5f7077ad1..24f2b51503c 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -1,3 +1,7 @@ +# specify transformation of conservative variables prior to taking gradients. +# specialize this function to compute gradients e.g., of primitive variables instead of conservative +gradient_variable_transformation(::AbstractEquationsParabolic, dg_parabolic) = cons2cons + # Linear scalar diffusion for use in linear scalar advection-diffusion problems abstract type AbstractLaplaceDiffusionEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("laplace_diffusion_2d.jl") diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 54f8c6e9924..41a190bdc1a 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -41,9 +41,10 @@ end # Transform solution variables prior to taking the gradient # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? -function transform_variables!(u_transformed, u, extra_args...) +function transform_variables!(u_transformed, u, mesh, equations_parabolic::AbstractEquationsParabolic, + dg::DGMulti, dg_parabolic, cache, cache_parabolic) @threaded for i in eachindex(u) - u_transformed[i] = u[i] + u_transformed[i] = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u[i], equations_parabolic) end end @@ -298,7 +299,8 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra reset_du!(du, dg) @unpack u_transformed, u_grad, viscous_flux = cache_parabolic - transform_variables!(u_transformed, u, mesh, dg, dg_parabolic, equations_parabolic) + transform_variables!(u_transformed, u, mesh, equations_parabolic, + dg, dg_parabolic, cache, cache_parabolic) calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 89461342ca5..1896a5c1a9d 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -16,7 +16,9 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @unpack u_transformed, u_grad = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, - equations_parabolic) + mesh, equations_parabolic, + dg, dg_parabolic, + cache, cache_parabolic) @trixi_timeit timer() "calculate gradient" calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, @@ -39,6 +41,22 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra end +# Transform solution variables prior to taking the gradient +# (e.g., conservative to primitive variables). Defaults to doing nothing. +# TODO: can we avoid copying data? +function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + dg::DG, dg_parabolic, cache, cache_parabolic) + @threaded for element in eachelement(dg, cache) + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_transformed_node = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u_node, equations_parabolic) + set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) + end + end +end + # TODO: dg_parabolic is not a DG type; it contains solver-specific information such as an LDG penalty parameter. function calc_divergence!(du, u, t, viscous_flux, mesh::TreeMesh{2}, equations_parabolic, From 3e3e41f2a1eab1845432997feb1280729f0f4c88 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:47:57 -0500 Subject: [PATCH 053/143] formatting and comments --- .../dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 086c3a995b7..3a263aa0ad1 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -20,7 +20,7 @@ equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) # Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." function initial_condition_erikkson_johnson(x, t, equations) l = 4 - epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to sqrt + epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to the sqrt lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) @@ -46,10 +46,10 @@ mesh = DGMultiMesh(dg; coordinates_min=(-1.0, -0.5), coordinates_max=(0.0, 0.5), boundary_condition = BoundaryConditionDirichlet(initial_condition) # define inviscid boundary conditions -boundary_conditions = (; :left => boundary_condition, - :top => boundary_condition, +boundary_conditions = (; :left => boundary_condition, + :top => boundary_condition, :bottom => boundary_condition, - :right => boundary_condition_do_nothing) + :right => boundary_condition_do_nothing) # define viscous boundary conditions boundary_conditions_parabolic = (; :entire_boundary => boundary_condition) From 63471512ef9568abe98a11d2031cbe8e30cd03ce Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:48:04 -0500 Subject: [PATCH 054/143] reverting elixir --- .../elixir_advection_diffusion_nonperiodic.jl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 3a263aa0ad1..a8e9e3329af 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -1,14 +1,8 @@ using Trixi, OrdinaryDiffEq -polydeg = 3 -r1D, w1D = StartUpDG.gauss_lobatto_quad(0, 0, polydeg) -rq, sq = vec.(StartUpDG.NodesAndModes.meshgrid(r1D, r1D)) -wq = (x->x[1] .* x[2])(vec.(StartUpDG.NodesAndModes.meshgrid(w1D, w1D))) - -dg = DGMulti(polydeg = polydeg, element_type = Quad(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), - volume_integral = VolumeIntegralWeakForm(); - quad_rule_vol=(rq,sq,wq), quad_rule_face=(r1D,w1D)) + volume_integral = VolumeIntegralWeakForm()) get_diffusivity() = 5.0e-2 From eb98568296d02ec14e864c0b65b1add7a2b1e453 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:48:17 -0500 Subject: [PATCH 055/143] comments --- examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index 2dce083330e..c49ca70aadf 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -38,7 +38,6 @@ function initial_condition_erikkson_johnson(x, t, equations) end initial_condition = initial_condition_erikkson_johnson -# define periodic boundary conditions everywhere boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), y_neg = BoundaryConditionDirichlet(initial_condition), y_pos = BoundaryConditionDirichlet(initial_condition), From 766cdc5b8e703937be7d2eda9b1a682563278dd0 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:48:35 -0500 Subject: [PATCH 056/143] standardizing time tol --- .../tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index c49ca70aadf..c55459ae56b 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -79,7 +79,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1.0e-10 +time_int_tol = 1.0e-8 sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, save_everystep=false, callback=callbacks) From c865fb78d9c05df01f507cb5677ccc79c90bd94a Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:49:23 -0500 Subject: [PATCH 057/143] minor fix to CNS boundary flux for convenience make it so that the density state is computed correctly, even though it's not used --- src/equations/compressible_navier_stokes_2d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 217c3810d60..777300779e5 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -237,7 +237,7 @@ end x, t, operator_type::Gradient, equations::CompressibleNavierStokesEquations2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) - return SVector(zero(eltype(u_inner)), v1, v2, u_inner[4]) + return SVector(u_inner[1], v1, v2, u_inner[4]) end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, From 08768a7ad29fc0b2ed3f8b7bb4eccdc7fc0cf6d5 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:49:33 -0500 Subject: [PATCH 058/143] formatting + comments --- src/equations/compressible_navier_stokes_2d.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 777300779e5..8527f5bbf9e 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -116,16 +116,16 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # Components of viscous stress tensor - # (4/3*(v1)_x - 2/3*(v2)_y) + # (4/3 * (v1)_x - 2/3 * (v2)_y) tau_11 = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) # ((v1)_y + (v2)_x) # stress tensor is symmetric tau_12 = ( dv1dy + dv2dx ) # = tau_21 - # (4/3*(v2)_y - 2/3*(v1)_x) + # (4/3 * (v2)_y - 2/3 * (v1)_x) tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) - # Fick's law q = -kappa*grad(T); constant is kappa*gamma/(Pr*(gamma-1)) - # Important note! Due to nondimensional scaling R = 1/gamma, so the + # Fick's law q = -kappa * grad(T); constant is kappa * gamma / (Pr * (gamma-1)) + # Important note! Due to nondimensional scaling R = 1 / gamma, so the # temperature T in the gradient computation already contains a factor of gamma q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr @@ -144,7 +144,6 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) g1 = zero(rho) g2 = f3 # tau_21 * nu g3 = tau_22 * nu - # g4 = ( v1 * tau_21 + v2 * tau_22 + q2 ) * nu g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * nu return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) From 6c38bdbba6e120405acafebc10a58ab39af326ea Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:50:02 -0500 Subject: [PATCH 059/143] using primitive variables in viscous flux instead of conservative --- src/equations/compressible_navier_stokes_2d.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 8527f5bbf9e..7161e1f7783 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -105,10 +105,7 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # Here grad_u is assumed to contain the gradients of the primitive variables (v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function - rho, rho_v1, rho_v2, _ = u - - v1 = rho_v1 / rho - v2 = rho_v2 / rho + rho, v1, v2, _ = u # grad_u contains derivatives of each hyperbolic variable _, dv1dx, dv2dx, dTdx = grad_u[1] From 0f67dd07bd902cab803583812c91f834cdf2e423 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 22:50:49 -0500 Subject: [PATCH 060/143] minor formatting --- .../dgmulti_2d/elixir_navier_stokes_convergence.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index 21ab09aac06..a72ab18ab1b 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -4,10 +4,13 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations +get_Re() = 100 +get_Pr() = .72 + equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), Mach_freestream=0.5, kappa=1.0) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -50,8 +53,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 kappa = 1 inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = 0.72 - Re = 100 + Pr = get_Pr() + Re = get_Re() # Same settings as in `initial_condition` # Amplitude and shift @@ -186,7 +189,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol # Create ODE problem with time span from 0.0 to 1.5 tspan = (0.0, .50) -ode = semidiscretize(semi, tspan); +ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() alive_callback = AliveCallback(alive_interval=10) From 6a1d908bdba547e3d7e7b754f585cfe1e0c6491a Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 23:27:15 -0500 Subject: [PATCH 061/143] add CNS tests --- test/test_parabolic_2d.jl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index a9d208b8fbc..2aae2ed279e 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -71,7 +71,7 @@ isdir(outdir) && rm(outdir, recursive=true) end @trixi_testset "DGMulti: elixir_advection_diffusion_periodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_periodic.jl"), + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_periodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), l2 = [0.03180371984888462], linf = [0.2136821621370909] @@ -79,13 +79,21 @@ isdir(outdir) && rm(outdir, recursive=true) end @trixi_testset "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_nonperiodic.jl"), + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_nonperiodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), l2 = [0.012561479036088107], linf = [0.10067620068384618] ) end + @trixi_testset "DGMulti: elixir_navier_stokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navier_stokes_convergence.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.1), + l2 = [0.00153550768125133, 0.0033843168272696357, 0.0036531858107444067, 0.009948436427519428], + linf = [0.005522560467190019, 0.013425258500731063, 0.013962115643483375, 0.027483102120516634] + ) + end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), From 6d5be6c52d2b65df8e402d4b1e57909cd273db08 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 12 Jul 2022 23:49:50 -0500 Subject: [PATCH 062/143] fix test --- test/test_parabolic_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 2aae2ed279e..94ab0235616 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -81,8 +81,8 @@ isdir(outdir) && rm(outdir, recursive=true) @trixi_testset "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_nonperiodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.012561479036088107], - linf = [0.10067620068384618] + l2 = [0.002123168335604323], + linf = [0.00963640423513712] ) end From bc58754f578f2497c6b905af9756ba8611113606 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 13 Jul 2022 08:27:50 -0500 Subject: [PATCH 063/143] testing if scoping issues fix TreeMesh tests --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 1896a5c1a9d..e4ce2a3a775 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -470,7 +470,7 @@ function calc_gradient!(u_grad, u, t, # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @unpack surface_flux_values = cache_parabolic.elements - @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + @unpack neighbor_ids, orientations = cache_parabolic.interfaces @threaded for interface in eachinterface(dg, cache_parabolic) # Get neighboring elements @@ -485,7 +485,8 @@ function calc_gradient!(u_grad, u, t, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) + u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, + equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage From f13045a8b7c637be1b9c8a7cc5856cdde6e4fa6f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 13 Jul 2022 11:31:25 -0500 Subject: [PATCH 064/143] decreasing timestep tol for TreeMesh parabolic test --- .../tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl | 2 +- test/test_parabolic_2d.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index c55459ae56b..74d0e83bdf0 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -79,7 +79,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1.0e-8 +time_int_tol = 1.0e-11 sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, save_everystep=false, callback=callbacks) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 94ab0235616..929072c9376 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -97,8 +97,8 @@ isdir(outdir) && rm(outdir, recursive=true) @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), - l2 = [0.0076468006081234705], - linf = [0.10067621027072088] + l2 = [0.007646800618485118], + linf = [0.10067621050468958] ) end From d29d583b1f75acaf0a8a9443a968f6fd3f65612f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 13 Jul 2022 16:05:07 -0500 Subject: [PATCH 065/143] enabling periodic BCs for TreeMesh + more tests --- .../elixir_advection_diffusion.jl | 2 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 18 ++++++++++++++++-- test/test_parabolic_2d.jl | 8 ++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index 1706d4d4184..d9ea702ea7c 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -77,7 +77,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1.0e-8 +time_int_tol = 1.0e-11 sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, save_everystep=false, callback=callbacks) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index e4ce2a3a775..a126da4afe9 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -122,7 +122,7 @@ function calc_divergence!(du, u, t, viscous_flux, # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @unpack surface_flux_values = cache_parabolic.elements - @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + @unpack neighbor_ids, orientations = cache_parabolic.interfaces @threaded for interface in eachinterface(dg, cache_parabolic) # Get neighboring elements @@ -137,7 +137,8 @@ function calc_divergence!(du, u, t, viscous_flux, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) + # TODO: should this u be cache_parabolic.interfaces.u?? + u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage @@ -281,6 +282,18 @@ function get_unsigned_normal_vector_2d(direction) end end +function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + return nothing +end + +function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + return nothing +end + function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) @@ -485,6 +498,7 @@ function calc_gradient!(u_grad, u, t, for i in eachnode(dg) # Call pointwise Riemann solver + # TODO: should this be cache_parabolic.interfaces.u?? u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 929072c9376..79084b35878 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -94,6 +94,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.4), polydeg=5, + l2 = [4.0915532997994255e-6], + linf = [2.3040850347877395e-5] + ) + end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), initial_refinement_level = 2, tspan=(0.0, 0.1), From abd020b943c447b3092ee2ac21fb30762e0909dd Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 13 Jul 2022 16:05:26 -0500 Subject: [PATCH 066/143] fix density BC flux (unused, but could be useful) --- src/equations/compressible_navier_stokes_2d.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 7161e1f7783..1ae4ba87ced 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -163,7 +163,6 @@ end prim2cons(u, equations.equations_hyperbolic) - # # Convert conservative variables to entropy # @inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) # rho, rho_v1, rho_v2, rho_e = u @@ -252,7 +251,7 @@ end equations::CompressibleNavierStokesEquations2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) - return SVector(zero(eltype(flux_inner)), v1, v2, T) + return SVector(u_inner[1], v1, v2, T) end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, From 663f4657ceb14ca7ddbccbfba3af12ffefea66bf Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 15 Jul 2022 11:38:35 -0500 Subject: [PATCH 067/143] adding non-working TreeMesh elixirs --- .../elixir_navier_stokes_convergence.jl | 216 ++++++++++++++++++ .../elixir_navier_stokes_lid_driven_cavity.jl | 77 +++++++ 2 files changed, 293 insertions(+) create mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl create mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl new file mode 100644 index 00000000000..8909578982a --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -0,0 +1,216 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +get_Re() = 1000 +get_Pr() = .72 + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), + Mach_freestream=0.5, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=(true, false), + n_cells_max=30_000) # set maximum capacity of tree data structure + + +# Define initial condition +# Note: If you change the parameters here, also change it in the corresponding source terms +function initial_condition_navier_stokes_convergence_test(x, t, equations) + + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + + y = x[2] + + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + kappa = 1 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = get_Pr() + Re = get_Re() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = (; x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_top_bottom, + y_pos = boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, .50) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl new file mode 100644 index 00000000000..4784cb7f890 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -0,0 +1,77 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, + Mach_freestream=0.1, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0, 0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) + +# define periodic boundary conditions everywhere +boundary_conditions = boundary_condition_slip_wall + +boundary_conditions_parabolic = (; x_neg = boundary_condition_cavity, + y_neg = boundary_condition_cavity, + y_pos = boundary_condition_lid, + x_pos = boundary_condition_cavity) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span from 0.0 to 1.5 +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary + + From 5ae580b78255384ec077ee7b516ac04ad7b8db70 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 15 Jul 2022 15:38:01 -0500 Subject: [PATCH 068/143] adding AD checks --- .../elixir_navier_stokes_convergence.jl | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 8909578982a..7ca891b85be 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -211,6 +211,52 @@ callbacks = CallbackSet(summary_callback, alive_callback) # run the simulation time_int_tol = 1e-8 -sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, save_everystep=false, callback=callbacks) summary_callback() # print the timer summary + +############################################################################### +# check accuracy of parabolic terms + +u_exact = (x, y, t) -> initial_condition_navier_stokes_convergence_test(SVector(x,y), t, equations) +dqdx = (x, y, t) -> ForwardDiff.derivative(x -> cons2prim(u_exact(x, y, t), equations_parabolic), x) +dqdy = (x, y, t) -> ForwardDiff.derivative(y -> cons2prim(u_exact(x, y, t), equations_parabolic), y) + +g = (x, y, t) -> Trixi.flux(cons2prim(u_exact(x,y,t), equations_parabolic), + (dqdx(x,y,t), dqdy(x,y,t)), equations_parabolic) +gx = (x, y, t) -> g(x, y, t)[1] +gy = (x, y, t) -> g(x, y, t)[2] + +dgdx = (x,y,t) -> ForwardDiff.derivative(x -> gx(x,y,t), x) +dgdy = (x,y,t) -> ForwardDiff.derivative(y -> gy(x,y,t), y) +div_f = (x,y,t) -> dgdx(x,y,t) + dgdy(x,y,t) + +x = vec(semi.cache.elements.node_coordinates[1, :, :, :]) +y = vec(semi.cache.elements.node_coordinates[2, :, :, :]) +t = tspan[end] + +trixi_wrap(u) = Trixi.wrap_array(vec(reinterpret(reshape, Float64, u)), semi) +dg = semi.solver +dg_parabolic = semi.solver_parabolic +@unpack cache, cache_parabolic = semi +boundary_conditions = semi.boundary_conditions_parabolic +u = u_exact.(x, y, t) +u = trixi_wrap(u) + +# check gradient +@unpack u_transformed, u_grad = cache_parabolic +Trixi.transform_variables!(u_transformed, u, mesh, equations_parabolic, dg, dg_parabolic, cache, cache_parabolic) +Trixi.calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) + +println("error in parabolic gradients: $(maximum(abs.(u_grad[1] - trixi_wrap(dqdx.(x,y,t)))) + maximum(abs.(u_grad[2] - trixi_wrap(dqdy.(x,y,t)))))") + +# check fluxes +Trixi.calc_viscous_fluxes!(u_grad, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) +println("error in parabolic fluxes: $(maximum(abs.(u_grad[1] - trixi_wrap(gx.(x,y,t)))) + maximum(abs.(u_grad[2] - trixi_wrap(gy.(x,y,t)))))") + +# check divergence +du = similar(u) +Trixi.reset_du!(du, dg, cache) +Trixi.calc_divergence!(du, u_transformed, t, u_grad, mesh, equations_parabolic, + boundary_conditions, dg, dg_parabolic, cache, cache_parabolic) +println("error in parabolic divergence: $(maximum(abs.(du - trixi_wrap(div_f.(x,y,t)))))") \ No newline at end of file From bfffc0035c31013918dd53d85b1d234e90a30eed Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 14:26:17 -0500 Subject: [PATCH 069/143] standardizing parameters in convergence elixirs --- .../elixir_navier_stokes_convergence.jl | 4 +- .../elixir_navier_stokes_convergence.jl | 49 +------------------ 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index a72ab18ab1b..f7d96c17c5f 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -14,13 +14,13 @@ equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=ge Mach_freestream=0.5, kappa=1.0) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux -dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = polydeg, element_type = Quad(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) -mesh = DGMultiMesh(dg, cells_per_dimension=(8, 8); periodicity=(true, false), is_on_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), is_on_boundary) # Define initial condition # Note: If you change the parameters here, also change it in the corresponding source terms diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 7ca891b85be..d731af84e32 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations -get_Re() = 1000 +get_Re() = 100 get_Pr() = .72 equations = CompressibleEulerEquations2D(1.4) @@ -25,7 +25,6 @@ mesh = TreeMesh(coordinates_min, coordinates_max, periodicity=(true, false), n_cells_max=30_000) # set maximum capacity of tree data structure - # Define initial condition # Note: If you change the parameters here, also change it in the corresponding source terms function initial_condition_navier_stokes_convergence_test(x, t, equations) @@ -193,7 +192,6 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), source_terms=source_terms_navier_stokes_convergence_test) - ############################################################################### # ODE solvers, callbacks etc. @@ -215,48 +213,3 @@ sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, dt = save_everystep=false, callback=callbacks) summary_callback() # print the timer summary -############################################################################### -# check accuracy of parabolic terms - -u_exact = (x, y, t) -> initial_condition_navier_stokes_convergence_test(SVector(x,y), t, equations) -dqdx = (x, y, t) -> ForwardDiff.derivative(x -> cons2prim(u_exact(x, y, t), equations_parabolic), x) -dqdy = (x, y, t) -> ForwardDiff.derivative(y -> cons2prim(u_exact(x, y, t), equations_parabolic), y) - -g = (x, y, t) -> Trixi.flux(cons2prim(u_exact(x,y,t), equations_parabolic), - (dqdx(x,y,t), dqdy(x,y,t)), equations_parabolic) -gx = (x, y, t) -> g(x, y, t)[1] -gy = (x, y, t) -> g(x, y, t)[2] - -dgdx = (x,y,t) -> ForwardDiff.derivative(x -> gx(x,y,t), x) -dgdy = (x,y,t) -> ForwardDiff.derivative(y -> gy(x,y,t), y) -div_f = (x,y,t) -> dgdx(x,y,t) + dgdy(x,y,t) - -x = vec(semi.cache.elements.node_coordinates[1, :, :, :]) -y = vec(semi.cache.elements.node_coordinates[2, :, :, :]) -t = tspan[end] - -trixi_wrap(u) = Trixi.wrap_array(vec(reinterpret(reshape, Float64, u)), semi) -dg = semi.solver -dg_parabolic = semi.solver_parabolic -@unpack cache, cache_parabolic = semi -boundary_conditions = semi.boundary_conditions_parabolic -u = u_exact.(x, y, t) -u = trixi_wrap(u) - -# check gradient -@unpack u_transformed, u_grad = cache_parabolic -Trixi.transform_variables!(u_transformed, u, mesh, equations_parabolic, dg, dg_parabolic, cache, cache_parabolic) -Trixi.calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) - -println("error in parabolic gradients: $(maximum(abs.(u_grad[1] - trixi_wrap(dqdx.(x,y,t)))) + maximum(abs.(u_grad[2] - trixi_wrap(dqdy.(x,y,t)))))") - -# check fluxes -Trixi.calc_viscous_fluxes!(u_grad, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) -println("error in parabolic fluxes: $(maximum(abs.(u_grad[1] - trixi_wrap(gx.(x,y,t)))) + maximum(abs.(u_grad[2] - trixi_wrap(gy.(x,y,t)))))") - -# check divergence -du = similar(u) -Trixi.reset_du!(du, dg, cache) -Trixi.calc_divergence!(du, u_transformed, t, u_grad, mesh, equations_parabolic, - boundary_conditions, dg, dg_parabolic, cache, cache_parabolic) -println("error in parabolic divergence: $(maximum(abs.(du - trixi_wrap(div_f.(x,y,t)))))") \ No newline at end of file From 17eafbb876388c7a9f699a06ac6a9aab2da13f08 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 14:26:43 -0500 Subject: [PATCH 070/143] minor cleanup --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index a126da4afe9..78445a04b34 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -98,22 +98,16 @@ function calc_divergence!(du, u, t, viscous_flux, right_element = interfaces.neighbor_ids[2, interface] if orientations[interface] == 1 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[1] - # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] - end + # interface in x-direction + for j in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, j, interface] = viscous_flux[1][v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = viscous_flux[1][v, 1, j, right_element] end else # if orientations[interface] == 2 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[2] - # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] - end + # interface in y-direction + for i in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, i, interface] = viscous_flux[2][v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = viscous_flux[2][v, i, 1, right_element] end end end From 0c4e098bd26fe42851c9ec6c3f791c3fb8f9615e Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 14:29:36 -0500 Subject: [PATCH 071/143] revert DGMulti CNS elixir setup back to the one used in tests --- examples/dgmulti_2d/elixir_navier_stokes_convergence.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index f7d96c17c5f..b3af1e0f14f 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -14,7 +14,7 @@ equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=ge Mach_freestream=0.5, kappa=1.0) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux -dg = DGMulti(polydeg = polydeg, element_type = Quad(), approximation_type = Polynomial(), +dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) From b70bbc046c116624ace2d0ab46cbdc9a44ae0690 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 14:29:50 -0500 Subject: [PATCH 072/143] adding TreeMesh CNS convergence test --- test/test_parabolic_2d.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 79084b35878..fee3e83049a 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -110,6 +110,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_navier_stokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_convergence.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + l2 = [0.0021116725306635146, 0.0034322351490824465, 0.003874252819611102, 0.012469246082522416], + linf = [0.012006418939297214, 0.03552087120958058, 0.02451274749176294, 0.11191122588577151] + ) + end + end # Clean up afterwards: delete Trixi output directory From 13e0c8fa0f968c7da1bab33ba837afc8643a0c55 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 17:18:33 -0500 Subject: [PATCH 073/143] removing redundant elixir --- .../elixir_navier_stokes_source_terms.jl | 272 ------------------ 1 file changed, 272 deletions(-) delete mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl deleted file mode 100644 index bd85946f1b3..00000000000 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_source_terms.jl +++ /dev/null @@ -1,272 +0,0 @@ -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal compressible Navier-Stokes equations - -equations = CompressibleEulerEquations2D(1.4) -# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition -# I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, - Reynolds=1000, - Prandtl=0.72, - Mach_freestream=0.5, - kappa=1.0 # thermal diffusivity - ) - -# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) - -coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) -coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) - -# Create a uniformly refined mesh with periodic boundaries -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=30_000) # set maximum capacity of tree data structure - -# Define initial condition -# Note: If you change the parameters here, also change it in the corresponding source terms -function initial_condition_navier_stokes_convergence_test(x, t, equation::CompressibleEulerEquations2D) - - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end - - -initial_condition = initial_condition_navier_stokes_convergence_test - - -@inline function source_terms_navier_stokes_convergence_test(u, x, t, - equations::CompressibleNavierStokesEquations2D) - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * equations.inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * equations.inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * equations.inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * equations.inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * equations.inv_gamma_minus_one * equations.kappa / equations.Pr - inv_Re = 1.0 / equations.Re - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * inv_Re - + 2.0 / 3.0 * v2_xy * inv_Re - - v1_yy * inv_Re - - v2_xy * inv_Re ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * inv_Re - - v2_xx * inv_Re - - 4.0 / 3.0 * v2_yy * inv_Re - + 2.0 / 3.0 * v1_xy * inv_Re ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * inv_Re - + 2.0 / 3.0 * v2_xy * v1 * inv_Re - - 4.0 / 3.0 * v1_x * v1_x * inv_Re - + 2.0 / 3.0 * v2_y * v1_x * inv_Re - - v1_xy * v2 * inv_Re - - v2_xx * v2 * inv_Re - - v1_y * v2_x * inv_Re - - v2_x * v2_x * inv_Re - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * inv_Re - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * inv_Re - - v2_xy * v1 * inv_Re - - v1_y * v1_y * inv_Re - - v2_x * v1_y * inv_Re - - 4.0 / 3.0 * v2_yy * v2 * inv_Re - + 2.0 / 3.0 * v1_xy * v2 * inv_Re - - 4.0 / 3.0 * v2_y * v2_y * inv_Re - + 2.0 / 3.0 * v1_x * v2_y * inv_Re - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * inv_Re ) - - return SVector(du1, du2, du3, du4) -end - - -# TODO: Wasn't sure of the call structure, but this should be what we need -function boundary_condition_no_slip_adiabatic_wall(u_inner, orientation, direction, - x, t, surface_flux_function, - equations::CompressibleEulerEquations2D) - u_boundary = SVector(u_inner[1], -u_inner[2], -u_inner[3], u_inner[4]) - - # Calculate boundary flux - if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary - flux = surface_flux_function(u_inner, u_boundary, orientation, equations) - else # u_boundary is "left" of boundary, u_inner is "right" of boundary - flux = surface_flux_function(u_boundary, u_inner, orientation, equations) - end - - return flux -end - - -# TODO: Wasn't sure of the call structure, but this should be what we need -function boundary_condition_no_slip_adiabatic_wall_neumann(grad_u_inner, orientation, direction, - x, t, surface_flux_function, - equations::CompressibleNavierStokesEquations2D) - # Copy the inner gradients to an external state array - grad_u_boundary .= grad_u_inner - - # Project out the appropriate temperature gradient pieces. Wasn't sure of array shape - if orientation == 1 - grad_u_norm = grad_u[1,3] # temperature gradient in x-direction - u_x_tangent = grad_u[1,3] - grad_u_norm - u_y_tangent = grad_u[2,3] - - # Update the external state gradients - grad_u_boundary[1,3] = u_x_tangent - grad_u_norm - grad_u_boundary[2,3] = u_y_tangent - else # orientation == 2 - grad_u_norm = grad_u[2,3] # temperature gradient in y-direction - u_x_tangent = grad_u[1,3] - u_y_tangent = grad_u[2,3] - grad_u_norm - - # Update the external state gradients - grad_u_boundary[1,3] = u_x_tangent - grad_u_boundary[2,3] = u_y_tangent - grad_u_norm - end - - # Calculate boundary flux (just averages so has no orientation I think) - flux = surface_flux_function(grad_u_inner, grad_u_boundary, orientation, equations) - - return flux -end - - -# Below is my best guess as to how to set periodic in x direction and walls -# in the y direcitons -boundary_condition= ( - x_neg=boundary_condition_periodic, - x_pos=boundary_condition_periodic, - y_neg=boundary_condition_no_slip_adiabatic_wall, - y_pos=boundary_condition_no_slip_adiabatic_wall, - ) -boundary_conditions_parabolic = ( - x_neg=boundary_condition_periodic, - x_pos=boundary_condition_periodic, - y_neg=boundary_condition_no_slip_adiabatic_wall_neumann, - y_pos=boundary_condition_no_slip_adiabatic_wall_neumann, - ) - -# A semidiscretization collects data structures and functions for the spatial discretization -semi = SemidiscretizationHyperbolicParabolic(mesh, - (equations, equations_parabolic), - initial_condition, solver; - boundary_conditions=(boundary_conditions, - boundary_conditions_parabolic)) - - -############################################################################### -# ODE solvers, callbacks etc. - -# Create ODE problem with time span from 0.0 to 1.5 -tspan = (0.0, 1.5) -ode = semidiscretize(semi, tspan); - -# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup -# and resets the timers -summary_callback = SummaryCallback() - -# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) - -# The AliveCallback prints short status information in regular intervals -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver -callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) - - -############################################################################### -# run the simulation - -# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1.0e-8 -sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, - save_everystep=false, callback=callbacks) - -# Print the timer summary -summary_callback() From 8cecb5f47984b313bad84b8c8899934f9b9bd7c2 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 17:26:05 -0500 Subject: [PATCH 074/143] add more tests --- .../elixir_navier_stokes_lid_driven_cavity.jl | 4 ++-- test/test_parabolic_2d.jl | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index 4784cb7f890..c42e7b605ab 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -57,11 +57,11 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol # ODE solvers, callbacks etc. # Create ODE problem with time span from 0.0 to 1.5 -tspan = (0.0, 10.0) +tspan = (0.0, 25.0) ode = semidiscretize(semi, tspan); summary_callback = SummaryCallback() -alive_callback = AliveCallback(alive_interval=10) +alive_callback = AliveCallback(alive_interval=100) analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) callbacks = CallbackSet(summary_callback, alive_callback) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index fee3e83049a..41b8f76d6ad 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -94,6 +94,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "DGMulti: elixir_navier_stokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navier_stokes_lid_driven_cavity.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.5), + l2 = [0.0002215612522711349, 0.028318325921400257, 0.009509168701069035, 0.028267900513539248], + linf = [0.0015622789413053395, 0.14886653390741342, 0.07163235655334241, 0.19472785105216417] + ) + end + @trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), initial_refinement_level = 2, tspan=(0.0, 0.4), polydeg=5, @@ -118,6 +126,14 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_navier_stokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_lid_driven_cavity.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.5), + l2 = [0.0001514457152968994, 0.018766076072331786, 0.007065070765651992, 0.020839900573430787], + linf = [0.0014523369373645734, 0.12366779944955876, 0.055324509971157544, 0.1609992780534526] + ) + end + end # Clean up afterwards: delete Trixi output directory From adb8eca2c14eb7b1f2dbfdfc140384c1d644990c Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 28 Jul 2022 17:26:56 -0500 Subject: [PATCH 075/143] add more test --- test/test_parabolic_2d.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 41b8f76d6ad..42d6b1d3752 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -70,6 +70,14 @@ isdir(outdir) && rm(outdir, recursive=true) @test getindex.(du, 1) ≈ 2 * y end + @trixi_testset "DGMulti: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.1), + l2 = [0.2485803335154642], + linf = [1.079606969242132] + ) + end + @trixi_testset "DGMulti: elixir_advection_diffusion_periodic.jl" begin @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_periodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), From 3281b49a070d232ba9d304143ba9e263fa72ef3a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Jul 2022 09:32:53 +0200 Subject: [PATCH 076/143] Apply suggestions from code review Co-authored-by: Hendrik Ranocha --- .../elixir_navier_stokes_convergence.jl | 6 +++--- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- .../elixir_advection_diffusion_nonperiodic.jl | 2 +- .../elixir_navier_stokes_convergence.jl | 6 +++--- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- src/equations/compressible_navier_stokes_2d.jl | 16 +++++++++------- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index b3af1e0f14f..e922a9cad12 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -5,7 +5,7 @@ using Trixi # semidiscretization of the ideal compressible Navier-Stokes equations get_Re() = 100 -get_Pr() = .72 +get_Pr() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition @@ -187,8 +187,8 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.5 -tspan = (0.0, .50) +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index d93cff55c5f..bdcc3a60607 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -51,7 +51,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.5 +# Create ODE problem with time span `tspan` tspan = (0.0, 10.0) ode = semidiscretize(semi, tspan); diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index 74d0e83bdf0..21e4866189b 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -56,7 +56,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.5 +# Create ODE problem with time span `tspan` tspan = (0.0, 1.5) ode = semidiscretize(semi, tspan); diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index d731af84e32..ee2307a90e7 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -5,7 +5,7 @@ using Trixi # semidiscretization of the ideal compressible Navier-Stokes equations get_Re() = 100 -get_Pr() = .72 +get_Pr() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition @@ -195,8 +195,8 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.5 -tspan = (0.0, .50) +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index c42e7b605ab..2a8fb635895 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -56,7 +56,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabol ############################################################################### # ODE solvers, callbacks etc. -# Create ODE problem with time span from 0.0 to 1.5 +# Create ODE problem with time span `tspan` tspan = (0.0, 25.0) ode = semidiscretize(semi, tspan); diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 1ae4ba87ced..e9be251077a 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -8,23 +8,25 @@ `CompressibleNavierStokesEquations2D` represents the diffusion (i.e. parabolic) terms applied to mass, momenta, and total energy together with the advective from -the `CompressibleEulerEquations2D`. +the [`CompressibleEulerEquations2D`](@ref). -gamma: adiabatic constant, -Re: Reynolds number, -Pr: Prandtl number, -Ma_inf: free-stream Mach number -kappa: thermal diffusivity for Fick's law +- `gamma`: adiabatic constant, +- `Re`: Reynolds number, +- `Pr`: Prandtl number, +- `Ma_inf`: free-stream Mach number +- `kappa`: thermal diffusivity for Fick's law For the particular scaling the vicosity is set internally to be μ = 1/Re. Further, the nondimensionalization takes the density-temperature-sound speed as the principle quantities such that +``` rho_inf = 1.0 T_ref = 1.0 c_inf = 1.0 p_inf = 1.0 / gamma u_inf = Ma_inf R = 1.0 / gamma +``` Other normalization strategies exist, see the reference below for details. - Marc Montagnac (2013) @@ -35,7 +37,7 @@ The scaling used herein is Section 4.5 of the reference. In two spatial dimensions we require gradients for three quantities, e.g., primitive quantities - grad(u), grad(v), and grad(T) + grad(v_1), grad(v_2), and grad(T) or the entropy variables grad(w_2), grad(w_3), grad(w_4) where From d6436791f685fd75cf2fcddba16819eaff97271d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 29 Jul 2022 06:24:45 +0200 Subject: [PATCH 077/143] set version to v0.4.43 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index eb1db2c1454..cf36fdce091 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.4.43-pre" +version = "0.4.43" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From a6244c230eb34519dc676300bf4830ed2c26e7a3 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 29 Jul 2022 06:25:00 +0200 Subject: [PATCH 078/143] set development version to v0.4.44-pre --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index cf36fdce091..fa707e3f4c0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Trixi" uuid = "a7f1ee26-1774-49b1-8366-f1abc58fbfcb" authors = ["Michael Schlottke-Lakemper ", "Gregor Gassner ", "Hendrik Ranocha ", "Andrew R. Winters ", "Jesse Chan "] -version = "0.4.43" +version = "0.4.44-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" From d6ab952a39933661787861a5d05fd4d0cbf28abe Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Fri, 29 Jul 2022 08:19:30 +0200 Subject: [PATCH 079/143] add YouTube links to JuliaCon presentations (#1192) * add YouTube links to JuliaCon presentations * Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Michael Schlottke-Lakemper --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a75aa2e9160..2313578379b 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,14 @@ *** **Trixi.jl at JuliaCon 2022**
-At this year's JuliaCon, we will be present with two contributions that involve Trixi.jl: +At this year's JuliaCon 2022, we have been present with two contributions that involve Trixi.jl: * [Running Julia code in parallel with MPI: Lessons learned](https://live.juliacon.org/talk/LUWYRJ), - 26th July 2022 + 26th July 2022. [Watch on YouTube](https://youtu.be/fog1x9rs71Q?t=5172), [repo](https://github.com/JuliaParallel/juliacon-2022-julia-for-hpc-minisymposium) * [From Mesh Generation to Adaptive Simulation: A Journey in Julia](https://live.juliacon.org/talk/YSLKZJ), - 27th July 2022 + 27th July 2022. [Watch on YouTube](https://youtu.be/_N4ozHr-t9E), [repo](https://github.com/trixi-framework/talk-2022-juliacon_toolchain) -We are looking forward to seeing you there ♥️ +If you have questions about Trixi.jl or our other projects, feel free to get in touch via Slack or open an issue ♥️ *** **Trixi.jl** is a numerical simulation framework for hyperbolic conservation From 689fe59c5ddbd0acd381bd58a3badfa847e62d83 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Jul 2022 10:12:57 +0200 Subject: [PATCH 080/143] improved readability of equation docstrings in compressible Euler files --- src/equations/compressible_euler_1d.jl | 4 ++-- src/equations/compressible_euler_2d.jl | 6 +++--- src/equations/compressible_euler_3d.jl | 8 ++++---- .../compressible_euler_multicomponent_1d.jl | 10 +++++----- .../compressible_euler_multicomponent_2d.jl | 12 ++++++------ 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/equations/compressible_euler_1d.jl b/src/equations/compressible_euler_1d.jl index 89ec07558bc..400650ed885 100644 --- a/src/equations/compressible_euler_1d.jl +++ b/src/equations/compressible_euler_1d.jl @@ -10,12 +10,12 @@ The compressible Euler equations ```math -\partial t +\frac{\partial}{\partial t} \begin{pmatrix} \rho \\ \rho v_1 \\ \rho e \end{pmatrix} + -\partial x +\frac{\partial}{\partial x} \begin{pmatrix} \rho v_1 \\ \rho v_1^2 + p \\ (\rho e +p) v_1 \end{pmatrix} diff --git a/src/equations/compressible_euler_2d.jl b/src/equations/compressible_euler_2d.jl index 9c3d94cffd8..35852c0d1f9 100644 --- a/src/equations/compressible_euler_2d.jl +++ b/src/equations/compressible_euler_2d.jl @@ -10,17 +10,17 @@ The compressible Euler equations ```math -\partial t +\frac{\partial}{\partial t} \begin{pmatrix} \rho \\ \rho v_1 \\ \rho v_2 \\ \rho e \end{pmatrix} + -\partial x +\frac{\partial}{\partial x} \begin{pmatrix} \rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ (\rho e +p) v_1 \end{pmatrix} + -\partial y +\frac{\partial}{\partial y} \begin{pmatrix} \rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ (\rho e +p) v_2 \end{pmatrix} diff --git a/src/equations/compressible_euler_3d.jl b/src/equations/compressible_euler_3d.jl index d919c600112..1b93674c8a2 100644 --- a/src/equations/compressible_euler_3d.jl +++ b/src/equations/compressible_euler_3d.jl @@ -10,22 +10,22 @@ The compressible Euler equations ```math -\partial t +\frac{\partial}{\partial t} \begin{pmatrix} \rho \\ \rho v_1 \\ \rho v_2 \\ \rho v_3 \\ \rho e \end{pmatrix} + -\partial x +\frac{\partial}{\partial x} \begin{pmatrix} \rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ \rho v_1 v_3 \\ ( \rho e +p) v_1 \end{pmatrix} + -\partial y +\frac{\partial}{\partial y} \begin{pmatrix} \rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ \rho v_1 v_3 \\ ( \rho e +p) v_2 \end{pmatrix} + -\partial z +\frac{\partial}{\partial z} \begin{pmatrix} \rho v_3 \\ \rho v_1 v_3 \\ \rho v_2 v_3 \\ \rho v_3^2 + p \\ ( \rho e +p) v_3 \end{pmatrix} diff --git a/src/equations/compressible_euler_multicomponent_1d.jl b/src/equations/compressible_euler_multicomponent_1d.jl index 39d8eb34f24..c5a3579ab3e 100644 --- a/src/equations/compressible_euler_multicomponent_1d.jl +++ b/src/equations/compressible_euler_multicomponent_1d.jl @@ -10,12 +10,12 @@ Multicomponent version of the compressible Euler equations ```math -\partial t +\frac{\partial}{\partial t} \begin{pmatrix} \rho v_1 \\ \rho e \\ \rho_1 \\ \rho_2 \\ \vdots \\ \rho_{n} \end{pmatrix} + -\partial x +\frac{\partial}{\partial x} \begin{pmatrix} \rho v_1^2 + p \\ (\rho e +p) v_1 \\ \rho_1 v_1 \\ \rho_2 v_1 \\ \vdots \\ \rho_{n} v_1 \end{pmatrix} @@ -25,15 +25,15 @@ Multicomponent version of the compressible Euler equations 0 \\ 0 \\ 0 \\ 0 \\ \vdots \\ 0 \end{pmatrix} ``` -for calorically perfect gas in one space dimension. -Here, ``\rho_i`` is the density of component ``i``, ``\rho=\sum_{i=1}^n\rho_i`` the sum of the individual ``\rho_i``, +for calorically perfect gas in one space dimension. +Here, ``\rho_i`` is the density of component ``i``, ``\rho=\sum_{i=1}^n\rho_i`` the sum of the individual ``\rho_i``, ``v_1`` the velocity, ``e`` the specific total energy **rather than** specific internal energy, and ```math p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho v_1^2 \right) ``` the pressure, ```math -\gamma=\frac{\sum_{i=1}^n\rho_i C_{v,i}\gamma_i}{\sum_{i=1}^n\rho_i C_{v,i}} +\gamma=\frac{\sum_{i=1}^n\rho_i C_{v,i}\gamma_i}{\sum_{i=1}^n\rho_i C_{v,i}} ``` total heat capacity ratio, ``\gamma_i`` heat capacity ratio of component ``i``, ```math diff --git a/src/equations/compressible_euler_multicomponent_2d.jl b/src/equations/compressible_euler_multicomponent_2d.jl index ad90969cf80..bb91cfbcb4e 100644 --- a/src/equations/compressible_euler_multicomponent_2d.jl +++ b/src/equations/compressible_euler_multicomponent_2d.jl @@ -10,17 +10,17 @@ Multicomponent version of the compressible Euler equations ```math -\partial t +\frac{\partial}{\partial t} \begin{pmatrix} \rho v_1 \\ \rho v_2 \\ \rho e \\ \rho_1 \\ \rho_2 \\ \vdots \\ \rho_{n} \end{pmatrix} + -\partial x +\frac{\partial}{\partial x} \begin{pmatrix} \rho v_1^2 + p \\ \rho v_1 v_2 \\ ( \rho e +p) v_1 \\ \rho_1 v_1 \\ \rho_2 v_1 \\ \vdots \\ \rho_{n} v_1 \end{pmatrix} + -\partial y +\frac{\partial}{\partial y} \begin{pmatrix} \rho v_1 v_2 \\ \rho v_2^2 + p \\ ( \rho e +p) v_2 \\ \rho_1 v_2 \\ \rho_2 v_2 \\ \vdots \\ \rho_{n} v_2 \end{pmatrix} @@ -29,15 +29,15 @@ Multicomponent version of the compressible Euler equations 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ \vdots \\ 0 \end{pmatrix} ``` -for calorically perfect gas in two space dimensions. -Here, ``\rho_i`` is the density of component ``i``, ``\rho=\sum_{i=1}^n\rho_i`` the sum of the individual ``\rho_i``, +for calorically perfect gas in two space dimensions. +Here, ``\rho_i`` is the density of component ``i``, ``\rho=\sum_{i=1}^n\rho_i`` the sum of the individual ``\rho_i``, ``v_1``, ``v_2`` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and ```math p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2 + v_2^2) \right) ``` the pressure, ```math -\gamma=\frac{\sum_{i=1}^n\rho_i C_{v,i}\gamma_i}{\sum_{i=1}^n\rho_i C_{v,i}} +\gamma=\frac{\sum_{i=1}^n\rho_i C_{v,i}\gamma_i}{\sum_{i=1}^n\rho_i C_{v,i}} ``` total heat capacity ratio, ``\gamma_i`` heat capacity ratio of component ``i``, ```math From 6002ba673068c4a0837d0d07f3115a1a7b83acde Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Jul 2022 16:51:37 +0200 Subject: [PATCH 081/143] Navier-Stokes in 2D on DGMulti and TreeMesh (#1165) * first draft of container for Navier-Stokes constants and fluxes * remove unneeded temperature computation * draft of elixir with possible boundary condition structure * added manufactured solution and source term * fix typo in function name for MMS * update variable names for consistency. improve comments * fix dumb typos in new equation system name * actually export new equations * add comment near variable_mapping declaration. * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * parabolic equations now exported separately * change name to CompressibleNavierStokesEquations2D * export NS with proper name * explicitly require compressible Euler in the type parameter * name kinematic viscosity nu for consistency with Lattice-Boltzmann * add promotion in constructor * make Reynolds, Prandtl, Mach, and kappa keyword arguments * update constructor call in elixir * reduce computation by exploiting stress tensor symmetry * fix unpacking of flux * modifying parabolic cache creation in cache, we assume we take the gradient of all hyperbolic variables. since the number of parabolic variables can differ from the number of hyperbolic variables, we pass in the hyperbolic equations to `create_cache_parabolic` now * comments * comments * formatting and renaming equations to equations_hyperbolic formatting comments * fix unpacking of gradients in flux * adding CNS BCs * adding lid-driven cavity elixir * adding variable transform, editing cons2prim for CNS * add prim2cons for NS (inconsistent right now) * add draft of DGMulti Navier Stokes convergence elixir * converging solution using elixir for TreeMesh with BCs * fixing DGMulti advection diffusion elixir convergence * naming equations as parabolic/hyperbolic * generalizing transform_variables * add TODO more todos * additional checks on get_unsigned_normal * adding isothermal BC * commenting out unused CNS functions for now * fix call to transform_variables * comments and cleanup * changing default solver and Re for cavity * adding more advection diffusion tests * label tests * add gradient_variables field to SemidiscretizationHyperbolicParabolic * Revert "add gradient_variables field to SemidiscretizationHyperbolicParabolic" This reverts commit 063b602ebdb06a09be0f1cb34d5f24cdc86c6a83. * allowing for specialization in transform_variables adding a function `gradient_variable_transformation` which should get specialized if the gradient variables are not conservative variables * formatting and comments * reverting elixir * comments * standardizing time tol * minor fix to CNS boundary flux for convenience make it so that the density state is computed correctly, even though it's not used * formatting + comments * using primitive variables in viscous flux instead of conservative * minor formatting * add CNS tests * fix test * testing if scoping issues fix TreeMesh tests * decreasing timestep tol for TreeMesh parabolic test * enabling periodic BCs for TreeMesh + more tests * fix density BC flux (unused, but could be useful) * adding non-working TreeMesh elixirs * adding AD checks * standardizing parameters in convergence elixirs * minor cleanup * revert DGMulti CNS elixir setup back to the one used in tests * adding TreeMesh CNS convergence test * removing redundant elixir * add more tests * add more test * Apply suggestions from code review Co-authored-by: Hendrik Ranocha * add docstrings Co-authored-by: Hendrik Ranocha Co-authored-by: Hendrik Ranocha Co-authored-by: Jesse Chan --- .../elixir_advection_diffusion_nonperiodic.jl | 69 +++++ .../elixir_navier_stokes_convergence.jl | 206 +++++++++++++ .../elixir_navier_stokes_lid_driven_cavity.jl | 70 +++++ .../elixir_advection_diffusion.jl | 2 +- .../elixir_advection_diffusion_nonperiodic.jl | 87 ++++++ .../elixir_navier_stokes_convergence.jl | 215 +++++++++++++ .../elixir_navier_stokes_lid_driven_cavity.jl | 77 +++++ src/Trixi.jl | 7 +- .../compressible_navier_stokes_2d.jl | 290 ++++++++++++++++++ src/equations/equations_parabolic.jl | 8 + src/equations/laplace_diffusion_2d.jl | 38 +-- ...semidiscretization_hyperbolic_parabolic.jl | 3 +- src/solvers/dgmulti/dg_parabolic.jl | 31 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 221 +++++++++++-- test/test_parabolic_2d.jl | 68 +++- 15 files changed, 1326 insertions(+), 66 deletions(-) create mode 100644 examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl create mode 100644 examples/dgmulti_2d/elixir_navier_stokes_convergence.jl create mode 100644 examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl create mode 100644 examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl create mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl create mode 100644 examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl create mode 100644 src/equations/compressible_navier_stokes_2d.jl diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl new file mode 100644 index 00000000000..a8e9e3329af --- /dev/null +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -0,0 +1,69 @@ +using Trixi, OrdinaryDiffEq + +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +get_diffusivity() = 5.0e-2 + +equations = LinearScalarAdvectionEquation2D(1.0, 0.0) +equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) + +# from "Robust DPG methods for transient convection-diffusion." +# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. +# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +function initial_condition_erikkson_johnson(x, t, equations) + l = 4 + epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to the sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_erikkson_johnson + +# tag different boundary segments +left(x, tol=50*eps()) = abs(x[1] + 1) < tol +right(x, tol=50*eps()) = abs(x[1]) < tol +bottom(x, tol=50*eps()) = abs(x[2] + .5) < tol +top(x, tol=50*eps()) = abs(x[2] - .5) < tol +entire_boundary(x, tol=50*eps()) = true +is_on_boundary = Dict(:left => left, :right => right, :top => top, :bottom => bottom, + :entire_boundary => entire_boundary) +mesh = DGMultiMesh(dg; coordinates_min=(-1.0, -0.5), coordinates_max=(0.0, 0.5), + cells_per_dimension=(16, 16), is_on_boundary) + +# BC types +boundary_condition = BoundaryConditionDirichlet(initial_condition) + +# define inviscid boundary conditions +boundary_conditions = (; :left => boundary_condition, + :top => boundary_condition, + :bottom => boundary_condition, + :right => boundary_condition_do_nothing) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :entire_boundary => boundary_condition) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) + +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl new file mode 100644 index 00000000000..e922a9cad12 --- /dev/null +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -0,0 +1,206 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +get_Re() = 100 +get_Pr() = 0.72 + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), + Mach_freestream=0.5, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralWeakForm()) + +top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol +is_on_boundary = Dict(:top_bottom => top_bottom) +mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), is_on_boundary) + +# Define initial condition +# Note: If you change the parameters here, also change it in the corresponding source terms +function initial_condition_navier_stokes_convergence_test(x, t, equations) + + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + + y = x[2] + + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + kappa = 1 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = get_Pr() + Re = get_Re() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl new file mode 100644 index 00000000000..bdcc3a60607 --- /dev/null +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -0,0 +1,70 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, + Mach_freestream=0.1, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), + surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), + volume_integral = VolumeIntegralFluxDifferencing(flux_ranocha)) + +top(x, tol=50*eps()) = abs(x[2] - 1) < tol +rest_of_boundary(x, tol=50*eps()) = !top(x, tol) +is_on_boundary = Dict(:top => top, :rest_of_boundary => rest_of_boundary) +mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); is_on_boundary) + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0, 0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) + +# define inviscid boundary conditions +boundary_conditions = (; :top => boundary_condition_slip_wall, + :rest_of_boundary => boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; :top => boundary_condition_lid, + :rest_of_boundary => boundary_condition_cavity) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, dg; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 10.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval, uEltype=real(dg)) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index 1706d4d4184..d9ea702ea7c 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -77,7 +77,7 @@ callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) # run the simulation # OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks -time_int_tol = 1.0e-8 +time_int_tol = 1.0e-11 sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, save_everystep=false, callback=callbacks) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl new file mode 100644 index 00000000000..21e4866189b --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -0,0 +1,87 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the linear advection-diffusion equation + +get_diffusivity() = 5.0e-2 +advection_velocity = (1.0, 0.0) +equations = LinearScalarAdvectionEquation2D(advection_velocity) +# Note: If you change the diffusion parameter here, also change it in the initial condition +equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -0.5) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 0.0, 0.5) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + +# from "Robust DPG methods for transient convection-diffusion." +# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. +# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +function initial_condition_erikkson_johnson(x, t, equations) + l = 4 + epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to sqrt + lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) + r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + s1 = (1 - sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) + u = exp(-l * t) * (exp(lambda_1 * x[1]) - exp(lambda_2 * x[1])) + + cos(pi * x[2]) * (exp(s1 * x[1]) - exp(r1 * x[1])) / (exp(-s1) - exp(-r1)) + return SVector{1}(u) +end +initial_condition = initial_condition_erikkson_johnson + +boundary_conditions = (; x_neg = BoundaryConditionDirichlet(initial_condition), + y_neg = BoundaryConditionDirichlet(initial_condition), + y_pos = BoundaryConditionDirichlet(initial_condition), + x_pos = boundary_condition_do_nothing) + +boundary_conditions_parabolic = BoundaryConditionDirichlet(initial_condition) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, + (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 1.5) +ode = semidiscretize(semi, tspan); + +# At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup +# and resets the timers +summary_callback = SummaryCallback() + +# The AnalysisCallback allows to analyse the solution in regular intervals and prints the results +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) + +# The AliveCallback prints short status information in regular intervals +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +# Create a CallbackSet to collect all callbacks such that they can be passed to the ODE solver +callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback) + + +############################################################################### +# run the simulation + +# OrdinaryDiffEq's `solve` method evolves the solution in time and executes the passed callbacks +time_int_tol = 1.0e-11 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) + +# Print the timer summary +summary_callback() diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl new file mode 100644 index 00000000000..ee2307a90e7 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -0,0 +1,215 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +get_Re() = 100 +get_Pr() = 0.72 + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), + Mach_freestream=0.5, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=(true, false), + n_cells_max=30_000) # set maximum capacity of tree data structure + +# Define initial condition +# Note: If you change the parameters here, also change it in the corresponding source terms +function initial_condition_navier_stokes_convergence_test(x, t, equations) + + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +initial_condition = initial_condition_navier_stokes_convergence_test + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + + y = x[2] + + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + kappa = 1 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = get_Pr() + Re = get_Re() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + +# BC types +velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) +heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) + +# define inviscid boundary conditions +boundary_conditions = (; x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_slip_wall, + y_pos = boundary_condition_slip_wall) + +# define viscous boundary conditions +boundary_conditions_parabolic = (; x_neg = boundary_condition_periodic, + x_pos = boundary_condition_periodic, + y_neg = boundary_condition_top_bottom, + y_pos = boundary_condition_top_bottom) + +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), initial_condition, solver; + boundary_conditions=(boundary_conditions, boundary_conditions_parabolic), + source_terms=source_terms_navier_stokes_convergence_test) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 0.5) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=10) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, dt = 1e-5, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary + diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl new file mode 100644 index 00000000000..2a8fb635895 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -0,0 +1,77 @@ +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal compressible Navier-Stokes equations + +equations = CompressibleEulerEquations2D(1.4) +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, + Mach_freestream=0.1, kappa=1.0) + +# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) + +coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) +coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) + +# Create a uniformly refined mesh with periodic boundaries +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + periodicity=false, + n_cells_max=30_000) # set maximum capacity of tree data structure + + +function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) + Ma = 0.1 + rho = 1.0 + u, v = 0, 0 + p = 1.0 / (Ma^2 * equations.gamma) + return prim2cons(SVector(rho, u, v, p), equations) +end +initial_condition = initial_condition_cavity + +# BC types +velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) +velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) +heat_bc = Adiabatic((x, t, equations) -> 0.0) +boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) + +# define periodic boundary conditions everywhere +boundary_conditions = boundary_condition_slip_wall + +boundary_conditions_parabolic = (; x_neg = boundary_condition_cavity, + y_neg = boundary_condition_cavity, + y_pos = boundary_condition_lid, + x_pos = boundary_condition_cavity) + +# A semidiscretization collects data structures and functions for the spatial discretization +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), + initial_condition, solver; + boundary_conditions=(boundary_conditions, + boundary_conditions_parabolic)) + +############################################################################### +# ODE solvers, callbacks etc. + +# Create ODE problem with time span `tspan` +tspan = (0.0, 25.0) +ode = semidiscretize(semi, tspan); + +summary_callback = SummaryCallback() +alive_callback = AliveCallback(alive_interval=100) +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +callbacks = CallbackSet(summary_callback, alive_callback) + +############################################################################### +# run the simulation + +time_int_tol = 1e-8 +sol = solve(ode, RDPK3SpFSAL49(), abstol=time_int_tol, reltol=time_int_tol, + save_everystep=false, callback=callbacks) +summary_callback() # print the timer summary + + diff --git a/src/Trixi.jl b/src/Trixi.jl index 2533f71ea9e..61d8fa46c2e 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -131,10 +131,12 @@ export AcousticPerturbationEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, LinearScalarAdvectionEquation3D, InviscidBurgersEquation1D, - LaplaceDiffusion2D, LatticeBoltzmannEquations2D, LatticeBoltzmannEquations3D, ShallowWaterEquations1D, ShallowWaterEquations2D +export LaplaceDiffusion2D, + CompressibleNavierStokesEquations2D + export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, flux_nonconservative_powell, @@ -161,7 +163,8 @@ export boundary_condition_do_nothing, BoundaryConditionNeumann, boundary_condition_noslip_wall, boundary_condition_slip_wall, - boundary_condition_wall + boundary_condition_wall, + BoundaryConditionViscousWall, NoSlip, Adiabatic, Isothermal export initial_condition_convergence_test, source_terms_convergence_test export source_terms_harmonic diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl new file mode 100644 index 00000000000..3003de4fda2 --- /dev/null +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -0,0 +1,290 @@ +@doc raw""" + CompressibleNavierStokesEquations2D(gamma, + Re, + Pr, + Ma_inf, + kappa, + equations) + +`CompressibleNavierStokesEquations2D` represents the diffusion (i.e. parabolic) terms applied +to mass, momenta, and total energy together with the advective from +the [`CompressibleEulerEquations2D`](@ref). + +- `gamma`: adiabatic constant, +- `Re`: Reynolds number, +- `Pr`: Prandtl number, +- `Ma_inf`: free-stream Mach number +- `kappa`: thermal diffusivity for Fick's law + +For the particular scaling the vicosity is set internally to be μ = 1/Re. +Further, the nondimensionalization takes the density-temperature-sound speed as +the principle quantities such that +``` +rho_inf = 1.0 +T_ref = 1.0 +c_inf = 1.0 +p_inf = 1.0 / gamma +u_inf = Ma_inf +R = 1.0 / gamma +``` + +Other normalization strategies exist, see the reference below for details. +- Marc Montagnac (2013) + Variable Normalization (nondimensionalization and scaling) for Navier-Stokes + equations: a practical guide + [CERFACS Technical report](https://www.cerfacs.fr/~montagna/TR-CFD-13-77.pdf) +The scaling used herein is Section 4.5 of the reference. + +In two spatial dimensions we require gradients for three quantities, e.g., +primitive quantities + grad(v_1), grad(v_2), and grad(T) +or the entropy variables + grad(w_2), grad(w_3), grad(w_4) +where + w_2 = rho v_1 / p, w_3 = rho v_2 / p, w_4 = -rho / p +""" + +# TODO: +# 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from +# the Euler equations +# 2) Add more here and probably some equations + +# TODO: Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function +struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} + gamma::RealT # ratio of specific heats + inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications + Re::RealT # Reynolds number + Pr::RealT # Prandtl number + Ma_inf::RealT # free-stream Mach number + kappa::RealT # thermal diffusivity for Fick's law + + p_inf::RealT # free-stream pressure + u_inf::RealT # free-stream velocity + R::RealT # gas constant (depends on nondimensional scaling!) + + equations_hyperbolic::E # CompressibleEulerEquations2D +end + +function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream, kappa) + γ = equations.gamma + inv_gamma_minus_one = equations.inv_gamma_minus_one + Re, Pr, Ma, κ = promote(Reynolds, Prandtl, Mach_freestream, kappa) + + # From the nondimensionalization discussed above set the remaining free-stream + # quantities + p_inf = 1 / γ + u_inf = Mach_freestream + R = 1 / γ + CompressibleNavierStokesEquations2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, + Re, Pr, Ma, κ, + p_inf, u_inf, R, + equations) +end + + +# This is the flexibility a user should have to select the different gradient variable types +# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesEquations2D) = ("v1", "v2", "T") +# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") + +varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) + +# we specialize this function to compute gradients of primitive variables instead of +# conservative variables. +gradient_variable_transformation(::CompressibleNavierStokesEquations2D, dg_parabolic) = cons2prim + +# no orientation specified since the flux is vector-valued +# Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 +# of the paper by Svärd, Carpenter and Nordström +# "A stable high-order finite difference scheme for the compressible Navier–Stokes +# equations, far-field boundary conditions" +# Although these authors use a different nondimensionalization so some constants are different +# particularly for Fick's law. +# +# Note, could be generalized to use Sutherland's law to get the molecular and thermal +# diffusivity +function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) + # Here grad_u is assumed to contain the gradients of the primitive variables (v1, v2, T) + # either computed directly or reverse engineered from the gradient of the entropy vairables + # by way of the `convert_gradient_variables` function + rho, v1, v2, _ = u + + # grad_u contains derivatives of each hyperbolic variable + _, dv1dx, dv2dx, dTdx = grad_u[1] + _, dv1dy, dv2dy, dTdy = grad_u[2] + + # Components of viscous stress tensor + + # (4/3 * (v1)_x - 2/3 * (v2)_y) + tau_11 = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) + # ((v1)_y + (v2)_x) + # stress tensor is symmetric + tau_12 = ( dv1dy + dv2dx ) # = tau_21 + # (4/3 * (v2)_y - 2/3 * (v1)_x) + tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) + + # Fick's law q = -kappa * grad(T); constant is kappa * gamma / (Pr * (gamma-1)) + # Important note! Due to nondimensional scaling R = 1 / gamma, so the + # temperature T in the gradient computation already contains a factor of gamma + q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr + q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr + + # kinematic viscosity is simply 1/Re for this nondimensionalization + nu = 1.0 / equations.Re + + # viscous flux components in the x-direction + f1 = zero(rho) + f2 = tau_11 * nu + f3 = tau_12 * nu + f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * nu + + # viscous flux components in the y-direction + # Note, symmetry is exploited for tau_12 = tau_21 + g1 = zero(rho) + g2 = f3 # tau_21 * nu + g3 = tau_22 * nu + g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * nu + + return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) +end + + +# Convert conservative variables to primitive +@inline function cons2prim(u, equations::CompressibleNavierStokesEquations2D) + rho, rho_v1, rho_v2, _ = u + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + T = temperature(u, equations) + + return SVector(rho, v1, v2, T) +end + +# TODO: make this consistent with cons2prim above and cons2prim for Euler! +@inline prim2cons(u, equations::CompressibleNavierStokesEquations2D) = + prim2cons(u, equations.equations_hyperbolic) + + +# # Convert conservative variables to entropy +# @inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) +# rho, rho_v1, rho_v2, rho_e = u + +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# v_square = v1^2 + v2^2 +# p = (equations.gamma - 1) * (rho_e - 0.5 * rho * v_square) + +# rho_p = rho / p + +# w2 = rho_p * v1 +# w3 = rho_p * v2 +# w4 = -rho_p + +# return SVector(w2, w3, w4) +# end + + +# @inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokesEquations2D) +# # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and +# # reverse engineers the gradients to be terms of the primitive variables (v1, v2, T). +# # Helpful because then the diffusive fluxes have the same form as on paper. +# rho, rho_v1, rho_v2, _ = u + +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# T = temperature(u, equations) + +# return SVector(equations.R * T * (grad_entropy_vars[1] + v1 * grad_entropy_vars[3]), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) +# equations.R * T * (grad_entropy_vars[2] + v2 * grad_entropy_vars[3]), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) +# equations.R * T * T * grad_entropy_vars[3] # grad(T) = R*T^2*grad(w_4)) +# ) +# end + + +@inline function temperature(u, equations::CompressibleNavierStokesEquations2D) + rho, rho_v1, rho_v2, rho_e = u + + p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2) / rho) + T = p / (equations.R * rho) + return T +end + +""" + struct BoundaryConditionViscousWall{V, H} + +Creates a wall-type boundary conditions for the compressible Navier-Stokes equations. +The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended +to be boundary condition types such as the `NoSlip` velocity boundary condition and the +`Adiabatic` or `Isothermal` heat boundary condition. +""" +struct BoundaryConditionViscousWall{V, H} + boundary_condition_velocity::V + boundary_condition_heat_flux::H +end + +""" + struct NoSlip{F} + +Creates a no-slip boundary condition with field `boundary_value_function`, which +should be a function with signature `boundary_value_function(x, t, equations)` +and should return a `SVector{NDIMS}` whose entries are the velocity vector at a +point `x` and time `t`. +""" +struct NoSlip{F} + boundary_value_function::F # value of the velocity vector on the boundary +end + +""" + struct Isothermal{F} + +Creates an isothermal temperature boundary condition with field `boundary_value_function`, +which should be a function with signature `boundary_value_function(x, t, equations)` and +return a scalar value for the temperature at point `x` and time `t`. +""" +struct Isothermal{F} + boundary_value_function::F # value of the temperature on the boundary +end + +""" + struct Adiabatic{F} + +Creates an adiabatic temperature boundary condition with field `boundary_value_function`, +which should be a function with signature `boundary_value_function(x, t, equations)` and +return a scalar value for the normal heat flux at point `x` and time `t`. +""" +struct Adiabatic{F} + boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Gradient, + equations::CompressibleNavierStokesEquations2D) + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + return SVector(u_inner[1], v1, v2, u_inner[4]) +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Divergence, + equations::CompressibleNavierStokesEquations2D) + # rho, v1, v2, _ = u_inner + normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + tau_1n, tau_2n = flux_inner[2:3] # extract fluxes for 2nd and 3rd equations + normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux + return SVector(flux_inner[1:3]..., normal_energy_flux) +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Gradient, + equations::CompressibleNavierStokesEquations2D) + v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) + T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) + return SVector(u_inner[1], v1, v2, T) +end + +@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, + x, t, operator_type::Divergence, + equations::CompressibleNavierStokesEquations2D) + return flux_inner +end + diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index fec0eed6f63..24f2b51503c 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -1,3 +1,11 @@ +# specify transformation of conservative variables prior to taking gradients. +# specialize this function to compute gradients e.g., of primitive variables instead of conservative +gradient_variable_transformation(::AbstractEquationsParabolic, dg_parabolic) = cons2cons + # Linear scalar diffusion for use in linear scalar advection-diffusion problems abstract type AbstractLaplaceDiffusionEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("laplace_diffusion_2d.jl") + +# Compressible Navier-Stokes equations +abstract type AbstractCompressibleNavierStokesEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end +include("compressible_navier_stokes_2d.jl") diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index c171741716b..1baa08c8199 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -6,49 +6,49 @@ with diffusivity ``\kappa`` applied to each solution component defined by `equat """ struct LaplaceDiffusion2D{E, N, T} <: AbstractLaplaceDiffusionEquations{2, N} diffusivity::T - equations::E + equations_hyperbolic::E end -LaplaceDiffusion2D(diffusivity, equations) = - LaplaceDiffusion2D{typeof(equations), nvariables(equations), typeof(diffusivity)}(diffusivity, equations) +LaplaceDiffusion2D(diffusivity, equations_hyperbolic) = + LaplaceDiffusion2D{typeof(equations_hyperbolic), nvariables(equations_hyperbolic), typeof(diffusivity)}(diffusivity, equations_hyperbolic) varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) = - varnames(variable_mapping, equations_parabolic.equations) + varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -function flux(u, grad_u, equations::LaplaceDiffusion2D) +function flux(u, grad_u, equations_parabolic::LaplaceDiffusion2D) dudx, dudy = grad_u - return SVector(equations.diffusivity * dudx, equations.diffusivity * dudy) + return SVector(equations_parabolic.diffusivity * dudx, equations_parabolic.diffusivity * dudy) end # TODO: should this remain in the equations file, be moved to solvers, or live in the elixir? # The penalization depends on the solver, but also depends explicitly on physical parameters, # and would probably need to be specialized for every different equation. -function penalty(u_outer, u_inner, inv_h, equations::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) - return dg.penalty_parameter * (u_outer - u_inner) * equations.diffusivity * inv_h +function penalty(u_outer, u_inner, inv_h, equations_parabolic::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) + return dg.penalty_parameter * (u_outer - u_inner) * equations_parabolic.diffusivity * inv_h end # Dirichlet-type boundary condition for use with a parabolic solver in weak form -@inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::LaplaceDiffusion2D) - return boundary_condition.boundary_value_function(x, t, equations) + equations_parabolic::LaplaceDiffusion2D) + return boundary_condition.boundary_value_function(x, t, equations_parabolic) end -@inline function (boundary_condition::BoundaryConditionDirichlet)(u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::LaplaceDiffusion2D) - return u_inner + equations_parabolic::LaplaceDiffusion2D) + return flux_inner end -@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::LaplaceDiffusion2D) - return boundary_condition.boundary_normal_flux_function(x, t, equations) + equations_parabolic::LaplaceDiffusion2D) + return boundary_condition.boundary_normal_flux_function(x, t, equations_parabolic) end -@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNeumann)(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::LaplaceDiffusion2D) + equations_parabolic::LaplaceDiffusion2D) return flux_inner end diff --git a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl index ea96aa5c363..52a48d7aa03 100644 --- a/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl +++ b/src/semidiscretization/semidiscretization_hyperbolic_parabolic.jl @@ -102,7 +102,8 @@ function SemidiscretizationHyperbolicParabolic(mesh, equations, equations_parabo _boundary_conditions = digest_boundary_conditions(boundary_conditions, mesh, solver, cache) _boundary_conditions_parabolic = digest_boundary_conditions(boundary_conditions_parabolic, mesh, solver, cache) - cache_parabolic = (; create_cache_parabolic(mesh, equations_parabolic, solver, solver_parabolic, RealT, uEltype)..., + cache_parabolic = (; create_cache_parabolic(mesh, equations, equations_parabolic, + solver, solver_parabolic, RealT, uEltype)..., initial_cache_parabolic...) SemidiscretizationHyperbolicParabolic{typeof(mesh), typeof(equations), typeof(equations_parabolic), diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 9578e3f9eff..41a190bdc1a 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -1,6 +1,10 @@ -function create_cache_parabolic(mesh::DGMultiMesh, equations::AbstractEquationsParabolic, +function create_cache_parabolic(mesh::DGMultiMesh, + equations_hyperbolic::AbstractEquations, + equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, dg_parabolic, RealT, uEltype) - nvars = nvariables(equations) + # default to taking derivatives of all hyperbolic terms + # TODO: utilize the parabolic variables in `equations_parabolic` to reduce memory usage in the parabolic cache + nvars = nvariables(equations_hyperbolic) @unpack M, Drst = dg.basis weak_differentiation_matrices = map(A -> -M \ (A' * M), Drst) @@ -37,9 +41,10 @@ end # Transform solution variables prior to taking the gradient # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? -function transform_variables!(u_transformed, u, equations) +function transform_variables!(u_transformed, u, mesh, equations_parabolic::AbstractEquationsParabolic, + dg::DGMulti, dg_parabolic, cache, cache_parabolic) @threaded for i in eachindex(u) - u_transformed[i] = u[i] + u_transformed[i] = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u[i], equations_parabolic) end end @@ -97,7 +102,7 @@ function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, scalar_flux_face_values[idM] = 0.5 * (uP + uM) # TODO: use strong/weak formulation for curved meshes? end - calc_boundary_flux!(scalar_flux_face_values, nothing, t, Gradient(), boundary_conditions, + calc_boundary_flux!(scalar_flux_face_values, u_face_values, t, Gradient(), boundary_conditions, mesh, equations, dg, cache, cache_parabolic) # compute surface contributions @@ -154,10 +159,9 @@ function calc_single_boundary_flux!(flux_face_values, u_face_values, t, # for both the gradient and the divergence, the boundary flux is scalar valued. # for the gradient, it is the solution; for divergence, it is the normal flux. - u_boundary = boundary_condition(flux_face_values[fid,e], - face_normal, face_coordinates, t, - operator_type, equations) - flux_face_values[fid,e] = u_boundary + flux_face_values[fid,e] = boundary_condition(flux_face_values[fid,e], u_face_values[fid,e], + face_normal, face_coordinates, t, + operator_type, equations) end end return nothing @@ -245,7 +249,7 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh end # interpolates from solution coefficients to face quadrature points - viscous_flux_face_values = cache_parabolic.grad_u_face_values + viscous_flux_face_values = cache_parabolic.grad_u_face_values # reuse storage for dim in eachdim(mesh) prolong2interfaces!(viscous_flux_face_values[dim], viscous_flux[dim], mesh, equations, dg.surface_integral, dg, cache) @@ -262,14 +266,14 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh for dim in eachdim(mesh) uM = viscous_flux_face_values[dim][idM] uP = viscous_flux_face_values[dim][idP] - # TODO: use strong/weak formulation? + # TODO: use strong/weak formulation to ensure stability on curved meshes? flux_face_value = flux_face_value + 0.5 * (uP + uM) * nxyzJ[dim][face_node_index] end scalar_flux_face_values[idM] = flux_face_value end # TODO: decide what to pass in - calc_boundary_flux!(scalar_flux_face_values, nothing, t, Divergence(), + calc_boundary_flux!(scalar_flux_face_values, cache_parabolic.u_face_values, t, Divergence(), boundary_conditions, mesh, equations, dg, cache, cache_parabolic) calc_viscous_penalty!(scalar_flux_face_values, cache_parabolic.u_face_values, t, @@ -295,7 +299,8 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra reset_du!(du, dg) @unpack u_transformed, u_grad, viscous_flux = cache_parabolic - transform_variables!(u_transformed, u, equations_parabolic) + transform_variables!(u_transformed, u, mesh, equations_parabolic, + dg, dg_parabolic, cache, cache_parabolic) calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 01f0ead469f..78445a04b34 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -16,7 +16,9 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @unpack u_transformed, u_grad = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, - equations_parabolic) + mesh, equations_parabolic, + dg, dg_parabolic, + cache, cache_parabolic) @trixi_timeit timer() "calculate gradient" calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, @@ -39,7 +41,23 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra end +# Transform solution variables prior to taking the gradient +# (e.g., conservative to primitive variables). Defaults to doing nothing. +# TODO: can we avoid copying data? +function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + dg::DG, dg_parabolic, cache, cache_parabolic) + @threaded for element in eachelement(dg, cache) + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_transformed_node = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u_node, equations_parabolic) + set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) + end + end +end +# TODO: dg_parabolic is not a DG type; it contains solver-specific information such as an LDG penalty parameter. function calc_divergence!(du, u, t, viscous_flux, mesh::TreeMesh{2}, equations_parabolic, boundary_conditions_parabolic, dg::DG, dg_parabolic, @@ -80,22 +98,16 @@ function calc_divergence!(du, u, t, viscous_flux, right_element = interfaces.neighbor_ids[2, interface] if orientations[interface] == 1 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[1] - # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] - end + # interface in x-direction + for j in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, j, interface] = viscous_flux[1][v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = viscous_flux[1][v, 1, j, right_element] end else # if orientations[interface] == 2 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[2] - # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] - end + # interface in y-direction + for i in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, i, interface] = viscous_flux[2][v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = viscous_flux[2][v, i, 1, right_element] end end end @@ -104,7 +116,7 @@ function calc_divergence!(du, u, t, viscous_flux, # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @unpack surface_flux_values = cache_parabolic.elements - @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + @unpack neighbor_ids, orientations = cache_parabolic.interfaces @threaded for interface in eachinterface(dg, cache_parabolic) # Get neighboring elements @@ -119,7 +131,8 @@ function calc_divergence!(du, u, t, viscous_flux, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) + # TODO: should this u be cache_parabolic.interfaces.u?? + u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage @@ -176,7 +189,8 @@ function calc_divergence!(du, u, t, viscous_flux, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_condition_periodic + calc_divergence_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + mesh, equations_parabolic, dg.surface_integral, dg) end # Prolong solution to mortars @@ -250,6 +264,161 @@ function calc_viscous_fluxes!(viscous_flux, u, mesh::TreeMesh{2}, end end +# TODO: decide if we should keep this, and if so, extend to 3D. +function get_unsigned_normal_vector_2d(direction) + if direction > 4 || direction < 1 + @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." + end + if direction==1 || direction==2 + return SVector(1.0, 0.0) + else + return SVector(0.0, 1.0) + end +end + +function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + return nothing +end + +function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + return nothing +end + +function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + @unpack surface_flux_values = cache.elements + @unpack n_boundaries_per_direction = cache.boundaries + + # Calculate indices + lasts = accumulate(+, n_boundaries_per_direction) + firsts = lasts - n_boundaries_per_direction .+ 1 + + # Calc boundary fluxes in each direction + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[1], + equations_parabolic, surface_integral, dg, cache, + 1, firsts[1], lasts[1]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[2], + equations_parabolic, surface_integral, dg, cache, + 2, firsts[2], lasts[2]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[3], + equations_parabolic, surface_integral, dg, cache, + 3, firsts[3], lasts[3]) + calc_gradient_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[4], + equations_parabolic, surface_integral, dg, cache, + 4, firsts[4], lasts[4]) +end +function calc_gradient_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:Any,4}, t, + boundary_condition, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + direction, first_boundary, last_boundary) + @unpack surface_flux = surface_integral + @unpack u, neighbor_ids, neighbor_sides, node_coordinates, orientations = cache.boundaries + + @threaded for boundary in first_boundary:last_boundary + # Get neighboring element + neighbor = neighbor_ids[boundary] + + for i in eachnode(dg) + # Get boundary flux + u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, boundary) + if neighbor_sides[boundary] == 1 # Element is on the left, boundary on the right + u_inner = u_ll + else # Element is on the right, boundary on the left + u_inner = u_rr + end + + # TODO: revisit if we want more general boundary treatments. + # This assumes the gradient numerical flux at the boundary is the gradient variable, + # which is consistent with BR1, LDG. + flux_inner = u_inner + + x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) + flux = boundary_condition(flux_inner, u_inner, get_unsigned_normal_vector_2d(direction), + x, t, Gradient(), equations_parabolic) + + # Copy flux to left and right element storage + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, direction, neighbor] = flux[v] + end + end + end + + return nothing +end + +function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG) + @unpack surface_flux_values = cache.elements + @unpack n_boundaries_per_direction = cache.boundaries + + # Calculate indices + lasts = accumulate(+, n_boundaries_per_direction) + firsts = lasts - n_boundaries_per_direction .+ 1 + + # Calc boundary fluxes in each direction + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[1], + equations_parabolic, surface_integral, dg, cache, + 1, firsts[1], lasts[1]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[2], + equations_parabolic, surface_integral, dg, cache, + 2, firsts[2], lasts[2]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[3], + equations_parabolic, surface_integral, dg, cache, + 3, firsts[3], lasts[3]) + calc_divergence_boundary_flux_by_direction!(surface_flux_values, t, boundary_conditions_parabolic[4], + equations_parabolic, surface_integral, dg, cache, + 4, firsts[4], lasts[4]) +end +function calc_divergence_boundary_flux_by_direction!(surface_flux_values::AbstractArray{<:Any,4}, t, + boundary_condition, + equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache, + direction, first_boundary, last_boundary) + @unpack surface_flux = surface_integral + + # Note: cache.boundaries.u contains the unsigned normal component (using "orientation", not "direction") + # of the viscous flux, as computed in `prolong2boundaries` of `calc_divergence!`` + @unpack u, neighbor_ids, neighbor_sides, node_coordinates, orientations = cache.boundaries + + @threaded for boundary in first_boundary:last_boundary + # Get neighboring element + neighbor = neighbor_ids[boundary] + + for i in eachnode(dg) + # Get viscous boundary fluxes + flux_ll, flux_rr = get_surface_node_vars(u, equations_parabolic, dg, i, boundary) + if neighbor_sides[boundary] == 1 # Element is on the left, boundary on the right + flux_inner = flux_ll + else # Element is on the right, boundary on the left + flux_inner = flux_rr + end + + x = get_node_coords(node_coordinates, equations_parabolic, dg, i, boundary) + + # TODO: add a field in `cache.boundaries` for gradient information. + # Here, we pass in `u_inner = nothing` since we overwrite cache.boundaries.u with gradient information. + # This currently works with Dirichlet/Neuman boundary conditions for LaplaceDiffusion2D and + # NoSlipWall/Adiabatic boundary conditions for CompressibleNavierStokesEquations2D as of 2022-6-27. + # It will not work with implementations which utilize `u_inner` to impose boundary conditions. + flux = boundary_condition(flux_inner, nothing, get_unsigned_normal_vector_2d(direction), + x, t, Divergence(), equations_parabolic) + + # Copy flux to left and right element storage + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, direction, neighbor] = flux[v] + end + end + end + + return nothing +end function calc_gradient!(u_grad, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, @@ -308,7 +477,7 @@ function calc_gradient!(u_grad, u, t, # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @unpack surface_flux_values = cache_parabolic.elements - @unpack u, neighbor_ids, orientations = cache_parabolic.interfaces + @unpack neighbor_ids, orientations = cache_parabolic.interfaces @threaded for interface in eachinterface(dg, cache_parabolic) # Get neighboring elements @@ -323,7 +492,9 @@ function calc_gradient!(u_grad, u, t, for i in eachnode(dg) # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(u, equations_parabolic, dg, i, interface) + # TODO: should this be cache_parabolic.interfaces.u?? + u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, + equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) # Copy flux to left and right element storage @@ -374,7 +545,8 @@ function calc_gradient!(u_grad, u, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - @assert boundary_conditions_parabolic == boundary_condition_periodic + calc_gradient_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + mesh, equations_parabolic, dg.surface_integral, dg) end # Prolong solution to mortars @@ -438,14 +610,15 @@ end # This method is called when a SemidiscretizationHyperbolic is constructed. # It constructs the basic `cache` used throughout the simulation to compute # the RHS etc. -function create_cache_parabolic(mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, +function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::AbstractEquations, + equations_parabolic::AbstractEquationsParabolic, dg::DG, dg_parabolic, RealT, uEltype) # Get cells for which an element needs to be created (i.e. all leaf cells) leaf_cell_ids = local_leaf_cells(mesh.tree) - elements = init_elements(leaf_cell_ids, mesh, equations_parabolic, dg.basis, RealT, uEltype) + elements = init_elements(leaf_cell_ids, mesh, equations_hyperbolic, dg.basis, RealT, uEltype) - n_vars = nvariables(equations_parabolic) + n_vars = nvariables(equations_hyperbolic) n_nodes = nnodes(elements) n_elements = nelements(elements) u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 4a792af4840..42d6b1d3752 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -70,19 +70,75 @@ isdir(outdir) && rm(outdir, recursive=true) @test getindex.(du, 1) ≈ 2 * y end - @trixi_testset "elixir_advection_diffusion_periodic.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion_periodic.jl"), + @trixi_testset "DGMulti: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.1), + l2 = [0.2485803335154642], + linf = [1.079606969242132] + ) + end + + @trixi_testset "DGMulti: elixir_advection_diffusion_periodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_periodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), l2 = [0.03180371984888462], linf = [0.2136821621370909] ) end - @trixi_testset "elixir_advection_diffusion.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_diffusion.jl"), + @trixi_testset "DGMulti: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_advection_diffusion_nonperiodic.jl"), cells_per_dimension = (4, 4), tspan=(0.0, 0.1), - l2 = [0.2485803335154642], - linf = [1.079606969242132] + l2 = [0.002123168335604323], + linf = [0.00963640423513712] + ) + end + + @trixi_testset "DGMulti: elixir_navier_stokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navier_stokes_convergence.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.1), + l2 = [0.00153550768125133, 0.0033843168272696357, 0.0036531858107444067, 0.009948436427519428], + linf = [0.005522560467190019, 0.013425258500731063, 0.013962115643483375, 0.027483102120516634] + ) + end + + @trixi_testset "DGMulti: elixir_navier_stokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "dgmulti_2d", "elixir_navier_stokes_lid_driven_cavity.jl"), + cells_per_dimension = (4, 4), tspan=(0.0, 0.5), + l2 = [0.0002215612522711349, 0.028318325921400257, 0.009509168701069035, 0.028267900513539248], + linf = [0.0015622789413053395, 0.14886653390741342, 0.07163235655334241, 0.19472785105216417] + ) + end + + @trixi_testset "TreeMesh2D: elixir_advection_diffusion.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.4), polydeg=5, + l2 = [4.0915532997994255e-6], + linf = [2.3040850347877395e-5] + ) + end + + @trixi_testset "TreeMesh2D: elixir_advection_diffusion_nonperiodic.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_advection_diffusion_nonperiodic.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + l2 = [0.007646800618485118], + linf = [0.10067621050468958] + ) + end + + @trixi_testset "TreeMesh2D: elixir_navier_stokes_convergence.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_convergence.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + l2 = [0.0021116725306635146, 0.0034322351490824465, 0.003874252819611102, 0.012469246082522416], + linf = [0.012006418939297214, 0.03552087120958058, 0.02451274749176294, 0.11191122588577151] + ) + end + + @trixi_testset "TreeMesh2D: elixir_navier_stokes_lid_driven_cavity.jl" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_lid_driven_cavity.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.5), + l2 = [0.0001514457152968994, 0.018766076072331786, 0.007065070765651992, 0.020839900573430787], + linf = [0.0014523369373645734, 0.12366779944955876, 0.055324509971157544, 0.1609992780534526] ) end From 5f485883210fb1b860ee4947d7a62653755ed388 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Jul 2022 19:10:36 +0200 Subject: [PATCH 082/143] add docstring for CNS equations --- .../compressible_navier_stokes_2d.jl | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 3003de4fda2..252bb5d9893 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -16,7 +16,44 @@ the [`CompressibleEulerEquations2D`](@ref). - `Ma_inf`: free-stream Mach number - `kappa`: thermal diffusivity for Fick's law -For the particular scaling the vicosity is set internally to be μ = 1/Re. +The particular form of the compressible Navier-Stokes implemented are +```math +\frac{\partial}{\partial t} +\begin{pmatrix} +\rho \\ \rho \vec{v} \\ \rho e +\end{pmatrix} ++ +\nabla \cdot +\begin{pmatrix} + \rho \vec{v} \\ \rho \vec{v}\vec{v}^T + p \underline{I} \\ (\rho e +p) \vec{v} +\end{pmatrix} += +\nabla \cdot +\begin{pmatrix} +0 \\ \underline{\tau} \\ \underline{\tau}\vec{v} - \nabla q +\end{pmatrix} +``` +where the system is closed with the ideal gas assumption giving +```math +p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2) \right) +``` +as the pressure. The terms on the right hand side of the system above +are built from the viscous stress tensor +```math +\underline{\tau} = \mu \left(\nabla\vec{v} + \left(\nabla\vec{v}\right)^T\right) - \frac{2}{3} \mu \left(\nabla\cdot\vec{v}\right)\underline{I} +``` +where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux +```math +\nabla q = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} +``` +where ``T`` is the temperature. +Under the assumption that the gas has a constant Prandtl number +the thermal conductivity is +```math +\kappa = \frac{\gamma \mu R}{(\gamma - 1)\textrm{Pr}} +``` + +For this particular scaling the vicosity is set internally to be μ = 1/Re. Further, the nondimensionalization takes the density-temperature-sound speed as the principle quantities such that ``` @@ -37,17 +74,22 @@ The scaling used herein is Section 4.5 of the reference. In two spatial dimensions we require gradients for three quantities, e.g., primitive quantities - grad(v_1), grad(v_2), and grad(T) +```math + \nabla v_1,\, \nabla v_2,\, \nabla T +```` or the entropy variables - grad(w_2), grad(w_3), grad(w_4) +```math + \nabla w_2,\, \nabla w_3,\, \nabla w_4 +``` where - w_2 = rho v_1 / p, w_3 = rho v_2 / p, w_4 = -rho / p +```math + w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} +```` """ # TODO: # 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from # the Euler equations -# 2) Add more here and probably some equations # TODO: Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} From baea3ecaf643e44777d0a26d95de2b2f779e7637 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 29 Jul 2022 12:29:24 -0500 Subject: [PATCH 083/143] removing some addressed TODOs --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 78445a04b34..a2230fcad8e 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -57,10 +57,12 @@ function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, end end -# TODO: dg_parabolic is not a DG type; it contains solver-specific information such as an LDG penalty parameter. +# note: the argument dg_parabolic is not a DG type; it contains solver-specific +# information such as an LDG penalty parameter. function calc_divergence!(du, u, t, viscous_flux, mesh::TreeMesh{2}, equations_parabolic, - boundary_conditions_parabolic, dg::DG, dg_parabolic, + boundary_conditions_parabolic, dg::DG, + dg_parabolic, # not a `DG` type cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" begin @@ -131,7 +133,6 @@ function calc_divergence!(du, u, t, viscous_flux, for i in eachnode(dg) # Call pointwise Riemann solver - # TODO: should this u be cache_parabolic.interfaces.u?? u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) @@ -492,7 +493,6 @@ function calc_gradient!(u_grad, u, t, for i in eachnode(dg) # Call pointwise Riemann solver - # TODO: should this be cache_parabolic.interfaces.u?? u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) flux = 0.5 * (u_ll + u_rr) From 0b17ec6602efc6a7f477b88c2e58fcfaeb68c106 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Jul 2022 20:07:08 +0200 Subject: [PATCH 084/143] adjust definition of the kappa constant --- .../elixir_navier_stokes_convergence.jl | 2 +- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- .../elixir_navier_stokes_convergence.jl | 2 +- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- .../compressible_navier_stokes_2d.jl | 36 +++++++++++-------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index e922a9cad12..9efab13ad61 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), - Mach_freestream=0.5, kappa=1.0) + Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Tri(), approximation_type = Polynomial(), diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index bdcc3a60607..fa837adcb7f 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -8,7 +8,7 @@ equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, - Mach_freestream=0.1, kappa=1.0) + Mach_freestream=0.1) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index ee2307a90e7..cb947b03d55 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -11,7 +11,7 @@ equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), - Mach_freestream=0.5, kappa=1.0) + Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index 2a8fb635895..ede29e95720 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -8,7 +8,7 @@ equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, - Mach_freestream=0.1, kappa=1.0) + Mach_freestream=0.1) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 252bb5d9893..7c35eaab8f6 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -16,7 +16,7 @@ the [`CompressibleEulerEquations2D`](@ref). - `Ma_inf`: free-stream Mach number - `kappa`: thermal diffusivity for Fick's law -The particular form of the compressible Navier-Stokes implemented are +The particular form of the compressible Navier-Stokes implemented is ```math \frac{\partial}{\partial t} \begin{pmatrix} @@ -25,7 +25,7 @@ The particular form of the compressible Navier-Stokes implemented are + \nabla \cdot \begin{pmatrix} - \rho \vec{v} \\ \rho \vec{v}\vec{v}^T + p \underline{I} \\ (\rho e +p) \vec{v} + \rho \vec{v} \\ \rho \vec{v}\vec{v}^T + p \underline{I} \\ (\rho e + p) \vec{v} \end{pmatrix} = \nabla \cdot @@ -42,7 +42,7 @@ are built from the viscous stress tensor ```math \underline{\tau} = \mu \left(\nabla\vec{v} + \left(\nabla\vec{v}\right)^T\right) - \frac{2}{3} \mu \left(\nabla\cdot\vec{v}\right)\underline{I} ``` -where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux +where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux is ```math \nabla q = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} ``` @@ -107,10 +107,16 @@ struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressi equations_hyperbolic::E # CompressibleEulerEquations2D end -function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream, kappa) +function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream) γ = equations.gamma inv_gamma_minus_one = equations.inv_gamma_minus_one - Re, Pr, Ma, κ = promote(Reynolds, Prandtl, Mach_freestream, kappa) + Re, Pr, Ma = promote(Reynolds, Prandtl, Mach_freestream) + + # Under the assumption of constant Prandtl number the thermal conductivity + # constant is kappa = gamma μ R / ((gamma-1) Pr). + # Important note! Due to nondimensional scaling R = 1 / gamma, this constant + # simplifies slightly. Also, the factor of μ is accounted for later. + κ = inv_gamma_minus_one / Pr # From the nondimensionalization discussed above set the remaining free-stream # quantities @@ -165,27 +171,27 @@ function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) # (4/3 * (v2)_y - 2/3 * (v1)_x) tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) - # Fick's law q = -kappa * grad(T); constant is kappa * gamma / (Pr * (gamma-1)) + # Fick's law q = -kappa * grad(T); constant is kappa = gamma μ R / ((gamma-1) Pr) # Important note! Due to nondimensional scaling R = 1 / gamma, so the # temperature T in the gradient computation already contains a factor of gamma - q1 = ( equations.kappa * equations.inv_gamma_minus_one * dTdx ) / equations.Pr - q2 = ( equations.kappa * equations.inv_gamma_minus_one * dTdy ) / equations.Pr + q1 = equations.kappa * dTdx + q2 = equations.kappa * dTdy # kinematic viscosity is simply 1/Re for this nondimensionalization - nu = 1.0 / equations.Re + mu = 1.0 / equations.Re # viscous flux components in the x-direction f1 = zero(rho) - f2 = tau_11 * nu - f3 = tau_12 * nu - f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * nu + f2 = tau_11 * mu + f3 = tau_12 * mu + f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * mu # viscous flux components in the y-direction # Note, symmetry is exploited for tau_12 = tau_21 g1 = zero(rho) - g2 = f3 # tau_21 * nu - g3 = tau_22 * nu - g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * nu + g2 = f3 # tau_21 * mu + g3 = tau_22 * mu + g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * mu return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) end From ba49eefecc9ffe1fe38efa8f4526880d018c3bbd Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 29 Jul 2022 15:25:27 -0500 Subject: [PATCH 085/143] avoid overwriting u_grad with viscous_flux results --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index a2230fcad8e..769819971a2 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -14,7 +14,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - @unpack u_transformed, u_grad = cache_parabolic + @unpack u_transformed, u_grad, viscous_flux = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, mesh, equations_parabolic, dg, dg_parabolic, @@ -25,12 +25,11 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra boundary_conditions, dg, cache, cache_parabolic) - # TODO: Do not misuse u_grad to store fluxes? - @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(u_grad, u_transformed, + @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(viscous_flux, u_grad, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) - @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, u_grad, + @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, viscous_flux, mesh, equations_parabolic, boundary_conditions, dg, @@ -247,15 +246,15 @@ function calc_divergence!(du, u, t, viscous_flux, end -function calc_viscous_fluxes!(viscous_flux, u, mesh::TreeMesh{2}, +function calc_viscous_fluxes!(viscous_flux, u_grad, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_grad_1_node = get_node_vars(viscous_flux[1], equations_parabolic, dg, i, j, element) - u_grad_2_node = get_node_vars(viscous_flux[2], equations_parabolic, dg, i, j, element) + u_grad_1_node = get_node_vars(u_grad[1], equations_parabolic, dg, i, j, element) + u_grad_2_node = get_node_vars(u_grad[2], equations_parabolic, dg, i, j, element) # Calculate viscous flux and store each component for later use viscous_flux_node = flux(u_node, (u_grad_1_node, u_grad_2_node), equations_parabolic) @@ -623,6 +622,7 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::Abstrac n_elements = nelements(elements) u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) u_grad = ntuple(_ -> similar(u_transformed), ndims(mesh)) + viscous_flux = ntuple(_ -> similar(u_transformed), ndims(mesh)) interfaces = init_interfaces(leaf_cell_ids, mesh, elements) @@ -631,7 +631,7 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::Abstrac # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries, u_grad, u_transformed) + cache = (; elements, interfaces, boundaries, u_grad, viscous_flux, u_transformed) # Add specialized parts of the cache required to compute the mortars etc. # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) From a8897aaac95ab2d6d2eb5fdf7f39e31b343bbeb1 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 29 Jul 2022 15:25:38 -0500 Subject: [PATCH 086/143] remove old TODOs --- src/solvers/dgmulti/dg_parabolic.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 41a190bdc1a..48913315c77 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -196,7 +196,7 @@ function calc_viscous_fluxes!(viscous_flux, u, u_grad, mesh::DGMultiMesh, # compute viscous flux at quad points for i in eachindex(local_u_values) u_i = local_u_values[i] - u_grad_i = getindex.(local_viscous_flux, i) # TODO: check if this allocates. Shouldn't for tuples or SVector... + u_grad_i = getindex.(local_viscous_flux, i) viscous_flux_i = flux(u_i, u_grad_i, equations) setindex!.(local_viscous_flux, viscous_flux_i, i) end @@ -272,7 +272,6 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh scalar_flux_face_values[idM] = flux_face_value end - # TODO: decide what to pass in calc_boundary_flux!(scalar_flux_face_values, cache_parabolic.u_face_values, t, Divergence(), boundary_conditions, mesh, equations, dg, cache, cache_parabolic) From e0fddfaa448a44f8b0710fcaac9a2c73f41e2100 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 29 Jul 2022 15:25:45 -0500 Subject: [PATCH 087/143] clarify TODOs for later --- src/solvers/dgmulti/dg_parabolic.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 48913315c77..2ddd45bbb26 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -83,7 +83,7 @@ function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, # compute volume contributions to gradients @threaded for e in eachelement(mesh, dg) for i in eachdim(mesh), j in eachdim(mesh) - dxidxhatj = mesh.md.rstxyzJ[i, j][1, e] # TODO: assumes mesh is affine + dxidxhatj = mesh.md.rstxyzJ[i, j][1, e] # TODO: DGMulti. Assumes mesh is affine here. apply_to_each_field(mul_by_accum!(weak_differentiation_matrices[j], dxidxhatj), view(u_grad[i], :, e), view(u, :, e)) end @@ -188,7 +188,7 @@ function calc_viscous_fluxes!(viscous_flux, u, u_grad, mesh::DGMultiMesh, end # interpolate u and gradient to quadrature points, store in `local_viscous_flux` - apply_to_each_field(mul_by!(dg.basis.Vq), local_u_values, view(u, :, e)) # TODO: can we avoid this when we don't need it? + apply_to_each_field(mul_by!(dg.basis.Vq), local_u_values, view(u, :, e)) # TODO: DGMulti. Specialize for nodal collocation methods (SBP, GaussSBP) for dim in eachdim(mesh) apply_to_each_field(mul_by!(dg.basis.Vq), local_viscous_flux[dim], view(u_grad[dim], :, e)) end From baec9672453bcb29e435c946fa42c17d68167516 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 29 Jul 2022 15:27:29 -0500 Subject: [PATCH 088/143] removing let statements --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 44 ++++++++++------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 769819971a2..eb8784dc55a 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -153,34 +153,28 @@ function calc_divergence!(du, u, t, viscous_flux, element = boundaries.neighbor_ids[boundary] if orientations[boundary] == 1 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[1] - # boundary in x-direction - if neighbor_sides[boundary] == 1 - # element in -x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] - end - else # Element in +x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = u[v, 1, l, element] - end + # boundary in x-direction + if neighbor_sides[boundary] == 1 + # element in -x direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[1, v, l, boundary] = viscous_flux[1][v, nnodes(dg), l, element] + end + else # Element in +x direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[2, v, l, boundary] = viscous_flux[1][v, 1, l, element] end end else # if orientations[boundary] == 2 - # TODO Make this cleaner (remove the let) - let u = viscous_flux[2] - # boundary in y-direction - if neighbor_sides[boundary] == 1 - # element in -y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] - end - else - # element in +y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = u[v, l, 1, element] - end + # boundary in y-direction + if neighbor_sides[boundary] == 1 + # element in -y direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[1, v, l, boundary] = viscous_flux[2][v, l, nnodes(dg), element] + end + else + # element in +y direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[2, v, l, boundary] = viscous_flux[2][v, l, 1, element] end end end From f6fd1f8f7d39238135b33811701a3d8dc8a6bd76 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 3 Aug 2022 09:09:26 +0200 Subject: [PATCH 089/143] rearrange main docstring. Fix typos in math environment causing it to not parse --- .../compressible_navier_stokes_2d.jl | 62 ++++++++----------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 7c35eaab8f6..1030a91171d 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -1,36 +1,31 @@ @doc raw""" - CompressibleNavierStokesEquations2D(gamma, - Re, - Pr, - Ma_inf, - kappa, - equations) - -`CompressibleNavierStokesEquations2D` represents the diffusion (i.e. parabolic) terms applied -to mass, momenta, and total energy together with the advective from + CompressibleNavierStokesEquations2D(gamma, Re, Pr, Ma_inf, equations) + +These equations contain the diffusion (i.e. parabolic) terms applied +to mass, momenta, and total energy together with the advective terms from the [`CompressibleEulerEquations2D`](@ref). - `gamma`: adiabatic constant, - `Re`: Reynolds number, - `Pr`: Prandtl number, - `Ma_inf`: free-stream Mach number -- `kappa`: thermal diffusivity for Fick's law +- `equations`: instance of the [`CompressibleEulerEquations2D`](@ref) The particular form of the compressible Navier-Stokes implemented is ```math \frac{\partial}{\partial t} \begin{pmatrix} -\rho \\ \rho \vec{v} \\ \rho e +\rho \\ \rho \mathbf{v} \\ \rho e \end{pmatrix} + \nabla \cdot \begin{pmatrix} - \rho \vec{v} \\ \rho \vec{v}\vec{v}^T + p \underline{I} \\ (\rho e + p) \vec{v} + \rho \mathbf{v} \\ \rho \mathbf{v}\mathbf{v}^T + p \underline{I} \\ (\rho e + p) \mathbf{v} \end{pmatrix} = \nabla \cdot \begin{pmatrix} -0 \\ \underline{\tau} \\ \underline{\tau}\vec{v} - \nabla q +0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \nabla q \end{pmatrix} ``` where the system is closed with the ideal gas assumption giving @@ -40,19 +35,33 @@ p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2) \right) as the pressure. The terms on the right hand side of the system above are built from the viscous stress tensor ```math -\underline{\tau} = \mu \left(\nabla\vec{v} + \left(\nabla\vec{v}\right)^T\right) - \frac{2}{3} \mu \left(\nabla\cdot\vec{v}\right)\underline{I} +\underline{\tau} = \mu \left(\nabla\mathbf{v} + \left(\nabla\mathbf{v}\right)^T\right) - \frac{2}{3} \mu \left(\nabla\cdot\mathbf{v}\right)\underline{I} ``` where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux is ```math \nabla q = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho} ``` -where ``T`` is the temperature. +where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fick's law. Under the assumption that the gas has a constant Prandtl number the thermal conductivity is ```math \kappa = \frac{\gamma \mu R}{(\gamma - 1)\textrm{Pr}} ``` +In two spatial dimensions we require gradients for three quantities, e.g., +primitive quantities +```math +\nabla v_1,\, \nabla v_2,\, \nabla T +``` +or the entropy variables +```math +\nabla w_2,\, \nabla w_3,\, \nabla w_4 +``` +where +```math +w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} +``` + For this particular scaling the vicosity is set internally to be μ = 1/Re. Further, the nondimensionalization takes the density-temperature-sound speed as the principle quantities such that @@ -71,28 +80,11 @@ Other normalization strategies exist, see the reference below for details. equations: a practical guide [CERFACS Technical report](https://www.cerfacs.fr/~montagna/TR-CFD-13-77.pdf) The scaling used herein is Section 4.5 of the reference. - -In two spatial dimensions we require gradients for three quantities, e.g., -primitive quantities -```math - \nabla v_1,\, \nabla v_2,\, \nabla T -```` -or the entropy variables -```math - \nabla w_2,\, \nabla w_3,\, \nabla w_4 -``` -where -```math - w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p} -```` """ - -# TODO: -# 1) For now I save gamma and inv(gamma-1) again, but we could potentially reuse them from -# the Euler equations - -# TODO: Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} + # TODO: + # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations + # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function gamma::RealT # ratio of specific heats inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications Re::RealT # Reynolds number From 0b63e5822822a6aa1539722c4e03110926f22291 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 11:42:16 +0200 Subject: [PATCH 090/143] update TODO notes --- .../dgmulti_2d/elixir_navier_stokes_convergence.jl | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index 9efab13ad61..58cb810742e 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -8,8 +8,6 @@ get_Re() = 100 get_Pr() = 0.72 equations = CompressibleEulerEquations2D(1.4) -# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition -# I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), Mach_freestream=0.5) @@ -25,10 +23,9 @@ mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), # Define initial condition # Note: If you change the parameters here, also change it in the corresponding source terms function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + A = 0.5 + c = 2.0 # convenience values for trig. functions pi_x = pi * x[1] @@ -46,9 +43,9 @@ end initial_condition = initial_condition_navier_stokes_convergence_test @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] + # TODO: parabolic # we currently need to hardcode these parameters until we fix the "combined equation" issue # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 kappa = 1 @@ -58,8 +55,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # Same settings as in `initial_condition` # Amplitude and shift - A = 0.5 - c = 2.0 + A = 0.5 + c = 2.0 # convenience values for trig. functions pi_x = pi * x[1] From 8bd0e1dc1a1d8397b5d6e58cb4d4743f0bb19b3c Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 11:44:26 +0200 Subject: [PATCH 091/143] Apply suggestions from code review Co-authored-by: Andrew Winters --- examples/dgmulti_2d/elixir_navier_stokes_convergence.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index 58cb810742e..e45de0144dd 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -48,7 +48,6 @@ initial_condition = initial_condition_navier_stokes_convergence_test # TODO: parabolic # we currently need to hardcode these parameters until we fix the "combined equation" issue # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - kappa = 1 inv_gamma_minus_one = inv(equations.gamma - 1) Pr = get_Pr() Re = get_Re() @@ -102,7 +101,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + T_const = equations.gamma * inv_gamma_minus_one / Pr inv_Re = 1.0 / Re inv_rho_cubed = 1.0 / (rho^3) From dcdbe07e63b3d92edc01eb3c621a9d102b898291 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 11:47:37 +0200 Subject: [PATCH 092/143] update TODO notes --- .../elixir_navier_stokes_lid_driven_cavity.jl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index fa837adcb7f..bd017cd209d 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -4,11 +4,15 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations +# TODO: parabolic; unify names of these accessor functions +reynolds_number() = 1000.0 +prandtl_number() = 0.72 +mach_number() = 0.1 + equations = CompressibleEulerEquations2D(1.4) -# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition -# I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, - Mach_freestream=0.1) +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), + Prandtl=prandtl_number(), + Mach_freestream=mach_number()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = GaussSBP(), @@ -21,7 +25,7 @@ is_on_boundary = Dict(:top => top, :rest_of_boundary => rest_of_boundary) mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); is_on_boundary) function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) - Ma = 0.1 + Ma = mach_number() rho = 1.0 u, v = 0, 0 p = 1.0 / (Ma^2 * equations.gamma) From 5eae2b0f0ff992e44a479bd95c2d065111667c34 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 11:49:13 +0200 Subject: [PATCH 093/143] Apply suggestions from code review Co-authored-by: Andrew Winters --- examples/tree_2d_dgsem/elixir_advection_diffusion.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index d9ea702ea7c..e701aa0517c 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -6,8 +6,8 @@ using Trixi advection_velocity = (1.5, 1.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) -# Note: If you change the diffusion parameter here, also change it in the initial condition -equations_parabolic = LaplaceDiffusion2D(5.0e-2, equations) +get_diffusivity() = 5.0e-2 +equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) @@ -28,7 +28,7 @@ function initial_condition_diffusive_convergence_test(x, t, equation::LinearScal x_trans = x - equation.advection_velocity * t # @unpack nu = equation - nu = 5.0e-2 + nu = get_diffusivity() c = 1.0 A = 0.5 L = 2 From 81776788c2a90d981b0a9d59de799920fc52a8fc Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 11:56:28 +0200 Subject: [PATCH 094/143] update TODO notes --- .../elixir_navier_stokes_lid_driven_cavity.jl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index ede29e95720..25cefc788c2 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -4,11 +4,15 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations +# TODO: parabolic; unify names of these accessor functions +reynolds_number() = 1000.0 +prandtl_number() = 0.72 +mach_number() = 0.1 + equations = CompressibleEulerEquations2D(1.4) -# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition -# I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=1000, Prandtl=0.72, - Mach_freestream=0.1) +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), + Prandtl=prandtl_number(), + Mach_freestream=mach_number()) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) @@ -24,7 +28,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, function initial_condition_cavity(x, t, equations::CompressibleEulerEquations2D) - Ma = 0.1 + Ma = mach_number() rho = 1.0 u, v = 0, 0 p = 1.0 / (Ma^2 * equations.gamma) From ada3fb9639aef3b0670823471d3759b6da83f1a1 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 09:54:41 -0500 Subject: [PATCH 095/143] changing diffusivity names Auto stash before merge of "parabolic-treemesh" and "origin/parabolic-treemesh" --- .../elixir_advection_diffusion_nonperiodic.jl | 6 +++--- .../dgmulti_2d/elixir_navier_stokes_convergence.jl | 12 +++++++----- .../elixir_advection_diffusion_nonperiodic.jl | 6 +++--- .../elixir_navier_stokes_convergence.jl | 10 +++++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index a8e9e3329af..72908e017cd 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -4,17 +4,17 @@ dg = DGMulti(polydeg = 3, element_type = Quad(), approximation_type = Polynomial surface_integral = SurfaceIntegralWeakForm(flux_lax_friedrichs), volume_integral = VolumeIntegralWeakForm()) -get_diffusivity() = 5.0e-2 +diffusivity() = 5.0e-2 equations = LinearScalarAdvectionEquation2D(1.0, 0.0) -equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # from "Robust DPG methods for transient convection-diffusion." # Building bridges: connections and challenges in modern approaches to numerical partial differential equations. # Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." function initial_condition_erikkson_johnson(x, t, equations) l = 4 - epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to the sqrt + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to the sqrt lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index e45de0144dd..a38bd530e3d 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -4,11 +4,13 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations -get_Re() = 100 -get_Pr() = 0.72 +Reynolds_number() = 100 +Prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), +# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition +# I really do not like this structure but it should work for now +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=Reynolds_number(), Prandtl=Prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -49,8 +51,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # we currently need to hardcode these parameters until we fix the "combined equation" issue # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = get_Pr() - Re = get_Re() + Pr = Prandtl_number() + Re = Reynolds_number() # Same settings as in `initial_condition` # Amplitude and shift diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index 21e4866189b..eec3b8d655f 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -4,11 +4,11 @@ using Trixi ############################################################################### # semidiscretization of the linear advection-diffusion equation -get_diffusivity() = 5.0e-2 +diffusivity() = 5.0e-2 advection_velocity = (1.0, 0.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) # Note: If you change the diffusion parameter here, also change it in the initial condition -equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) @@ -27,7 +27,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, # Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." function initial_condition_erikkson_johnson(x, t, equations) l = 4 - epsilon = get_diffusivity() # TODO: this requires epsilon < .6 due to sqrt + epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index cb947b03d55..0f0e32f06ec 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -4,13 +4,13 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations -get_Re() = 100 -get_Pr() = 0.72 +Reynolds_number() = 100 +Prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=get_Re(), Prandtl=get_Pr(), +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=Reynolds_number(), Prandtl=Prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -56,8 +56,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 kappa = 1 inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = get_Pr() - Re = get_Re() + Pr = Prandtl_number() + Re = Reynolds_number() # Same settings as in `initial_condition` # Amplitude and shift From c547b1cb7917293beed1cab38afcf856652073ff Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 09:56:57 -0500 Subject: [PATCH 096/143] Reynolds/Prandtl number name changes for consistency --- .../dgmulti_2d/elixir_navier_stokes_convergence.jl | 10 +++++----- .../tree_2d_dgsem/elixir_navier_stokes_convergence.jl | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index a38bd530e3d..edffc19c739 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -4,13 +4,13 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations -Reynolds_number() = 100 -Prandtl_number() = 0.72 +reynolds_number() = 100 +prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=Reynolds_number(), Prandtl=Prandtl_number(), +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -51,8 +51,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # we currently need to hardcode these parameters until we fix the "combined equation" issue # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = Prandtl_number() - Re = Reynolds_number() + Pr = prandtl_number() + Re = reynolds_number() # Same settings as in `initial_condition` # Amplitude and shift diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 0f0e32f06ec..9e084857603 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -4,13 +4,13 @@ using Trixi ############################################################################### # semidiscretization of the ideal compressible Navier-Stokes equations -Reynolds_number() = 100 -Prandtl_number() = 0.72 +reynolds_number() = 100 +prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=Reynolds_number(), Prandtl=Prandtl_number(), +equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -56,8 +56,8 @@ initial_condition = initial_condition_navier_stokes_convergence_test # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 kappa = 1 inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = Prandtl_number() - Re = Reynolds_number() + Pr = prandtl_number() + Re = reynolds_number() # Same settings as in `initial_condition` # Amplitude and shift From d0848b5366d7b5ddf0b902f9e92b547b06045fff Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 10:08:15 -0500 Subject: [PATCH 097/143] Apply suggestions from code review Co-authored-by: Hendrik Ranocha Co-authored-by: Michael Schlottke-Lakemper Co-authored-by: Andrew Winters --- .../elixir_advection_diffusion_nonperiodic.jl | 9 ++++++--- .../elixir_navier_stokes_convergence.jl | 1 + .../tree_2d_dgsem/elixir_advection_diffusion.jl | 4 +--- .../elixir_advection_diffusion_nonperiodic.jl | 10 ++++++---- .../elixir_navier_stokes_convergence.jl | 15 +++++---------- src/equations/compressible_navier_stokes_2d.jl | 17 +++++++++-------- src/equations/laplace_diffusion_2d.jl | 2 +- src/solvers/dgmulti/dg_parabolic.jl | 2 +- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 72908e017cd..1993d1dee58 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -9,9 +9,12 @@ diffusivity() = 5.0e-2 equations = LinearScalarAdvectionEquation2D(1.0, 0.0) equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) -# from "Robust DPG methods for transient convection-diffusion." -# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. -# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +# Example setup taken from +# - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). +# Robust DPG methods for transient convection-diffusion. +# In: Building bridges: connections and challenges in modern approaches +# to numerical partial differential equations. +# [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_erikkson_johnson(x, t, equations) l = 4 epsilon = diffusivity() # TODO: this requires epsilon < .6 due to the sqrt diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index edffc19c739..10d3abc350c 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -24,6 +24,7 @@ mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), # Define initial condition # Note: If you change the parameters here, also change it in the corresponding source terms +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) # Amplitude and shift A = 0.5 diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index e701aa0517c..fb473c51713 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -22,12 +22,10 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max=30_000) # set maximum capacity of tree data structure # Define initial condition -# Note: If you change the diffusion parameter here, also change it in the parabolic equation definition function initial_condition_diffusive_convergence_test(x, t, equation::LinearScalarAdvectionEquation2D) # Store translated coordinate for easy use of exact solution x_trans = x - equation.advection_velocity * t - # @unpack nu = equation nu = get_diffusivity() c = 1.0 A = 0.5 @@ -56,7 +54,7 @@ semi = SemidiscretizationHyperbolicParabolic(mesh, # Create ODE problem with time span from 0.0 to 1.5 tspan = (0.0, 1.5) -ode = semidiscretize(semi, tspan); +ode = semidiscretize(semi, tspan) # At the beginning of the main loop, the SummaryCallback prints a summary of the simulation setup # and resets the timers diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl index eec3b8d655f..1f0bfb788ad 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion_nonperiodic.jl @@ -7,7 +7,6 @@ using Trixi diffusivity() = 5.0e-2 advection_velocity = (1.0, 0.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) -# Note: If you change the diffusion parameter here, also change it in the initial condition equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -22,9 +21,12 @@ mesh = TreeMesh(coordinates_min, coordinates_max, periodicity=false, n_cells_max=30_000) # set maximum capacity of tree data structure -# from "Robust DPG methods for transient convection-diffusion." -# Building bridges: connections and challenges in modern approaches to numerical partial differential equations. -# Springer, Cham, 2016. 179-203. Ellis, Truman, Jesse Chan, and Leszek Demkowicz." +# Example setup taken from +# - Truman Ellis, Jesse Chan, and Leszek Demkowicz (2016). +# Robust DPG methods for transient convection-diffusion. +# In: Building bridges: connections and challenges in modern approaches +# to numerical partial differential equations. +# [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_erikkson_johnson(x, t, equations) l = 4 epsilon = diffusivity() # TODO: this requires epsilon < .6 due to sqrt diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 9e084857603..f85f108f6c1 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -8,8 +8,6 @@ reynolds_number() = 100 prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) -# Note: If you change the Navier-Stokes parameters here, also change them in the initial condition -# I really do not like this structure but it should work for now equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=0.5) @@ -28,10 +26,9 @@ mesh = TreeMesh(coordinates_min, coordinates_max, # Define initial condition # Note: If you change the parameters here, also change it in the corresponding source terms function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 + A = 0.5 + c = 2.0 # convenience values for trig. functions pi_x = pi * x[1] @@ -49,20 +46,18 @@ end initial_condition = initial_condition_navier_stokes_convergence_test @inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] # we currently need to hardcode these parameters until we fix the "combined equation" issue # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - kappa = 1 inv_gamma_minus_one = inv(equations.gamma - 1) Pr = prandtl_number() Re = reynolds_number() # Same settings as in `initial_condition` # Amplitude and shift - A = 0.5 - c = 2.0 + A = 0.5 + c = 2.0 # convenience values for trig. functions pi_x = pi * x[1] @@ -108,7 +103,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one * kappa / Pr + T_const = equations.gamma * inv_gamma_minus_one / Pr inv_Re = 1.0 / Re inv_rho_cubed = 1.0 / (rho^3) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 1030a91171d..41e95fef4b3 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -82,7 +82,7 @@ Other normalization strategies exist, see the reference below for details. The scaling used herein is Section 4.5 of the reference. """ struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} - # TODO: + # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function gamma::RealT # ratio of specific heats @@ -100,7 +100,7 @@ struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressi end function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream) - γ = equations.gamma + gamma = equations.gamma inv_gamma_minus_one = equations.inv_gamma_minus_one Re, Pr, Ma = promote(Reynolds, Prandtl, Mach_freestream) @@ -108,7 +108,7 @@ function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquatio # constant is kappa = gamma μ R / ((gamma-1) Pr). # Important note! Due to nondimensional scaling R = 1 / gamma, this constant # simplifies slightly. Also, the factor of μ is accounted for later. - κ = inv_gamma_minus_one / Pr + kappa = inv_gamma_minus_one / Pr # From the nondimensionalization discussed above set the remaining free-stream # quantities @@ -122,6 +122,7 @@ function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquatio end +# TODO: parabolic # This is the flexibility a user should have to select the different gradient variable types # varnames(::typeof(cons2prim) , ::CompressibleNavierStokesEquations2D) = ("v1", "v2", "T") # varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") @@ -250,7 +251,7 @@ end end """ - struct BoundaryConditionViscousWall{V, H} + struct BoundaryConditionViscousWall Creates a wall-type boundary conditions for the compressible Navier-Stokes equations. The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended @@ -263,9 +264,9 @@ struct BoundaryConditionViscousWall{V, H} end """ - struct NoSlip{F} + struct NoSlip -Creates a no-slip boundary condition with field `boundary_value_function`, which +Use to create a no-slip boundary condition with `BoundaryConditionViscousWall`. The field `boundary_value_function` should be a function with signature `boundary_value_function(x, t, equations)` and should return a `SVector{NDIMS}` whose entries are the velocity vector at a point `x` and time `t`. @@ -275,7 +276,7 @@ struct NoSlip{F} end """ - struct Isothermal{F} + struct Isothermal Creates an isothermal temperature boundary condition with field `boundary_value_function`, which should be a function with signature `boundary_value_function(x, t, equations)` and @@ -286,7 +287,7 @@ struct Isothermal{F} end """ - struct Adiabatic{F} + struct Adiabatic Creates an adiabatic temperature boundary condition with field `boundary_value_function`, which should be a function with signature `boundary_value_function(x, t, equations)` and diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index 1baa08c8199..66846639599 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -21,7 +21,7 @@ function flux(u, grad_u, equations_parabolic::LaplaceDiffusion2D) return SVector(equations_parabolic.diffusivity * dudx, equations_parabolic.diffusivity * dudy) end -# TODO: should this remain in the equations file, be moved to solvers, or live in the elixir? +# TODO: parabolic; should this remain in the equations file, be moved to solvers, or live in the elixir? # The penalization depends on the solver, but also depends explicitly on physical parameters, # and would probably need to be specialized for every different equation. function penalty(u_outer, u_inner, inv_h, equations_parabolic::LaplaceDiffusion2D, dg::ViscousFormulationLocalDG) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 2ddd45bbb26..b4ca12311b2 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -3,7 +3,7 @@ function create_cache_parabolic(mesh::DGMultiMesh, equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, dg_parabolic, RealT, uEltype) # default to taking derivatives of all hyperbolic terms - # TODO: utilize the parabolic variables in `equations_parabolic` to reduce memory usage in the parabolic cache + # TODO: parabolic; utilize the parabolic variables in `equations_parabolic` to reduce memory usage in the parabolic cache nvars = nvariables(equations_hyperbolic) @unpack M, Drst = dg.basis From b2f0621998ccc2a79db66ec0f3a8304ea49b7f77 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 10:43:22 -0500 Subject: [PATCH 098/143] fixing bug introduced by GH code review --- src/equations/compressible_navier_stokes_2d.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 41e95fef4b3..a32a71a2df6 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -112,13 +112,13 @@ function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquatio # From the nondimensionalization discussed above set the remaining free-stream # quantities - p_inf = 1 / γ + p_inf = 1 / gamma u_inf = Mach_freestream - R = 1 / γ - CompressibleNavierStokesEquations2D{typeof(γ),typeof(equations)}(γ, inv_gamma_minus_one, - Re, Pr, Ma, κ, - p_inf, u_inf, R, - equations) + R = 1 / gamma + CompressibleNavierStokesEquations2D{typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, + Re, Pr, Ma, kappa, + p_inf, u_inf, R, + equations) end From e3fdde8c5257b6936ef42a36c3a153de10d3af7f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 10:43:47 -0500 Subject: [PATCH 099/143] moving manufactured solution into the CNS equations file --- .../elixir_navier_stokes_convergence.jl | 143 ------------------ .../elixir_navier_stokes_convergence.jl | 141 ----------------- .../compressible_navier_stokes_2d.jl | 143 ++++++++++++++++++ 3 files changed, 143 insertions(+), 284 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index 10d3abc350c..7df00740d85 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -22,151 +22,8 @@ top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), is_on_boundary) -# Define initial condition -# Note: If you change the parameters here, also change it in the corresponding source terms -# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) -function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end - initial_condition = initial_condition_navier_stokes_convergence_test -@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - Re = reynolds_number() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_Re = 1.0 / Re - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * inv_Re - + 2.0 / 3.0 * v2_xy * inv_Re - - v1_yy * inv_Re - - v2_xy * inv_Re ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * inv_Re - - v2_xx * inv_Re - - 4.0 / 3.0 * v2_yy * inv_Re - + 2.0 / 3.0 * v1_xy * inv_Re ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * inv_Re - + 2.0 / 3.0 * v2_xy * v1 * inv_Re - - 4.0 / 3.0 * v1_x * v1_x * inv_Re - + 2.0 / 3.0 * v2_y * v1_x * inv_Re - - v1_xy * v2 * inv_Re - - v2_xx * v2 * inv_Re - - v1_y * v2_x * inv_Re - - v2_x * v2_x * inv_Re - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * inv_Re - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * inv_Re - - v2_xy * v1 * inv_Re - - v1_y * v1_y * inv_Re - - v2_x * v1_y * inv_Re - - 4.0 / 3.0 * v2_yy * v2 * inv_Re - + 2.0 / 3.0 * v1_xy * v2 * inv_Re - - 4.0 / 3.0 * v2_y * v2_y * inv_Re - + 2.0 / 3.0 * v1_x * v2_y * inv_Re - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * inv_Re ) - - return SVector(du1, du2, du3, du4) -end - # BC types velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index f85f108f6c1..331dd95333d 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -23,149 +23,8 @@ mesh = TreeMesh(coordinates_min, coordinates_max, periodicity=(true, false), n_cells_max=30_000) # set maximum capacity of tree data structure -# Define initial condition -# Note: If you change the parameters here, also change it in the corresponding source terms -function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end - initial_condition = initial_condition_navier_stokes_convergence_test -@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - Re = reynolds_number() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_Re = 1.0 / Re - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * inv_Re - + 2.0 / 3.0 * v2_xy * inv_Re - - v1_yy * inv_Re - - v2_xy * inv_Re ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * inv_Re - - v2_xx * inv_Re - - 4.0 / 3.0 * v2_yy * inv_Re - + 2.0 / 3.0 * v1_xy * inv_Re ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * inv_Re - + 2.0 / 3.0 * v2_xy * v1 * inv_Re - - 4.0 / 3.0 * v1_x * v1_x * inv_Re - + 2.0 / 3.0 * v2_y * v1_x * inv_Re - - v1_xy * v2 * inv_Re - - v2_xx * v2 * inv_Re - - v1_y * v2_x * inv_Re - - v2_x * v2_x * inv_Re - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * inv_Re - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * inv_Re - - v2_xy * v1 * inv_Re - - v1_y * v1_y * inv_Re - - v2_x * v1_y * inv_Re - - 4.0 / 3.0 * v2_yy * v2 * inv_Re - + 2.0 / 3.0 * v1_xy * v2 * inv_Re - - 4.0 / 3.0 * v2_y * v2_y * inv_Re - + 2.0 / 3.0 * v1_x * v2_y * inv_Re - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * inv_Re ) - - return SVector(du1, du2, du3, du4) -end - # BC types velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index a32a71a2df6..8d94a09497a 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -329,3 +329,146 @@ end return flux_inner end +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) +# and by the initial condition (which passes in `CompressibleEulerEquations2D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + Re = reynolds_number() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end \ No newline at end of file From a8ed40e4bb157167338f5476570a12580be7f5ca Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 11:00:59 -0500 Subject: [PATCH 100/143] fix allocation issue --- src/equations/compressible_navier_stokes_2d.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 8d94a09497a..2c9dff7717d 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -310,11 +310,12 @@ end # rho, v1, v2, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) - tau_1n, tau_2n = flux_inner[2:3] # extract fluxes for 2nd and 3rd equations + _, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux - return SVector(flux_inner[1:3]..., normal_energy_flux) + return SVector(flux_inner[1], flux_inner[2], flux_inner[3], normal_energy_flux) end + @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, equations::CompressibleNavierStokesEquations2D) From 9bf37263b9e69ece4da31552a75ad0439872e506 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 8 Aug 2022 18:20:07 +0200 Subject: [PATCH 101/143] get_diffusivity -> diffusivity --- examples/tree_2d_dgsem/elixir_advection_diffusion.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl index fb473c51713..e538f701919 100644 --- a/examples/tree_2d_dgsem/elixir_advection_diffusion.jl +++ b/examples/tree_2d_dgsem/elixir_advection_diffusion.jl @@ -6,8 +6,8 @@ using Trixi advection_velocity = (1.5, 1.0) equations = LinearScalarAdvectionEquation2D(advection_velocity) -get_diffusivity() = 5.0e-2 -equations_parabolic = LaplaceDiffusion2D(get_diffusivity(), equations) +diffusivity() = 5.0e-2 +equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) @@ -26,7 +26,7 @@ function initial_condition_diffusive_convergence_test(x, t, equation::LinearScal # Store translated coordinate for easy use of exact solution x_trans = x - equation.advection_velocity * t - nu = get_diffusivity() + nu = diffusivity() c = 1.0 A = 0.5 L = 2 From a6b6d91f88c5dc1d32455f9bb53f54ef925c43a6 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 11:26:20 -0500 Subject: [PATCH 102/143] removing cruft code, adding comment on messy prim2cons routine --- .../compressible_navier_stokes_2d.jl | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 2c9dff7717d..eed500fdad1 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -201,47 +201,14 @@ end return SVector(rho, v1, v2, T) end -# TODO: make this consistent with cons2prim above and cons2prim for Euler! +# This routine is required because `prim2cons` is called in `initial_condition`, which +# is called with `equations::CompressibleEulerEquations2D`. This means it is inconsistent +# with `cons2prim(..., ::CompressibleNavierStokesEquations2D)` as defined above. +# TODO: parabolic. Is there a way to clean this up? @inline prim2cons(u, equations::CompressibleNavierStokesEquations2D) = prim2cons(u, equations.equations_hyperbolic) -# # Convert conservative variables to entropy -# @inline function cons2entropy(u, equations::CompressibleNavierStokesEquations2D) -# rho, rho_v1, rho_v2, rho_e = u - -# v1 = rho_v1 / rho -# v2 = rho_v2 / rho -# v_square = v1^2 + v2^2 -# p = (equations.gamma - 1) * (rho_e - 0.5 * rho * v_square) - -# rho_p = rho / p - -# w2 = rho_p * v1 -# w3 = rho_p * v2 -# w4 = -rho_p - -# return SVector(w2, w3, w4) -# end - - -# @inline function convert_gradient_variables(u, grad_entropy_vars, equations::CompressibleNavierStokesEquations2D) -# # Takes the solution values `u` and gradient of the variables (w_2, w_3, w_4) and -# # reverse engineers the gradients to be terms of the primitive variables (v1, v2, T). -# # Helpful because then the diffusive fluxes have the same form as on paper. -# rho, rho_v1, rho_v2, _ = u - -# v1 = rho_v1 / rho -# v2 = rho_v2 / rho -# T = temperature(u, equations) - -# return SVector(equations.R * T * (grad_entropy_vars[1] + v1 * grad_entropy_vars[3]), # grad(u) = R*T*(grad(w_2)+v1*grad(w_4)) -# equations.R * T * (grad_entropy_vars[2] + v2 * grad_entropy_vars[3]), # grad(v) = R*T*(grad(w_3)+v2*grad(w_4)) -# equations.R * T * T * grad_entropy_vars[3] # grad(T) = R*T^2*grad(w_4)) -# ) -# end - - @inline function temperature(u, equations::CompressibleNavierStokesEquations2D) rho, rho_v1, rho_v2, rho_e = u From 69880c4b273d3f5212507514721752503a76b951 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 11:28:03 -0500 Subject: [PATCH 103/143] moving manufactured solution back into elixirs --- .../elixir_navier_stokes_convergence.jl | 144 ++++++++++++++++++ .../elixir_navier_stokes_convergence.jl | 144 ++++++++++++++++++ .../compressible_navier_stokes_2d.jl | 143 ----------------- 3 files changed, 288 insertions(+), 143 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index 7df00740d85..c67b67e119e 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -22,6 +22,150 @@ top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), is_on_boundary) +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) +# and by the initial condition (which passes in `CompressibleEulerEquations2D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + Re = reynolds_number() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + initial_condition = initial_condition_navier_stokes_convergence_test # BC types diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 331dd95333d..07a5a8d8fd5 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -23,6 +23,150 @@ mesh = TreeMesh(coordinates_min, coordinates_max, periodicity=(true, false), n_cells_max=30_000) # set maximum capacity of tree data structure +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) +# and by the initial condition (which passes in `CompressibleEulerEquations2D`). +# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) +function initial_condition_navier_stokes_convergence_test(x, t, equations) + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) + v2 = v1 + p = rho^2 + + return prim2cons(SVector(rho, v1, v2, p), equations) +end + +@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) + y = x[2] + + # TODO: parabolic + # we currently need to hardcode these parameters until we fix the "combined equation" issue + # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 + inv_gamma_minus_one = inv(equations.gamma - 1) + Pr = prandtl_number() + Re = reynolds_number() + + # Same settings as in `initial_condition` + # Amplitude and shift + A = 0.5 + c = 2.0 + + # convenience values for trig. functions + pi_x = pi * x[1] + pi_y = pi * x[2] + pi_t = pi * t + + # compute the manufactured solution and all necessary derivatives + rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) + rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) + rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) + rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) + + v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) + v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) + v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) + v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) + - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) + - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) + v2 = v1 + v2_t = v1_t + v2_x = v1_x + v2_y = v1_y + v2_xx = v1_xx + v2_xy = v1_xy + v2_yy = v1_yy + + p = rho * rho + p_t = 2.0 * rho * rho_t + p_x = 2.0 * rho * rho_x + p_y = 2.0 * rho * rho_y + p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x + p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y + + # Note this simplifies slightly because the ansatz assumes that v1 = v2 + E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) + E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t + E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x + E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y + + # Some convenience constants + T_const = equations.gamma * inv_gamma_minus_one / Pr + inv_Re = 1.0 / Re + inv_rho_cubed = 1.0 / (rho^3) + + # compute the source terms + # density equation + du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y + + # x-momentum equation + du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 + + 2.0 * rho * v1 * v1_x + + rho_y * v1 * v2 + + rho * v1_y * v2 + + rho * v1 * v2_y + # stress tensor from x-direction + - 4.0 / 3.0 * v1_xx * inv_Re + + 2.0 / 3.0 * v2_xy * inv_Re + - v1_yy * inv_Re + - v2_xy * inv_Re ) + # y-momentum equation + du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 + + rho * v1_x * v2 + + rho * v1 * v2_x + + rho_y * v2^2 + + 2.0 * rho * v2 * v2_y + # stress tensor from y-direction + - v1_xy * inv_Re + - v2_xx * inv_Re + - 4.0 / 3.0 * v2_yy * inv_Re + + 2.0 / 3.0 * v1_xy * inv_Re ) + # total energy equation + du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) + + v2_y * (E + p) + v2 * (E_y + p_y) + # stress tensor and temperature gradient terms from x-direction + - 4.0 / 3.0 * v1_xx * v1 * inv_Re + + 2.0 / 3.0 * v2_xy * v1 * inv_Re + - 4.0 / 3.0 * v1_x * v1_x * inv_Re + + 2.0 / 3.0 * v2_y * v1_x * inv_Re + - v1_xy * v2 * inv_Re + - v2_xx * v2 * inv_Re + - v1_y * v2_x * inv_Re + - v2_x * v2_x * inv_Re + - T_const * inv_rho_cubed * ( p_xx * rho * rho + - 2.0 * p_x * rho * rho_x + + 2.0 * p * rho_x * rho_x + - p * rho * rho_xx ) * inv_Re + # stress tensor and temperature gradient terms from y-direction + - v1_yy * v1 * inv_Re + - v2_xy * v1 * inv_Re + - v1_y * v1_y * inv_Re + - v2_x * v1_y * inv_Re + - 4.0 / 3.0 * v2_yy * v2 * inv_Re + + 2.0 / 3.0 * v1_xy * v2 * inv_Re + - 4.0 / 3.0 * v2_y * v2_y * inv_Re + + 2.0 / 3.0 * v1_x * v2_y * inv_Re + - T_const * inv_rho_cubed * ( p_yy * rho * rho + - 2.0 * p_y * rho * rho_y + + 2.0 * p * rho_y * rho_y + - p * rho * rho_yy ) * inv_Re ) + + return SVector(du1, du2, du3, du4) +end + initial_condition = initial_condition_navier_stokes_convergence_test # BC types diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index eed500fdad1..d898d331863 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -297,146 +297,3 @@ end return flux_inner end -# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` -# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) -# and by the initial condition (which passes in `CompressibleEulerEquations2D`). -# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) -function initial_condition_navier_stokes_convergence_test(x, t, equations) - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - v1 = sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A * (x[2] - 1.0)) ) * cos(pi_t) - v2 = v1 - p = rho^2 - - return prim2cons(SVector(rho, v1, v2, p), equations) -end - -@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations) - y = x[2] - - # TODO: parabolic - # we currently need to hardcode these parameters until we fix the "combined equation" issue - # see also https://github.com/trixi-framework/Trixi.jl/pull/1160 - inv_gamma_minus_one = inv(equations.gamma - 1) - Pr = prandtl_number() - Re = reynolds_number() - - # Same settings as in `initial_condition` - # Amplitude and shift - A = 0.5 - c = 2.0 - - # convenience values for trig. functions - pi_x = pi * x[1] - pi_y = pi * x[2] - pi_t = pi * t - - # compute the manufactured solution and all necessary derivatives - rho = c + A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_t = -pi * A * sin(pi_x) * cos(pi_y) * sin(pi_t) - rho_x = pi * A * cos(pi_x) * cos(pi_y) * cos(pi_t) - rho_y = -pi * A * sin(pi_x) * sin(pi_y) * cos(pi_t) - rho_xx = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - rho_yy = -pi * pi * A * sin(pi_x) * cos(pi_y) * cos(pi_t) - - v1 = sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_t = -pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * sin(pi_t) - v1_x = pi * cos(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_y = sin(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_xx = -pi * pi * sin(pi_x) * log(y + 2.0) * (1.0 - exp(-A * (y - 1.0))) * cos(pi_t) - v1_xy = pi * cos(pi_x) * (A * log(y + 2.0) * exp(-A * (y - 1.0)) + (1.0 - exp(-A * (y - 1.0))) / (y + 2.0)) * cos(pi_t) - v1_yy = (sin(pi_x) * ( 2.0 * A * exp(-A * (y - 1.0)) / (y + 2.0) - - A * A * log(y + 2.0) * exp(-A * (y - 1.0)) - - (1.0 - exp(-A * (y - 1.0))) / ((y + 2.0) * (y + 2.0))) * cos(pi_t)) - v2 = v1 - v2_t = v1_t - v2_x = v1_x - v2_y = v1_y - v2_xx = v1_xx - v2_xy = v1_xy - v2_yy = v1_yy - - p = rho * rho - p_t = 2.0 * rho * rho_t - p_x = 2.0 * rho * rho_x - p_y = 2.0 * rho * rho_y - p_xx = 2.0 * rho * rho_xx + 2.0 * rho_x * rho_x - p_yy = 2.0 * rho * rho_yy + 2.0 * rho_y * rho_y - - # Note this simplifies slightly because the ansatz assumes that v1 = v2 - E = p * inv_gamma_minus_one + 0.5 * rho * (v1^2 + v2^2) - E_t = p_t * inv_gamma_minus_one + rho_t * v1^2 + 2.0 * rho * v1 * v1_t - E_x = p_x * inv_gamma_minus_one + rho_x * v1^2 + 2.0 * rho * v1 * v1_x - E_y = p_y * inv_gamma_minus_one + rho_y * v1^2 + 2.0 * rho * v1 * v1_y - - # Some convenience constants - T_const = equations.gamma * inv_gamma_minus_one / Pr - inv_Re = 1.0 / Re - inv_rho_cubed = 1.0 / (rho^3) - - # compute the source terms - # density equation - du1 = rho_t + rho_x * v1 + rho * v1_x + rho_y * v2 + rho * v2_y - - # x-momentum equation - du2 = ( rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2 - + 2.0 * rho * v1 * v1_x - + rho_y * v1 * v2 - + rho * v1_y * v2 - + rho * v1 * v2_y - # stress tensor from x-direction - - 4.0 / 3.0 * v1_xx * inv_Re - + 2.0 / 3.0 * v2_xy * inv_Re - - v1_yy * inv_Re - - v2_xy * inv_Re ) - # y-momentum equation - du3 = ( rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2 - + rho * v1_x * v2 - + rho * v1 * v2_x - + rho_y * v2^2 - + 2.0 * rho * v2 * v2_y - # stress tensor from y-direction - - v1_xy * inv_Re - - v2_xx * inv_Re - - 4.0 / 3.0 * v2_yy * inv_Re - + 2.0 / 3.0 * v1_xy * inv_Re ) - # total energy equation - du4 = ( E_t + v1_x * (E + p) + v1 * (E_x + p_x) - + v2_y * (E + p) + v2 * (E_y + p_y) - # stress tensor and temperature gradient terms from x-direction - - 4.0 / 3.0 * v1_xx * v1 * inv_Re - + 2.0 / 3.0 * v2_xy * v1 * inv_Re - - 4.0 / 3.0 * v1_x * v1_x * inv_Re - + 2.0 / 3.0 * v2_y * v1_x * inv_Re - - v1_xy * v2 * inv_Re - - v2_xx * v2 * inv_Re - - v1_y * v2_x * inv_Re - - v2_x * v2_x * inv_Re - - T_const * inv_rho_cubed * ( p_xx * rho * rho - - 2.0 * p_x * rho * rho_x - + 2.0 * p * rho_x * rho_x - - p * rho * rho_xx ) * inv_Re - # stress tensor and temperature gradient terms from y-direction - - v1_yy * v1 * inv_Re - - v2_xy * v1 * inv_Re - - v1_y * v1_y * inv_Re - - v2_x * v1_y * inv_Re - - 4.0 / 3.0 * v2_yy * v2 * inv_Re - + 2.0 / 3.0 * v1_xy * v2 * inv_Re - - 4.0 / 3.0 * v2_y * v2_y * inv_Re - + 2.0 / 3.0 * v1_x * v2_y * inv_Re - - T_const * inv_rho_cubed * ( p_yy * rho * rho - - 2.0 * p_y * rho * rho_y - + 2.0 * p * rho_y * rho_y - - p * rho * rho_yy ) * inv_Re ) - - return SVector(du1, du2, du3, du4) -end \ No newline at end of file From 133be3e8d17b0111b5a7fbecdf793bef15770f7b Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 11:41:57 -0500 Subject: [PATCH 104/143] Update examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl --- examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 1993d1dee58..1832ea1acf1 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -42,7 +42,7 @@ mesh = DGMultiMesh(dg; coordinates_min=(-1.0, -0.5), coordinates_max=(0.0, 0.5), # BC types boundary_condition = BoundaryConditionDirichlet(initial_condition) -# define inviscid boundary conditions +# define inviscid boundary conditions, enforce "do nothing" boundary condition at the outflow boundary_conditions = (; :left => boundary_condition, :top => boundary_condition, :bottom => boundary_condition, From 928347b21cd2fd6c9019f28a4d9b5772f00d5963 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 12:25:05 -0500 Subject: [PATCH 105/143] TODO -> Todo, and .6 -> 0.6 d --- examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl index 1832ea1acf1..b6adf242299 100644 --- a/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl +++ b/examples/dgmulti_2d/elixir_advection_diffusion_nonperiodic.jl @@ -17,7 +17,7 @@ equations_parabolic = LaplaceDiffusion2D(diffusivity(), equations) # [DOI](https://doi.org/10.1007/978-3-319-41640-3_6). function initial_condition_erikkson_johnson(x, t, equations) l = 4 - epsilon = diffusivity() # TODO: this requires epsilon < .6 due to the sqrt + epsilon = diffusivity() # Note: this requires epsilon < 0.6 due to the sqrt lambda_1 = (-1 + sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) lambda_2 = (-1 - sqrt(1 - 4 * epsilon * l)) / (-2 * epsilon) r1 = (1 + sqrt(1 + 4 * pi^2 * epsilon^2)) / (2 * epsilon) From 1060898d75236bb3c1809dd6a8cb445d3412d7a8 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 12:31:42 -0500 Subject: [PATCH 106/143] Update src/solvers/dgsem_tree/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index eb8784dc55a..042ad9f5204 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -187,6 +187,8 @@ function calc_divergence!(du, u, t, viscous_flux, mesh, equations_parabolic, dg.surface_integral, dg) end + # TODO: parabolic; extend to mortars + @assert nmortars(dg, cache) == 0 # Prolong solution to mortars # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( # cache, u, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) From 0d358def0b066bb54d38e6eaef56892573911978 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 12:52:09 -0500 Subject: [PATCH 107/143] adding note to Adiabatic/Isothermal BCs --- src/equations/compressible_navier_stokes_2d.jl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index d898d331863..d1a9589b387 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -245,9 +245,10 @@ end """ struct Isothermal -Creates an isothermal temperature boundary condition with field `boundary_value_function`, -which should be a function with signature `boundary_value_function(x, t, equations)` and -return a scalar value for the temperature at point `x` and time `t`. +Used to create a no-slip boundary condition with `BoundaryConditionViscousWall`. +The field `boundary_value_function` should be a function with signature +`boundary_value_function(x, t, equations)` and return a scalar value for the +temperature at point `x` and time `t`. """ struct Isothermal{F} boundary_value_function::F # value of the temperature on the boundary @@ -256,9 +257,10 @@ end """ struct Adiabatic -Creates an adiabatic temperature boundary condition with field `boundary_value_function`, -which should be a function with signature `boundary_value_function(x, t, equations)` and -return a scalar value for the normal heat flux at point `x` and time `t`. +Used to create a no-slip boundary condition with `BoundaryConditionViscousWall`. +The field `boundary_value_normal_flux_function` should be a function with signature +`boundary_value_normal_flux_function(x, t, equations)` and return a scalar value for the +normal heat flux at point `x` and time `t`. """ struct Adiabatic{F} boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn From 4f757d303b7506b71014445a4c50747d396b916a Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 12:59:00 -0500 Subject: [PATCH 108/143] replacing CompressibleNavierStokesEquations with ...Diffusion --- .../elixir_navier_stokes_convergence.jl | 6 ++-- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- .../elixir_navier_stokes_convergence.jl | 6 ++-- .../elixir_navier_stokes_lid_driven_cavity.jl | 2 +- src/Trixi.jl | 2 +- .../compressible_navier_stokes_2d.jl | 36 ++++++++++--------- src/equations/equations_parabolic.jl | 4 +-- src/equations/laplace_diffusion_2d.jl | 2 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index c67b67e119e..d2601f07e3e 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -10,7 +10,7 @@ prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) # Note: If you change the Navier-Stokes parameters here, also change them in the initial condition # I really do not like this structure but it should work for now -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -22,8 +22,8 @@ top_bottom(x, tol=50*eps()) = abs(abs(x[2]) - 1) < tol is_on_boundary = Dict(:top_bottom => top_bottom) mesh = DGMultiMesh(dg, cells_per_dimension=(16, 16); periodicity=(true, false), is_on_boundary) -# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` -# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index bd017cd209d..7030b5ba553 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -10,7 +10,7 @@ prandtl_number() = 0.72 mach_number() = 0.1 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=mach_number()) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 07a5a8d8fd5..942de106e0c 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -8,7 +8,7 @@ reynolds_number() = 100 prandtl_number() = 0.72 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux @@ -23,8 +23,8 @@ mesh = TreeMesh(coordinates_min, coordinates_max, periodicity=(true, false), n_cells_max=30_000) # set maximum capacity of tree data structure -# Note: the initial condition cannot be specialized to `CompressibleNavierStokesEquations2D` -# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesEquations2D`) +# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion2D` +# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion2D`) # and by the initial condition (which passes in `CompressibleEulerEquations2D`). # This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000) function initial_condition_navier_stokes_convergence_test(x, t, equations) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index 25cefc788c2..0c9a7b89d9f 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -10,7 +10,7 @@ prandtl_number() = 0.72 mach_number() = 0.1 equations = CompressibleEulerEquations2D(1.4) -equations_parabolic = CompressibleNavierStokesEquations2D(equations, Reynolds=reynolds_number(), +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, Reynolds=reynolds_number(), Prandtl=prandtl_number(), Mach_freestream=mach_number()) diff --git a/src/Trixi.jl b/src/Trixi.jl index 61d8fa46c2e..53bc6c1b791 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -135,7 +135,7 @@ export AcousticPerturbationEquations2D, ShallowWaterEquations1D, ShallowWaterEquations2D export LaplaceDiffusion2D, - CompressibleNavierStokesEquations2D + CompressibleNavierStokesDiffusion2D export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index d1a9589b387..1fc66e0b396 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -1,5 +1,5 @@ @doc raw""" - CompressibleNavierStokesEquations2D(gamma, Re, Pr, Ma_inf, equations) + CompressibleNavierStokesDiffusion2D(gamma, Re, Pr, Ma_inf, equations) These equations contain the diffusion (i.e. parabolic) terms applied to mass, momenta, and total energy together with the advective terms from @@ -81,7 +81,7 @@ Other normalization strategies exist, see the reference below for details. [CERFACS Technical report](https://www.cerfacs.fr/~montagna/TR-CFD-13-77.pdf) The scaling used herein is Section 4.5 of the reference. """ -struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesEquations{2, 4} +struct CompressibleNavierStokesDiffusion2D{RealT <: Real, E <: AbstractCompressibleEulerEquations{2}} <: AbstractCompressibleNavierStokesDiffusion{2, 4} # TODO: parabolic # 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations # 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function @@ -99,7 +99,7 @@ struct CompressibleNavierStokesEquations2D{RealT <: Real, E <: AbstractCompressi equations_hyperbolic::E # CompressibleEulerEquations2D end -function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream) +function CompressibleNavierStokesDiffusion2D(equations::CompressibleEulerEquations2D; Reynolds, Prandtl, Mach_freestream) gamma = equations.gamma inv_gamma_minus_one = equations.inv_gamma_minus_one Re, Pr, Ma = promote(Reynolds, Prandtl, Mach_freestream) @@ -115,7 +115,7 @@ function CompressibleNavierStokesEquations2D(equations::CompressibleEulerEquatio p_inf = 1 / gamma u_inf = Mach_freestream R = 1 / gamma - CompressibleNavierStokesEquations2D{typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, + CompressibleNavierStokesDiffusion2D{typeof(gamma), typeof(equations)}(gamma, inv_gamma_minus_one, Re, Pr, Ma, kappa, p_inf, u_inf, R, equations) @@ -124,15 +124,15 @@ end # TODO: parabolic # This is the flexibility a user should have to select the different gradient variable types -# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesEquations2D) = ("v1", "v2", "T") -# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesEquations2D) = ("w2", "w3", "w4") +# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesDiffusion2D) = ("v1", "v2", "T") +# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesDiffusion2D) = ("w2", "w3", "w4") -varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesEquations2D) = +varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesDiffusion2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # we specialize this function to compute gradients of primitive variables instead of # conservative variables. -gradient_variable_transformation(::CompressibleNavierStokesEquations2D, dg_parabolic) = cons2prim +gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D, dg_parabolic) = cons2prim # no orientation specified since the flux is vector-valued # Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 @@ -144,7 +144,7 @@ gradient_variable_transformation(::CompressibleNavierStokesEquations2D, dg_parab # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, grad_u, equations::CompressibleNavierStokesEquations2D) +function flux(u, grad_u, equations::CompressibleNavierStokesDiffusion2D) # Here grad_u is assumed to contain the gradients of the primitive variables (v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function @@ -191,7 +191,7 @@ end # Convert conservative variables to primitive -@inline function cons2prim(u, equations::CompressibleNavierStokesEquations2D) +@inline function cons2prim(u, equations::CompressibleNavierStokesDiffusion2D) rho, rho_v1, rho_v2, _ = u v1 = rho_v1 / rho @@ -203,13 +203,13 @@ end # This routine is required because `prim2cons` is called in `initial_condition`, which # is called with `equations::CompressibleEulerEquations2D`. This means it is inconsistent -# with `cons2prim(..., ::CompressibleNavierStokesEquations2D)` as defined above. +# with `cons2prim(..., ::CompressibleNavierStokesDiffusion2D)` as defined above. # TODO: parabolic. Is there a way to clean this up? -@inline prim2cons(u, equations::CompressibleNavierStokesEquations2D) = +@inline prim2cons(u, equations::CompressibleNavierStokesDiffusion2D) = prim2cons(u, equations.equations_hyperbolic) -@inline function temperature(u, equations::CompressibleNavierStokesEquations2D) +@inline function temperature(u, equations::CompressibleNavierStokesDiffusion2D) rho, rho_v1, rho_v2, rho_e = u p = (equations.gamma - 1) * (rho_e - 0.5 * (rho_v1^2 + rho_v2^2) / rho) @@ -217,6 +217,8 @@ end return T end +# TODO: can we generalize this to MHD? +# !!! warning "Experimental feature" """ struct BoundaryConditionViscousWall @@ -268,14 +270,14 @@ end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::CompressibleNavierStokesEquations2D) + equations::CompressibleNavierStokesDiffusion2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) return SVector(u_inner[1], v1, v2, u_inner[4]) end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::CompressibleNavierStokesEquations2D) + equations::CompressibleNavierStokesDiffusion2D) # rho, v1, v2, _ = u_inner normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x, t, equations) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -287,7 +289,7 @@ end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, - equations::CompressibleNavierStokesEquations2D) + equations::CompressibleNavierStokesDiffusion2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t, equations) return SVector(u_inner[1], v1, v2, T) @@ -295,7 +297,7 @@ end @inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, - equations::CompressibleNavierStokesEquations2D) + equations::CompressibleNavierStokesDiffusion2D) return flux_inner end diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index 24f2b51503c..4e2aec24946 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -3,9 +3,9 @@ gradient_variable_transformation(::AbstractEquationsParabolic, dg_parabolic) = cons2cons # Linear scalar diffusion for use in linear scalar advection-diffusion problems -abstract type AbstractLaplaceDiffusionEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end +abstract type AbstractLaplaceDiffusion{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("laplace_diffusion_2d.jl") # Compressible Navier-Stokes equations -abstract type AbstractCompressibleNavierStokesEquations{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end +abstract type AbstractCompressibleNavierStokesDiffusion{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end include("compressible_navier_stokes_2d.jl") diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index 66846639599..fcfc2a24a95 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -4,7 +4,7 @@ `LaplaceDiffusion2D` represents a scalar diffusion term ``\nabla \cdot (\kappa\nabla u))`` with diffusivity ``\kappa`` applied to each solution component defined by `equations`. """ -struct LaplaceDiffusion2D{E, N, T} <: AbstractLaplaceDiffusionEquations{2, N} +struct LaplaceDiffusion2D{E, N, T} <: AbstractLaplaceDiffusion{2, N} diffusivity::T equations_hyperbolic::E end diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index eb8784dc55a..75e2ec899e2 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -399,7 +399,7 @@ function calc_divergence_boundary_flux_by_direction!(surface_flux_values::Abstra # TODO: add a field in `cache.boundaries` for gradient information. # Here, we pass in `u_inner = nothing` since we overwrite cache.boundaries.u with gradient information. # This currently works with Dirichlet/Neuman boundary conditions for LaplaceDiffusion2D and - # NoSlipWall/Adiabatic boundary conditions for CompressibleNavierStokesEquations2D as of 2022-6-27. + # NoSlipWall/Adiabatic boundary conditions for CompressibleNavierStokesDiffusion2D as of 2022-6-27. # It will not work with implementations which utilize `u_inner` to impose boundary conditions. flux = boundary_condition(flux_inner, nothing, get_unsigned_normal_vector_2d(direction), x, t, Divergence(), equations_parabolic) From 65f491b1196573b9ae6b07f833b99d50cf913840 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:03:22 -0500 Subject: [PATCH 109/143] Update src/solvers/dgsem_tree/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 7f1b4ac0f8b..ae8892521ff 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -260,7 +260,7 @@ function calc_viscous_fluxes!(viscous_flux, u_grad, u, mesh::TreeMesh{2}, end end -# TODO: decide if we should keep this, and if so, extend to 3D. +# TODO: parabolic; decide if we should keep this, and if so, extend to 3D. function get_unsigned_normal_vector_2d(direction) if direction > 4 || direction < 1 @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." From d2facb0949f55b973ad7527c00d8f843bdba4d11 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:03:30 -0500 Subject: [PATCH 110/143] Update src/solvers/dgsem_tree/dg_2d_parabolic.jl Co-authored-by: Hendrik Ranocha --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index ae8892521ff..aa5865964cb 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -544,15 +544,7 @@ function calc_gradient!(u_grad, u, t, mesh, equations_parabolic, dg.surface_integral, dg) end - # Prolong solution to mortars - # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( - # cache, u, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) - - # Calculate mortar fluxes - # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( - # cache.elements.surface_flux_values, mesh, - # have_nonconservative_terms(equations_parabolic), equations_parabolic, - # dg.mortar, dg.surface_integral, dg, cache) +# TODO: parabolic; mortars # Calculate surface integrals @trixi_timeit timer() "surface integral" begin From 299f04e4c91c73a5fe66e81007a256b7d1027cb4 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:12:19 -0500 Subject: [PATCH 111/143] documenting Jacobian sign flip --- src/solvers/dgmulti/dg_parabolic.jl | 4 ++++ src/solvers/dgsem_tree/dg_2d_parabolic.jl | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index b4ca12311b2..0022e437df6 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -282,6 +282,10 @@ function calc_divergence!(du, u::StructArray, t, viscous_flux, mesh::DGMultiMesh # surface contributions apply_to_each_field(mul_by_accum!(dg.basis.LIFT), du, scalar_flux_face_values) + # Note: we do not flip the sign of the geometric Jacobian here. + # This is because the parabolic fluxes are assumed to be of the form + # `du/dt + df/dx = dg/dx + source(x,t)`, + # where f(u) is the inviscid flux and g(u) is the viscous flux. invert_jacobian!(du, mesh, equations, dg, cache; scaling=1.0) end diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 7f1b4ac0f8b..a37d778dbf8 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -636,7 +636,10 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::Abstrac end -# Needed to *not* flip the sign of the inverse Jacobian +# Needed to *not* flip the sign of the inverse Jacobian. +# This is because the parabolic fluxes are assumed to be of the form +# `du/dt + df/dx = dg/dx + source(x,t)`, +# where f(u) is the inviscid flux and g(u) is the viscous flux. function apply_jacobian!(du, mesh::TreeMesh{2}, equations::AbstractEquationsParabolic, dg::DG, cache) From 144fc593a31502b5de39cd3d4ecaf77a586331c2 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:22:24 -0500 Subject: [PATCH 112/143] remove extra arg to `gradient_variable_transformation` --- src/equations/compressible_navier_stokes_2d.jl | 2 +- src/equations/equations_parabolic.jl | 2 +- src/solvers/dgmulti/dg_parabolic.jl | 2 +- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 1fc66e0b396..e8f449d9e53 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -132,7 +132,7 @@ varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesDiffusio # we specialize this function to compute gradients of primitive variables instead of # conservative variables. -gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D, dg_parabolic) = cons2prim +gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D) = cons2prim # no orientation specified since the flux is vector-valued # Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 diff --git a/src/equations/equations_parabolic.jl b/src/equations/equations_parabolic.jl index 4e2aec24946..340cf0e4294 100644 --- a/src/equations/equations_parabolic.jl +++ b/src/equations/equations_parabolic.jl @@ -1,6 +1,6 @@ # specify transformation of conservative variables prior to taking gradients. # specialize this function to compute gradients e.g., of primitive variables instead of conservative -gradient_variable_transformation(::AbstractEquationsParabolic, dg_parabolic) = cons2cons +gradient_variable_transformation(::AbstractEquationsParabolic) = cons2cons # Linear scalar diffusion for use in linear scalar advection-diffusion problems abstract type AbstractLaplaceDiffusion{NDIMS, NVARS} <: AbstractEquationsParabolic{NDIMS, NVARS} end diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 6da29b9b30b..ac4e62137a5 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -44,7 +44,7 @@ end function transform_variables!(u_transformed, u, mesh, equations_parabolic::AbstractEquationsParabolic, dg::DGMulti, dg_parabolic, cache, cache_parabolic) @threaded for i in eachindex(u) - u_transformed[i] = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u[i], equations_parabolic) + u_transformed[i] = gradient_variable_transformation(equations_parabolic)(u[i], equations_parabolic) end end diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 5eee856ffa9..55a7b624c60 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -50,7 +50,7 @@ function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_transformed_node = gradient_variable_transformation(equations_parabolic, dg_parabolic)(u_node, equations_parabolic) + u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, equations_parabolic) set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) end end From ce7a045c037add613ca8fa34c39b4bd050a332f4 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:32:12 -0500 Subject: [PATCH 113/143] Update src/solvers/dgsem_tree/dg_2d_parabolic.jl Co-authored-by: Michael Schlottke-Lakemper --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 55a7b624c60..8d56d98a4a8 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -265,7 +265,7 @@ function get_unsigned_normal_vector_2d(direction) if direction > 4 || direction < 1 @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." end - if direction==1 || direction==2 + if direction == 1 || direction == 2 return SVector(1.0, 0.0) else return SVector(0.0, 1.0) From 5bf23e51b35babd0f92a0c490be2808ac42eb54c Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:35:17 -0500 Subject: [PATCH 114/143] change warning to error --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 8d56d98a4a8..f76a6324c35 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -263,7 +263,7 @@ end # TODO: parabolic; decide if we should keep this, and if so, extend to 3D. function get_unsigned_normal_vector_2d(direction) if direction > 4 || direction < 1 - @warn "Direction = $direction; in 2D, direction should be 1, 2, 3, or 4." + error("Direction = $direction; in 2D, direction should be 1, 2, 3, or 4.") end if direction == 1 || direction == 2 return SVector(1.0, 0.0) From 9f4a8b102be152fc4caa96d4f51c971e496ad6d1 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 13:55:21 -0500 Subject: [PATCH 115/143] fix bug introduced by search/replace --- src/solvers/dgmulti/dg_parabolic.jl | 4 ++-- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index ac4e62137a5..36b0172eb39 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -167,7 +167,7 @@ function calc_single_boundary_flux!(flux_face_values, u_face_values, t, return nothing end -function calc_flux_viscouses!(flux_viscous, u, u_grad, mesh::DGMultiMesh, +function calc_viscous_fluxes!(flux_viscous, u, u_grad, mesh::DGMultiMesh, equations::AbstractEquationsParabolic, dg::DGMulti, cache, cache_parabolic) @@ -308,7 +308,7 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) - calc_flux_viscouses!(flux_viscous, u_transformed, u_grad, + calc_viscous_fluxes!(flux_viscous, u_transformed, u_grad, mesh, equations_parabolic, dg, cache, cache_parabolic) calc_divergence!(du, u_transformed, t, flux_viscous, mesh, equations_parabolic, diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index f76a6324c35..7dc563f0e6d 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -25,7 +25,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra boundary_conditions, dg, cache, cache_parabolic) - @trixi_timeit timer() "calculate viscous fluxes" calc_flux_viscouses!(flux_viscous, u_grad, u_transformed, + @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(flux_viscous, u_grad, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) @@ -242,7 +242,7 @@ function calc_divergence!(du, u, t, flux_viscous, end -function calc_flux_viscouses!(flux_viscous, u_grad, u, mesh::TreeMesh{2}, +function calc_viscous_fluxes!(flux_viscous, u_grad, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) From 1159377d6dd2d385a952510b441dcf0f38a3731f Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 15:22:44 -0500 Subject: [PATCH 116/143] dg_parabolic -> parabolic_scheme --- src/solvers/dgmulti/dg_parabolic.jl | 20 ++++++++++---------- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 36b0172eb39..563eb431544 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -1,7 +1,7 @@ function create_cache_parabolic(mesh::DGMultiMesh, equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, - dg::DGMulti, dg_parabolic, RealT, uEltype) + dg::DGMulti, parabolic_scheme, RealT, uEltype) # default to taking derivatives of all hyperbolic terms # TODO: parabolic; utilize the parabolic variables in `equations_parabolic` to reduce memory usage in the parabolic cache nvars = nvariables(equations_hyperbolic) @@ -42,7 +42,7 @@ end # (e.g., conservative to primitive variables). Defaults to doing nothing. # TODO: can we avoid copying data? function transform_variables!(u_transformed, u, mesh, equations_parabolic::AbstractEquationsParabolic, - dg::DGMulti, dg_parabolic, cache, cache_parabolic) + dg::DGMulti, parabolic_scheme, cache, cache_parabolic) @threaded for i in eachindex(u) u_transformed[i] = gradient_variable_transformation(equations_parabolic)(u[i], equations_parabolic) end @@ -211,13 +211,13 @@ end # no penalization for a BR1 parabolic solver function calc_viscous_penalty!(scalar_flux_face_values, u_face_values, t, boundary_conditions, mesh, equations::AbstractEquationsParabolic, dg::DGMulti, - dg_parabolic::ViscousFormulationBassiRebay1, cache, cache_parabolic) + parabolic_scheme::ViscousFormulationBassiRebay1, cache, cache_parabolic) return nothing end function calc_viscous_penalty!(scalar_flux_face_values, u_face_values, t, boundary_conditions, mesh, equations::AbstractEquationsParabolic, dg::DGMulti, - dg_parabolic, cache, cache_parabolic) + parabolic_scheme, cache, cache_parabolic) # compute fluxes at interfaces @unpack scalar_flux_face_values, inv_h = cache_parabolic @unpack mapM, mapP = mesh.md @@ -225,7 +225,7 @@ function calc_viscous_penalty!(scalar_flux_face_values, u_face_values, t, bounda idM, idP = mapM[face_node_index], mapP[face_node_index] uM, uP = u_face_values[idM], u_face_values[idP] inv_h_face = inv_h[face_node_index] - scalar_flux_face_values[idM] = scalar_flux_face_values[idM] + penalty(uP, uM, inv_h_face, equations, dg_parabolic) + scalar_flux_face_values[idM] = scalar_flux_face_values[idM] + penalty(uP, uM, inv_h_face, equations, parabolic_scheme) end return nothing end @@ -233,7 +233,7 @@ end function calc_divergence!(du, u::StructArray, t, flux_viscous, mesh::DGMultiMesh, equations::AbstractEquationsParabolic, - boundary_conditions, dg::DGMulti, dg_parabolic, cache, cache_parabolic) + boundary_conditions, dg::DGMulti, parabolic_scheme, cache, cache_parabolic) @unpack weak_differentiation_matrices = cache_parabolic @@ -276,7 +276,7 @@ function calc_divergence!(du, u::StructArray, t, flux_viscous, mesh::DGMultiMesh boundary_conditions, mesh, equations, dg, cache, cache_parabolic) calc_viscous_penalty!(scalar_flux_face_values, cache_parabolic.u_face_values, t, - boundary_conditions, mesh, equations, dg, dg_parabolic, + boundary_conditions, mesh, equations, dg, parabolic_scheme, cache, cache_parabolic) # surface contributions @@ -297,13 +297,13 @@ end # boundary conditions will be applied to both grad(u) and div(u). function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions, source_terms, - dg::DGMulti, dg_parabolic, cache, cache_parabolic) + dg::DGMulti, parabolic_scheme, cache, cache_parabolic) reset_du!(du, dg) @unpack u_transformed, u_grad, flux_viscous = cache_parabolic transform_variables!(u_transformed, u, mesh, equations_parabolic, - dg, dg_parabolic, cache, cache_parabolic) + dg, parabolic_scheme, cache, cache_parabolic) calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) @@ -312,7 +312,7 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra mesh, equations_parabolic, dg, cache, cache_parabolic) calc_divergence!(du, u_transformed, t, flux_viscous, mesh, equations_parabolic, - boundary_conditions, dg, dg_parabolic, cache, cache_parabolic) + boundary_conditions, dg, parabolic_scheme, cache, cache_parabolic) return nothing diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 7dc563f0e6d..b77627cac89 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -8,7 +8,7 @@ # boundary conditions will be applied to both grad(u) and div(u). function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, initial_condition, boundary_conditions, source_terms, - dg::DG, dg_parabolic, cache, cache_parabolic) + dg::DG, parabolic_scheme, cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) @@ -17,7 +17,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @unpack u_transformed, u_grad, flux_viscous = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, mesh, equations_parabolic, - dg, dg_parabolic, + dg, parabolic_scheme, cache, cache_parabolic) @trixi_timeit timer() "calculate gradient" calc_gradient!(u_grad, u_transformed, t, mesh, @@ -33,7 +33,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra mesh, equations_parabolic, boundary_conditions, dg, - dg_parabolic, cache, + parabolic_scheme, cache, cache_parabolic) return nothing @@ -45,7 +45,7 @@ end # TODO: can we avoid copying data? function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, - dg::DG, dg_parabolic, cache, cache_parabolic) + dg::DG, parabolic_scheme, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) @@ -56,12 +56,12 @@ function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, end end -# note: the argument dg_parabolic is not a DG type; it contains solver-specific +# note: the argument parabolic_scheme is not a DG type; it contains solver-specific # information such as an LDG penalty parameter. function calc_divergence!(du, u, t, flux_viscous, mesh::TreeMesh{2}, equations_parabolic, boundary_conditions_parabolic, dg::DG, - dg_parabolic, # not a `DG` type + parabolic_scheme, # not a `DG` type cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" begin @@ -599,7 +599,7 @@ end # the RHS etc. function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::AbstractEquations, equations_parabolic::AbstractEquationsParabolic, - dg::DG, dg_parabolic, RealT, uEltype) + dg::DG, parabolic_scheme, RealT, uEltype) # Get cells for which an element needs to be created (i.e. all leaf cells) leaf_cell_ids = local_leaf_cells(mesh.tree) From bf42a660a9e6f5d4c75c5297767679a5c168e525 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 15:49:03 -0500 Subject: [PATCH 117/143] BoundaryConditionViscousWall -> BoundaryConditionNavierStokesWall --- .../elixir_navier_stokes_convergence.jl | 2 +- .../elixir_navier_stokes_lid_driven_cavity.jl | 4 ++-- .../elixir_navier_stokes_convergence.jl | 2 +- .../elixir_navier_stokes_lid_driven_cavity.jl | 4 ++-- src/Trixi.jl | 2 +- src/equations/compressible_navier_stokes_2d.jl | 18 +++++++++--------- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl index d2601f07e3e..4995acccb78 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_convergence.jl @@ -171,7 +171,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test # BC types velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; :top_bottom => boundary_condition_slip_wall) diff --git a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl index 7030b5ba553..be8ad1a0730 100644 --- a/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/dgmulti_2d/elixir_navier_stokes_lid_driven_cavity.jl @@ -37,8 +37,8 @@ initial_condition = initial_condition_cavity velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) heat_bc = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) -boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) +boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) # define inviscid boundary conditions boundary_conditions = (; :top => boundary_condition_slip_wall, diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 942de106e0c..6ecb7f7d8fe 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -172,7 +172,7 @@ initial_condition = initial_condition_navier_stokes_convergence_test # BC types velocity_bc_top_bottom = NoSlip((x, t, equations) -> initial_condition_navier_stokes_convergence_test(x, t, equations)[2:3]) heat_bc_top_bottom = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_top_bottom = BoundaryConditionViscousWall(velocity_bc_top_bottom, heat_bc_top_bottom) +boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom, heat_bc_top_bottom) # define inviscid boundary conditions boundary_conditions = (; x_neg = boundary_condition_periodic, diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl index 0c9a7b89d9f..bf40aaa41df 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_lid_driven_cavity.jl @@ -40,8 +40,8 @@ initial_condition = initial_condition_cavity velocity_bc_lid = NoSlip((x, t, equations) -> SVector(1.0, 0.0)) velocity_bc_cavity = NoSlip((x, t, equations) -> SVector(0.0, 0.0)) heat_bc = Adiabatic((x, t, equations) -> 0.0) -boundary_condition_lid = BoundaryConditionViscousWall(velocity_bc_lid, heat_bc) -boundary_condition_cavity = BoundaryConditionViscousWall(velocity_bc_cavity, heat_bc) +boundary_condition_lid = BoundaryConditionNavierStokesWall(velocity_bc_lid, heat_bc) +boundary_condition_cavity = BoundaryConditionNavierStokesWall(velocity_bc_cavity, heat_bc) # define periodic boundary conditions everywhere boundary_conditions = boundary_condition_slip_wall diff --git a/src/Trixi.jl b/src/Trixi.jl index 53bc6c1b791..e6e4e6da692 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -164,7 +164,7 @@ export boundary_condition_do_nothing, boundary_condition_noslip_wall, boundary_condition_slip_wall, boundary_condition_wall, - BoundaryConditionViscousWall, NoSlip, Adiabatic, Isothermal + BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal export initial_condition_convergence_test, source_terms_convergence_test export source_terms_harmonic diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index e8f449d9e53..32499d03f02 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -220,14 +220,14 @@ end # TODO: can we generalize this to MHD? # !!! warning "Experimental feature" """ - struct BoundaryConditionViscousWall + struct BoundaryConditionNavierStokesWall Creates a wall-type boundary conditions for the compressible Navier-Stokes equations. The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended to be boundary condition types such as the `NoSlip` velocity boundary condition and the `Adiabatic` or `Isothermal` heat boundary condition. """ -struct BoundaryConditionViscousWall{V, H} +struct BoundaryConditionNavierStokesWall{V, H} boundary_condition_velocity::V boundary_condition_heat_flux::H end @@ -235,7 +235,7 @@ end """ struct NoSlip -Use to create a no-slip boundary condition with `BoundaryConditionViscousWall`. The field `boundary_value_function` +Use to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. The field `boundary_value_function` should be a function with signature `boundary_value_function(x, t, equations)` and should return a `SVector{NDIMS}` whose entries are the velocity vector at a point `x` and time `t`. @@ -247,7 +247,7 @@ end """ struct Isothermal -Used to create a no-slip boundary condition with `BoundaryConditionViscousWall`. +Used to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. The field `boundary_value_function` should be a function with signature `boundary_value_function(x, t, equations)` and return a scalar value for the temperature at point `x` and time `t`. @@ -259,7 +259,7 @@ end """ struct Adiabatic -Used to create a no-slip boundary condition with `BoundaryConditionViscousWall`. +Used to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. The field `boundary_value_normal_flux_function` should be a function with signature `boundary_value_normal_flux_function(x, t, equations)` and return a scalar value for the normal heat flux at point `x` and time `t`. @@ -268,14 +268,14 @@ struct Adiabatic{F} boundary_value_normal_flux_function::F # scaled heat flux 1/T * kappa * dT/dn end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) return SVector(u_inner[1], v1, v2, u_inner[4]) end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, <:Adiabatic})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D) # rho, v1, v2, _ = u_inner @@ -287,7 +287,7 @@ end end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Gradient, equations::CompressibleNavierStokesDiffusion2D) v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x, t, equations) @@ -295,7 +295,7 @@ end return SVector(u_inner[1], v1, v2, T) end -@inline function (boundary_condition::BoundaryConditionViscousWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, +@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip, <:Isothermal})(flux_inner, u_inner, normal::AbstractVector, x, t, operator_type::Divergence, equations::CompressibleNavierStokesDiffusion2D) return flux_inner From 020fb1504f9ad1af69418425dd2edc559406622d Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 16:06:12 -0500 Subject: [PATCH 118/143] u_grad -> gradients --- src/solvers/dgmulti/dg_parabolic.jl | 36 +++++++++++------------ src/solvers/dgsem_tree/dg_2d_parabolic.jl | 36 +++++++++++------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 563eb431544..953c371fcbc 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -12,8 +12,8 @@ function create_cache_parabolic(mesh::DGMultiMesh, # u_transformed stores "transformed" variables for computing the gradient @unpack md = mesh u_transformed = allocate_nested_array(uEltype, nvars, size(md.x), dg) - u_grad = ntuple(_ -> similar(u_transformed), ndims(mesh)) - flux_viscous = similar.(u_grad) + gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) + flux_viscous = similar.(gradients) u_face_values = allocate_nested_array(uEltype, nvars, size(md.xf), dg) scalar_flux_face_values = similar(u_face_values) @@ -32,7 +32,7 @@ function create_cache_parabolic(mesh::DGMultiMesh, end end - return (; u_transformed, u_grad, flux_viscous, + return (; u_transformed, gradients, flux_viscous, weak_differentiation_matrices, inv_h, u_face_values, grad_u_face_values, scalar_flux_face_values, local_u_values_threaded, local_flux_viscous_threaded, local_flux_face_values_threaded) @@ -54,7 +54,7 @@ function prolong2interfaces!(u_face_values, u, mesh::DGMultiMesh, equations::Abs apply_to_each_field(mul_by!(dg.basis.Vf), u_face_values, u) end -function calc_gradient_surface_integral(u_grad, u, scalar_flux_face_values, +function calc_gradient_surface_integral(gradients, u, scalar_flux_face_values, mesh, equations::AbstractEquationsParabolic, dg::DGMulti, cache, cache_parabolic) @unpack local_flux_face_values_threaded = cache_parabolic @@ -65,19 +65,19 @@ function calc_gradient_surface_integral(u_grad, u, scalar_flux_face_values, # compute flux * (nx, ny, nz) local_flux_values[i] = scalar_flux_face_values[i, e] * mesh.md.nxyzJ[dim][i, e] end - apply_to_each_field(mul_by_accum!(dg.basis.LIFT), view(u_grad[dim], :, e), local_flux_values) + apply_to_each_field(mul_by_accum!(dg.basis.LIFT), view(gradients[dim], :, e), local_flux_values) end end end -function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, +function calc_gradient!(gradients, u::StructArray, t, mesh::DGMultiMesh, equations::AbstractEquationsParabolic, boundary_conditions, dg::DGMulti, cache, cache_parabolic) @unpack weak_differentiation_matrices = cache_parabolic - for dim in eachindex(u_grad) - reset_du!(u_grad[dim], dg) + for dim in eachindex(gradients) + reset_du!(gradients[dim], dg) end # compute volume contributions to gradients @@ -85,7 +85,7 @@ function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, for i in eachdim(mesh), j in eachdim(mesh) dxidxhatj = mesh.md.rstxyzJ[i, j][1, e] # TODO: DGMulti. Assumes mesh is affine here. apply_to_each_field(mul_by_accum!(weak_differentiation_matrices[j], dxidxhatj), - view(u_grad[i], :, e), view(u, :, e)) + view(gradients[i], :, e), view(u, :, e)) end end @@ -106,11 +106,11 @@ function calc_gradient!(u_grad, u::StructArray, t, mesh::DGMultiMesh, mesh, equations, dg, cache, cache_parabolic) # compute surface contributions - calc_gradient_surface_integral(u_grad, u, scalar_flux_face_values, + calc_gradient_surface_integral(gradients, u, scalar_flux_face_values, mesh, equations, dg, cache, cache_parabolic) for dim in eachdim(mesh) - invert_jacobian!(u_grad[dim], mesh, equations, dg, cache; scaling=1.0) + invert_jacobian!(gradients[dim], mesh, equations, dg, cache; scaling=1.0) end end @@ -167,7 +167,7 @@ function calc_single_boundary_flux!(flux_face_values, u_face_values, t, return nothing end -function calc_viscous_fluxes!(flux_viscous, u, u_grad, mesh::DGMultiMesh, +function calc_viscous_fluxes!(flux_viscous, u, gradients, mesh::DGMultiMesh, equations::AbstractEquationsParabolic, dg::DGMulti, cache, cache_parabolic) @@ -190,14 +190,14 @@ function calc_viscous_fluxes!(flux_viscous, u, u_grad, mesh::DGMultiMesh, # interpolate u and gradient to quadrature points, store in `local_flux_viscous` apply_to_each_field(mul_by!(dg.basis.Vq), local_u_values, view(u, :, e)) # TODO: DGMulti. Specialize for nodal collocation methods (SBP, GaussSBP) for dim in eachdim(mesh) - apply_to_each_field(mul_by!(dg.basis.Vq), local_flux_viscous[dim], view(u_grad[dim], :, e)) + apply_to_each_field(mul_by!(dg.basis.Vq), local_flux_viscous[dim], view(gradients[dim], :, e)) end # compute viscous flux at quad points for i in eachindex(local_u_values) u_i = local_u_values[i] - u_grad_i = getindex.(local_flux_viscous, i) - flux_viscous_i = flux(u_i, u_grad_i, equations) + gradients_i = getindex.(local_flux_viscous, i) + flux_viscous_i = flux(u_i, gradients_i, equations) setindex!.(local_flux_viscous, flux_viscous_i, i) end @@ -301,14 +301,14 @@ function rhs_parabolic!(du, u, t, mesh::DGMultiMesh, equations_parabolic::Abstra reset_du!(du, dg) - @unpack u_transformed, u_grad, flux_viscous = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = cache_parabolic transform_variables!(u_transformed, u, mesh, equations_parabolic, dg, parabolic_scheme, cache, cache_parabolic) - calc_gradient!(u_grad, u_transformed, t, mesh, equations_parabolic, + calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) - calc_viscous_fluxes!(flux_viscous, u_transformed, u_grad, + calc_viscous_fluxes!(flux_viscous, u_transformed, gradients, mesh, equations_parabolic, dg, cache, cache_parabolic) calc_divergence!(du, u_transformed, t, flux_viscous, mesh, equations_parabolic, diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index b77627cac89..cc8a34e4862 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -14,18 +14,18 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - @unpack u_transformed, u_grad, flux_viscous = cache_parabolic + @unpack u_transformed, gradients, flux_viscous = cache_parabolic @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, mesh, equations_parabolic, dg, parabolic_scheme, cache, cache_parabolic) - @trixi_timeit timer() "calculate gradient" calc_gradient!(u_grad, u_transformed, t, mesh, + @trixi_timeit timer() "calculate gradient" calc_gradient!(gradients, u_transformed, t, mesh, equations_parabolic, boundary_conditions, dg, cache, cache_parabolic) - @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(flux_viscous, u_grad, u_transformed, + @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) @@ -242,18 +242,18 @@ function calc_divergence!(du, u, t, flux_viscous, end -function calc_viscous_fluxes!(flux_viscous, u_grad, u, mesh::TreeMesh{2}, +function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_grad_1_node = get_node_vars(u_grad[1], equations_parabolic, dg, i, j, element) - u_grad_2_node = get_node_vars(u_grad[2], equations_parabolic, dg, i, j, element) + gradients_1_node = get_node_vars(gradients[1], equations_parabolic, dg, i, j, element) + gradients_2_node = get_node_vars(gradients[2], equations_parabolic, dg, i, j, element) # Calculate viscous flux and store each component for later use - flux_viscous_node = flux(u_node, (u_grad_1_node, u_grad_2_node), equations_parabolic) + flux_viscous_node = flux(u_node, (gradients_1_node, gradients_2_node), equations_parabolic) set_node_vars!(flux_viscous[1], flux_viscous_node[1], equations_parabolic, dg, i, j, element) set_node_vars!(flux_viscous[2], flux_viscous_node[2], equations_parabolic, dg, i, j, element) end @@ -416,13 +416,13 @@ function calc_divergence_boundary_flux_by_direction!(surface_flux_values::Abstra return nothing end -function calc_gradient!(u_grad, u, t, +function calc_gradient!(gradients, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" begin - reset_du!(u_grad[1], dg, cache) - reset_du!(u_grad[2], dg, cache) + reset_du!(gradients[1], dg, cache) + reset_du!(gradients[2], dg, cache) end # Calculate volume integral @@ -435,11 +435,11 @@ function calc_gradient!(u_grad, u, t, u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) for ii in eachnode(dg) - multiply_add_to_node_vars!(u_grad[1], derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) + multiply_add_to_node_vars!(gradients[1], derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) end for jj in eachnode(dg) - multiply_add_to_node_vars!(u_grad[2], derivative_dhat[jj, j], u_node, equations_parabolic, dg, i, jj, element) + multiply_add_to_node_vars!(gradients[2], derivative_dhat[jj, j], u_node, equations_parabolic, dg, i, jj, element) end end end @@ -560,7 +560,7 @@ function calc_gradient!(u_grad, u, t, @threaded for element in eachelement(dg, cache) for l in eachnode(dg) for v in eachvariable(equations_parabolic) - let du = u_grad[1] + let du = gradients[1] # surface at -x du[v, 1, l, element] = ( du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) @@ -570,7 +570,7 @@ function calc_gradient!(u_grad, u, t, du[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) end - let du = u_grad[2] + let du = gradients[2] # surface at -y du[v, l, 1, element] = ( du[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) @@ -586,8 +586,8 @@ function calc_gradient!(u_grad, u, t, # Apply Jacobian from mapping to reference element @trixi_timeit timer() "Jacobian" begin - apply_jacobian!(u_grad[1], mesh, equations_parabolic, dg, cache_parabolic) - apply_jacobian!(u_grad[2], mesh, equations_parabolic, dg, cache_parabolic) + apply_jacobian!(gradients[1], mesh, equations_parabolic, dg, cache_parabolic) + apply_jacobian!(gradients[2], mesh, equations_parabolic, dg, cache_parabolic) end return nothing @@ -609,7 +609,7 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::Abstrac n_nodes = nnodes(elements) n_elements = nelements(elements) u_transformed = Array{uEltype}(undef, n_vars, n_nodes, n_nodes, n_elements) - u_grad = ntuple(_ -> similar(u_transformed), ndims(mesh)) + gradients = ntuple(_ -> similar(u_transformed), ndims(mesh)) flux_viscous = ntuple(_ -> similar(u_transformed), ndims(mesh)) interfaces = init_interfaces(leaf_cell_ids, mesh, elements) @@ -619,7 +619,7 @@ function create_cache_parabolic(mesh::TreeMesh{2}, equations_hyperbolic::Abstrac # mortars = init_mortars(leaf_cell_ids, mesh, elements, dg.mortar) # cache = (; elements, interfaces, boundaries, mortars) - cache = (; elements, interfaces, boundaries, u_grad, flux_viscous, u_transformed) + cache = (; elements, interfaces, boundaries, gradients, flux_viscous, u_transformed) # Add specialized parts of the cache required to compute the mortars etc. # cache = (;cache..., create_cache(mesh, equations_parabolic, dg.mortar, uEltype)...) From 76a8563c417e98fb015f2b2d46fd5096c59b6fb8 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 16:59:22 -0500 Subject: [PATCH 119/143] fix test --- test/test_parabolic_2d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 42d6b1d3752..51a1fe11c9a 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -45,7 +45,7 @@ isdir(outdir) && rm(outdir, recursive=true) @test boundary_condition_do_nothing(u0, nothing) == u0 @unpack cache, cache_parabolic, equations_parabolic = semi - @unpack u_grad = cache_parabolic + u_grad = cache_parabolic.gradients for dim in eachindex(u_grad) fill!(u_grad[dim], zero(eltype(u_grad[dim]))) end From 0fc9828f184b0f9b147af123ad7c5c676f2e1268 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 17:28:10 -0500 Subject: [PATCH 120/143] renaming --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index cc8a34e4862..e0448d37868 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -183,7 +183,7 @@ function calc_divergence!(du, u, t, flux_viscous, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - calc_divergence_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + calc_boundary_flux_divergence!(cache_parabolic, t, boundary_conditions_parabolic, mesh, equations_parabolic, dg.surface_integral, dg) end @@ -272,19 +272,19 @@ function get_unsigned_normal_vector_2d(direction) end end -function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, +function calc_boundary_flux_gradients!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) return nothing end -function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, +function calc_boundary_flux_divergence!(cache, t, boundary_conditions_parabolic::BoundaryConditionPeriodic, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) return nothing end -function calc_gradient_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, +function calc_boundary_flux_gradients!(cache, t, boundary_conditions_parabolic::NamedTuple, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) @unpack surface_flux_values = cache.elements @@ -348,7 +348,7 @@ function calc_gradient_boundary_flux_by_direction!(surface_flux_values::Abstract return nothing end -function calc_divergence_boundary_flux!(cache, t, boundary_conditions_parabolic::NamedTuple, +function calc_boundary_flux_divergence!(cache, t, boundary_conditions_parabolic::NamedTuple, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG) @unpack surface_flux_values = cache.elements @@ -540,7 +540,7 @@ function calc_gradient!(gradients, u, t, # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin - calc_gradient_boundary_flux!(cache_parabolic, t, boundary_conditions_parabolic, + calc_boundary_flux_gradients!(cache_parabolic, t, boundary_conditions_parabolic, mesh, equations_parabolic, dg.surface_integral, dg) end From 3b46afdc465a12fc2735b5a5ad74c3c47bb79662 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 17:34:12 -0500 Subject: [PATCH 121/143] update comment --- src/equations/compressible_navier_stokes_2d.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 32499d03f02..bb7cda911b9 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -144,25 +144,25 @@ gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D) = cons2p # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, grad_u, equations::CompressibleNavierStokesDiffusion2D) - # Here grad_u is assumed to contain the gradients of the primitive variables (v1, v2, T) +function flux(u, gradients, equations::CompressibleNavierStokesDiffusion2D) + # Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function rho, v1, v2, _ = u - # grad_u contains derivatives of each hyperbolic variable - _, dv1dx, dv2dx, dTdx = grad_u[1] - _, dv1dy, dv2dy, dTdy = grad_u[2] + # gradients contains derivatives of each hyperbolic variable + _, dv1dx, dv2dx, dTdx = gradients[1] + _, dv1dy, dv2dy, dTdy = gradients[2] # Components of viscous stress tensor # (4/3 * (v1)_x - 2/3 * (v2)_y) - tau_11 = ( 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy ) + tau_11 = 4.0 / 3.0 * dv1dx - 2.0 / 3.0 * dv2dy # ((v1)_y + (v2)_x) # stress tensor is symmetric - tau_12 = ( dv1dy + dv2dx ) # = tau_21 + tau_12 = dv1dy + dv2dx # = tau_21 # (4/3 * (v2)_y - 2/3 * (v1)_x) - tau_22 = ( 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx ) + tau_22 = 4.0 / 3.0 * dv2dy - 2.0 / 3.0 * dv1dx # Fick's law q = -kappa * grad(T); constant is kappa = gamma μ R / ((gamma-1) Pr) # Important note! Due to nondimensional scaling R = 1 / gamma, so the From 8e949654791df5619cfe8ee3466d2f14cedabec1 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 18:05:44 -0500 Subject: [PATCH 122/143] converting to signature `flux(u, gradients, orientation, equations)` --- .../compressible_navier_stokes_2d.jl | 34 +++++++++++-------- src/equations/laplace_diffusion_2d.jl | 8 +++-- src/solvers/dgmulti/dg_parabolic.jl | 6 ++-- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 7 ++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index bb7cda911b9..3aa1bc4c527 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -144,7 +144,7 @@ gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D) = cons2p # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, gradients, equations::CompressibleNavierStokesDiffusion2D) +function flux(u, gradients, orientation::Int, equations::CompressibleNavierStokesDiffusion2D) # Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function @@ -173,20 +173,24 @@ function flux(u, gradients, equations::CompressibleNavierStokesDiffusion2D) # kinematic viscosity is simply 1/Re for this nondimensionalization mu = 1.0 / equations.Re - # viscous flux components in the x-direction - f1 = zero(rho) - f2 = tau_11 * mu - f3 = tau_12 * mu - f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * mu - - # viscous flux components in the y-direction - # Note, symmetry is exploited for tau_12 = tau_21 - g1 = zero(rho) - g2 = f3 # tau_21 * mu - g3 = tau_22 * mu - g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * mu - - return (SVector(f1, f2, f3, f4) , SVector(g1, g2, g3, g4)) + if orientation == 1 + # viscous flux components in the x-direction + f1 = zero(rho) + f2 = tau_11 * mu + f3 = tau_12 * mu + f4 = ( v1 * tau_11 + v2 * tau_12 + q1 ) * mu + + return SVector(f1, f2, f3, f4) + else # if orientation == 2 + # viscous flux components in the y-direction + # Note, symmetry is exploited for tau_12 = tau_21 + g1 = zero(rho) + g2 = tau_12 * mu # tau_21 * mu + g3 = tau_22 * mu + g4 = ( v1 * tau_12 + v2 * tau_22 + q2 ) * mu + + return SVector(g1, g2, g3, g4) + end end diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index fcfc2a24a95..d3a968680fd 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -16,9 +16,13 @@ varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -function flux(u, grad_u, equations_parabolic::LaplaceDiffusion2D) +function flux(u, grad_u, orientation::Int, equations_parabolic::LaplaceDiffusion2D) dudx, dudy = grad_u - return SVector(equations_parabolic.diffusivity * dudx, equations_parabolic.diffusivity * dudy) + if orientation == 1 + return SVector(equations_parabolic.diffusivity * dudx) + else # if orientation == 2 + return SVector(equations_parabolic.diffusivity * dudy) + end end # TODO: parabolic; should this remain in the equations file, be moved to solvers, or live in the elixir? diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 953c371fcbc..421b9bebcaf 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -197,8 +197,10 @@ function calc_viscous_fluxes!(flux_viscous, u, gradients, mesh::DGMultiMesh, for i in eachindex(local_u_values) u_i = local_u_values[i] gradients_i = getindex.(local_flux_viscous, i) - flux_viscous_i = flux(u_i, gradients_i, equations) - setindex!.(local_flux_viscous, flux_viscous_i, i) + for dim in eachdim(mesh) + flux_viscous_i = flux(u_i, gradients_i, dim, equations) + setindex!(local_flux_viscous[dim], flux_viscous_i, i) + end end # project back to the DG approximation space diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index e0448d37868..5747cb2e5a2 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -253,9 +253,10 @@ function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, gradients_2_node = get_node_vars(gradients[2], equations_parabolic, dg, i, j, element) # Calculate viscous flux and store each component for later use - flux_viscous_node = flux(u_node, (gradients_1_node, gradients_2_node), equations_parabolic) - set_node_vars!(flux_viscous[1], flux_viscous_node[1], equations_parabolic, dg, i, j, element) - set_node_vars!(flux_viscous[2], flux_viscous_node[2], equations_parabolic, dg, i, j, element) + flux_viscous_node_x = flux(u_node, (gradients_1_node, gradients_2_node), 1, equations_parabolic) + flux_viscous_node_y = flux(u_node, (gradients_1_node, gradients_2_node), 2, equations_parabolic) + set_node_vars!(flux_viscous[1], flux_viscous_node_x, equations_parabolic, dg, i, j, element) + set_node_vars!(flux_viscous[2], flux_viscous_node_y, equations_parabolic, dg, i, j, element) end end end From f5f48fc04e822340e8613f62c2558c280beaafd3 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 18:43:15 -0500 Subject: [PATCH 123/143] using prolong2interfaces/boundaries --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 58 ++--------------------- 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 5747cb2e5a2..8cde57ff8a2 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -448,27 +448,8 @@ function calc_gradient!(gradients, u, t, # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" begin - @unpack interfaces = cache_parabolic - @unpack orientations = interfaces - - @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] - - if orientations[interface] == 1 - # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, j, interface] = u[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = u[v, 1, j, right_element] - end - else # if orientations[interface] == 2 - # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, i, interface] = u[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = u[v, i, 1, right_element] - end - end - end + # TODO: parabolic, should we pass in something else for `surface_integral` here? + prolong2interfaces!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) end # Calculate interface fluxes @@ -504,39 +485,8 @@ function calc_gradient!(gradients, u, t, # Prolong solution to boundaries @trixi_timeit timer() "prolong2boundaries" begin - @unpack boundaries = cache_parabolic - @unpack orientations, neighbor_sides = boundaries - - @threaded for boundary in eachboundary(dg, cache_parabolic) - element = boundaries.neighbor_ids[boundary] - - if orientations[boundary] == 1 - # boundary in x-direction - if neighbor_sides[boundary] == 1 - # element in -x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = u[v, nnodes(dg), l, element] - end - else # Element in +x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = u[v, 1, l, element] - end - end - else # if orientations[boundary] == 2 - # boundary in y-direction - if neighbor_sides[boundary] == 1 - # element in -y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = u[v, l, nnodes(dg), element] - end - else - # element in +y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = u[v, l, 1, element] - end - end - end - end + # TODO: parabolic, should we pass in something else for `surface_integral` here? + prolong2boundaries!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) end # Calculate boundary fluxes From da319b9f869c2e50df9b4b04b63528b9bced2eed Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 18:53:43 -0500 Subject: [PATCH 124/143] unpacking `gradients` and `flux_viscous` --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 80 ++++++++++++----------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 8cde57ff8a2..e1290c5bd4f 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -73,10 +73,12 @@ function calc_divergence!(du, u, t, flux_viscous, @unpack derivative_dhat = dg.basis @threaded for element in eachelement(dg, cache) + flux_viscous_x, flux_viscous_y = flux_viscous + # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) - flux_1_node = get_node_vars(flux_viscous[1], equations_parabolic, dg, i, j, element) - flux_2_node = get_node_vars(flux_viscous[2], equations_parabolic, dg, i, j, element) + flux_1_node = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, element) + flux_2_node = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, element) for ii in eachnode(dg) multiply_add_to_node_vars!(du, derivative_dhat[ii, i], flux_1_node, equations_parabolic, dg, ii, j, element) @@ -94,6 +96,8 @@ function calc_divergence!(du, u, t, flux_viscous, @unpack interfaces = cache_parabolic @unpack orientations = interfaces + flux_viscous_x, flux_viscous_y = flux_viscous + @threaded for interface in eachinterface(dg, cache) left_element = interfaces.neighbor_ids[1, interface] right_element = interfaces.neighbor_ids[2, interface] @@ -101,14 +105,14 @@ function calc_divergence!(du, u, t, flux_viscous, if orientations[interface] == 1 # interface in x-direction for j in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, j, interface] = flux_viscous[1][v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = flux_viscous[1][v, 1, j, right_element] + interfaces.u[1, v, j, interface] = flux_viscous_x[v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = flux_viscous_x[v, 1, j, right_element] end else # if orientations[interface] == 2 # interface in y-direction for i in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, i, interface] = flux_viscous[2][v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = flux_viscous[2][v, i, 1, right_element] + interfaces.u[1, v, i, interface] = flux_viscous_y[v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = flux_viscous_y[v, i, 1, right_element] end end end @@ -157,11 +161,11 @@ function calc_divergence!(du, u, t, flux_viscous, if neighbor_sides[boundary] == 1 # element in -x direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = flux_viscous[1][v, nnodes(dg), l, element] + boundaries.u[1, v, l, boundary] = flux_viscous_x[v, nnodes(dg), l, element] end else # Element in +x direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = flux_viscous[1][v, 1, l, element] + boundaries.u[2, v, l, boundary] = flux_viscous_x[v, 1, l, element] end end else # if orientations[boundary] == 2 @@ -169,12 +173,12 @@ function calc_divergence!(du, u, t, flux_viscous, if neighbor_sides[boundary] == 1 # element in -y direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = flux_viscous[2][v, l, nnodes(dg), element] + boundaries.u[1, v, l, boundary] = flux_viscous_y[v, l, nnodes(dg), element] end else # element in +y direction of boundary for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = flux_viscous[2][v, l, 1, element] + boundaries.u[2, v, l, boundary] = flux_viscous_y[v, l, 1, element] end end end @@ -245,18 +249,21 @@ end function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) + + gradients_x, gradients_y = gradients + flux_viscous_x, flux_viscous_y = flux_viscous # output arrays @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - gradients_1_node = get_node_vars(gradients[1], equations_parabolic, dg, i, j, element) - gradients_2_node = get_node_vars(gradients[2], equations_parabolic, dg, i, j, element) + gradients_1_node = get_node_vars(gradients_x, equations_parabolic, dg, i, j, element) + gradients_2_node = get_node_vars(gradients_y, equations_parabolic, dg, i, j, element) # Calculate viscous flux and store each component for later use flux_viscous_node_x = flux(u_node, (gradients_1_node, gradients_2_node), 1, equations_parabolic) flux_viscous_node_y = flux(u_node, (gradients_1_node, gradients_2_node), 2, equations_parabolic) - set_node_vars!(flux_viscous[1], flux_viscous_node_x, equations_parabolic, dg, i, j, element) - set_node_vars!(flux_viscous[2], flux_viscous_node_y, equations_parabolic, dg, i, j, element) + set_node_vars!(flux_viscous_x, flux_viscous_node_x, equations_parabolic, dg, i, j, element) + set_node_vars!(flux_viscous_y, flux_viscous_node_y, equations_parabolic, dg, i, j, element) end end end @@ -420,10 +427,13 @@ end function calc_gradient!(gradients, u, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) + + gradients_x, gradients_y = gradients + # Reset du @trixi_timeit timer() "reset ∂u/∂t" begin - reset_du!(gradients[1], dg, cache) - reset_du!(gradients[2], dg, cache) + reset_du!(gradients_x, dg, cache) + reset_du!(gradients_y, dg, cache) end # Calculate volume integral @@ -436,11 +446,11 @@ function calc_gradient!(gradients, u, t, u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) for ii in eachnode(dg) - multiply_add_to_node_vars!(gradients[1], derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) + multiply_add_to_node_vars!(gradients_x, derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) end for jj in eachnode(dg) - multiply_add_to_node_vars!(gradients[2], derivative_dhat[jj, j], u_node, equations_parabolic, dg, i, jj, element) + multiply_add_to_node_vars!(gradients_y, derivative_dhat[jj, j], u_node, equations_parabolic, dg, i, jj, element) end end end @@ -511,25 +521,21 @@ function calc_gradient!(gradients, u, t, @threaded for element in eachelement(dg, cache) for l in eachnode(dg) for v in eachvariable(equations_parabolic) - let du = gradients[1] - # surface at -x - du[v, 1, l, element] = ( - du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) - - # surface at +x - du[v, nnodes(dg), l, element] = ( - du[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) - end + # surface at -x + gradients_x[v, 1, l, element] = ( + gradients_x[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) - let du = gradients[2] - # surface at -y - du[v, l, 1, element] = ( - du[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) + # surface at +x + gradients_x[v, nnodes(dg), l, element] = ( + gradients_x[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) - # surface at +y - du[v, l, nnodes(dg), element] = ( - du[v, l, nnodes(dg), element] + surface_flux_values[v, l, 4, element] * factor_2) - end + # surface at -y + gradients_y[v, l, 1, element] = ( + gradients_y[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) + + # surface at +y + gradients_y[v, l, nnodes(dg), element] = ( + gradients_y[v, l, nnodes(dg), element] + surface_flux_values[v, l, 4, element] * factor_2) end end end @@ -537,8 +543,8 @@ function calc_gradient!(gradients, u, t, # Apply Jacobian from mapping to reference element @trixi_timeit timer() "Jacobian" begin - apply_jacobian!(gradients[1], mesh, equations_parabolic, dg, cache_parabolic) - apply_jacobian!(gradients[2], mesh, equations_parabolic, dg, cache_parabolic) + apply_jacobian!(gradients_x, mesh, equations_parabolic, dg, cache_parabolic) + apply_jacobian!(gradients_y, mesh, equations_parabolic, dg, cache_parabolic) end return nothing From 4b9b04ff6f1bfad06065937f4c3b0c00b03d29fb Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 19:02:30 -0500 Subject: [PATCH 125/143] using calc_surface_integral! --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 32 ++--------------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index e1290c5bd4f..06a6ed51746 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -205,36 +205,8 @@ function calc_divergence!(du, u, t, flux_viscous, # Calculate surface integrals @trixi_timeit timer() "surface integral" begin - @unpack boundary_interpolation = dg.basis - @unpack surface_flux_values = cache_parabolic.elements - - # Note that all fluxes have been computed with outward-pointing normal vectors. - # Access the factors only once before beginning the loop to increase performance. - # We also use explicit assignments instead of `+=` to let `@muladd` turn these - # into FMAs (see comment at the top of the file). - factor_1 = boundary_interpolation[1, 1] - factor_2 = boundary_interpolation[nnodes(dg), 2] - @threaded for element in eachelement(dg, cache) - for l in eachnode(dg) - for v in eachvariable(equations_parabolic) - # surface at -x - du[v, 1, l, element] = ( - du[v, 1, l, element] - surface_flux_values[v, l, 1, element] * factor_1) - - # surface at +x - du[v, nnodes(dg), l, element] = ( - du[v, nnodes(dg), l, element] + surface_flux_values[v, l, 2, element] * factor_2) - - # surface at -y - du[v, l, 1, element] = ( - du[v, l, 1, element] - surface_flux_values[v, l, 3, element] * factor_1) - - # surface at +y - du[v, l, nnodes(dg), element] = ( - du[v, l, nnodes(dg), element] + surface_flux_values[v, l, 4, element] * factor_2) - end - end - end + # TODO: parabolic, should we pass in something else for `surface_integral` here? + calc_surface_integral!(du, u, mesh, equations_parabolic, dg.surface_integral, dg, cache_parabolic) end # Apply Jacobian from mapping to reference element From 7b74f19884a553c48ac2f84c97efe7a927d2a894 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 8 Aug 2022 19:15:06 -0500 Subject: [PATCH 126/143] adding @muladd --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 06a6ed51746..c775c04b081 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -1,3 +1,9 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin + # This file collects all methods that have been updated to work with parabolic systems of equations # # assumptions: parabolic terms are of the form div(f(u, grad(u))) and @@ -576,3 +582,5 @@ function apply_jacobian!(du, mesh::TreeMesh{2}, return nothing end + +end # @muladd \ No newline at end of file From 9b051853054818230eb3be8190a71975dbe9a72a Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Tue, 9 Aug 2022 08:54:12 +0200 Subject: [PATCH 127/143] Apply suggestions from code review --- src/equations/compressible_navier_stokes_2d.jl | 10 ++++++---- src/equations/laplace_diffusion_2d.jl | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index 3aa1bc4c527..fb6734290e7 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -144,7 +144,7 @@ gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D) = cons2p # # Note, could be generalized to use Sutherland's law to get the molecular and thermal # diffusivity -function flux(u, gradients, orientation::Int, equations::CompressibleNavierStokesDiffusion2D) +function flux(u, gradients, orientation::Integer, equations::CompressibleNavierStokesDiffusion2D) # Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T) # either computed directly or reverse engineered from the gradient of the entropy vairables # by way of the `convert_gradient_variables` function @@ -222,7 +222,6 @@ end end # TODO: can we generalize this to MHD? -# !!! warning "Experimental feature" """ struct BoundaryConditionNavierStokesWall @@ -230,6 +229,9 @@ Creates a wall-type boundary conditions for the compressible Navier-Stokes equat The fields `boundary_condition_velocity` and `boundary_condition_heat_flux` are intended to be boundary condition types such as the `NoSlip` velocity boundary condition and the `Adiabatic` or `Isothermal` heat boundary condition. + +!!! warning "Experimental feature" + This is an experimental feature and may change in future releases. """ struct BoundaryConditionNavierStokesWall{V, H} boundary_condition_velocity::V @@ -251,7 +253,7 @@ end """ struct Isothermal -Used to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. +Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). The field `boundary_value_function` should be a function with signature `boundary_value_function(x, t, equations)` and return a scalar value for the temperature at point `x` and time `t`. @@ -263,7 +265,7 @@ end """ struct Adiabatic -Used to create a no-slip boundary condition with `BoundaryConditionNavierStokesWall`. +Used to create a no-slip boundary condition with [`BoundaryConditionNavierStokesWall`](@ref). The field `boundary_value_normal_flux_function` should be a function with signature `boundary_value_normal_flux_function(x, t, equations)` and return a scalar value for the normal heat flux at point `x` and time `t`. diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index d3a968680fd..d65945b0108 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -16,7 +16,7 @@ varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -function flux(u, grad_u, orientation::Int, equations_parabolic::LaplaceDiffusion2D) +function flux(u, grad_u, orientation::Integer, equations_parabolic::LaplaceDiffusion2D) dudx, dudy = grad_u if orientation == 1 return SVector(equations_parabolic.diffusivity * dudx) From 1ff6b875a1fd890f888824effcbb4257133c60b8 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 9 Aug 2022 02:23:52 -0500 Subject: [PATCH 128/143] update comments --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index c775c04b081..09e15e8acb5 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -211,7 +211,7 @@ function calc_divergence!(du, u, t, flux_viscous, # Calculate surface integrals @trixi_timeit timer() "surface integral" begin - # TODO: parabolic, should we pass in something else for `surface_integral` here? + # we pass in the hyperbolic `dg.surface_integral` as a dummy argument calc_surface_integral!(du, u, mesh, equations_parabolic, dg.surface_integral, dg, cache_parabolic) end @@ -436,7 +436,7 @@ function calc_gradient!(gradients, u, t, # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" begin - # TODO: parabolic, should we pass in something else for `surface_integral` here? + # we pass in the hyperbolic `dg.surface_integral` as a dummy argument prolong2interfaces!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) end @@ -473,7 +473,7 @@ function calc_gradient!(gradients, u, t, # Prolong solution to boundaries @trixi_timeit timer() "prolong2boundaries" begin - # TODO: parabolic, should we pass in something else for `surface_integral` here? + # we pass in the hyperbolic `dg.surface_integral` as a dummy argument prolong2boundaries!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) end From e8bccba1fe12cecff255f8a2572c7454e792953e Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 10:09:18 +0200 Subject: [PATCH 129/143] Rename grad_u -> gradients --- src/equations/laplace_diffusion_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/laplace_diffusion_2d.jl b/src/equations/laplace_diffusion_2d.jl index d65945b0108..2f1afe25a6d 100644 --- a/src/equations/laplace_diffusion_2d.jl +++ b/src/equations/laplace_diffusion_2d.jl @@ -16,8 +16,8 @@ varnames(variable_mapping, equations_parabolic::LaplaceDiffusion2D) = varnames(variable_mapping, equations_parabolic.equations_hyperbolic) # no orientation specified since the flux is vector-valued -function flux(u, grad_u, orientation::Integer, equations_parabolic::LaplaceDiffusion2D) - dudx, dudy = grad_u +function flux(u, gradients, orientation::Integer, equations_parabolic::LaplaceDiffusion2D) + dudx, dudy = gradients if orientation == 1 return SVector(equations_parabolic.diffusivity * dudx) else # if orientation == 2 From f05bc7db2a2868ad88376458b24954ce6e6af198 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Tue, 9 Aug 2022 03:24:23 -0500 Subject: [PATCH 130/143] Update src/equations/compressible_navier_stokes_2d.jl Co-authored-by: Michael Schlottke-Lakemper --- src/equations/compressible_navier_stokes_2d.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/equations/compressible_navier_stokes_2d.jl b/src/equations/compressible_navier_stokes_2d.jl index fb6734290e7..683ff1f8514 100644 --- a/src/equations/compressible_navier_stokes_2d.jl +++ b/src/equations/compressible_navier_stokes_2d.jl @@ -134,7 +134,6 @@ varnames(variable_mapping, equations_parabolic::CompressibleNavierStokesDiffusio # conservative variables. gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D) = cons2prim -# no orientation specified since the flux is vector-valued # Explicit formulas for the diffussive Navier-Stokes fluxes are available, e.g. in Section 2 # of the paper by Svärd, Carpenter and Nordström # "A stable high-order finite difference scheme for the compressible Navier–Stokes From 56921899e6f3f51698ec58f8463f0c95baa184ad Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 10:29:10 +0200 Subject: [PATCH 131/143] Rename remaining grad_u/u_grad -> gradients --- src/solvers/dgmulti/dg_parabolic.jl | 6 +++--- test/test_parabolic_2d.jl | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index 421b9bebcaf..ec8d03e5d5d 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -17,7 +17,7 @@ function create_cache_parabolic(mesh::DGMultiMesh, u_face_values = allocate_nested_array(uEltype, nvars, size(md.xf), dg) scalar_flux_face_values = similar(u_face_values) - grad_u_face_values = ntuple(_ -> similar(u_face_values), ndims(mesh)) + gradients_face_values = ntuple(_ -> similar(u_face_values), ndims(mesh)) local_u_values_threaded = [similar(u_transformed, dg.basis.Nq) for _ in 1:Threads.nthreads()] local_flux_viscous_threaded = [ntuple(_ -> similar(u_transformed, dg.basis.Nq), ndims(mesh)) for _ in 1:Threads.nthreads()] @@ -34,7 +34,7 @@ function create_cache_parabolic(mesh::DGMultiMesh, return (; u_transformed, gradients, flux_viscous, weak_differentiation_matrices, inv_h, - u_face_values, grad_u_face_values, scalar_flux_face_values, + u_face_values, gradients_face_values, scalar_flux_face_values, local_u_values_threaded, local_flux_viscous_threaded, local_flux_face_values_threaded) end @@ -251,7 +251,7 @@ function calc_divergence!(du, u::StructArray, t, flux_viscous, mesh::DGMultiMesh end # interpolates from solution coefficients to face quadrature points - flux_viscous_face_values = cache_parabolic.grad_u_face_values # reuse storage + flux_viscous_face_values = cache_parabolic.gradients_face_values # reuse storage for dim in eachdim(mesh) prolong2interfaces!(flux_viscous_face_values[dim], flux_viscous[dim], mesh, equations, dg.surface_integral, dg, cache) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 51a1fe11c9a..11e31ff7764 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -45,24 +45,24 @@ isdir(outdir) && rm(outdir, recursive=true) @test boundary_condition_do_nothing(u0, nothing) == u0 @unpack cache, cache_parabolic, equations_parabolic = semi - u_grad = cache_parabolic.gradients - for dim in eachindex(u_grad) - fill!(u_grad[dim], zero(eltype(u_grad[dim]))) + @unpack gradients = cache_parabolic + for dim in eachindex(gradients) + fill!(gradients[dim], zero(eltype(gradients[dim]))) end t = 0.0 # pass in `boundary_condition_periodic` to skip boundary flux/integral evaluation - Trixi.calc_gradient!(u_grad, ode.u0, t, mesh, equations_parabolic, + Trixi.calc_gradient!(gradients, ode.u0, t, mesh, equations_parabolic, boundary_condition_periodic, dg, cache, cache_parabolic) @unpack x, y = mesh.md - @test getindex.(u_grad[1], 1) ≈ 2 * x .* y - @test getindex.(u_grad[2], 1) ≈ x.^2 + @test getindex.(gradients[1], 1) ≈ 2 * x .* y + @test getindex.(gradients[2], 1) ≈ x.^2 - u_flux = similar.(u_grad) - Trixi.calc_viscous_fluxes!(u_flux, ode.u0, u_grad, mesh, equations_parabolic, + u_flux = similar.(gradients) + Trixi.calc_viscous_fluxes!(u_flux, ode.u0, gradients, mesh, equations_parabolic, dg, cache, cache_parabolic) - @test u_flux[1] ≈ u_grad[1] - @test u_flux[2] ≈ u_grad[2] + @test u_flux[1] ≈ gradients[1] + @test u_flux[2] ≈ gradients[2] du = similar(ode.u0) Trixi.calc_divergence!(du, ode.u0, t, u_flux, mesh, equations_parabolic, boundary_condition_periodic, From 5437f7be7e670747b37d43a5c2afb099ef1b586e Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 11:32:11 +0200 Subject: [PATCH 132/143] Refactor into prolong2interfaces! --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 78 ++++++++++++----------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 09e15e8acb5..42a04e8ef4c 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -70,17 +70,14 @@ function calc_divergence!(du, u, t, flux_viscous, parabolic_scheme, # not a `DG` type cache, cache_parabolic) # Reset du - @trixi_timeit timer() "reset ∂u/∂t" begin - reset_du!(du, dg, cache) - end + @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) # Calculate volume integral @trixi_timeit timer() "volume integral" begin @unpack derivative_dhat = dg.basis - @threaded for element in eachelement(dg, cache) - - flux_viscous_x, flux_viscous_y = flux_viscous + flux_viscous_x, flux_viscous_y = flux_viscous + @threaded for element in eachelement(dg, cache) # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) flux_1_node = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, element) @@ -98,31 +95,8 @@ function calc_divergence!(du, u, t, flux_viscous, end # Prolong solution to interfaces - @trixi_timeit timer() "prolong2interfaces" begin - @unpack interfaces = cache_parabolic - @unpack orientations = interfaces - - flux_viscous_x, flux_viscous_y = flux_viscous - - @threaded for interface in eachinterface(dg, cache) - left_element = interfaces.neighbor_ids[1, interface] - right_element = interfaces.neighbor_ids[2, interface] - - if orientations[interface] == 1 - # interface in x-direction - for j in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, j, interface] = flux_viscous_x[v, nnodes(dg), j, left_element] - interfaces.u[2, v, j, interface] = flux_viscous_x[v, 1, j, right_element] - end - else # if orientations[interface] == 2 - # interface in y-direction - for i in eachnode(dg), v in eachvariable(equations_parabolic) - interfaces.u[1, v, i, interface] = flux_viscous_y[v, i, nnodes(dg), left_element] - interfaces.u[2, v, i, interface] = flux_viscous_y[v, i, 1, right_element] - end - end - end - end + @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( + cache_parabolic, flux_viscous, mesh, equations_parabolic, dg.surface_integral, dg, cache) # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @@ -158,6 +132,7 @@ function calc_divergence!(du, u, t, flux_viscous, @trixi_timeit timer() "prolong2boundaries" begin @unpack boundaries = cache_parabolic @unpack orientations, neighbor_sides = boundaries + flux_viscous_x, flux_viscous_y = flux_viscous @threaded for boundary in eachboundary(dg, cache_parabolic) element = boundaries.neighbor_ids[boundary] @@ -224,6 +199,39 @@ function calc_divergence!(du, u, t, flux_viscous, end +# This is the version used to calculate the divergence of the viscous fluxes +# we pass in the hyperbolic `dg.surface_integral` as a dummy argument +function prolong2interfaces!(cache_parabolic, flux_viscous, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache) + @unpack interfaces = cache_parabolic + @unpack orientations = interfaces + + flux_viscous_x, flux_viscous_y = flux_viscous + + @threaded for interface in eachinterface(dg, cache) + left_element = interfaces.neighbor_ids[1, interface] + right_element = interfaces.neighbor_ids[2, interface] + + if orientations[interface] == 1 + # interface in x-direction + for j in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, j, interface] = flux_viscous_x[v, nnodes(dg), j, left_element] + interfaces.u[2, v, j, interface] = flux_viscous_x[v, 1, j, right_element] + end + else # if orientations[interface] == 2 + # interface in y-direction + for i in eachnode(dg), v in eachvariable(equations_parabolic) + interfaces.u[1, v, i, interface] = flux_viscous_y[v, i, nnodes(dg), left_element] + interfaces.u[2, v, i, interface] = flux_viscous_y[v, i, 1, right_element] + end + end + end + + return nothing +end + + function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) @@ -435,10 +443,8 @@ function calc_gradient!(gradients, u, t, end # Prolong solution to interfaces - @trixi_timeit timer() "prolong2interfaces" begin - # we pass in the hyperbolic `dg.surface_integral` as a dummy argument - prolong2interfaces!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) - end + @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( + cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @@ -583,4 +589,4 @@ function apply_jacobian!(du, mesh::TreeMesh{2}, return nothing end -end # @muladd \ No newline at end of file +end # @muladd From be8a5e0ceaad6406e13958ba4f4a4c5606a6b770 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 11:49:31 +0200 Subject: [PATCH 133/143] Refactor calc_volume_integral! --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 56 ++++++++++++++--------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 42a04e8ef4c..dca824377ec 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -73,26 +73,10 @@ function calc_divergence!(du, u, t, flux_viscous, @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) # Calculate volume integral - @trixi_timeit timer() "volume integral" begin - @unpack derivative_dhat = dg.basis - flux_viscous_x, flux_viscous_y = flux_viscous - - @threaded for element in eachelement(dg, cache) - # Calculate volume terms in one element - for j in eachnode(dg), i in eachnode(dg) - flux_1_node = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, element) - flux_2_node = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, element) - - for ii in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[ii, i], flux_1_node, equations_parabolic, dg, ii, j, element) - end - - for jj in eachnode(dg) - multiply_add_to_node_vars!(du, derivative_dhat[jj, j], flux_2_node, equations_parabolic, dg, i, jj, element) - end - end - end - end + @trixi_timeit timer() "volume integral" calc_volume_integral!( + du, flux_viscous, mesh, + have_nonconservative_terms(equations_parabolic), equations_parabolic, + dg.volume_integral, dg, cache) # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( @@ -199,7 +183,37 @@ function calc_divergence!(du, u, t, flux_viscous, end -# This is the version used to calculate the divergence of the viscous fluxes +# This is the version used when calculating the divergence of the viscous fluxes +function calc_volume_integral!(du, flux_viscous, + mesh::TreeMesh{2}, + nonconservative_terms, + equations_parabolic::AbstractEquationsParabolic, + volume_integral::VolumeIntegralWeakForm, + dg::DGSEM, cache) + @unpack derivative_dhat = dg.basis + flux_viscous_x, flux_viscous_y = flux_viscous + + @threaded for element in eachelement(dg, cache) + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + flux_1_node = get_node_vars(flux_viscous_x, equations_parabolic, dg, i, j, element) + flux_2_node = get_node_vars(flux_viscous_y, equations_parabolic, dg, i, j, element) + + for ii in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[ii, i], flux_1_node, equations_parabolic, dg, ii, j, element) + end + + for jj in eachnode(dg) + multiply_add_to_node_vars!(du, derivative_dhat[jj, j], flux_2_node, equations_parabolic, dg, i, jj, element) + end + end + end + + return nothing +end + + +# This is the version used when calculating the divergence of the viscous fluxes # we pass in the hyperbolic `dg.surface_integral` as a dummy argument function prolong2interfaces!(cache_parabolic, flux_viscous, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, From cbadcb82bd31908319d4bb367abdf8c2ebb029ba Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 11:49:49 +0200 Subject: [PATCH 134/143] Refactor calc_interface_flux --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 67 +++++++++++++---------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index dca824377ec..89a10b6d849 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -83,34 +83,10 @@ function calc_divergence!(du, u, t, flux_viscous, cache_parabolic, flux_viscous, mesh, equations_parabolic, dg.surface_integral, dg, cache) # Calculate interface fluxes - @trixi_timeit timer() "interface flux" begin - @unpack surface_flux_values = cache_parabolic.elements - @unpack neighbor_ids, orientations = cache_parabolic.interfaces - - @threaded for interface in eachinterface(dg, cache_parabolic) - # Get neighboring elements - left_id = neighbor_ids[1, interface] - right_id = neighbor_ids[2, interface] - - # Determine interface direction with respect to elements: - # orientation = 1: left -> 2, right -> 1 - # orientation = 2: left -> 4, right -> 3 - left_direction = 2 * orientations[interface] - right_direction = 2 * orientations[interface] - 1 - - for i in eachnode(dg) - # Call pointwise Riemann solver - u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) - flux = 0.5 * (u_ll + u_rr) - - # Copy flux to left and right element storage - for v in eachvariable(equations_parabolic) - surface_flux_values[v, i, left_direction, left_id] = flux[v] - surface_flux_values[v, i, right_direction, right_id] = flux[v] - end - end - end - end + @trixi_timeit timer() "interface flux" calc_interface_flux!( + cache_parabolic.elements.surface_flux_values, mesh, + have_nonconservative_terms(equations_parabolic), equations_parabolic, + dg, cache_parabolic) # Prolong solution to boundaries @trixi_timeit timer() "prolong2boundaries" begin @@ -246,6 +222,41 @@ function prolong2interfaces!(cache_parabolic, flux_viscous, end +# This is the version used when calculating the divergence of the viscous fluxes +function calc_interface_flux!(surface_flux_values, + mesh::TreeMesh{2}, + nonconservative_terms::Val{false}, equations_parabolic, + dg::DG, cache_parabolic) + @unpack neighbor_ids, orientations = cache_parabolic.interfaces + + @threaded for interface in eachinterface(dg, cache_parabolic) + # Get neighboring elements + left_id = neighbor_ids[1, interface] + right_id = neighbor_ids[2, interface] + + # Determine interface direction with respect to elements: + # orientation = 1: left -> 2, right -> 1 + # orientation = 2: left -> 4, right -> 3 + left_direction = 2 * orientations[interface] + right_direction = 2 * orientations[interface] - 1 + + for i in eachnode(dg) + # Call pointwise Riemann solver + u_ll, u_rr = get_surface_node_vars(cache_parabolic.interfaces.u, equations_parabolic, dg, i, interface) + flux = 0.5 * (u_ll + u_rr) + + # Copy flux to left and right element storage + for v in eachvariable(equations_parabolic) + surface_flux_values[v, i, left_direction, left_id] = flux[v] + surface_flux_values[v, i, right_direction, right_id] = flux[v] + end + end + end + + return nothing +end + + function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) From 3400e83824dcec5601e7ccbf16f93f4de56bd819 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 12:11:58 +0200 Subject: [PATCH 135/143] Refactor prolong2boundaries! --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 81 +++++++++++++---------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 89a10b6d849..05a2afc46cd 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -89,42 +89,8 @@ function calc_divergence!(du, u, t, flux_viscous, dg, cache_parabolic) # Prolong solution to boundaries - @trixi_timeit timer() "prolong2boundaries" begin - @unpack boundaries = cache_parabolic - @unpack orientations, neighbor_sides = boundaries - flux_viscous_x, flux_viscous_y = flux_viscous - - @threaded for boundary in eachboundary(dg, cache_parabolic) - element = boundaries.neighbor_ids[boundary] - - if orientations[boundary] == 1 - # boundary in x-direction - if neighbor_sides[boundary] == 1 - # element in -x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = flux_viscous_x[v, nnodes(dg), l, element] - end - else # Element in +x direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = flux_viscous_x[v, 1, l, element] - end - end - else # if orientations[boundary] == 2 - # boundary in y-direction - if neighbor_sides[boundary] == 1 - # element in -y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[1, v, l, boundary] = flux_viscous_y[v, l, nnodes(dg), element] - end - else - # element in +y direction of boundary - for l in eachnode(dg), v in eachvariable(equations_parabolic) - boundaries.u[2, v, l, boundary] = flux_viscous_y[v, l, 1, element] - end - end - end - end - end + @trixi_timeit timer() "prolong2boundaries" prolong2boundaries!( + cache_parabolic, flux_viscous, mesh, equations_parabolic, dg.surface_integral, dg, cache) # Calculate boundary fluxes @trixi_timeit timer() "boundary flux" begin @@ -257,6 +223,49 @@ function calc_interface_flux!(surface_flux_values, end +# This is the version used when calculating the divergence of the viscous fluxes +function prolong2boundaries!(cache_parabolic, flux_viscous, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, + surface_integral, dg::DG, cache) + @unpack boundaries = cache_parabolic + @unpack orientations, neighbor_sides = boundaries + flux_viscous_x, flux_viscous_y = flux_viscous + + @threaded for boundary in eachboundary(dg, cache_parabolic) + element = boundaries.neighbor_ids[boundary] + + if orientations[boundary] == 1 + # boundary in x-direction + if neighbor_sides[boundary] == 1 + # element in -x direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[1, v, l, boundary] = flux_viscous_x[v, nnodes(dg), l, element] + end + else # Element in +x direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[2, v, l, boundary] = flux_viscous_x[v, 1, l, element] + end + end + else # if orientations[boundary] == 2 + # boundary in y-direction + if neighbor_sides[boundary] == 1 + # element in -y direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[1, v, l, boundary] = flux_viscous_y[v, l, nnodes(dg), element] + end + else + # element in +y direction of boundary + for l in eachnode(dg), v in eachvariable(equations_parabolic) + boundaries.u[2, v, l, boundary] = flux_viscous_y[v, l, 1, element] + end + end + end + end + + return nothing +end + + function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) From cb82c8fff7c313c641492cdfeba1b3250ee2a5c2 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 12:26:36 +0200 Subject: [PATCH 136/143] Refactor calc_divergence! --- src/solvers/dgsem_tree/dg_2d.jl | 1 + src/solvers/dgsem_tree/dg_2d_parabolic.jl | 116 ++++++++-------------- 2 files changed, 43 insertions(+), 74 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index 5215db6edc0..775d74e3726 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -961,6 +961,7 @@ end end +# we pass in the hyperbolic `dg.surface_integral` as a dummy argument for dispatch function calc_surface_integral!(du, u, mesh::Union{TreeMesh{2}, StructuredMesh{2}}, equations, surface_integral::SurfaceIntegralWeakForm, dg::DG, cache) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 05a2afc46cd..bae707fb357 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -10,65 +10,29 @@ # will be discretized first order form as follows: # 1. compute grad(u) # 2. compute f(u, grad(u)) -# 3. compute div(u) -# boundary conditions will be applied to both grad(u) and div(u). +# 3. compute div(f(u, grad(u))) (i.e., the "regular" rhs! call) +# boundary conditions will be applied to both grad(u) and div(f(u, grad(u))). function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, - initial_condition, boundary_conditions, source_terms, + initial_condition, boundary_conditions_parabolic, source_terms, dg::DG, parabolic_scheme, cache, cache_parabolic) - - # Reset du - @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) - - @unpack u_transformed, gradients, flux_viscous = cache_parabolic - @trixi_timeit timer() "transform variables" transform_variables!(u_transformed, u, - mesh, equations_parabolic, - dg, parabolic_scheme, - cache, cache_parabolic) - - @trixi_timeit timer() "calculate gradient" calc_gradient!(gradients, u_transformed, t, mesh, - equations_parabolic, - boundary_conditions, dg, - cache, cache_parabolic) - - @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, - mesh, equations_parabolic, - dg, cache, cache_parabolic) - - @trixi_timeit timer() "calculate divergence" calc_divergence!(du, u_transformed, t, flux_viscous, - mesh, - equations_parabolic, - boundary_conditions, dg, - parabolic_scheme, cache, - cache_parabolic) - return nothing + # Convert conservative variables to a form more suitable for viscous flux calculations + @trixi_timeit timer() "transform variables" transform_variables!( + u_transformed, u, mesh, equations_parabolic, dg, parabolic_scheme, cache, cache_parabolic) -end + # Compute the gradients of the transformed variables + @trixi_timeit timer() "calculate gradient" calc_gradient!( + gradients, u_transformed, t, mesh, equations_parabolic, boundary_conditions_parabolic, dg, + cache, cache_parabolic) -# Transform solution variables prior to taking the gradient -# (e.g., conservative to primitive variables). Defaults to doing nothing. -# TODO: can we avoid copying data? -function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, - equations_parabolic::AbstractEquationsParabolic, - dg::DG, parabolic_scheme, cache, cache_parabolic) - @threaded for element in eachelement(dg, cache) - # Calculate volume terms in one element - for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) - u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, equations_parabolic) - set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) - end - end -end + # Compute and store the viscous fluxes + @trixi_timeit timer() "calculate viscous fluxes" calc_viscous_fluxes!( + flux_viscous, gradients, u_transformed, mesh, equations_parabolic, dg, cache, cache_parabolic) + + # The remainder of this function is essentially a regular rhs! for parabolic equations (i.e., it + # computes the divergence of the viscous fluxes) -# note: the argument parabolic_scheme is not a DG type; it contains solver-specific -# information such as an LDG penalty parameter. -function calc_divergence!(du, u, t, flux_viscous, - mesh::TreeMesh{2}, equations_parabolic, - boundary_conditions_parabolic, dg::DG, - parabolic_scheme, # not a `DG` type - cache, cache_parabolic) # Reset du @trixi_timeit timer() "reset ∂u/∂t" reset_du!(du, dg, cache) @@ -93,37 +57,40 @@ function calc_divergence!(du, u, t, flux_viscous, cache_parabolic, flux_viscous, mesh, equations_parabolic, dg.surface_integral, dg, cache) # Calculate boundary fluxes - @trixi_timeit timer() "boundary flux" begin - calc_boundary_flux_divergence!(cache_parabolic, t, boundary_conditions_parabolic, - mesh, equations_parabolic, dg.surface_integral, dg) - end + @trixi_timeit timer() "boundary flux" calc_boundary_flux_divergence!( + cache_parabolic, t, boundary_conditions_parabolic, mesh, equations_parabolic, + dg.surface_integral, dg) # TODO: parabolic; extend to mortars @assert nmortars(dg, cache) == 0 - # Prolong solution to mortars - # @trixi_timeit timer() "prolong2mortars" prolong2mortars!( - # cache, u, mesh, equations_parabolic, dg.mortar, dg.surface_integral, dg) - - # Calculate mortar fluxes - # @trixi_timeit timer() "mortar flux" calc_mortar_flux!( - # cache.elements.surface_flux_values, mesh, - # have_nonconservative_terms(equations_parabolic), equations_parabolic, - # dg.mortar, dg.surface_integral, dg, cache) # Calculate surface integrals - @trixi_timeit timer() "surface integral" begin - # we pass in the hyperbolic `dg.surface_integral` as a dummy argument - calc_surface_integral!(du, u, mesh, equations_parabolic, dg.surface_integral, dg, cache_parabolic) - end + @trixi_timeit timer() "surface integral" calc_surface_integral!( + du, u, mesh, equations_parabolic, dg.surface_integral, dg, cache_parabolic) # Apply Jacobian from mapping to reference element - @trixi_timeit timer() "Jacobian" begin - apply_jacobian!(du, mesh, equations_parabolic, dg, cache_parabolic) - end + @trixi_timeit timer() "Jacobian" apply_jacobian!( + du, mesh, equations_parabolic, dg, cache_parabolic) return nothing end +# Transform solution variables prior to taking the gradient +# (e.g., conservative to primitive variables). Defaults to doing nothing. +# TODO: can we avoid copying data? +function transform_variables!(u_transformed, u, mesh::TreeMesh{2}, + equations_parabolic::AbstractEquationsParabolic, + dg::DG, parabolic_scheme, cache, cache_parabolic) + @threaded for element in eachelement(dg, cache) + # Calculate volume terms in one element + for j in eachnode(dg), i in eachnode(dg) + u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_transformed_node = gradient_variable_transformation(equations_parabolic)(u_node, equations_parabolic) + set_node_vars!(u_transformed, u_transformed_node, equations_parabolic, dg, i, j, element) + end + end +end + # This is the version used when calculating the divergence of the viscous fluxes function calc_volume_integral!(du, flux_viscous, @@ -269,9 +236,9 @@ end function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) - gradients_x, gradients_y = gradients flux_viscous_x, flux_viscous_y = flux_viscous # output arrays + @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients @@ -288,6 +255,7 @@ function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, end end + # TODO: parabolic; decide if we should keep this, and if so, extend to 3D. function get_unsigned_normal_vector_2d(direction) if direction > 4 || direction < 1 @@ -523,7 +491,7 @@ function calc_gradient!(gradients, u, t, mesh, equations_parabolic, dg.surface_integral, dg) end -# TODO: parabolic; mortars + # TODO: parabolic; mortars # Calculate surface integrals @trixi_timeit timer() "surface integral" begin From 5c7becc60383088cd2d4ca9ae41cccb6cc4fd0fc Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 12:42:30 +0200 Subject: [PATCH 137/143] Formatting consistency --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 29 +++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index bae707fb357..54a07f42a91 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -123,7 +123,7 @@ end # This is the version used when calculating the divergence of the viscous fluxes -# we pass in the hyperbolic `dg.surface_integral` as a dummy argument +# we pass in the hyperbolic `dg.surface_integral` as a dummy argument for dispatch function prolong2interfaces!(cache_parabolic, flux_viscous, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) @@ -233,7 +233,7 @@ function prolong2boundaries!(cache_parabolic, flux_viscous, end -function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, +function calc_viscous_fluxes!(flux_viscous, gradients, u_transformed, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DG, cache, cache_parabolic) gradients_x, gradients_y = gradients @@ -242,7 +242,7 @@ function calc_viscous_fluxes!(flux_viscous, gradients, u, mesh::TreeMesh{2}, @threaded for element in eachelement(dg, cache) for j in eachnode(dg), i in eachnode(dg) # Get solution and gradients - u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_node = get_node_vars(u_transformed, equations_parabolic, dg, i, j, element) gradients_1_node = get_node_vars(gradients_x, equations_parabolic, dg, i, j, element) gradients_2_node = get_node_vars(gradients_y, equations_parabolic, dg, i, j, element) @@ -412,14 +412,16 @@ function calc_divergence_boundary_flux_by_direction!(surface_flux_values::Abstra return nothing end -function calc_gradient!(gradients, u, t, + +# Calculate the gradient of the transformed variables +function calc_gradient!(gradients, u_transformed, t, mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) gradients_x, gradients_y = gradients # Reset du - @trixi_timeit timer() "reset ∂u/∂t" begin + @trixi_timeit timer() "reset gradients" begin reset_du!(gradients_x, dg, cache) reset_du!(gradients_y, dg, cache) end @@ -431,7 +433,7 @@ function calc_gradient!(gradients, u, t, # Calculate volume terms in one element for j in eachnode(dg), i in eachnode(dg) - u_node = get_node_vars(u, equations_parabolic, dg, i, j, element) + u_node = get_node_vars(u_transformed, equations_parabolic, dg, i, j, element) for ii in eachnode(dg) multiply_add_to_node_vars!(gradients_x, derivative_dhat[ii, i], u_node, equations_parabolic, dg, ii, j, element) @@ -446,7 +448,7 @@ function calc_gradient!(gradients, u, t, # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( - cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) + cache_parabolic, u_transformed, mesh, equations_parabolic, dg.surface_integral, dg) # Calculate interface fluxes @trixi_timeit timer() "interface flux" begin @@ -480,16 +482,13 @@ function calc_gradient!(gradients, u, t, end # Prolong solution to boundaries - @trixi_timeit timer() "prolong2boundaries" begin - # we pass in the hyperbolic `dg.surface_integral` as a dummy argument - prolong2boundaries!(cache_parabolic, u, mesh, equations_parabolic, dg.surface_integral, dg) - end + @trixi_timeit timer() "prolong2boundaries" prolong2boundaries!( + cache_parabolic, u_transformed, mesh, equations_parabolic, dg.surface_integral, dg) # Calculate boundary fluxes - @trixi_timeit timer() "boundary flux" begin - calc_boundary_flux_gradients!(cache_parabolic, t, boundary_conditions_parabolic, - mesh, equations_parabolic, dg.surface_integral, dg) - end + @trixi_timeit timer() "boundary flux" calc_boundary_flux_gradients!( + cache_parabolic, t, boundary_conditions_parabolic, mesh, equations_parabolic, + dg.surface_integral, dg) # TODO: parabolic; mortars From 9510dc8c318ff986502a7c36cc442f4dc89b4e44 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 13:05:36 +0200 Subject: [PATCH 138/143] Remove dispatch on volume integral type --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 54a07f42a91..82ef4ea062b 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -39,8 +39,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra # Calculate volume integral @trixi_timeit timer() "volume integral" calc_volume_integral!( du, flux_viscous, mesh, - have_nonconservative_terms(equations_parabolic), equations_parabolic, - dg.volume_integral, dg, cache) + have_nonconservative_terms(equations_parabolic), equations_parabolic, dg, cache) # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( @@ -97,7 +96,6 @@ function calc_volume_integral!(du, flux_viscous, mesh::TreeMesh{2}, nonconservative_terms, equations_parabolic::AbstractEquationsParabolic, - volume_integral::VolumeIntegralWeakForm, dg::DGSEM, cache) @unpack derivative_dhat = dg.basis flux_viscous_x, flux_viscous_y = flux_viscous From 831f878e9aef3f214d1e3101d5f19c7065f3c52e Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 13:28:07 +0200 Subject: [PATCH 139/143] Add comment on why surface_integral is passed to prolong2interfaces! --- src/solvers/dgmulti/dg.jl | 2 ++ src/solvers/dgmulti/dg_parabolic.jl | 1 + src/solvers/dgmulti/sbp.jl | 1 + src/solvers/dgsem_p4est/dg_2d.jl | 1 + src/solvers/dgsem_p4est/dg_3d.jl | 1 + src/solvers/dgsem_tree/dg_1d.jl | 1 + src/solvers/dgsem_tree/dg_2d.jl | 1 + src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- src/solvers/dgsem_tree/dg_3d.jl | 1 + src/solvers/dgsem_unstructured/dg_2d.jl | 1 + 10 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/solvers/dgmulti/dg.jl b/src/solvers/dgmulti/dg.jl index c4abe2e91b7..e6caf61c168 100644 --- a/src/solvers/dgmulti/dg.jl +++ b/src/solvers/dgmulti/dg.jl @@ -158,6 +158,7 @@ function max_dt(u, t, mesh::DGMultiMesh, end # interpolates from solution coefficients to face quadrature points +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::DGMultiMesh, equations, surface_integral, dg::DGMulti) rd = dg.basis @@ -259,6 +260,7 @@ function calc_surface_integral!(du, u, surface_integral::SurfaceIntegralWeakForm end # Specialize for nodal SBP discretizations. Uses that Vf*u = u[Fmask,:] +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::DGMultiMesh, equations, surface_integral, dg::DGMultiSBP) rd = dg.basis diff --git a/src/solvers/dgmulti/dg_parabolic.jl b/src/solvers/dgmulti/dg_parabolic.jl index ec8d03e5d5d..50cfd8ab17d 100644 --- a/src/solvers/dgmulti/dg_parabolic.jl +++ b/src/solvers/dgmulti/dg_parabolic.jl @@ -49,6 +49,7 @@ function transform_variables!(u_transformed, u, mesh, equations_parabolic::Abstr end # interpolates from solution coefficients to face quadrature points +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(u_face_values, u, mesh::DGMultiMesh, equations::AbstractEquationsParabolic, surface_integral, dg::DGMulti, cache) apply_to_each_field(mul_by!(dg.basis.Vf), u_face_values, u) diff --git a/src/solvers/dgmulti/sbp.jl b/src/solvers/dgmulti/sbp.jl index 49bad9d8547..357e6550660 100644 --- a/src/solvers/dgmulti/sbp.jl +++ b/src/solvers/dgmulti/sbp.jl @@ -433,6 +433,7 @@ function estimate_dt(mesh::DGMultiMesh, dg::DGMultiPeriodicFDSBP) end # do nothing for interface terms if using a periodic operator +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::DGMultiMesh, equations, surface_integral, dg::DGMultiPeriodicFDSBP) @assert nelements(mesh, dg, cache) == 1 diff --git a/src/solvers/dgsem_p4est/dg_2d.jl b/src/solvers/dgsem_p4est/dg_2d.jl index e4103909646..68ff171b44f 100644 --- a/src/solvers/dgsem_p4est/dg_2d.jl +++ b/src/solvers/dgsem_p4est/dg_2d.jl @@ -56,6 +56,7 @@ end end end +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::P4estMesh{2}, equations, surface_integral, dg::DG) diff --git a/src/solvers/dgsem_p4est/dg_3d.jl b/src/solvers/dgsem_p4est/dg_3d.jl index 8723c5c70e0..66df88f0e7c 100644 --- a/src/solvers/dgsem_p4est/dg_3d.jl +++ b/src/solvers/dgsem_p4est/dg_3d.jl @@ -83,6 +83,7 @@ end return (i1, i2) end +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::P4estMesh{3}, equations, surface_integral, dg::DG) diff --git a/src/solvers/dgsem_tree/dg_1d.jl b/src/solvers/dgsem_tree/dg_1d.jl index 16495000561..17d1c779364 100644 --- a/src/solvers/dgsem_tree/dg_1d.jl +++ b/src/solvers/dgsem_tree/dg_1d.jl @@ -371,6 +371,7 @@ end end +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::TreeMesh{1}, equations, surface_integral, dg::DG) @unpack interfaces = cache diff --git a/src/solvers/dgsem_tree/dg_2d.jl b/src/solvers/dgsem_tree/dg_2d.jl index 775d74e3726..d725a8d828e 100644 --- a/src/solvers/dgsem_tree/dg_2d.jl +++ b/src/solvers/dgsem_tree/dg_2d.jl @@ -490,6 +490,7 @@ end end +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::TreeMesh{2}, equations, surface_integral, dg::DG) @unpack interfaces = cache diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 82ef4ea062b..9f0a4678388 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -121,7 +121,7 @@ end # This is the version used when calculating the divergence of the viscous fluxes -# we pass in the hyperbolic `dg.surface_integral` as a dummy argument for dispatch +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache_parabolic, flux_viscous, mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, surface_integral, dg::DG, cache) diff --git a/src/solvers/dgsem_tree/dg_3d.jl b/src/solvers/dgsem_tree/dg_3d.jl index 611691f9f85..acd1b31d646 100644 --- a/src/solvers/dgsem_tree/dg_3d.jl +++ b/src/solvers/dgsem_tree/dg_3d.jl @@ -544,6 +544,7 @@ end end +# We pass the `surface_integral` argument solely for dispatch function prolong2interfaces!(cache, u, mesh::TreeMesh{3}, equations, surface_integral, dg::DG) @unpack interfaces = cache diff --git a/src/solvers/dgsem_unstructured/dg_2d.jl b/src/solvers/dgsem_unstructured/dg_2d.jl index 4128e1c6295..f2872652c8b 100644 --- a/src/solvers/dgsem_unstructured/dg_2d.jl +++ b/src/solvers/dgsem_unstructured/dg_2d.jl @@ -81,6 +81,7 @@ end # prolong the solution into the convenience array in the interior interface container +# We pass the `surface_integral` argument solely for dispatch # Note! this routine is for quadrilateral elements with "right-handed" orientation function prolong2interfaces!(cache, u, mesh::UnstructuredMesh2D, From 23015ea02de130f9253aed467a7714128e8ba89e Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 14:49:35 +0200 Subject: [PATCH 140/143] Explicitly use weak form volume integral to allow easy overriding in test --- examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl index 6ecb7f7d8fe..173c01365c1 100644 --- a/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl +++ b/examples/tree_2d_dgsem/elixir_navier_stokes_convergence.jl @@ -12,7 +12,8 @@ equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, Reynolds=re Mach_freestream=0.5) # Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux -solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs) +solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs, + volume_integral=VolumeIntegralWeakForm()) coordinates_min = (-1.0, -1.0) # minimum coordinates (min(x), min(y)) coordinates_max = ( 1.0, 1.0) # maximum coordinates (max(x), max(y)) From d1ea1be5ce3e7993f937021f946e0ecef4def126 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 14:51:40 +0200 Subject: [PATCH 141/143] Add flux differencing test for CNS test --- test/test_parabolic_2d.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_parabolic_2d.jl b/test/test_parabolic_2d.jl index 11e31ff7764..c61e5cf918c 100644 --- a/test/test_parabolic_2d.jl +++ b/test/test_parabolic_2d.jl @@ -134,6 +134,15 @@ isdir(outdir) && rm(outdir, recursive=true) ) end + @trixi_testset "TreeMesh2D: elixir_navier_stokes_convergence.jl (flux differencing)" begin + @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_convergence.jl"), + initial_refinement_level = 2, tspan=(0.0, 0.1), + volume_integral=VolumeIntegralFluxDifferencing(flux_central), + l2 = [0.0021116725306635146, 0.0034322351490824465, 0.003874252819611102, 0.012469246082522416], + linf = [0.012006418939297214, 0.03552087120958058, 0.02451274749176294, 0.11191122588577151] + ) + end + @trixi_testset "TreeMesh2D: elixir_navier_stokes_lid_driven_cavity.jl" begin @test_trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_navier_stokes_lid_driven_cavity.jl"), initial_refinement_level = 2, tspan=(0.0, 0.5), From 9976085026cdd9a7ee8cba027cba943485508bdd Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 16:43:56 +0200 Subject: [PATCH 142/143] Remove erroneous P4estMesh{2} dispatch --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 9f0a4678388..41375c8ab10 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -413,7 +413,7 @@ end # Calculate the gradient of the transformed variables function calc_gradient!(gradients, u_transformed, t, - mesh::Union{TreeMesh{2}, P4estMesh{2}}, equations_parabolic, + mesh::TreeMesh{2}, equations_parabolic, boundary_conditions_parabolic, dg::DG, cache, cache_parabolic) gradients_x, gradients_y = gradients From b06f9272192d569fad8e7a826a4c470530eb114d Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Tue, 9 Aug 2022 16:46:38 +0200 Subject: [PATCH 143/143] Remove non-cons terms from parabolic solver --- src/solvers/dgsem_tree/dg_2d_parabolic.jl | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/solvers/dgsem_tree/dg_2d_parabolic.jl b/src/solvers/dgsem_tree/dg_2d_parabolic.jl index 41375c8ab10..8099d5d6a6e 100644 --- a/src/solvers/dgsem_tree/dg_2d_parabolic.jl +++ b/src/solvers/dgsem_tree/dg_2d_parabolic.jl @@ -38,8 +38,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra # Calculate volume integral @trixi_timeit timer() "volume integral" calc_volume_integral!( - du, flux_viscous, mesh, - have_nonconservative_terms(equations_parabolic), equations_parabolic, dg, cache) + du, flux_viscous, mesh, equations_parabolic, dg, cache) # Prolong solution to interfaces @trixi_timeit timer() "prolong2interfaces" prolong2interfaces!( @@ -47,9 +46,7 @@ function rhs_parabolic!(du, u, t, mesh::TreeMesh{2}, equations_parabolic::Abstra # Calculate interface fluxes @trixi_timeit timer() "interface flux" calc_interface_flux!( - cache_parabolic.elements.surface_flux_values, mesh, - have_nonconservative_terms(equations_parabolic), equations_parabolic, - dg, cache_parabolic) + cache_parabolic.elements.surface_flux_values, mesh, equations_parabolic, dg, cache_parabolic) # Prolong solution to boundaries @trixi_timeit timer() "prolong2boundaries" prolong2boundaries!( @@ -93,9 +90,7 @@ end # This is the version used when calculating the divergence of the viscous fluxes function calc_volume_integral!(du, flux_viscous, - mesh::TreeMesh{2}, - nonconservative_terms, - equations_parabolic::AbstractEquationsParabolic, + mesh::TreeMesh{2}, equations_parabolic::AbstractEquationsParabolic, dg::DGSEM, cache) @unpack derivative_dhat = dg.basis flux_viscous_x, flux_viscous_y = flux_viscous @@ -155,8 +150,7 @@ end # This is the version used when calculating the divergence of the viscous fluxes function calc_interface_flux!(surface_flux_values, - mesh::TreeMesh{2}, - nonconservative_terms::Val{false}, equations_parabolic, + mesh::TreeMesh{2}, equations_parabolic, dg::DG, cache_parabolic) @unpack neighbor_ids, orientations = cache_parabolic.interfaces