6sys.path.insert(0, os.path.abspath(
".."))
8from EulerPDE
import get_flux, get_max_eigenvalue
9from EulerFWave
import fWave
11from DiffusionPDE
import stencil
15This application is based on:
16"Breaking of thunderstorm-generated gravity waves as a source of short-period ducted waves at mesopause altitudes", Snively and Pasko, 2003, doi:10.1029/2003GL018436
19if __name__ ==
"__main__":
20 parser = exahype2.ArgumentParser(
21 "ExaHyPE 2 Gravity Waves Thunderstorm Argument Parser"
25 degrees_of_freedom=16,
31 default=
"./thunderstorm_model.csv",
33 help=
"Path to CSV file for use as initial conditions for this project.",
35 args = parser.parse_args()
38 size = [1_200e3, 220e3, 1_200e3]
44 atmosphere_initial_conditions = (
46 csv_file_path=args.csv_file_path,
47 initialize_density=
True,
48 initialize_hydrogen=
False,
51 // momenta are in m/s * kg/m^3 = kg/(m^2 * s)
52 Q[Shortcuts::rhou] = HORIZONTAL_WINDSPEED * Q[Shortcuts::rho];
53 Q[Shortcuts::rhov] = 0.0;
55 Q[Shortcuts::rhow] = 0.0;
58 const auto M = Q[Shortcuts::O2] + Q[Shortcuts::O] + Q[Shortcuts::N2];
59 const auto iM = 1.0 / M;
60 const auto meanMolecularMass = (MOLAR_MASS_NITROGEN * Q[Shortcuts::N2] + MOLAR_MASS_MOLECULAR_OXYGEN * Q[Shortcuts::O2] + MOLAR_MASS_ATOMIC_OXYGEN * Q[Shortcuts::O]) * iM; // in kg/mol
61 const auto pressure = Q[Shortcuts::rho] * UNIVERSAL_GAS_CONSTANT * Q[Shortcuts::T] / meanMolecularMass;
62 #if !defined(WITH_GPU)
63 assertion5(pressure > 0.0, M, meanMolecularMass, Q[Shortcuts::rho], Q[Shortcuts::T], pressure);
66 const auto gamma = (1.4 * (M - Q[Shortcuts::O]) + 1.67 * Q[Shortcuts::O]) * iM;
68 Q[Shortcuts::E] = pressure / (gamma - 1) + 0.5 * Q[Shortcuts::rho] * (HORIZONTAL_WINDSPEED * HORIZONTAL_WINDSPEED);
70 Q[Shortcuts::backgroundDensity] = Q[Shortcuts::rho];
71 Q[Shortcuts::backgroundPressure] = pressure;"""
74 atmosphere_boundary_conditions =
"""
75 // normal == 0 => left
76 // normal == 1 => bottom
77 // normal == 2 => right
80 if (normal == 0 || normal == 2) {
82 for (int unknown = 0; unknown < NumberOfUnknowns + NumberOfAuxiliaryVariables; ++unknown) {
83 Qoutside[unknown] = Qinside[unknown];
85 } else if (normal == 1 || normal == 3) {
86 const auto M = Qinside[Shortcuts::O2] + Qinside[Shortcuts::O] + Qinside[Shortcuts::N2];
87 const auto iM = 1.0 / M;
88 const auto meanMolecularMass = (MOLAR_MASS_NITROGEN * Qinside[Shortcuts::N2] + MOLAR_MASS_MOLECULAR_OXYGEN * Qinside[Shortcuts::O2] + MOLAR_MASS_ATOMIC_OXYGEN * Qinside[Shortcuts::O]) * iM; // in kg/mol
89 const auto pressure = Qinside[Shortcuts::rho] * UNIVERSAL_GAS_CONSTANT * Qinside[Shortcuts::T] / meanMolecularMass;
90 #if !defined(WITH_GPU)
91 assertion5(pressure > 0.0, M, meanMolecularMass, Qinside[Shortcuts::rho], Qinside[Shortcuts::T], pressure);
94 const auto gamma = (1.4 * (M - Qinside[Shortcuts::O]) + 1.67 * Qinside[Shortcuts::O]) * iM;
96 // positive dy upwards, negative dz downwards
97 const auto dy = normal == 3 ? h(1) : -h(1);
99 const auto specificGasConstant = UNIVERSAL_GAS_CONSTANT / meanMolecularMass;
100 const auto scaleHeight = specificGasConstant * Qinside[Shortcuts::T] / GRAVITY;
101 const auto exponentialDistribution = tarch::la::pow(tarch::la::E, -dy / scaleHeight);
103 const auto densityOutside = Qinside[Shortcuts::rho] * exponentialDistribution;
104 const auto pressureOutside = pressure * exponentialDistribution;
106 Qoutside[Shortcuts::rho] = densityOutside;
107 const auto u = Qinside[Shortcuts::rhou] / Qinside[Shortcuts::rho];
108 const auto v = Qinside[Shortcuts::rhov] / Qinside[Shortcuts::rho];
110 const auto w = Qinside[Shortcuts::rhow] / Qinside[Shortcuts::rho];
111 const auto vSq = u * u + v * v + w * w;
113 const auto vSq = u * u + v * v;
116 Qoutside[Shortcuts::E] = pressureOutside / (gamma - 1) + 0.5 * densityOutside * vSq;
119 // Reflective at bottom to keep atmosphere
120 // from escaping the domain through the Earth's surface
121 Qoutside[Shortcuts::rhou] = u * densityOutside;
122 Qoutside[Shortcuts::rhov] = -v * densityOutside;
124 Qoutside[Shortcuts::rhow] = w * densityOutside;
128 Qoutside[Shortcuts::rhou] = u * densityOutside;
129 Qoutside[Shortcuts::rhov] = v * densityOutside;
131 Qoutside[Shortcuts::rhow] = w * densityOutside;
135 for (int auxiliaryVariable = 0; auxiliaryVariable < NumberOfAuxiliaryVariables; ++auxiliaryVariable) {
136 Qoutside[NumberOfUnknowns + auxiliaryVariable] = Qinside[NumberOfUnknowns + auxiliaryVariable];
139 Qoutside[Shortcuts::backgroundDensity] = densityOutside;
140 Qoutside[Shortcuts::backgroundPressure] = pressureOutside;
143 max_h = 1.1 * min(size) / (3.0**args.min_depth)
144 min_h = max_h * 3.0 ** (-args.amr_levels)
146 atmosphere_unknowns = {
153 if args.dimensions == 3:
154 atmosphere_unknowns[
"rhow"] = 1
156 atmosphere_auxiliary_variables = {
161 "backgroundDensity": 1,
162 "backgroundPressure": 1,
165 atmosphere_solver = exahype2.solvers.fv.godunov.GlobalAdaptiveTimeStep(
167 patch_size=args.degrees_of_freedom,
168 unknowns=atmosphere_unknowns,
169 auxiliary_variables=atmosphere_auxiliary_variables,
172 time_step_relaxation=0.5,
175 atmosphere_solver.set_implementation(
176 initial_conditions=atmosphere_initial_conditions,
177 boundary_conditions=atmosphere_boundary_conditions,
179 riemann_solver=fWave,
180 max_eigenvalue=get_max_eigenvalue(),
183 atmosphere_solver.add_user_solver_includes(
'#include "tarch/reader/CSVReader.h"\n')
185 atmosphere_solver.set_implementation(
186 source_term=
"""for(int unknown = 0; unknown < NumberOfUnknowns; ++unknown) {
190 applications::exahype2::GravityWaves::Thunderstorm::ForcingTerms::scenario(Q, x, h, t, S);"""
193 atmosphere_solver.add_user_solver_includes(
'#include "ForcingTerms.h"')
194 atmosphere_solver.add_solver_constants(GravityWaves.CSV_CONSTANTS)
200 diffusion_unknowns = {
205 if args.dimensions == 3:
206 diffusion_unknowns[
"w"] = 1
208 diffusion_unknowns[
"T"] = 1
210 diffusion_auxiliary_variables = {
222 if args.dimensions == 3:
223 diffusion_auxiliary_variables[
"backgroundW"] = 1
224 diffusion_auxiliary_variables[
"backgroundT"] = 1
226 diffusion_initial_conditions = (
228 csv_file_path=args.csv_file_path,
229 initialize_density=
True,
230 initialize_hydrogen=
False,
233 // "Doppler ducting of short-period gravity waves by midlatitude tidal wind structure", Snively et al., 2007
234 // exponential function between (110km, 100 m^2/s) and (150km, 5000 m^2/s)
235 // 5000 m^2/s implied in Thermosphere Ducted Gravity Waves but fully stated in Doppler Ducting
236 auto viscosityFunction = [](const double altitude) {
237 if(tarch::la::smaller(altitude, 110'000.0)) {
241 return 0.00212732 * tarch::la::pow(tarch::la::E, 0.0000978006 * altitude);
244 Q[Shortcuts::u] = HORIZONTAL_WINDSPEED;
245 Q[Shortcuts::backgroundU] = Q[Shortcuts::u];
247 Q[Shortcuts::v] = 0.0;
248 Q[Shortcuts::backgroundV] = 0.0;
251 Q[Shortcuts::w] = 0.0;
252 Q[Shortcuts::backgroundW] = 0.0;
255 Q[Shortcuts::nu] = viscosityFunction(x(1));
256 Q[Shortcuts::kappa] = 1.5 * Q[Shortcuts::nu];
258 const auto M = Q[Shortcuts::O2] + Q[Shortcuts::O] + Q[Shortcuts::N2];
259 const auto iM = 1.0 / M;
260 const auto meanMolecularMass = (MOLAR_MASS_NITROGEN * Q[Shortcuts::N2] + MOLAR_MASS_MOLECULAR_OXYGEN * Q[Shortcuts::O2] + MOLAR_MASS_ATOMIC_OXYGEN * Q[Shortcuts::O]) * iM; // in kg/mol
261 const auto pressure = Q[Shortcuts::rho] * UNIVERSAL_GAS_CONSTANT * Q[Shortcuts::T] / meanMolecularMass;
262 const auto gamma = (1.4 * (M - Q[Shortcuts::O]) + 1.67 * Q[Shortcuts::O]) * iM;
264 Q[Shortcuts::E] = pressure / (gamma - 1) + 0.5 * Q[Shortcuts::rho] * (HORIZONTAL_WINDSPEED * HORIZONTAL_WINDSPEED);
265 Q[Shortcuts::backgroundT] = Q[Shortcuts::T];"""
268 diffusion_boundary_conditions =
"""
269 // normal == 0 => left
270 // normal == 1 => bottom
271 // normal == 2 => right
272 // normal == 3 => top
274 for (int unknown = 0; unknown < NumberOfUnknowns + NumberOfAuxiliaryVariables; ++unknown) {
275 Qoutside0[unknown] = Qinside[unknown];
279 // Reflective at bottom to keep atmosphere
280 // from escaping the domain through the Earth's surface
281 Qoutside0[Shortcuts::u] = Qinside[Shortcuts::u];
282 Qoutside0[Shortcuts::v] = -Qinside[Shortcuts::v];
284 Qoutside0[Shortcuts::w] = Qinside[Shortcuts::w];
288 diffusion_solver = exahype2.solvers.fd.GlobalAdaptiveTimeStep(
290 patch_size=args.degrees_of_freedom,
291 unknowns=diffusion_unknowns,
292 auxiliary_variables=diffusion_auxiliary_variables,
295 time_step_relaxation=0.5,
297 solvers_before_in_coupling=[atmosphere_solver],
300 diffusion_solver.set_implementation(
301 initial_conditions=diffusion_initial_conditions,
302 boundary_conditions=diffusion_boundary_conditions,
303 max_eigenvalue=
"return 1.0;",
307 diffusion_solver.add_user_solver_includes(
'#include "tarch/reader/CSVReader.h"\n')
308 diffusion_solver.add_solver_constants(GravityWaves.CSV_CONSTANTS)
315 atmospheric_solver=atmosphere_solver,
316 diffusion_solver=diffusion_solver,
317 chemical_solver=
None,
318 size=size[: args.dimensions],
322 project.output.makefile.add_cpp_file(
"ForcingTerms.cpph")
324 project.output.makefile.add_CXX_flag(f
"""-DDENSITY_THRESHOLD=1E-9""")
325 project.output.makefile.add_CXX_flag(f
"""-DPRESSURE_THRESHOLD=1E-9""")
326 project.output.makefile.add_CXX_flag(f
"""-DTEMPERATURE_THRESHOLD=1E-9""")
327 project.output.makefile.add_CXX_flag(f
"""-DVELOCITY_THRESHOLD=1E-9""")
328 project.output.makefile.add_CXX_flag(f
"""-DHORIZONTAL_WINDSPEED=0.0""")
330 project.build(make=
True, make_clean_first=
True, throw_away_data_after_build=
True)
get_CSV_initializer(csv_file_path, bool initialize_density, bool initialize_hydrogen)
create_peano_project(atmospheric_solver, diffusion_solver, chemical_solver, size, arguments)