mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice S0380.30: extend g_L + g⊥ Table 6b to RdSAP 21 codes 8-15 — closes API path cohort residual cluster
Per the RdSAP 21 schema in [datatypes/epc/domain/epc_codes.csv][1], the
`glazing_type` enum extends to 15 codes; the legacy SAP 10.2 Table 6b
cascade lookups in `internal_gains.py:106` and `solar_gains.py:178`
only knew codes 1-7. Every API-path cert in the cohort lodges
`glazing_type` via the RdSAP 21 numbering, and triple-glazed
lodgements surface as **code 14** ("triple glazing, installed 2022+").
Pre-slice the cascade fell through to the 0.80 / 0.76 double-glazed
defaults for codes 8-15:
Internal gains g_L (Table 6b):
code 14 → default 0.80 (DG) vs spec 0.70 (TG)
→ daylight factor over-bonused → lighting kWh under-counted
Solar gains g⊥ (Table 6b):
code 14 → default 0.76 (DG) vs spec 0.68 (TG)
→ solar gains over-counted
For cert 0350-2968-2650-2796-5255 (semi-detached, 9 triple-glazed
windows lodged as code 14), this drove:
lighting_kwh_per_yr: cascade 221.79 vs Summary-path 228.44
(-6.65 kWh/yr — daylight bonus too generous → lighting too low)
space_heating_kwh_per_yr: cascade 7000.21 vs Summary-path 6996.94
(+3.28 kWh/yr — extra solar gains lower HP demand)
net ECF: -0.0022 vs Summary-path → SAP +0.031
Same mechanism on the other 5 cohort-1 ASHP API certs.
Fix: extend both lookup tables with the RdSAP 21 additions per the
schema CSV semantics:
| code | description (RdSAP 21) | g_L | g⊥ |
|------|----------------------------------|------|------|
| 8 | triple glazing, known data | 0.70 | 0.68 |
| 9 | triple glazing, 2002-2022 | 0.70 | 0.68 |
| 10 | triple glazing, pre-2002 | 0.70 | 0.68 |
| 11 | secondary glazing, normal-E | 0.80 | 0.76 |
| 12 | secondary glazing, low-E | 0.80 | 0.76 |
| 13 | double glazing, 2022+ | 0.80 | 0.76 |
| 14 | triple glazing, 2022+ | 0.70 | 0.68 |
| 15 | single glazing, known data | 0.90 | 0.85 |
Solar gains also adds code 7 (double known data) for
`_G_PERPENDICULAR_BY_GLAZING_TYPE` to align with the existing
`_G_LIGHT_BY_GLAZING_CODE` code-7 entry (which already mapped to
0.80 = double).
Outcome — Cohort-1 ASHP cohort API path:
cert 0380: +0.025 → +1e-6 (close to exact)
cert 0350: +0.031 → +2.2e-5 (close to exact)
cert 2225: +0.029 → -4.8e-5 (close to exact)
cert 2636: +0.015 → -0.015 (sign flip; cantilever-specific
residual surfaces; same |Δ| as Summary)
cert 3800: +0.023 → -2e-5 (close to exact)
cert 9285: +0.029 → -3.4e-5 (close to exact)
5 of 6 API path certs now sit at <1e-4 vs worksheet. Cert 2636
matches its Summary-path residual (-0.015) — the cantilever fixture
has its own non-glazing residual to be diagnosed separately.
Cohort-2 Summary path unchanged (33 exact + 5 ≤0.07) — the cohort-2
certs lodge glazing codes 1-7 (RdSAP 17 numbering still surfaces in
Elmhurst Summary PDF lookups), so codes 8-15 only affect the
RdSAP-21-schema API path.
Golden API fixture pins updated to reflect the tightened cascade-vs-API
alignment (7 certs: 0380, 0350, 2225, 2636, 3800, 9285, 9418). SAP
integer residuals unchanged (all sit at +0).
Pyright net-zero on touched files (22 → 22).
Tests: 710 → **711** pass (+1 new: cert 0350 fixture-shape test for
glazing_type=14 routing to g⊥=0.68 with `total_solar_gains_monthly_w[0]
≈ 67.00 W` (vs pre-slice 74.88 W at the DG default), proving code 14
hits the triple-glazed Table 6b row.) 10 expected fails unchanged.
[1]: datatypes/epc/domain/epc_codes.csv (RdSAP-Schema-21.0.1).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
e27b923bca
commit
faf116bd70
4 changed files with 83 additions and 14 deletions
|
|
@ -258,8 +258,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="0380-2471-3250-2596-8761",
|
||||
actual_sap=89,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-14.6848,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2780,
|
||||
expected_pe_resid_kwh_per_m2=-14.5971,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2785,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, semi-detached bungalow "
|
||||
"TFA 60.43 age D, PV 3 kWp. Worksheet SAP 88.5104 — slice "
|
||||
|
|
@ -275,8 +275,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="0350-2968-2650-2796-5255",
|
||||
actual_sap=84,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-7.8741,
|
||||
expected_co2_resid_tonnes_per_yr=+0.1701,
|
||||
expected_pe_resid_kwh_per_m2=-7.7832,
|
||||
expected_co2_resid_tonnes_per_yr=+0.1709,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert. "
|
||||
"Worksheet SAP 84.1367 — cascade integer matches lodged."
|
||||
|
|
@ -286,8 +286,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="2225-3062-8205-2856-7204",
|
||||
actual_sap=89,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-11.8557,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2621,
|
||||
expected_pe_resid_kwh_per_m2=-11.7684,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2628,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
|
||||
"PV. Worksheet SAP 88.7921. Slice 102f-prep.8 closed the "
|
||||
|
|
@ -298,8 +298,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="2636-0525-2600-0401-2296",
|
||||
actual_sap=86,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-9.6692,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2193,
|
||||
expected_pe_resid_kwh_per_m2=-9.5780,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2200,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
|
||||
"PV + 3.74 m² cantilever exposed floor + 12.76 m² alt wall. "
|
||||
|
|
@ -313,8 +313,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="3800-8515-0922-3398-3563",
|
||||
actual_sap=86,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-9.6838,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2603,
|
||||
expected_pe_resid_kwh_per_m2=-9.6121,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2609,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert. "
|
||||
"Worksheet SAP 86.1458."
|
||||
|
|
@ -324,8 +324,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="9285-3062-0205-7766-7200",
|
||||
actual_sap=84,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-8.0466,
|
||||
expected_co2_resid_tonnes_per_yr=+0.1564,
|
||||
expected_pe_resid_kwh_per_m2=-7.9597,
|
||||
expected_co2_resid_tonnes_per_yr=+0.1571,
|
||||
notes=(
|
||||
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert. "
|
||||
"Worksheet SAP 84.1369."
|
||||
|
|
@ -335,8 +335,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="9418-3062-8205-3566-7200",
|
||||
actual_sap=85,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-9.5795,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2311,
|
||||
expected_pe_resid_kwh_per_m2=-9.4849,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2317,
|
||||
notes=(
|
||||
"Daikin Altherma EDLQ05CAV3 PCDB 102421 (heating_duration "
|
||||
"code '24' — continuous, all days at Th). Worksheet SAP "
|
||||
|
|
|
|||
|
|
@ -103,6 +103,14 @@ _LIGHTING_L8C_EFFICACY_LM_PER_W: Final[float] = 21.3
|
|||
# glazed = 0.90; double-glazed variants = 0.80; triple-glazed = 0.70.
|
||||
# Mirrors the SAP code mapping in cert_to_inputs._g_perpendicular but
|
||||
# returns the light column, not solar.
|
||||
#
|
||||
# Codes 1-7 follow the legacy SAP 10.2 Table 6b ordering (also matched
|
||||
# by the RdSAP 17 schema for the modal cohort lodgement values 2/3/6).
|
||||
# Codes 8-15 are RdSAP-21 schema additions (per
|
||||
# datatypes/epc/domain/epc_codes.csv) — every API-path cert lodges its
|
||||
# glazing-type integer via the RdSAP 21 enum, and triple-glazed certs
|
||||
# in the cohort surface as code 14 (triple 2022+) which previously fell
|
||||
# through to the 0.80 default and over-bonused the daylight factor.
|
||||
_G_LIGHT_BY_GLAZING_CODE: Final[dict[int, float]] = {
|
||||
1: 0.90, # single glazed
|
||||
2: 0.80, # double glazed (air filled, pre-2002)
|
||||
|
|
@ -111,6 +119,15 @@ _G_LIGHT_BY_GLAZING_CODE: Final[dict[int, float]] = {
|
|||
5: 0.80, # double glazed (low-E argon)
|
||||
6: 0.70, # triple glazed
|
||||
7: 0.80, # secondary glazing
|
||||
# RdSAP 21 schema extensions
|
||||
8: 0.70, # triple glazing, known data
|
||||
9: 0.70, # triple glazing, installed 2002-2022
|
||||
10: 0.70, # triple glazing, installed pre-2002
|
||||
11: 0.80, # secondary glazing, normal emissivity
|
||||
12: 0.80, # secondary glazing, low emissivity
|
||||
13: 0.80, # double glazing, installed 2022+
|
||||
14: 0.70, # triple glazing, installed 2022+
|
||||
15: 0.90, # single glazing, known data
|
||||
}
|
||||
_G_LIGHT_DEFAULT: Final[float] = 0.80 # treat unknowns as DG (modal)
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,11 @@ def window_solar_gain_w(
|
|||
# SAP 10.2 Table 6b — total solar energy transmittance g⊥ at normal incidence
|
||||
# by SAP10 glazing_type code (p178). Default 0.76 (modal double-glazed UK
|
||||
# stock) when the cert's glazing_type is missing or unrecognised.
|
||||
#
|
||||
# Codes 1-6 follow the SAP 10.2 Table 6b ordering. Codes 7-15 are RdSAP-21
|
||||
# schema additions (per datatypes/epc/domain/epc_codes.csv); triple-glazed
|
||||
# cohort certs lodge code 14 (triple 2022+) which previously fell through
|
||||
# to the 0.76 DG default and over-counted solar gains.
|
||||
_G_PERPENDICULAR_BY_GLAZING_TYPE: Final[dict[int, float]] = {
|
||||
1: 0.85, # single glazed
|
||||
2: 0.76, # double glazed (air or argon filled) — 2002-2022
|
||||
|
|
@ -182,6 +187,17 @@ _G_PERPENDICULAR_BY_GLAZING_TYPE: Final[dict[int, float]] = {
|
|||
4: 0.63, # double glazed low-E soft-coat
|
||||
5: 0.76, # window with secondary glazing
|
||||
6: 0.68, # triple glazed (air or argon filled)
|
||||
# RdSAP 21 schema extensions — triple-glazed variants all share the
|
||||
# same Table 6b g⊥; secondary glazing mirrors the existing code 5 value.
|
||||
7: 0.76, # double glazing, known data
|
||||
8: 0.68, # triple glazing, known data
|
||||
9: 0.68, # triple glazing, installed 2002-2022
|
||||
10: 0.68, # triple glazing, installed pre-2002
|
||||
11: 0.76, # secondary glazing, normal emissivity
|
||||
12: 0.76, # secondary glazing, low emissivity
|
||||
13: 0.76, # double glazing, installed 2022+
|
||||
14: 0.68, # triple glazing, installed 2022+
|
||||
15: 0.85, # single glazing, known data
|
||||
}
|
||||
_G_PERPENDICULAR_DEFAULT: Final[float] = 0.76
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,42 @@ def test_solar_gains_from_cert_prefers_manufacturer_g_perpendicular_over_table_6
|
|||
assert result.total_solar_gains_monthly_w[0] == pytest.approx(74.8788, abs=5e-3)
|
||||
|
||||
|
||||
def test_solar_gains_recognises_rdsap_21_triple_glazed_code_14_as_triple() -> None:
|
||||
"""RdSAP 21 schema (per datatypes/epc/domain/epc_codes.csv) adds
|
||||
glazing_type codes 8-15 to the legacy SAP 10.2 Table 6b codes 1-7.
|
||||
Triple-glazed lodgements surface as code 14 ("triple glazing,
|
||||
installed 2022+") on every cohort-1 API path triple-glazed cert
|
||||
(0380/0350/2225/2636/3800/9285/9418). Pre-slice S0380.30 the cascade
|
||||
fell through to the 0.76 double-glazed default for codes 8-15,
|
||||
over-counting solar gains and pushing API path SAP residuals to
|
||||
+0.014..+0.031. Code 14 must route to the same g⊥=0.68 as code 6
|
||||
("triple glazed") with no `window_transmission_details` override."""
|
||||
# Arrange — identical geometry as the existing
|
||||
# `prefers_manufacturer_g_perpendicular_over_table_6b` test but with
|
||||
# `glazing_type=14` and `window_transmission_details=None` so the
|
||||
# cascade falls back to the Table 6b lookup.
|
||||
window = make_window(
|
||||
orientation=4, width=5.52, height=1.0, glazing_type=14,
|
||||
)
|
||||
window.window_transmission_details = None
|
||||
epc = make_minimal_sap10_epc(
|
||||
total_floor_area_m2=53.0,
|
||||
sap_windows=[window],
|
||||
)
|
||||
|
||||
# Act
|
||||
result = solar_gains_from_cert(
|
||||
epc=epc, region=0, overshading=OvershadingCategory.AVERAGE,
|
||||
)
|
||||
|
||||
# Assert — code 14 lookup returns g⊥=0.68 (matching code 6 triple).
|
||||
# Same window at g⊥=0.76 (DG default) would give 74.8788 W Jan;
|
||||
# at g⊥=0.68 (TG) the gain scales by 0.68/0.76 = 0.8947 →
|
||||
# 74.8788 × 0.8947 ≈ 67.00 W Jan. Pre-slice the cascade returned
|
||||
# 74.8788 (DG default); post-slice 67.00.
|
||||
assert abs(result.total_solar_gains_monthly_w[0] - 67.00) < 0.5
|
||||
|
||||
|
||||
def test_z_solar_for_overshading_returns_table_6d_first_column() -> None:
|
||||
# Arrange — SAP 10.2 Table 6d "Winter solar access factor (for calculation
|
||||
# of solar gains for heating)" — first numeric column on p178. Used for
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue