OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
HeatData.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
55
56#ifndef OPENSWMM_ENGINE_DATA_HEAT_DATA_HPP
57#define OPENSWMM_ENGINE_DATA_HEAT_DATA_HPP
58
59#include <limits>
60#include <vector>
61
62#include "BedZoneData.hpp" // SedimentConfig — H6b's bed zone configuration
63#include "HeatOverrideData.hpp" // HeatElement / HeatAttr / HeatScope — PE
64
65namespace openswmm {
66
70enum class HeatSource : int {
74 DWF = 1,
75 GW = 2,
76 RDII = 3,
78 IFACE = 5,
81};
82
88enum class HeatSubArea : int { IMPERV0 = 0, IMPERV1 = 1, PERV = 2, COUNT_ = 3 };
89
98enum class DryTempPolicy : int {
101 HOLD = 0,
104 AIR = 1,
108};
109
130 double water_conductivity = 0.606;
131 double sed_conductivity = 2.6;
132 double sed_density = 1970.0;
133 double sed_specific_heat = 2758.0;
134};
135
146enum class ShortwaveMode : int {
150};
151
169 double latitude_deg = 0.0;
170 double longitude_deg = 0.0;
171 double timezone_hours = 0.0;
172 bool has_latitude = false;
173 bool has_longitude = false;
177 bool has_timezone = false;
178
187 double elevation_m = 0.0;
188 bool has_elevation = false;
189
190 // ---- Bird & Hulstrom (1981) atmosphere. Defaults are the paper's
191 // standard atmosphere.
192 double aod380 = 0.30;
193 double aod500 = 0.20;
194 double precip_water_cm = 1.42;
195 double ozone_cm = 0.34;
196 double ground_albedo = 0.20;
202};
203
218 bool configured = false;
219 bool use_timeseries = false;
220 int ts_index = -1;
221 double fraction = 0.0;
222
223 double sw_atten_k = 0.75;
224 double sw_atten_n = 3.4;
225 double lw_cloud_k = 0.17;
226};
227
238 double shortwave_wm2 = 0.0;
239 double albedo = 0.0;
240 double shade_factor = 0.0;
241 double sky_view = 1.0;
242 double emiss_water = 0.97;
243 double emiss_landcover = 0.97;
244 double atm_emiss_coeff = 0.5;
245 double lw_reflection = 0.03;
246
264 double landcover_temp = std::numeric_limits<double>::quiet_NaN();
265
270 int sw_ts_index = -1;
271};
272
288 std::vector<HeatOverrideRow> rows;
289
290 std::vector<RadiativeConfig> rad_link;
291 std::vector<RadiativeConfig> rad_node;
292 std::vector<SedimentConfig> sed_link;
293 std::vector<RadiativeConfig> rad_cell;
294 std::vector<SedimentConfig> sed_cell;
295
296 bool resolved = false;
297
302 bool empty() const noexcept { return rows.empty(); }
309 void clear() { *this = HeatOverrideData{}; }
310};
311
325 bool configured = false;
326
329 bool radiative_exchange = false;
330
333
344 bool surface_exchange = false;
345
348
352 bool layer_conduction = false;
353
356
364 bool sediment_exchange = false;
365
372
376
380
384
386 static constexpr double kDefaultTemp = 20.0;
387
392
394 bool configured_source[static_cast<int>(HeatSource::COUNT_)] = {};
395
396 // NODE-scope overrides (DWF / EXTERNAL_INFLOW), parallel arrays.
397 std::vector<int> node_over_source;
398 std::vector<int> node_over_node;
399 std::vector<double> node_over_temp;
400
411 double source_temp(HeatSource s, int node) const noexcept {
412 for (std::size_t i = 0; i < node_over_source.size(); ++i)
413 if (node_over_source[i] == static_cast<int>(s) && node_over_node[i] == node)
414 return node_over_temp[i];
415 return global_temp[static_cast<int>(s)];
416 }
417};
418
427struct HeatState {
428 std::vector<unsigned char> mesh_contact_link;
429 std::vector<double> node_temp_vol_in;
437 std::vector<double> node_lid_drain_temp_vol_in;
438 std::vector<double> node_temp;
439 std::vector<double> link_temp;
440
442 bool legacy_seeded = false;
443
444 // ---- H6a per-step solar forcing (plan §2.5). RESOLVED ONCE PER STEP by
445 // `updateSolarForcing`, then read const by every flux call.
446 //
447 // This is state, not config, which is why it lives here: `Jin`
448 // under TIMESERIES or COMPUTED changes every step, while
449 // `RadiativeConfig::shortwave_wm2` is what the deck wrote and must
450 // not be overwritten (a hot-started or re-opened model would
451 // otherwise resume from a stale interpolation rather than from its
452 // own configuration).
453 //
454 // It is also what keeps the SPA cost argument honest: shortwave is
455 // GLOBAL scope, so the position is computed once per step and every
456 // element reads the same cached number. A per-element solve is
457 // plan §7 work and would not use this field.
458
472 double shortwave_now = -1.0;
474 double cloud_now = 0.0;
475
476 // ---- H5a watershed rows. Sized by `resizeWatershed`, NOT by `resize`.
477 // Kept a separate call deliberately: A3 widened `WaterAgeState::
478 // resize` with a defaulted third parameter, four existing two-
479 // argument call sites then silently emptied the new arrays at
480 // runtime, and the validator had to remove the default to move the
481 // failure back to the compiler. A second function cannot be called
482 // short, so the hazard is unrepresentable rather than observed.
483
485 std::vector<double> subarea_temp;
489 std::vector<double> subarea_vol_prev;
491 std::vector<double> subcatch_runoff_temp;
495 std::vector<double> subcatch_runon_temp_vol_in;
496
517 std::vector<double> subcatch_runon_temp_rate;
518
524 std::vector<double> subcatch_outfall_temp_vol;
525
531 std::vector<double> subcatch_lid_drain_temp_cfs;
532
533 static constexpr int kNSubArea = static_cast<int>(HeatSubArea::COUNT_);
534
547 void resize(int n_nodes, int n_links, double initial_temp) {
548 // Lazy 1D backend seeding must retain the router's already-bound
549 // contact ownership. Model/router initialization clears that mask.
550 node_temp_vol_in.assign(static_cast<std::size_t>(n_nodes), 0.0);
551 node_lid_drain_temp_vol_in.assign(static_cast<std::size_t>(n_nodes), 0.0);
552 node_temp.assign(static_cast<std::size_t>(n_nodes), initial_temp);
553 link_temp.assign(static_cast<std::size_t>(n_links), initial_temp);
554 legacy_seeded = false;
555 // H6a. `clear()` resets these via whole-struct assignment, but
556 // `resize()` is what runs at INITIALIZE — so a re-initialize on an
557 // already-run context would otherwise leave the previous run's
558 // forcing readable, and `swmm_heat_get_current_shortwave` documents
559 // itself as unresolved before the first step.
560 shortwave_now = -1.0;
561 cloud_now = 0.0;
562 }
563
573 void resizeWatershed(int n_subcatch, double initial_temp) {
574 const auto n = static_cast<std::size_t>(n_subcatch);
575 subarea_temp.assign(n * static_cast<std::size_t>(kNSubArea), initial_temp);
576 subarea_vol_prev.assign(n * static_cast<std::size_t>(kNSubArea), 0.0);
577 subcatch_runoff_temp.assign(n, initial_temp);
578 subcatch_runon_temp_vol_in.assign(n, 0.0);
579 subcatch_runon_temp_rate.assign(n, 0.0);
580 subcatch_outfall_temp_vol.assign(n, 0.0);
581 subcatch_lid_drain_temp_cfs.assign(n, 0.0);
582 }
583
591 bool watershedSized(int n_subcatch) const noexcept {
592 return subarea_temp.size() ==
593 static_cast<std::size_t>(n_subcatch) * static_cast<std::size_t>(kNSubArea);
594 }
595
602 void clear() { *this = HeatState{}; }
603};
604
605} // namespace openswmm
606
607#endif // OPENSWMM_ENGINE_DATA_HEAT_DATA_HPP
Plan H6b — the bed / hyporheic transient-storage zone.
Plan PE — per-element radiative and bed attributes.
Definition Node.cpp:38
Definition ExchangeLaw.hpp:60
DryTempPolicy
What a dry or absent element reports (plan D-H5c, user 2026-08-19).
Definition HeatData.hpp:98
@ HOLD
Definition HeatData.hpp:101
@ AIR
Definition HeatData.hpp:104
@ DEFAULT
Definition HeatData.hpp:107
HeatSubArea
Definition HeatData.hpp:88
@ IMPERV0
Definition HeatData.hpp:88
@ COUNT_
Definition HeatData.hpp:88
@ IMPERV1
Definition HeatData.hpp:88
@ PERV
Definition HeatData.hpp:88
@ TIMESERIES
Data from an in-file [TIMESERIES].
Definition GageData.hpp:58
HeatSource
Definition HeatData.hpp:70
@ RAINFALL
Definition HeatData.hpp:71
@ RDII
Definition HeatData.hpp:76
@ COUNT_
Definition HeatData.hpp:80
@ DWF
Definition HeatData.hpp:74
@ EXTERNAL_INFLOW
Definition HeatData.hpp:77
@ INITIAL_STATE
water in the network at t = 0
Definition HeatData.hpp:79
@ GW
Definition HeatData.hpp:75
@ IFACE
Definition HeatData.hpp:78
ShortwaveMode
Where incoming shortwave Jin comes from (plan §2.5, phase H6a).
Definition HeatData.hpp:146
@ COMPUTED
SHORTWAVE GLOBAL COMPUTED — position + clear-sky.
Definition HeatData.hpp:149
@ CONSTANT
SHORTWAVE GLOBAL <W/m²> — the H3 spelling.
Definition HeatData.hpp:147
[CLOUD_COVER] — one fraction driving two modules (H6a, D-H6a-2).
Definition HeatData.hpp:217
double sw_atten_n
Kasten–Czeplak n.
Definition HeatData.hpp:224
double fraction
C ∈ [0,1], constant spelling.
Definition HeatData.hpp:221
int ts_index
Index into ctx.tables, -1 = none.
Definition HeatData.hpp:220
double sw_atten_k
Kasten–Czeplak k.
Definition HeatData.hpp:223
bool use_timeseries
Definition HeatData.hpp:219
double lw_cloud_k
Bolz k_lw.
Definition HeatData.hpp:225
bool configured
No [CLOUD_COVER] section → clear sky.
Definition HeatData.hpp:218
Vertical conduction between LID layers (plan §6.1 D-H5b, H5b).
Definition HeatData.hpp:129
double sed_specific_heat
J/kg/K (gwmodel.cpp:52)
Definition HeatData.hpp:133
double water_conductivity
W/m/K (gwmodel.h:885)
Definition HeatData.hpp:130
double sed_density
kg/m³ (gwmodel.cpp:51)
Definition HeatData.hpp:132
double sed_conductivity
W/m/K (gwmodel.h:886)
Definition HeatData.hpp:131
Parsed model.heat state (heat component, phase H1).
Definition HeatData.hpp:324
bool configured_source[static_cast< int >(HeatSource::COUNT_)]
Whether the user set this source explicitly (vs. taking the default).
Definition HeatData.hpp:394
SolarConfig solar
Definition HeatData.hpp:379
ConductionConfig conduction
Parameters for the module above.
Definition HeatData.hpp:355
bool radiative_exchange
Definition HeatData.hpp:329
double global_temp[static_cast< int >(HeatSource::COUNT_)]
GLOBAL inlet temperature per source, °C.
Definition HeatData.hpp:389
bool sediment_exchange
Definition HeatData.hpp:364
RadiativeConfig radiative
Parameters for the module above.
Definition HeatData.hpp:332
HeatOverrideData overrides
Definition HeatData.hpp:375
static constexpr double kDefaultTemp
Default inlet temperature when a source has no row (°C).
Definition HeatData.hpp:386
DryTempPolicy dry_temp_policy
[HEAT_FLUXES] DRY_ELEMENT_TEMPERATURE HOLD|AIR|DEFAULT (D-H5c).
Definition HeatData.hpp:347
std::vector< int > node_over_source
HeatSource as int.
Definition HeatData.hpp:397
bool surface_exchange
[HEAT_FLUXES] SURFACE_EXCHANGE ON — latent + sensible exchange at the free surface (plan §2....
Definition HeatData.hpp:344
std::vector< double > node_over_temp
°C
Definition HeatData.hpp:399
bool configured
Definition HeatData.hpp:325
bool layer_conduction
Definition HeatData.hpp:352
double source_temp(HeatSource s, int node) const noexcept
Read the first matching node/source temperature override or global fallback.
Definition HeatData.hpp:411
CloudConfig cloud
Definition HeatData.hpp:383
SedimentConfig sediment
Definition HeatData.hpp:371
std::vector< int > node_over_node
node index
Definition HeatData.hpp:398
Dense per-element attribute storage (PE2, D-PE2).
Definition HeatData.hpp:287
std::vector< SedimentConfig > sed_link
[link], empty ⇒ use global
Definition HeatData.hpp:292
std::vector< SedimentConfig > sed_cell
[surface mesh cell], not ARD cells
Definition HeatData.hpp:294
bool empty() const noexcept
Test whether authored heat-override rows are absent.
Definition HeatData.hpp:302
std::vector< HeatOverrideRow > rows
as parsed; the serializer's input
Definition HeatData.hpp:288
std::vector< RadiativeConfig > rad_node
[node], empty ⇒ use global
Definition HeatData.hpp:291
std::vector< RadiativeConfig > rad_cell
[surface mesh cell]
Definition HeatData.hpp:293
std::vector< RadiativeConfig > rad_link
[link], empty ⇒ use global
Definition HeatData.hpp:290
bool resolved
Definition HeatData.hpp:296
void clear()
Reset authored and resolved heat-override storage.
Definition HeatData.hpp:309
Runtime heat state shared by the engines (phase H1).
Definition HeatData.hpp:427
std::vector< double > subarea_temp
[subcatch * kNSubArea + subarea], °C — ponded surface temperature.
Definition HeatData.hpp:485
static constexpr int kNSubArea
Definition HeatData.hpp:533
std::vector< double > link_temp
[link], °C
Definition HeatData.hpp:439
bool legacy_seeded
The LEGACY mirror seeds INITIAL_STATE on its first step.
Definition HeatData.hpp:442
std::vector< double > subcatch_runoff_temp
[subcatch], °C — temperature the subcatchment's runoff leaves at.
Definition HeatData.hpp:491
bool watershedSized(int n_subcatch) const noexcept
Check the length of the subarea temperature vector only.
Definition HeatData.hpp:591
std::vector< double > subcatch_lid_drain_temp_cfs
Definition HeatData.hpp:531
std::vector< double > node_temp_vol_in
Definition HeatData.hpp:429
std::vector< double > node_lid_drain_temp_vol_in
Definition HeatData.hpp:437
double cloud_now
Cloud fraction at the current step, C ∈ [0,1]. 0 = clear.
Definition HeatData.hpp:474
std::vector< double > node_temp
[node], °C
Definition HeatData.hpp:438
std::vector< unsigned char > mesh_contact_link
Empty in prescribed compatibility mode.
Definition HeatData.hpp:428
std::vector< double > subcatch_outfall_temp_vol
Definition HeatData.hpp:524
void resize(int n_nodes, int n_links, double initial_temp)
Replace network heat arrays and reset current forcing caches.
Definition HeatData.hpp:547
std::vector< double > subcatch_runon_temp_rate
Definition HeatData.hpp:517
std::vector< double > subarea_vol_prev
Definition HeatData.hpp:489
void clear()
Release all network/watershed heat state and restore cache sentinels.
Definition HeatData.hpp:602
void resizeWatershed(int n_subcatch, double initial_temp)
Replace subcatchment heat arrays and their three-subarea histories.
Definition HeatData.hpp:573
double shortwave_now
Definition HeatData.hpp:472
std::vector< double > subcatch_runon_temp_vol_in
Definition HeatData.hpp:495
[RADIATIVE_FLUXES] parameters (heat plan §2.2, phase H3).
Definition HeatData.hpp:237
double sky_view
fsky, 1 = open sky
Definition HeatData.hpp:241
double atm_emiss_coeff
Brunt Aa.
Definition HeatData.hpp:244
double shade_factor
fs, 0 = unshaded
Definition HeatData.hpp:240
double albedo
Rs, reference default.
Definition HeatData.hpp:239
int sw_ts_index
Index into ctx.tables under TIMESERIES; -1 otherwise.
Definition HeatData.hpp:270
double lw_reflection
RL.
Definition HeatData.hpp:245
double shortwave_wm2
Incoming solar Jin, W/m² (0 = night)
Definition HeatData.hpp:238
double emiss_landcover
εlc
Definition HeatData.hpp:243
ShortwaveMode sw_mode
Definition HeatData.hpp:268
double landcover_temp
Land-cover radiating temperature, °C. NaN ⇒ use air temperature.
Definition HeatData.hpp:264
double emiss_water
εw
Definition HeatData.hpp:242
[SEDIMENT_EXCHANGE] — the bed zone's material and geometry.
Definition BedZoneData.hpp:88
[SOLAR_RADIATION] — site geometry and Bird atmosphere (H6a).
Definition HeatData.hpp:168
double ozone_cm
Ozone column, cm (NTP)
Definition HeatData.hpp:195
double timezone_hours
Offset from UTC, +E (e.g. MST = -7).
Definition HeatData.hpp:171
bool has_timezone
Definition HeatData.hpp:177
double longitude_deg
+E. REQUIRED under COMPUTED.
Definition HeatData.hpp:170
bool has_elevation
Definition HeatData.hpp:188
double elevation_m
Definition HeatData.hpp:187
double aod380
Aerosol optical depth at 380 nm.
Definition HeatData.hpp:192
bool has_longitude
Definition HeatData.hpp:173
double precip_water_cm
Precipitable water vapour, cm.
Definition HeatData.hpp:194
double ground_albedo
Definition HeatData.hpp:196
bool has_latitude
Set by the parser, checked at close.
Definition HeatData.hpp:172
double latitude_deg
+N. REQUIRED under COMPUTED.
Definition HeatData.hpp:169
double aod500
Aerosol optical depth at 500 nm.
Definition HeatData.hpp:193