mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 93: API mapper window_transmission_details from glazing_type
The API schema lodges `glazing_type` (int code) per window but `window_transmission_details=None` and `frame_factor=None`. Without per-window U lodgement the cascade falls back to a single global `u_window(None,None,None)=2.5` × total area, which over-shot cert 001479's window W/K by +2.63 (cascade 46.23 vs worksheet 43.60). Fix: `_API_GLAZING_TYPE_TO_TRANSMISSION` lookup translates `glazing_type` → (u_value, solar_transmittance, frame_factor) and the mapper populates `WindowTransmissionDetails` + `frame_factor` per window so the cascade uses its per-window U fast path (each window contributes A × U_eff_individual rather than total_area × U_eff_global). Two codes mapped now: 3 → DG pre-2002 U=2.8 g=0.76 FF=0.70 13 → DG post-2022 Argon U=1.4 g=0.72 FF=0.70 Cert 001479 lodges 8 Main windows at glazing_type=3 + 1 Ext1 window at glazing_type=13 — exactly the manufacturer-lodged worksheet values. The cascade now matches the worksheet's `Windows 1: 13.96 × 2.518 = 35.15 W/K` and `Windows 2: 6.37 × 1.3258 = 8.45 W/K` → **windows W/K EXACT 43.5962**. **Cert 001479 API path: fabric heat loss is now COMPLETELY EXACT across all 6 components** (walls/party/roof/floor/windows/doors all match worksheet at the worksheet's 4 d.p. precision). Total fabric: 139.4957 W/K ✓ (was 122.6130 before Slice 87) walls: 39.7652 ✓ party walls: 17.0700 ✓ roof: 10.3438 ✓ floor: 23.1705 ✓ windows: 43.5962 ✓ doors: 5.5500 ✓ API SAP delta progression through Slices 87-93: Slice 87 baseline: +3.0752 After Slice 90: +1.5298 (party walls) After Slice 91: +1.0970 (descriptive strings + roof desc) After Slice 92: +1.0022 (floor dims) After Slice 93: +1.1846 (windows — fabric now EXACT) The +1.18 SAP gap is now PURELY non-fabric: candidates are internal gains, solar gains, ventilation, MIT, or hot water cascade — to diagnose in the next slice. Golden cert residuals updated for the cascade improvements. Pyright net-zero on mapper.py (33 → 33). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
8e752e5720
commit
7281b7b300
2 changed files with 58 additions and 16 deletions
|
|
@ -1524,7 +1524,11 @@ class EpcPropertyDataMapper:
|
|||
glazing_gap=w.glazing_gap,
|
||||
orientation=w.orientation,
|
||||
window_type=w.window_type,
|
||||
frame_factor=w.frame_factor,
|
||||
frame_factor=(
|
||||
w.frame_factor
|
||||
if w.frame_factor is not None
|
||||
else _API_GLAZING_TYPE_TO_TRANSMISSION.get(w.glazing_type, (None, None, None))[2]
|
||||
),
|
||||
glazing_type=w.glazing_type,
|
||||
window_width=_measurement_value(w.window_width),
|
||||
window_height=_measurement_value(w.window_height),
|
||||
|
|
@ -1532,6 +1536,16 @@ class EpcPropertyDataMapper:
|
|||
window_location=w.window_location,
|
||||
window_wall_type=w.window_wall_type,
|
||||
permanent_shutters_present=w.permanent_shutters_present == "Y",
|
||||
# When the API lodgement carries explicit
|
||||
# `window_transmission_details`, pass through verbatim
|
||||
# (Manufacturer-lodged U + solar takes precedence over
|
||||
# the cascade default). Otherwise derive from the
|
||||
# `glazing_type` integer code via the SAP10 lookup —
|
||||
# gives the cascade per-window U-values for the
|
||||
# `windows_have_per_window_u` fast path in
|
||||
# `heat_transmission.py`, matching the cohort
|
||||
# Elmhurst behaviour (which sets these per-window via
|
||||
# `make_window`).
|
||||
window_transmission_details=(
|
||||
WindowTransmissionDetails(
|
||||
u_value=w.window_transmission_details.u_value,
|
||||
|
|
@ -1539,7 +1553,15 @@ class EpcPropertyDataMapper:
|
|||
solar_transmittance=w.window_transmission_details.solar_transmittance,
|
||||
)
|
||||
if w.window_transmission_details is not None
|
||||
else None
|
||||
else (
|
||||
WindowTransmissionDetails(
|
||||
u_value=_API_GLAZING_TYPE_TO_TRANSMISSION[w.glazing_type][0],
|
||||
data_source="SAP10 lookup (glazing_type)",
|
||||
solar_transmittance=_API_GLAZING_TYPE_TO_TRANSMISSION[w.glazing_type][1],
|
||||
)
|
||||
if w.glazing_type in _API_GLAZING_TYPE_TO_TRANSMISSION
|
||||
else None
|
||||
)
|
||||
),
|
||||
permanent_shutters_insulated=w.permanent_shutters_insulated,
|
||||
)
|
||||
|
|
@ -2070,6 +2092,26 @@ def _api_roof_construction_str(value: Optional[int]) -> Optional[str]:
|
|||
_API_FLOOR_HEAT_LOSS_EXPOSED: Final[int] = 1
|
||||
|
||||
|
||||
# GOV.UK API `glazing_type` integer → (u_value W/m²K, g_perpendicular,
|
||||
# frame_factor) lookup the cascade reads via `window_transmission_
|
||||
# details` for per-window cascade fidelity. The cascade defaults to a
|
||||
# single global `u_window(None,None,None)=2.5` and `_G_PERPENDICULAR_
|
||||
# DEFAULT=0.76` when these are unset — close to right for typical
|
||||
# DG-pre-2002 dwellings but wildly off for newer DG (e.g. cert 001479
|
||||
# Ext1 lodges glazing_type=13 → manufacturer DG post-2022 Argon
|
||||
# U=1.4 / g=0.72, vs cascade default U=2.5).
|
||||
#
|
||||
# Codes observed across the 10 golden fixtures: 3 (Main DG pre-2002)
|
||||
# and 13 (Ext1 post-2022 Argon). The wider SAP10.2 glazing-type enum
|
||||
# (4-12, 14+) is not yet mapped — incremental coverage as new
|
||||
# fixtures surface them.
|
||||
_API_GLAZING_TYPE_TO_TRANSMISSION: Dict[int, tuple[float, float, float]] = {
|
||||
# (u_value, solar_transmittance/g_⊥, frame_factor)
|
||||
3: (2.8, 0.76, 0.70), # Double glazed, pre-2002
|
||||
13: (1.4, 0.72, 0.70), # Double glazed, Argon-filled post-2022
|
||||
}
|
||||
|
||||
|
||||
def _api_build_sap_floor_dimensions(
|
||||
fds: List[Any],
|
||||
floor_heat_loss: Optional[int],
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="0300-2747-7640-2526-2135",
|
||||
actual_sap=78,
|
||||
expected_sap_resid=+2,
|
||||
expected_pe_resid_kwh_per_m2=-0.9139,
|
||||
expected_co2_resid_tonnes_per_yr=-0.9974,
|
||||
expected_pe_resid_kwh_per_m2=-0.2955,
|
||||
expected_co2_resid_tonnes_per_yr=-0.9443,
|
||||
notes=(
|
||||
"Large semi-detached, TFA 526, age D, gas boiler PCDB-listed "
|
||||
"(no Table 4b code). Cert lodges open_flues_count=1 + "
|
||||
|
|
@ -119,8 +119,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="6035-7729-2309-0879-2296",
|
||||
actual_sap=70,
|
||||
expected_sap_resid=-5,
|
||||
expected_pe_resid_kwh_per_m2=+37.7305,
|
||||
expected_co2_resid_tonnes_per_yr=+0.8510,
|
||||
expected_pe_resid_kwh_per_m2=+39.1452,
|
||||
expected_co2_resid_tonnes_per_yr=+0.8845,
|
||||
notes=(
|
||||
"Mid-terrace, TFA 128, age A, gas combi Table 4b code 104. "
|
||||
"Slice 59 per-bp window apportionment tightens all 3 "
|
||||
|
|
@ -132,9 +132,9 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
_GoldenExpectation(
|
||||
cert_number="7536-3827-0600-0600-0276",
|
||||
actual_sap=68,
|
||||
expected_sap_resid=+2,
|
||||
expected_pe_resid_kwh_per_m2=-11.7633,
|
||||
expected_co2_resid_tonnes_per_yr=-0.3124,
|
||||
expected_sap_resid=+1,
|
||||
expected_pe_resid_kwh_per_m2=-8.8124,
|
||||
expected_co2_resid_tonnes_per_yr=-0.2337,
|
||||
notes=(
|
||||
"Detached + 2 extensions, TFA 152. Multi-age bps (Main=D, "
|
||||
"Ext1=L, Ext2=F). Slice 59 (per-bp window apportionment) and "
|
||||
|
|
@ -147,8 +147,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="8135-1728-8500-0511-3296",
|
||||
actual_sap=72,
|
||||
expected_sap_resid=+1,
|
||||
expected_pe_resid_kwh_per_m2=-13.0069,
|
||||
expected_co2_resid_tonnes_per_yr=-0.2200,
|
||||
expected_pe_resid_kwh_per_m2=-10.0737,
|
||||
expected_co2_resid_tonnes_per_yr=-0.1645,
|
||||
notes=(
|
||||
"Semi-detached, TFA 102, age C, gas PCDB-listed. Cert lodges "
|
||||
"blocked_chimneys_count=1. Slice 59 per-bp window apportionment "
|
||||
|
|
@ -160,8 +160,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="2130-1033-4050-5007-8395",
|
||||
actual_sap=82,
|
||||
expected_sap_resid=+2,
|
||||
expected_pe_resid_kwh_per_m2=-44.8941,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2250,
|
||||
expected_pe_resid_kwh_per_m2=-43.5103,
|
||||
expected_co2_resid_tonnes_per_yr=+0.2414,
|
||||
notes=(
|
||||
"End-terrace + 1 extension, TFA 64, gas combi PCDB index 17505, "
|
||||
"postcode DE22 (PCDB Table 172 match), PV: 2× 2.04 kWp arrays "
|
||||
|
|
@ -179,9 +179,9 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
_GoldenExpectation(
|
||||
cert_number="0390-2254-6420-2126-5561",
|
||||
actual_sap=65,
|
||||
expected_sap_resid=+1,
|
||||
expected_pe_resid_kwh_per_m2=-3.5091,
|
||||
expected_co2_resid_tonnes_per_yr=-0.0136,
|
||||
expected_sap_resid=+0,
|
||||
expected_pe_resid_kwh_per_m2=-1.9117,
|
||||
expected_co2_resid_tonnes_per_yr=+0.0102,
|
||||
notes=(
|
||||
"End-terrace + 1 extension, TFA 80, gas combi PCDB index 18119, "
|
||||
"no PV, no secondary, postcode LN12 (PCDB Table 172 match). "
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue