Slice S0380.50: §4 seasonal monthly HW fuel for PV β cascade

The PV β-factor cascade was prorating the annual hot-water fuel kWh
uniformly by days when feeding D_PV,m per Appendix M1 footnote 32.
The worksheet uses §4 (219)m = (62)m / efficiency monthly — which is
seasonal (peaks in Jan when cold-mains-inlet drives energy content,
troughs in Jul/Aug). For cert 0380: worksheet Jul (219) = 68.30 kWh
vs cascade days-prorated 74.60 kWh — over-counted summer D_PV by
~6 kWh/month.

Per Appendix M1 footnote 32: "D_PV,m = ... + E_water,m" where
"E_water,m = (219)_m if water heating fuel code applied in Section
10a of the SAP worksheet is 30". (219)_m is the §4 fuel kWh per
month, not annual / 12.

Fix: scale `wh_result.output_monthly_kwh` to sum to the annual fuel
`hw_kwh` (equivalent to dividing each month by the annual-average
efficiency — exact for single-COP HP water heaters; close enough
for PCDB combi winter/summer-split efficiencies because the annual
total already accounts for the seasonal-efficiency mix). None fall-
back to the legacy days-proration when wh_result is absent
(TFA-missing certs).

Cohort PE residual closure (kWh/m²):

| Cert | Post-S0380.49 | Post-S0380.50 |
|---|---:|---:|
| 0350 | -2.96 | **-2.90** |
| 0380 | -3.06 | **-2.96** |
| 2225 | -3.73 | **-3.54** |
| 2636 | -3.44 | **-3.28** |
| 3800 | -3.25 | **-3.16** |
| 9285 | -2.81 | **-2.74** |
| 9418 | -3.01 | **-2.89** |

Modest but real cohort closure (~0.1 kWh/m² each). The remaining
~3 kWh/m² traces to a small cascade β over-count (0.751 vs worksheet
0.739) — likely Appendix L monthly-weighting details for appliances/
cooking/electric-shower in D_PV; deferred to a follow-up slice.

Cert 9501 (PV no battery) unchanged at +0.65 PE.
CO2 cohort: <0.11 t/yr (within tolerance, re-pinned in same slice).
SAP scores all exact. 763 pass + 0 fail. Pyright net-zero.
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-28 19:56:57 +00:00 committed by Jun-te Kim
parent fb1e7895fa
commit 7496ad024b
2 changed files with 58 additions and 35 deletions

View file

@ -3128,6 +3128,28 @@ def cert_to_inputs(
# = electricity → Table 12 code 30) per the Appendix M1 §3a fuel
# inclusion list.
pv_monthly_kwh = _pv_monthly_generation_kwh(epc, climate)
# SAP 10.2 Appendix M1 footnote 32 D_PV,m uses §4 (219)m monthly
# water-heating fuel kWh — which is the (62)m output divided by the
# water-heater efficiency. Uniform days-proration over the annual
# `hw_kwh` over-counts D_PV in summer and under-counts in winter
# (the (45)m hot-water energy content is seasonal, peaking in Jan).
# Scale `wh_output_monthly_kwh` to sum to the annual fuel `hw_kwh`
# — equivalent to dividing each month by the annual-average
# efficiency, which matches the worksheet's (219)m for HP / single-
# efficiency water heaters. For PCDB combis with distinct winter /
# summer efficiencies, `_apply_water_efficiency` already accounted
# for the seasonal split in the annual total; preserving the §4
# monthly shape here keeps the per-month distribution faithful.
if wh_result is not None and sum(wh_result.output_monthly_kwh) > 0:
output_total = sum(wh_result.output_monthly_kwh)
hot_water_monthly_kwh_for_pv = tuple(
wh_result.output_monthly_kwh[m] / output_total * hw_kwh
for m in range(12)
)
else:
hot_water_monthly_kwh_for_pv = _days_in_month_proportioned(
hw_kwh, _DAYS_IN_MONTH,
)
pv_eligible_demand_monthly_kwh = _pv_eligible_demand_monthly_kwh(
lighting_monthly_kwh=lighting_monthly_kwh,
appliances_monthly_kwh=appliances_monthly_kwh,
@ -3140,7 +3162,7 @@ def cert_to_inputs(
pumps_fans_kwh, _DAYS_IN_MONTH,
),
main_1_fuel_monthly_kwh=energy_requirements_result.main_1_fuel_monthly_kwh,
hot_water_monthly_kwh=_days_in_month_proportioned(hw_kwh, _DAYS_IN_MONTH),
hot_water_monthly_kwh=hot_water_monthly_kwh_for_pv,
main_fuel_code_table_12=(
API_FUEL_TO_TABLE_12.get(main_fuel, main_fuel)
if main_fuel is not None else None

View file

@ -257,93 +257,94 @@ _EXPECTATIONS: tuple[_GoldenExpectation, ...] = (
cert_number="0380-2471-3250-2596-8761",
actual_sap=89,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-3.0557,
expected_co2_resid_tonnes_per_yr=-0.0549,
expected_pe_resid_kwh_per_m2=-2.9633,
expected_co2_resid_tonnes_per_yr=-0.0548,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, semi-detached bungalow "
"TFA 60.43 age D, PV 3 kWp + 5 kWh battery. Worksheet SAP "
"88.5104. Slice S0380.48 surfaced the 5-kWh battery from "
"the flat-shape real-API JSON (PE +8.09 → -4.01). Slice "
"S0380.49 then wired effective-monthly Table 12e PE factor "
"into the PV split — dwelling 1.4952 (vs worksheet 1.4960), "
"exported 0.4283 (vs worksheet 0.4268) — closing PE -4.01 "
"→ -3.06. The residual -3 traces to a small β fine-tuning "
"gap (cascade 0.751 vs worksheet 0.7426) — monthly D_PV "
"distribution detail."
"88.5104. Slice S0380.48 surfaced the 5-kWh battery (PE "
"+8.09 → -4.01); .49 wired Table 12e effective-monthly PE "
"factor (PE -4.01 → -3.06); Slice S0380.50 replaced "
"days-prorated hot-water demand in the PV β cascade with "
"the §4 (62)m seasonal output scaled to annual fuel (PE "
"-3.06 → -2.96). Remaining ~3 kWh/m² traces to a small "
"cascade β over-count (0.751 vs worksheet 0.739) — "
"monthly D_PV distribution for appliances/cooking/electric-"
"shower likely needs Appendix L-aligned monthly weights."
),
),
_GoldenExpectation(
cert_number="0350-2968-2650-2796-5255",
actual_sap=84,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-2.9642,
expected_co2_resid_tonnes_per_yr=-0.0865,
expected_pe_resid_kwh_per_m2=-2.8973,
expected_co2_resid_tonnes_per_yr=-0.0864,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
"PV + 5 kWh battery. Worksheet SAP 84.1367. Slice S0380.49 "
"Table 12e PE factor wiring closed PE -3.58 → -2.96."
"PV + 5 kWh battery. Worksheet SAP 84.1367. Slice S0380.50 "
"HW seasonal-monthly fix closed PE -2.96 → -2.90."
),
),
_GoldenExpectation(
cert_number="2225-3062-8205-2856-7204",
actual_sap=89,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-3.7259,
expected_co2_resid_tonnes_per_yr=-0.0729,
expected_pe_resid_kwh_per_m2=-3.5393,
expected_co2_resid_tonnes_per_yr=-0.0726,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
"PV + 5 kWh battery. Worksheet SAP 88.7921. Slice S0380.49 "
"Table 12e PE factor wiring closed PE -4.50 → -3.73."
"PV + 5 kWh battery. Worksheet SAP 88.7921. Slice S0380.50 "
"HW seasonal-monthly fix closed PE -3.73 → -3.54."
),
),
_GoldenExpectation(
cert_number="2636-0525-2600-0401-2296",
actual_sap=86,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-3.4364,
expected_co2_resid_tonnes_per_yr=-0.0603,
expected_pe_resid_kwh_per_m2=-3.2775,
expected_co2_resid_tonnes_per_yr=-0.0601,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
"PV + 5 kWh battery + 3.74 m² cantilever + 12.76 m² alt wall. "
"Worksheet SAP 86.2641. Slice S0380.49 Table 12e PE factor "
"wiring closed PE -4.14 → -3.44."
"Worksheet SAP 86.2641. Slice S0380.50 HW seasonal-monthly "
"fix closed PE -3.44 → -3.28."
),
),
_GoldenExpectation(
cert_number="3800-8515-0922-3398-3563",
actual_sap=86,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-3.2511,
expected_co2_resid_tonnes_per_yr=-0.0166,
expected_pe_resid_kwh_per_m2=-3.1623,
expected_co2_resid_tonnes_per_yr=-0.0165,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
"PV + 5 kWh battery. Worksheet SAP 86.1458. Slice S0380.49 "
"Table 12e PE factor wiring closed PE -4.01 → -3.25."
"PV + 5 kWh battery. Worksheet SAP 86.1458. Slice S0380.50 "
"HW seasonal-monthly fix closed PE -3.25 → -3.16."
),
),
_GoldenExpectation(
cert_number="9285-3062-0205-7766-7200",
actual_sap=84,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-2.8078,
expected_co2_resid_tonnes_per_yr=-0.1003,
expected_pe_resid_kwh_per_m2=-2.7361,
expected_co2_resid_tonnes_per_yr=-0.1002,
notes=(
"Mitsubishi PUZ-WM50VHA PCDB 104568, ASHP cohort cert with "
"PV + 5 kWh battery. Worksheet SAP 84.1369. Slice S0380.49 "
"Table 12e PE factor wiring closed PE -3.46 → -2.81."
"PV + 5 kWh battery. Worksheet SAP 84.1369. Slice S0380.50 "
"HW seasonal-monthly fix closed PE -2.81 → -2.74."
),
),
_GoldenExpectation(
cert_number="9418-3062-8205-3566-7200",
actual_sap=85,
expected_sap_resid=+0,
expected_pe_resid_kwh_per_m2=-3.0084,
expected_co2_resid_tonnes_per_yr=-0.0485,
expected_pe_resid_kwh_per_m2=-2.8890,
expected_co2_resid_tonnes_per_yr=-0.0483,
notes=(
"Daikin Altherma EDLQ05CAV3 PCDB 102421 (heating_duration "
"code '24' — continuous, all days at Th) + 5 kWh battery. "
"Worksheet SAP 84.6305. Slice S0380.49 Table 12e PE factor "
"wiring closed PE -3.76 → -3.01."
"Worksheet SAP 84.6305. Slice S0380.50 HW seasonal-monthly "
"fix closed PE -3.01 → -2.89."
),
),
)