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 {
113inline constexpr std::array<std::array<double, 2>, 10> makeUcfInv() {
114 std::array<std::array<double, 2>, 10> r{};
115 for (int q = 0; q < 10; ++q)
116 for (int u = 0; u < 2; ++u)
117 r[static_cast<std::size_t>(q)][static_cast<std::size_t>(u)] =
118 1.0 / Ucf[q][u];
119 return r;
120}
121inline constexpr std::array<double, 6> makeQcfInv() {
122 std::array<double, 6> r{};
123 for (int f = 0; f < 6; ++f) r[static_cast<std::size_t>(f)] = 1.0 / Qcf[f];
124 return r;
125}
126} // namespace detail
127
129inline constexpr std::array<std::array<double, 2>, 10> Ucf_inv = detail::makeUcfInv();
130
132inline constexpr std::array<double, 6> Qcf_inv = detail::makeQcfInv();
133
134// ============================================================================
135// Convenience constants — common fixed conversions not unit-system dependent
136// ============================================================================
137
138static constexpr double ACRES_TO_FT2 = 43560.0;
139static constexpr double FT3_TO_MGAL = 7.48052e-6;
140static constexpr double SEC_PER_DAY = 86400.0;
141
142// ============================================================================
143// UCF function — matching legacy UCF()
144// ============================================================================
145
162double UCF(int quantity, const SimulationOptions& opts);
163
176double UCF_inv(int quantity, const SimulationOptions& opts);
177
185int getUnitSystem(int flow_units);
186
188inline constexpr const char* FlowUnitWords[6] =
189 { "CFS", "GPM", "MGD", "CMS", "LPS", "MLD" };
190
191// ============================================================================
192// DisplayUnits — single source of truth for internal → display conversion
193// ============================================================================
194//
195// Built once from SimulationOptions via DisplayUnits::from(). Carries the
196// internal→display multipliers (display = internal * factor) plus the matching
197// unit-label words, so every output / report consumer shares one definition
198// instead of re-deriving Ucf / Qcf inline. Mirrors legacy statsrpt.c / report.c
199// UCF()-based output and the VolUnitsWords / PondingUnitsWords tables.
201 int unit_system = 0;
202 int flow_units = 0;
203
204 // --- internal → display multipliers (display = internal * factor) ---
205 double flow = 1.0;
206 double length = 1.0;
207 double volume = 1.0;
208 double rainfall = 1.0;
209 double raindepth = 1.0;
210 double evaprate = 1.0;
211 double landarea = 1.0;
212 double mvol = 1.0;
213 double landvol = 1.0;
214
215 // --- unit-label words (legacy statsrpt.c / report.c) ---
216 const char* flow_word = "CFS";
217 const char* length_word = "Feet";
218 const char* depth_word = "in";
219 const char* vel_word = "ft/sec";
220 const char* mvol_word = "10^6 gal";
221 const char* landvol_word = "acre-feet";
222 const char* storage_vol_word = "1000 ft3";
223
225 static DisplayUnits from(const SimulationOptions& opts);
226
228 double temperature(double tF) const {
229 return unit_system == 0 ? tF : (5.0 / 9.0) * (tF - 32.0);
230 }
231};
232
233} // namespace ucf
234} // namespace openswmm
235
236#endif // OPENSWMM_UNIT_CONVERSION_HPP
Definition UnitConversion.hpp:112
constexpr std::array< double, 6 > makeQcfInv()
Definition UnitConversion.hpp:121
constexpr std::array< std::array< double, 2 >, 10 > makeUcfInv()
Definition UnitConversion.hpp:113
Definition UnitConversion.cpp:31
constexpr const char * FlowUnitWords[6]
Legacy FlowUnitWords — index by FlowUnits enum (CFS,GPM,MGD,CMS,LPS,MLD).
Definition UnitConversion.hpp:188
constexpr std::array< std::array< double, 2 >, 10 > Ucf_inv
Reciprocal of Ucf[quantity][unit_system] — multiply display by this → internal.
Definition UnitConversion.hpp:129
Quantity
Definition UnitConversion.hpp:56
@ TEMPERATURE
Divide °F (US) or °C (SI) by this → °F.
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:132
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 NodeCoupling.cpp:16
All SWMM simulation options parsed from [OPTIONS] section.
Definition SimulationOptions.hpp:166
Definition UnitConversion.hpp:200
const char * depth_word
rainfall / runoff depth (in | mm)
Definition UnitConversion.hpp:218
int flow_units
FlowUnits enum value.
Definition UnitConversion.hpp:202
const char * vel_word
link velocity (ft/sec | m/sec)
Definition UnitConversion.hpp:219
double landarea
ft² → ac | ha
Definition UnitConversion.hpp:211
const char * flow_word
CFS | CMS | ...
Definition UnitConversion.hpp:216
const char * mvol_word
10^6 gal | 10^6 ltr
Definition UnitConversion.hpp:220
double length
ft → ft | m
Definition UnitConversion.hpp:206
double temperature(double tF) const
Internal temperature (°F) → display (°F for US, °C for SI).
Definition UnitConversion.hpp:228
static DisplayUnits from(const SimulationOptions &opts)
Build from simulation options (selects unit system + flow units).
Definition UnitConversion.cpp:67
double rainfall
ft/s → in/hr | mm/hr
Definition UnitConversion.hpp:208
double volume
ft³ → ft³ | m³
Definition UnitConversion.hpp:207
double raindepth
ft → in | mm (also runoff-depth columns)
Definition UnitConversion.hpp:209
const char * storage_vol_word
1000 ft3 | 1000 m3
Definition UnitConversion.hpp:222
double mvol
ft³ → 10^6 gal | 10^6 ltr
Definition UnitConversion.hpp:212
const char * landvol_word
acre-feet | hectare-m
Definition UnitConversion.hpp:221
int unit_system
0 = US, 1 = SI
Definition UnitConversion.hpp:201
double flow
cfs → display flow (Qcf)
Definition UnitConversion.hpp:205
double evaprate
ft/s → in/day | mm/day
Definition UnitConversion.hpp:210
double landvol
ft³ → acre-ft | hectare-m
Definition UnitConversion.hpp:213
const char * length_word
depth / HGL / surcharge column
Definition UnitConversion.hpp:217