mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
S0380.236: extension party-wall type read independently of "As Main Wall"
RdSAP 10 §3.3: "As Main Wall: Yes" makes an extension inherit the main dwelling's external wall CONSTRUCTION only — the party wall type is lodged separately per building part in the Summary §7 block and may differ. `_extract_extensions` was copying `main_walls.party_wall_type` into the inherited WallDetails, so every extension reused the main's party wall U. On the double_glazing fixture (Summary_001431) the Main lodges party "CU Cavity masonry unfilled" (SAP10 wall_construction 4 → u_party_wall 0.5) but the 1st Extension lodges "U Unable to determine" (→ 0 → RdSAP default 0.25). Pre-fix both building parts used 0.5, inflating worksheet (32) party-wall heat loss by 6.56 W/K (Ext1 26.25 m² × 0.25). After the fix worksheet (32) is exact: ours 32.573 vs worksheet 32.5725. Now reads the extension's own "Party Wall Type" from its §7 chunk, falling back to the main's only when the extension lodges none. Adds a fixture + test asserting Main=4 / Ext=0 with distinct u_party_wall. Suite 2413 pass; no cohort regression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3e45b7fa3b
commit
ea35bed24c
3 changed files with 44 additions and 1 deletions
|
|
@ -670,12 +670,24 @@ class ElmhurstSiteNotesExtractor:
|
|||
# even when the main wall fields are inherited; merge
|
||||
# them into the inherited WallDetails so the bp carries
|
||||
# them through to its SapBuildingPart.
|
||||
#
|
||||
# "As Main Wall: Yes" inherits the EXTERNAL wall
|
||||
# construction only — the PARTY WALL TYPE is lodged
|
||||
# separately in the extension's §7 block and may differ
|
||||
# (cert 001431: Main "CU Cavity masonry unfilled" U=0.5,
|
||||
# 1st Extension "U Unable to determine" → RdSAP default
|
||||
# U=0.25). Read the extension's own party wall type when
|
||||
# present; fall back to the main's only when absent.
|
||||
ext_party_wall_type = (
|
||||
self._local_str(wall_lines, "Party Wall Type")
|
||||
or main_walls.party_wall_type
|
||||
)
|
||||
walls = WallDetails(
|
||||
wall_type=main_walls.wall_type,
|
||||
insulation=main_walls.insulation,
|
||||
thickness_unknown=main_walls.thickness_unknown,
|
||||
u_value_known=main_walls.u_value_known,
|
||||
party_wall_type=main_walls.party_wall_type,
|
||||
party_wall_type=ext_party_wall_type,
|
||||
thickness_mm=main_walls.thickness_mm,
|
||||
insulation_thickness_mm=main_walls.insulation_thickness_mm,
|
||||
alternative_walls=self._alternative_walls_from_lines(wall_lines),
|
||||
|
|
|
|||
BIN
backend/documents_parser/tests/fixtures/Summary_001431_double_glazing.pdf
vendored
Normal file
BIN
backend/documents_parser/tests/fixtures/Summary_001431_double_glazing.pdf
vendored
Normal file
Binary file not shown.
|
|
@ -1502,6 +1502,37 @@ def test_elmhurst_glazing_label_full_coverage_per_sap10_table_6b() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_extension_party_wall_type_read_independently_of_as_main_wall() -> None:
|
||||
# Arrange — RdSAP 10 §3.3: "As Main Wall: Yes" inherits only the
|
||||
# external wall CONSTRUCTION; the party wall type is lodged
|
||||
# separately per building part and may differ. The double_glazing
|
||||
# fixture (Summary_001431) lodges Main party "CU Cavity masonry
|
||||
# unfilled" (SAP10 wall_construction 4 → u_party_wall 0.5) but the
|
||||
# 1st Extension party "U Unable to determine" (→ wall_construction 0
|
||||
# → RdSAP default u_party_wall 0.25), even though the extension is
|
||||
# "As Main Wall: Yes". Pre-fix the extension inherited the Main's
|
||||
# party type (both 0.5), inflating worksheet (32) party heat loss.
|
||||
pages = _summary_pdf_to_textract_style_pages(
|
||||
_FIXTURES / "Summary_001431_double_glazing.pdf"
|
||||
)
|
||||
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||
|
||||
# Assert — Main BP keeps cavity-unfilled (4); the extension BP gets
|
||||
# the "Unable to determine" sentinel (0), a distinct party wall U.
|
||||
party_codes = [
|
||||
bp.party_wall_construction for bp in epc.sap_building_parts
|
||||
]
|
||||
assert party_codes == [4, 0], (
|
||||
f"expected Main=4 (CU, U=0.5) + Ext=0 (Unable, U=0.25), got {party_codes}"
|
||||
)
|
||||
# The two map to different SAP party-wall U-values.
|
||||
assert abs(u_party_wall(4) - 0.5) <= 1e-9
|
||||
assert abs(u_party_wall(0) - 0.25) <= 1e-9
|
||||
|
||||
|
||||
def test_summary_mapper_raises_on_unmapped_glazing_type_label() -> None:
|
||||
# Arrange — same strict-coverage gate as the cylinder-size helper
|
||||
# (Slice S0380.15 + S0380.16): silently routing an unknown glazing
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue