![]() |
OpenSWMM Engine
6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
|
Phase H5a — temperature on subcatchment surfaces. More...
Go to the source code of this file.
Namespaces | |
| namespace | openswmm |
| namespace | openswmm::runoff |
| namespace | openswmm::transport |
Functions | |
| void | openswmm::transport::addRunonTemperature (SimulationContext &ctx, int donor_sc, int receiver_sc, double q) |
Accumulate run-on temperature from donor_sc onto receiver_sc. | |
| void | openswmm::transport::addRunonTemperatureAt (SimulationContext &ctx, int receiver_sc, double q, double temp_c) |
| Accumulate run-on at an explicitly supplied temperature. | |
| void | openswmm::transport::routeSubcatchmentTemperature (SimulationContext &ctx, const runoff::RunoffSoA &soa, double dt) |
| Advance ponded subarea temperatures one runoff step. | |
Phase H5a — temperature on subcatchment surfaces.
This is A3's WaterAgeWatershed with the same complete-mix bookkeeping and three deliberate differences, which are the whole content of the file:
+dt every step because that is what age IS. Temperature gains nothing from the passage of time; it changes only by mixing and by flux.WaterAgeWatershed clamps with std::max(a, 0.0) because a negative age is meaningless. A negative temperature is ordinary — this is the same difference HeatLegacy makes against WaterAgeLegacy.DryTempPolicy (plan D-H5c).RunoffSoA::area × frac[k].RunoffSoA::area is not ctx.subcatches.area, and the difference is bigger than it looks. Runoff.cpp:197-199 builds it as ctx.subcatches.area / ucf_area − total_lid_area_ft2: the SoA row is ft², the context row is in the deck's user area units — acres in US customary, a factor of 43560. The LID footprint is the second, far smaller correction. Substituting ctx.subcatches.area here was measured at 14.34 °C against 12.95 °C on a LID deck, with the ponded volume ledger collapsing from 27342 ft³ to 0.78 ft³.
Note what does NOT go wrong: a temperature is intensive, and the exchange area cancels exactly against the thermal mass in relaxT (it enters only through k = A·J′/(ρ cp V), and A / V ≡ 1 / depth_prev), so the flux term alone cannot see the substitution. It survives only through runon_depth_rate = runon_rate / area, which converts a run-on flow into the depth rate that weights it against rainfall. That is the one place the number has to be right, and it is not where the double-counting argument would look.
runoff_.execute, because that is when the depths it reads are current. H2's node and link bindings run on the ROUTING clock inside routeLegacyHeat. Both are correct; the dt each passes is its own, and conflating them would scale every flux by the wrong interval.