§6 slice 1: Z-solar Table 6d lookup (winter solar access factor)

z_solar_for_overshading() returns Table 6d first column (0.3/0.54/0.77/1.0).
Tracer for §6 — mirrors §5's _Z_L_BY_OVERSHADING pattern. Distinct from the
lighting Z_L (third column) used by §5 and the cooling Z (second column,
out of scope for SAP heating rating).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-20 20:07:33 +00:00
parent 29feee7869
commit da5909de3d
2 changed files with 32 additions and 0 deletions

View file

@ -37,6 +37,23 @@ from domain.sap.climate.appendix_u import (
horizontal_solar_irradiance_w_per_m2,
solar_declination_deg,
)
from domain.sap.worksheet.internal_gains import OvershadingCategory
# Table 6d first column — winter solar access factor Z for heating gains.
# Distinct from the lighting Z_L (third column, §5) and cooling Z (second
# column, out of scope). SAP 10.2 spec p178.
_Z_SOLAR_BY_OVERSHADING: Final[dict[OvershadingCategory, float]] = {
OvershadingCategory.HEAVY: 0.3,
OvershadingCategory.MORE_THAN_AVERAGE: 0.54,
OvershadingCategory.AVERAGE: 0.77,
OvershadingCategory.VERY_LITTLE: 1.0,
}
def z_solar_for_overshading(overshading: OvershadingCategory) -> float:
"""SAP 10.2 Table 6d winter solar access factor Z for heating gains."""
return _Z_SOLAR_BY_OVERSHADING[overshading]
class Orientation(Enum):

View file

@ -11,13 +11,28 @@ Appendix U §U3.2 (pages 127-129), Table U4 (latitudes), Table U5
import pytest
from domain.sap.worksheet.internal_gains import OvershadingCategory
from domain.sap.worksheet.solar_gains import (
Orientation,
surface_solar_flux_w_per_m2,
window_solar_gain_w,
z_solar_for_overshading,
)
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
# SAP rating + DPER/TPER; distinct from the lighting Z_L (third column,
# consumed by §5) and the cooling Z (second column, out of scope).
# Act / Assert
assert z_solar_for_overshading(OvershadingCategory.HEAVY) == 0.3
assert z_solar_for_overshading(OvershadingCategory.MORE_THAN_AVERAGE) == 0.54
assert z_solar_for_overshading(OvershadingCategory.AVERAGE) == 0.77
assert z_solar_for_overshading(OvershadingCategory.VERY_LITTLE) == 1.0
def test_uk_average_south_vertical_july_returns_hand_computed_flux() -> None:
# Arrange — UK average region (0), South-facing vertical (p=90°), July.
# Hand-computed from Appendix U §U3.2 with Table U5 South constants: