Solar Usefulness¶
Simulated benefit weights: an ISO 13790 Annex C hourly thermal model
("5R1C") plus perturbation attribution, producing the hourly benefit /
harm series consumed by benefit mode's usefulness_path. See
Carving Modes for the user-level
workflow and Tutorial 5 for a walkthrough.
urbansolarcarver.usefulness
¶
Physics-derived solar usefulness for benefit mode (ISO 13790 5R1C).
Implements the ISO 13790 Annex C simple hourly method ("5R1C" — five conductances, one capacitance) and derives, by perturbation, the marginal usefulness of solar gain at every hour of the year:
benefit[t] = -dQ_heating / dPhi_sol(t) in [0, 1]
harm[t] = +dQ_cooling / dPhi_sol(t) in [0, 1]
The two series are written to a solar_usefulness.json artifact that
benefit mode can consume in place of its balance-point Heaviside filter.
Provenance: this is an independent implementation written directly from
the ISO 13790 Annex C equation set (not a fork or port of an existing
simulator). It is cross-validated against ETH Zurich's RC_BuildingSimulator
(MIT, https://github.com/architecture-building-systems/RC_BuildingSimulator;
Jayathissa et al., Applied Energy 202, 2017) on three archetype scenarios
(medium office, heavy masonry, light insulated) driven by the bundled
Golden TMY3 EPW: annual heating/cooling demand totals to ~1 Wh/year plus
hourly air/mass temperatures and demands at sampled hours, with the
oracle's derived conductances fed in directly so the hourly recurrence is
what is compared. Reference data: tests/data/oracle_5r1c_reference.json;
regression: tests/test_usefulness.py. Design, coefficient provenance,
and declared limitations: design/solar-usefulness.md; user-level
documentation: docs/simulated-weights.md.
This module is deliberately NumPy-only at import time (no torch, no ladybug) so it stays usable as a standalone generator; the EPW-facing helper imports Ladybug lazily.
ZoneParams(floor_area, h_tr_em, h_tr_w, h_tr_is, h_tr_ms, h_ve, c_m, a_m, a_t, t_set_heating=20.0, t_set_cooling=26.0)
dataclass
¶
5R1C parameters, all conductances in W/K, capacitance in J/K.
Use :meth:from_archetype to derive them from physical archetype
inputs per the standard; tests may also construct directly from
known conductances (e.g. oracle-derived values).
from_archetype(floor_area, volume, u_opaque, area_opaque, u_window, area_window, ach_vent, ach_infiltration, heat_recovery=0.0, mass_class='medium', t_set_heating=20.0, t_set_cooling=26.0)
classmethod
¶
Derive the network from archetype inputs per ISO 13790.
- A_tot = 4.5 · A_f; H_tr,is = 3.45 · A_tot
- (A_m, C_m) from the Table-12 mass class
- H_tr,ms = 9.1 · A_m
- H_tr,em = 1 / (1/H_tr,op − 1/H_tr,ms) (§12.2.2 serial split)
- H_ve = 1200 · b_ek · V · ACH_tot/3600, with the heat-recovery adjustment b_ek = 1 − (ACH_vent/ACH_tot) · η_hr (Annex E).
SimulationResult(q_heating_wh, q_cooling_wh, t_air, t_m, demand_w)
dataclass
¶
Annual outcome of :func:simulate (single trajectory).
simulate(p, t_out, phi_int, phi_sol, t_m_init=20.0)
¶
Annual 5R1C simulation of a single zone (Wh demands, °C series).
Parameters are hourly arrays of length 8760: outdoor dry-bulb [°C], internal gains [W], transmitted solar gains [W].
solar_usefulness(p, t_out, phi_int, phi_sol, eps=1.0, t_m_init=20.0)
¶
Marginal hourly solar usefulness by central-difference perturbation.
Returns (benefit, harm), each (8760,) in [0, 1]:
the fraction of one extra watt-hour of solar gain at hour t that
offsets heating demand / becomes cooling load over the year.
Values are marginal at this archetype's operating point; hours at a control-regime switch produce subgradients (smoothed by the central difference). Small out-of-range values from switching noise are clipped; gross violations warn.
transmitted_solar_from_epw(epw_path, windows)
¶
Hourly transmitted solar gain [W] for a set of vertical windows.
windows: sequence of (azimuth_deg, area_m2, g_value); azimuth in
Ladybug convention (0 = N, 90 = E, 180 = S, 270 = W). Irradiance from
the EPW via Ladybug's isotropic directional model.
write_usefulness(path, benefit, harm, meta)
¶
Write the solar_usefulness.json artifact (schema in the design note).
read_usefulness(path)
¶
Read and validate a solar_usefulness.json artifact.
Returns (benefit, harm, meta).
expand_shoebox(archetype)
¶
Expand the shoebox geometry shorthand into explicit archetype areas.
Instead of floor_area / volume / area_opaque / area_window
/ windows, an archetype may describe a rectangular single-zone box:
width— east-west dimension (m)length— north-south dimension (m)height— storey height (m)wwr— window-to-wall ratio per facade, keyed by cardinal name (north/east/south/west); omitted sides get noneg_value— glazing solar transmittance for all windows (default 0.6)orientation— degrees to rotate the box clockwise from north (optional, default 0)
Derived: floor area = width x length; volume = floor area x height;
per-facade window areas = wwr x facade area; area_opaque = opaque
walls + roof (ground slab excluded); area_window = sum of windows.
Archetypes without shoebox keys pass through unchanged.
generate_usefulness(epw_path, archetype, out_path, internal_gains_w_m2=5.0, eps=1.0)
¶
Run the full 5R1C usefulness pipeline: EPW + archetype → artifact.
archetype holds the :meth:ZoneParams.from_archetype keyword
arguments plus windows: a list of [azimuth_deg, area_m2, g_value].
internal_gains_w_m2 is either a single flat value or a 24-value
daily occupancy profile [W/m² per hour of day], tiled over the year.