mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
S0380.204: extract Main Heating2's own emitter + control (§14.1)
Prerequisite for the SAP 10.2 p.186 two-systems-different-parts MIT. When two main systems heat different parts of a dwelling, §14.1 Main Heating2 lodges its OWN "Heat Emitter" + "Main Heating Controls Sap" (simulated case 6: Main 1 radiators / control 2106 serving the living area, Main 2 underfloor / control 2110 serving elsewhere). The extractor + mapper dropped both — `MainHeatingDetail.heat_emitter_type` and `main_heating_control` came through as empty-string sentinels, so the cascade saw system 2 as having no responsiveness (defaulted R=1.0) and no control type. - `MainHeating2` datatype gains `heat_emitter` + `heating_controls_sap`. - The extractor reads them from the §14.1 block. - `_map_elmhurst_main_heating_2` maps them via the same helpers as Main 1 (`_elmhurst_heat_emitter_int` → underfloor-in-screed = emitter 2, Table 4d R=0.75; `_elmhurst_sap_control_code` → 2110, Table 4e type 3), threading the dwelling floor + age band for the underfloor subtype. Empty-string fallback preserved for the legacy DHW-only Main 2 (cert 000565 §14.1 omits emitter/control). No cascade output changes yet — the MIT consumer lands in S0380.205. Full suite 2358 pass + 0 fail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a42e03529c
commit
2b1afa7339
4 changed files with 52 additions and 6 deletions
|
|
@ -1346,6 +1346,8 @@ class ElmhurstSiteNotesExtractor:
|
|||
fan_assisted_flue=self._local_bool(lines, "Fan Assisted Flue"),
|
||||
percentage_of_heat=pct,
|
||||
main_heating_sap_code=main_heating_sap_code,
|
||||
heat_emitter=self._local_str(lines, "Heat Emitter"),
|
||||
heating_controls_sap=self._local_str(lines, "Main Heating Controls Sap"),
|
||||
)
|
||||
|
||||
def _extract_community_heating(self) -> Optional[CommunityHeating]:
|
||||
|
|
|
|||
|
|
@ -4863,6 +4863,8 @@ def _map_elmhurst_main_heating_2(
|
|||
mh2: Optional[ElmhurstMainHeating2],
|
||||
*,
|
||||
fallback_fuel_type: Union[int, str, None] = None,
|
||||
main_floor: Optional[ElmhurstFloorDetails] = None,
|
||||
main_age_band: Optional[str] = None,
|
||||
) -> Optional[MainHeatingDetail]:
|
||||
"""Build a `MainHeatingDetail` from the Elmhurst §14.1 Main Heating2
|
||||
block. Returns None when no Main 2 is lodged (extractor convention:
|
||||
|
|
@ -4917,20 +4919,32 @@ def _map_elmhurst_main_heating_2(
|
|||
category = _ELMHURST_HEATING_CATEGORY_HEAT_PUMP
|
||||
elif pcdb_index is not None and mh2.fuel_type in _ELMHURST_GAS_BOILER_FUEL_TYPES:
|
||||
category = _ELMHURST_HEATING_CATEGORY_GAS_BOILER
|
||||
# §14.1 lodges Main 2's own "Heat Emitter" + "Main Heating Controls
|
||||
# Sap" when the two systems heat different parts of the dwelling
|
||||
# (simulated case 6: Main 1 radiators / 2106, Main 2 underfloor /
|
||||
# 2110). Map them through the same helpers as Main 1 so the SAP 10.2
|
||||
# p.186 two-systems-different-parts MIT can read system 2's
|
||||
# responsiveness (underfloor → emitter 2 → R=0.75) + control type.
|
||||
# Empty-string sentinels preserved for the legacy DHW-only Main 2
|
||||
# (cert 000565: §14.1 omits emitter/control → consumers key off
|
||||
# Main 1).
|
||||
emitter_int = _elmhurst_heat_emitter_int(
|
||||
mh2.heat_emitter, main_floor=main_floor, main_age_band=main_age_band
|
||||
)
|
||||
control_int = _elmhurst_sap_control_code(mh2.heating_controls_sap)
|
||||
return MainHeatingDetail(
|
||||
# Main 2 doesn't carry its own FGHRS lodgement in §14.1; the
|
||||
# cert-level renewables block is the single source of truth and
|
||||
# is already wired into Main 1.
|
||||
has_fghrs=False,
|
||||
main_fuel_type=resolved_fuel,
|
||||
# §14.1 doesn't lodge a heat emitter (the emitter is Main 1's
|
||||
# radiator/UFH); leave as empty-string sentinel for cascade
|
||||
# consumers that key off Main 1's emitter.
|
||||
heat_emitter_type="",
|
||||
heat_emitter_type=(
|
||||
emitter_int if emitter_int is not None else mh2.heat_emitter
|
||||
),
|
||||
emitter_temperature="",
|
||||
fan_flue_present=mh2.fan_assisted_flue,
|
||||
boiler_flue_type=_elmhurst_flue_type_int(mh2.flue_type),
|
||||
main_heating_control="",
|
||||
main_heating_control=control_int if control_int is not None else "",
|
||||
main_heating_category=category,
|
||||
main_heating_number=2,
|
||||
main_heating_fraction=mh2.percentage_of_heat,
|
||||
|
|
@ -5127,7 +5141,10 @@ def _map_elmhurst_sap_heating(survey: ElmhurstSiteNotes) -> SapHeating:
|
|||
# system") while Main 1 handles space heat. None when the §14.1
|
||||
# block is absent or lodges only placeholder zeros.
|
||||
main_2_detail = _map_elmhurst_main_heating_2(
|
||||
mh.main_heating_2, fallback_fuel_type=main_1_detail.main_fuel_type
|
||||
mh.main_heating_2,
|
||||
fallback_fuel_type=main_1_detail.main_fuel_type,
|
||||
main_floor=survey.floor,
|
||||
main_age_band=survey.construction_age_band,
|
||||
)
|
||||
main_heating_details = (
|
||||
[main_1_detail, main_2_detail]
|
||||
|
|
|
|||
|
|
@ -244,6 +244,15 @@ class MainHeating2:
|
|||
fan_assisted_flue: bool = False
|
||||
percentage_of_heat: int = 0
|
||||
main_heating_sap_code: Optional[int] = None
|
||||
# §14.1 "Heat Emitter" (e.g. "Underfloor Heating") + "Main Heating
|
||||
# Controls Sap" (e.g. "SAP code 2110, ..."). Lodged when the two main
|
||||
# systems serve different parts of the dwelling with their own
|
||||
# emitter + control (simulated case 6: Main 1 radiators / control
|
||||
# 2106, Main 2 underfloor / control 2110). Needed for the SAP 10.2
|
||||
# p.186 two-systems-different-parts MIT (weighted responsiveness +
|
||||
# elsewhere two-control blend).
|
||||
heat_emitter: str = ""
|
||||
heating_controls_sap: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
|||
|
|
@ -283,6 +283,24 @@ def test_section_3_roof_windows_case6_match_pdf() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_case6_main_2_emitter_and_control_extracted() -> None:
|
||||
"""Simulated case 6's §14.1 Main Heating2 lodges its OWN emitter
|
||||
("Underfloor Heating") and control ("SAP code 2110, ...") — the two
|
||||
main systems heat different parts (Main 1 radiators/2106 living, Main
|
||||
2 underfloor/2110 elsewhere). Pre-S0380.204 the extractor + mapper
|
||||
dropped both (emitter='' / control=''), so the SAP 10.2 p.186 two-
|
||||
systems-different-parts MIT could not read system 2's responsiveness
|
||||
(underfloor → emitter 2 → R=0.75) or control type (2110 → type 3)."""
|
||||
# Arrange / Act
|
||||
epc = _w001431_case6.build_epc()
|
||||
main_2 = epc.sap_heating.main_heating_details[1]
|
||||
|
||||
# Assert — emitter 2 (underfloor in screed → Table 4d R=0.75) +
|
||||
# control 2110 (Table 4e type 3 zone control).
|
||||
assert main_2.heat_emitter_type == 2
|
||||
assert main_2.main_heating_control == 2110
|
||||
|
||||
|
||||
def test_section_4f_pumps_fans_case6_match_pdf() -> None:
|
||||
"""(231) pumps/fans pin for simulated case 6 — a DUAL-oil-boiler
|
||||
detached dwelling. Worksheet (231) = 356 = (230c) central heating
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue