WasteHeatAirConditioning
Waste heat and air-conditioning heat removal aggregation for the urban canopy thermal column. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:440 (`WasteHeatAirConditioning` @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4) Eqs. 4.55-4.56: the unclamped total waste heat H_wasteheat_unclamped distributes heating/cooling fluxes from the roof and the two walls (sunlit and shaded) into the canyon air, weighted by the efficiency factors f_heat = 1/0.75 and f_cool = 1/0.25, the roof area fraction W_roof, and the canyon-wall geometry factor (1 - W_roof) * H_W per Eq. 4.55; this is clamped at H_wasteheat_max = 100 W/m^2 to produce H_wasteheat. The air-conditioning heat removal H_aircond is the sum of the three cooling fluxes (F_cool_roof + F_cool_sunwall + F_cool_shdwall) per Eq. 4.56. Parameterized as observed-only with three algebraic equations: H_wasteheat_unclamped, H_wasteheat, H_aircond are state variables; F_heat_roof, F_cool_roof, F_heat_sunwall, F_cool_sunwall, F_heat_shdwall, F_cool_shdwall, W_roof, H_W are inputs (parameters in standalone form).
Description
Waste heat and air-conditioning heat removal aggregation for the urban canopy thermal column. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:440 (WasteHeatAirConditioning @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4) Eqs. 4.55-4.56: the unclamped total waste heat H_wasteheat_unclamped distributes heating/cooling fluxes from the roof and the two walls (sunlit and shaded) into the canyon air, weighted by the efficiency factors f_heat = 1/0.75 and f_cool = 1/0.25, the roof area fraction W_roof, and the canyon-wall geometry factor (1 - W_roof) * H_W per Eq. 4.55; this is clamped at H_wasteheat_max = 100 W/m^2 to produce H_wasteheat. The air-conditioning heat removal H_aircond is the sum of the three cooling fluxes (F_cool_roof + F_cool_sunwall + F_cool_shdwall) per Eq. 4.56. Parameterized as observed-only with three algebraic equations: H_wasteheat_unclamped, H_wasteheat, H_aircond are state variables; F_heat_roof, F_cool_roof, F_heat_sunwall, F_cool_sunwall, F_heat_shdwall, F_cool_shdwall, W_roof, H_W are inputs (parameters in standalone form).
Reference
_source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:440
Upstream WasteHeatAirConditioning is an MTK @component with eight @parameters (F_heat_roof, F_cool_roof, F_heat_sunwall, F_cool_sunwall, F_heat_shdwall, F_cool_shdwall, W_roof, H_W), three time-indexed @variables (H_wasteheat_unclamped, H_wasteheat, H_aircond), and three algebraic equations (no derivatives). Identical equation structure preserved here.
The upstream component declares three @constants, all encoded here as parameters with the upstream default values: f_heat = 1.0/0.75 (heating efficiency factor, dimensionless), f_cool = 1.0/0.25 = 4.0 (cooling efficiency factor, dimensionless), and H_wasteheat_max = 100.0 W/m^2 (maximum waste heat limit on the clamped output). f_heat is encoded as the exact ratio 1.0/0.75 = 1.3333333333333333… in IEEE-754 — the upstream Julia literal 1.0/0.75 resolves to the same double; preserving the value as a parameter default keeps the rational structure visible and matches the convention used by sibling files (heating_cooling_flux.esm preserves alpha_CN = 0.5 and zero_flux = 0.0 W/m^2 as parameters with upstream default values).
The clamp uses min(H_wasteheat_unclamped, H_wasteheat_max) — the upstream uses Julia’s two-argument min which the ESS AST exposes as the min op. When H_wasteheat_unclamped <= H_wasteheat_max, H_wasteheat = H_wasteheat_unclamped (pass-through); when H_wasteheat_unclamped > H_wasteheat_max, H_wasteheat = H_wasteheat_max = 100 W/m^2 exactly. The equality case (H_wasteheat_unclamped == H_wasteheat_max) is well-defined by min semantics — both branches give the same numeric value.
The Eq. 4.56 air-conditioning heat removal H_aircond is a simple three-term sum of cooling fluxes (F_cool_roof + F_cool_sunwall + F_cool_shdwall). It is decoupled from H_wasteheat and the geometry parameters W_roof, H_W — exercised independently in the H_aircond_decoupled_from_geometry test.
Observability classification: this component is functionally observed-only — every output variable is given by a single algebraic equation in terms of the parameters, and the (t) time index has no role since there are no derivatives. Test scenarios use time_span: [0, 1] and sample at t=0 to mirror the convention used by sibling observed-only ESM files in this rig (heating_cooling_flux.esm, snow_capping_runoff.esm, total_phase_change_energy.esm).
Tolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); the equations involve only multiplication, addition, subtraction, and min — all at IEEE-754 ULP precision (~1e-16). 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files (heating_cooling_flux.esm uses 1e-9 for the analogous Crank-Nicholson + ifelse equations). Tighter abs: 1e-12 is asserted on outputs that are exactly zero by construction so the assertion does not silently accept a stuck-at-1e-3 regression._
Parameters
| Name | Units | Default | Description |
|---|---|---|---|
f_heat | 1 | 1.3333333333333333 | Heating efficiency factor (dimensionless) — upstream @constants f_heat = 1.0/0.75; multiplies the heating-flux terms in Eq. 4.55 to convert the building floor heating flux into the total waste heat dumped to the canyon air |
f_cool | 1 | 4.0 | Cooling efficiency factor (dimensionless) — upstream @constants f_cool = 1.0/0.25 = 4.0; multiplies the cooling-flux terms in Eq. 4.55 to convert the building floor cooling flux into the total waste heat dumped to the canyon air (cooling efficiency is lower than heating, so f_cool > f_heat) |
H_wasteheat_max | W/m^2 | 100.0 | Maximum waste heat limit (W/m^2) — upstream @constants H_wasteheat_max = 100; the min clamp in Eq. 4.55 caps the unclamped waste heat at this value to avoid unphysical heat injection into the canyon air during extreme HVAC demand |
F_heat_roof | W/m^2 | 0.0 | Heating flux for roof (W/m^2) — input from a HeatingCoolingFlux instance attached to the roof column; non-negative magnitude of the HVAC heating demand at the roof |
F_cool_roof | W/m^2 | 0.0 | Cooling flux for roof (W/m^2) — input from a HeatingCoolingFlux instance attached to the roof column; non-negative magnitude of the HVAC cooling demand at the roof |
F_heat_sunwall | W/m^2 | 0.0 | Heating flux for sunlit wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the sunlit-wall column |
F_cool_sunwall | W/m^2 | 0.0 | Cooling flux for sunlit wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the sunlit-wall column |
F_heat_shdwall | W/m^2 | 0.0 | Heating flux for shaded wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the shaded-wall column |
F_cool_shdwall | W/m^2 | 0.0 | Cooling flux for shaded wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the shaded-wall column |
W_roof | 1 | 0.3 | Roof fraction (dimensionless) — fraction of the urban canyon footprint occupied by roof. At W_roof = 1, only the roof term contributes to Eq. 4.55; at W_roof = 0, only the wall terms contribute (weighted by H_W) |
H_W | 1 | 1.0 | Height-to-width ratio (dimensionless) — canyon-wall geometry factor that scales the wall contribution to Eq. 4.55. At H_W = 0, the walls contribute nothing regardless of W_roof; at H_W = 1, the walls have unit weighting on the (1 - W_roof) road-area fraction |
Observed
| Name | Units | Default | Description |
|---|---|---|---|
H_wasteheat_unclamped | W/m^2 | Unclamped total waste heat (Oleson Eq. 4.55, before the max clamp): W_roof * (f_heat * F_heat_roof + f_cool * F_cool_roof) + (1 - W_roof) * H_W * (f_heat * F_heat_sunwall + f_cool * F_cool_sunwall + f_heat * F_heat_shdwall + f_cool * F_cool_shdwall) | |
H_wasteheat | W/m^2 | Total waste heat clamped at H_wasteheat_max (Oleson Eq. 4.55): min(H_wasteheat_unclamped, H_wasteheat_max). This is the waste heat dumped to the canyon air after the upper-bound cap is applied | |
H_aircond | W/m^2 | Heat removed by air conditioning (Oleson Eq. 4.56): F_cool_roof + F_cool_sunwall + F_cool_shdwall — sum of cooling fluxes from all three building surfaces |
Observed expressions
$$ H_{wasteheat\,unclamped} = W_{roof} \cdot \left(f_{heat} \cdot F_{heat\,roof} + f_{cool} \cdot F_{cool\,roof}\right) + \left(1.0 - W_{roof}\right) \cdot H_{W} \cdot \left(f_{heat} \cdot F_{heat\,sunwall} + f_{cool} \cdot F_{cool\,sunwall} + f_{heat} \cdot F_{heat\,shdwall} + f_{cool} \cdot F_{cool\,shdwall}\right) $$Unclamped total waste heat (Oleson Eq. 4.55, before the max clamp): W_roof * (f_heat * F_heat_roof + f_cool * F_cool_roof) + (1 - W_roof) * H_W * (f_heat * F_heat_sunwall + f_cool * F_cool_sunwall + f_heat * F_heat_shdwall + f_cool * F_cool_shdwall)
$$ H_{wasteheat} = \mathrm{min}\left(H_{wasteheat\,unclamped}, H_{wasteheat\,max}\right) $$Total waste heat clamped at H_wasteheat_max (Oleson Eq. 4.55): min(H_wasteheat_unclamped, H_wasteheat_max). This is the waste heat dumped to the canyon air after the upper-bound cap is applied
$$ H_{aircond} = F_{cool\,roof} + F_{cool\,sunwall} + F_{cool\,shdwall} $$Heat removed by air conditioning (Oleson Eq. 4.56): F_cool_roof + F_cool_sunwall + F_cool_shdwall — sum of cooling fluxes from all three building surfaces
Analyses
wasteheat_vs_roof_heating_flux_with_clamp
Sweep F_heat_roof from 0 to a value large enough to drive the unclamped waste heat past H_wasteheat_max = 100 W/m^2, with W_roof = 1 (all-roof canyon so walls do not contribute) and all cooling fluxes = 0. Unclamped grows linearly as f_heat * F_heat_roof = (4/3) * F_heat_roof; H_wasteheat tracks it until F_heat_roof = 75 W/m^2 (where unclamped = 100) and then saturates at 100. Surfaces the saturation knee of the Eq. 4.55 clamp directly.
Time span: 0.0 → 1.0
Swept over: F_heat_roof


wasteheat_vs_W_roof_and_H_W_geometry
Joint sweep over (W_roof, H_W) at fixed efficiency-weighted flux contributions to surface the canyon-geometry weighting in Eq. 4.55. Fixed fluxes are chosen so the roof and wall contributions are roughly comparable (F_heat_roof = F_cool_roof = 10, F_heat_sunwall = F_cool_sunwall = F_heat_shdwall = F_cool_shdwall = 6, all in W/m^2). The unclamped waste heat is a bilinear function of W_roof and H_W with a saddle structure: it grows with H_W at fixed W_roof < 1 (more wall contribution), and grows with W_roof at fixed H_W < (roof / wall) (more roof contribution).
Time span: 0.0 → 1.0
Swept over: W_roof, H_W


Raw .esm
Raw .esm JSON (this component)
{
"reference": {
"notes": "source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:440\nUpstream `WasteHeatAirConditioning` is an MTK `@component` with eight `@parameters` (F_heat_roof, F_cool_roof, F_heat_sunwall, F_cool_sunwall, F_heat_shdwall, F_cool_shdwall, W_roof, H_W), three time-indexed `@variables` (H_wasteheat_unclamped, H_wasteheat, H_aircond), and three algebraic equations (no derivatives). Identical equation structure preserved here.\n\nThe upstream component declares three `@constants`, all encoded here as parameters with the upstream default values: f_heat = 1.0/0.75 (heating efficiency factor, dimensionless), f_cool = 1.0/0.25 = 4.0 (cooling efficiency factor, dimensionless), and H_wasteheat_max = 100.0 W/m^2 (maximum waste heat limit on the clamped output). f_heat is encoded as the exact ratio 1.0/0.75 = 1.3333333333333333... in IEEE-754 — the upstream Julia literal `1.0/0.75` resolves to the same double; preserving the value as a parameter default keeps the rational structure visible and matches the convention used by sibling files (heating_cooling_flux.esm preserves alpha_CN = 0.5 and zero_flux = 0.0 W/m^2 as parameters with upstream default values).\n\nThe clamp uses `min(H_wasteheat_unclamped, H_wasteheat_max)` — the upstream uses Julia's two-argument `min` which the ESS AST exposes as the `min` op. When H_wasteheat_unclamped <= H_wasteheat_max, H_wasteheat = H_wasteheat_unclamped (pass-through); when H_wasteheat_unclamped > H_wasteheat_max, H_wasteheat = H_wasteheat_max = 100 W/m^2 exactly. The equality case (H_wasteheat_unclamped == H_wasteheat_max) is well-defined by `min` semantics — both branches give the same numeric value.\n\nThe Eq. 4.56 air-conditioning heat removal H_aircond is a simple three-term sum of cooling fluxes (F_cool_roof + F_cool_sunwall + F_cool_shdwall). It is decoupled from H_wasteheat and the geometry parameters W_roof, H_W — exercised independently in the H_aircond_decoupled_from_geometry test.\n\nObservability classification: this component is functionally observed-only — every output variable is given by a single algebraic equation in terms of the parameters, and the `(t)` time index has no role since there are no derivatives. Test scenarios use `time_span: [0, 1]` and sample at t=0 to mirror the convention used by sibling observed-only ESM files in this rig (heating_cooling_flux.esm, snow_capping_runoff.esm, total_phase_change_energy.esm).\n\nTolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); the equations involve only multiplication, addition, subtraction, and `min` — all at IEEE-754 ULP precision (~1e-16). 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files (heating_cooling_flux.esm uses 1e-9 for the analogous Crank-Nicholson + ifelse equations). Tighter `abs: 1e-12` is asserted on outputs that are exactly zero by construction so the assertion does not silently accept a stuck-at-1e-3 regression."
},
"tolerance": {
"rel": 1e-09
},
"variables": {
"f_heat": {
"type": "parameter",
"units": "1",
"default": 1.3333333333333333,
"description": "Heating efficiency factor (dimensionless) — upstream `@constants` f_heat = 1.0/0.75; multiplies the heating-flux terms in Eq. 4.55 to convert the building floor heating flux into the total waste heat dumped to the canyon air"
},
"f_cool": {
"type": "parameter",
"units": "1",
"default": 4.0,
"description": "Cooling efficiency factor (dimensionless) — upstream `@constants` f_cool = 1.0/0.25 = 4.0; multiplies the cooling-flux terms in Eq. 4.55 to convert the building floor cooling flux into the total waste heat dumped to the canyon air (cooling efficiency is lower than heating, so f_cool > f_heat)"
},
"H_wasteheat_max": {
"type": "parameter",
"units": "W/m^2",
"default": 100.0,
"description": "Maximum waste heat limit (W/m^2) — upstream `@constants` H_wasteheat_max = 100; the `min` clamp in Eq. 4.55 caps the unclamped waste heat at this value to avoid unphysical heat injection into the canyon air during extreme HVAC demand"
},
"F_heat_roof": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Heating flux for roof (W/m^2) — input from a HeatingCoolingFlux instance attached to the roof column; non-negative magnitude of the HVAC heating demand at the roof"
},
"F_cool_roof": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Cooling flux for roof (W/m^2) — input from a HeatingCoolingFlux instance attached to the roof column; non-negative magnitude of the HVAC cooling demand at the roof"
},
"F_heat_sunwall": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Heating flux for sunlit wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the sunlit-wall column"
},
"F_cool_sunwall": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Cooling flux for sunlit wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the sunlit-wall column"
},
"F_heat_shdwall": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Heating flux for shaded wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the shaded-wall column"
},
"F_cool_shdwall": {
"type": "parameter",
"units": "W/m^2",
"default": 0.0,
"description": "Cooling flux for shaded wall (W/m^2) — input from a HeatingCoolingFlux instance attached to the shaded-wall column"
},
"W_roof": {
"type": "parameter",
"units": "1",
"default": 0.3,
"description": "Roof fraction (dimensionless) — fraction of the urban canyon footprint occupied by roof. At W_roof = 1, only the roof term contributes to Eq. 4.55; at W_roof = 0, only the wall terms contribute (weighted by H_W)"
},
"H_W": {
"type": "parameter",
"units": "1",
"default": 1.0,
"description": "Height-to-width ratio (dimensionless) — canyon-wall geometry factor that scales the wall contribution to Eq. 4.55. At H_W = 0, the walls contribute nothing regardless of W_roof; at H_W = 1, the walls have unit weighting on the (1 - W_roof) road-area fraction"
},
"H_wasteheat_unclamped": {
"type": "unknown",
"units": "W/m^2",
"description": "Unclamped total waste heat (Oleson Eq. 4.55, before the max clamp): W_roof * (f_heat * F_heat_roof + f_cool * F_cool_roof) + (1 - W_roof) * H_W * (f_heat * F_heat_sunwall + f_cool * F_cool_sunwall + f_heat * F_heat_shdwall + f_cool * F_cool_shdwall)"
},
"H_wasteheat": {
"type": "unknown",
"units": "W/m^2",
"description": "Total waste heat clamped at H_wasteheat_max (Oleson Eq. 4.55): min(H_wasteheat_unclamped, H_wasteheat_max). This is the waste heat dumped to the canyon air after the upper-bound cap is applied"
},
"H_aircond": {
"type": "unknown",
"units": "W/m^2",
"description": "Heat removed by air conditioning (Oleson Eq. 4.56): F_cool_roof + F_cool_sunwall + F_cool_shdwall — sum of cooling fluxes from all three building surfaces"
}
},
"equations": [
{
"lhs": "H_wasteheat_unclamped",
"rhs": {
"op": "+",
"args": [
{
"op": "*",
"args": [
"W_roof",
{
"op": "+",
"args": [
{
"op": "*",
"args": [
"f_heat",
"F_heat_roof"
]
},
{
"op": "*",
"args": [
"f_cool",
"F_cool_roof"
]
}
]
}
]
},
{
"op": "*",
"args": [
{
"op": "-",
"args": [
1.0,
"W_roof"
]
},
"H_W",
{
"op": "+",
"args": [
{
"op": "*",
"args": [
"f_heat",
"F_heat_sunwall"
]
},
{
"op": "*",
"args": [
"f_cool",
"F_cool_sunwall"
]
},
{
"op": "*",
"args": [
"f_heat",
"F_heat_shdwall"
]
},
{
"op": "*",
"args": [
"f_cool",
"F_cool_shdwall"
]
}
]
}
]
}
]
}
},
{
"lhs": "H_wasteheat",
"rhs": {
"op": "min",
"args": [
"H_wasteheat_unclamped",
"H_wasteheat_max"
]
}
},
{
"lhs": "H_aircond",
"rhs": {
"op": "+",
"args": [
"F_cool_roof",
"F_cool_sunwall",
"F_cool_shdwall"
]
}
}
],
"tests": [
{
"id": "upstream_equation_verification",
"description": "Reproduces upstream `WasteHeatAirConditioning - Equation Verification` test (UrbanCanopy.jl test/roof_wall_road_snow_temperatures_test.jl:369). Canonical case: F_heat_roof=10, F_cool_roof=5, F_heat_sunwall=8, F_cool_sunwall=3, F_heat_shdwall=7, F_cool_shdwall=2 (W/m^2), W_roof=0.3, H_W=1.0. With f_heat=4/3 and f_cool=4 the unclamped waste heat is 0.3*((4/3)*10 + 4*5) + 0.7*1.0*((4/3)*8 + 4*3 + (4/3)*7 + 4*2) = 0.3*(40/3 + 20) + 0.7*40 = 0.3*100/3 + 28 = 10 + 28 = 38 W/m^2 (below the 100 W/m^2 cap, so the clamp is a pass-through). H_aircond = 5 + 3 + 2 = 10 W/m^2. Anchors fidelity to the upstream Julia component at this canonical fixture point.",
"parameter_overrides": {
"F_heat_roof": 10.0,
"F_cool_roof": 5.0,
"F_heat_sunwall": 8.0,
"F_cool_sunwall": 3.0,
"F_heat_shdwall": 7.0,
"F_cool_shdwall": 2.0,
"W_roof": 0.3,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 38.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 38.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 10.0
}
]
},
{
"id": "upstream_max_clamping",
"description": "Reproduces upstream `WasteHeatAirConditioning - Max Clamping` test (UrbanCanopy.jl test/roof_wall_road_snow_temperatures_test.jl:393). 10x larger fluxes than the canonical case: F_heat_roof=100, F_cool_roof=50, F_heat_sunwall=80, F_cool_sunwall=30, F_heat_shdwall=70, F_cool_shdwall=20 (W/m^2), W_roof=0.3, H_W=1.0. The unclamped result is 0.3*((4/3)*100 + 4*50) + 0.7*1.0*((4/3)*80 + 4*30 + (4/3)*70 + 4*20) = 0.3*(400/3 + 200) + 0.7*400 = 0.3*1000/3 + 280 = 100 + 280 = 380 W/m^2, which exceeds H_wasteheat_max = 100, so the clamp activates and H_wasteheat = 100 W/m^2 exactly. H_aircond = 50 + 30 + 20 = 100 W/m^2. Verifies the `min` clamp pins the output at the configured ceiling.",
"parameter_overrides": {
"F_heat_roof": 100.0,
"F_cool_roof": 50.0,
"F_heat_sunwall": 80.0,
"F_cool_sunwall": 30.0,
"F_heat_shdwall": 70.0,
"F_cool_shdwall": 20.0,
"W_roof": 0.3,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 380.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 100.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 100.0
}
]
},
{
"id": "all_zero_inputs",
"description": "Zero-flux limit: every heating and cooling flux is zero (no HVAC demand from any building surface). The unclamped waste heat is 0 regardless of W_roof and H_W, the clamp passes through (min(0, 100) = 0), and the cooling sum is 0. Exercises the additive-zero limit of Eqs. 4.55-4.56 and confirms the geometry parameters do not inject spurious heat when the flux inputs are off.",
"parameter_overrides": {
"F_heat_roof": 0.0,
"F_cool_roof": 0.0,
"F_heat_sunwall": 0.0,
"F_cool_sunwall": 0.0,
"F_heat_shdwall": 0.0,
"F_cool_shdwall": 0.0,
"W_roof": 0.3,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
}
]
},
{
"id": "exact_max_clamp_boundary",
"description": "Boundary case: F_cool_roof=25 alone gives unclamped = 0.3*((4/3)*0 + 4*25) + 0.7*1*0 = 0.3*100 = 30; raising the roof terms so the unclamped result lands exactly at the clamp surfaces the `min(x, x) = x` branch. Concretely, F_cool_roof = 250/3 (≈83.333) and W_roof = 1, H_W arbitrary gives unclamped = 1*((4/3)*0 + 4*(250/3)) = 1000/3 ≈ 333.333 — too large. Use F_cool_roof = 25 with W_roof = 1: unclamped = 4*25 = 100 = H_wasteheat_max exactly. min(100, 100) = 100 by `min` semantics. Verifies the equality branch of the `min` clamp.",
"parameter_overrides": {
"F_heat_roof": 0.0,
"F_cool_roof": 25.0,
"F_heat_sunwall": 0.0,
"F_cool_sunwall": 0.0,
"F_heat_shdwall": 0.0,
"F_cool_shdwall": 0.0,
"W_roof": 1.0,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 100.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 100.0
}
]
},
{
"id": "W_roof_one_only_roof_contributes",
"description": "Limit case W_roof = 1 (all-roof canyon): the wall coefficient (1 - W_roof) = 0 zeroes out the wall terms regardless of H_W and the wall fluxes. Unclamped waste heat collapses to f_heat * F_heat_roof + f_cool * F_cool_roof = (4/3)*15 + 4*6 = 20 + 24 = 44 W/m^2. The clamp passes through (44 < 100). H_aircond remains decoupled from W_roof and sums all three cooling fluxes (6 + 9 + 4 = 19). Isolates the roof contribution to Eq. 4.55 and confirms the (1 - W_roof) factor cleanly removes the wall terms.",
"parameter_overrides": {
"F_heat_roof": 15.0,
"F_cool_roof": 6.0,
"F_heat_sunwall": 8.0,
"F_cool_sunwall": 9.0,
"F_heat_shdwall": 7.0,
"F_cool_shdwall": 4.0,
"W_roof": 1.0,
"H_W": 2.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 44.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 44.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 19.0
}
]
},
{
"id": "W_roof_zero_only_walls_contribute",
"description": "Limit case W_roof = 0 (no roof in canyon, e.g. open-pit street geometry): the roof coefficient W_roof = 0 zeroes out the roof terms regardless of the roof fluxes. Unclamped waste heat collapses to (1 - W_roof) * H_W * (sum of wall efficiency-weighted fluxes) = 1.0 * 1.5 * ((4/3)*6 + 4*3 + (4/3)*9 + 4*5) = 1.5 * (8 + 12 + 12 + 20) = 1.5 * 52 = 78 W/m^2. The clamp passes through (78 < 100). Isolates the wall contribution and confirms H_W scales it linearly. H_aircond = 99 + 3 + 5 = 107 (decoupled, larger than H_wasteheat).",
"parameter_overrides": {
"F_heat_roof": 12.0,
"F_cool_roof": 99.0,
"F_heat_sunwall": 6.0,
"F_cool_sunwall": 3.0,
"F_heat_shdwall": 9.0,
"F_cool_shdwall": 5.0,
"W_roof": 0.0,
"H_W": 1.5
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 78.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 78.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 107.0
}
]
},
{
"id": "H_W_zero_no_wall_contribution",
"description": "Limit case H_W = 0 (flat canyon, no walls): the wall coefficient (1 - W_roof) * H_W = 0 zeroes out the wall terms regardless of W_roof and the wall fluxes. Unclamped waste heat collapses to the roof-only term W_roof * (f_heat * F_heat_roof + f_cool * F_cool_roof) = 0.5 * ((4/3)*12 + 4*9) = 0.5 * (16 + 36) = 26 W/m^2. The clamp passes through. Verifies the canyon-geometry factor cleanly removes the wall contribution and exercises a different W_roof value (0.5) than the canonical 0.3.",
"parameter_overrides": {
"F_heat_roof": 12.0,
"F_cool_roof": 9.0,
"F_heat_sunwall": 80.0,
"F_cool_sunwall": 60.0,
"F_heat_shdwall": 70.0,
"F_cool_shdwall": 50.0,
"W_roof": 0.5,
"H_W": 0.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 26.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 26.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 119.0
}
]
},
{
"id": "H_aircond_decoupled_from_geometry",
"description": "H_aircond depends only on the three cooling fluxes and NOT on W_roof, H_W, or any heating flux. Vary the geometry to extreme values (W_roof = 0.5, H_W = 5) and the heating fluxes to large values (F_heat_* = 200) while keeping the cooling fluxes at the canonical 5/3/2 W/m^2. H_aircond must still equal 5 + 3 + 2 = 10. Verifies Eq. 4.56 is mechanically decoupled from Eq. 4.55 — the clamp surfaces H_wasteheat at H_wasteheat_max = 100 in this scenario since H_wasteheat_unclamped is well above the cap.",
"parameter_overrides": {
"F_heat_roof": 200.0,
"F_cool_roof": 5.0,
"F_heat_sunwall": 200.0,
"F_cool_sunwall": 3.0,
"F_heat_shdwall": 200.0,
"F_cool_shdwall": 2.0,
"W_roof": 0.5,
"H_W": 5.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 100.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 10.0
}
]
},
{
"id": "cooling_only_no_heating",
"description": "Cooling-dominant regime (summer afternoon, all surfaces above the comfort window): every heating flux is zero, every cooling flux is positive. F_cool_roof=8, F_cool_sunwall=12 (hot sunlit wall), F_cool_shdwall=6 (cooler shaded wall), W_roof=0.4, H_W=1.2. Unclamped = 0.4*(0 + 4*8) + 0.6*1.2*(0 + 4*12 + 0 + 4*6) = 0.4*32 + 0.72*(48 + 24) = 12.8 + 0.72*72 = 12.8 + 51.84 = 64.64 W/m^2. Clamp passes through (64.64 < 100). H_aircond = 8 + 12 + 6 = 26 W/m^2. Confirms the cooling-only branch of the efficiency-weighted sum.",
"parameter_overrides": {
"F_heat_roof": 0.0,
"F_cool_roof": 8.0,
"F_heat_sunwall": 0.0,
"F_cool_sunwall": 12.0,
"F_heat_shdwall": 0.0,
"F_cool_shdwall": 6.0,
"W_roof": 0.4,
"H_W": 1.2
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 64.64
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 64.64
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 26.0
}
]
},
{
"id": "heating_only_no_cooling",
"description": "Heating-dominant regime (winter night, all surfaces below the comfort window): every cooling flux is zero, every heating flux is positive. F_heat_roof=12, F_heat_sunwall=15, F_heat_shdwall=18, W_roof=0.25, H_W=2.0. Unclamped = 0.25*((4/3)*12 + 0) + 0.75*2.0*((4/3)*15 + 0 + (4/3)*18 + 0) = 0.25*16 + 1.5*(20 + 24) = 4 + 1.5*44 = 4 + 66 = 70 W/m^2. Clamp passes through (70 < 100). H_aircond = 0 + 0 + 0 = 0 exactly (decoupled from heating fluxes). Confirms the heating-only branch of the efficiency-weighted sum and that H_aircond cleanly drops out when cooling is off.",
"parameter_overrides": {
"F_heat_roof": 12.0,
"F_cool_roof": 0.0,
"F_heat_sunwall": 15.0,
"F_cool_sunwall": 0.0,
"F_heat_shdwall": 18.0,
"F_cool_shdwall": 0.0,
"W_roof": 0.25,
"H_W": 2.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 70.0
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 70.0
},
{
"variable": "H_aircond",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
}
]
},
{
"id": "just_above_clamp_boundary",
"description": "Strict-clamp boundary case: unclamped is set just above H_wasteheat_max via F_cool_roof = 25.01 with W_roof = 1 (all-roof canyon, walls drop out). Unclamped = 1*(0 + 4*25.01) = 100.04, which is greater than H_wasteheat_max = 100, so min(100.04, 100) = 100 exactly. Verifies that the `min` clamp activates at strict overshoot, not equality, and pins the output at exactly the ceiling value.",
"parameter_overrides": {
"F_heat_roof": 0.0,
"F_cool_roof": 25.01,
"F_heat_sunwall": 0.0,
"F_cool_sunwall": 0.0,
"F_heat_shdwall": 0.0,
"F_cool_shdwall": 0.0,
"W_roof": 1.0,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "H_wasteheat_unclamped",
"time": 0.0,
"expected": 100.04
},
{
"variable": "H_wasteheat",
"time": 0.0,
"expected": 100.0
}
]
}
],
"analyses": [
{
"id": "wasteheat_vs_roof_heating_flux_with_clamp",
"description": "Sweep F_heat_roof from 0 to a value large enough to drive the unclamped waste heat past H_wasteheat_max = 100 W/m^2, with W_roof = 1 (all-roof canyon so walls do not contribute) and all cooling fluxes = 0. Unclamped grows linearly as f_heat * F_heat_roof = (4/3) * F_heat_roof; H_wasteheat tracks it until F_heat_roof = 75 W/m^2 (where unclamped = 100) and then saturates at 100. Surfaces the saturation knee of the Eq. 4.55 clamp directly.",
"initial_state": {},
"parameters": {
"F_cool_roof": 0.0,
"F_heat_sunwall": 0.0,
"F_cool_sunwall": 0.0,
"F_heat_shdwall": 0.0,
"F_cool_shdwall": 0.0,
"W_roof": 1.0,
"H_W": 1.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"parameter_sweep": {
"type": "cartesian",
"dimensions": [
{
"parameter": "F_heat_roof",
"range": {
"start": 0.0,
"stop": 150.0,
"count": 31,
"scale": "linear"
}
}
]
},
"plots": [
{
"id": "H_wasteheat_unclamped_curve",
"type": "line",
"description": "Unclamped waste heat vs F_heat_roof: a straight line through the origin with slope f_heat = 4/3 per Eq. 4.55.",
"x": {
"variable": "F_heat_roof",
"label": "F_heat_roof (W/m^2)"
},
"y": {
"variable": "H_wasteheat_unclamped",
"label": "H_wasteheat_unclamped (W/m^2)"
}
},
{
"id": "H_wasteheat_clamped_curve",
"type": "line",
"description": "Clamped waste heat vs F_heat_roof: tracks the unclamped curve up to F_heat_roof = 75 W/m^2 (where the unclamped value equals H_wasteheat_max = 100) and then saturates flat at 100 W/m^2 — the Eq. 4.55 `min` cap.",
"x": {
"variable": "F_heat_roof",
"label": "F_heat_roof (W/m^2)"
},
"y": {
"variable": "H_wasteheat",
"label": "H_wasteheat (W/m^2)"
}
}
]
},
{
"id": "wasteheat_vs_W_roof_and_H_W_geometry",
"description": "Joint sweep over (W_roof, H_W) at fixed efficiency-weighted flux contributions to surface the canyon-geometry weighting in Eq. 4.55. Fixed fluxes are chosen so the roof and wall contributions are roughly comparable (F_heat_roof = F_cool_roof = 10, F_heat_sunwall = F_cool_sunwall = F_heat_shdwall = F_cool_shdwall = 6, all in W/m^2). The unclamped waste heat is a bilinear function of W_roof and H_W with a saddle structure: it grows with H_W at fixed W_roof < 1 (more wall contribution), and grows with W_roof at fixed H_W < (roof / wall) (more roof contribution).",
"initial_state": {},
"parameters": {
"F_heat_roof": 10.0,
"F_cool_roof": 10.0,
"F_heat_sunwall": 6.0,
"F_cool_sunwall": 6.0,
"F_heat_shdwall": 6.0,
"F_cool_shdwall": 6.0
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"parameter_sweep": {
"type": "cartesian",
"dimensions": [
{
"parameter": "W_roof",
"range": {
"start": 0.0,
"stop": 1.0,
"count": 11,
"scale": "linear"
}
},
{
"parameter": "H_W",
"range": {
"start": 0.0,
"stop": 3.0,
"count": 11,
"scale": "linear"
}
}
]
},
"plots": [
{
"id": "H_wasteheat_unclamped_heatmap",
"type": "heatmap",
"description": "H_wasteheat_unclamped as a bilinear function of (W_roof, H_W) per Eq. 4.55: the roof term is linear in W_roof and the wall term is bilinear in (1 - W_roof) * H_W.",
"x": {
"variable": "W_roof",
"label": "W_roof (dimensionless)"
},
"y": {
"variable": "H_W",
"label": "H_W (dimensionless)"
},
"value": {
"variable": "H_wasteheat_unclamped",
"reduce": "final"
}
},
{
"id": "H_wasteheat_heatmap",
"type": "heatmap",
"description": "H_wasteheat (clamped) over the same (W_roof, H_W) grid: same shape as the unclamped surface where it remains below 100 W/m^2, but flattens at 100 W/m^2 in the upper-right where the wall contribution drives the sum past the cap.",
"x": {
"variable": "W_roof",
"label": "W_roof (dimensionless)"
},
"y": {
"variable": "H_W",
"label": "H_W (dimensionless)"
},
"value": {
"variable": "H_wasteheat",
"reduce": "final"
}
}
]
}
]
}