Peano
Loading...
Searching...
No Matches
FVSolver.cpp
Go to the documentation of this file.
1// This file is part of the ExaHyPE2 project. For conditions of distribution and
2// use, please see the copyright notice at www.peano-framework.org
3#include "FVSolver.h"
4
5#include "Constants.h"
8
9tarch::logging::Log applications::exahype2::swe::FVSolver::_log("applications::exahype2::swe::FVSolver");
10
11
12void applications::exahype2::swe::FVSolver::initialCondition(
13 [[maybe_unused]] double* const NOALIAS Q, // Q[3+1]
14 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
15 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
16 [[maybe_unused]] const bool gridIsConstructed
17) {
18 Q[Shortcuts::h] = 100;
19 Q[Shortcuts::hu] = 0;
20 Q[Shortcuts::hv] = 0;
21 Q[Shortcuts::b] = -100;
22}
23
24
25void applications::exahype2::swe::FVSolver::boundaryConditions(
26 [[maybe_unused]] const double* const NOALIAS Qinside, // Qinside[3+1]
27 [[maybe_unused]] double* const NOALIAS Qoutside, // Qoutside[3+1]
28 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
29 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
30 [[maybe_unused]] const double t,
31 [[maybe_unused]] const int normal
32) {
33 Qoutside[Shortcuts::h] = Qinside[Shortcuts::h];
34 Qoutside[Shortcuts::hu] = -Qinside[Shortcuts::hu];
35 Qoutside[Shortcuts::hv] = -Qinside[Shortcuts::hv];
36 Qoutside[Shortcuts::b] = Qinside[Shortcuts::b];
37}
38
39
40::exahype2::RefinementCommand applications::exahype2::swe::FVSolver::refinementCriterion(
41 [[maybe_unused]] const double* const NOALIAS Q, // Q[3+1]
42 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
43 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
44 [[maybe_unused]] const double t
45) {
46 auto result = ::exahype2::RefinementCommand::Keep;
47 // @todo Implement
48 return result;
49}
50
51
52double applications::exahype2::swe::FVSolver::maxEigenvalue(
53 [[maybe_unused]] const double* const NOALIAS Q, // Q[3+1]
54 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
55 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
56 [[maybe_unused]] const double t,
57 [[maybe_unused]] const double dt,
58 [[maybe_unused]] const int normal
59) {
60 double L[3];
61 L[Shortcuts::h] = 0.0;
62 L[Shortcuts::hu] = 0.0;
63 L[Shortcuts::hv] = 0.0;
64
65 constexpr double DRY_TOL = std::numeric_limits<double>::epsilon();
66 if (Q[Shortcuts::h] <= DRY_TOL) {
67 return 0.0;
68 }
69
70 const double u = Q[Shortcuts::hu + normal] / Q[Shortcuts::h];
71 const double c = std::sqrt(GRAV * Q[Shortcuts::h]);
72 L[Shortcuts::h] = u;
73 L[Shortcuts::hu] = u + c;
74 L[Shortcuts::hv] = u - c;
75
76 return std::fmax(std::fabs(L[0]), std::fmax(std::fabs(L[1]), std::fabs(L[2])));
77}
78
79
80void applications::exahype2::swe::FVSolver::flux(
81 [[maybe_unused]] const double* const NOALIAS Q, // Q[3+1]
82 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
83 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
84 [[maybe_unused]] const double t,
85 [[maybe_unused]] const double dt,
86 [[maybe_unused]] const int normal,
87 [[maybe_unused]] double* const NOALIAS F // F[3]
88) {
89 F[Shortcuts::h] = 0.0;
90 F[Shortcuts::hu] = 0.0;
91 F[Shortcuts::hv] = 0.0;
92 F[Shortcuts::b] = 0.0;
93
94 constexpr double DRY_TOL = std::numeric_limits<double>::epsilon();
95 if (Q[Shortcuts::h] <= DRY_TOL) {
96 return;
97 }
98
99 const double ih = 1.0 / Q[Shortcuts::h];
100
101 F[Shortcuts::h] = Q[Shortcuts::hu + normal];
102 F[Shortcuts::hu] = Q[Shortcuts::hu + normal] * Q[Shortcuts::hu] * ih;
103 F[Shortcuts::hv] = Q[Shortcuts::hu + normal] * Q[Shortcuts::hv] * ih;
104 F[Shortcuts::hu + normal] += 0.5 * GRAV * Q[Shortcuts::h] * Q[Shortcuts::h];
105}
106
107
108void applications::exahype2::swe::FVSolver::nonconservativeProduct(
109 [[maybe_unused]] const double* const NOALIAS Q, // Q[3+1]
110 [[maybe_unused]] const double* const NOALIAS deltaQ, // deltaQ[3+1]
111 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
112 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
113 [[maybe_unused]] const double t,
114 [[maybe_unused]] const double dt,
115 [[maybe_unused]] const int normal,
116 [[maybe_unused]] double* const NOALIAS BTimesDeltaQ // BTimesDeltaQ[3]
117) {
118 BTimesDeltaQ[Shortcuts::h] = 0.0;
119 BTimesDeltaQ[Shortcuts::hu] = 0.0;
120 BTimesDeltaQ[Shortcuts::hv] = 0.0;
121 BTimesDeltaQ[Shortcuts::b] = 0.0;
122
123 constexpr double DRY_TOL = std::numeric_limits<double>::epsilon();
124 if (Q[Shortcuts::h] <= DRY_TOL) {
125 return;
126 }
127
128 BTimesDeltaQ[Shortcuts::hu + normal] = GRAV * Q[Shortcuts::h] * (deltaQ[Shortcuts::h] + deltaQ[Shortcuts::b]);
129}
130
132 namespace {
145 auto constant([[maybe_unused]] const auto x, [[maybe_unused]] const auto y) {
152
153 return 1.04e-4; // Example value for mid-latitudes
154 };
155
168 auto betaPlane([[maybe_unused]] const auto x, [[maybe_unused]] const auto y) {
175
176 constexpr double f0 = 1.0e-4; // f0 = reference Coriolis value
177 constexpr double beta = 2.0e-11; // β: meridional gradient of the Coriolis parameter (df/dy), used in β-plane
178 // approximation
179 return f0 + (beta * y);
180 };
181
194 auto sphere([[maybe_unused]] const auto x, [[maybe_unused]] const auto y) {
202
203 constexpr double omega = 7.2921150e-5;
204 constexpr double toRad = M_PI / 180.0;
205
206 const auto [lon, lat] = projection::albers_equal_area::ellipsoid::inverse(x, y);
207 const auto latRad = lat * toRad;
208 return 2.0 * omega * std::sin(latRad);
209 };
210 } // namespace
211} // namespace corriolis_force
212
213namespace {
229 auto manningFriction(const auto h, const auto hu, const auto hv) {
230 namespace constants = ::applications::exahype2::swe;
231 constexpr auto manningFriction = 0.025; // sm^(1/3)
232 constexpr auto hMin = 0.2; // threshold to ensure stable bottom friction computation when h → 0
233
234 const auto hSafe = (h > hMin ? h : hMin); // minimal water depth to avoid division by zero or instability near
235 // dry cells
236 const auto h43 = (hSafe * std::cbrt(hSafe)); // h^(4/3) is not stable for small h -> 0, TODO may need some more
237 // work
238
239 return -constants::GRAV * manningFriction * manningFriction * std::sqrt((hu * hu) + (hv * hv)) / h43;
240 }
241
242 auto atmosphericPressure(const auto x, const auto y, const auto t) {
243 namespace constants = ::applications::exahype2::swe;
244 constexpr auto aLon = constants::pointLonA;
245 constexpr auto aLat = constants::pointLatA;
246
247 constexpr auto bLon = constants::pointLonB;
248 constexpr auto bLat = constants::pointLatB;
249
250 // https://edanya.uma.es/hysea/index.php/benchmarks/meteo-tsunami/143-reproducing-real-meteotsunami-in-the-gulf-of-mexico
251 auto pressureGaus = [](const auto x, const auto y) {
252 constexpr auto C = 0.5;
253 constexpr auto AL = 37.61;
254 constexpr auto AR = 4.665;
255 constexpr auto BL = 0.31;
256 constexpr auto BR = 0.5;
257 const auto y2 = ((y / C) * (y / C));
258 if (x < 0) {
259 return -AL * x * std::exp(-y2 - ((x / BL) * (x / BL)));
260 }
261 if (x > 0) {
262 return -AR * x * std::exp(-y2 - ((x / BR) * (x / BR)));
263 }
264 return 0.0;
265 };
266
267 auto distanceOverTime = [](const auto t) {
268 constexpr auto speed = 20.0; // 20 m/s
269 return speed * t;
270 };
271
272 // Computes the geographic point at distance l (in meters) along the great-circle vector from a to b,
273 // using projected coordinates for distance calculation and linear interpolation in lon/lat.
274 auto pointOnVector = [](const auto l) {
275 const auto [aX, aY] = projection::albers_equal_area::ellipsoid::forward(aLon, aLat);
276 const auto [bX, bY] = projection::albers_equal_area::ellipsoid::forward(bLon, bLat);
277 static const auto distance = std::sqrt(((bX - aX) * (bX - aX)) + ((bY - aY) * (bY - aY)));
278 return std::pair{aLon + (l * (bLon - aLon) / distance), aLat + (l * (bLat - aLat) / distance)};
279 };
280
281 // Rotates (lon, lat) so that the path from a to b lies along the x-axis; used to align atmospheric pressure
282 // spatially.
283 auto rotLonLat = [](const auto lon, const auto lat) {
284 constexpr auto dLon = bLon - aLon;
285 constexpr auto dLat = bLat - aLat;
286
287 static const auto rad = std::atan2(dLat, dLon);
288
289 static const auto sin = std::sin(rad);
290 static const auto cos = std::cos(rad);
291
292 const auto lonNew = (lon * cos) + (lat * sin);
293 const auto latNew = (-lon * sin) + (lat * cos);
294 return std::pair{lonNew, latNew};
295 };
296
297 const auto distance = distanceOverTime(t);
298 const auto [lon, lat] = projection::albers_equal_area::ellipsoid::inverse(x, y);
299 const auto [lonCenter, latCenter] = pointOnVector(distance);
300 const auto [lonRot, latRot] = rotLonLat(lon - lonCenter, lat - latCenter);
301 return pressureGaus(lonRot, latRot);
302 };
303} // namespace
304
305void applications::exahype2::swe::FVSolver::sourceTerm(
306 [[maybe_unused]] const double* const NOALIAS Q, // Q[3+1]
307 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& x,
308 [[maybe_unused]] const tarch::la::Vector<DIMENSIONS, double>& h,
309 [[maybe_unused]] const double t,
310 [[maybe_unused]] const double dt,
311 [[maybe_unused]] double* const NOALIAS S // S[3]
312) {
313 namespace constants = ::applications::exahype2::swe;
314
320
321 // default values
322 S[Shortcuts::h] = 0;
323 S[Shortcuts::hu] = 0;
324 S[Shortcuts::hv] = 0;
325
326 // Skip dry cells
327 constexpr double DRY_TOL = std::numeric_limits<double>::epsilon();
328 if (Q[Shortcuts::h] <= DRY_TOL) {
329 return;
330 }
331
339 constexpr auto waterDensity = constants::waterDensity;
340
341 const auto xCoord = x(0);
342 const auto yCoord = x(1);
343
344 const auto uVel = Q[Shortcuts::hu] / Q[Shortcuts::h];
345 const auto vVel = Q[Shortcuts::hv] / Q[Shortcuts::h];
346
347 // Update Source term
348 S[Shortcuts::hu] = corriolis_force::sphere(xCoord, yCoord) * uVel;
349 S[Shortcuts::hv] = -corriolis_force::sphere(xCoord, yCoord) * vVel;
350
351 S[Shortcuts::hu] += manningFriction(Q[Shortcuts::h], Q[Shortcuts::hu], Q[Shortcuts::hv]) * Q[Shortcuts::hu];
352 S[Shortcuts::hv] += manningFriction(Q[Shortcuts::h], Q[Shortcuts::hu], Q[Shortcuts::hv]) * Q[Shortcuts::hv];
353
354 auto wrapperAtmosphericPressure = [](const auto x, const auto y, const auto t) {
355 return atmosphericPressure(x, y, t);
356 };
357
359 partialX(wrapperAtmosphericPressure, xCoord, yCoord, t)
360 / waterDensity;
362 partialY(wrapperAtmosphericPressure, xCoord, yCoord, t)
363 / waterDensity;
364}
auto partialY(auto f, const auto x, const auto y, const auto t)
Approximates the partial derivative ∂f/∂y of a function f(x, y, t) using central differences.
auto partialX(auto f, const auto x, const auto y, const auto t)
Approximates the partial derivative ∂f/∂x of a function f(x, y, t) using central differences.
auto inverse(const auto x, const auto y)
Inverts the Albers Equal-Area Conic projection for WGS_1984 and returns the geographic coordinates (l...
auto forward(const auto lon, const auto lat)