Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ This enables in particular adaptive mesh refinement for that solver-mesh combina
Instead, it is possible to reconstruct in custom variables, if functions `cons2recon` and `recon2cons` are provided to
`VolumeIntegralPureLGLFiniteVolumeO2` and `VolumeIntegralShockCapturingRRG`([#2817]).
- Add Legendre-Gauss basis for DGSEM and implement solver (`VolumeIntegralWeakForm` and `SurfaceIntegralWeakForm` only) support for conforming 1D & 2D `TreeMesh`es ([#1965]).
- Extended 3D support for subcell limiting with `P4estMesh` was added ([#2763]).
- Extended 3D support for subcell limiting was added ([#2763], [#2846]).
In the new version, local (minimum and maximum) limiting for conservative variables (using the
keyword `local_twosided_variables_cons` in `SubcellLimiterIDP()`) is supported.
keyword `local_twosided_variables_cons` in `SubcellLimiterIDP()`) with `P4estMesh` is supported.
Moreover, initial support for `TreeMesh{3}` including positivity limiting on periodic meshes was added.

## Changes when updating to v0.15 from v0.14.x

Expand Down
98 changes: 98 additions & 0 deletions examples/tree_3d_dgsem/elixir_euler_sedov_blast_wave_sc_subcell.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Trixi

###############################################################################
# semidiscretization of the compressible Euler equations

equations = CompressibleEulerEquations3D(1.4)

"""
initial_condition_sedov_blast_wave(x, t, equations::CompressibleEulerEquations3D)

The Sedov blast wave setup based on example 35.1.4 from Flash
- https://flash.rochester.edu/site/flashcode/user_support/flash4_ug_4p8.pdf
with smaller strength of the initial discontinuity.
"""
function initial_condition_sedov_blast_wave(x, t,
equations::CompressibleEulerEquations3D)
# Set up polar coordinates
inicenter = SVector(0.0, 0.0, 0.0)
x_norm = x[1] - inicenter[1]
y_norm = x[2] - inicenter[2]
z_norm = x[3] - inicenter[3]
r = sqrt(x_norm^2 + y_norm^2 + z_norm^2)

# Setup based on https://flash.rochester.edu/site/flashcode/user_support/flash_ug_devel/node187.html#SECTION010114000000000000000
r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6)
E = 1.0
p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2)
p0_outer = 1.0e-5

# Calculate primitive variables
rho = 1.0
v1 = 0.0
v2 = 0.0
v3 = 0.0
p = r > r0 ? p0_outer : p0_inner

return prim2cons(SVector(rho, v1, v2, v3, p), equations)
end
initial_condition = initial_condition_sedov_blast_wave

surface_flux = flux_lax_friedrichs
volume_flux = flux_ranocha
polydeg = 3
basis = LobattoLegendreBasis(polydeg)
limiter_idp = SubcellLimiterIDP(equations, basis;
positivity_variables_cons = ["rho"],
positivity_variables_nonlinear = [pressure],
max_iterations_newton = 20)
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
volume_flux_dg = volume_flux,
volume_flux_fv = surface_flux)
solver = DGSEM(basis, surface_flux, volume_integral)

coordinates_min = (-1.0, -1.0, -1.0)
coordinates_max = (1.0, 1.0, 1.0)
mesh = TreeMesh(coordinates_min, coordinates_max,
initial_refinement_level = 3,
n_cells_max = 100_000,
periodicity = true)

# create the semi discretization object
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
boundary_conditions = boundary_condition_periodic)

###############################################################################
# ODE solvers, callbacks etc.

tspan = (0.0, 3.0)
ode = semidiscretize(semi, tspan)

summary_callback = SummaryCallback()

analysis_interval = 100
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)

alive_callback = AliveCallback(analysis_interval = analysis_interval)

save_solution = SaveSolutionCallback(interval = 10,
save_initial_solution = true,
save_final_solution = true,
extra_node_variables = (:limiting_coefficient,))

stepsize_callback = StepsizeCallback(cfl = 0.5)

callbacks = CallbackSet(summary_callback,
analysis_callback,
alive_callback,
save_solution,
stepsize_callback)

###############################################################################
# run the simulation

stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback())

sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
callback = callbacks);
2 changes: 1 addition & 1 deletion src/callbacks_stage/subcell_limiter_idp_correction_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#! format: noindent

function perform_idp_correction!(u, dt,
mesh::P4estMesh{3},
mesh::Union{TreeMesh{3}, P4estMesh{3}},
equations, dg, cache)
@unpack inverse_weights = dg.basis # Plays role of inverse DG-subcell sizes
@unpack antidiffusive_flux1_L, antidiffusive_flux1_R, antidiffusive_flux2_L, antidiffusive_flux2_R, antidiffusive_flux3_L, antidiffusive_flux3_R = cache.antidiffusive_fluxes
Expand Down
44 changes: 22 additions & 22 deletions src/solvers/dgsem_p4est/dg_3d_subcell_limiters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@muladd begin
#! format: noindent

function create_cache(mesh::P4estMesh{3},
function create_cache(mesh::Union{TreeMesh{3}, P4estMesh{3}},
equations, volume_integral::VolumeIntegralSubcellLimiting,
dg::DG, cache_containers, uEltype)
cache = create_cache(mesh, equations,
Expand Down Expand Up @@ -61,7 +61,7 @@ end

# Subcell limiting currently only implemented for certain mesh types
@inline function volume_integral_kernel!(du, u, element,
mesh::P4estMesh{3},
mesh::Union{TreeMesh{3}, P4estMesh{3}},
nonconservative_terms, equations,
volume_integral::VolumeIntegralSubcellLimiting,
dg::DGSEM, cache)
Expand Down Expand Up @@ -171,12 +171,12 @@ end
end

# FV-form flux `fhat` in x direction
for k in eachnode(dg), j in eachnode(dg), i in 1:(nnodes(dg) - 1),
v in eachvariable(equations)

fhat1_L[v, i + 1, j, k] = fhat1_L[v, i, j, k] +
weights[i] * flux_temp[v, i, j, k]
fhat1_R[v, i + 1, j, k] = fhat1_L[v, i + 1, j, k]
for k in eachnode(dg), j in eachnode(dg), i in 1:(nnodes(dg) - 1)
for v in eachvariable(equations)
fhat1_L[v, i + 1, j, k] = fhat1_L[v, i, j, k] +
weights[i] * flux_temp[v, i, j, k]
fhat1_R[v, i + 1, j, k] = fhat1_L[v, i + 1, j, k]
end
end

# Split form volume flux in orientation 2: y direction
Expand Down Expand Up @@ -206,12 +206,12 @@ end
end

# FV-form flux `fhat` in y direction
for k in eachnode(dg), j in 1:(nnodes(dg) - 1), i in eachnode(dg),
v in eachvariable(equations)

fhat2_L[v, i, j + 1, k] = fhat2_L[v, i, j, k] +
weights[j] * flux_temp[v, i, j, k]
fhat2_R[v, i, j + 1, k] = fhat2_L[v, i, j + 1, k]
for k in eachnode(dg), j in 1:(nnodes(dg) - 1), i in eachnode(dg)
for v in eachvariable(equations)
fhat2_L[v, i, j + 1, k] = fhat2_L[v, i, j, k] +
weights[j] * flux_temp[v, i, j, k]
fhat2_R[v, i, j + 1, k] = fhat2_L[v, i, j + 1, k]
end
end

# Split form volume flux in orientation 3: z direction
Expand Down Expand Up @@ -241,12 +241,12 @@ end
end

# FV-form flux `fhat` in z direction
for k in 1:(nnodes(dg) - 1), j in eachnode(dg), i in eachnode(dg),
v in eachvariable(equations)

fhat3_L[v, i, j, k + 1] = fhat3_L[v, i, j, k] +
weights[k] * flux_temp[v, i, j, k]
fhat3_R[v, i, j, k + 1] = fhat3_L[v, i, j, k + 1]
for k in 1:(nnodes(dg) - 1), j in eachnode(dg), i in eachnode(dg)
for v in eachvariable(equations)
fhat3_L[v, i, j, k + 1] = fhat3_L[v, i, j, k] +
weights[k] * flux_temp[v, i, j, k]
fhat3_R[v, i, j, k + 1] = fhat3_L[v, i, j, k + 1]
end
end

return nothing
Expand Down Expand Up @@ -551,7 +551,7 @@ end
fstar1_L, fstar1_R,
fstar2_L, fstar2_R,
fstar3_L, fstar3_R,
u, mesh::P4estMesh{3},
u, mesh::Union{TreeMesh{3}, P4estMesh{3}},
nonconservative_terms::False, equations,
limiter::SubcellLimiterIDP, dg, element, cache)
@unpack antidiffusive_flux1_L, antidiffusive_flux1_R, antidiffusive_flux2_L, antidiffusive_flux2_R, antidiffusive_flux3_L, antidiffusive_flux3_R = cache.antidiffusive_fluxes
Expand Down Expand Up @@ -602,7 +602,7 @@ end
fstar1_L, fstar1_R,
fstar2_L, fstar2_R,
fstar3_L, fstar3_R,
u, mesh::P4estMesh{3},
u, mesh::Union{TreeMesh{3}, P4estMesh{3}},
nonconservative_terms::True, equations,
limiter::SubcellLimiterIDP, dg, element, cache)
@unpack antidiffusive_flux1_L, antidiffusive_flux2_L, antidiffusive_flux1_R, antidiffusive_flux2_R, antidiffusive_flux3_L, antidiffusive_flux3_R = cache.antidiffusive_fluxes
Expand Down
16 changes: 10 additions & 6 deletions src/solvers/dgsem_structured/dg_2d_subcell_limiters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@
end

# FV-form flux `fhat` in x direction
for j in eachnode(dg), i in 1:(nnodes(dg) - 1), v in eachvariable(equations)
fhat1_L[v, i + 1, j] = fhat1_L[v, i, j] + weights[i] * flux_temp[v, i, j]
fhat1_R[v, i + 1, j] = fhat1_L[v, i + 1, j]
for j in eachnode(dg), i in 1:(nnodes(dg) - 1)
for v in eachvariable(equations)
fhat1_L[v, i + 1, j] = fhat1_L[v, i, j] + weights[i] * flux_temp[v, i, j]
fhat1_R[v, i + 1, j] = fhat1_L[v, i + 1, j]
end
end

# Split form volume flux in orientation 2: y direction
Expand Down Expand Up @@ -91,9 +93,11 @@
end

# FV-form flux `fhat` in y direction
for j in 1:(nnodes(dg) - 1), i in eachnode(dg), v in eachvariable(equations)
fhat2_L[v, i, j + 1] = fhat2_L[v, i, j] + weights[j] * flux_temp[v, i, j]
fhat2_R[v, i, j + 1] = fhat2_L[v, i, j + 1]
for j in 1:(nnodes(dg) - 1), i in eachnode(dg)
for v in eachvariable(equations)
fhat2_L[v, i, j + 1] = fhat2_L[v, i, j] + weights[j] * flux_temp[v, i, j]
fhat2_R[v, i, j + 1] = fhat2_L[v, i, j + 1]
end
end

return nothing
Expand Down
1 change: 1 addition & 0 deletions src/solvers/dgsem_tree/dg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,5 @@ include("dg_3d_compressible_euler.jl")
include("subcell_limiters.jl")
include("subcell_limiters_2d.jl")
include("dg_2d_subcell_limiters.jl")
include("dg_3d_subcell_limiters.jl")
end # @muladd
16 changes: 10 additions & 6 deletions src/solvers/dgsem_tree/dg_2d_subcell_limiters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,11 @@ end
end

# FV-form flux `fhat` in x direction
for j in eachnode(dg), i in 1:(nnodes(dg) - 1), v in eachvariable(equations)
fhat1_L[v, i + 1, j] = fhat1_L[v, i, j] + weights[i] * flux_temp[v, i, j]
fhat1_R[v, i + 1, j] = fhat1_L[v, i + 1, j]
for j in eachnode(dg), i in 1:(nnodes(dg) - 1)
for v in eachvariable(equations)
fhat1_L[v, i + 1, j] = fhat1_L[v, i, j] + weights[i] * flux_temp[v, i, j]
fhat1_R[v, i + 1, j] = fhat1_L[v, i + 1, j]
end
end

# Split form volume flux in orientation 2: y direction
Expand All @@ -172,9 +174,11 @@ end
end

# FV-form flux `fhat` in y direction
for j in 1:(nnodes(dg) - 1), i in eachnode(dg), v in eachvariable(equations)
fhat2_L[v, i, j + 1] = fhat2_L[v, i, j] + weights[j] * flux_temp[v, i, j]
fhat2_R[v, i, j + 1] = fhat2_L[v, i, j + 1]
for j in 1:(nnodes(dg) - 1), i in eachnode(dg)
for v in eachvariable(equations)
fhat2_L[v, i, j + 1] = fhat2_L[v, i, j] + weights[j] * flux_temp[v, i, j]
fhat2_R[v, i, j + 1] = fhat2_L[v, i, j + 1]
end
end

return nothing
Expand Down
109 changes: 109 additions & 0 deletions src/solvers/dgsem_tree/dg_3d_subcell_limiters.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# 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
#! format: noindent

# Calculate the DG staggered volume fluxes `fhat` in subcell FV-form inside the element
# (**without non-conservative terms**).
#
# See also `flux_differencing_kernel!`.
@inline function calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, fhat3_L, fhat3_R,
u, mesh::TreeMesh{3},
have_nonconservative_terms::False, equations,
volume_flux, dg::DGSEM, element, cache)
@unpack weights, derivative_split = dg.basis
@unpack flux_temp_threaded = cache

flux_temp = flux_temp_threaded[Threads.threadid()]

# The FV-form fluxes are calculated in a recursive manner, i.e.:
# fhat_(0,1) = w_0 * FVol_0,
# fhat_(j,j+1) = fhat_(j-1,j) + w_j * FVol_j, for j=1,...,N-1,
# with the split form volume fluxes FVol_j = -2 * sum_i=0^N D_ji f*_(j,i).

# To use the symmetry of the `volume_flux`, the split form volume flux is precalculated
# like in `calc_volume_integral!` for the `VolumeIntegralFluxDifferencing`
# and saved in in `flux_temp`.

# Split form volume flux in orientation 1: x direction
flux_temp .= zero(eltype(flux_temp))

for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
u_node = get_node_vars(u, equations, dg, i, j, k, element)

# All diagonal entries of `derivative_split` are zero. Thus, we can skip
# the computation of the diagonal terms. In addition, we use the symmetry
# of the `volume_flux` to save half of the possible two-point flux
# computations.
for ii in (i + 1):nnodes(dg)
u_node_ii = get_node_vars(u, equations, dg, ii, j, k, element)
flux1 = volume_flux(u_node, u_node_ii, 1, equations)
multiply_add_to_node_vars!(flux_temp, derivative_split[i, ii], flux1,
equations, dg, i, j, k)
multiply_add_to_node_vars!(flux_temp, derivative_split[ii, i], flux1,
equations, dg, ii, j, k)
end
end

# FV-form flux `fhat` in x direction
for k in eachnode(dg), j in eachnode(dg), i in 1:(nnodes(dg) - 1)
for v in eachvariable(equations)
fhat1_L[v, i + 1, j, k] = fhat1_L[v, i, j, k] +
weights[i] * flux_temp[v, i, j, k]
fhat1_R[v, i + 1, j, k] = fhat1_L[v, i + 1, j, k]
end
end

# Split form volume flux in orientation 2: y direction
flux_temp .= zero(eltype(flux_temp))

for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
u_node = get_node_vars(u, equations, dg, i, j, k, element)
for jj in (j + 1):nnodes(dg)
u_node_jj = get_node_vars(u, equations, dg, i, jj, k, element)
flux2 = volume_flux(u_node, u_node_jj, 2, equations)
multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], flux2,
equations, dg, i, j, k)
multiply_add_to_node_vars!(flux_temp, derivative_split[jj, j], flux2,
equations, dg, i, jj, k)
end
end

# FV-form flux `fhat` in y direction
for k in eachnode(dg), j in 1:(nnodes(dg) - 1), i in eachnode(dg)
for v in eachvariable(equations)
fhat2_L[v, i, j + 1, k] = fhat2_L[v, i, j, k] +
weights[j] * flux_temp[v, i, j, k]
fhat2_R[v, i, j + 1, k] = fhat2_L[v, i, j + 1, k]
end
end

# Split form volume flux in orientation 3: z direction
flux_temp .= zero(eltype(flux_temp))

for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
u_node = get_node_vars(u, equations, dg, i, j, k, element)
for kk in (k + 1):nnodes(dg)
u_node_kk = get_node_vars(u, equations, dg, i, j, kk, element)
flux3 = volume_flux(u_node, u_node_kk, 3, equations)
multiply_add_to_node_vars!(flux_temp, derivative_split[k, kk], flux3,
equations, dg, i, j, k)
multiply_add_to_node_vars!(flux_temp, derivative_split[kk, k], flux3,
equations, dg, i, j, kk)
end
end

# FV-form flux `fhat` in z direction
for k in 1:(nnodes(dg) - 1), j in eachnode(dg), i in eachnode(dg)
for v in eachvariable(equations)
fhat3_L[v, i, j, k + 1] = fhat3_L[v, i, j, k] +
weights[k] * flux_temp[v, i, j, k]
fhat3_R[v, i, j, k + 1] = fhat3_L[v, i, j, k + 1]
end
end

return nothing
end
end # @muladd
Loading
Loading