mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Slice S0380.26: RdSAP10 §5.8 dry-lining adjustment on alt walls — closes cert 7700 -0.44 → +5e-5
Per RdSAP10 §5.8 final note + Table 14 page 41:
"For drylining including laths and plaster use Rinsulation = 0.17 m²K/W."
Applied additively to the base U-value of an otherwise-uninsulated wall:
U_adjusted = 1 / (1/U_base + 0.17) — rounded to 2 d.p. half-up.
Closed form for the cohort fixture (cavity-as-built age C, U_base=1.5):
1 / (1/1.5 + 0.17) = 1.19522... → 1.20 ✓ matches worksheet
Cert 7700-3362-0922-7022-3563 (Summary_000905.pdf / dr87-0001-000905.pdf)
is an End-Terrace house age C lodging:
- Main wall: CavityWallDensePlasterDenseBlock, Filled Cavity, U=0.70
- Alt wall 1: 14.44 m² Cavity As-Built, Dry-lining: Yes (worksheet
`CavityWallPlasterOnDabsDenseBlock`, U=1.20)
Pre-slice the Elmhurst alt-wall mapper hard-coded `wall_dry_lined="N"`
and the cascade ignored the field everywhere — alt-wall U routed to the
cavity-as-built default (1.50), giving fabric (33) 148.72 W/K vs
worksheet 144.38 (Δ +4.33 W/K = ~+0.44 SAP). Worksheet "SAP value" line
lodges unrounded SAP 63.4425.
Implementation:
1. `AlternativeWall.dry_lined: bool = False` on the Elmhurst surveys
dataclass.
2. Elmhurst extractor reads "Alternative Wall N Dry-lining: Yes/No"
into the new field.
3. `_map_elmhurst_alternative_wall` propagates `wall_dry_lined="Y"`
instead of the hard-coded "N".
4. `u_wall` gains a `dry_lined: bool = False` kwarg and a single
§5.8 adjustment site at the as-built bucket (bucket=0). Insulated
buckets already absorb the dry-lining R via Table 14.
5. `_alt_wall_w_per_k` passes `dry_lined=alt_wall.wall_dry_lined == "Y"`.
Scope is the alt-wall path only — main BPs in the corpus all lodge
`wall_dry_lined="N"` (or the Summary PDF omits the field for the main
wall), so the main-wall call site is untouched. Conservative regression
posture per the user's strict cohort-pin convention.
Cohort-2 outcome (38 certs, Summary path):
exact (<1e-4): 22 → **23** (+1: cert 7700 -0.44 → +4.87e-05)
0.07..0.5: 1 → **0** (-1: cert 7700 closes out)
0.5..1: 1 → 1 (cert 9796 unchanged — MIT precision floor)
RAISES: 0 → 0
Cohort-1 ASHP cohort untouched: all certs lodge wall_dry_lined="N", so
the alt-wall call site short-circuits to the original cascade. Verified
no regressions across the 22 previously-exact cohort-2 certs either.
Pyright net-zero on all 8 touched files (183 → 183).
Tests: 704 → 708 pass (+4 new: u_wall §5.8 adjustment fires
correctly; cavity-as-built unchanged without flag; insulated bucket
unaffected by flag; heat_transmission alt-wall delta = 14.44 × 0.30
W/K; cert 7700 full chain hits worksheet 63.4425 at < 1e-4),
10 expected fails unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
73fedc0ecd
commit
c144d444e2
8 changed files with 209 additions and 8 deletions
|
|
@ -294,6 +294,13 @@ class ElmhurstSiteNotesExtractor:
|
||||||
u_value_known=self._local_bool(
|
u_value_known=self._local_bool(
|
||||||
lines, f"Alternative Wall {n} U-value Known"
|
lines, f"Alternative Wall {n} U-value Known"
|
||||||
),
|
),
|
||||||
|
# RdSAP10 §5.8 + Table 14: dry-lined uninsulated wall adds
|
||||||
|
# R = 0.17 m²K/W to base U. Cohort fixture: cert 7700
|
||||||
|
# Alt 1 "CavityWallPlasterOnDabs" lodges Dry-lining: Yes →
|
||||||
|
# U = 1/(1/1.5 + 0.17) ≈ 1.20.
|
||||||
|
dry_lined=self._local_bool(
|
||||||
|
lines, f"Alternative Wall {n} Dry-lining"
|
||||||
|
),
|
||||||
))
|
))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,38 @@ def test_summary_2102_secondary_heating_routes_house_coal_for_open_fire() -> Non
|
||||||
assert epc.sap_heating.secondary_fuel_type == 11
|
assert epc.sap_heating.secondary_fuel_type == 11
|
||||||
|
|
||||||
|
|
||||||
|
def test_summary_7700_full_chain_sap_matches_worksheet_pdf_exactly() -> None:
|
||||||
|
# Arrange — cohort-2 cert 7700-3362-0922-7022-3563 (Summary_000905.pdf
|
||||||
|
# / dr87-0001-000905.pdf) is the first cohort fixture to exercise
|
||||||
|
# the alt-wall dry-lining adjustment. End-Terrace house age C, main
|
||||||
|
# wall filled cavity (CavityWallDensePlasterDenseBlock, U=0.70),
|
||||||
|
# alt wall 14.44 m² Cavity As-Built, Dry-lining: Yes
|
||||||
|
# (CavityWallPlasterOnDabsDenseBlock, worksheet U=1.20).
|
||||||
|
#
|
||||||
|
# Per RdSAP10 §5.8 + Table 14 page 41: dry-lining adds R = 0.17
|
||||||
|
# m²K/W → U = 1/(1/1.5 + 0.17) = 1.19522... → 2 d.p. half-up = 1.20.
|
||||||
|
# Pre-slice the alt sub-area's `wall_dry_lined="N"` hard-code routed
|
||||||
|
# to the cavity-as-built default (U=1.50), giving fabric (33)
|
||||||
|
# 148.72 W/K vs worksheet 144.38 (Δ +4.33 W/K = ~+0.44 SAP). Worksheet
|
||||||
|
# "SAP value" line lodges unrounded SAP **63.4425**.
|
||||||
|
cert_dir = Path(
|
||||||
|
"sap worksheets/additional with api 2/7700-3362-0922-7022-3563"
|
||||||
|
)
|
||||||
|
summary_pdf = next(cert_dir.glob("Summary_*.pdf"))
|
||||||
|
pages = _summary_pdf_to_textract_style_pages(summary_pdf)
|
||||||
|
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||||
|
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = calculate_sap_from_inputs(
|
||||||
|
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
worksheet_unrounded_sap = 63.4425
|
||||||
|
assert abs(result.sap_score_continuous - worksheet_unrounded_sap) < 1e-4
|
||||||
|
|
||||||
|
|
||||||
def test_summary_9501_flat_has_no_built_form_in_summary_pdf() -> None:
|
def test_summary_9501_flat_has_no_built_form_in_summary_pdf() -> None:
|
||||||
# Arrange — cert 9501 (Summary_000784.pdf) is a flat. The Elmhurst
|
# Arrange — cert 9501 (Summary_000784.pdf) is a flat. The Elmhurst
|
||||||
# Summary's §1.0 "Property type" section lodges the built-form
|
# Summary's §1.0 "Property type" section lodges the built-form
|
||||||
|
|
|
||||||
|
|
@ -2875,7 +2875,7 @@ def _map_elmhurst_alternative_wall(
|
||||||
case, matching the full-cert-text "TimberWallOneLayer" lodgement)."""
|
case, matching the full-cert-text "TimberWallOneLayer" lodgement)."""
|
||||||
return SapAlternativeWall(
|
return SapAlternativeWall(
|
||||||
wall_area=a.area_m2,
|
wall_area=a.area_m2,
|
||||||
wall_dry_lined="N",
|
wall_dry_lined="Y" if a.dry_lined else "N",
|
||||||
wall_construction=_elmhurst_wall_construction_int(a.wall_type) or 0,
|
wall_construction=_elmhurst_wall_construction_int(a.wall_type) or 0,
|
||||||
wall_insulation_type=_elmhurst_wall_insulation_int(a.insulation) or 4,
|
wall_insulation_type=_elmhurst_wall_insulation_int(a.insulation) or 4,
|
||||||
wall_thickness_measured="Y" if not a.thickness_unknown else "N",
|
wall_thickness_measured="Y" if not a.thickness_unknown else "N",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,12 @@ class AlternativeWall:
|
||||||
gross wall that has a different construction (e.g. a small 1.43 m²
|
gross wall that has a different construction (e.g. a small 1.43 m²
|
||||||
timber-frame panel on an otherwise cavity-walled extension). Up to
|
timber-frame panel on an otherwise cavity-walled extension). Up to
|
||||||
two alternative walls per bp; Elmhurst lodges them in §7's "1st/2nd
|
two alternative walls per bp; Elmhurst lodges them in §7's "1st/2nd
|
||||||
Extension" subsection under the "Alternative Wall N <field>" prefix."""
|
Extension" subsection under the "Alternative Wall N <field>" prefix.
|
||||||
|
|
||||||
|
`dry_lined` carries Summary §7 "Alternative Wall N Dry-lining: Yes/No".
|
||||||
|
RdSAP10 §5.8 + Table 14: a dry-lined uninsulated wall adds R = 0.17
|
||||||
|
m²K/W to the base U-value (cavity-as-built age C: U = 1/(1/1.5 + 0.17)
|
||||||
|
≈ 1.20). Cohort fixture: cert 7700 alt-wall (CavityWallPlasterOnDabs)."""
|
||||||
|
|
||||||
area_m2: float
|
area_m2: float
|
||||||
wall_type: str # e.g. "TI Timber Frame"
|
wall_type: str # e.g. "TI Timber Frame"
|
||||||
|
|
@ -65,6 +70,7 @@ class AlternativeWall:
|
||||||
thickness_unknown: bool
|
thickness_unknown: bool
|
||||||
thickness_mm: Optional[int]
|
thickness_mm: Optional[int]
|
||||||
u_value_known: bool
|
u_value_known: bool
|
||||||
|
dry_lined: bool = False
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
||||||
|
|
@ -921,5 +921,9 @@ def _alt_wall_w_per_k(
|
||||||
insulation_present=alt_insulation_present,
|
insulation_present=alt_insulation_present,
|
||||||
description=wall_description,
|
description=wall_description,
|
||||||
wall_insulation_type=alt_wall.wall_insulation_type,
|
wall_insulation_type=alt_wall.wall_insulation_type,
|
||||||
|
# RdSAP10 §5.8 + Table 14: dry-lined alt-wall adds R = 0.17 m²K/W
|
||||||
|
# when no insulation thickness is lodged. Cohort fixture: cert
|
||||||
|
# 7700 Alt 1 (Cavity, As-Built, Dry-lined) → 1.50 → 1.20.
|
||||||
|
dry_lined=alt_wall.wall_dry_lined == "Y",
|
||||||
)
|
)
|
||||||
return alt_u * net_alt_area
|
return alt_u * net_alt_area
|
||||||
|
|
|
||||||
|
|
@ -1119,6 +1119,65 @@ def test_basement_alt_wall_uses_table_23_u_value_not_cascade() -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dry_lined_alt_wall_cavity_as_built_age_c_applies_rdsap_5_8_r_0_17_adjustment() -> None:
|
||||||
|
"""RdSAP10 §5.8 + Table 14 page 41: dry-lined uninsulated alt-wall
|
||||||
|
adds R = 0.17 m²K/W. Cohort fixture: cert 7700-3362-0922-7022-3563
|
||||||
|
Alt 1 lodges 14.44 m² Cavity, As-Built, Dry-lining: Yes, age C —
|
||||||
|
worksheet `CavityWallPlasterOnDabsDenseBlock` row (29a) U=1.20,
|
||||||
|
A×U = 14.44 × 1.20 = 17.3280 W/K. Without dry-lining the cascade
|
||||||
|
would route to the cavity-as-built default (U=1.50, A×U=21.66).
|
||||||
|
Difference: 4.33 W/K → ~+0.44 SAP — the entire cert 7700 residual."""
|
||||||
|
from dataclasses import replace
|
||||||
|
# Arrange — age C single-bp dwelling, main wall filled-cavity (U=0.70,
|
||||||
|
# so the difference we isolate sits entirely on the alt sub-area).
|
||||||
|
main_age_c = make_building_part(
|
||||||
|
identifier=BuildingPartIdentifier.MAIN,
|
||||||
|
construction_age_band="C",
|
||||||
|
wall_construction=4,
|
||||||
|
wall_insulation_type=2, # filled cavity → main wall U=0.70
|
||||||
|
party_wall_construction=1, roof_construction=4,
|
||||||
|
floor_dimensions=[
|
||||||
|
make_floor_dimension(
|
||||||
|
total_floor_area_m2=80.0, room_height_m=2.5,
|
||||||
|
party_wall_length_m=0.0, heat_loss_perimeter_m=35.0, floor=0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
with_dry_lined_alt = replace(
|
||||||
|
main_age_c,
|
||||||
|
sap_alternative_wall_1=SapAlternativeWall(
|
||||||
|
wall_area=14.44, wall_dry_lined="Y",
|
||||||
|
wall_construction=4, wall_insulation_type=4,
|
||||||
|
wall_thickness_measured="N",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
without_dry_lined_alt = replace(
|
||||||
|
main_age_c,
|
||||||
|
sap_alternative_wall_1=SapAlternativeWall(
|
||||||
|
wall_area=14.44, wall_dry_lined="N",
|
||||||
|
wall_construction=4, wall_insulation_type=4,
|
||||||
|
wall_thickness_measured="N",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
epc_dry_lined = make_minimal_sap10_epc(
|
||||||
|
total_floor_area_m2=80.0, country_code="ENG",
|
||||||
|
sap_building_parts=[with_dry_lined_alt],
|
||||||
|
)
|
||||||
|
epc_plain = make_minimal_sap10_epc(
|
||||||
|
total_floor_area_m2=80.0, country_code="ENG",
|
||||||
|
sap_building_parts=[without_dry_lined_alt],
|
||||||
|
)
|
||||||
|
result_dry_lined = heat_transmission_from_cert(epc_dry_lined)
|
||||||
|
result_plain = heat_transmission_from_cert(epc_plain)
|
||||||
|
|
||||||
|
# Assert — the alt-wall A×U delta is exactly 14.44 × (1.50 - 1.20)
|
||||||
|
# = 4.3320 W/K. Closed form: 1/(1/1.5 + 0.17) = 1.19522... → 2 d.p. = 1.20.
|
||||||
|
delta = result_plain.walls_w_per_k - result_dry_lined.walls_w_per_k
|
||||||
|
assert abs(delta - (14.44 * (1.50 - 1.20))) <= 1e-9
|
||||||
|
|
||||||
|
|
||||||
def test_basement_floor_uses_table_23_u_value_for_whole_floor_when_basement_detected() -> None:
|
def test_basement_floor_uses_table_23_u_value_for_whole_floor_when_basement_detected() -> None:
|
||||||
"""User-confirmed convention: when a part has a basement, the WHOLE
|
"""User-confirmed convention: when a part has a basement, the WHOLE
|
||||||
floor=0 is the basement floor. Table 23 F-column overrides the
|
floor=0 is the basement floor. Table 23 F-column overrides the
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,12 @@ WALL_INSULATION_CAVITY_PLUS_INTERNAL: Final[int] = 7
|
||||||
# (cavity + external/internal insulation).
|
# (cavity + external/internal insulation).
|
||||||
_WALL_INSULATION_LAMBDA_W_PER_MK: Final[float] = 0.04
|
_WALL_INSULATION_LAMBDA_W_PER_MK: Final[float] = 0.04
|
||||||
|
|
||||||
|
# RdSAP10 §5.8 final note + Table 14 page 41: "For drylining including
|
||||||
|
# laths and plaster use Rinsulation = 0.17 m²K/W." Applied additively to
|
||||||
|
# the base U-value of an otherwise-uninsulated wall when the cert lodges
|
||||||
|
# `wall_dry_lined = "Y"` — see `u_wall(dry_lined=True)`.
|
||||||
|
_DRY_LINING_RESISTANCE_M2K_PER_W: Final[float] = 0.17
|
||||||
|
|
||||||
|
|
||||||
_AGE_BANDS: Final[tuple[str, ...]] = tuple("ABCDEFGHIJKLM")
|
_AGE_BANDS: Final[tuple[str, ...]] = tuple("ABCDEFGHIJKLM")
|
||||||
|
|
||||||
|
|
@ -329,6 +335,7 @@ def u_wall(
|
||||||
insulation_present: bool = False,
|
insulation_present: bool = False,
|
||||||
description: Optional[str] = None,
|
description: Optional[str] = None,
|
||||||
wall_insulation_type: Optional[int] = None,
|
wall_insulation_type: Optional[int] = None,
|
||||||
|
dry_lined: bool = False,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""RdSAP10 wall U-value in W/m^2K, never null.
|
"""RdSAP10 wall U-value in W/m^2K, never null.
|
||||||
|
|
||||||
|
|
@ -344,6 +351,16 @@ def u_wall(
|
||||||
dedicated "Filled cavity" row is used in preference to the
|
dedicated "Filled cavity" row is used in preference to the
|
||||||
thickness-bucketed cascade — the two encode different things (filled-
|
thickness-bucketed cascade — the two encode different things (filled-
|
||||||
cavity is a construction state, not an added-insulation thickness).
|
cavity is a construction state, not an added-insulation thickness).
|
||||||
|
|
||||||
|
`dry_lined` triggers the RdSAP10 §5.8 + Table 14 adjustment:
|
||||||
|
U_adjusted = 1 / (1/U_base + R_dryline) with R_dryline = 0.17 m²K/W.
|
||||||
|
The adjustment is applied only when the base U comes from the
|
||||||
|
uninsulated bucket (no measured insulation thickness, no filled-cavity
|
||||||
|
branch, no surveyor "described as insulated" override) — for those
|
||||||
|
branches the dry-lining R is already absorbed into the assumed
|
||||||
|
insulation stack. Cohort fixture: cert 7700 Alt 1 cavity-as-built
|
||||||
|
age C with Dry-lining: Yes — base U=1.5 → adjusted U=1.20 (2 d.p.,
|
||||||
|
matching worksheet `CavityWallPlasterOnDabsDenseBlock`).
|
||||||
"""
|
"""
|
||||||
measured = _measured_u_from_description(description)
|
measured = _measured_u_from_description(description)
|
||||||
if measured is not None:
|
if measured is not None:
|
||||||
|
|
@ -394,12 +411,21 @@ def u_wall(
|
||||||
# Country override first.
|
# Country override first.
|
||||||
overrides = _COUNTRY_KLM_OVERRIDES.get(ctry, {}).get((wall_type, bucket), {})
|
overrides = _COUNTRY_KLM_OVERRIDES.get(ctry, {}).get((wall_type, bucket), {})
|
||||||
if band in overrides:
|
if band in overrides:
|
||||||
return overrides[band]
|
u_base = overrides[band]
|
||||||
|
else:
|
||||||
base = _ENG_WALL.get((wall_type, bucket))
|
base = _ENG_WALL.get((wall_type, bucket))
|
||||||
if base is None:
|
u_base = base[age_idx] if base is not None else 1.5
|
||||||
return 1.5
|
# RdSAP10 §5.8 + Table 14 page 41 — dry-lining (including lath and
|
||||||
return base[age_idx]
|
# plaster) adds R = 0.17 m²K/W to an otherwise-uninsulated wall:
|
||||||
|
# U_adjusted = 1 / (1/U_base + 0.17), rounded to 2 d.p. half-up.
|
||||||
|
# Only the as-built uninsulated bucket triggers the adjustment;
|
||||||
|
# insulated buckets already incorporate the dry-lining R via Table 14.
|
||||||
|
if dry_lined and bucket == 0:
|
||||||
|
u_unrounded = 1.0 / (1.0 / u_base + _DRY_LINING_RESISTANCE_M2K_PER_W)
|
||||||
|
return float(
|
||||||
|
Decimal(str(u_unrounded)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||||
|
)
|
||||||
|
return u_base
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,73 @@ def test_u_wall_unfilled_cavity_england_age_band_e_unchanged_at_1_5() -> None:
|
||||||
assert result == pytest.approx(1.5, abs=0.001)
|
assert result == pytest.approx(1.5, abs=0.001)
|
||||||
|
|
||||||
|
|
||||||
|
def test_u_wall_dry_lined_cavity_as_built_age_c_applies_rdsap_5_8_r_0_17_adjustment() -> None:
|
||||||
|
# Arrange — RdSAP10 §5.8 final note + Table 14 page 41: "For drylining
|
||||||
|
# including laths and plaster use Rinsulation = 0.17 m²K/W." Applied
|
||||||
|
# additively to the base U-value of an otherwise-uninsulated wall.
|
||||||
|
# Cohort fixture: cert 7700-3362-0922-7022-3563 Alt 1 lodges Cavity,
|
||||||
|
# As-Built, Dry-lining: Yes, age band C → worksheet
|
||||||
|
# `CavityWallPlasterOnDabsDenseBlock` U-value = 1.20 W/m²K.
|
||||||
|
# Closed form: 1 / (1/1.5 + 0.17) = 1.19522... → 2 d.p. half-up = 1.20.
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = u_wall(
|
||||||
|
country=Country.ENG,
|
||||||
|
age_band="C",
|
||||||
|
construction=WALL_CAVITY,
|
||||||
|
insulation_thickness_mm=None,
|
||||||
|
insulation_present=False,
|
||||||
|
wall_insulation_type=4,
|
||||||
|
dry_lined=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert — adjusted U is rounded to 2 d.p. matching the dr87 worksheet's
|
||||||
|
# `UValueFinal` column for this construction.
|
||||||
|
assert abs(result - 1.20) <= 1e-9
|
||||||
|
|
||||||
|
|
||||||
|
def test_u_wall_not_dry_lined_cavity_as_built_age_c_returns_unadjusted_1_5() -> None:
|
||||||
|
# Arrange — same age + construction as the dry-lined case above but
|
||||||
|
# without the dry-lining flag. Cascade must return the bare Table 6
|
||||||
|
# "Cavity as built" row value (no R = 0.17 added).
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = u_wall(
|
||||||
|
country=Country.ENG,
|
||||||
|
age_band="C",
|
||||||
|
construction=WALL_CAVITY,
|
||||||
|
insulation_thickness_mm=None,
|
||||||
|
insulation_present=False,
|
||||||
|
wall_insulation_type=4,
|
||||||
|
dry_lined=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert abs(result - 1.50) <= 1e-9
|
||||||
|
|
||||||
|
|
||||||
|
def test_u_wall_dry_lined_with_measured_insulation_thickness_no_adjustment() -> None:
|
||||||
|
# Arrange — once a measured insulation thickness is lodged, Table 6's
|
||||||
|
# insulated buckets already incorporate the dry-lining R via Table 14.
|
||||||
|
# Applying R = 0.17 on top would double-count. Cavity + 100 mm
|
||||||
|
# insulation, age band E → Table 6 cavity-100mm row = 0.32 W/m²K
|
||||||
|
# regardless of the dry-lining flag.
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = u_wall(
|
||||||
|
country=Country.ENG,
|
||||||
|
age_band="E",
|
||||||
|
construction=WALL_CAVITY,
|
||||||
|
insulation_thickness_mm=100,
|
||||||
|
insulation_present=True,
|
||||||
|
wall_insulation_type=4,
|
||||||
|
dry_lined=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert abs(result - 0.32) <= 1e-9
|
||||||
|
|
||||||
|
|
||||||
def test_u_wall_cavity_as_built_england_age_band_g_returns_table6_value() -> None:
|
def test_u_wall_cavity_as_built_england_age_band_g_returns_table6_value() -> None:
|
||||||
# Arrange — Table 6, England, Cavity as built, age band G -> 0.60 W/m^2K.
|
# Arrange — Table 6, England, Cavity as built, age band G -> 0.60 W/m^2K.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue