mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
fix(u-value): RdSAP10 ignores gov-API wall insulation conductivity → §5.8 default λ
The gov EPC API field wall_insulation_thermal_conductivity is OUTPUT metadata in the openly-published EPC, not an input to the RdSAP10 tool (Elmhurst) that produced it — its wall entry is Type + Insulation + thickness only, with no conductivity field. So the RdSAP10 reduced-data method always uses the SAP 10.2 §5.8 (p.41) default λ=0.04 W/m·K, whatever code the register lodged. `_resolve_wall_insulation_lambda_w_per_mk` previously mapped only code 1 (→0.04) and RAISED on others, blocking cert 2090-6909-8060-5201-6401 (code 3 on an internally-insulated 360mm solid-brick wall) with calc_raise:ValueError. Now it returns the §5.8 default for any code. Validated: 2090 computes to SAP 73.97 vs lodged 74 (err -0.03); λ of 0.04 / 0.03 / 0.025 all round to 74, and Elmhurst exposes no conductivity input, so 0.04 is the spec-faithful RdSAP10 value. Eval computed 905→906; mean|err| 1.708→1.706. Regression green (only the 2 pre-existing stone-wall U failures); pyright net-zero (69=69). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
449d8c5b95
commit
f40485887d
2 changed files with 37 additions and 41 deletions
|
|
@ -177,42 +177,27 @@ WALL_INSULATION_CAVITY_PLUS_INTERNAL: Final[int] = 7
|
|||
# (cavity + external/internal insulation).
|
||||
_WALL_INSULATION_LAMBDA_W_PER_MK: Final[float] = 0.04
|
||||
|
||||
# RdSAP 10 §5.8 (page 41) — when documentary evidence lodges the insulation
|
||||
# thermal conductivity, the R-value calc uses it instead of the 0.04 default.
|
||||
# The spec offers three λ: 0.04 (mineral wool / EPS, the default), 0.03 (XPS),
|
||||
# 0.025 (PUR / PIR / phenolic). The GOV.UK API surfaces a coded value
|
||||
# (`wall_insulation_thermal_conductivity`); code 1 = the default 0.04 (the
|
||||
# only code observed — cert 2130 Ext1, whose documentary-evidence path does
|
||||
# not fire as no wall thickness is lodged, so the value is captured but
|
||||
# unused there). Other codes raise until a worksheet-backed fixture confirms
|
||||
# their λ — the same incremental-coverage discipline as the glazing-type map.
|
||||
_WALL_INSULATION_CONDUCTIVITY_CODE_TO_LAMBDA: Final[dict[int, float]] = {
|
||||
1: 0.04,
|
||||
}
|
||||
|
||||
|
||||
def _resolve_wall_insulation_lambda_w_per_mk(
|
||||
conductivity: "str | int | None",
|
||||
) -> float:
|
||||
"""Resolve the insulation λ (W/m·K) for the §5.8 documentary-evidence
|
||||
R-value calc. Absent / "Unknown" → the 0.04 default; a mapped integer
|
||||
code → its λ; an unmapped integer code raises so the enum is confirmed
|
||||
against a worksheet rather than silently mis-factored."""
|
||||
if conductivity is None:
|
||||
return _WALL_INSULATION_LAMBDA_W_PER_MK
|
||||
if isinstance(conductivity, str):
|
||||
text = conductivity.strip()
|
||||
if not text or text.lower() == "unknown" or not text.isdigit():
|
||||
return _WALL_INSULATION_LAMBDA_W_PER_MK
|
||||
conductivity = int(text)
|
||||
lam = _WALL_INSULATION_CONDUCTIVITY_CODE_TO_LAMBDA.get(conductivity)
|
||||
if lam is None:
|
||||
raise ValueError(
|
||||
"unmapped wall_insulation_thermal_conductivity code "
|
||||
f"{conductivity!r}; add its RdSAP 10 §5.8 λ "
|
||||
"(0.04 / 0.03 / 0.025 W/m·K) once a worksheet confirms it"
|
||||
)
|
||||
return lam
|
||||
"""Insulation λ (W/m·K) for the §5.8 documentary-evidence R-value calc.
|
||||
|
||||
The RdSAP10 reduced-data method does NOT consume the gov-API
|
||||
`wall_insulation_thermal_conductivity` field: the Elmhurst RdSAP10
|
||||
tool exposes no conductivity input (a wall is Type + Insulation +
|
||||
thickness only), so SAP 10.2 §5.8 (p.41) default λ=0.04 W/m·K
|
||||
(mineral wool / EPS) always applies, whatever code the register
|
||||
lodged. The argument is retained for call-site compatibility but
|
||||
every value resolves to the default.
|
||||
|
||||
SAP 10.2 §5.8 also lists 0.03 (XPS) / 0.025 (PUR/PIR/phenolic) for
|
||||
*full* SAP documentary evidence, but those are not selectable in the
|
||||
RdSAP10 path we model. Verified: cert 2090-6909-8060-5201-6401 lodges
|
||||
code 3 on an internally-insulated solid-brick wall and reproduces its
|
||||
lodged SAP 74 at λ=0.04 (continuous 73.97; 0.04/0.03/0.025 all round
|
||||
to 74). Pre-this the helper mapped only code 1 and raised on others,
|
||||
blocking the cert with `unmapped ... code 3`."""
|
||||
return _WALL_INSULATION_LAMBDA_W_PER_MK
|
||||
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1954,15 +1954,26 @@ def test_resolve_wall_insulation_lambda_code_1_is_default_mineral_wool() -> None
|
|||
assert abs(lam_str - 0.04) <= 1e-9
|
||||
|
||||
|
||||
def test_resolve_wall_insulation_lambda_unmapped_code_raises() -> None:
|
||||
# Arrange — an unmapped code must raise (incremental-coverage gate)
|
||||
# rather than silently mis-factor the R-value.
|
||||
import pytest as _pytest
|
||||
|
||||
def test_resolve_wall_insulation_lambda_any_code_uses_default() -> None:
|
||||
# Arrange — the RdSAP10 reduced-data method does NOT consume the
|
||||
# gov-API `wall_insulation_thermal_conductivity` field: the Elmhurst
|
||||
# RdSAP10 tool exposes no conductivity input (a wall is Type +
|
||||
# Insulation + thickness only), so SAP 10.2 §5.8 (p.41) default
|
||||
# λ=0.04 W/m·K always applies regardless of the lodged code. Cert
|
||||
# 2090-6909-8060-5201-6401 lodges code 3 on an internally-insulated
|
||||
# solid-brick wall and reproduces its lodged SAP 74 at λ=0.04
|
||||
# (continuous 73.97; 0.04/0.03/0.025 all round to 74). Pre-this the
|
||||
# helper mapped only code 1 and RAISED on 2/3, blocking the cert.
|
||||
from domain.sap10_ml.rdsap_uvalues import (
|
||||
_resolve_wall_insulation_lambda_w_per_mk,
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
with _pytest.raises(ValueError):
|
||||
_resolve_wall_insulation_lambda_w_per_mk(2)
|
||||
# Act
|
||||
lam_2 = _resolve_wall_insulation_lambda_w_per_mk(2)
|
||||
lam_3 = _resolve_wall_insulation_lambda_w_per_mk(3)
|
||||
lam_3_str = _resolve_wall_insulation_lambda_w_per_mk("3")
|
||||
|
||||
# Assert — every code resolves to the §5.8 default 0.04, never raises.
|
||||
assert abs(lam_2 - 0.04) <= 1e-9
|
||||
assert abs(lam_3 - 0.04) <= 1e-9
|
||||
assert abs(lam_3_str - 0.04) <= 1e-9
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue