 |
Peano
|
Go to the documentation of this file.
7 **** F-Wave Riemann Solver for the Shallow Water Equation
10 * This solver does not support inundation. For dry cells, we assume an infinitely high solid wall
11 * at the shore-line, which is equivalent to reflecting boundary conditions. Thus no water is
12 * able to pass the shoreline, and we have to assure that the particle velocity at the boundary is
17 * @article{bale2002wave,
18 * title={A wave propagation method for conservation laws and balance laws with spatially varying flux functions},
19 * author={Bale, D.S. and LeVeque, R.J. and Mitran, S. and Rossmanith, J.A.}, journal={SIAM Journal on Scientific Computing},
24 * publisher={Citeseer}}
26 * @book{leveque2002finite,
27 * Author = {LeVeque, R. J.},
28 * Date-Added = {2011-09-13 14:09:31 +0000},
29 * Date-Modified = {2011-10-31 09:46:40 +0000},
30 * Publisher = {Cambridge University Press},
31 * Title = {Finite Volume Methods for Hyperbolic Problems},
35 * @webpage{levequeclawpack,
36 * Author = {LeVeque, R. J.},
37 * Lastchecked = {January, 05, 2011},
38 * Title = {Clawpack Sofware},
39 * Url = {https://github.com/clawpack/clawpack-4.x/blob/master/geoclaw/2d/lib}}
43 enum class WetDryState {
44 DryDry, /**< Both cells are dry. */
45 WetWet, /**< Both cells are wet. */
46 WetDryInundation, /**< 1st cell: wet, 2nd cell: dry. 1st cell lies higher than the 2nd one. */
47 WetDryWall, /**< 1st cell: wet, 2nd cell: dry. 1st cell lies lower than the 2nd one. Momentum is not large enough to overcome the difference. */
48 WetDryWallInundation, /**< 1st cell: wet, 2nd cell: dry. 1st cell lies lower than the 2nd one. Momentum is large enough to overcome the difference. */
49 DryWetInundation, /**< 1st cell: dry, 2nd cell: wet. 1st cell lies lower than the 2nd one. */
50 DryWetWall, /**< 1st cell: dry, 2nd cell: wet. 1st cell lies higher than the 2nd one. Momentum is not large enough to overcome the difference. */
51 DryWetWallInundation /**< 1st cell: dry, 2nd cell: wet. 1st cell lies higher than the 2nd one. Momentum is large enough to overcome the difference. */
54 // Set speeds to zero (will be determined later)
58 // Not const here as they may get reassigned due to boundary conditions
59 double hLeft = QL[Shortcuts::h];
60 double hRight = QR[Shortcuts::h];
61 double huLeft = QL[Shortcuts::hu + normal];
62 double huRight = QR[Shortcuts::hu + normal];
63 double bLeft = QL[Shortcuts::z];
64 double bRight = QR[Shortcuts::z];
66 //! Wet/dry state of our Riemann-problem
67 WetDryState wetDryState = WetDryState::WetWet; // Assume everything is wet
69 // Determine the wet/dry state
70 if (hLeft <= hThreshold && hRight <= hThreshold) { // Both cells are dry
71 wetDryState = WetDryState::DryDry;
72 } else if (hLeft <= hThreshold) { // Left cell dry, right cell wet
73 uRight = huRight / hRight;
74 // Set wall boundary conditions (inundation is not supported!)
79 wetDryState = WetDryState::DryWetWall;
80 } else if (hRight <= hThreshold) { // Left cell wet, right cell dry
81 uLeft = huLeft / hLeft;
86 wetDryState = WetDryState::WetDryWall;
88 uLeft = huLeft / hLeft;
89 uRight = huRight / hRight;
90 wetDryState = WetDryState::WetWet;
93 // Zero updates in the beginning
94 for (int i = 0; i < 3; i++) {
99 // Return in the case of dry cells
100 if (wetDryState == WetDryState::DryDry) {
104 // Compute eigenvalues of the Jacobian matrices in states Q_{i-1} and Q_{i}
105 const double hRoe = 0.5 * (hRight + hLeft);
106 const double uRoe = (uLeft * std::sqrt(hLeft) + uRight * std::sqrt(hRight)) / (std::sqrt(hLeft) + std::sqrt(hRight));
107 const double roeSpeeds[2] = {uRoe - std::sqrt(g * hRoe), uRoe + std::sqrt(g * hRoe)};
108 const double characteristicSpeeds[2] = {uLeft - std::sqrt(g * hLeft), uRight + std::sqrt(g * hRight)};
109 const double einfeldtSpeeds[2] = {std::fmin(characteristicSpeeds[0], roeSpeeds[0]), std::fmax(characteristicSpeeds[1], roeSpeeds[1])};
111 // Set wave speeds (lambda Roe)
112 //! Wave speeds of the f-waves
113 const double waveSpeeds[2] {einfeldtSpeeds[0], einfeldtSpeeds[1]};
114 const double deltaLambda = waveSpeeds[1] - waveSpeeds[0];
116 #if !defined(WITH_GPU)
117 // Wave speed of the 1st wave family should be less than the speed of the 2nd wave family.
118 assertion(waveSpeeds[0] < waveSpeeds[1]);
119 assertion(std::fabs(deltaLambda) > 0); // Make sure we do not divide by 0
122 const double inverseDeltaLambda = 1.0 / deltaLambda;
124 // Compute the inverse matrix R^{-1} to obtain Eigencoefficients (alpha)
128 // \lambda_{1} \lambda_{2}
130 // Inverse: https://mathworld.wolfram.com/MatrixInverse.html
134 // deltaLambda -\lambda_{1} 1
135 const double Rinv[2][2] {
136 { inverseDeltaLambda * waveSpeeds[1], -inverseDeltaLambda },
137 { inverseDeltaLambda * -waveSpeeds[0], inverseDeltaLambda }
141 const double fluxLeft[2] {huLeft, huLeft * uLeft + 0.5 * g * hLeft * hLeft};
142 const double fluxRight[2] {huRight, huRight * uRight + 0.5 * g * hRight * hRight};
144 // Add source term (bathymetry) into the decomposition of the jump in the flux function
145 const double deltaxPsi = -g * (bRight - bLeft) * hRoe;
146 // Calculate flux difference f(Q_i) - f(Q_{i-1})
147 const double deltaFlux[2] {fluxRight[0] - fluxLeft[0], fluxRight[1] - fluxLeft[1] - deltaxPsi};
149 // Solve linear equations
150 const double alpha[2] {
151 Rinv[0][0] * deltaFlux[0] + Rinv[0][1] * deltaFlux[1],
152 Rinv[1][0] * deltaFlux[0] + Rinv[1][1] * deltaFlux[1]
156 const double fWaves[2][2] {
157 { alpha[0], alpha[0] * waveSpeeds[0] },
158 { alpha[1], alpha[1] * waveSpeeds[1] }
161 // Compute the net-updates
162 double hUpdateLeft = 0.0;
163 double hUpdateRight = 0.0;
164 double huUpdateLeft = 0.0;
165 double huUpdateRight = 0.0;
167 constexpr double ZERO_TOL = std::numeric_limits<double>::epsilon();
169 if (waveSpeeds[0] < ZERO_TOL) { // Left going
170 hUpdateLeft += fWaves[0][0];
171 huUpdateLeft += fWaves[0][1];
172 } else if (waveSpeeds[0] > ZERO_TOL) { // Right going
173 hUpdateRight -= fWaves[0][0];
174 huUpdateRight -= fWaves[0][1];
175 } else { // Split waves
176 hUpdateLeft += 0.5 * fWaves[0][0];
177 huUpdateLeft += 0.5 * fWaves[0][1];
178 hUpdateRight -= 0.5 * fWaves[0][0];
179 huUpdateRight -= 0.5 * fWaves[0][1];
183 if (waveSpeeds[1] < ZERO_TOL) { // Left going
184 hUpdateLeft += fWaves[1][0];
185 huUpdateLeft += fWaves[1][1];
186 } else if (waveSpeeds[1] > ZERO_TOL) { // Right going
187 hUpdateRight -= fWaves[1][0];
188 huUpdateRight -= fWaves[1][1];
189 } else { // Split waves
190 hUpdateLeft += 0.5 * fWaves[1][0];
191 huUpdateLeft += 0.5 * fWaves[1][1];
192 hUpdateRight -= 0.5 * fWaves[1][0];
193 huUpdateRight -= 0.5 * fWaves[1][1];
196 // Zero ghost updates (wall boundary)
197 if (wetDryState == WetDryState::WetDryWall) {
200 } else if (wetDryState == WetDryState::DryWetWall) {
205 // Compute maximum wave speed (-> CFL-condition)
206 const double maxWaveSpeed = std::fmax(std::fabs(waveSpeeds[0]), std::fabs(waveSpeeds[1]));
208 #if !defined(WITH_GPU)
209 assertion(!std::isnan(hUpdateLeft));
210 assertion(!std::isnan(hUpdateRight));
211 assertion(!std::isnan(huUpdateLeft));
212 assertion(!std::isnan(huUpdateRight));
213 assertion(!std::isnan(maxWaveSpeed));
217 FL[Shortcuts::h] = hUpdateLeft;
218 FR[Shortcuts::h] = hUpdateRight;
219 FL[normal + 1] = huUpdateLeft;
220 FR[normal + 1] = huUpdateRight;