"""SAP 10.2 Table 13 — high-rate fraction for electric DHW heating. Sourced verbatim from `domain/sap10_calculator/docs/specs/sap-10-2-full- specification-2025-03-14.pdf`, page 197 (Table 13). RdSAP10 §10.5 (PDF p.54) routes electric immersion water heating here via Table 12a's "Immersion water heater" row, whose Water-heating column reads "Fraction from Table 13". The table gives the fraction of DHW electricity consumed at the HIGH rate for a cylinder with a single or dual immersion heater on an off-peak tariff; the remainder is at the low rate. Note 2 of the table supplies exact equations equivalent to the tabulated (rounded) grid — this module evaluates those equations, so no floor-area interpolation is needed: 7-hour tariff (>= 7 hours/day at the low rate) Dual: [(6.8 - 0.024 V) N + 14 - 0.07 V] / 100 Single: [(14530 - 762 N) / V - 80 + 10 N] / 100 10-hour tariff (>= 10 hours/day at the low rate) Dual: [(6.8 - 0.036 V) N + 14 - 0.105 V] / 100 Single: [(14530 - 762 N) / (1.5 V) - 80 + 10 N] / 100 where V is the cylinder volume (litres) and N is the assumed occupancy (Appendix J Table 1b). Per Note 2 the result is clamped to [0, 1]. Table 12a (PDF p.191) — whose title reads "High-rate fractions for systems using 7-hour and 10-hour tariffs" — routes the "Immersion water heater" row to Table 13 for the tariff "7-hour or 10-hour" ONLY. An 18-hour or 24-hour tariff is outside Table 12a/13'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 (all DHW billed at the low rate). The Elmhurst dr87 worksheet for solid fuel 5 (cert 001431: 18-hour meter, 110 L dual immersion, WHC 903) confirms this — HW (245) high-rate = 0.0 kWh, (246) low-rate = 100%. (An earlier reading mapped 18-/24-hour to the 10-hour column via Note 1's "at least 10 hours"; the worksheet refutes it — Table 12a's title bounds the table to the two named tariffs.) Heat pumps providing water heating only are treated as dual immersion (Note 1) — out of scope of this helper (callers route those via Table 12a). """ from __future__ import annotations from domain.sap10_calculator.tables.table_12a import Tariff def electric_dhw_high_rate_fraction( *, cylinder_volume_l: float, occupancy_n: float, single_immersion: bool, tariff: Tariff, ) -> float: """SAP 10.2 Table 13 (PDF p.197) high-rate fraction for an electric immersion DHW cylinder on an off-peak tariff. `single_immersion` selects the single- vs dual-immersion equation (RdSAP10 §10.5 p.54: an immersion is assumed dual on a dual meter). The 7-hour tariff uses the 7-hour equations; the 10-hour tariff uses the 10-hour equations. The 18-hour and 24-hour tariffs are outside Table 12a/13's "7-hour and 10-hour" scope (PDF p.191 title) — they provide >= 18 hours/day at the low rate, so the high-rate fraction is 0. STANDARD has no off-peak split and is rejected — callers must early-return before this fires. """ if tariff is Tariff.STANDARD: raise ValueError("Table 13 high-rate fraction is undefined for STANDARD") if tariff in (Tariff.EIGHTEEN_HOUR, Tariff.TWENTY_FOUR_HOUR): # Outside Table 12a's 7-hour/10-hour scope — >= 18 h/day low rate # heats the cylinder entirely off-peak (high-rate fraction 0). return 0.0 v = cylinder_volume_l n = occupancy_n if tariff is Tariff.SEVEN_HOUR: if single_immersion: fraction = ((14530 - 762 * n) / v - 80 + 10 * n) / 100 else: fraction = ((6.8 - 0.024 * v) * n + 14 - 0.07 * v) / 100 else: # 10-hour tariff (18-/24-hour handled above as out-of-scope). if single_immersion: fraction = ((14530 - 762 * n) / (1.5 * v) - 80 + 10 * n) / 100 else: fraction = ((6.8 - 0.036 * v) * n + 14 - 0.105 * v) / 100 return max(0.0, min(1.0, fraction))