mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
fix(glazing): remap divergent RdSAP-21 glazing codes 4/5 to cascade g slots
The g-value tables (_G_PERPENDICULAR_BY_GLAZING_TYPE solar g⊥,
_G_LIGHT_BY_GLAZING_CODE daylight g_L) are keyed on the SAP 10.2 Table 6b
cascade enum, but _api_cascade_glazing_type only translated code 1. Codes 4
and 5 sit in the 1-6 range where RdSAP-21 and the cascade enum disagree
(RdSAP-21 4=secondary/5=single vs cascade 4=double-low-E/5=secondary), so an
API single-glazed window read the cascade-5 secondary g (0.76/0.80) instead
of single (0.85/0.90), and a secondary window read cascade-4 double-low-E
(0.63). Added the {4:5, 5:1} remap entries the existing design comment
already anticipated ("only divergent codes need a remap").
Correctness fix: solar/daylight gains are second-order, so eval is unchanged
(56.66% within-0.5, 0 certs flip) — the dominant single-glazing error was the
U-value, closed in a0432977's Table 24 transmission map. This closes the
keying inconsistency to prevent future drift. 4 AAA tests, goldens + gate
green, pyright net-zero (38=38).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8e1e746a3e
commit
49fb6c1b8e
2 changed files with 61 additions and 0 deletions
|
|
@ -2988,6 +2988,16 @@ def _api_glazing_transmission(
|
|||
# remap — incremental coverage as new fixtures surface them.
|
||||
_API_TO_SAP10_CASCADE_GLAZING_CODE: Dict[int, int] = {
|
||||
1: 2, # RdSAP 21 DG pre-2002 → cascade DG (g_L=0.80, not single 0.90)
|
||||
# RdSAP-21 codes 4 and 5 DIVERGE from the cascade enum in the 1-6 range
|
||||
# (cascade 4 = double low-E soft-coat, 5 = secondary). Without these the
|
||||
# g-tables read the wrong slot: a single-glazed window (RdSAP-21 5) took
|
||||
# the cascade-5 secondary g (g⊥ 0.76 / g_L 0.80) for solar + daylight
|
||||
# gains instead of single (0.85 / 0.90), and a secondary-glazed window
|
||||
# (RdSAP-21 4) took cascade-4 double-low-E (0.63). Correctness fix
|
||||
# (gains are second-order — negligible SAP impact; the dominant single-
|
||||
# glazing error was the U-value, closed in the Table 24 transmission map).
|
||||
4: 5, # RdSAP 21 secondary glazing → cascade secondary slot (0.76/0.80)
|
||||
5: 1, # RdSAP 21 single glazing → cascade single slot (0.85/0.90)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1188,3 +1188,54 @@ class TestApiGlazingTransmissionTable24:
|
|||
|
||||
# Assert
|
||||
assert result == (2.0, 0.72, 0.70)
|
||||
|
||||
|
||||
class TestApiCascadeGlazingCodeDivergentRemap:
|
||||
"""`_api_cascade_glazing_type` must translate the RdSAP-21 glazing codes
|
||||
that DIVERGE from the SAP 10.2 Table 6b cascade enum the g-value tables
|
||||
(`_G_PERPENDICULAR_BY_GLAZING_TYPE` / `_G_LIGHT_BY_GLAZING_CODE`) are
|
||||
keyed on. Only code 1 was ever remapped; codes 4 and 5 sit in the 1-6
|
||||
range where the two enums disagree — RdSAP-21 4=secondary / 5=single,
|
||||
cascade 4=double-low-E / 5=secondary — so an API single-glazed window
|
||||
(5) read the cascade-5 (secondary) g slot for solar + daylight gains."""
|
||||
|
||||
def test_single_glazing_code_5_remaps_to_cascade_single_slot_1(self) -> None:
|
||||
# Arrange — RdSAP-21 code 5 = single glazing; cascade single slot
|
||||
# is 1 (g⊥ 0.85, g_L 0.90), not cascade 5 (secondary, 0.76/0.80).
|
||||
from datatypes.epc.domain.mapper import _api_cascade_glazing_type # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# Act
|
||||
result = _api_cascade_glazing_type(5)
|
||||
|
||||
# Assert
|
||||
assert result == 1
|
||||
|
||||
def test_secondary_glazing_code_4_remaps_to_cascade_secondary_slot_5(self) -> None:
|
||||
# Arrange — RdSAP-21 code 4 = secondary glazing; cascade secondary
|
||||
# slot is 5 (g⊥ 0.76, g_L 0.80), not cascade 4 (double low-E 0.63).
|
||||
from datatypes.epc.domain.mapper import _api_cascade_glazing_type # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# Act
|
||||
result = _api_cascade_glazing_type(4)
|
||||
|
||||
# Assert
|
||||
assert result == 5
|
||||
|
||||
def test_double_pre_2002_code_1_remap_unchanged(self) -> None:
|
||||
# Arrange — regression guard: the existing code-1 remap (→2) stands.
|
||||
from datatypes.epc.domain.mapper import _api_cascade_glazing_type # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# Act
|
||||
result = _api_cascade_glazing_type(1)
|
||||
|
||||
# Assert
|
||||
assert result == 2
|
||||
|
||||
def test_rdsap21_native_codes_pass_through(self) -> None:
|
||||
# Arrange — codes 9-15 already coincide with the g-table's RdSAP-21
|
||||
# extension slots, so they must pass through untranslated.
|
||||
from datatypes.epc.domain.mapper import _api_cascade_glazing_type # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# Act / Assert
|
||||
assert _api_cascade_glazing_type(14) == 14
|
||||
assert _api_cascade_glazing_type(9) == 9
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue