"""SAP 10.2 Table 13 — high-rate fraction for electric DHW heating. Locks `electric_dhw_high_rate_fraction` against the published table grid and the Note-2 clamp at `domain/sap10_calculator/docs/specs/sap-10-2-full-specification-2025-03-14.pdf`, page 197. Table 12a's "Immersion water heater" row (PDF p.191) routes electric immersion DHW here. The helper evaluates the Note-2 equations, which the spec offers as an exact alternative to the rounded grid — the pins below check that the equations reproduce the published 2-dp cells. """ from __future__ import annotations from domain.sap10_calculator.tables.table_12a import Tariff from domain.sap10_calculator.tables.table_13 import ( electric_dhw_high_rate_fraction, ) # Appendix J Table 1b occupancy N at a few total floor areas (m²) — the # anchor for the V/N grid cells below. Computed from the same piecewise # formula the §4 worksheet uses (water_heating.assumed_occupancy). _N_AT_TFA_100 = 2.7395 # N(100 m²) _N_AT_TFA_60 = 1.9816 # N(60 m²) # Table 13 high-rate-fraction grid cells (PDF p.197), keyed by (floor # area row, cylinder litres column, tariff, single?) → published value. _GRID_TOL = 0.005 # the published grid is rounded to 2 dp def test_table_13_dual_immersion_matches_published_grid() -> None: # Arrange — SAP 10.2 Table 13 (PDF p.197), 110 L cylinder, dual # immersion. Floor area 100 m² row: 7-hour = 0.18, 10-hour = 0.10. # Act seven = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=False, tariff=Tariff.SEVEN_HOUR, ) ten = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=False, tariff=Tariff.TEN_HOUR, ) # Assert assert abs(seven - 0.18) <= _GRID_TOL assert abs(ten - 0.10) <= _GRID_TOL def test_table_13_single_immersion_matches_published_grid() -> None: # Arrange — SAP 10.2 Table 13 (PDF p.197), 110 L cylinder, single # immersion. Floor area 100 m² row: 7-hour = 0.61, 10-hour = 0.23. # Single immersion carries a much larger high-rate fraction than dual. # Act seven = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=True, tariff=Tariff.SEVEN_HOUR, ) ten = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=True, tariff=Tariff.TEN_HOUR, ) # Assert assert abs(seven - 0.61) <= _GRID_TOL assert abs(ten - 0.23) <= _GRID_TOL def test_table_13_large_cylinder_single_immersion_clamps_to_zero() -> None: # Arrange — SAP 10.2 Table 13 Note 2 (PDF p.197): "If these formulae # give a value less than zero, set the high-rate fraction to zero." A # 210 L cylinder with single immersion on a 10-hour tariff falls below # zero (the published 210 L 10-hour column is 0), so the helper clamps. # Act fraction = electric_dhw_high_rate_fraction( cylinder_volume_l=210.0, occupancy_n=_N_AT_TFA_60, single_immersion=True, tariff=Tariff.TEN_HOUR, ) # Assert assert fraction == 0.0 def test_table_13_eighteen_and_twenty_four_hour_bill_full_low_rate() -> None: # Arrange — SAP 10.2 Table 12a (PDF p.191) is titled "High-rate # fractions for systems using 7-hour and 10-hour tariffs"; its # "Immersion water heater" row lists the tariff as "7-hour or 10-hour" # only, routing to Table 13. An 18-hour / 24-hour tariff is OUTSIDE the # table's scope: it provides at least 18 hours/day at the low rate, more # than enough to heat any immersion cylinder off-peak, so the high-rate # fraction is 0 (100% billed at the low rate). The Elmhurst dr87 # worksheet for solid fuel 5 (cert 001431: 18-hour meter, 110 L dual # immersion, WHC 903) bills HW (245) high-rate = 0.0 kWh, (246) low-rate # = 100% — confirming high_frac = 0 for an 18-hour immersion DHW. # Act eighteen = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=False, tariff=Tariff.EIGHTEEN_HOUR, ) twenty_four = electric_dhw_high_rate_fraction( cylinder_volume_l=110.0, occupancy_n=_N_AT_TFA_100, single_immersion=False, tariff=Tariff.TWENTY_FOUR_HOUR, ) # Assert assert eighteen == 0.0 assert twenty_four == 0.0