Peano
Loading...
Searching...
No Matches
11_tsunami.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3"""!
4
5Create the PNG illustrations of the tutorial 11_tsunami.ipynb
6
7The script builds the tutorial's shallow water setup, runs it and writes
8snapshots of the water height into the directory of this script. It does
9so twice: for the flat sea floor and for the sea floor shaped like the logo
10of Durham University (section "Adding bathymetry and external files", which
11reads the logo from tutorials/exahype2/bathymetry). The tutorial derives
12flux and eigenvalue of the latter with SymPy, whereas we use the handwritten
13versions here. Both give the same results. Finally, it runs the setup of
14section "Letting the bathymetry shape the flow", which uses the surface
15elevation eta as unknown, and plots it at t=0, 0.1, 0.2 and 0.4. Call the
16script from anywhere:
17
18 python3 tutorials/exahype2/illustrations/11_tsunami.py
19
20All builds and outputs go into a temporary directory (or --work-directory).
21
22"""
23import argparse
24import os
25import subprocess
26import sys
27import tempfile
28
29Here = os.path.dirname(os.path.abspath(__file__))
30PeanoRoot = os.path.abspath(os.path.join(Here, "..", "..", ".."))
31sys.path.insert(0, os.path.join(PeanoRoot, "src"))
32
33import matplotlib
34
35matplotlib.use("Agg")
36import matplotlib.pyplot as plt
37
38import peano4.api
39import exahype2
41
42
43Flux = """
44 constexpr double g = 9.81;
45 const double h = Q[Variables::h];
46 const double un = Q[Variables::hu + normal] / h;
47 F[Variables::h] = Q[Variables::hu + normal];
48 F[Variables::hu] = Q[Variables::hu] * un;
49 F[Variables::hv] = Q[Variables::hv] * un;
50 F[Variables::hu + normal] += 0.5 * g * h * h;
51"""
52
53MaxEigenvalue = """
54 constexpr double g = 9.81;
55 const double h = Q[Variables::h];
56 const double un = Q[Variables::hu + normal] / h;
57 lambdaMax[0] = std::abs(un) + std::sqrt(g * h);
58"""
59
60InitPointWisely = """
61 Q[Variables::h] = 1.0 + 0.1 * std::exp(-100.0 * (x[0] * x[0] + x[1] * x[1]));
62 Q[Variables::hu] = 0.0;
63 Q[Variables::hv] = 0.0;
64 Q[Variables::b] = 0.0;
65"""
66
67InitPointWiselyWithLogo = """
68 const int column = std::clamp(static_cast<int>((x[0] + 1.0) / 2.0 * DurhamLogoSize), 0, DurhamLogoSize - 1);
69 const int row = std::clamp(static_cast<int>((1.0 - x[1]) / 2.0 * DurhamLogoSize), 0, DurhamLogoSize - 1);
70 const double depth = DurhamLogo[row][column] == '1' ? 4.0 : 1.0;
71
72 Q[Variables::h] = depth + 0.1 * std::exp(-100.0 * (x[0] * x[0] + x[1] * x[1]));
73 Q[Variables::hu] = 0.0;
74 Q[Variables::hv] = 0.0;
75 Q[Variables::b] = -depth;
76"""
77
78FluxEta = """
79 constexpr double g = 9.81;
80 const double h = Q[Variables::eta] - Q[Variables::b];
81 const double un = Q[Variables::hu + normal] / h;
82 F[Variables::eta] = Q[Variables::hu + normal];
83 F[Variables::hu] = Q[Variables::hu] * un;
84 F[Variables::hv] = Q[Variables::hv] * un;
85 F[Variables::hu + normal] += 0.5 * g * h * h;
86"""
87
88MaxEigenvalueEta = """
89 constexpr double g = 9.81;
90 const double h = Q[Variables::eta] - Q[Variables::b];
91 const double un = Q[Variables::hu + normal] / h;
92 lambdaMax[0] = std::abs(un) + std::sqrt(g * h);
93"""
94
95NonconservativeProductEta = """
96 constexpr double g = 9.81;
97 const double h = Q[Variables::eta] - Q[Variables::b];
98 BTimesDeltaQ[Variables::eta] = 0.0;
99 BTimesDeltaQ[Variables::hu] = 0.0;
100 BTimesDeltaQ[Variables::hv] = 0.0;
101 BTimesDeltaQ[Variables::hu + normal] = g * h * deltaQ[Variables::b];
102"""
103
104InitPointWiselyEta = """
105 const int column = std::clamp(static_cast<int>((x[0] + 1.0) / 2.0 * DurhamLogoSize), 0, DurhamLogoSize - 1);
106 const int row = std::clamp(static_cast<int>((1.0 - x[1]) / 2.0 * DurhamLogoSize), 0, DurhamLogoSize - 1);
107 const double depth = DurhamLogo[row][column] == '1' ? 4.0 : 1.0;
108
109 Q[Variables::eta] = 0.1 * std::exp(-100.0 * (x[0] * x[0] + x[1] * x[1]));
110 Q[Variables::hu] = 0.0;
111 Q[Variables::hv] = 0.0;
112 Q[Variables::b] = -depth;
113"""
114
115Bathymetry = os.path.join(Here, "..", "bathymetry")
116
117PatchFile = "solution-SWE.peano-patch-file"
118
119
121 directory,
122 init=InitPointWisely,
123 with_logo=False,
124 first_unknown="h",
125 flux=Flux,
126 max_eigenvalue=MaxEigenvalue,
127 nonconservative_product=None,
128):
129 """!
130
131 Generate, compile and run the tutorial setup within directory
132
133 with_logo adds the depth map DurhamLogo from Bathymetry to the build.
134 first_unknown is the name of the first unknown, i.e. h or eta.
135
136 """
137 project = exahype2.api.Project(
138 namespace=["tutorials", "exahype2", "tsunami"],
139 project_name="Tsunami",
140 directory=directory,
141 executable="tsunami",
142 )
143 solver = exahype2.api.Solver(
144 "SWE", {first_unknown: 1, "hu": 1, "hv": 1}, {"b": 1}
145 )
146 solver.add_user_solver_includes("#include <cmath>\n#include <algorithm>\n")
147 if with_logo:
148 solver.add_user_solver_includes('#include "DurhamLogo.h"\n')
149 solver.add_pde_term(exahype2.api.Flux(implementation=flux, stateless=False))
150 solver.add_pde_term(
151 exahype2.api.MaxEigenvalue(implementation=max_eigenvalue, stateless=False)
152 )
153 if nonconservative_product is not None:
154 solver.add_pde_term(
156 implementation=nonconservative_product, stateless=False
157 )
158 )
159 solver.add_pde_term(
160 exahype2.api.InitPointWisely(implementation=init, stateless=False)
161 )
162 solver.numerical_scheme = exahype2.api.fv.RusanovWithExplicitEuler(solver, 9)
163 solver.grid_construction = exahype2.api.fv.SetupSimulationOverRegularGrid(
164 solver, volume_size=0.01
165 )
166 solver.plotter = exahype2.api.fv.PlotAsVTKFile(
167 solver, first_plot_time_stamp=0.0, time_in_between_plots=0.05
168 )
169 project.add_solver(solver)
170 project.set_global_simulation_parameters(
171 dimensions=2,
172 offset=[-1.0, -1.0],
173 size=[2.0, 2.0],
174 min_end_time=0.4,
175 max_end_time=0.4,
176 periodic_BC=[True, True, True],
177 )
178 project.set_Peano4_installation(PeanoRoot, peano4.api.output.CompileMode.RELEASE)
179 peano4_project = project.generate_Peano4_project()
180 if with_logo:
181 makefile = peano4_project.output.makefile
182 makefile.add_cpp_file(os.path.join(Bathymetry, "DurhamLogo.cpp"))
183 makefile.add_h_file(os.path.join(Bathymetry, "DurhamLogo.h"))
184 makefile.add_header_search_path(Bathymetry)
185 peano4_project.generate()
186 subprocess.run(["make", "-j"], cwd=directory, check=True, stdout=subprocess.DEVNULL)
187 subprocess.run(["./tsunami"], cwd=directory, check=True, stdout=subprocess.DEVNULL)
188
189
190def plot_snapshots(directory, prefix, label="water height h", with_early=False):
191 """!
192
193 First unknown at the start, half way through and at the end
194
195 with_early adds the snapshot at a quarter of the simulated time.
196
197 """
198 file_name = os.path.join(directory, PatchFile)
199 snapshots = len(tarch.plotter.api.notebook.read_snapshots(file_name))
200 selection = [
201 (0, "start"),
202 ((snapshots - 1) // 2, "middle"),
203 (snapshots - 1, "end"),
204 ]
205 if with_early:
206 selection.insert(1, ((snapshots - 1) // 4, "early"))
207 for snapshot, suffix in selection:
208 fig, ax = plt.subplots(figsize=(6, 5))
210 file_name, snapshot, 0, ax=ax, label=label
211 )
212 fig.savefig(
213 os.path.join(Here, prefix + suffix + ".png"),
214 dpi=100,
215 bbox_inches="tight",
216 )
217 plt.close(fig)
218
219
220def plot_sea_floor(directory, prefix):
221 """! Sea floor b, which does not change over time"""
222 fig, ax = plt.subplots(figsize=(6, 5))
224 os.path.join(directory, PatchFile), 0, 3, ax=ax, cmap="Purples_r", label="sea floor b"
225 )
226 fig.savefig(os.path.join(Here, prefix + "b.png"), dpi=100, bbox_inches="tight")
227 plt.close(fig)
228
229
230if __name__ == "__main__":
231 parser = argparse.ArgumentParser(
232 description="Create the PNGs of the tutorial 11_tsunami.ipynb"
233 )
234 parser.add_argument(
235 "--work-directory",
236 default=None,
237 help="Directory for builds and outputs (default: temporary directory)",
238 )
239 args = parser.parse_args()
240
241 work_directory = args.work_directory or tempfile.mkdtemp(prefix="11_tsunami-")
242 print("build and run in {}".format(work_directory))
243 flat = os.path.join(work_directory, "flat")
244 build_and_run(flat)
245 plot_snapshots(flat, "11_tsunami-")
246
247 bathymetry = os.path.join(work_directory, "bathymetry")
248 build_and_run(bathymetry, InitPointWiselyWithLogo, with_logo=True)
249 plot_snapshots(bathymetry, "11_tsunami-bathymetry-")
250 plot_sea_floor(bathymetry, "11_tsunami-bathymetry-")
251
252 ncp = os.path.join(work_directory, "ncp")
254 ncp,
255 InitPointWiselyEta,
256 with_logo=True,
257 first_unknown="eta",
258 flux=FluxEta,
259 max_eigenvalue=MaxEigenvalueEta,
260 nonconservative_product=NonconservativeProductEta,
261 )
263 ncp, "11_tsunami-ncp-", label="surface elevation eta", with_early=True
264 )
265 print("wrote PNGs into {}".format(Here))
The conservative flux F(Q) of a hyperbolic PDE.
Definition Flux.py:8
Point-wise initial condition: given the physical position of a single degree of freedom,...
The maximum absolute eigenvalue of the flux Jacobian in a given direction, i.e.
The non-conservative product B(Q) applied to a jump deltaQ in a given direction, i....
ExaHyPE 2 project.
Definition Project.py:15
Abstract base class for all ExaHyPE 2 solvers.
Definition Solver.py:17
Plotting counterpart to RusanovWithExplicitEuler: maps the patch data of a Finite Volume scheme with ...
Finite Volumes with a Rusanov Riemann solver and explicit Euler time stepping, realised over a block-...
Setup phase counterpart to RusanovWithExplicitEuler: sets the initial condition for a Finite Volume s...
build_and_run(directory, init=InitPointWisely, with_logo=False, first_unknown="h", flux=Flux, max_eigenvalue=MaxEigenvalue, nonconservative_product=None)
Generate, compile and run the tutorial setup within directory.
plot_sea_floor(directory, prefix)
Sea floor b, which does not change over time.
plot_snapshots(directory, prefix, label="water height h", with_early=False)
First unknown at the start, half way through and at the end.
Interactive visualisation of Peano patch files within Jupyter notebooks.
Definition notebook.py:1
plot_snapshot(file_name, snapshot=-1, unknown=0, clim=None, ax=None, cmap="viridis", label=None)
Plot one unknown of one snapshot.
Definition notebook.py:100
read_snapshots(file_name)
Return list of (time stamp, list of patch files) from a patch meta file.
Definition notebook.py:30