mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 21a: relabel ambient SAP 10.3 → SAP 10.2 in calculator docstrings
The codebase targets SAP 10.2 (14-03-2025) per ADR-0010 and the values match SAP 10.2 (grid CO2 = 0.136 not 0.086, ECF deflator = 0.42, etc.). But ~35 docstrings/comments labelled formulas / sections / appendices as "SAP 10.3 (13-01-2026)" — mis-labeling without affecting behaviour. Relabels all of them to "SAP 10.2 specification (14-03-2025)" where the formula being implemented is identical between 10.2 and 10.3 (which is the vast majority — §1-§9 heat balance, §11/§13 SAP rating equations, Appendix U climate tables, Table 9a/9c utilisation factor). Intentionally retained: - `worksheet/rating.py:14` — explicit comparison "SAP 10.3 widens these to 0.36 / 16.21 / 108.8 / 120.5" annotating where 10.3 values would differ from the 10.2 values we ship. - `tables/table_12.py` — its docstring explicitly compares 10.2 vs 10.3 CO2 / PEF differences; the file's purpose is the 10.2 → 10.3 reference table, so the 10.3 label is intentional discussion. All 515 passing tests continue to pass (only the 48 known cascade-pin failures from slice 19a remain — those are real residuals, not label issues). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
e2d9f77d0f
commit
20424a2dca
11 changed files with 41 additions and 41 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 synthetic-input calculator orchestrator.
|
"""SAP 10.2 synthetic-input calculator orchestrator.
|
||||||
|
|
||||||
Drives the 12-month heat-balance loop from a typed `CalculatorInputs`
|
Drives the 12-month heat-balance loop from a typed `CalculatorInputs`
|
||||||
aggregate and emits a typed `SapResult`. This module is the physics
|
aggregate and emits a typed `SapResult`. This module is the physics
|
||||||
|
|
@ -26,7 +26,7 @@ Annual totals = month sums; ECF = §13 Table 12 deflator × total cost /
|
||||||
emission factor × delivered fuel (single-fuel approximation in this
|
emission factor × delivered fuel (single-fuel approximation in this
|
||||||
slice — slice S-A8 splits hot-water/lighting onto per-fuel factors).
|
slice — slice S-A8 splits hot-water/lighting onto per-fuel factors).
|
||||||
|
|
||||||
Reference: SAP 10.3 specification (13-01-2026) §§5-13 (pages 23-43), Table
|
Reference: SAP 10.2 specification (14-03-2025) §§5-13 (pages 23-43), Table
|
||||||
9a/9b/9c (pages 184-186), Table 12 (page 191), Appendix L + U.
|
9a/9b/9c (pages 184-186), Table 12 (page 191), Appendix L + U.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ _ZERO_FUEL_COST_RESULT: Final[FuelCostResult] = FuelCostResult(
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class CalculatorInputs:
|
class CalculatorInputs:
|
||||||
"""Synthetic SAP 10.3 calculator inputs. The cert→inputs mapper
|
"""Synthetic SAP 10.2 calculator inputs. The cert→inputs mapper
|
||||||
(S-A7b) produces one of these from an `EpcPropertyData`.
|
(S-A7b) produces one of these from an `EpcPropertyData`.
|
||||||
|
|
||||||
Fuel-cost fields are per-end-use because SAP §12 / Table 32 charges
|
Fuel-cost fields are per-end-use because SAP §12 / Table 32 charges
|
||||||
|
|
@ -224,7 +224,7 @@ class CalculatorInputs:
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class MonthlyEntry:
|
class MonthlyEntry:
|
||||||
"""Per-month worksheet outputs for downstream audit. SAP 10.3 §§5-9."""
|
"""Per-month worksheet outputs for downstream audit. SAP 10.2 §§5-9."""
|
||||||
|
|
||||||
month: int
|
month: int
|
||||||
external_temp_c: float
|
external_temp_c: float
|
||||||
|
|
@ -321,7 +321,7 @@ def _solve_month(
|
||||||
|
|
||||||
|
|
||||||
def calculate_sap_from_inputs(inputs: CalculatorInputs) -> SapResult:
|
def calculate_sap_from_inputs(inputs: CalculatorInputs) -> SapResult:
|
||||||
"""Run SAP 10.3 §§5-13 monthly loop on synthetic inputs; return a
|
"""Run SAP 10.2 §§5-13 monthly loop on synthetic inputs; return a
|
||||||
typed `SapResult`. Cert-shape mapping is the job of `cert_to_inputs`
|
typed `SapResult`. Cert-shape mapping is the job of `cert_to_inputs`
|
||||||
(S-A7b); this entry point is pure physics."""
|
(S-A7b); this entry point is pure physics."""
|
||||||
tfa = inputs.dimensions.total_floor_area_m2
|
tfa = inputs.dimensions.total_floor_area_m2
|
||||||
|
|
@ -521,7 +521,7 @@ def calculate_sap_from_inputs(inputs: CalculatorInputs) -> SapResult:
|
||||||
|
|
||||||
|
|
||||||
class Sap10Calculator:
|
class Sap10Calculator:
|
||||||
"""Deterministic SAP 10.3 calculator entry point. Maps an
|
"""Deterministic SAP 10.2 calculator entry point. Maps an
|
||||||
`EpcPropertyData` to typed `CalculatorInputs` via the RdSAP-driven
|
`EpcPropertyData` to typed `CalculatorInputs` via the RdSAP-driven
|
||||||
`cert_to_inputs` mapper and runs the 12-month worksheet loop.
|
`cert_to_inputs` mapper and runs the 12-month worksheet loop.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""SAP 10.3 Appendix U — climate data lookups.
|
"""SAP 10.2 Appendix U — climate data lookups.
|
||||||
|
|
||||||
Source: BRE, *The Government's Standard Assessment Procedure for Energy
|
Source: BRE, *The Government's Standard Assessment Procedure for Energy
|
||||||
Rating of Dwellings, SAP 10.3* (13-01-2026), Appendix U.
|
Rating of Dwellings, SAP 10.2* (14-03-2025), Appendix U.
|
||||||
|
|
||||||
Three monthly tables across 22 SAP climate regions (index 0 = UK average,
|
Three monthly tables across 22 SAP climate regions (index 0 = UK average,
|
||||||
1-21 = named regions per Table U6 postcode mapping):
|
1-21 = named regions per Table U6 postcode mapping):
|
||||||
|
|
@ -11,7 +11,7 @@ Three monthly tables across 22 SAP climate regions (index 0 = UK average,
|
||||||
- Table U3: Mean global solar irradiance on a horizontal plane (W/m²)
|
- Table U3: Mean global solar irradiance on a horizontal plane (W/m²)
|
||||||
plus monthly solar declination (°)
|
plus monthly solar declination (°)
|
||||||
|
|
||||||
Month is 1-12 (January = 1). Region indices map to the SAP 10.3 region
|
Month is 1-12 (January = 1). Region indices map to the SAP 10.2 region
|
||||||
names; lookup helpers raise `ValueError` on out-of-range inputs so callers
|
names; lookup helpers raise `ValueError` on out-of-range inputs so callers
|
||||||
can fail fast.
|
can fail fast.
|
||||||
"""
|
"""
|
||||||
|
|
@ -109,7 +109,7 @@ def wind_speed_m_per_s(region: int, month: int) -> float:
|
||||||
# Table U3 — Mean global solar irradiance on a horizontal plane (W/m²),
|
# Table U3 — Mean global solar irradiance on a horizontal plane (W/m²),
|
||||||
# 22 regions × 12 months. Used (with Table U3 declination + per-window
|
# 22 regions × 12 months. Used (with Table U3 declination + per-window
|
||||||
# orientation/pitch) to derive surface flux for solar-gains calculation
|
# orientation/pitch) to derive surface flux for solar-gains calculation
|
||||||
# (SAP 10.3 §6.1).
|
# (SAP 10.2 §6.1).
|
||||||
_TABLE_U3: Final[tuple[tuple[float, ...], ...]] = (
|
_TABLE_U3: Final[tuple[tuple[float, ...], ...]] = (
|
||||||
(26, 54, 96, 150, 192, 200, 189, 157, 115, 66, 33, 21), # 0 UK average
|
(26, 54, 96, 150, 192, 200, 189, 157, 115, 66, 33, 21), # 0 UK average
|
||||||
(30, 56, 98, 157, 195, 217, 203, 173, 127, 73, 39, 24), # 1 Thames
|
(30, 56, 98, 157, 195, 217, 203, 173, 127, 73, 39, 24), # 1 Thames
|
||||||
|
|
@ -139,7 +139,7 @@ _TABLE_U3: Final[tuple[tuple[float, ...], ...]] = (
|
||||||
def horizontal_solar_irradiance_w_per_m2(region: int, month: int) -> float:
|
def horizontal_solar_irradiance_w_per_m2(region: int, month: int) -> float:
|
||||||
"""Mean global solar irradiance on a horizontal plane (W/m²) for a SAP
|
"""Mean global solar irradiance on a horizontal plane (W/m²) for a SAP
|
||||||
climate region in a month. The starting point for the per-orientation
|
climate region in a month. The starting point for the per-orientation
|
||||||
surface-flux calculation in SAP 10.3 §6.1."""
|
surface-flux calculation in SAP 10.2 §6.1."""
|
||||||
_validate(region, month)
|
_validate(region, month)
|
||||||
return float(_TABLE_U3[region][month - 1])
|
return float(_TABLE_U3[region][month - 1])
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ _SOLAR_DECLINATION: Final[tuple[float, ...]] = (
|
||||||
|
|
||||||
|
|
||||||
def solar_declination_deg(month: int) -> float:
|
def solar_declination_deg(month: int) -> float:
|
||||||
"""Solar declination angle (°) for the given month. SAP 10.3 Appendix U
|
"""Solar declination angle (°) for the given month. SAP 10.2 Appendix U
|
||||||
Table U3 footer — independent of region."""
|
Table U3 footer — independent of region."""
|
||||||
_validate_month(month)
|
_validate_month(month)
|
||||||
return _SOLAR_DECLINATION[month - 1]
|
return _SOLAR_DECLINATION[month - 1]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""RdSAP 10 cert → SAP 10.3 CalculatorInputs mapping.
|
"""RdSAP 10 cert → SAP 10.2 CalculatorInputs mapping.
|
||||||
|
|
||||||
Reads `EpcPropertyData` (the gov EPC API / site-notes domain model) and
|
Reads `EpcPropertyData` (the gov EPC API / site-notes domain model) and
|
||||||
produces the typed `CalculatorInputs` the synthetic-input orchestrator
|
produces the typed `CalculatorInputs` the synthetic-input orchestrator
|
||||||
|
|
@ -13,7 +13,7 @@ Defaulting rules per RdSAP 10 (10-06-2025):
|
||||||
- Heat transmission: §5 (port in `worksheet/heat_transmission.py`)
|
- Heat transmission: §5 (port in `worksheet/heat_transmission.py`)
|
||||||
- Infiltration: §4 Table 5 (port in `worksheet/ventilation.py`)
|
- Infiltration: §4 Table 5 (port in `worksheet/ventilation.py`)
|
||||||
- Living-area fraction: Table 27 by `habitable_rooms_count`
|
- Living-area fraction: Table 27 by `habitable_rooms_count`
|
||||||
- Heating efficiency: SAP 10.3 Tables 4a/4b (existing
|
- Heating efficiency: SAP 10.2 Tables 4a/4b (existing
|
||||||
`domain.ml.sap_efficiencies.seasonal_efficiency` cascade)
|
`domain.ml.sap_efficiencies.seasonal_efficiency` cascade)
|
||||||
- Hot-water demand: Appendix J (existing `domain.ml.demand`)
|
- Hot-water demand: Appendix J (existing `domain.ml.demand`)
|
||||||
- Lighting demand: Appendix L simplified (`domain.ml.demand`)
|
- Lighting demand: Appendix L simplified (`domain.ml.demand`)
|
||||||
|
|
@ -30,7 +30,7 @@ Edge cases deliberately deferred to Session B:
|
||||||
- control_temperature_adjustment from main_heating_control code 2101/2103/2106
|
- control_temperature_adjustment from main_heating_control code 2101/2103/2106
|
||||||
(defaults to 0)
|
(defaults to 0)
|
||||||
|
|
||||||
Reference: RdSAP 10 specification (10-06-2025); SAP 10.3 specification
|
Reference: RdSAP 10 specification (10-06-2025); SAP 10.2 specification
|
||||||
(13-01-2026) Tables 4a/4b/4e/12.
|
(13-01-2026) Tables 4a/4b/4e/12.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -277,7 +277,7 @@ SAP_10_2_SPEC_PRICES: Final[PriceTable] = PriceTable(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# SAP 10.3 Table 9 main_heating_control codes → control type (1/2/3).
|
# SAP 10.2 Table 9 main_heating_control codes → control type (1/2/3).
|
||||||
# Type 1: no time + temp control, or one but not both.
|
# Type 1: no time + temp control, or one but not both.
|
||||||
# Type 2: programmer + room thermostat (+/− TRVs).
|
# Type 2: programmer + room thermostat (+/− TRVs).
|
||||||
# Type 3: time-and-temperature zone control (e.g. separate living-zone
|
# Type 3: time-and-temperature zone control (e.g. separate living-zone
|
||||||
|
|
@ -376,7 +376,7 @@ def _first_main_heating(epc: EpcPropertyData) -> Optional[MainHeatingDetail]:
|
||||||
|
|
||||||
|
|
||||||
def _control_type(main: Optional[MainHeatingDetail]) -> int:
|
def _control_type(main: Optional[MainHeatingDetail]) -> int:
|
||||||
"""SAP 10.3 §7.1 / Table 9 control type 1/2/3 from the
|
"""SAP 10.2 §7.1 / Table 9 control type 1/2/3 from the
|
||||||
`main_heating_control` code on `MainHeatingDetail`. Defaults to 2
|
`main_heating_control` code on `MainHeatingDetail`. Defaults to 2
|
||||||
(programmer + room thermostat) when the code is missing — the modal
|
(programmer + room thermostat) when the code is missing — the modal
|
||||||
RdSAP case."""
|
RdSAP case."""
|
||||||
|
|
@ -389,7 +389,7 @@ def _control_type(main: Optional[MainHeatingDetail]) -> int:
|
||||||
|
|
||||||
|
|
||||||
def _responsiveness(main: Optional[MainHeatingDetail]) -> float:
|
def _responsiveness(main: Optional[MainHeatingDetail]) -> float:
|
||||||
"""SAP 10.3 Table 9b responsiveness R ∈ [0, 1]. Radiators ≈ 1.0;
|
"""SAP 10.2 Table 9b responsiveness R ∈ [0, 1]. Radiators ≈ 1.0;
|
||||||
underfloor ≈ 0.25. Defaults to radiators."""
|
underfloor ≈ 0.25. Defaults to radiators."""
|
||||||
if main is None:
|
if main is None:
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
@ -656,7 +656,7 @@ def _water_efficiency_with_category_inherit(
|
||||||
|
|
||||||
|
|
||||||
def _co2_factor_kg_per_kwh(main: Optional[MainHeatingDetail]) -> float:
|
def _co2_factor_kg_per_kwh(main: Optional[MainHeatingDetail]) -> float:
|
||||||
"""SAP 10.3 Table 12 CO2 emission factor by fuel code."""
|
"""SAP 10.2 Table 12 CO2 emission factor by fuel code."""
|
||||||
return co2_factor_kg_per_kwh(_main_fuel_code(main))
|
return co2_factor_kg_per_kwh(_main_fuel_code(main))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Parity-validation report for the deterministic SAP 10.3 calculator.
|
"""Parity-validation report for the deterministic SAP 10.2 calculator.
|
||||||
|
|
||||||
ADR-0009 Session B compares `Sap10Calculator.calculate(epc).sap_score`
|
ADR-0009 Session B compares `Sap10Calculator.calculate(epc).sap_score`
|
||||||
to the cert's `energy_rating_current` across a 1000-cert stratified
|
to the cert's `energy_rating_current` across a 1000-cert stratified
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 §1 — dwelling dimensions.
|
"""SAP 10.2 §1 — dwelling dimensions.
|
||||||
|
|
||||||
Builds the typed `Dimensions` aggregate that the rest of the worksheet
|
Builds the typed `Dimensions` aggregate that the rest of the worksheet
|
||||||
reads: total floor area, volume, gross/party wall areas, ground and top
|
reads: total floor area, volume, gross/party wall areas, ground and top
|
||||||
|
|
@ -7,7 +7,7 @@ floor areas, perimeter. Geometry is summed across every entry in
|
||||||
N parts produces totals over all N. Room-in-roof contributes one
|
N parts produces totals over all N. Room-in-roof contributes one
|
||||||
additional storey per part where present (RdSAP §1.8 + §3.9).
|
additional storey per part where present (RdSAP §1.8 + §3.9).
|
||||||
|
|
||||||
Reference: SAP 10.3 specification (13-01-2026), §1 (pages 10-12); for
|
Reference: SAP 10.2 specification (14-03-2025), §1 (pages 10-12); for
|
||||||
existing dwellings see RdSAP 10 §3 (areas and dimensions).
|
existing dwellings see RdSAP 10 §3 (areas and dimensions).
|
||||||
|
|
||||||
Edge cases explicitly out of scope for the first slice (see ADR-0009
|
Edge cases explicitly out of scope for the first slice (see ADR-0009
|
||||||
|
|
@ -34,7 +34,7 @@ _RR_SIMPLIFIED_STOREY_HEIGHT_M: Final[float] = 2.45
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Dimensions:
|
class Dimensions:
|
||||||
"""SAP 10.3 §1 geometric inputs to the monthly heat-balance loop."""
|
"""SAP 10.2 §1 geometric inputs to the monthly heat-balance loop."""
|
||||||
|
|
||||||
total_floor_area_m2: float
|
total_floor_area_m2: float
|
||||||
volume_m3: float
|
volume_m3: float
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ class DwellingExposure:
|
||||||
dwelling. Houses + bungalows expose both floor and roof; flats expose
|
dwelling. Houses + bungalows expose both floor and roof; flats expose
|
||||||
only the surfaces that aren't party with neighbouring dwellings.
|
only the surfaces that aren't party with neighbouring dwellings.
|
||||||
|
|
||||||
SAP 10.3 §3 / RdSAP 10 §5: heat-transmission excludes party surfaces;
|
SAP 10.2 §3 / RdSAP 10 §5: heat-transmission excludes party surfaces;
|
||||||
`party_walls_w_per_k` already captures the party-wall channel using
|
`party_walls_w_per_k` already captures the party-wall channel using
|
||||||
its own U_party.
|
its own U_party.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 mean internal temperature (Tables 9, 9b, 9c).
|
"""SAP 10.2 mean internal temperature (Tables 9, 9b, 9c).
|
||||||
|
|
||||||
The dwelling has two temperature zones during heating periods:
|
The dwelling has two temperature zones during heating periods:
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ Standard SAP heating schedule:
|
||||||
- 9 hours heating per day, two off-periods of 7 h and 8 h (control types 1, 2)
|
- 9 hours heating per day, two off-periods of 7 h and 8 h (control types 1, 2)
|
||||||
- Control type 3 zones the heating: 9 h and 8 h off in 'elsewhere'
|
- Control type 3 zones the heating: 9 h and 8 h off in 'elsewhere'
|
||||||
|
|
||||||
Reference: SAP 10.3 specification (13-01-2026) Table 9 (page 183),
|
Reference: SAP 10.2 specification (14-03-2025) Table 9 (page 183),
|
||||||
Table 9b (page 184), Table 9c (page 185).
|
Table 9b (page 184), Table 9c (page 185).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ def off_period_temperature_reduction_c(
|
||||||
utilisation_factor: float,
|
utilisation_factor: float,
|
||||||
time_constant_h: float,
|
time_constant_h: float,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""SAP 10.3 Table 9b — temperature reduction `u` during a heating-off
|
"""SAP 10.2 Table 9b — temperature reduction `u` during a heating-off
|
||||||
period, in °C below the heating-period temperature.
|
period, in °C below the heating-period temperature.
|
||||||
|
|
||||||
t_c = 4 + 0.25 × τ
|
t_c = 4 + 0.25 × τ
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,12 @@ def energy_cost_factor(
|
||||||
total_cost_gbp: float,
|
total_cost_gbp: float,
|
||||||
total_floor_area_m2: float,
|
total_floor_area_m2: float,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""SAP 10.3 §13 equation (7): ECF = 0.36 × cost / (TFA + 45)."""
|
"""SAP 10.2 §13 equation (7): ECF = 0.36 × cost / (TFA + 45)."""
|
||||||
return ENERGY_COST_DEFLATOR * total_cost_gbp / (total_floor_area_m2 + FLOOR_AREA_OFFSET_M2)
|
return ENERGY_COST_DEFLATOR * total_cost_gbp / (total_floor_area_m2 + FLOOR_AREA_OFFSET_M2)
|
||||||
|
|
||||||
|
|
||||||
def sap_rating(*, ecf: float) -> float:
|
def sap_rating(*, ecf: float) -> float:
|
||||||
"""SAP 10.3 §13 equations (8)/(9). Un-rounded result so callers can
|
"""SAP 10.2 §13 equations (8)/(9). Un-rounded result so callers can
|
||||||
inspect the continuous value; `sap_rating_integer` rounds and clamps."""
|
inspect the continuous value; `sap_rating_integer` rounds and clamps."""
|
||||||
if ecf >= ECF_LOG_THRESHOLD:
|
if ecf >= ECF_LOG_THRESHOLD:
|
||||||
return _SAP_LOG_INTERCEPT - _SAP_LOG_SLOPE * log10(ecf)
|
return _SAP_LOG_INTERCEPT - _SAP_LOG_SLOPE * log10(ecf)
|
||||||
|
|
@ -56,7 +56,7 @@ def sap_rating(*, ecf: float) -> float:
|
||||||
|
|
||||||
|
|
||||||
def sap_rating_integer(*, ecf: float) -> int:
|
def sap_rating_integer(*, ecf: float) -> int:
|
||||||
"""SAP 10.3 §13: round the continuous SAP rating to the nearest integer
|
"""SAP 10.2 §13: round the continuous SAP rating to the nearest integer
|
||||||
and clamp to a minimum of 1 ("if the result of the calculation is less
|
and clamp to a minimum of 1 ("if the result of the calculation is less
|
||||||
than 1 the rating should be quoted as 1"). The integer value is the
|
than 1 the rating should be quoted as 1"). The integer value is the
|
||||||
one published on the EPC."""
|
one published on the EPC."""
|
||||||
|
|
@ -68,7 +68,7 @@ def environmental_impact_rating(
|
||||||
co2_emissions_kg_per_yr: float,
|
co2_emissions_kg_per_yr: float,
|
||||||
total_floor_area_m2: float,
|
total_floor_area_m2: float,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""SAP 10.3 §14 equations (10)-(12). Un-rounded EI rating; mirrors the
|
"""SAP 10.2 §14 equations (10)-(12). Un-rounded EI rating; mirrors the
|
||||||
SAP rating curve but uses CO2 emissions per (TFA + 45) as the input."""
|
SAP rating curve but uses CO2 emissions per (TFA + 45) as the input."""
|
||||||
cf = co2_emissions_kg_per_yr / (total_floor_area_m2 + FLOOR_AREA_OFFSET_M2)
|
cf = co2_emissions_kg_per_yr / (total_floor_area_m2 + FLOOR_AREA_OFFSET_M2)
|
||||||
if cf >= _CF_LOG_THRESHOLD:
|
if cf >= _CF_LOG_THRESHOLD:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 §6 + Appendix U §U3.2 — solar gains.
|
"""SAP 10.2 §6 + Appendix U §U3.2 — solar gains.
|
||||||
|
|
||||||
Two layers:
|
Two layers:
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ Defaults for g⊥ (Table 6b), FF (Table 6c), Z (Table 6d) are deferred to
|
||||||
the cert→inputs mapper slice — this module takes them as caller inputs so
|
the cert→inputs mapper slice — this module takes them as caller inputs so
|
||||||
its physics is independent of cert-shape assumptions.
|
its physics is independent of cert-shape assumptions.
|
||||||
|
|
||||||
Reference: SAP 10.3 specification §6 + Appendix U §§U3.2-3.3 (pages
|
Reference: SAP 10.2 specification §6 + Appendix U §§U3.2-3.3 (pages
|
||||||
127-129); Table U5 columns map 8 cardinal cert orientations to 5
|
127-129); Table U5 columns map 8 cardinal cert orientations to 5
|
||||||
coefficient sets (N, NE/NW, E/W, SE/SW, S).
|
coefficient sets (N, NE/NW, E/W, SE/SW, S).
|
||||||
"""
|
"""
|
||||||
|
|
@ -116,7 +116,7 @@ def surface_solar_flux_w_per_m2(
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Per-orientation per-pitch monthly solar flux on a surface (W/m²).
|
"""Per-orientation per-pitch monthly solar flux on a surface (W/m²).
|
||||||
|
|
||||||
SAP 10.3 Appendix U §U3.2 polynomial conversion from the horizontal
|
SAP 10.2 Appendix U §U3.2 polynomial conversion from the horizontal
|
||||||
irradiance in Table U3 to any orientation/tilt combination.
|
irradiance in Table U3 to any orientation/tilt combination.
|
||||||
"""
|
"""
|
||||||
s_h = horizontal_solar_irradiance_w_per_m2(region, month)
|
s_h = horizontal_solar_irradiance_w_per_m2(region, month)
|
||||||
|
|
@ -146,7 +146,7 @@ def window_solar_gain_w(
|
||||||
frame_factor: float,
|
frame_factor: float,
|
||||||
overshading_factor: float,
|
overshading_factor: float,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Solar gain through a window (W). SAP 10.3 §6.1 equation (5):
|
"""Solar gain through a window (W). SAP 10.2 §6.1 equation (5):
|
||||||
|
|
||||||
G_solar = 0.9 × A_w × S × g⊥ × FF × Z
|
G_solar = 0.9 × A_w × S × g⊥ × FF × Z
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 Table 9c step 10 — monthly space-heating requirement.
|
"""SAP 10.2 Table 9c step 10 — monthly space-heating requirement.
|
||||||
|
|
||||||
Final step of the heating worksheet: the heat the heating system has to
|
Final step of the heating worksheet: the heat the heating system has to
|
||||||
deliver to maintain the mean internal temperature, given the loss rate to
|
deliver to maintain the mean internal temperature, given the loss rate to
|
||||||
|
|
@ -10,7 +10,7 @@ the outside and the gains the dwelling has already accumulated.
|
||||||
If Q_heat would be negative or below 1 kWh in any month, set it to 0 per
|
If Q_heat would be negative or below 1 kWh in any month, set it to 0 per
|
||||||
the Table 9c clamp.
|
the Table 9c clamp.
|
||||||
|
|
||||||
Reference: SAP 10.3 specification (13-01-2026) Table 9c (page 185).
|
Reference: SAP 10.2 specification (14-03-2025) Table 9c (page 185).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -37,7 +37,7 @@ def monthly_heat_requirement_kwh(
|
||||||
total_gains_w: float,
|
total_gains_w: float,
|
||||||
days_in_month: int,
|
days_in_month: int,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""SAP 10.3 Table 9c step 10. Returns delivered kWh required for the
|
"""SAP 10.2 Table 9c step 10. Returns delivered kWh required for the
|
||||||
month; clamps to 0 when below 1 kWh or negative."""
|
month; clamps to 0 when below 1 kWh or negative."""
|
||||||
loss_rate_w = heat_transfer_coefficient_w_per_k * (
|
loss_rate_w = heat_transfer_coefficient_w_per_k * (
|
||||||
internal_temperature_c - external_temperature_c
|
internal_temperature_c - external_temperature_c
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""SAP 10.3 Table 9a — heating utilisation factor η.
|
"""SAP 10.2 Table 9a — heating utilisation factor η.
|
||||||
|
|
||||||
η reduces the contribution of internal + solar gains when they outpace the
|
η reduces the contribution of internal + solar gains when they outpace the
|
||||||
dwelling's heat-loss rate. A well-insulated dwelling with large solar gains
|
dwelling's heat-loss rate. A well-insulated dwelling with large solar gains
|
||||||
|
|
@ -16,7 +16,7 @@ The time constant τ = TMP / (3.6 × HLP) comes from the dwelling's thermal
|
||||||
mass parameter and heat-loss parameter; computed by the orchestrator and
|
mass parameter and heat-loss parameter; computed by the orchestrator and
|
||||||
passed in here.
|
passed in here.
|
||||||
|
|
||||||
Reference: SAP 10.3 specification (13-01-2026) Table 9a (page 184).
|
Reference: SAP 10.2 specification (14-03-2025) Table 9a (page 184).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -28,7 +28,7 @@ def utilisation_factor(
|
||||||
heat_loss_rate_w: float,
|
heat_loss_rate_w: float,
|
||||||
time_constant_h: float,
|
time_constant_h: float,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""SAP 10.3 Table 9a heating utilisation factor η.
|
"""SAP 10.2 Table 9a heating utilisation factor η.
|
||||||
|
|
||||||
γ = total_gains_w / heat_loss_rate_w; η ∈ (0, 1]. When the heat-loss
|
γ = total_gains_w / heat_loss_rate_w; η ∈ (0, 1]. When the heat-loss
|
||||||
rate is non-positive (dwelling already balanced or gaining), η = 1
|
rate is non-positive (dwelling already balanced or gaining), η = 1
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue