Skip to content

Commit 691c88f

Browse files
committed
Add full 3d implementation on P4estMesh
1 parent 5f271e7 commit 691c88f

12 files changed

+2332
-17
lines changed

examples/p4est_3d_dgsem/elixir_euler_sedov_sc_subcell.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function initial_condition_sedov_blast_wave(x, t,
2525
r0 = 0.21875 # = 3.5 * smallest dx (for domain length=4 and max-ref=6)
2626
E = 1.0
2727
p0_inner = 3 * (equations.gamma - 1) * E / (4 * pi * r0^2)
28-
p0_outer = 1.0e-1 # "simpler" setup since positivity limiter for pressure is not yet supported in 3D
28+
p0_outer = 1.0e-5
2929

3030
# Calculate primitive variables
3131
rho = 1.0
@@ -44,7 +44,12 @@ volume_flux = flux_ranocha
4444
polydeg = 3
4545
basis = LobattoLegendreBasis(polydeg)
4646
limiter_idp = SubcellLimiterIDP(equations, basis;
47-
positivity_variables_cons = ["rho"])
47+
positivity_variables_cons = ["rho"],
48+
positivity_variables_nonlinear = [pressure],
49+
local_twosided_variables_cons = [],
50+
local_onesided_variables_nonlinear = [],
51+
max_iterations_newton = 40, # Default parameters are not sufficient to fulfill bounds properly.
52+
newton_tolerances = (1.0e-14, 1.0e-15))
4853
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
4954
volume_flux_dg = volume_flux,
5055
volume_flux_fv = surface_flux)
@@ -91,7 +96,7 @@ callbacks = CallbackSet(summary_callback,
9196
###############################################################################
9297
# run the simulation
9398

94-
stage_callbacks = (SubcellLimiterIDPCorrection(),)
99+
stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback())
95100

96101
sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
97102
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using OrdinaryDiffEqLowStorageRK
2+
using Trixi
3+
4+
###############################################################################
5+
# semidiscretization of the compressible Euler equations
6+
7+
equations = CompressibleEulerEquations3D(1.4)
8+
9+
initial_condition = initial_condition_convergence_test
10+
11+
boundary_condition = BoundaryConditionDirichlet(initial_condition)
12+
boundary_conditions = Dict(:Bottom => boundary_condition,
13+
:Top => boundary_condition,
14+
:Circle => boundary_condition,
15+
:Cut => boundary_condition)
16+
17+
surface_flux = flux_lax_friedrichs
18+
volume_flux = flux_ranocha
19+
polydeg = 4
20+
basis = LobattoLegendreBasis(polydeg)
21+
limiter_idp = SubcellLimiterIDP(equations, basis;
22+
positivity_variables_cons = ["rho"],
23+
positivity_variables_nonlinear = [pressure],
24+
local_twosided_variables_cons = [],
25+
local_onesided_variables_nonlinear = [])
26+
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
27+
volume_flux_dg = volume_flux,
28+
volume_flux_fv = surface_flux)
29+
solver = DGSEM(basis, surface_flux, volume_integral)
30+
31+
# Unstructured 3D half circle mesh from HOHQMesh
32+
mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/11461efbfb02c42e06aca338b3d0b645/raw/81deeb1ebc4945952c30af5bb75fe222a18d975c/abaqus_half_circle_3d.inp",
33+
joinpath(@__DIR__, "abaqus_half_circle_3d.inp"))
34+
35+
mesh = P4estMesh{3}(mesh_file, initial_refinement_level = 0)
36+
37+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
38+
source_terms = source_terms_convergence_test,
39+
boundary_conditions = boundary_conditions)
40+
41+
###############################################################################
42+
# ODE solvers, callbacks etc.
43+
44+
tspan = (0.0, 1.0)
45+
ode = semidiscretize(semi, tspan)
46+
47+
summary_callback = SummaryCallback()
48+
49+
analysis_interval = 100
50+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
51+
extra_analysis_integrals = (entropy,))
52+
53+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
54+
55+
save_solution = SaveSolutionCallback(interval = 1,
56+
save_initial_solution = true,
57+
save_final_solution = true,
58+
solution_variables = cons2prim,
59+
extra_node_variables = (:limiting_coefficient,))
60+
61+
stepsize_callback = StepsizeCallback(cfl = 0.5)
62+
63+
callbacks = CallbackSet(summary_callback,
64+
analysis_callback, alive_callback,
65+
save_solution,
66+
stepsize_callback)
67+
68+
###############################################################################
69+
# run the simulation
70+
71+
stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback())
72+
73+
sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
74+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
75+
ode_default_options()..., callback = callbacks);
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using Trixi
2+
3+
###############################################################################
4+
# semidiscretization of the compressible ideal GLM-MHD equations
5+
6+
equations = IdealGlmMhdEquations3D(1.4)
7+
8+
"""
9+
initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations3D)
10+
11+
Weak magnetic blast wave setup taken from Section 6.1 of the paper:
12+
- A. M. Rueda-Ramírez, S. Hennemann, F. J. Hindenlang, A. R. Winters, G. J. Gassner (2021)
13+
An entropy stable nodal discontinuous Galerkin method for the resistive MHD
14+
equations. Part II: Subcell finite volume shock capturing
15+
[doi: 10.1016/j.jcp.2021.110580](https://doi.org/10.1016/j.jcp.2021.110580)
16+
"""
17+
function initial_condition_blast_wave(x, t, equations::IdealGlmMhdEquations3D)
18+
# Center of the blast wave is selected for the domain [0, 3]^3
19+
inicenter = (1.5, 1.5, 1.5)
20+
x_norm = x[1] - inicenter[1]
21+
y_norm = x[2] - inicenter[2]
22+
z_norm = x[3] - inicenter[3]
23+
r = sqrt(x_norm^2 + y_norm^2 + z_norm^2)
24+
25+
delta_0 = 0.1
26+
r_0 = 0.3
27+
lambda = exp(5.0 / delta_0 * (r - r_0))
28+
29+
prim_inner = SVector(1.2, 0.1, 0.0, 0.1, 0.9, 1.0, 1.0, 1.0, 0.0)
30+
prim_outer = SVector(1.2, 0.2, -0.4, 0.2, 0.3, 1.0, 1.0, 1.0, 0.0)
31+
prim_vars = (prim_inner + lambda * prim_outer) / (1.0 + lambda)
32+
33+
return prim2cons(prim_vars, equations)
34+
end
35+
initial_condition = initial_condition_blast_wave
36+
37+
surface_flux = (flux_lax_friedrichs, flux_nonconservative_powell_local_symmetric)
38+
volume_flux = (flux_hindenlang_gassner, flux_nonconservative_powell_local_symmetric)
39+
polydeg = 3
40+
basis = LobattoLegendreBasis(polydeg)
41+
limiter_idp = SubcellLimiterIDP(equations, basis;
42+
positivity_variables_cons = ["rho"],
43+
positivity_variables_nonlinear = [pressure])
44+
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
45+
volume_flux_dg = volume_flux,
46+
volume_flux_fv = surface_flux)
47+
solver = DGSEM(basis, surface_flux, volume_integral)
48+
49+
# Mapping as described in https://arxiv.org/abs/2012.12040 but with slightly less warping.
50+
# The mapping will be interpolated at tree level, and then refined without changing
51+
# the geometry interpolant.
52+
function mapping(xi_, eta_, zeta_)
53+
# Transform input variables between -1 and 1 onto [0,3]
54+
xi = 1.5 * xi_ + 1.5
55+
eta = 1.5 * eta_ + 1.5
56+
zeta = 1.5 * zeta_ + 1.5
57+
58+
y = eta +
59+
3 / 11 * (cos(1.5 * pi * (2 * xi - 3) / 3) *
60+
cos(0.5 * pi * (2 * eta - 3) / 3) *
61+
cos(0.5 * pi * (2 * zeta - 3) / 3))
62+
63+
x = xi +
64+
3 / 11 * (cos(0.5 * pi * (2 * xi - 3) / 3) *
65+
cos(2 * pi * (2 * y - 3) / 3) *
66+
cos(0.5 * pi * (2 * zeta - 3) / 3))
67+
68+
z = zeta +
69+
3 / 11 * (cos(0.5 * pi * (2 * x - 3) / 3) *
70+
cos(pi * (2 * y - 3) / 3) *
71+
cos(0.5 * pi * (2 * zeta - 3) / 3))
72+
73+
return SVector(x, y, z)
74+
end
75+
76+
trees_per_dimension = (2, 2, 2)
77+
mesh = P4estMesh(trees_per_dimension,
78+
polydeg = 3,
79+
mapping = mapping,
80+
# coordinates_min = (0.0, 0.0, 0.0),
81+
# coordinates_max = (3.0, 3.0, 3.0),
82+
initial_refinement_level = 2,
83+
periodicity = true)
84+
85+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)
86+
87+
###############################################################################
88+
# ODE solvers, callbacks etc.
89+
90+
tspan = (0.0, 0.5)
91+
ode = semidiscretize(semi, tspan)
92+
93+
summary_callback = SummaryCallback()
94+
95+
analysis_interval = 100
96+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)
97+
98+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
99+
100+
save_solution = SaveSolutionCallback(interval = 100,
101+
save_initial_solution = true,
102+
save_final_solution = true,
103+
solution_variables = cons2prim,
104+
extra_node_variables = (:limiting_coefficient,))
105+
106+
cfl = 0.9
107+
stepsize_callback = StepsizeCallback(cfl = cfl)
108+
109+
glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl)
110+
111+
callbacks = CallbackSet(summary_callback,
112+
analysis_callback,
113+
alive_callback,
114+
save_solution,
115+
stepsize_callback,
116+
glm_speed_callback)
117+
118+
###############################################################################
119+
# run the simulation
120+
stage_callbacks = (SubcellLimiterIDPCorrection(), BoundsCheckCallback())
121+
122+
sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
123+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
124+
ode_default_options()..., callback = callbacks);

src/callbacks_stage/subcell_bounds_check.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,5 @@ end
214214
end
215215

216216
include("subcell_bounds_check_2d.jl")
217+
include("subcell_bounds_check_3d.jl")
217218
end # @muladd

src/callbacks_stage/subcell_bounds_check_2d.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@muladd begin
66
#! format: noindent
77

8-
@inline function check_bounds(u, equations::AbstractEquations{2}, # only works for 2D
8+
@inline function check_bounds(u, equations::AbstractEquations{2},
99
solver, cache, limiter::SubcellLimiterIDP)
1010
(; local_twosided, positivity, local_onesided) = solver.volume_integral.limiter
1111
(; variable_bounds) = limiter.cache.subcell_limiter_coefficients
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2+
# Since these FMAs can increase the performance of many numerical algorithms,
3+
# we need to opt-in explicitly.
4+
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5+
@muladd begin
6+
#! format: noindent
7+
8+
@inline function check_bounds(u, equations::AbstractEquations{3},
9+
solver, cache, limiter::SubcellLimiterIDP)
10+
(; local_twosided, positivity, local_onesided) = solver.volume_integral.limiter
11+
(; variable_bounds) = limiter.cache.subcell_limiter_coefficients
12+
(; idp_bounds_delta_local, idp_bounds_delta_global) = limiter.cache
13+
14+
# Note: In order to get the maximum deviation from the target bounds, this bounds check
15+
# requires a reduction in every RK stage and for every enabled limiting option. To make
16+
# this Thread-parallel we are using Polyester.jl's (at least v0.7.10) `@batch reduction`
17+
# functionality.
18+
# Although `@threaded` and `@batch` are currently used equivalently in Trixi.jl, we use
19+
# `@batch` here to allow a possible redefinition of `@threaded` without creating errors here.
20+
# See also https://github.com/trixi-framework/Trixi.jl/pull/1888#discussion_r1537785293.
21+
22+
if local_twosided
23+
for v in limiter.local_twosided_variables_cons
24+
v_string = string(v)
25+
key_min = Symbol(v_string, "_min")
26+
key_max = Symbol(v_string, "_max")
27+
deviation_min = idp_bounds_delta_local[key_min]
28+
deviation_max = idp_bounds_delta_local[key_max]
29+
@batch reduction=((max, deviation_min), (max, deviation_max)) for element in eachelement(solver,
30+
cache)
31+
for k in eachnode(solver), j in eachnode(solver), i in eachnode(solver)
32+
var = u[v, i, j, k, element]
33+
# Note: We always save the absolute deviations >= 0 and therefore use the
34+
# `max` operator for the lower and upper bound. The different directions of
35+
# upper and lower bound are considered in their calculations with a
36+
# different sign.
37+
deviation_min = max(deviation_min,
38+
variable_bounds[key_min][i, j, k, element] -
39+
var)
40+
deviation_max = max(deviation_max,
41+
var -
42+
variable_bounds[key_max][i, j, k, element])
43+
end
44+
end
45+
idp_bounds_delta_local[key_min] = deviation_min
46+
idp_bounds_delta_local[key_max] = deviation_max
47+
end
48+
end
49+
if local_onesided
50+
for (variable, min_or_max) in limiter.local_onesided_variables_nonlinear
51+
key = Symbol(string(variable), "_", string(min_or_max))
52+
deviation = idp_bounds_delta_local[key]
53+
sign_ = min_or_max(1.0, -1.0)
54+
@batch reduction=(max, deviation) for element in eachelement(solver, cache)
55+
for k in eachnode(solver), j in eachnode(solver), i in eachnode(solver)
56+
v = variable(get_node_vars(u, equations, solver, i, j, k, element),
57+
equations)
58+
# Note: We always save the absolute deviations >= 0 and therefore use the
59+
# `max` operator for lower and upper bounds. The different directions of
60+
# upper and lower bounds are considered with `sign_`.
61+
deviation = max(deviation,
62+
sign_ *
63+
(v - variable_bounds[key][i, j, k, element]))
64+
end
65+
end
66+
idp_bounds_delta_local[key] = deviation
67+
end
68+
end
69+
if positivity
70+
for v in limiter.positivity_variables_cons
71+
if v in limiter.local_twosided_variables_cons
72+
continue
73+
end
74+
key = Symbol(string(v), "_min")
75+
deviation = idp_bounds_delta_local[key]
76+
@batch reduction=(max, deviation) for element in eachelement(solver, cache)
77+
for k in eachnode(solver), j in eachnode(solver), i in eachnode(solver)
78+
var = u[v, i, j, k, element]
79+
deviation = max(deviation,
80+
variable_bounds[key][i, j, k, element] - var)
81+
end
82+
end
83+
idp_bounds_delta_local[key] = deviation
84+
end
85+
for variable in limiter.positivity_variables_nonlinear
86+
key = Symbol(string(variable), "_min")
87+
deviation = idp_bounds_delta_local[key]
88+
@batch reduction=(max, deviation) for element in eachelement(solver, cache)
89+
for k in eachnode(solver), j in eachnode(solver), i in eachnode(solver)
90+
var = variable(get_node_vars(u, equations, solver, i, j, k,
91+
element),
92+
equations)
93+
deviation = max(deviation,
94+
variable_bounds[key][i, j, k, element] - var)
95+
end
96+
end
97+
idp_bounds_delta_local[key] = deviation
98+
end
99+
end
100+
101+
for (key, _) in idp_bounds_delta_local
102+
# Update global maximum deviations
103+
idp_bounds_delta_global[key] = max(idp_bounds_delta_global[key],
104+
idp_bounds_delta_local[key])
105+
end
106+
107+
return nothing
108+
end
109+
end # @muladd

0 commit comments

Comments
 (0)