mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice S0380.160: SAP 10.2 Table 5a wet-pump gate for central heating gain
SAP 10.2 Table 5a (PDF p.177) row "Central heating pump in heated
space" only applies to mains with a water-loop circulation pump.
Footnote a) names two exclusions verbatim ("Does not apply if a
heating system used solely for domestic hot water. ... Not applicable
for electric heat pumps from database."), and the row's name carries
the implicit third: dry mains with no central heating pump (electric
storage heaters, electric direct-acting, solid-fuel room heaters
without back-boilers) — the row simply doesn't list them.
Pre-slice `internal_gains_from_cert` gated only on Note a) (HP
exclusion), applying `central_heating_pump_w(date_category=...)` to
every non-HP main. The default UNKNOWN-date branch added 7 W of pump
gain to (70)m for every dry-system fixture in the controlled-variable
corpus, even though the worksheet (70)m = 0 every month.
Per-line walk on electric 3 (SAP code 401 "Manual charge control"):
cascade (73)[Jan] = 640.21 W
worksheet (73)[Jan] = 633.21 W delta = +7.00 W
cascade (70)[Jan] = 7.00 W
worksheet (70)[Jan] = 0.00 W Table 5a inapplicable
The +7 W winter-month gain lowered cascade SH demand by ~38 kWh/yr
(cascade 11050 vs worksheet 11088). At Table 32 18-hour low-rate
~7.4 p/kWh that's £2.50/yr under-charging — matching the cluster's
uniform Δcost = -£1.96..-£2.80 pattern. Continuous SAP rose ~+0.10
because cost dominates the ECF.
Fix: new `_any_main_system_has_central_heating_pump(epc)` predicate
in `internal_gains.py`, mirroring `cert_to_inputs._is_wet_boiler_main`
(S0380.149 — Table 4f kWh side). Wet if any non-HP main lodges:
- sap_main_heating_code in {101-141, 151-161, 191-196} (gas/oil/
solid-fuel/electric boilers per Table 4a/4b),
- main_heating_index_number (PCDB Table 322 record),
- main_heating_category in {1, 2} (RdSAP central heating), OR
- heat_emitter_type in {1, 3} (radiators / fan-coil per Table 4d).
Dead `_all_main_systems_are_heat_pumps` helper removed (the new
predicate subsumes its role).
Cluster closures (10 variants):
electric 3: SAP +0.1215 → -0.0000, cost -£2.80 → -£0.00
electric 5: SAP +0.1081 → -0.0000, cost -£2.49 → -£0.00
electric 6: SAP +0.1081 → -0.0000, cost -£2.49 → -£0.00
electric 7: SAP +0.1017 → -0.0000, cost -£2.34 → -£0.00
electric 8: SAP +0.0941 → -0.0000, cost -£2.17 → -£0.00
electric 9: SAP +0.1199 → -0.0000, cost -£2.76 → -£0.00
solid fuel 4: SAP +0.0850 → -0.0000, cost -£1.96 → -£0.00
solid fuel 9: SAP +0.1072 → -0.0000, cost -£2.47 → -£0.00
solid fuel 10: SAP +0.1134 → +0.0000, cost -£2.61 → -£0.00
solid fuel 11: SAP +0.0912 → +0.0000, cost -£2.10 → +£0.00
Σ |ΔSAP_c| across 25-variant cohort: 1.24 → 0.18. All 10 cluster
variants now join the lighting-PE +48.66 / CO2 +11.95 deferred
cohort (Elmhurst-vs-spec monthly factor quirk, same shape as
electric 1 + solid fuel 5/6/7/8 from prior closures).
Verbatim spec quote (SAP 10.2 Table 5a row 1, PDF p.177):
"Central heating pump in heated space, 2013 or later 3 a)"
"Central heating pump in heated space, 2012 or earlier 10 a)"
"Central heating pump in heated space, unknown date 7 a)"
The row name ("Central heating pump") gates by construction: dry
systems have no central heating pump and the row's three sub-rows
don't apply.
No regressions on the other 31 variants or any golden fixture; the
6 Elmhurst U985 fixtures lodge PCDB index → the new predicate
returns True → pump_w unchanged.
Tests: 904 pass (+1), 0 fail. Pyright net-zero (35 → 35).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
0261f446f0
commit
af34ad9846
3 changed files with 165 additions and 31 deletions
|
|
@ -304,16 +304,31 @@ class _CorpusExpectation:
|
|||
# (cascade SH demand +57 kWh vs worksheet — Cat 5 specific). No
|
||||
# regressions on the other 24 variants — gate keyed on the new
|
||||
# warm-air-code frozenset and only electric 2 has a code in that set.
|
||||
#
|
||||
# Slice S0380.160 closed the 10-variant cluster (electric 3/5/6/7/8/9
|
||||
# + solid fuel 4/9/10/11) by gating SAP 10.2 Table 5a row "Central
|
||||
# heating pump in heated space" (PDF p.177) on whether the cert lodges
|
||||
# a wet, non-HP main. Pre-slice the cascade added 7 W of pump gain
|
||||
# (UNKNOWN-date default) to (70)m for every non-HP main; per the per-
|
||||
# line walk on electric 3, worksheet (70)m = 0 across all 12 months
|
||||
# because storage heaters / dry room heaters have no primary water
|
||||
# loop. The +7 W winter gain was lowering cascade SH demand by ~38
|
||||
# kWh/yr (cascade 11050 vs worksheet 11088 for electric 3), in turn
|
||||
# under-charging cost by ~£2.50 and pushing continuous SAP up ~+0.10.
|
||||
# Cluster SAP / cost / CO2 (rating block) now EXACT for all 10
|
||||
# variants; only the lighting-PE +48.66 / +11.95 CO2 deferred quirk
|
||||
# remains (same offset as electric 1 + solid fuel 5/6/7/8). Cluster
|
||||
# Σ|ΔSAP_c| 1.06 → 0.00 in one slice.
|
||||
_EXPECTATIONS: tuple[_CorpusExpectation, ...] = (
|
||||
_CorpusExpectation(variant='ashp', block='11a', expected_sap_resid=-0.0240, expected_cost_resid_gbp=+0.5536, expected_co2_resid_kg=+7.3267, expected_pe_resid_kwh=+36.3435),
|
||||
_CorpusExpectation(variant='electric 1', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6605),
|
||||
_CorpusExpectation(variant='electric 2', block='11a', expected_sap_resid=-0.1087, expected_cost_resid_gbp=+2.5037, expected_co2_resid_kg=+16.5405, expected_pe_resid_kwh=+97.6875),
|
||||
_CorpusExpectation(variant='electric 3', block='11a', expected_sap_resid=+0.1215, expected_cost_resid_gbp=-2.8003, expected_co2_resid_kg=+6.7227, expected_pe_resid_kwh=-5.9859),
|
||||
_CorpusExpectation(variant='electric 5', block='11a', expected_sap_resid=+0.1081, expected_cost_resid_gbp=-2.4918, expected_co2_resid_kg=+7.2978, expected_pe_resid_kwh=+0.0658),
|
||||
_CorpusExpectation(variant='electric 6', block='11a', expected_sap_resid=+0.1081, expected_cost_resid_gbp=-2.4918, expected_co2_resid_kg=+7.3225, expected_pe_resid_kwh=+0.1603),
|
||||
_CorpusExpectation(variant='electric 7', block='11a', expected_sap_resid=+0.1017, expected_cost_resid_gbp=-2.3444, expected_co2_resid_kg=+7.6424, expected_pe_resid_kwh=+3.0976),
|
||||
_CorpusExpectation(variant='electric 8', block='11a', expected_sap_resid=+0.0941, expected_cost_resid_gbp=-2.1679, expected_co2_resid_kg=+7.9230, expected_pe_resid_kwh=+6.5824),
|
||||
_CorpusExpectation(variant='electric 9', block='11a', expected_sap_resid=+0.1199, expected_cost_resid_gbp=-2.7611, expected_co2_resid_kg=+6.8225, expected_pe_resid_kwh=-4.5085),
|
||||
_CorpusExpectation(variant='electric 3', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='electric 5', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='electric 6', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9452, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='electric 7', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9452, expected_pe_resid_kwh=+48.6605),
|
||||
_CorpusExpectation(variant='electric 8', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='electric 9', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9452, expected_pe_resid_kwh=+48.6605),
|
||||
_CorpusExpectation(variant='gshp', block='11a', expected_sap_resid=-0.0178, expected_cost_resid_gbp=+0.4092, expected_co2_resid_kg=+7.0616, expected_pe_resid_kwh=+33.5171),
|
||||
_CorpusExpectation(variant='oil 1', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+0.0000, expected_pe_resid_kwh=+0.0000),
|
||||
_CorpusExpectation(variant='oil pcdb 1', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=-0.0000, expected_pe_resid_kwh=+0.0000),
|
||||
|
|
@ -329,14 +344,14 @@ _EXPECTATIONS: tuple[_CorpusExpectation, ...] = (
|
|||
# control-type gaps — separate slices.
|
||||
_CorpusExpectation(variant='solid fuel 2', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=-93.0988, expected_pe_resid_kwh=-1027.5099),
|
||||
_CorpusExpectation(variant='solid fuel 3', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+0.0000, expected_pe_resid_kwh=-0.0000),
|
||||
_CorpusExpectation(variant='solid fuel 4', block='11a', expected_sap_resid=+0.0850, expected_cost_resid_gbp=-1.9582, expected_co2_resid_kg=-9.3050, expected_pe_resid_kwh=-5.7762),
|
||||
_CorpusExpectation(variant='solid fuel 4', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9452, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 5', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 6', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9452, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 7', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 8', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 9', block='11a', expected_sap_resid=+0.1072, expected_cost_resid_gbp=-2.4702, expected_co2_resid_kg=+9.6917, expected_pe_resid_kwh=-5.0715),
|
||||
_CorpusExpectation(variant='solid fuel 10', block='11a', expected_sap_resid=+0.1134, expected_cost_resid_gbp=-2.6121, expected_co2_resid_kg=+9.3131, expected_pe_resid_kwh=-13.9149),
|
||||
_CorpusExpectation(variant='solid fuel 11', block='11a', expected_sap_resid=+0.0912, expected_cost_resid_gbp=-2.1006, expected_co2_resid_kg=+10.5547, expected_pe_resid_kwh=-0.7387),
|
||||
_CorpusExpectation(variant='solid fuel 9', block='11a', expected_sap_resid=-0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 10', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=-0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
_CorpusExpectation(variant='solid fuel 11', block='11a', expected_sap_resid=+0.0000, expected_cost_resid_gbp=+0.0000, expected_co2_resid_kg=+11.9451, expected_pe_resid_kwh=+48.6604),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -658,18 +658,76 @@ def _pump_date_category_from_cert(epc: EpcPropertyData) -> PumpDateCategory:
|
|||
_HEAT_PUMP_MAIN_HEATING_CATEGORY: Final[int] = 4
|
||||
|
||||
|
||||
def _all_main_systems_are_heat_pumps(epc: EpcPropertyData) -> bool:
|
||||
"""True iff every lodged main heating system is a heat pump
|
||||
(category 4). When True, SAP 10.2 Table 5a Note a) zeros the
|
||||
central-heating-pump GAIN. When False (mixed HP + boiler, or
|
||||
boiler-only), the non-HP system's pump gain still applies."""
|
||||
# SAP 10.2 Table 5a row "Central heating pump in heated space" (PDF
|
||||
# p.177) only applies to mains with a water-loop circulation pump.
|
||||
# Dry mains — electric storage heaters (Table 4a Cat 7 codes 401-409,
|
||||
# 421), warm-air heaters without HPs (Cat 9), solid-fuel room heaters
|
||||
# without back-boilers (codes 631-636 minus the boiler combos at
|
||||
# 151-161), electric direct-acting heaters — have no primary water
|
||||
# loop, so the row simply doesn't apply and worksheet (70)m = 0.
|
||||
#
|
||||
# Mirrors `cert_to_inputs._WET_BOILER_CODE_RANGES` (Table 4f kWh
|
||||
# accounting). Kept as a sibling constant here so the worksheet layer
|
||||
# does not depend on rdsap. Same code-range coverage:
|
||||
# 101-141 Gas/oil boilers (Table 4b)
|
||||
# 151-161 Solid-fuel boilers + back-boiler combos (Table 4a)
|
||||
# 191-196 Electric boilers + CPSU (Table 4a)
|
||||
_WET_BOILER_SAP_CODE_RANGES: Final[tuple[range, ...]] = (
|
||||
range(101, 142),
|
||||
range(151, 162),
|
||||
range(191, 197),
|
||||
)
|
||||
|
||||
# Heat-emitter types (Table 4d) that imply a wet primary loop —
|
||||
# radiators (1) and fan-coil units (3) require water-side delivery.
|
||||
# UFH (2) excluded because it can be wet OR electric (in-screed cable);
|
||||
# the SAP code or category disambiguates. Warm-air (4) and electric
|
||||
# storage / direct-acting emitters are dry. Used only as a fallback
|
||||
# when no SAP code / PCDB index / category is lodged (e.g. the 000490
|
||||
# hand-built unit-test fixture).
|
||||
_WET_HEAT_EMITTER_TYPES: Final[frozenset[int]] = frozenset({1, 3})
|
||||
|
||||
|
||||
def _any_main_system_has_central_heating_pump(epc: EpcPropertyData) -> bool:
|
||||
"""SAP 10.2 Table 5a row "Central heating pump in heated space"
|
||||
(PDF p.177) — predicate for whether the pump-gain row applies.
|
||||
|
||||
Identifies wet, non-HP mains by (any of):
|
||||
- sap_main_heating_code in Table 4a/4b wet-boiler ranges
|
||||
(gas/oil/solid-fuel/electric boilers)
|
||||
- main_heating_index_number lodged + category not HP (PCDB
|
||||
Table 322 gas/oil boiler record)
|
||||
- main_heating_category in {1, 2} (RdSAP "central heating" with
|
||||
or without separate HW — both wet)
|
||||
- heat_emitter_type in {1 radiators, 3 fan-coil} (Table 4d wet
|
||||
emitter types; UFH/2 excluded as it can be electric)
|
||||
|
||||
HP mains (category 4) are skipped per Table 5a Note a) "Not
|
||||
applicable for electric heat pumps from database." Where any
|
||||
non-HP main qualifies as wet, the pump gain applies (per the
|
||||
same note's clause about two mains in the same space).
|
||||
|
||||
Mirrors `cert_to_inputs._is_wet_boiler_main` — see docstring there
|
||||
for the kWh-side parallel in Table 4f.
|
||||
"""
|
||||
details = epc.sap_heating.main_heating_details
|
||||
if not details:
|
||||
return False
|
||||
return all(
|
||||
d.main_heating_category == _HEAT_PUMP_MAIN_HEATING_CATEGORY
|
||||
for d in details
|
||||
)
|
||||
for d in details:
|
||||
if d.main_heating_category == _HEAT_PUMP_MAIN_HEATING_CATEGORY:
|
||||
continue
|
||||
code = d.sap_main_heating_code
|
||||
if code is not None and any(
|
||||
code in r for r in _WET_BOILER_SAP_CODE_RANGES
|
||||
):
|
||||
return True
|
||||
if d.main_heating_index_number is not None:
|
||||
return True
|
||||
if d.main_heating_category in {1, 2}:
|
||||
return True
|
||||
if d.heat_emitter_type in _WET_HEAT_EMITTER_TYPES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def internal_gains_from_cert(
|
||||
|
|
@ -725,21 +783,26 @@ def internal_gains_from_cert(
|
|||
daylight_factor=c_daylight,
|
||||
)
|
||||
|
||||
# SAP 10.2 Table 5a Note a) (PDF p.177): the central-heating-pump
|
||||
# GAIN is "Not applicable for electric heat pumps from database".
|
||||
# Zero only when EVERY lodged main heating system is an HP — when
|
||||
# any non-HP system (gas boiler, oil boiler, etc.) is present, its
|
||||
# circulation pump still contributes 3/7/10 W per the pump's
|
||||
# installation date (Table 5a row 1). Cert 000565 lodges HP main 1
|
||||
# + gas boiler main 2 → 3 W gain (worksheet line 70 confirms
|
||||
# 3.0000 W in 8 winter months, 0 in summer). Cert 0380 (HP-only)
|
||||
# → 0 W gain (worksheet line 70 confirms 0 every month).
|
||||
if _all_main_systems_are_heat_pumps(epc):
|
||||
pump_w = 0.0
|
||||
else:
|
||||
# SAP 10.2 Table 5a row "Central heating pump in heated space"
|
||||
# (PDF p.177) — the gain applies only to mains with a water-loop
|
||||
# circulation pump. Excludes:
|
||||
# (i) HP mains per Table 5a Note a) "Not applicable for electric
|
||||
# heat pumps from database" (cert 0380 HP-only → 0 W),
|
||||
# (ii) Dry mains with no primary water loop — electric storage
|
||||
# heaters (Cat 7), warm-air heaters (Cat 9), solid-fuel room
|
||||
# heaters without back-boilers, electric direct-acting.
|
||||
# Worksheet (70)m = 0 across the 41-variant controlled-
|
||||
# variable corpus for every dry main; see
|
||||
# `_any_main_system_has_central_heating_pump`.
|
||||
# Mixed HP + wet-boiler mains (cert 000565: HP main 1 + gas boiler
|
||||
# main 2) DO carry the gain via the non-HP main's pump (worksheet
|
||||
# line 70 confirms 3.0000 W in 8 winter months, 0 in summer).
|
||||
if _any_main_system_has_central_heating_pump(epc):
|
||||
pump_w = central_heating_pump_w(
|
||||
date_category=_pump_date_category_from_cert(epc)
|
||||
)
|
||||
else:
|
||||
pump_w = 0.0
|
||||
# Liquid-fuel + warm-air + PIV + MV + HIU branches default to zero for
|
||||
# the combi-gas-natural-vent population; future slices will detect them
|
||||
# from epc.main_heating_details + epc.mechanical_ventilation.
|
||||
|
|
|
|||
|
|
@ -575,6 +575,62 @@ def test_internal_gains_from_cert_reproduces_000490_worksheet_end_to_end() -> No
|
|||
assert result.total_internal_gains_monthly_w[m] == pytest.approx(expected_73[m], abs=1e-1), f"(73) month {m+1}"
|
||||
|
||||
|
||||
def test_internal_gains_pumps_fans_is_zero_for_electric_storage_heater_main() -> None:
|
||||
"""SAP 10.2 Table 5a (PDF p.177) row "Central heating pump in heated
|
||||
space" — the gain applies only to mains with a water-loop circulation
|
||||
pump. Electric storage heaters (Table 4a Cat 7 codes 401-409 + 421)
|
||||
have no primary water loop and no circulation pump, so the row does
|
||||
not apply and worksheet (70)m = 0 every month.
|
||||
|
||||
Mirrors the kWh-side gate in `cert_to_inputs._table_4f_circulation_pump_kwh`
|
||||
(S0380.149). Worksheet evidence: the controlled-variable corpus at
|
||||
`sap worksheets/heating systems examples/` lodges 001431 under 41
|
||||
heating-system variants — every dry electric storage / room-heater
|
||||
variant lodges (70)m = 0.0 across all 12 months (e.g. electric 3,
|
||||
solid fuel 4/9/10/11).
|
||||
"""
|
||||
# Arrange — minimal cert lodging an Elmhurst-style electric storage
|
||||
# heater main (Table 4a code 401 "Manual charge control") with no
|
||||
# PCDB index, no category, no heat-emitter (storage heaters distribute
|
||||
# heat directly to the room — no emitter loop).
|
||||
sap_heating = SapHeating(
|
||||
instantaneous_wwhrs=InstantaneousWwhrs(),
|
||||
main_heating_details=[
|
||||
MainHeatingDetail(
|
||||
has_fghrs=False,
|
||||
main_fuel_type=30, # mains electricity
|
||||
heat_emitter_type="", # storage heaters have no emitter loop
|
||||
emitter_temperature="",
|
||||
sap_main_heating_code=401,
|
||||
main_heating_control=2401,
|
||||
central_heating_pump_age_str="Unknown",
|
||||
),
|
||||
],
|
||||
has_fixed_air_conditioning=False,
|
||||
)
|
||||
epc = make_minimal_sap10_epc(
|
||||
total_floor_area_m2=90.0,
|
||||
low_energy_fixed_lighting_bulbs_count=6,
|
||||
sap_windows=[],
|
||||
sap_heating=sap_heating,
|
||||
)
|
||||
|
||||
# Act
|
||||
result = internal_gains_from_cert(
|
||||
epc=epc,
|
||||
dwelling_volume_m3=227.25,
|
||||
heat_gains_from_water_heating_monthly_kwh=(0.0,) * 12,
|
||||
overshading=OvershadingCategory.AVERAGE,
|
||||
)
|
||||
|
||||
# Assert — (70)m is zero in every month, including heating months
|
||||
# (Jan-May, Oct-Dec) where wet-system pumps would contribute 3/7/10 W.
|
||||
for m in range(12):
|
||||
assert abs(result.pumps_fans_monthly_w[m] - 0.0) <= 1e-9, (
|
||||
f"(70) month {m+1} = {result.pumps_fans_monthly_w[m]:.4f}, expected 0.0"
|
||||
)
|
||||
|
||||
|
||||
def _build_section_5_epc(fixture: ModuleType) -> EpcPropertyData:
|
||||
"""Wrap a fixture's base `build_epc()` with the §5-relevant fields it
|
||||
doesn't yet carry: sap_windows (DG air-filled / PVC), low-energy bulb
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue