OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
UnitConversion.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
40
41#ifndef OPENSWMM_UNIT_CONVERSION_HPP
42#define OPENSWMM_UNIT_CONVERSION_HPP
43
44#include <array>
45
46namespace openswmm {
47
49
50namespace ucf {
51
52// ============================================================================
53// Quantity codes — matching legacy enums.h
54// ============================================================================
55
69
70// ============================================================================
71// Conversion factor tables — identical to legacy Ucf[10][2] and Qcf[6]
72// ============================================================================
73
76static constexpr double Ucf[10][2] = {
77 // US SI
78 {43200.0, 1097280.0}, // RAINFALL: in/hr, mm/hr → ft/sec
79 {12.0, 304.8}, // RAINDEPTH: in, mm → ft
80 {1036800.0, 26334720.0}, // EVAPRATE: in/day, mm/day → ft/sec
81 {1.0, 0.3048}, // LENGTH: ft, m → ft
82 {2.2956e-5, 0.92903e-5}, // LANDAREA: ac, ha → ft²
83 {1.0, 0.02832}, // VOLUME: ft³, m³ → ft³
84 {1.0, 1.608}, // WINDSPEED: mph, km/hr → mph
85 {1.0, 1.8}, // TEMPERATURE: °F, °C → °F
86 {2.203e-6, 1.0e-6}, // MASS: lb, kg → mg
87 {43560.0, 3048.0} // GWFLOW: cfs/ac, cms/ha → ft/sec
88};
89
91static constexpr double Qcf[6] = {
92 1.0, // CFS → cfs
93 448.831, // GPM → cfs
94 0.64632, // MGD → cfs
95 0.02832, // CMS → cfs
96 28.317, // LPS → cfs
97 2.4466 // MLD → cfs
98};
99
100// ============================================================================
101// Precomputed reciprocal tables — multiply instead of divide
102// ============================================================================
103//
104// Display → internal conversion is `internal = display / Ucf` everywhere. To
105// let hot/peripheral conversion sites multiply by a hoisted loop-invariant
106// instead of dividing, expose the compile-time reciprocals. These are derived
107// from Ucf/Qcf so they can never drift out of sync.
108//
109// Convention: internal = display * Ucf_inv[q][us] (display → internal)
110// display = internal * Ucf[q][us] (internal → display)
111
112namespace detail {
117inline constexpr std::array<std::array<double, 2>, 10> makeUcfInv() {
118 std::array<std::array<double, 2>, 10> r{};
119 for (int q = 0; q < 10; ++q)
120 for (int u = 0; u < 2; ++u)
121 r[static_cast<std::size_t>(q)][static_cast<std::size_t>(u)] = 1.0 / Ucf[q][u];
122 return r;
123}
124
128inline constexpr std::array<double, 6> makeQcfInv() {
129 std::array<double, 6> r{};
130 for (int f = 0; f < 6; ++f)
131 r[static_cast<std::size_t>(f)] = 1.0 / Qcf[f];
132 return r;
133}
134} // namespace detail
135
137inline constexpr std::array<std::array<double, 2>, 10> Ucf_inv = detail::makeUcfInv();
138
140inline constexpr std::array<double, 6> Qcf_inv = detail::makeQcfInv();
141
142// ============================================================================
143// Convenience constants — common fixed conversions not unit-system dependent
144// ============================================================================
145
146static constexpr double ACRES_TO_FT2 = 43560.0;
147static constexpr double FT3_TO_MGAL = 7.48052e-6;
148static constexpr double SEC_PER_DAY = 86400.0;
149
150// ============================================================================
151// UCF function — matching legacy UCF()
152// ============================================================================
153
170double UCF(int quantity, const SimulationOptions& opts);
171
184double UCF_inv(int quantity, const SimulationOptions& opts);
185
193int getUnitSystem(int flow_units);
194
196inline constexpr const char* FlowUnitWords[6] = {"CFS", "GPM", "MGD", "CMS", "LPS", "MLD"};
197
198// ============================================================================
199// DisplayUnits — single source of truth for internal → display conversion
200// ============================================================================
201//
202// Built once from SimulationOptions via DisplayUnits::from(). Carries the
203// internal→display multipliers (display = internal * factor) plus the matching
204// unit-label words, so every output / report consumer shares one definition
205// instead of re-deriving Ucf / Qcf inline. Mirrors legacy statsrpt.c / report.c
206// UCF()-based output and the VolUnitsWords / PondingUnitsWords tables.
208 int unit_system = 0;
209 int flow_units = 0;
210
211 // --- internal → display multipliers (display = internal * factor) ---
212 double flow = 1.0;
213 double length = 1.0;
214 double volume = 1.0;
215 double rainfall = 1.0;
216 double raindepth = 1.0;
217 double evaprate = 1.0;
218 double landarea = 1.0;
219 double mvol = 1.0;
220 double landvol = 1.0;
221
222 // --- unit-label words (legacy statsrpt.c / report.c) ---
223 const char* flow_word = "CFS";
224 const char* length_word = "Feet";
225 const char* depth_word = "in";
226 const char* vel_word = "ft/sec";
227 const char* mvol_word = "10^6 gal";
228 const char* landvol_word = "acre-feet";
229 const char* storage_vol_word = "1000 ft3";
230
241 static DisplayUnits from(const SimulationOptions& opts);
242
249 double temperature(double tF) const {
250 return unit_system == 0 ? tF : (5.0 / 9.0) * (tF - 32.0);
251 }
252};
253
254} // namespace ucf
255} // namespace openswmm
256
257#endif // OPENSWMM_UNIT_CONVERSION_HPP
Definition UnitConversion.hpp:112
constexpr std::array< double, 6 > makeQcfInv()
Build compile-time reciprocals of flow conversion factors.
Definition UnitConversion.hpp:128
constexpr std::array< std::array< double, 2 >, 10 > makeUcfInv()
Build compile-time reciprocals of every quantity/system conversion.
Definition UnitConversion.hpp:117
Definition UnitConversion.cpp:31
constexpr const char * FlowUnitWords[6]
Legacy FlowUnitWords — index by FlowUnits enum (CFS,GPM,MGD,CMS,LPS,MLD).
Definition UnitConversion.hpp:196
constexpr std::array< std::array< double, 2 >, 10 > Ucf_inv
Reciprocal of Ucf[quantity][unit_system] — multiply display by this → internal.
Definition UnitConversion.hpp:137
Quantity
Definition UnitConversion.hpp:56
@ TEMPERATURE
Legacy scale entry only; absolute temperatures require offset conversion.
Definition UnitConversion.hpp:64
@ EVAPRATE
Divide in/day (US) or mm/day (SI) by this → ft/sec.
Definition UnitConversion.hpp:59
@ LANDAREA
Divide ac (US) or ha (SI) by this → ft²
Definition UnitConversion.hpp:61
@ MASS
Divide lb (US) or kg (SI) by this → mg.
Definition UnitConversion.hpp:65
@ VOLUME
Divide ft³ (US) or m³ (SI) by this → ft³
Definition UnitConversion.hpp:62
@ FLOW
Divide display flow units by this → cfs.
Definition UnitConversion.hpp:67
@ RAINFALL
Divide in/hr (US) or mm/hr (SI) by this → ft/sec.
Definition UnitConversion.hpp:57
@ RAINDEPTH
Divide in (US) or mm (SI) by this → ft.
Definition UnitConversion.hpp:58
@ WINDSPEED
Divide mph (US) or km/hr (SI) by this → mph.
Definition UnitConversion.hpp:63
@ LENGTH
Divide ft (US) or m (SI) by this → ft.
Definition UnitConversion.hpp:60
@ GWFLOW
Divide cfs/ac (US) or cms/ha (SI) by this → ft/sec.
Definition UnitConversion.hpp:66
constexpr std::array< double, 6 > Qcf_inv
Reciprocal of Qcf[flow_units] — multiply display flow by this → cfs.
Definition UnitConversion.hpp:140
double UCF(int quantity, const SimulationOptions &opts)
Get unit conversion factor for a quantity.
Definition UnitConversion.cpp:39
double UCF_inv(int quantity, const SimulationOptions &opts)
Reciprocal of UCF — multiply display by this to get internal units.
Definition UnitConversion.cpp:53
int getUnitSystem(int flow_units)
Determine unit system (0=US, 1=SI) from flow units.
Definition UnitConversion.cpp:33
Definition ExchangeLaw.hpp:60
All SWMM simulation options parsed from [OPTIONS] section.
Definition SimulationOptions.hpp:168
Definition UnitConversion.hpp:207
const char * depth_word
rainfall / runoff depth (in | mm)
Definition UnitConversion.hpp:225
int flow_units
FlowUnits enum value.
Definition UnitConversion.hpp:209
const char * vel_word
link velocity (ft/sec | m/sec)
Definition UnitConversion.hpp:226
double landarea
ft² → ac | ha
Definition UnitConversion.hpp:218
const char * flow_word
CFS | CMS | ...
Definition UnitConversion.hpp:223
const char * mvol_word
10^6 gal | 10^6 ltr
Definition UnitConversion.hpp:227
double length
ft → ft | m
Definition UnitConversion.hpp:213
double temperature(double tF) const
Convert an internal Fahrenheit temperature to this bundle's display scale.
Definition UnitConversion.hpp:249
static DisplayUnits from(const SimulationOptions &opts)
Build display factors and borrowed static labels from flow-unit options.
Definition UnitConversion.cpp:67
double rainfall
ft/s → in/hr | mm/hr
Definition UnitConversion.hpp:215
double volume
ft³ → ft³ | m³
Definition UnitConversion.hpp:214
double raindepth
ft → in | mm (also runoff-depth columns)
Definition UnitConversion.hpp:216
const char * storage_vol_word
1000 ft3 | 1000 m3
Definition UnitConversion.hpp:229
double mvol
ft³ → 10^6 gal | 10^6 ltr
Definition UnitConversion.hpp:219
const char * landvol_word
acre-feet | hectare-m
Definition UnitConversion.hpp:228
int unit_system
0 = US, 1 = SI
Definition UnitConversion.hpp:208
double flow
cfs → display flow (Qcf)
Definition UnitConversion.hpp:212
double evaprate
ft/s → in/day | mm/day
Definition UnitConversion.hpp:217
double landvol
ft³ → acre-ft | hectare-m
Definition UnitConversion.hpp:220
const char * length_word
depth / HGL / surcharge column
Definition UnitConversion.hpp:224