§6 slice 3: _g_perpendicular honours SapWindow.window_transmission_details

Elmhurst lodges per-window g⊥ via Manufacturer-source
window_transmission_details.solar_transmittance on every window — the
Table 6b code lookup is the cascade fallback, not the primary path.
Without this the orchestrator picks Table 6b defaults that don't match
the worksheet (e.g. glazing_type=4 defaults to low-E soft 0.63, but the
manufacturer-declared value 0.76 is what the §6 row uses).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-20 20:34:05 +00:00
parent 4b83e7023f
commit d56fef4d62
2 changed files with 36 additions and 2 deletions

View file

@ -258,7 +258,12 @@ class SolarGainsResult:
def _g_perpendicular(w: SapWindow) -> float:
"""Table 6b g⊥ by glazing_type code, defaulting to 0.76 for unknowns."""
"""Table 6b g⊥. Prefer the cert's measured value
(`window_transmission_details.solar_transmittance`) when present
Elmhurst lodges it for every window; Table 6b is the cascade fallback.
"""
if w.window_transmission_details is not None:
return float(w.window_transmission_details.solar_transmittance)
if isinstance(w.glazing_type, int) and w.glazing_type in _G_PERPENDICULAR_BY_GLAZING_TYPE:
return _G_PERPENDICULAR_BY_GLAZING_TYPE[w.glazing_type]
return _G_PERPENDICULAR_DEFAULT

View file

@ -11,7 +11,7 @@ Appendix U §U3.2 (pages 127-129), Table U4 (latitudes), Table U5
import pytest
from datatypes.epc.domain.epc_property_data import SapWindow
from datatypes.epc.domain.epc_property_data import SapWindow, WindowTransmissionDetails
from domain.ml.tests._fixtures import make_minimal_sap10_epc, make_window
from domain.sap.worksheet.internal_gains import OvershadingCategory
from domain.sap.worksheet.solar_gains import (
@ -63,6 +63,35 @@ def test_solar_gains_from_cert_reproduces_000490_line_83_total() -> None:
), f"(83) month {m+1}"
def test_solar_gains_from_cert_prefers_manufacturer_g_perpendicular_over_table_6b() -> None:
# Arrange — SAP 10.2 §6.1 + Table 6b note 2: when the manufacturer
# supplies a measured solar transmittance via the cert's
# `window_transmission_details`, it overrides the Table 6b code lookup.
# Elmhurst lodges this for every window (Source = "Manufacturer"). Same
# 5.52 m² SE window as 000490 SE, but glazing_type=4 (low-E soft, table
# default 0.63) with manufacturer g⊥=0.76 — the manufacturer value must
# win, reproducing the worksheet gain.
window = make_window(
orientation=4, width=5.52, height=1.0, glazing_type=4,
)
window.window_transmission_details = WindowTransmissionDetails(
u_value=2.8, data_source=1, solar_transmittance=0.76,
)
epc = make_minimal_sap10_epc(
total_floor_area_m2=53.0,
sap_windows=[window],
)
# Act
result = solar_gains_from_cert(
epc=epc, region=0, overshading=OvershadingCategory.AVERAGE,
)
# Assert — single SE window, Jan UK-avg flux 36.7938, gain 74.8788 W
assert result.southeast_monthly_w[0] == pytest.approx(74.8788, abs=5e-3)
assert result.total_solar_gains_monthly_w[0] == pytest.approx(74.8788, abs=5e-3)
def test_z_solar_for_overshading_returns_table_6d_first_column() -> None:
# Arrange — SAP 10.2 Table 6d "Winter solar access factor (for calculation
# of solar gains for heating)" — first numeric column on p178. Used for