mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Closes the +£104 cost / +4.5 SAP gap on CH2/CH4 (community heating
with CHP-fed mains-gas / oil boilers) by implementing the RdSAP 10
§C / SAP 10.2 Appendix C (PDF p.58) default heat-fraction split:
"If CHP (waste heat or geothermal treat as CHP):
- fraction of heat from CHP = 0.35
- CHP overall efficiency 75%
- heat to power ratio = 2.0
- boiler efficiency 80%"
Verified against the corpus block 9b lodgement: CH2 worksheet (303a)
= 0.3500 + (303b) = 0.6500 + (305) = 1.00 + (306) DLF = 1.45. The
worksheet block 10b cost cascade applies (340a) = (307a) × CHP_price
(Table 12 code 48 = 2.97 p/kWh) + (340b) = (307b) × boiler_price
(Table 12 codes 51-58 = 4.24 p/kWh) with (307a) = 0.35 × (307),
(307b) = 0.65 × (307).
Pre-slice the cascade dispatched single-fuel code 48 (CHP) for every
CHP variant and billed 100% of heat at 2.97 p/kWh, under-charging by
~£104/yr versus the worksheet's 35% × 2.97 + 65% × 4.24 = 3.7945
p/kWh blended rate.
Three layers wired:
1. Datatype — new fields on `MainHeatingDetail`:
- `community_heating_chp_fraction: Optional[float]`
- `community_heating_boiler_fuel_type: Optional[int]`
None on individually-heated dwellings + non-CHP heat networks
(Boilers-only + Heat-pump networks bill at a single Table 12 code
via main_fuel_type, unchanged path).
2. Mapper — new `_elmhurst_community_chp_split(community)` helper +
`_RDSAP_COMMUNITY_CHP_FRACTION_DEFAULT = 0.35` constant. When the
§14.1 Community Heat Source is "Combined Heat and Power": returns
(0.35, boiler_fuel_code) where boiler_fuel_code is resolved from
the §14.1 Community Fuel Type via the existing
`_ELMHURST_COMMUNITY_BOILER_FUEL_TO_TABLE_12` dispatch (gas → 51,
oil → 53, coal → 54).
3. Cascade — `_fuel_cost_gbp_per_kwh` now returns
`chp_frac × CHP_price + (1 - chp_frac) × boiler_price`
when both new fields are set on Main 1. Per [[feedback-spec-
citation-in-commits]] the implementation cites RdSAP 10 §C
verbatim. Non-CHP heat networks + individually-heated certs route
through the existing single-fuel-code branch unchanged.
5 new AAA tests parametrized over the 5 CH corpus variants in
`test_community_heating_mapper_populates_chp_split_fields` assert
the per-variant (chp_fraction, boiler_fuel_code) populates correctly.
Closures vs pre-S0380.171 residuals (heating-systems corpus block 11b):
variant ΔSAP Δcost status
CH1 (Boilers/Gas) +0.5915 -£13.63 unchanged (no CHP split)
CH2 (CHP/Gas) +4.50→-0.0076 -£104→+£0.17 ✓ CLOSED
CH3 (HP/Elec) +0.5915 -£13.63 unchanged (no CHP split)
CH4 (CHP/Oil) +4.50→-0.0076 -£104→+£0.17 ✓ CLOSED
CH6 (CHP/Coal) -3.52→-8.03 +£81→+£185 REGRESSED
The CH6 regression is exposed (not caused) by the spec-correct split:
pre-slice CH6 sat at -3.52 SAP / +£81 by coincidence — the cascade's
CHP-only pricing (2.97 p/kWh) cancelled with cascade DLF=1.45
(Table 12c age G default) against the CH6 worksheet's lodged DLF=1.0.
Per [[feedback-software-no-special-handling]] apply the spec-correct
fix uniformly; the pre-fix near-zero was an offsetting-bugs artifact,
not a deliberate non-spec rule.
The CH6 worksheet (306) DLF=1.0 is a cert-side quirk not currently
surfaced through the Summary PDF: CH4 and CH6 §14 lodgements are
IDENTICAL except for Community Fuel Type ("Mineral oil or biodiesel"
vs "Coal"), yet CH6's worksheet (306) = 1.0000 while CH4's = 1.4500.
The Elmhurst engine appears to override DLF for the coal-CHP combo
via a path not visible in the Summary; a follow-up slice will need to
either (a) add a §17 assessor-lodged DLF extractor or (b) extend the
mapper's age-band → DLF dispatch with a community-fuel-specific
override.
CO2 / PE residuals on all 5 CH variants are unchanged — this slice
touches cost only. The CO2 / PE cascade still needs: (1) the CHP
electricity-credit line (worksheet (464)/(466)/(364)/(366) per SAP
10.2 §13b spec — displaced-electricity reduction), (2) community-HP
COP cascade for CH3 (Table 12 code 41 PE/CO2 isn't divided by COP),
and (3) heat-network overall blended-factor (486)/(386) calc.
Test baseline at HEAD: 926 pass + 1 skipped (was 921 + 1 at
predecessor
|
||
|---|---|---|
| .. | ||
| epc | ||
| magicplan | ||
| __init__.py | ||
| datatypes.py | ||
| enums.py | ||