.. _ch:dimensional_splitting: Two-Dimensional Solver ====================== In this part of out project, we'll cover the extension of our one-dimensional discretization to two spatial dimensions. Then, we'll compare our two-dimensional solver to the one-dimensional one of the previous parts. After this chapter, we have all numerics at hand and will be able to conduct tsunami simulations in the following parts. Dimensional Splitting --------------------- In their differential form, the two-dimensional shallow water equations are given as: .. math:: :label: eq:swe2d \begin{bmatrix} h \\ hu \\ hv \end{bmatrix}_t + \begin{bmatrix} hu \\ hu^2 + \frac{1}{2}gh^2 \\ huv \end{bmatrix}_x + \begin{bmatrix} hv \\ huv \\ hv^2 + \frac{1}{2} g h^2 \end{bmatrix}_y = S(x,y,t). :math:`t \in \mathbb{R}^+` is time. :math:`x \in \mathbb{R}` and :math:`y \in \mathbb{R}` are the Cartesian coordinates. The quantities :math:`q = [h, hu, hv]^T` are given through the space-time dependent water height :math:`h(x,y,t)`, the momentum in :math:`x`-direction :math:`hu(x,y,t)` and the momentum in :math:`y`-direction :math:`hv(x,y,t)`. :math:`F := [ hu, hu^2 + \frac{1}{2}gh^2, huv ]^T` is the flux function in :math:`x`-direction, and :math:`G := [ hv, huv, hv^2 + \frac{1}{2} g h^2]^T` the one in :math:`y`-direction. :math:`g` is the used gravity, usually we use :math:`g:=9.80665 \text{m}/\text{s}^2`. As for the one-dimensional shallow water equations, we only consider the space-dependent effect of bathymetry :math:`B(x,y)` in the source term :math:`S(x,y) = [0, -ghB_x, -ghB_y]^T`. The method of dimensional splitting allows us to apply our one-dimensional f-wave solver to the shallow water equations in two spatial dimensions. For this we split the two-dimensional problem into two one-dimensional ones which we solve after each other in so-called sweeps. The :math:`x`-sweep is given as: .. math:: Q_{i,j}^* = Q_{i,j}^n - \frac{\Delta t}{\Delta x} \left( A^+ \Delta Q_{i-1/2,j} + A^- \Delta Q_{i+1/2,j} \right) \quad \forall i \in \{ 1, .., n \}, \; j \in \{ 0, .., n+1 \}. The :math:`y`-sweep is applied to the intermediate values :math:`Q_{i,j}^*` and defined as: .. math:: Q_{i,j}^{n+1} = Q_{i,j}^* - \frac{\Delta t}{\Delta y} \left( B^+ \Delta Q^*_{i,j-1/2} + B^- \Delta Q^*_{i,j+1/2} \right) \quad \forall i,j \in \{ 1, .., n \}. As in the one-dimensional case, a cell :math:`\mathcal{C}_i` is influenced by all neighboring cells which are connected through the net-updates :math:`A^\pm \Delta Q_{i\mp1/2,j}` of the vertical edges :math:`x_{i\mp1/2,j}` and :math:`B^\pm \Delta Q^*_{i,j\mp1/2}` of the horizontal edges :math:`y_{i, j\mp1/2}`. The time step restriction due to the CFL criterion for :math:`\Delta t` is similar to the one-dimensional case but has to be true in the :math:`x`- and :math:`y`-sweep: .. math:: :label: eq:cfl2d \Delta t < \frac{1}{2} \cdot \frac{\Delta x}{\lambda_x^\text{max}}\quad \wedge \quad \Delta t < \frac{1}{2} \cdot \frac{\Delta y}{\lambda_y^\text{max}}, where :math:`\lambda_x^\text{max}` is the maximum eigenvalue appearing in the :math:`x`-sweep and :math:`\lambda_y^\text{max}` the maximum eigenvalue in the :math:`y`-sweep. **Note:** We continue using our constant time step derived in the setup phase. This is valid as long as the CFL-criterion in :eq:`eq:cfl2d` is satisfied for all time steps. .. _tasks-2-2: .. admonition:: Tasks #. Add support for two-dimensional problems to the solver. Implement dimensional splitting through a new class ``patches::WavePropagation2d``. Change other parts of the software as required but keep supporting one-dimensional settings. #. Implement a circular dam break setup in the computational domain :math:`[-50, 50]^2` by using the following initial values: .. math:: \begin{cases} [h, hu, hv]^T = [10, 0, 0]^T &\text{if } \sqrt{x^2+y^2} < 10 \\ [h, hu, hv]^T = [5, 0, 0]^T \quad &\text{else} \end{cases} #. Illustrate your support for bathymetry in two dimensions by adding an obstacle to the computational domain of the circular dam break setup. Stations -------- When solving wave propagation problems, we are often times interested in output at specific points (or stations) of the computational domain. For a given station :math:`s=(x,y)`, a quantity of interest, e.g., the deviation of the water colum from sea level :math:`\eta_s(t) = h_s(t) + b_s(t)` is then typically visualized, compared or analyzed. An example workload, often requiring per-station output, is given through verification and validation. In verification, we might run two solvers with the same inputs and compare the solution at a set of important stations. In validation, we would run our solver, and compare the resulting synthetic data to observed data. .. figure:: data_4/tohoku_dart_stations.png :name: fig:tohoku_dart_stations :align: center :width: 100% Map of some DART stations in the Pacific. The stations are shown as yellow diamonds with their respective ids. :numref:`fig:tohoku_dart_stations` shows a set of stations which are of interest for the 2011 M 9.1 Tohoku tsunami event. Specifically, the locations of some `Deep-ocean Assessment and Reporting of Tsunamis (DART) <https://nctr.pmel.noaa.gov/Dart/>`__ stations are given. For these stations, we can `access <https://www.ncei.noaa.gov/maps/hazards/>`__ data of past tsunami events and thus do validation by comparing our numerical solutions to the measured data. An example of such a comparison is given in :numref:`fig:tohoku_21419`. .. figure:: data_4/tohoku_21419.svg :name: fig:tohoku_21419 :align: center :width: 100% Comparison of synthetic data ("Computed Solution") to observed data ("Measured Data") at DART station 21419 for the 2011 M 9.1 Tohoku tsunami event. .. admonition:: Tasks #. Add a new class ``tsunami_lab::io::Stations`` which summarizes a collection of user-defined stations. Each station has a name and a location in space. All stations share the output frequency in seconds. The output for each station should be written in a separate ASCII-CSV file. #. Find a suitable way to provide the names and locations of each stations to your solver. Further, implement a time step-independent output frequency for the stations. Keep in mind, that this runtime-configuration should be extensible and usable in later parts of the project. One possible solution are XML-based runtime configurations through the library `pugixml <https://pugixml.org/>`__. #. Use a symmetric problem setup, e.g., a circular dam break problem, to compare your two-dimensional solver to your one-dimensional one at a set of stations. #. (optional) Run a "convergence study", i.e., use a synthetic setup and decrease the size of your grid cells. For example, for the computational domain :math:`\Omega = [0, 100\text{m}]^2` you could test mesh-spacings :math:`h \in \{ 50, 25, 10, 7.5, 5, 4, 3, 2, 1 \}`. Compare your solution at a set of points, what do you observe?