Skip to content

Commit ae36086

Browse files
Well-balanced mortars for ShallowWaterMultiLayerEquations2D (#102)
* initial commit. Well-balanced working on fully wet mortars * forgot to add new elixir * comment out mortar desingularization to experiment * cleanup new prolong2mortars function * cleanup new well-balancedness test elixir * better elixir file name * cleanup and add AMR pertubation test file * add Monai flood with AMR elixir * add tests * fix incorrect file name in new test * add TrixiBottomTopography to testing Project.toml * apply formatter * add three mound with AMR elixir * update file name * formatter * add three mound elixir to testing * better comments in new elixirs * adjust amr controller values in three mound test case * update three mound test values * fix type stability dispatch on spline functions in Monai elixir * adjust the spline constructors in the monai tutorial as well * adjust comments * Apply suggestions from code review Co-authored-by: Patrick Ersing <114223904+patrickersing@users.noreply.github.com> * adjust Monai elixir and do not allow 0 water heights on the mortars * keep the save solution callback in new WB elixir * fix merge conflicts in Monai elixir * adjust AMR parameters in three mound test case * adjust comments in new mortar routine * apply formatter * adjust test values * update header comments in the four new elixirs to summarize the current state of affairs * apply formatter to examples * adjust sensitive perturbation test values * apply formatter * apply formatter * slightly soften abs tol for Monai test to 1e-12 * further soften tolenace for Monai --------- Co-authored-by: Patrick Ersing <114223904+patrickersing@users.noreply.github.com>
1 parent 891417c commit ae36086

11 files changed

+1172
-46
lines changed

docs/src/tutorials/elixir_shallowwater_monai_tsunami.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ generate_mesh(monai);
156156
# and specify the gravitational acceleration to `gravity = 9.812`
157157
# as well as a background water height `H0 = 0.0`.
158158
# In contrast to the [`Trixi.ShallowWaterEquations2D`](@extref Trixi.ShallowWaterEquations2D) type,
159-
# this equation type allows contains additional parameters and methods needed to handle wetting and drying.
159+
# this equation type contains additional parameters and methods needed to handle wetting and drying.
160160
equations = ShallowWaterEquationsWetDry2D(gravity = 9.81, H0 = 0.0)
161161

162162
# Next, we construct an approximation to the bathymetry with TrixiBottomTopography.jl using
@@ -169,8 +169,10 @@ spline_bathymetry_file = Trixi.download("https://gist.githubusercontent.com/andr
169169

170170
# Create a bicubic B-spline interpolation of the bathymetry data, then create a function
171171
# to evaluate the resulting spline at a given point $(x,y)$.
172-
bath_spline_struct = BicubicBSpline(spline_bathymetry_file, end_condition = "not-a-knot")
173-
bathymetry(x, y) = spline_interpolation(bath_spline_struct, x, y);
172+
# The type of this struct is fixed as `BicubicBSpline`.
173+
const bath_spline_struct = BicubicBSpline(spline_bathymetry_file,
174+
end_condition = "not-a-knot")
175+
bathymetry(x::Float64, y::Float64) = spline_interpolation(bath_spline_struct, x, y);
174176

175177
# We then create a function to supply the initial condition for the simulation.
176178
@inline function initial_condition_monai_tsunami(x, t,
@@ -211,8 +213,9 @@ wavemaker_bc_file = Trixi.download("https://gist.githubusercontent.com/andrewwin
211213

212214
# Similar to the bathymetry approximation, we construct a cubic B-spline interpolation
213215
# of the data, then create a function to evaluate the resulting spline at a given $t$ value.
214-
h_spline_struct = CubicBSpline(wavemaker_bc_file; end_condition = "not-a-knot")
215-
H_from_wave_maker(t) = spline_interpolation(h_spline_struct, t);
216+
# The type of this struct is fixed as `CubicBSpline`.
217+
const h_spline_struct = CubicBSpline(wavemaker_bc_file; end_condition = "not-a-knot")
218+
H_from_wave_maker(t::Float64) = spline_interpolation(h_spline_struct, t);
216219

217220
# Now we are equipped to define the specialized boundary condition for the incident
218221
# wave maker.
@@ -264,7 +267,7 @@ boundary_condition = Dict(:Bottom => boundary_condition_slip_wall,
264267
h, hv_1, hv_2, _ = u
265268

266269
n = 0.001 # friction coefficient
267-
h = (h^2 + max(h^2, 1e-8)) / (2.0 * h) # desingularization procedure
270+
h = (h^2 + max(h^2, 1e-8)) / (2 * h) # desingularization procedure
268271

269272
## Compute the common friction term
270273
Sf = -equations.gravity * n^2 * h^(-7 / 3) * sqrt(hv_1^2 + hv_2^2)
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
2+
using OrdinaryDiffEqSSPRK, OrdinaryDiffEqLowStorageRK
3+
using Trixi
4+
using TrixiShallowWater
5+
using TrixiBottomTopography
6+
7+
# See the tutorial
8+
# https://trixi-framework.github.io/TrixiShallowWater.jl/stable/tutorials/elixir_shallowwater_monai_tsunami/
9+
# for a thorough explanation of this problem setup.
10+
#
11+
# This elixir allows for experimentation with AMR with this complex test case.
12+
# In the current state, AMR on wet/dry fronts remains sensitive to the limiting of the water height,
13+
# desingularization of the velocities, and the design of the AMR indicator.
14+
# Further, there remains an appreciable loss of conservation, with conservation errors
15+
# of ≈1e-5 in the water height for this test case as the flow evolves.
16+
# More investigation is needed to identify exactly why each aspect of this strange behavior occurs.
17+
# For instance, the conservation loss may be related to the choice of the CFL that guarantees
18+
# a positive water height as well as a positive element-wise mean necessary in the limiting.
19+
20+
###############################################################################
21+
# Semidiscretization of the multilayer shallow water equations with one layer
22+
# to fallback to be the standard shallow water equations
23+
24+
equations = ShallowWaterMultiLayerEquations2D(gravity = 9.81, H0 = 0.0,
25+
rhos = 1.0)
26+
27+
# Get the precision type for type stable dispatch on the helper spline functions
28+
RealT = typeof(equations.gravity)
29+
30+
# Create a bicubic B-spline interpolation of the bathymetry data, then create a function
31+
# to evaluate the resulting spline at a given point $(x,y)$.
32+
spline_bathymetry_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/21255c980c4eda5294f91e8dfe6c7e33/raw/1afb73928892774dc3a902e0c46ffd882ef03ee3/monai_bathymetry_data.txt",
33+
joinpath(@__DIR__, "monai_bathymetry_data.txt"));
34+
35+
# B-spline interpolation of the underlying data.
36+
# The type of this struct is fixed as `BicubicBSpline`.
37+
const bath_spline_struct = BicubicBSpline(spline_bathymetry_file,
38+
end_condition = "not-a-knot")
39+
bathymetry(x::RealT, y::RealT) = spline_interpolation(bath_spline_struct, x, y)
40+
41+
# Initial condition is a constant background state
42+
function initial_condition_monai_tsunami(x, t, equations::ShallowWaterMultiLayerEquations2D)
43+
# Set the background water height
44+
H = equations.H0
45+
46+
# Initially water is at rest
47+
v1 = zero(H)
48+
v2 = zero(H)
49+
50+
# Bottom topography values are computed from the bicubic spline created above
51+
x1, x2 = x
52+
b = bathymetry(x1, x2)
53+
54+
# It is mandatory to shift the water level at dry areas to make sure the water height h
55+
# stays positive. The system would not be stable for h set to a hard 0 due to division by h in
56+
# the computation of velocity, e.g., (h v) / h. Therefore, a small dry state threshold
57+
# with a default value of 5*eps() ≈ 1e-15 in double precision, is set in the constructor above
58+
# for the ShallowWaterMultiLayerEquations2D and added to the initial condition if h = 0.
59+
# This default value can be changed within the constructor call depending on the simulation setup.
60+
H = max(H, b + equations.threshold_limiter)
61+
62+
# Return the conservative variables
63+
return prim2cons(SVector(H, v1, v2, b), equations)
64+
end
65+
66+
initial_condition = initial_condition_monai_tsunami
67+
68+
# Tsunami test case uses a specialized wave maker type of boundary condition.
69+
# It is used to model an incident wave that approaches from off-shore
70+
# with a water depth of $h = 13.535\,\text{cm}$. To create the incident wave information
71+
# that is valid over the time interval $t \in [0\,s, 22.5\,s]$.
72+
73+
# We download the incident wave data that has been preprocessed to be in the format
74+
# required by TrixiBottomTopography.
75+
water_height_data = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/5b11f5f175bddb326d11d8e28398127e/raw/64980e0e4526e0fcd49589b34ee5458b9a1cebff/monai_wavemaker_bc.txt",
76+
joinpath(@__DIR__, "monai_wavemaker_bc.txt"));
77+
78+
# Similar to the bathymetry approximation, we construct a cubic B-spline interpolation
79+
# of the data, then create a function to evaluate the resulting spline at a given $t$ value.
80+
# The type of this struct is fixed as `CubicBSpline`.
81+
const h_spline_struct = CubicBSpline(water_height_data; end_condition = "not-a-knot")
82+
H_from_wave_maker(t::RealT) = spline_interpolation(h_spline_struct, t)
83+
84+
# Now we can define the specialized boundary condition for the incident wave maker.
85+
@inline function boundary_condition_wave_maker(u_inner, normal_direction::AbstractVector,
86+
x, t, surface_flux_functions,
87+
equations::ShallowWaterMultiLayerEquations2D)
88+
surface_flux_function, nonconservative_flux_function = surface_flux_functions
89+
90+
# Compute the water height from the wave maker input file data
91+
# and then clip to avoid negative water heights and division by zero
92+
h_ext = max(equations.threshold_limiter, H_from_wave_maker(t) - u_inner[4])
93+
94+
# Compute the incoming velocity as in Eq. (10) of the paper
95+
# - S. Vater, N. Beisiegel, and J. Behrens (2019)
96+
# A limiter-based well-balanced discontinuous Galerkin method for shallow-water flows
97+
# with wetting and drying: Triangular grids
98+
# [DOI: 10.1002/fld.4762](https://doi.org/10.1002/fld.4762)
99+
h0 = 0.13535 # reference incident water height converted to meters
100+
v1_ext = 2 * (sqrt(equations.gravity * h_ext) - sqrt(equations.gravity * h0))
101+
102+
# Create the external solution state in the conservative variables
103+
u_outer = SVector(h_ext, h_ext * v1_ext, zero(eltype(x)), u_inner[4])
104+
105+
# Calculate the boundary flux and nonconservative contributions
106+
flux = surface_flux_function(u_inner, u_outer, normal_direction, equations)
107+
108+
noncons_flux = nonconservative_flux_function(u_inner, u_outer, normal_direction,
109+
equations)
110+
111+
return flux, noncons_flux
112+
end
113+
114+
boundary_condition = Dict(:Bottom => boundary_condition_slip_wall,
115+
:Top => boundary_condition_slip_wall,
116+
:Right => boundary_condition_slip_wall,
117+
:Left => boundary_condition_wave_maker)
118+
119+
# Manning friction source term
120+
@inline function source_terms_manning_friction(u, x, t,
121+
equations::ShallowWaterMultiLayerEquations2D)
122+
# Grab the conservative variables
123+
h, hv_1, hv_2, _ = u
124+
125+
# Desingularization
126+
h = (h^2 + max(h^2, 1e-8)) / (2 * h)
127+
128+
# friction coefficient
129+
n = 0.001
130+
131+
# Compute the common friction term
132+
Sf = -equations.gravity * n^2 * h^(-7 / 3) * sqrt(hv_1^2 + hv_2^2)
133+
134+
return SVector(zero(h),
135+
Sf * hv_1,
136+
Sf * hv_2,
137+
zero(h))
138+
end
139+
140+
###############################################################################
141+
# Get the DG approximation space
142+
143+
volume_flux = (flux_ersing_etal, flux_nonconservative_ersing_etal)
144+
145+
surface_flux = (FluxHydrostaticReconstruction(FluxPlusDissipation(flux_ersing_etal,
146+
DissipationLocalLaxFriedrichs()),
147+
hydrostatic_reconstruction_ersing_etal),
148+
FluxHydrostaticReconstruction(flux_nonconservative_ersing_etal,
149+
hydrostatic_reconstruction_ersing_etal))
150+
151+
basis = LobattoLegendreBasis(3)
152+
153+
# Cannot simply use `waterheight` here for multilayer equations.
154+
# Need a helper function to extract the relevant variable.
155+
@inline function main_waterheight(u, equations)
156+
return waterheight(u, equations)[1]
157+
end
158+
159+
indicator_sc = IndicatorHennemannGassnerShallowWater(equations, basis,
160+
alpha_max = 0.5,
161+
alpha_min = 0.001,
162+
alpha_smooth = true,
163+
variable = main_waterheight)
164+
volume_integral = VolumeIntegralShockCapturingHG(indicator_sc;
165+
volume_flux_dg = volume_flux,
166+
volume_flux_fv = surface_flux)
167+
168+
solver = DGSEM(basis, surface_flux, volume_integral)
169+
170+
###############################################################################
171+
# Get the unstructured quad mesh from a file (downloads the file if not available locally)
172+
173+
mesh_file = Trixi.download("https://gist.githubusercontent.com/andrewwinters5000/d26356bdc8e8d742a3035b3f71c71a68/raw/9d6ceedb844e92313d1dac2318a28c87ffbb9de2/mesh_monai_shore.inp",
174+
joinpath(@__DIR__, "mesh_monai_shore.inp"));
175+
176+
mesh = P4estMesh{2}(mesh_file)
177+
178+
# create the semi discretization object
179+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver;
180+
boundary_conditions = boundary_condition,
181+
source_terms = source_terms_manning_friction)
182+
183+
###############################################################################
184+
# ODE solvers, callbacks etc.
185+
186+
tspan = (0.0, 22.5)
187+
ode = semidiscretize(semi, tspan)
188+
189+
###############################################################################
190+
# Callbacks
191+
192+
summary_callback = SummaryCallback()
193+
194+
analysis_interval = 1000
195+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
196+
extra_analysis_errors = (:conservation_error,),
197+
save_analysis = false)
198+
199+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
200+
201+
save_solution = SaveSolutionCallback(dt = 0.2,
202+
save_initial_solution = true,
203+
save_final_solution = true)
204+
205+
stepsize_callback = StepsizeCallback(cfl = 0.5)
206+
207+
# Another possible AMR indicator function could be the water height with `IndicatorLoehner`
208+
@inline function momentum_norm(u, equations::ShallowWaterMultiLayerEquations2D)
209+
_, h_v1, h_v2, _ = u
210+
return sqrt(h_v1^2 + h_v2^2)
211+
end
212+
213+
amr_controller = ControllerThreeLevel(semi,
214+
IndicatorMax(semi, variable = momentum_norm),
215+
base_level = 0,
216+
med_level = 1, med_threshold = 0.012,
217+
max_level = 3, max_threshold = 0.015)
218+
219+
amr_callback = AMRCallback(semi, amr_controller,
220+
interval = 5,
221+
adapt_initial_condition = false,
222+
adapt_initial_condition_only_refine = false)
223+
224+
callbacks = CallbackSet(summary_callback,
225+
analysis_callback,
226+
alive_callback,
227+
amr_callback,
228+
save_solution,
229+
stepsize_callback)
230+
231+
###############################################################################
232+
# run the simulation
233+
234+
stage_limiter! = PositivityPreservingLimiterShallowWater(variables = (waterheight,))
235+
236+
sol = solve(ode, SSPRK43(stage_limiter!);
237+
ode_default_options()...,
238+
callback = callbacks,
239+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
240+
adaptive = false);

0 commit comments

Comments
 (0)