mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
SAP 10.2 Appendix D §D2.1 (2) Equation (D1) (PDF p.57):
If the boiler provides both space and water heating, and the summer
seasonal efficiency is lower than the winter seasonal efficiency,
the efficiency is a combination of winter and summer seasonal
efficiencies according to the relative proportion of heat needed
from the boiler for space and water heating in the month concerned:
Q_space + Q_water
η_water,m = ───────────────────────────────
Q_space/η_winter + Q_water/η_summer
where Q_space (kWh/month) is the quantity calculated at (98c)m
multiplied by (204) or by (205);
Q_water (kWh/month) is the quantity calculated at (64)m;
η_winter and η_summer are the winter and summer seasonal
efficiencies (from Table 4b).
Pre-slice the cascade only wired Eq D1 for PCDB-tested boilers (the
`pcdb_record` branch in `_apply_water_efficiency`). For non-PCDB
Table 4b boilers (`sap_main_heating_code` 101-141) where the cert
lodges no `main_heating_index_number`, the cascade fell through to
the scalar `water_efficiency_pct` divisor — which resolved via WHC
901 inherit to Table 4b WINTER eff (wrong direction; spec wants the
monthly Eq D1 blend).
This slice:
- Adds `domain/sap10_calculator/tables/table_4b.py` with the full
41-row Table 4b (winter, summer) pair dict for codes 101-141
verbatim from SAP 10.2 PDF p.168 (Table 4b).
- Refactors `_apply_water_efficiency` parameter from
`pcdb_record: Optional[GasOilBoilerRecord]` to
`eq_d1_winter_summer_pct: Optional[tuple[float, float]]` —
decouples the Eq D1 input from the PCDB record so a Table 4b
fallback can populate it without faking a PCDB record.
- Resolves Eq D1 inputs at the call site with priority order:
1. PCDB Table 105 winter/summer (existing path)
2. SAP 10.2 Table 4b (PDF p.168) winter/summer when PCDB
absent + WHC=901 (`_WHC_FROM_MAIN_HEATING`, the spec form
of "boiler provides both space and water heating").
§9.4.11 -5pp interlock applies symmetrically to both columns of
whichever (winter, summer) tuple is resolved.
Oil 1 cert worksheet (217)m verified Jan 81.83 / Apr 81.42 / May
79.94 / Jun-Sep 72.00 / Dec 81.86 — exact back-solve to Eq D1 with
Table 4b code 127 (winter 84, summer 72). Annual HW fuel (219) =
Σ (64)m × 100 / (217)m = 3638.99 kWh/yr ≡ cascade post-slice.
Cascade impact:
Heating-systems corpus (worksheet-pinned, oil 1 only on pin grid):
oil 1 SAP +1.76 → +1.18 (Δ -0.59)
cost -£40.60 → -£27.12 (Δ +£13.48)
CO2 -129.22 → -55.36 (Δ +73.86 kg/yr)
PE -590.02 → -275.52 (Δ +314.50 kWh/yr)
Remaining oil 1 residual is Table 4f auxiliary energy (cascade
pumps_fans 130 kWh vs worksheet 265 kWh — missing the oil-boiler
pump 100 kWh + CH pump 130 vs ws 165). Follow-up slice.
Golden fixtures (cert-pinned, integer-rounded PE):
cert 0240 (dual oil combi 130, no cylinder): PE +0.05 → +1.02
cert 6035 (gas combi 104, no cylinder): PE +46.10 → +47.29
Both shifts reflect spec-correct Eq D1 now firing for non-PCDB
combi-no-cylinder configs. The pre-slice near-zero pin on cert
0240 was masking offsetting cascade gaps (likely Table 4f
auxiliary energy and/or dual-main Q_space split per (98c)m ×
(204) which the cascade currently treats as full demand).
Following [[reference-unmapped-sap-code]] discipline, the new Table
4b dict is the canonical spec-source — `domain.sap10_ml.sap_
efficiencies._SPACE_EFF_BY_CODE` still carries the winter column for
the ML feature cascade and is left in place per the sap10_ml
deprecation plan (separate migration).
Test:
test_sap_appendix_d_eq_d1_water_efficiency_monthly_for_non_pcdb_
table_4b_boiler_with_cylinder — asserts cert 1431 oil 1 HW fuel
annual = 3638.99 ± 1.0 kWh/yr (matches worksheet (219)).
Extended handover suite: 890 pass, 0 fail. Pyright net-zero (44=44).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| fixtures | ||
| __init__.py | ||
| test_elmhurst_end_to_end.py | ||
| test_elmhurst_extractor.py | ||
| test_end_to_end.py | ||
| test_extractor.py | ||
| test_heating_systems_corpus.py | ||
| test_pdf.py | ||
| test_summary_pdf_mapper_chain.py | ||