mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
slice S-B12: water-heating eff inherits main_heating_category cascade
The legacy water_heating_efficiency(901, main_code) returns 0.80 (gas boiler default) when sap_main_heating_code is None — even if the main system is a heat pump (category=4, efficiency 2.30). For "from main system" water codes (901/902/914), we must inherit through the FULL main-heating cascade including the category fallback. Discovered by hand-tracing cert 0320-2850 (Semi-detached bungalow, heat-pump main with no SAP code lodged, actual SAP 70, predicted 49). HW was being charged at 0.80 eff for a 2.30-eff dwelling — 2.9× too much HW fuel. 100-cert parity probe: MAE 4.66 → 4.53 (-0.13) RMSE 6.27 → 5.96 bias -0.70 → -0.57 within ±10: 94% → 95% Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
737e5d6bf5
commit
1a6996abbb
1 changed files with 36 additions and 2 deletions
|
|
@ -50,7 +50,7 @@ from datatypes.epc.domain.epc_property_data import (
|
|||
from domain.ml.demand import predicted_hot_water_kwh, predicted_lighting_kwh
|
||||
from domain.ml.sap_efficiencies import (
|
||||
seasonal_efficiency,
|
||||
water_heating_efficiency,
|
||||
water_heating_efficiency as _legacy_water_heating_efficiency,
|
||||
)
|
||||
from domain.sap.calculator import CalculatorInputs, WindowInput
|
||||
from domain.sap.tables.table_12 import co2_factor_kg_per_kwh, unit_price_p_per_kwh
|
||||
|
|
@ -411,6 +411,35 @@ def _other_fuel_cost_gbp_per_kwh(prices: PriceTable) -> float:
|
|||
return prices.standard_electricity_p_per_kwh * _PENCE_TO_GBP
|
||||
|
||||
|
||||
# Water-heating codes that say "inherit from the main system" — the
|
||||
# `seasonal_efficiency` cascade returns 0 as a sentinel for these in the
|
||||
# legacy `domain.ml.sap_efficiencies` module. We need to inherit through
|
||||
# the SAME cascade the main heating uses, including the main_heating_
|
||||
# category fallback (e.g. heat pumps return 2.30 via category 4).
|
||||
_WATER_INHERIT_FROM_MAIN_CODES: Final[frozenset[int]] = frozenset({901, 902, 914})
|
||||
|
||||
|
||||
def _water_efficiency_with_category_inherit(
|
||||
*,
|
||||
water_heating_code: Optional[int],
|
||||
main_code: Optional[int],
|
||||
main_category: Optional[int],
|
||||
main_fuel: Optional[int],
|
||||
) -> float:
|
||||
"""When the cert says "hot water comes from the main system" (codes
|
||||
901 / 902 / 914), inherit the main system's efficiency — and crucially
|
||||
inherit the cascade that maps `main_heating_category` to a default
|
||||
when `sap_main_heating_code` is None. The legacy water_heating_efficiency
|
||||
only passes main_code through and so collapses heat pumps (cat 4) +
|
||||
no-code lodgements into the 0.80 gas-boiler default.
|
||||
"""
|
||||
if water_heating_code is None:
|
||||
return _legacy_water_heating_efficiency(None, main_code)
|
||||
if water_heating_code in _WATER_INHERIT_FROM_MAIN_CODES:
|
||||
return seasonal_efficiency(main_code, main_category, main_fuel)
|
||||
return _legacy_water_heating_efficiency(water_heating_code, main_code)
|
||||
|
||||
|
||||
|
||||
|
||||
def _co2_factor_kg_per_kwh(main: Optional[MainHeatingDetail]) -> float:
|
||||
|
|
@ -499,7 +528,12 @@ def cert_to_inputs(
|
|||
)
|
||||
|
||||
eff = seasonal_efficiency(main_code, main_category, main_fuel)
|
||||
water_eff = water_heating_efficiency(epc.sap_heating.water_heating_code, main_code)
|
||||
water_eff = _water_efficiency_with_category_inherit(
|
||||
water_heating_code=epc.sap_heating.water_heating_code,
|
||||
main_code=main_code,
|
||||
main_category=main_category,
|
||||
main_fuel=main_fuel,
|
||||
)
|
||||
hw_kwh = predicted_hot_water_kwh(
|
||||
total_floor_area_m2=epc.total_floor_area_m2,
|
||||
seasonal_efficiency_water=water_eff,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue