9physical_offset = [-39870.0, 0.0]
10physical_size = [379700.0, L / 3]
11square_side = max(physical_size)
14 physical_offset[0] - 0.5 * (square_side - physical_size[0]),
15 physical_offset[1] - 0.5 * (square_side - physical_size[1]),
17size = [square_side, square_side]
22 Compute the Manning coefficient n based on the Chezy formulation:
24 C = 18 * log(0.37 * H / z0)
30 Water depth in meters.
32 Roughness length in meters (default: 0.003).
37 Manning coefficient (dimensionless).
40 raise ValueError(
"Water depth H must be positive.")
42 C = 18.0 * np.log10(0.37 * H / z0)
49print(
"Manning coefficient:", manning_coefficient_value)
51initial_conditions = f
"""
52 static tarch::reader::NetCDFFieldParser fieldParser(
53 "bathymetry/test_R1_dx100_H{H}_b.grd",
56 PhysicalDomainOffsetX,
57 PhysicalDomainOffsetY,
63 // TODO: This sampling is needed to make the square domain works without NaNs. However, it gives unphysical solutions.
64 // The setup should be a rectangular domain, but this breaks limiting. The limiter needs to be fixed first.
65 const double sampleX =
66 x(0) < PhysicalDomainOffsetX ? PhysicalDomainOffsetX :
67 (x(0) > PhysicalDomainOffsetX + PhysicalDomainSizeX ? PhysicalDomainOffsetX + PhysicalDomainSizeX : x(0));
68 const double sampleY =
69 x(1) < PhysicalDomainOffsetY ? PhysicalDomainOffsetY :
70 (x(1) > PhysicalDomainOffsetY + PhysicalDomainSizeY ? PhysicalDomainOffsetY + PhysicalDomainSizeY : x(1));
72 const double bathymetry = fieldParser.sampleTopology(sampleX, sampleY);
73 Q[Shortcuts::h] = -std::min(bathymetry, 0.0);
74 Q[Shortcuts::hu] = 0.0;
75 Q[Shortcuts::hv] = 0.0;
76 Q[Shortcuts::z] = bathymetry;
79boundary_conditions =
"""
81 // x-normal: left and right boundary
83 Qoutside[0] = Qinside[0];
84 Qoutside[1] = Qinside[1];
85 Qoutside[2] = Qinside[2];
86 Qoutside[3] = Qinside[3];
87 } else if (normal == 1) {
88 // y-normal: top and bottom boundary
90 Qoutside[0] = Qinside[0];
91 Qoutside[1] = Qinside[1];
92 Qoutside[2] = -Qinside[2];
93 Qoutside[3] = Qinside[3];
97is_physically_admissible =
"""
98 if (x(0) < PhysicalDomainOffsetX or x(0) > PhysicalDomainOffsetX + PhysicalDomainSizeX) {
101 if (x(1) < PhysicalDomainOffsetY or x(1) > PhysicalDomainOffsetY + PhysicalDomainSizeY) {
105 if (std::abs(x[0] - DomainOffset[0]) < h[0] or std::abs(x[0] - DomainOffset[0] - DomainSize[0]) < h[0]) {
108 if (std::abs(x[1] - DomainOffset[1]) < h[1] or std::abs(x[1] - DomainOffset[1] - DomainSize[1]) < h[1]) {
112 if (x(0) - PhysicalDomainOffsetX > 0.85 * PhysicalDomainSizeX) {
115 if (x(0) - PhysicalDomainOffsetX < 0.15 * PhysicalDomainSizeX) {
122parser = exahype2.ArgumentParser()
126 degrees_of_freedom=7,
128args = parser.parse_args()
131 "g": [9.81,
"double"],
132 "hThreshold": [1e-5,
"double"],
133 "PhysicalDomainOffsetX": [physical_offset[0],
"double"],
134 "PhysicalDomainOffsetY": [physical_offset[1],
"double"],
135 "PhysicalDomainSizeX": [physical_size[0],
"double"],
136 "PhysicalDomainSizeY": [physical_size[1],
"double"],
137 "water_density": [1000,
"double"],
138 "manning_param": [manning_coefficient_value,
"double"],
139 "corriolis_param": [9.35e-5,
"double"],
140 "pressure": [100,
"double"],
141 "speed_pressure": [22.15,
"double"],
142 "period_pressure": [1800,
"double"],
143 "background_pressure": [101300,
"double"],
147max_h = 1.1 * min(physical_size) / (3.0**args.min_depth)
148min_h = max_h * 3.0 ** (-args.amr_levels)
149dg_order = args.degrees_of_freedom - 1
151aderdg_solver = exahype2.solvers.aderdg.GlobalAdaptiveTimeStep(
154 unknowns={
"h": 1,
"hu": 1,
"hv": 1,
"z": 1},
155 auxiliary_variables=0,
158 time_step_relaxation=0.9,
161aderdg_solver.set_implementation(
162 initial_conditions=initial_conditions,
163 boundary_conditions=boundary_conditions,
164 flux=f
"ShallowWater::flux<double, Shortcuts, {aderdg_solver.unknowns}>(Q, x, h, t, dt, normal, F);",
165 ncp=f
"ShallowWater::nonconservativeProduct<double, Shortcuts, {aderdg_solver.unknowns}>(Q, deltaQ, x, h, t, dt, normal, BTimesDeltaQ);",
166 max_eigenvalue=
"return ShallowWater::maxEigenvalue<double, Shortcuts>(Q,x,h,t,dt,normal);",
168 // Compute max eigenvalue over face
170 for(int xy=0; xy<Order+1; xy++){
171 smax = std::max(smax, maxEigenvalue(&QL[xy*4], x, h, t, dt, direction));
172 smax = std::max(smax, maxEigenvalue(&QR[xy*4], x, h, t, dt, direction));
175 for(int xy=0; xy<Order+1; xy++){
176 if (QL[xy*4+0] <= hThreshold or QR[xy*4+0] <= hThreshold) {
177 FR[xy*4+0] = FL[xy*4+0] = 0.0;
178 FR[xy*4+1] = FL[xy*4+1] = 0.0;
179 FR[xy*4+2] = FL[xy*4+2] = 0.0;
180 FR[xy*4+3] = FL[xy*4+3] = 0.0;
184 // h gets added term from bathymetry, u and v are regular Rusanov, b does not change
185 FL[xy*4+0] = 0.5*(FL[xy*4+0]+FR[xy*4+0] + smax*(QL[xy*4+0]+QL[xy*4+3]-QR[xy*4+0]-QR[xy*4+3]) );
186 FL[xy*4+1] = 0.5*(FL[xy*4+1]+FR[xy*4+1] + smax*(QL[xy*4+1]-QR[xy*4+1]) );
187 FL[xy*4+2] = 0.5*(FL[xy*4+2]+FR[xy*4+2] + smax*(QL[xy*4+2]-QR[xy*4+2]) );
190 FR[xy*4+0] = FL[xy*4+0];
191 FR[xy*4+1] = FL[xy*4+1];
192 FR[xy*4+2] = FL[xy*4+2];
195 // Contribution from NCP
196 FL[xy*4+direction+1] += 0.5*g*0.5*(QL[xy*4+0]+QR[xy*4+0])*(QR[xy*4+3]+QR[xy*4+0]-QL[xy*4+3]-QL[xy*4+0]);
197 FR[xy*4+direction+1] -= 0.5*g*0.5*(QL[xy*4+0]+QR[xy*4+0])*(QR[xy*4+3]+QR[xy*4+0]-QL[xy*4+3]-QL[xy*4+0]);
200 source_term=f
"meteotsunami::sourceTerm<double, Shortcuts, {aderdg_solver.unknowns}, {aderdg_solver.auxiliary_variables}>(Q, x, h, t, dt, S);",
203aderdg_solver.add_user_solver_includes(
206#include "SourceTerm.h"
207#include "tarch/reader/NetCDFFieldParser.h"
211fv_solver = exahype2.solvers.fv.godunov.GlobalAdaptiveTimeStep(
213 patch_size=dg_order * 2 + 1,
214 unknowns={
"h": 1,
"hu": 1,
"hv": 1},
215 auxiliary_variables={
"z": 1},
218 time_step_relaxation=0.9,
221fv_solver.set_implementation(
222 initial_conditions=initial_conditions,
223 boundary_conditions=boundary_conditions,
224 source_term=f
"meteotsunami::sourceTerm<double, Shortcuts, {fv_solver.unknowns}, {fv_solver.auxiliary_variables}>(Q, x, h, t, dt, S);",
225 riemann_solver=
"return fWaveRiemannSolver<double, Shortcuts>(QL, QR, x, h, t, dt, normal, FL, FR);",
228fv_solver.add_user_solver_includes(
230#include "../FWaveRiemannSolver.h"
231#include "SourceTerm.h"
232#include "tarch/reader/NetCDFFieldParser.h"
236limiter_solver = exahype2.solvers.limiting.StaticLimiting(
237 name=
"LimiterSolver",
238 regular_solver=aderdg_solver,
239 limiting_solver=fv_solver,
240 physical_admissibility_criterion=is_physically_admissible,
243project = exahype2.Project(
244 namespace=[
"applications",
"exahype2",
"ShallowWater"],
245 project_name=
"Meteotsunami",
247 executable=
"ExaHyPE",
250project.add_solver(aderdg_solver)
251project.add_solver(fv_solver)
252project.add_solver(limiter_solver)
254if args.number_of_snapshots <= 0:
255 time_in_between_plots = 0.0
257 time_in_between_plots = args.end_time / args.number_of_snapshots
258 project.set_output_path(args.output)
260project.set_global_simulation_parameters(
264 min_end_time=args.end_time,
265 max_end_time=args.end_time,
266 first_plot_time_stamp=0.0,
267 time_in_between_plots=time_in_between_plots,
269 args.periodic_boundary_conditions_x,
270 args.periodic_boundary_conditions_y,
274project.set_build_mode(mode=peano4.output.string_to_mode(args.build_mode))
275project = project.generate_Peano4_project(verbose=
False)
276for const_name, const_info
in constants.items():
277 const_val, const_type = const_info
278 project.constants.export_constexpr_with_type(const_name, str(const_val), const_type)
279project.output.makefile.set_target_device(args.target_device)
280project.build(make=
True, make_clean_first=
True, throw_away_data_after_build=
True)
float manning_coefficient(float H, float z0=0.003)
Compute the Manning coefficient n based on the Chezy formulation: