Skip to content

Commit cb3deba

Browse files
Fix convergence problems for flux_nonconservative_ersing_etal_local_jump (#131)
* use local normal direction for flux_ersing_local_jump * add elixirs to test convergence and EC on curvilinear meshes * apply formatter * fix testing * format examples * make ec test case reproducible * add note for flux_nonconservative_ersing_local_jump * make use of local normal direction explicit --------- Co-authored-by: Andrés Rueda-Ramírez <aruedara@uni-koeln.de>
1 parent 0dfa47b commit cb3deba

File tree

5 files changed

+301
-6
lines changed

5 files changed

+301
-6
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using OrdinaryDiffEqSSPRK, OrdinaryDiffEqLowStorageRK
2+
using Trixi
3+
using TrixiShallowWater
4+
using Symbolics
5+
6+
###############################################################################
7+
# Semidiscretization of the multilayer shallow water equations with a single layer to test
8+
# convergence. The initial condition and source term are created using the
9+
# method of manufactured solutions (MMS) with the help of Symbolics.jl.
10+
11+
equations = ShallowWaterMultiLayerEquations2D(gravity = 1.1, rhos = (1.0))
12+
13+
### Create manufactured solution for method of manufactured solutions (MMS)
14+
15+
# Symbolic Variables
16+
@variables x_sym[1:2], t_sym, g
17+
18+
# Define Differentials
19+
Dt, Dx, Dy = Differential(t_sym), Differential(x_sym[1]), Differential(x_sym[2])
20+
21+
## Initial condition
22+
###############################################################################
23+
# Primitive Variables
24+
ω = pi * 1.0
25+
H = 4.0 + 0.2 * cos* x_sym[1] + t_sym) + 0.2 * cos* x_sym[2] + t_sym)
26+
v1 = 0.5
27+
v2 = 0.5
28+
b = 1.0 + 0.2 * cos* x_sym[1]) + 0.2 * cos* x_sym[2])
29+
h = H - b
30+
31+
init = [H, v1, v2, b]
32+
33+
## PDE
34+
###############################################################################
35+
eqs = [
36+
Dt(h) + Dx(h * v1) + Dy(h * v2),
37+
Dt(h * v1) + Dx(h * v1^2 + 0.5 * g * h^2) + Dy(h * v1 * v2) + g * h * Dx(b),
38+
Dt(h * v2) + Dx(h * v1 * v2) + Dy(h * v2^2 + 0.5 * g * h^2) + g * h * Dy(b),
39+
0
40+
]
41+
42+
## Create the functions for the manufactured solution
43+
########################################################################################
44+
# Expand derivatives
45+
du_exprs = expand_derivatives.(eqs)
46+
47+
# Build functions
48+
du_funcs = build_function.(du_exprs, Ref(x_sym), t_sym, g, expression = Val(false))
49+
50+
init_funcs = build_function.(init, Ref(x_sym), t_sym, expression = Val(false))
51+
52+
function initial_condition_convergence_mms(x,
53+
t,
54+
equations::ShallowWaterMultiLayerEquations2D)
55+
prim = SVector{4, Float64}([f(x, t) for f in init_funcs]...)
56+
return prim2cons(prim, equations)
57+
end
58+
59+
function source_terms_convergence_mms(u,
60+
x,
61+
t,
62+
equations::ShallowWaterMultiLayerEquations2D)
63+
g = equations.gravity
64+
return SVector{4, Float64}([f(x, t, g) for f in du_funcs]...)
65+
end
66+
67+
initial_condition = initial_condition_convergence_mms
68+
69+
###############################################################################
70+
# Get the DG approximation space
71+
72+
polydeg = 3
73+
volume_flux = (flux_ersing_etal, flux_nonconservative_ersing_etal_local_jump)
74+
surface_flux = (flux_ersing_etal, flux_nonconservative_ersing_etal_local_jump)
75+
76+
basis = LobattoLegendreBasis(polydeg)
77+
limiter_idp = SubcellLimiterIDP(equations, basis;)
78+
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
79+
volume_flux_dg = volume_flux,
80+
volume_flux_fv = surface_flux)
81+
solver = DGSEM(basis, surface_flux, volume_integral)
82+
83+
###############################################################################
84+
# Get the P4estMesh and setup a periodic mesh on the domain [-1,1]^2 with an affine type mapping to
85+
# obtain a warped curvilinear mesh.
86+
function mapping_twist(xi, eta)
87+
y = eta + 0.1 * sin(pi * xi) * cos(0.5 * pi * eta)
88+
x = xi + 0.1 * sin(pi * eta) * cos(0.5 * pi * xi)
89+
return SVector(x, y)
90+
end
91+
92+
# Create warped P4estMesh with 8 x 8 elements
93+
trees_per_dimension = (2, 2)
94+
mesh = P4estMesh(trees_per_dimension, polydeg = 3,
95+
initial_refinement_level = 2,
96+
periodicity = true,
97+
mapping = mapping_twist)
98+
99+
# create the semi discretization object
100+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
101+
source_terms = source_terms_convergence_mms,
102+
boundary_conditions = boundary_condition_periodic)
103+
104+
###############################################################################
105+
# ODE solvers, callbacks etc.
106+
107+
tspan = (0.0, 0.1)
108+
ode = semidiscretize(semi, tspan)
109+
110+
summary_callback = SummaryCallback()
111+
112+
analysis_interval = 500
113+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)
114+
115+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
116+
117+
save_solution = SaveSolutionCallback(interval = 500,
118+
save_initial_solution = true,
119+
save_final_solution = true)
120+
121+
stepsize_callback = StepsizeCallback(cfl = 0.7)
122+
123+
callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution,
124+
stepsize_callback)
125+
126+
###############################################################################
127+
# run the simulation
128+
129+
stage_callbacks = (SubcellLimiterIDPCorrection(),)
130+
131+
sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
132+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
133+
ode_default_options()...,
134+
callback = callbacks, adaptive = false);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using OrdinaryDiffEqSSPRK, OrdinaryDiffEqLowStorageRK
2+
using Trixi
3+
using TrixiShallowWater
4+
5+
###############################################################################
6+
# Semidiscretization of the multilayer shallow water equations with a single layer and a bottom
7+
# topography function for a blast wave test with discontinuous initial conditions to test entropy
8+
# conservation with the subcell limiting volume integral on a curvilinear mesh.
9+
10+
equations = ShallowWaterMultiLayerEquations2D(gravity = 9.81, rhos = (1.0))
11+
12+
function initial_condition_weak_blast_wave(x, t,
13+
equations::ShallowWaterMultiLayerEquations2D)
14+
# Set up polar coordinates
15+
RealT = eltype(x)
16+
inicenter = SVector(convert(RealT, 0.0), convert(RealT, 0.0))
17+
x_norm = x[1] - inicenter[1]
18+
y_norm = x[2] - inicenter[2]
19+
r = sqrt(x_norm^2 + y_norm^2)
20+
phi = atan(y_norm, x_norm)
21+
sin_phi, cos_phi = sincos(phi)
22+
23+
# Calculate primitive variables
24+
H = r > 0.2f0 ? 3.8f0 : 4.0f0
25+
v1 = r > 0.2f0 ? zero(RealT) : convert(RealT, 0.1882) * cos_phi
26+
v2 = r > 0.2f0 ? zero(RealT) : convert(RealT, 0.1882) * sin_phi
27+
v1 = 0.0
28+
v2 = 0.0
29+
30+
# Setup a continuous bottom topography
31+
r = 0.4
32+
b = (((x[1])^2 + (x[2])^2) < r^2 ?
33+
0.5 * (cos(1 / r * pi * sqrt((x[1])^2 + (x[2])^2)) + 1) : 0.0)
34+
35+
return prim2cons(SVector(H, v1, v2, b), equations)
36+
end
37+
38+
initial_condition = initial_condition_weak_blast_wave
39+
40+
###############################################################################
41+
# Get the DG approximation space
42+
43+
polydeg = 3
44+
volume_flux = (flux_ersing_etal, flux_nonconservative_ersing_etal_local_jump)
45+
surface_flux = (flux_ersing_etal, flux_nonconservative_ersing_etal_local_jump)
46+
47+
basis = LobattoLegendreBasis(polydeg)
48+
# For reproducibility set the limiting coefficients to pure DG,
49+
# see https://github.com/trixi-framework/Trixi.jl/pull/2007
50+
limiter_idp = SubcellLimiterIDP(equations, basis;)
51+
volume_integral = VolumeIntegralSubcellLimiting(limiter_idp;
52+
volume_flux_dg = volume_flux,
53+
volume_flux_fv = surface_flux)
54+
solver = DGSEM(basis, surface_flux, volume_integral)
55+
56+
###############################################################################
57+
# Get the P4estMesh and setup a periodic mesh on the domain [-1,1]^2 with an affine type mapping to
58+
# obtain a warped curvilinear mesh.
59+
function mapping_twist(xi, eta)
60+
y = eta + 0.1 * sin(pi * xi) * cos(0.5 * pi * eta)
61+
x = xi + 0.1 * sin(pi * eta) * cos(0.5 * pi * xi)
62+
return SVector(x, y)
63+
end
64+
65+
# Create P4estMesh with 8 x 8 elements
66+
trees_per_dimension = (2, 2)
67+
mesh = P4estMesh(trees_per_dimension, polydeg = 2,
68+
initial_refinement_level = 2,
69+
periodicity = true,
70+
mapping = mapping_twist)
71+
72+
# Create the semi discretization object
73+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
74+
boundary_conditions = boundary_condition_periodic)
75+
76+
###############################################################################
77+
# ODE solver
78+
79+
tspan = (0.0, 0.2)
80+
ode = semidiscretize(semi, tspan)
81+
82+
summary_callback = SummaryCallback()
83+
84+
analysis_interval = 100
85+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
86+
analysis_polydeg = polydeg,
87+
extra_analysis_errors = (:conservation_error,))
88+
89+
stepsize_callback = StepsizeCallback(cfl = 0.5)
90+
91+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
92+
93+
save_solution = SaveSolutionCallback(dt = 0.1,
94+
save_initial_solution = true,
95+
save_final_solution = true,
96+
extra_node_variables = (:limiting_coefficient,))
97+
98+
callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution,
99+
stepsize_callback)
100+
101+
###############################################################################
102+
103+
# Setup the stage callbacks
104+
stage_callbacks = (SubcellLimiterIDPCorrection(),)
105+
106+
# run the simulation
107+
sol = Trixi.solve(ode, Trixi.SimpleSSPRK33(stage_callbacks = stage_callbacks);
108+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
109+
ode_default_options()...,
110+
callback = callbacks, adaptive = false);

examples/tree_2d_dgsem/elixir_shallowwater_ec.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ ode = semidiscretize(semi, tspan)
4444
###############################################################################
4545
# Workaround to set a discontinuous bottom topography and initial condition for debugging and testing.
4646

47-
# alternative version of the initial conditinon used to setup a truly discontinuous
47+
# alternative version of the initial condition used to setup a truly discontinuous
4848
# bottom topography function and initial condition for this academic testcase of entropy conservation.
4949
# The errors from the analysis callback are not important but `∑∂S/∂U ⋅ Uₜ` should be around machine roundoff
5050
# In contrast to the usual signature of initial conditions, this one get passed the

src/equations/shallow_water_multilayer_2d.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,12 @@ or jump portion of the non-conservative flux based on the type of the
624624
nonconservative_type argument, employing multiple dispatch. They are used to
625625
compute the subcell fluxes in [`Trixi.VolumeIntegralSubcellLimiting`](@extref).
626626
627+
!!! note
628+
While `flux_nonconservative_ersing_etal_local_jump` and [`flux_nonconservative_ersing_etal`](@ref)
629+
are equivalent at interfaces, the volume formulation for [`Trixi.VolumeIntegralSubcellLimiting`](@extref)
630+
differs as `flux_nonconservative_ersing_etal_local_jump` applies the local normal direction
631+
instead of the averaged one.
632+
627633
## References
628634
- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts
629635
Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf.
@@ -653,7 +659,7 @@ end
653659
nonconservative_type::Trixi.NonConservativeLocal,
654660
nonconservative_term::Integer)
655661
flux_nonconservative_ersing_local_jump(u_ll, u_rr,
656-
normal_direction::AbstractVector,
662+
normal_direction_ll::AbstractVector,
657663
equations::ShallowWaterMultiLayerEquations2D,
658664
nonconservative_type::Trixi.NonConservativeLocal,
659665
nonconservative_term::Integer)
@@ -695,7 +701,7 @@ Local part of the nonconservative term needed for the calculation of the non-con
695701
end
696702

697703
@inline function flux_nonconservative_ersing_etal_local_jump(u_ll,
698-
normal_direction::AbstractVector,
704+
normal_direction_ll::AbstractVector,
699705
equations::ShallowWaterMultiLayerEquations2D,
700706
nonconservative_type::Trixi.NonConservativeLocal,
701707
nonconservative_term::Integer)
@@ -714,7 +720,9 @@ end
714720
f_h = zero(real(equations))
715721
f_hv = g * h_ll[i]
716722

717-
setlayer!(f, f_h, f_hv, f_hv, i, equations)
723+
setlayer!(f, f_h, f_hv * normal_direction_ll[1], f_hv * normal_direction_ll[2],
724+
i,
725+
equations)
718726
end
719727

720728
return SVector(f)
@@ -812,8 +820,8 @@ end
812820
f_hv += h_jump[j]
813821
end
814822
end
815-
setlayer!(f, f_h, f_hv * normal_direction[1],
816-
f_hv * normal_direction[2], i, equations)
823+
setlayer!(f, f_h, f_hv,
824+
f_hv, i, equations)
817825
end
818826

819827
return SVector(f)

test/test_p4est_2d.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,25 @@ end # SWE
165165
@test_allocations(Trixi.rhs!, semi, sol, 15000)
166166
end
167167

168+
@trixi_testset "elixir_shallowwater_multilayer_convergence_sc_subcell_curved.jl" begin
169+
@test_trixi_include(joinpath(EXAMPLES_DIR,
170+
"elixir_shallowwater_multilayer_convergence_sc_subcell_curved.jl"),
171+
l2=[
172+
0.00013275624153302434,
173+
0.0001586600356395913,
174+
0.000158660035639501,
175+
2.9583315272612922e-5
176+
],
177+
linf=[
178+
0.0007544272991792944,
179+
0.0007250877164874936,
180+
0.00072508771648927,
181+
9.31948456051046e-5
182+
])
183+
# Allocation testing is disabled as the symbolic source term computation is known to cause
184+
# allocations.
185+
end
186+
168187
@trixi_testset "elixir_shallowwater_multilayer_well_balanced_wet_dry_nonconforming.jl" begin
169188
@test_trixi_include(joinpath(EXAMPLES_DIR,
170189
"elixir_shallowwater_multilayer_well_balanced_wet_dry_nonconforming.jl"),
@@ -319,6 +338,30 @@ end # SWE
319338
# Corresponding issue: https://github.com/trixi-framework/Trixi.jl/issues/1877
320339
@test_allocations(Trixi.rhs!, semi, sol, 15000)
321340
end
341+
342+
@trixi_testset "elixir_shallowwater_multilayer_ec_sc_subcell.jl" begin
343+
@test_trixi_include(joinpath(EXAMPLES_DIR,
344+
"elixir_shallowwater_multilayer_ec_sc_subcell.jl"),
345+
l2=[
346+
0.04338581073333642,
347+
0.12068863355590975,
348+
0.12068863355590971,
349+
7.906244739074657e-18
350+
],
351+
linf=[
352+
0.2550462084344076,
353+
0.42004261172048024,
354+
0.4200426117204863,
355+
1.1102230246251565e-16
356+
])
357+
# Ensure that we do not have excessive memory allocations
358+
# (e.g., from type instabilities)
359+
# Larger values for allowed allocations due to usage of custom
360+
# integrator which are not *recorded* for the methods from
361+
# OrdinaryDiffEq.jl
362+
# Corresponding issue: https://github.com/trixi-framework/Trixi.jl/issues/1877
363+
@test_allocations(Trixi.rhs!, semi, sol, 15000)
364+
end
322365
end # MLSWE
323366
end # P4estMesh2D
324367

0 commit comments

Comments
 (0)