mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice S0380.108: Connected-to-heated-space RR gables deduct from A_RR (RdSAP 10 §3.9.2 + Table 4 row 4)
Closes the largest single localised fabric residual on cert 000565
(roof +1.59 W/K over, area +4.70 m² over) by routing
Connected-gable surfaces through a new `connected_wall` kind that
deducts area from the residual A_RR per the spec but contributes
0 W/K per RdSAP 10 Table 4 row 4.
RdSAP 10 §3.9.2 step (d) (PDF p.23) verbatim:
"The areas of gable walls are deducted from the calculated total
RR area, and the remaining area of RR, ARR_final is then
calculated. This area is treated as roof structure.
ARR_final = ARR_wall − (ΣARR_common_wall + ΣARR_gable +
ΣARR_party + ΣARR_sheltered +
ΣARR_connected)"
RdSAP 10 Table 4 row 4 (PDF p.22):
"ARR_connected — Adjacent to heated space — U-value = 0"
The U=0 means no heat-loss contribution, but the area STILL appears
in the deduction equation as ΣARR_connected. Pre-slice the mapper's
`_map_elmhurst_rir_surface` returned None for Connected gables,
dropping them entirely from `detailed_surfaces` so the cascade
neither billed them nor deducted them. The residual A_RR was
therefore over by their lodged area.
Cert 000565 Ext1 §8.1 lodges (Simplified Type 2):
Gable Wall 1 L=4.00 H=6.00 Connected U=0
Gable Wall 2 L=8.00 H=9.00 Exposed U=1.70
Common Wall 1 L=9.00 H=1.00 U=1.70
Common Wall 2 L=5.00 H=1.80 U=1.70
Gable Wall 1 area via §3.9.2 quadratic:
A_gable_1 = 4 × (0.25 + 6)
− (6 − 1)²/2 ← subtract triangle above Common Wall 1
− (6 − 1.8)²/2 ← subtract triangle above Common Wall 2
= 25.0 − 12.5 − 8.82
= 3.68 m²
Pre-slice:
A_RR shell = 12.5 × √(34 / 1.5) = 59.51 m²
Σ wall areas = 11.25 + 10.25 + 16.08 = 37.58 m²
Residual = 21.93 m² (worksheet: 18.25; over by +3.68)
Roof W/K = 21.93 × 0.35 = 7.68 (worksheet: 6.39; over by +1.29)
3-layer fix:
1. Mapper `_map_elmhurst_rir_surface` (datatypes/epc/domain/mapper.py)
now routes "Connected" gable_type to kind="connected_wall" with
u_value=0 and area via the Simplified Type 2 quadratic correction.
2. Heat transmission `heat_transmission_from_cert` (domain/sap10_
calculator/worksheet/heat_transmission.py) adds a connected_wall
branch that deducts area from rr_walls_in_a_rr_area but skips
walls/party W/K contribution.
3. AAA test pins Ext1 Connected gable area at 3.68 m² and U=0.
Movement at HEAD `b7fa5f74` → post-slice (cert 000565):
Fabric (cascade vs ws):
walls 602.53 → 602.53 (Δ -1.54 W/K; unchanged)
roof 52.97 → 51.68 (Δ +1.59 → +0.30 W/K; closes 81%)
TB 129.35 → 128.80 (Δ +0.70 → +0.15 W/K; closes 79%)
total area 862.34 → 858.66 (Δ +4.70 → +1.02 m²; closes 78%)
total W/K 937.40 → 935.54 (Δ +0.33 → -1.52 W/K; sign flips)
End-result pins:
**sap_score (int) 28 → 29 ✓ EXACT vs ws 29** (RECOVERED from
S0380.107 transient
rounding flip)
sap_score_continuous 28.4959 → 28.5380 (Δ -0.0128 → +0.0293)
ecf 5.3881 → 5.3838 (Δ +0.0015 → -0.0028)
total_fuel_cost_gbp 4681.39 → 4677.64 (Δ +1.13 → -2.62)
co2_kg_per_yr 6449.13 → 6444.27 (Δ +1.51 → -3.35)
space_heating_kwh 59028.80 → 58974.84 (Δ +20.5 → -33.5)
main_heating_fuel 34722.83 → 34691.09 (Δ +12.0 → -19.7)
lighting_kwh 1382.67 → 1382.67 (unchanged)
pumps_fans_kwh ✓ EXACT (unchanged)
Continuous SAP and downstream pins SIGN-FLIPPED again
(cascade was over post-.107, now under post-.108). Per user
direction: transient drift acceptable while closing a true
intermediate-value bug. The remaining net HTC -1.52 W/K is
mostly walls (-1.54 W/K) — closing the Detailed-RR walls
residual is the next leverage front.
Cohort safety: none of the 6 cohort certs lodge a Connected
gable (grep audit across all Summary fixtures). The new
`connected_wall` branch only fires for the cert 000565 Ext1 BP.
Test count: 606 pass + 8 expected 000565 fails → **608 pass +
7 expected 000565 fails** (sap_score back to exact + new
Connected-gable test green). Pyright net-zero per touched
file (57 baseline → 57 post-change).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b7fa5f74ec
commit
9159e91fbc
3 changed files with 102 additions and 5 deletions
|
|
@ -2065,6 +2065,75 @@ def test_summary_000565_window_routing_uses_bp_roof_type_per_rdsap_10_section_3_
|
|||
)
|
||||
|
||||
|
||||
def test_summary_000565_ext1_rir_connected_gable_deducts_from_a_rr_per_rdsap_10_section_3_9_2() -> None:
|
||||
# Arrange — RdSAP 10 §3.9.2 (PDF p.23) step (d) verbatim:
|
||||
#
|
||||
# "The areas of gable walls are deducted from the calculated total
|
||||
# RR area, and the remaining area of RR, ARR_final is then
|
||||
# calculated. This area is treated as roof structure.
|
||||
# ARR_final = ARR_wall − (ΣARR_common_wall + ΣARR_gable +
|
||||
# ΣARR_party + ΣARR_sheltered +
|
||||
# ΣARR_connected)"
|
||||
#
|
||||
# RdSAP 10 Table 4 row 4 (PDF p.22): "ARR_connected — Adjacent to
|
||||
# heated space — U-value = 0". The U=0 means no heat-loss
|
||||
# contribution, but the area STILL deducts from the residual A_RR
|
||||
# (spec step (d) explicitly sums ARR_connected in the deduction).
|
||||
#
|
||||
# Cert 000565 Ext1 §8.1 lodges (Simplified Type 2 RR):
|
||||
#
|
||||
# Gable Wall 1 L=4.00 H=6.00 Connected U=0
|
||||
# Gable Wall 2 L=8.00 H=9.00 Exposed U=1.70
|
||||
# Common Wall 1 L=9.00 H=1.00 U=1.70
|
||||
# Common Wall 2 L=5.00 H=1.80 U=1.70
|
||||
#
|
||||
# Gable area via §3.9.2 quadratic (subtract triangular slice above
|
||||
# each common wall):
|
||||
#
|
||||
# A_gable_1 = 4 × (0.25 + 6) − (6 − 1)²/2 − (6 − 1.8)²/2
|
||||
# = 25.0 − 12.5 − 8.82
|
||||
# = 3.68 m²
|
||||
#
|
||||
# Pre-S0380.108 the mapper dropped Connected gables entirely
|
||||
# (`_map_elmhurst_rir_surface` returned None). The cascade's
|
||||
# residual A_RR was therefore over by +3.68 m²:
|
||||
#
|
||||
# A_RR shell = 12.5 × √(34 / 1.5) = 59.51 m²
|
||||
# Σ wall areas (current) = 11.25 + 10.25 + 16.08 = 37.58 m²
|
||||
# Residual (cascade) = 59.51 − 37.58 = 21.93 m² (over)
|
||||
# Residual (worksheet) = 59.51 − 37.58 − 3.68 = 18.25 m²
|
||||
#
|
||||
# Worksheet (30) row "Roof room Ext1 remaining area: 18.25" at U=0.35
|
||||
# → 6.3875 W/K. Cascade pre-slice 21.93 × 0.35 → 7.6755 W/K
|
||||
# (over by +1.29 W/K on roof — the largest single localised
|
||||
# residual on cert 000565 per HANDOVER_POST_S0380_103.md).
|
||||
pages = _summary_pdf_to_textract_style_pages(_SUMMARY_000565_PDF)
|
||||
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||
|
||||
# Assert — Ext1 RIR detailed_surfaces holds the Connected gable
|
||||
# with the quadratic-corrected area, so the cascade deducts it
|
||||
# from A_RR per step (d).
|
||||
ext1_rir = epc.sap_building_parts[1].sap_room_in_roof
|
||||
assert ext1_rir is not None
|
||||
assert ext1_rir.detailed_surfaces is not None
|
||||
connected_gables = [
|
||||
s for s in ext1_rir.detailed_surfaces
|
||||
if s.kind == "connected_wall"
|
||||
]
|
||||
assert len(connected_gables) == 1, (
|
||||
f"expected 1 Connected gable; got {len(connected_gables)} "
|
||||
f"(detailed_surfaces kinds: "
|
||||
f"{[s.kind for s in ext1_rir.detailed_surfaces]})"
|
||||
)
|
||||
# 4 × (0.25 + 6) − (6 − 1)²/2 − (6 − 1.8)²/2 = 3.68
|
||||
assert abs(connected_gables[0].area_m2 - 3.68) <= 1e-4
|
||||
# U-value = 0 per Table 4 row 4 (no heat-loss contribution)
|
||||
assert connected_gables[0].u_value == 0.0
|
||||
|
||||
|
||||
def test_summary_000565_main_1_ashp_sap_code_224_routes_to_main_heating_category_4_per_sap_table_4a() -> None:
|
||||
# Arrange — SAP 10.2 Table 4a (PDF p.165) "Main heating systems":
|
||||
# the category column lists "Heat pumps" as category 4. Codes in
|
||||
|
|
|
|||
|
|
@ -3349,12 +3349,31 @@ def _map_elmhurst_rir_surface(
|
|||
"""
|
||||
if surface.length_m <= 0 or surface.height_m <= 0:
|
||||
return None
|
||||
# RdSAP 10 §3.10 Table 4 row 4 — "Connected to heated space" gables
|
||||
# are internal partitions, not heat-loss surfaces. Per Summary PDF
|
||||
# schema the column reads "Connected" (or the verbose "Connected
|
||||
# to heated space"); drop either form.
|
||||
# RdSAP 10 §3.9.2 step (d) (PDF p.23) — Connected-to-heated-space
|
||||
# gables contribute U=0 (Table 4 row 4, PDF p.22) but their area
|
||||
# STILL deducts from the residual A_RR per the explicit
|
||||
# ΣARR_connected term in the spec equation. Route to a discrete
|
||||
# "connected_wall" kind so heat_transmission can deduct the area
|
||||
# without adding to walls or party W/K. Area follows the same
|
||||
# Simplified Type 2 quadratic as exposed gables.
|
||||
if surface.gable_type in ("Connected", "Connected to heated space"):
|
||||
return None
|
||||
length_m, height_m = surface.length_m, surface.height_m
|
||||
if is_simplified and common_wall_heights:
|
||||
correction = sum(
|
||||
((height_m - h) ** 2) / 2.0
|
||||
for h in common_wall_heights
|
||||
if height_m > h
|
||||
)
|
||||
area_m2 = _round_half_up_2dp(
|
||||
1.0, max(0.0, length_m * (0.25 + height_m) - correction)
|
||||
)
|
||||
else:
|
||||
area_m2 = _round_half_up_2dp(length_m, height_m)
|
||||
return SapRoomInRoofSurface(
|
||||
kind="connected_wall",
|
||||
area_m2=area_m2,
|
||||
u_value=0.0,
|
||||
)
|
||||
if surface.name.startswith("Common Wall"):
|
||||
# RdSAP 10 §3.9.2 Simplified Type 2 — common walls billing into
|
||||
# the RR carry the storey-below main-wall U via the lodged
|
||||
|
|
|
|||
|
|
@ -914,6 +914,15 @@ def heat_transmission_from_cert(
|
|||
rr_detailed_area += area
|
||||
walls += u_common * area
|
||||
rr_walls_in_a_rr_area += area
|
||||
elif kind == "connected_wall":
|
||||
# RdSAP 10 Table 4 row 4 (PDF p.22) — "Adjacent to
|
||||
# heated space" gables have U=0 (no heat-loss
|
||||
# contribution) but §3.9.2 step (d) explicitly
|
||||
# deducts ΣA_RR_connected from the residual A_RR.
|
||||
# Mapper precomputes the area via the Simplified
|
||||
# Type 2 quadratic. Skip walls/party W/K; count the
|
||||
# area in the A_RR deduction only.
|
||||
rr_walls_in_a_rr_area += area
|
||||
# RdSAP 10 §3.10.1 residual area = simplified A_RR shell
|
||||
# minus the wall surfaces just enumerated. Uses the same
|
||||
# §3.9.1 `12.5 × √(A_RR_floor / 1.5)` formula as the
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue