OpenSWMM Engine  6.0.0-alpha.1
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.1)
Loading...
Searching...
No Matches
KokkosInertialKernels.hpp
Go to the documentation of this file.
1
24
25#ifndef OPENSWMM_ENGINE_2D_GPU_KOKKOS_INERTIAL_KERNELS_HPP
26#define OPENSWMM_ENGINE_2D_GPU_KOKKOS_INERTIAL_KERNELS_HPP
27
28#include "KokkosSurfaceKernels.hpp" // ExecSpace, DView/CDView/IView/CIView, MeshViews, StateViews
29
30namespace openswmm::twoD::gpu {
31
43
45KOKKOS_INLINE_FUNCTION constexpr double inertialG() { return 9.80665; }
46
47// ---------------------------------------------------------------------------
48// Explicit half F_E: cell sources + continuity divergence + surface-gradient
49// gravity. y layout = [V(0..nt), q(nt..nt+ne)].
50// ---------------------------------------------------------------------------
51inline void evaluateInertialFe(const MeshViews& m, const StateViews& s,
52 const InertialEdgeViews& E,
53 DView y, DView ydot, double dry_depth) {
54 const int nt = m.n_tri;
55 const int ne = E.ne;
56 auto tri_cz = m.tri_cz; auto tri_area = m.tri_area;
57 auto head = s.head; auto depth = s.depth;
58 auto rain = s.rainfall; auto coup = s.coupling_flux; auto evap = s.evap_rate;
59 auto cL = E.cL; auto cR = E.cR; auto xi = E.xi; auto inv_dx = E.inv_dx;
60 auto zface = E.zface; auto cptr = E.cell_ptr; auto cedge = E.cell_edge;
61 auto csign = E.cell_sign;
62 const double G = inertialG();
63
64 // 1. Reconstruct head/depth + cell source forcing.
65 Kokkos::parallel_for("inert_fe_cells", Kokkos::RangePolicy<ExecSpace>(0, nt),
66 KOKKOS_LAMBDA(int i) {
67 const double A = tri_area(i);
68 const double v = y(i) > 0.0 ? y(i) : 0.0;
69 const double d = (A > 1.0e-30) ? v / A : 0.0;
70 depth(i) = d;
71 head(i) = tri_cz(i) + d;
72 ydot(i) = A * (rain(i) + coup(i) - evapSink(evap(i), d, dry_depth));
73 });
74
75 // 2. Continuity divergence added to the cell rows (race-free CSR gather).
76 Kokkos::parallel_for("inert_fe_cont", Kokkos::RangePolicy<ExecSpace>(0, nt),
77 KOKKOS_LAMBDA(int i) {
78 double sgx = 0.0;
79 for (int k = cptr(i); k < cptr(i + 1); ++k) {
80 const int e = cedge(k);
81 sgx += csign(k) * y(nt + e) * xi(e);
82 }
83 ydot(i) -= sgx;
84 });
85
86 // 3. Surface-gradient gravity on the edge rows.
87 Kokkos::parallel_for("inert_fe_grav", Kokkos::RangePolicy<ExecSpace>(0, ne),
88 KOKKOS_LAMBDA(int e) {
89 const int l = cL(e), r = cR(e);
90 const double hf = Kokkos::fmax(head(l), head(r)) - zface(e);
91 ydot(nt + e) = (hf > dry_depth)
92 ? -G * hf * (head(r) - head(l)) * inv_dx(e)
93 : 0.0;
94 });
95}
96
97// ---------------------------------------------------------------------------
98// Implicit half F_I: per-edge friction only (the stiff, diagonal term). Cell
99// rows carry no implicit term (transport is explicit).
100// ---------------------------------------------------------------------------
101inline void evaluateInertialFi(const MeshViews& m, const StateViews& s,
102 const InertialEdgeViews& E,
103 DView y, DView ydot, double dry_depth) {
104 const int nt = m.n_tri;
105 const int ne = E.ne;
106 auto tri_cz = m.tri_cz; auto tri_area = m.tri_area; auto mn = m.mannings_n;
107 auto head = s.head;
108 auto cL = E.cL; auto cR = E.cR; auto zface = E.zface;
109 const double G = inertialG();
110
111 // Reconstruct head (for h_f) and zero the cell rows.
112 Kokkos::parallel_for("inert_fi_cells", Kokkos::RangePolicy<ExecSpace>(0, nt),
113 KOKKOS_LAMBDA(int i) {
114 const double A = tri_area(i);
115 const double v = y(i) > 0.0 ? y(i) : 0.0;
116 head(i) = tri_cz(i) + ((A > 1.0e-30) ? v / A : 0.0);
117 ydot(i) = 0.0;
118 });
119
120 // Friction on the edge rows; dry interface relaxes residual q to 0.
121 Kokkos::parallel_for("inert_fi_fric", Kokkos::RangePolicy<ExecSpace>(0, ne),
122 KOKKOS_LAMBDA(int e) {
123 const int l = cL(e), r = cR(e);
124 const double hf = Kokkos::fmax(head(l), head(r)) - zface(e);
125 const double qe = y(nt + e);
126 double dq;
127 if (hf > dry_depth) {
128 const double n = 0.5 * (mn(l) + mn(r));
129 const double hf73 = Kokkos::pow(hf, 7.0 / 3.0);
130 dq = -G * n * n * qe * Kokkos::fabs(qe) / hf73;
131 } else {
132 dq = -qe;
133 }
134 ydot(nt + e) = dq;
135 });
136}
137
138// ---------------------------------------------------------------------------
139// Block-Jacobi preconditioner. The implicit operator is block-diagonal —
140// I on the cells (no implicit term) and (I+γR) on the edges (friction) — so the
141// preconditioner is its EXACT inverse: identity on cells, w_e=1/(1+γR_e) on
142// edges. No scatter, no global solve.
143// ---------------------------------------------------------------------------
144inline void precondInertialSetup(const MeshViews& m, const StateViews& s,
145 const InertialEdgeViews& E,
146 DView y, DView wq, double gamma, double dry_depth) {
147 const int nt = m.n_tri;
148 const int ne = E.ne;
149 auto tri_cz = m.tri_cz; auto tri_area = m.tri_area; auto mn = m.mannings_n;
150 auto head = s.head;
151 auto cL = E.cL; auto cR = E.cR; auto zface = E.zface;
152 const double G = inertialG();
153
154 Kokkos::parallel_for("inert_pc_head", Kokkos::RangePolicy<ExecSpace>(0, nt),
155 KOKKOS_LAMBDA(int i) {
156 const double A = tri_area(i);
157 const double v = y(i) > 0.0 ? y(i) : 0.0;
158 head(i) = tri_cz(i) + ((A > 1.0e-30) ? v / A : 0.0);
159 });
160
161 Kokkos::parallel_for("inert_pc_wq", Kokkos::RangePolicy<ExecSpace>(0, ne),
162 KOKKOS_LAMBDA(int e) {
163 const int l = cL(e), r = cR(e);
164 const double hf = Kokkos::fmax(head(l), head(r)) - zface(e);
165 double R;
166 if (hf > dry_depth) {
167 const double n = 0.5 * (mn(l) + mn(r));
168 const double hf73 = Kokkos::pow(hf, 7.0 / 3.0);
169 R = 2.0 * G * n * n * Kokkos::fabs(y(nt + e)) / hf73;
170 } else {
171 R = 1.0;
172 }
173 wq(e) = 1.0 / (1.0 + gamma * R);
174 });
175}
176
179inline void precondInertialSolve(int nt, const InertialEdgeViews& E,
180 DView r, DView z, DView wq) {
181 const int ne = E.ne;
182 Kokkos::parallel_for("inert_ps_cells", Kokkos::RangePolicy<ExecSpace>(0, nt),
183 KOKKOS_LAMBDA(int i) { z(i) = r(i); });
184 Kokkos::parallel_for("inert_ps_edges", Kokkos::RangePolicy<ExecSpace>(0, ne),
185 KOKKOS_LAMBDA(int e) { z(nt + e) = wq(e) * r(nt + e); });
186}
187
190inline void writebackEdgeFlux(int nt, const InertialEdgeViews& E,
191 DView y, DView edge_flux) {
192 const int ne = E.ne;
193 const std::size_t n3 = edge_flux.extent(0);
194 auto xi = E.xi; auto slotL = E.slotL; auto slotR = E.slotR;
195 Kokkos::parallel_for("inert_eflux_zero",
196 Kokkos::RangePolicy<ExecSpace>(0, static_cast<int>(n3)),
197 KOKKOS_LAMBDA(int k) { edge_flux(k) = 0.0; });
198 Kokkos::parallel_for("inert_eflux_write", Kokkos::RangePolicy<ExecSpace>(0, ne),
199 KOKKOS_LAMBDA(int e) {
200 const double f = y(nt + e) * xi(e);
201 edge_flux(slotL(e)) = -f;
202 edge_flux(slotR(e)) = +f;
203 });
204}
205
206} // namespace openswmm::twoD::gpu
207
208#endif // OPENSWMM_ENGINE_2D_GPU_KOKKOS_INERTIAL_KERNELS_HPP
Performance-portable RHS pipeline for the 2D surface router (Phase 1).
Definition ArkodeKokkosSurfaceSolver.cpp:29
void evaluateInertialFe(const MeshViews &m, const StateViews &s, const InertialEdgeViews &E, DView y, DView ydot, double dry_depth)
Definition KokkosInertialKernels.hpp:51
Kokkos::View< double *, MemSpace > DView
mutable double array
Definition KokkosSurfaceKernels.hpp:81
Kokkos::View< const double *, MemSpace > CDView
const double array
Definition KokkosSurfaceKernels.hpp:82
Kokkos::View< const int *, MemSpace > CIView
const int array
Definition KokkosSurfaceKernels.hpp:84
void writebackEdgeFlux(int nt, const InertialEdgeViews &E, DView y, DView edge_flux)
Definition KokkosInertialKernels.hpp:190
KOKKOS_INLINE_FUNCTION double evapSink(double rate, double depth, double dry_depth)
Depth-limited evaporation sink (mirrors evapSink()).
Definition KokkosSurfaceKernels.hpp:126
void precondInertialSolve(int nt, const InertialEdgeViews &E, DView r, DView z, DView wq)
Definition KokkosInertialKernels.hpp:179
KOKKOS_INLINE_FUNCTION constexpr double inertialG()
Gravity constant (SI). Matches ArkodeSurfaceSolver.
Definition KokkosInertialKernels.hpp:45
void precondInertialSetup(const MeshViews &m, const StateViews &s, const InertialEdgeViews &E, DView y, DView wq, double gamma, double dry_depth)
Definition KokkosInertialKernels.hpp:144
void evaluateInertialFi(const MeshViews &m, const StateViews &s, const InertialEdgeViews &E, DView y, DView ydot, double dry_depth)
Definition KokkosInertialKernels.hpp:101
double * y
Definition odesolve.c:28
Definition KokkosInertialKernels.hpp:34
int ne
Definition KokkosInertialKernels.hpp:35
CIView cL
Definition KokkosInertialKernels.hpp:36
CIView cell_edge
[nnz] incident edge id
Definition KokkosInertialKernels.hpp:40
CDView zface
[ne] edge length, 1/Δx, interface bed
Definition KokkosInertialKernels.hpp:37
CIView slotL
Definition KokkosInertialKernels.hpp:38
CIView slotR
[ne] flat mesh edge slots for q→edge_flux writeback
Definition KokkosInertialKernels.hpp:38
CDView cell_sign
[nnz] +1 (cell==cL) / −1 (cell==cR)
Definition KokkosInertialKernels.hpp:41
CIView cell_ptr
[n_tri+1] CSR row pointers
Definition KokkosInertialKernels.hpp:39
CDView xi
Definition KokkosInertialKernels.hpp:37
CIView cR
[ne] incident cells (oriented cL→cR)
Definition KokkosInertialKernels.hpp:36
CDView inv_dx
Definition KokkosInertialKernels.hpp:37
Immutable mesh geometry/topology mirrored to device once at initialize().
Definition KokkosSurfaceKernels.hpp:87
CDView tri_area
Definition KokkosSurfaceKernels.hpp:91
CDView mannings_n
[n_tri]
Definition KokkosSurfaceKernels.hpp:91
CDView tri_cz
Definition KokkosSurfaceKernels.hpp:91
int n_tri
Definition KokkosSurfaceKernels.hpp:88
Mutable per-step state mirrored on device.
Definition KokkosSurfaceKernels.hpp:102
DView coupling_flux
Definition KokkosSurfaceKernels.hpp:107
DView head
Definition KokkosSurfaceKernels.hpp:103
DView evap_rate
[n_tri] sources
Definition KokkosSurfaceKernels.hpp:107
DView depth
[n_tri]
Definition KokkosSurfaceKernels.hpp:103
DView rainfall
Definition KokkosSurfaceKernels.hpp:107