mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 100b: API TFA — include per-bp RR floor area in continuous TFA
`_total_floor_area_from_building_parts` previously summed only `sap_floor_dimensions[*].total_floor_area`; the RR floor area lives under `sap_room_in_roof.floor_area` per RdSAP §3.9 convention and was dropped from the per-bp TFA sum. Cert 9501 (113.08 m² real TFA, of which 31.8 m² is RR) showed TFA 81.28 on the API path — the cascade then under-computed occupancy N (Appendix J), HW kWh (Appendix J), lighting kWh (Appendix L), and internal gains. Add the RR contribution to the sum. The top-level `schema.total_floor_area` scalar (integer-rounded for cert 9501: 113 vs raw 113.08) is still the fallback when no per-bp dims are lodged. Re-pinned residuals (improvements — TFA now includes the previously- dropped RR storey): - 0240: SAP -15 → -14, PE +15.69 → +12.49, CO2 +0.90 → +0.70 - 6035: PE +49.51 → +48.30, CO2 +1.14 → +1.10 Effect on cert 9501 API path: TFA 81.28 → 113.08 (= worksheet 113.08 exact). SAP delta still -9.32 vs worksheet — the remaining gap is dominated by the missing PV credit (£250 — next slice). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
8e74b6b8b8
commit
d529f91a8e
2 changed files with 25 additions and 12 deletions
|
|
@ -1875,15 +1875,24 @@ def _measurement_value(field: Any) -> float:
|
|||
|
||||
|
||||
def _total_floor_area_from_building_parts(building_parts: Any) -> Optional[float]:
|
||||
"""Sum per-bp `sap_floor_dimensions[*].total_floor_area` to recover the
|
||||
precise TFA. The GOV.UK EPB API JSON's top-level `total_floor_area`
|
||||
is rounded to the integer (cert 001479: 30.45+30.77+5.37+1.92 = 68.51
|
||||
→ lodged 69), but the worksheet computes continuous SAP from the
|
||||
unrounded geometry. `epc.total_floor_area_m2` is read directly by
|
||||
"""Sum per-bp `sap_floor_dimensions[*].total_floor_area` (plus each bp's
|
||||
`sap_room_in_roof.floor_area` when present) to recover the precise
|
||||
TFA.
|
||||
|
||||
The GOV.UK EPB API JSON's top-level `total_floor_area` is rounded to
|
||||
the integer (cert 001479: 30.45+30.77+5.37+1.92 = 68.51 → lodged 69),
|
||||
but the worksheet computes continuous SAP from the unrounded
|
||||
geometry. `epc.total_floor_area_m2` is read directly by
|
||||
`water_heating_from_cert` to derive occupancy N (Appendix J), which
|
||||
drives HW, lighting (Appendix L), and internal-gains kWh — so the
|
||||
rounded scalar shifts SAP by ~+0.0006 on cert 001479. Returns None
|
||||
when no per-bp dims are lodged so callers fall back to the scalar."""
|
||||
rounded scalar shifts SAP by ~+0.0006 on cert 001479. RR floor area
|
||||
is NOT in `sap_floor_dimensions` on the API path (it lives under
|
||||
`sap_room_in_roof.floor_area` per RdSAP §3.9 convention), so cert
|
||||
9501's RR storey (31.8 m²) was previously dropped from the per-bp
|
||||
TFA sum → TFA 81.28 vs worksheet 113.08.
|
||||
|
||||
Returns None when no per-bp dims are lodged so callers fall back to
|
||||
the scalar."""
|
||||
if not building_parts:
|
||||
return None
|
||||
total = 0.0
|
||||
|
|
@ -1893,6 +1902,10 @@ def _total_floor_area_from_building_parts(building_parts: Any) -> Optional[float
|
|||
for fd in floor_dims:
|
||||
total += _measurement_value(fd.total_floor_area)
|
||||
found = True
|
||||
rir: Any = getattr(bp, "sap_room_in_roof", None)
|
||||
if rir is not None and getattr(rir, "floor_area", None) is not None:
|
||||
total += _measurement_value(rir.floor_area)
|
||||
found = True
|
||||
return total if found else None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -74,9 +74,9 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
_GoldenExpectation(
|
||||
cert_number="0240-0200-5706-2365-8010",
|
||||
actual_sap=73,
|
||||
expected_sap_resid=-15,
|
||||
expected_pe_resid_kwh_per_m2=+15.6873,
|
||||
expected_co2_resid_tonnes_per_yr=+0.8999,
|
||||
expected_sap_resid=-14,
|
||||
expected_pe_resid_kwh_per_m2=+12.4941,
|
||||
expected_co2_resid_tonnes_per_yr=+0.6957,
|
||||
notes=(
|
||||
"Detached house, TFA 118, age J, oil boiler PCDB-listed + PV + "
|
||||
"RR on BP[0]. Mapper DOES extract sap_room_in_roof.room_in_roof_"
|
||||
|
|
@ -135,8 +135,8 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
|
|||
cert_number="6035-7729-2309-0879-2296",
|
||||
actual_sap=70,
|
||||
expected_sap_resid=-6,
|
||||
expected_pe_resid_kwh_per_m2=+49.5139,
|
||||
expected_co2_resid_tonnes_per_yr=+1.1423,
|
||||
expected_pe_resid_kwh_per_m2=+48.3043,
|
||||
expected_co2_resid_tonnes_per_yr=+1.1019,
|
||||
notes=(
|
||||
"Mid-terrace, TFA 128, age A, gas combi Table 4b code 104. "
|
||||
"Slice 59 per-bp window apportionment tightens all 3 "
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue