mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-27 23:35:01 +00:00
Map oil and solid-fuel boilers to their SAP codes and companion set 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
04774a8888
commit
0dd164567c
1 changed files with 57 additions and 0 deletions
|
|
@ -217,6 +217,22 @@ _GAS_BOILER_CODES = frozenset({102, 104, 120})
|
|||
_COMBI_CODES = frozenset({104})
|
||||
_GAS_BOILER_CATEGORY = 2
|
||||
_MAINS_GAS_FUEL = 26
|
||||
|
||||
# Non-gas wet boilers modelled on the gas-boiler pattern (ADR-0067). Oil boilers
|
||||
# take the modern/condensing SAP Table 4b codes (A-G deferred, like gas): 127
|
||||
# regular condensing (84%), 130 combi condensing (82%) — 130 is the combi (no
|
||||
# cylinder). A solid-fuel boiler is a single conservative member — SAP Table 4a
|
||||
# 151 (manual-feed independent boiler, 0.60), the lowest-efficiency independent
|
||||
# solid boiler, so it never over-credits an unknown coal/wood/dual fuel; the
|
||||
# property's `main_fuel` override drives carbon (it does not change the code).
|
||||
_OIL_BOILER_CODES = frozenset({127, 130})
|
||||
_OIL_BOILER_COMBI_CODES = frozenset({130})
|
||||
_SOLID_FUEL_BOILER_CODES = frozenset({151})
|
||||
_FUEL_BOILER_CODES = _OIL_BOILER_CODES | _SOLID_FUEL_BOILER_CODES
|
||||
_FUEL_BOILER_CATEGORY = 2
|
||||
# Fan flue: a modern condensing oil boiler is room-sealed / fan-assisted (like a
|
||||
# gas boiler); a solid-fuel boiler vents through a conventional (non-fanned) flue.
|
||||
_FAN_FLUE_BOILER_CODES = _OIL_BOILER_CODES
|
||||
# SAP Table 4a "from the main system" water-heating code — a gas boiler heats hot
|
||||
# water from itself, so the override routes water heating to the main system on
|
||||
# mains gas (clearing a storage dwelling's old electric-immersion arrangement).
|
||||
|
|
@ -288,6 +304,13 @@ _MAIN_HEATING_CODES: dict[str, int] = {
|
|||
"Gas room heater, flush live-effect": 605,
|
||||
"Gas room heater, open flue 1980 or later": 603,
|
||||
"Gas room heater, open flue pre-1980": 601,
|
||||
# Oil / solid-fuel wet boilers off the fuel-agnostic gas default (ADR-0067):
|
||||
# oil regular 127 / oil combi 130 (Table 4b condensing), solid 151 (Table 4a
|
||||
# manual-feed independent). Companions (fuel, category, control, cylinder, fan
|
||||
# flue) drag from `_fuel_boiler_overlay`, modelled on the gas-boiler path.
|
||||
"Oil boiler, regular": 127,
|
||||
"Oil boiler, combi": 130,
|
||||
"Solid fuel boiler": 151,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -368,6 +391,12 @@ def _natural_fuel_for(code: int) -> Optional[int]:
|
|||
or code in _ELECTRIC_UNDERFLOOR_CODES
|
||||
):
|
||||
return _ELECTRICITY_FUEL
|
||||
if code in _OIL_BOILER_CODES:
|
||||
return _OIL_FUEL
|
||||
if code in _SOLID_FUEL_BOILER_CODES:
|
||||
# Solid fuel is ambiguous (coal / wood / dual); house coal is the
|
||||
# conservative default, overridden by the property's `main_fuel` (ADR-0067).
|
||||
return _HOUSE_COAL_FUEL
|
||||
if code in _SOLID_FUEL_ROOM_HEATER_CODES:
|
||||
return _HOUSE_COAL_FUEL
|
||||
if code in _OIL_ROOM_HEATER_CODES:
|
||||
|
|
@ -398,6 +427,32 @@ def _gas_boiler_overlay(code: int) -> HeatingOverlay:
|
|||
)
|
||||
|
||||
|
||||
def _fuel_boiler_overlay(code: int) -> HeatingOverlay:
|
||||
"""The coherent companion set for a non-gas wet boiler (oil / solid fuel),
|
||||
modelled on the gas-boiler pattern (ADR-0067): SAP Table 4a category 2, full
|
||||
modern controls (Table 4e 2106), a single-rate meter, hot water from the main
|
||||
system, and a cylinder unless it is a combi.
|
||||
|
||||
Differs from the gas boiler deliberately: the natural fuel is oil / house coal
|
||||
(the property's `main_fuel` override wins by last-wins composition and drives
|
||||
carbon); `gas_connection_available` is left UNSET (None) so it inherits the
|
||||
lodged EPC — an oil/solid boiler needs no gas main, unlike a gas boiler which
|
||||
forces it True; and a solid-fuel boiler vents through a conventional
|
||||
(non-fanned) flue."""
|
||||
fuel = _natural_fuel_for(code)
|
||||
return HeatingOverlay(
|
||||
sap_main_heating_code=code,
|
||||
main_heating_category=_FUEL_BOILER_CATEGORY,
|
||||
main_fuel_type=fuel,
|
||||
main_heating_control=_FULL_BOILER_CONTROL,
|
||||
fan_flue_present=code in _FAN_FLUE_BOILER_CODES,
|
||||
meter_type=_SINGLE_RATE_METER,
|
||||
water_heating_code=_FROM_MAIN_WATER_HEATING_CODE,
|
||||
water_heating_fuel=fuel,
|
||||
has_hot_water_cylinder=code not in _OIL_BOILER_COMBI_CODES,
|
||||
)
|
||||
|
||||
|
||||
def natural_fuel_for(main_heating_value: str) -> Optional[int]:
|
||||
"""The RdSAP `main_fuel` code a heating archetype unambiguously implies — its
|
||||
natural fuel (ADR-0041) — or None for an unmapped archetype. Exposed so a
|
||||
|
|
@ -416,6 +471,8 @@ def main_heating_overlay_for(
|
|||
return None
|
||||
if code in _GAS_BOILER_CODES:
|
||||
return EpcSimulation(heating=_gas_boiler_overlay(code))
|
||||
if code in _FUEL_BOILER_CODES:
|
||||
return EpcSimulation(heating=_fuel_boiler_overlay(code))
|
||||
category = _category_for(code)
|
||||
control = _control_for(code)
|
||||
if category is None or control is None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue