mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice S0380.3: surface wall_insulation_type=6 for 'FE Filled Cavity + External'
Extends `_ELMHURST_INSULATION_CODE_TO_SAP10` in `datatypes/epc/domain/mapper.py` with the two-letter dual codes documented on Elmhurst Summary PDFs: "FE" → 6 (Filled cavity + External insulation; cohort fixture) "FI" → 7 (Filled cavity + Internal insulation; mirror, no fixture) The cascade `wall_insulation_type` enum (per `domain/sap10_ml/rdsap_uvalues.py` lines 120-131) treats codes 6 and 7 as composite-resistance walls (filled cavity in series with an external/internal insulation layer), routing through a different U-value calc than the plain filled-cavity default. Cert 0380's Summary lodges `walls.insulation = "FE Filled Cavity + External"` which until this slice fell through `_leading_code` to a missing dict entry and the mapper produced `wall_insulation_type=None`, defaulting the cascade to the as-built path and overstating walls heat loss by +58 W/K. Forcing function (Slice S0380.1): cert 0380 Summary cascade SAP moves from 81.7528 (Δ -6.7576 — i.e. after Slice S0380.2 only) to 86.8671 (Δ -1.6433) — closes ~76% of the remaining gap. `walls_w_per_k` drops from 69.6900 to 24.6238. Residual ~13 W/K wall gap vs API's 11.6150 is the next workstream: `wall_insulation_thickness` is still None on the Summary EPC (API lodges '100mm'). Without the thickness the cascade applies the composite U-value at the dual-code's default thickness rather than the lodged 100 mm. Added focused unit test `test_summary_0380_filled_cavity_plus_external_insulation_routes_to_code_6` that pins both `wall_construction == 4` and `wall_insulation_type == 6` on the mapper boundary, so future debuggers can localise regressions in the dual-code lookup before walking the full chain. Pyright baseline preserved: datatypes/epc/domain/mapper.py: 32 errors (no new errors introduced) backend/documents_parser/tests/test_summary_pdf_mapper_chain.py: 0 errors Regression suite: 671 pass + 11 fail (vs handover baseline 669 + 10 — net +2 pass for the two new GREEN unit tests across Slices S0380.2-3, +1 fail still being the S0380.1 chain test that this slice continues to close but does not yet fully resolve). Spec refs: - SAP 10.2 §3.7 / Table S5 (U-values for masonry walls — composite filled-cavity-plus-insulation calc) - `domain/sap10_ml/rdsap_uvalues.py:120` (RdSAP schema `wall_insulation_type` enum: 6 = filled cavity + external) - Cert 0380 worksheet `dr87-0001-000899.pdf` (lodges Mitsubishi PUZ-WM50VHA ASHP on a cavity wall with subsequent external insulation — the composite-wall fixture) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b1a1bb8dbb
commit
575cdd539a
2 changed files with 33 additions and 0 deletions
|
|
@ -514,6 +514,30 @@ def test_summary_0380_main_heating_category_is_heat_pump() -> None:
|
|||
assert main.main_heating_category == 4
|
||||
|
||||
|
||||
def test_summary_0380_filled_cavity_plus_external_insulation_routes_to_code_6() -> None:
|
||||
# Arrange — cert 0380's Summary lodges main walls as
|
||||
# `wall_type = "CA Cavity"` and `insulation = "FE Filled Cavity +
|
||||
# External"` (a cavity wall with subsequent external-insulation
|
||||
# upgrade). The cascade enum `wall_insulation_type=6` is
|
||||
# "filled cavity + external insulation" (per
|
||||
# `domain.sap10_ml.rdsap_uvalues` lines 120-131); without it the
|
||||
# cascade defaults to the as-built routing and overstates walls
|
||||
# heat loss by +58 W/K on cert 0380 (Summary 69.69 vs API 11.62
|
||||
# at HEAD before this slice). API path EPC for cert 0380 surfaces
|
||||
# `wall_insulation_type=6` and is the ground-truth pin here.
|
||||
pages = _summary_pdf_to_textract_style_pages(_SUMMARY_000899_PDF)
|
||||
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||
|
||||
# Assert
|
||||
assert epc.sap_building_parts, "no building parts surfaced"
|
||||
main = epc.sap_building_parts[0]
|
||||
assert main.wall_construction == 4 # 4 = Cavity ('CA')
|
||||
assert main.wall_insulation_type == 6 # 6 = filled cavity + external
|
||||
|
||||
|
||||
def test_summary_0380_full_chain_sap_matches_worksheet_pdf_exactly() -> None:
|
||||
# Arrange — cert 0380-2471-3250-2596-8761 (Summary_000899.pdf /
|
||||
# dr87-0001-000899.pdf) is the first heat-pump cert under per-cert
|
||||
|
|
|
|||
|
|
@ -2040,12 +2040,21 @@ _ELMHURST_WALL_CODE_TO_SAP10: Dict[str, int] = {
|
|||
|
||||
# Elmhurst wall-insulation-type codes mapped to the SAP10 integer enum
|
||||
# documented at domain.sap10_ml.rdsap_uvalues.WALL_INSULATION_FILLED_CAVITY.
|
||||
# Two-letter dual codes ("FE", "FI") encode a cavity-wall that received a
|
||||
# subsequent external- or internal-insulation upgrade — these map to the
|
||||
# SAP10 composite codes 6 and 7, which the cascade routes through the
|
||||
# series-resistance composite-U calc rather than the filled-cavity table
|
||||
# default. Cert 0380's `walls.insulation = "FE Filled Cavity + External"`
|
||||
# is the cohort fixture pinning the FE branch.
|
||||
_ELMHURST_INSULATION_CODE_TO_SAP10: Dict[str, int] = {
|
||||
"E": 1, # External wall insulation
|
||||
"F": 2, # Filled cavity
|
||||
"I": 3, # Internal wall insulation
|
||||
"A": 4, # As built / assumed (default cascade)
|
||||
"N": 5, # None specified
|
||||
"FE": 6, # Filled cavity + external insulation (cohort: cert 0380)
|
||||
"FI": 7, # Filled cavity + internal insulation (no fixture yet —
|
||||
# mirror of FE for the internal-upgrade variant)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue