mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Audit: pin u_roof description cascade against RdSAP10 Table 16 for golden cert cohort
Mirror of the wall cohort pin. Worksheet fixtures lodge roofs=[] so the description-driven branch of u_roof was never validated at cascade level. New parametrised test pins 8 (description, age, thickness) tuples from the golden certs against the Table 16 col-1 (loft insulation thickness known) value. All 8 cases match spec: u_roof is correct on the thickness-known path even when joined-description from multiple roof rows contains noise. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
15789f5acf
commit
acc6331dc3
1 changed files with 53 additions and 0 deletions
|
|
@ -1230,3 +1230,56 @@ def test_u_wall_matches_table6_for_every_cohort_description_age_pair(
|
|||
|
||||
# Assert
|
||||
assert abs(u - expected_u) < 1e-4
|
||||
|
||||
|
||||
# ----- Description-cascade cohort pins (Roofs) -----
|
||||
#
|
||||
# Mirror of the wall cohort pins above. The Elmhurst worksheet fixtures
|
||||
# lodge `roofs=[]`, so the cascade-pin tests do not exercise u_roof's
|
||||
# description path either. The 8 golden API certs lodge `roofs[].
|
||||
# description` strings — these tests pin each (description, age,
|
||||
# thickness) tuple seen in that cohort against the RdSAP10 Table 16
|
||||
# (loft-insulation-thickness-known) value the spec mandates.
|
||||
#
|
||||
# Excluded: ambiguous joined-description cases where one bp lodges no
|
||||
# thickness and another lodges a value — the calc routes through Table
|
||||
# 18 defaults whose interaction with the description cascade needs
|
||||
# separate pinning. "(another dwelling above)" is also excluded — its
|
||||
# u_roof value is ignored by heat_transmission once roof_area is zeroed.
|
||||
_TABLE_16_ENG_ROOF_COHORT_PINS: tuple[tuple[str, str, int, float], ...] = (
|
||||
# (joined_description, age_band, thickness_mm, expected_u_w_per_m2k)
|
||||
# Table 16 col 1 — thickness-known path, U independent of age band.
|
||||
("Pitched, 100 mm loft insulation", "D", 100, 0.40), # cert 7536 bp0
|
||||
("Pitched, 100 mm loft insulation | Pitched, insulated (assumed)", "D", 100, 0.40), # cert 7536 bp0 (joined)
|
||||
("Pitched, 270 mm loft insulation", "D", 270, 0.16), # cert 0300 bp0
|
||||
("Pitched, 300 mm loft insulation | Flat, no insulation", "D", 300, 0.14), # cert 0390-2954 bp0
|
||||
("Pitched, 300 mm loft insulation | Roof room(s), limited insulation (assumed)", "A", 300, 0.14), # cert 6035 bp0
|
||||
("Pitched, 300 mm loft insulation | Flat, insulated", "C", 300, 0.14), # cert 8135 bp0
|
||||
("Pitched, 300 mm loft insulation | Pitched, 100 mm loft insulation", "B", 300, 0.14), # cert 2130 bp0
|
||||
("Pitched, 400+ mm loft insulation | Pitched, insulated (assumed)", "J", 400, 0.11), # cert 0240 bp0
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"description, age_band, thickness_mm, expected_u",
|
||||
_TABLE_16_ENG_ROOF_COHORT_PINS,
|
||||
)
|
||||
def test_u_roof_matches_table16_for_every_cohort_description_thickness_pair(
|
||||
description: str,
|
||||
age_band: str,
|
||||
thickness_mm: int,
|
||||
expected_u: float,
|
||||
) -> None:
|
||||
# Arrange — inputs replicate what `heat_transmission_from_cert` feeds
|
||||
# `u_roof` for the main building part in the golden cert cohort.
|
||||
|
||||
# Act
|
||||
u = u_roof(
|
||||
country=Country.ENG,
|
||||
age_band=age_band,
|
||||
insulation_thickness_mm=thickness_mm,
|
||||
description=description,
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert abs(u - expected_u) < 1e-4
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue