OpenSWMM Engine  6.0.0-alpha.1
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.1)
Loading...
Searching...
No Matches
XSectLookup.hpp
Go to the documentation of this file.
1
39
40#ifndef OPENSWMM_XSECT_LOOKUP_HPP
41#define OPENSWMM_XSECT_LOOKUP_HPP
42
43namespace openswmm::xsect {
44
54inline double lookup_exact(double x, const double* t, int n) noexcept {
55 const double delta = 1.0 / static_cast<double>(n - 1); // same rounding as legacy
56 int i = static_cast<int>(x / delta); // DIVIDE (legacy), not x*inv_delta
57 if (i >= n - 1) return t[n - 1];
58
59 double x0 = i * delta;
60 double y = t[i] + (x - x0) * (t[i + 1] - t[i]) / delta; // grouping matches legacy
61
62 if (i < 2) { // quadratic refinement for low x
63 double x1 = (static_cast<double>(i) + 1.0) * delta;
64 double y2 = y + (x - x0) * (x - x1) / (delta * delta) *
65 (t[i] / 2.0 - t[i + 1] + t[i + 2] / 2.0);
66 if (y2 > 0.0) y = y2;
67 }
68 if (y < 0.0) y = 0.0;
69 return y;
70}
71
72// ============================================================================
73// Fast mode (opt-in, NOT bit-exact) — plan §6.
74//
75// Enabled per-build with -DSWMM_XSECT_FAST_LOOKUP. Substitutes the baseline
76// reciprocal-multiply form: normalize by a precomputed 1/y_full and index /
77// interpolate with `* inv_delta` (inv_delta = N-1 is an EXACT integer) instead
78// of `/ delta`. This removes ~3 IEEE divisions per element (measured ~25% faster
79// in the fused circular kernel on arm64) at the cost of ULP-level deviation from
80// legacy (measured well inside the abs 1e-8 / rel 1e-7 tolerance gate — see
81// tests/unit/engine/test_xsect_parity.cpp XSectFastMode). Default OFF: the
82// bit-exact `lookup_exact` path above is the shipped default.
83//
84// `lookup_fast` is always compiled (so the tolerance test can assert its bound
85// regardless of the active default), but is only *wired into the kernels* when
86// SWMM_XSECT_FAST_LOOKUP is defined.
87// ============================================================================
88
90inline double lookup_fast(double x, const double* t, int n) noexcept {
91 const double inv_delta = static_cast<double>(n - 1); // exact integer
92 const double delta = 1.0 / inv_delta;
93 if (x < 0.0) x = 0.0; else if (x > 1.0) x = 1.0; // fast mode pre-clamps
94 int i = static_cast<int>(x * inv_delta);
95 if (i >= n - 1) return t[n - 1];
96 double x0 = i * delta;
97 double y = t[i] + (x - x0) * (t[i + 1] - t[i]) * inv_delta;
98 if (i < 2) {
99 double x1 = (static_cast<double>(i) + 1.0) * delta;
100 double y2 = y + (x - x0) * (x - x1) * (inv_delta * inv_delta) *
101 (t[i] / 2.0 - t[i + 1] + t[i + 2] / 2.0);
102 if (y2 > 0.0) y = y2;
103 }
104 if (y < 0.0) y = 0.0;
105 return y;
106}
107
108// Mode-aware normalization. In the default (bit-exact) build `param` is y_full
109// and x = y/yFull via IEEE divide; under SWMM_XSECT_FAST_LOOKUP `param` is the
110// precomputed inv_y_full and x = depth*inv (clamped). The kernels feed the
111// matching per-link array (see XSectBatch.cpp norm_param()).
112inline double norm_x(double depth, double param) noexcept {
113#ifdef SWMM_XSECT_FAST_LOOKUP
114 double x = depth * param; // param == inv_y_full
115 if (x < 0.0) x = 0.0; else if (x > 1.0) x = 1.0;
116 return x;
117#else
118 return (param > 0.0 && depth > 0.0) ? (depth / param) : 0.0; // param == y_full
119#endif
120}
121
123inline double norm_lookup(double depth, double param, const double* t, int n) noexcept {
124#ifdef SWMM_XSECT_FAST_LOOKUP
125 return lookup_fast(norm_x(depth, param), t, n);
126#else
127 return lookup_exact(norm_x(depth, param), t, n);
128#endif
129}
130
131} // namespace openswmm::xsect
132
133#endif // OPENSWMM_XSECT_LOOKUP_HPP
Definition XSectBatch.hpp:126
double lookup_fast(double x, const double *t, int n) noexcept
Reciprocal-multiply lookup (fast, NOT bit-exact — see §6).
Definition XSectLookup.hpp:90
double norm_lookup(double depth, double param, const double *t, int n) noexcept
Mode-aware normalize + table lookup (bit-exact by default; §6 fast if opted in).
Definition XSectLookup.hpp:123
double lookup_exact(double x, const double *t, int n) noexcept
Bit-exact transliteration of legacy xsect.c:lookup().
Definition XSectLookup.hpp:54
double norm_x(double depth, double param) noexcept
Definition XSectLookup.hpp:112
double * y
Definition odesolve.c:28