OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
InertialKernels.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2//
3// Copyright 2026 Caleb Buahin
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
52
53#ifndef OPENSWMM_ENGINE_2D_INERTIAL_KERNELS_HPP
54#define OPENSWMM_ENGINE_2D_INERTIAL_KERNELS_HPP
55
56#include <algorithm>
57#include <cmath>
58
59#include "../data/MeshData.hpp"
62#include "../mesh/QuadVfr.hpp"
63
64// Portable kernel-function marker (P5 Kokkos port): host builds get plain
65// `inline`; the GPU plugin defines OPENSWMM_KERNEL_FN to
66// KOKKOS_INLINE_FUNCTION *before* including this header so the identical
67// scalar bodies compile for the device (CUDA/HIP/SYCL) as well. The math uses
68// std:: functions deliberately — CUDA/HIP provide device overloads and Kokkos
69// enables relaxed-constexpr; keeping one spelling preserves single-source
70// bit-identity with the serial marcher.
71#ifndef OPENSWMM_KERNEL_FN
72#define OPENSWMM_KERNEL_FN inline
73#endif
74
76
77inline constexpr double kGravity = 9.80665;
78
85inline constexpr double kEtaDeadband = 1.0e-12;
86
96OPENSWMM_KERNEL_FN double qMagnitude(double x, double y) noexcept {
97 return std::sqrt(x * x + y * y);
98}
99
102OPENSWMM_KERNEL_FN void etaDepthScalar(double area, double cz,
103 double z1, double z2, double z3,
104 bool vfr, double vfr_min_wet_frac,
105 double V, double& eta,
106 double& depth) noexcept {
107 const double v = (V > 0.0) ? V : 0.0;
108 depth = (area > 1.0e-30) ? v / area : 0.0;
109 if (vfr) {
110 vfrSort3(z1, z2, z3);
111 eta = vfrEtaFromMeanDepth(z1, z2, z3, depth, vfr_min_wet_frac);
112 } else {
113 eta = cz + depth;
114 }
115}
116
118OPENSWMM_KERNEL_FN double volumeFromEtaScalar(double area, double cz,
119 double z1, double z2, double z3,
120 bool vfr, double vfr_min_wet_frac,
121 double eta) noexcept {
122 if (vfr) {
123 vfrSort3(z1, z2, z3);
124 return area * vfrMeanDepthFromEta(z1, z2, z3, eta, vfr_min_wet_frac);
125 }
126 const double d = eta - cz;
127 return (d > 0.0) ? area * d : 0.0;
128}
129
132OPENSWMM_KERNEL_FN void etaDepthQuadScalar(double area, double cz,
133 const double* zs, double A1, double A2,
134 bool vfr, double vfr_min_wet_frac,
135 double V, double& eta,
136 double& depth) noexcept {
137 const double v = (V > 0.0) ? V : 0.0;
138 depth = (area > 1.0e-30) ? v / area : 0.0;
139 if (vfr) eta = quadEtaFromMeanDepth(zs, A1, A2, depth, vfr_min_wet_frac);
140 else eta = cz + depth;
141}
142
144OPENSWMM_KERNEL_FN double volumeFromEtaQuadScalar(double area, double cz,
145 const double* zs, double A1,
146 double A2, bool vfr,
147 double vfr_min_wet_frac,
148 double eta) noexcept {
149 if (vfr) return area * quadMeanDepthFromEta(zs, A1, A2, eta, vfr_min_wet_frac);
150 const double d = eta - cz;
151 return (d > 0.0) ? area * d : 0.0;
152}
153
154#if defined(__GNUC__) || defined(__clang__)
155#define OPENSWMM_2D_NOINLINE __attribute__((noinline))
156#elif defined(_MSC_VER)
157#define OPENSWMM_2D_NOINLINE __declspec(noinline)
158#else
159#define OPENSWMM_2D_NOINLINE
160#endif
161
169 const SolverOptions2D& o,
170 int i, double V, double& eta,
171 double& depth) noexcept {
172 etaDepthQuadScalar(m.tri_area[i], m.tri_cz[i],
173 &m.quad_vfr_z[static_cast<std::size_t>(i) * kQuadVfrZ],
174 m.quad_vfr_a[static_cast<std::size_t>(i) * 2],
175 m.quad_vfr_a[static_cast<std::size_t>(i) * 2 + 1],
176 true, o.vfr_min_wet_frac, V, eta, depth);
177}
178
183inline void cellEtaDepth(const MeshData& m, const SolverOptions2D& o,
184 int i, double V, double& eta, double& depth) noexcept {
185 // Branch BEFORE the geometry loads: under the default FLAT closure the
186 // three vertex-index loads and the three scattered vz gathers below are
187 // dead, and this is the hottest call in the marcher (every cell, every
188 // firing).
189 if (o.cell_closure != CellClosure2D::VFR) {
190 etaDepthScalar(m.tri_area[i], m.tri_cz[i], 0.0, 0.0, 0.0,
191 false, o.vfr_min_wet_frac, V, eta, depth);
192 return;
193 }
194 if (m.cell_nv[static_cast<std::size_t>(i)] == 4) {
195 cellEtaDepthQuad(m, o, i, V, eta, depth);
196 return;
197 }
198 etaDepthScalar(m.tri_area[i], m.tri_cz[i],
199 m.vz[m.cell_vertex(i, 0)], m.vz[m.cell_vertex(i, 1)],
200 m.vz[m.cell_vertex(i, 2)],
201 true, o.vfr_min_wet_frac, V, eta, depth);
202}
203
207inline double cellVolumeFromEta(const MeshData& m, const SolverOptions2D& o,
208 int i, double eta) noexcept {
209 if (m.cell_nv[static_cast<std::size_t>(i)] == 4) {
211 m.tri_area[i], m.tri_cz[i],
212 &m.quad_vfr_z[static_cast<std::size_t>(i) * kQuadVfrZ],
213 m.quad_vfr_a[static_cast<std::size_t>(i) * 2],
214 m.quad_vfr_a[static_cast<std::size_t>(i) * 2 + 1],
215 o.cell_closure == CellClosure2D::VFR, o.vfr_min_wet_frac, eta);
216 }
217 return volumeFromEtaScalar(m.tri_area[i], m.tri_cz[i],
218 m.vz[m.cell_vertex(i, 0)], m.vz[m.cell_vertex(i, 1)],
219 m.vz[m.cell_vertex(i, 2)],
220 o.cell_closure == CellClosure2D::VFR,
221 o.vfr_min_wet_frac, eta);
222}
223
230OPENSWMM_KERNEL_FN double faceFlowDepth(double etaL, double etaR, double zface) noexcept {
231 return std::max(etaL, etaR) - zface;
232}
233
245OPENSWMM_KERNEL_FN double faceDepthFromEta(double eta, double z_lo, double z_hi) noexcept {
246 if (eta <= z_lo) return 0.0;
247 const double dz = z_hi - z_lo;
248 if (dz < 1.0e-9) return eta - z_lo; // level edge
249 if (eta <= z_hi) {
250 const double t = eta - z_lo;
251 return t * t / (2.0 * dz);
252 }
253 return eta - 0.5 * (z_lo + z_hi);
254}
255
262OPENSWMM_KERNEL_FN double faceFlowDepthVfr(double etaL, double etaR,
263 double z_lo, double z_hi) noexcept {
264 return faceDepthFromEta(std::max(etaL, etaR), z_lo, z_hi);
265}
266
282OPENSWMM_KERNEL_FN double inertialFaceUpdate(double q, double qhat, double hf, double dt,
283 double slope, double n2,
284 double q_mag, double adv = 0.0) noexcept {
285 const double h73 = hf * hf * std::cbrt(hf);
286 const double num = qhat - dt * (kGravity * hf * slope + adv);
287 const double den = 1.0 + kGravity * dt * n2 * q_mag / h73;
288 return num / den;
289}
290
306OPENSWMM_KERNEL_FN double inertialAdvection(double q_f, double unL, double hL,
307 double unR, double hR,
308 double inv_dx_normal) noexcept {
309 const double FL = unL * ((unL > 0.0) ? hL * unL : q_f);
310 const double FR = unR * ((unR > 0.0) ? q_f : hR * unR);
311 return (FR - FL) * inv_dx_normal;
312}
313
317OPENSWMM_KERNEL_FN double froudeCap(double q, double hf, double fr_max) noexcept {
318 const double qcap = fr_max * hf * std::sqrt(kGravity * hf);
319 return std::clamp(q, -qcap, qcap);
320}
321
325OPENSWMM_KERNEL_FN double cellCflDt(double alpha, double lchar, double h,
326 double speed) noexcept {
327 const double c = std::sqrt(kGravity * h) + speed;
328 return (c > 1.0e-12) ? alpha * lchar / c : 1.0e30;
329}
330
335OPENSWMM_KERNEL_FN double positivityScale(double V, double outflow_m3s, double dt,
336 double beta) noexcept {
337 if (outflow_m3s <= 0.0 || dt <= 0.0) return 1.0;
338 const double avail = beta * std::max(V, 0.0);
339 const double take = outflow_m3s * dt;
340 return (take <= avail) ? 1.0 : avail / take;
341}
342
343} // namespace openswmm::twoD::inertial
344
345#endif // OPENSWMM_ENGINE_2D_INERTIAL_KERNELS_HPP
#define OPENSWMM_KERNEL_FN
Definition ExplicitKokkosSurfaceSolver.cpp:18
#define OPENSWMM_2D_NOINLINE
Definition InertialKernels.hpp:159
Structure-of-Arrays (SoA) storage for 2D triangular mesh geometry.
Volume–free-surface relationship (VFR) for a quadrilateral cell.
Configuration options for the 2D surface routing solver.
Volume–free-surface (VFR) closure for a planar-bed triangular cell.
Definition InertialKernels.hpp:75
void cellEtaDepth(const MeshData &m, const SolverOptions2D &o, int i, double V, double &eta, double &depth) noexcept
Definition InertialKernels.hpp:183
OPENSWMM_KERNEL_FN double froudeCap(double q, double hf, double fr_max) noexcept
Definition InertialKernels.hpp:317
OPENSWMM_KERNEL_FN double qMagnitude(double x, double y) noexcept
Definition InertialKernels.hpp:96
double cellVolumeFromEta(const MeshData &m, const SolverOptions2D &o, int i, double eta) noexcept
Definition InertialKernels.hpp:207
OPENSWMM_KERNEL_FN double inertialAdvection(double q_f, double unL, double hL, double unR, double hR, double inv_dx_normal) noexcept
Definition InertialKernels.hpp:306
OPENSWMM_KERNEL_FN double cellCflDt(double alpha, double lchar, double h, double speed) noexcept
Definition InertialKernels.hpp:325
constexpr double kEtaDeadband
Definition InertialKernels.hpp:85
OPENSWMM_KERNEL_FN double volumeFromEtaScalar(double area, double cz, double z1, double z2, double z3, bool vfr, double vfr_min_wet_frac, double eta) noexcept
Scalar core of the η → V inverse (device-callable).
Definition InertialKernels.hpp:118
OPENSWMM_2D_NOINLINE void cellEtaDepthQuad(const MeshData &m, const SolverOptions2D &o, int i, double V, double &eta, double &depth) noexcept
Definition InertialKernels.hpp:168
OPENSWMM_KERNEL_FN void etaDepthScalar(double area, double cz, double z1, double z2, double z3, bool vfr, double vfr_min_wet_frac, double V, double &eta, double &depth) noexcept
Definition InertialKernels.hpp:102
OPENSWMM_KERNEL_FN double positivityScale(double V, double outflow_m3s, double dt, double beta) noexcept
Definition InertialKernels.hpp:335
OPENSWMM_KERNEL_FN double faceFlowDepth(double etaL, double etaR, double zface) noexcept
Definition InertialKernels.hpp:230
OPENSWMM_KERNEL_FN double volumeFromEtaQuadScalar(double area, double cz, const double *zs, double A1, double A2, bool vfr, double vfr_min_wet_frac, double eta) noexcept
Quad η → V inverse (device-callable).
Definition InertialKernels.hpp:144
OPENSWMM_KERNEL_FN double inertialFaceUpdate(double q, double qhat, double hf, double dt, double slope, double n2, double q_mag, double adv=0.0) noexcept
Definition InertialKernels.hpp:282
OPENSWMM_KERNEL_FN void etaDepthQuadScalar(double area, double cz, const double *zs, double A1, double A2, bool vfr, double vfr_min_wet_frac, double V, double &eta, double &depth) noexcept
Definition InertialKernels.hpp:132
constexpr double kGravity
matches the existing kernels
Definition InertialKernels.hpp:77
OPENSWMM_KERNEL_FN double faceDepthFromEta(double eta, double z_lo, double z_hi) noexcept
Definition InertialKernels.hpp:245
OPENSWMM_KERNEL_FN double faceFlowDepthVfr(double etaL, double etaR, double z_lo, double z_hi) noexcept
Definition InertialKernels.hpp:262
OPENSWMM_KERNEL_FN double vfrMeanDepthFromEta(double z1, double z2, double z3, double eta, double eps) noexcept
Definition VfrClosure.hpp:144
OPENSWMM_KERNEL_FN void vfrSort3(double &z1, double &z2, double &z3) noexcept
Sort three vertex elevations in place so z1 <= z2 <= z3.
Definition VfrClosure.hpp:78
constexpr int kQuadVfrZ
Definition QuadVfr.hpp:73
OPENSWMM_KERNEL_FN double quadEtaFromMeanDepth(const double *zs, double A1, double A2, double mean_depth, double eps) noexcept
Definition QuadVfr.hpp:125
OPENSWMM_KERNEL_FN double quadMeanDepthFromEta(const double *zs, double A1, double A2, double eta, double eps) noexcept
Definition QuadVfr.hpp:86
OPENSWMM_KERNEL_FN double vfrEtaFromMeanDepth(double z1, double z2, double z3, double mean_depth, double eps) noexcept
Definition VfrClosure.hpp:165
@ VFR
Planar-bed VFR closure (regularized), CPU solvers only.
Definition SolverOptions2D.hpp:61
double * y
Definition odesolve.c:28
SoA storage for 2D mixed triangle/quad mesh geometry and topology.
Definition MeshData.hpp:67
Configuration for the 2D surface routing solver.
Definition SolverOptions2D.hpp:208