Skip to content

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 none
  • g_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.