mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 102f: Layer 4 chain tests for 7-cert ASHP cohort at spec-precision floor
Pins the full API → cert_to_inputs → calculate_sap_from_inputs cascade
for each of the 7 ASHP cohort certs against the Elmhurst dr87
worksheet's continuous SAP. Tolerance is 0.07 (NOT 1e-4 like the
boiler cohort) — see HANDOVER_CERT_0380_MIT_CASCADE.md:
- BRE web confirmed max_output_kw matches cascade (4.39 for
Mitsubishi PCDB 104568, 3.933 for Daikin PCDB 102421).
- Cascade (39) annual HLC matches worksheet at 4 dp exact for
certs 0380, 2225.
- Back-solving worksheet η_space implies ~0.15% drift in
Elmhurst's internal η_space interpolation precision (likely
a vendor rounding convention not in public SAP 10.2 spec).
The 7-cert cohort clusters within +0.030..+0.060 SAP — this is the
spec-precision floor for the publicly-documented cascade.
At rounded (integer SAP) precision, all 7 cascade integers match
the lodged values exactly (residual = 0, pinned in
`_GOLDEN_EXPECTATIONS` per slice 102f-prep.11).
Cohort summary:
0380 88.5698 vs 88.5104 Δ=+0.059 Mitsubishi PUZ-WM50VHA
0350 84.1825 vs 84.1367 Δ=+0.046 Mitsubishi PUZ-WM50VHA
2225 88.8362 vs 88.7921 Δ=+0.044 Mitsubishi PUZ-WM50VHA + PV
2636 86.2964 vs 86.2641 Δ=+0.032 Mitsubishi PUZ-WM50VHA + cantilever
3800 86.1900 vs 86.1458 Δ=+0.044 Mitsubishi PUZ-WM50VHA
9285 84.1871 vs 84.1369 Δ=+0.050 Mitsubishi PUZ-WM50VHA
9418 84.6601 vs 84.6305 Δ=+0.030 Daikin Altherma EDLQ05CAV3 ("24" duration)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
38a5f906bc
commit
c00866607b
1 changed files with 112 additions and 0 deletions
|
|
@ -925,6 +925,118 @@ def test_api_001479_full_chain_sap_matches_worksheet_pdf_exactly() -> None:
|
|||
assert abs(result.sap_score_continuous - worksheet_unrounded_sap) < 1e-4
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Layer 4 chain tests — 7-cert ASHP cohort
|
||||
# ============================================================================
|
||||
# These pin the API → from_api_response → cert_to_inputs →
|
||||
# calculate_sap_from_inputs cascade against each cert's Elmhurst dr87
|
||||
# worksheet unrounded SAP. Tolerance is 0.07 (NOT 1e-4 like the boiler
|
||||
# cohort above) — see HANDOVER_CERT_0380_MIT_CASCADE.md for the
|
||||
# investigation: BRE web confirmed max_output_kw matches cascade
|
||||
# exactly (4.39 / 3.933), cascade (39) annual HLC matches worksheet
|
||||
# at 4 dp, but back-solving worksheet η_space implies ~0.15% drift
|
||||
# in Elmhurst's internal interpolation precision (likely a vendor
|
||||
# rounding convention not in the public SAP 10.2 spec). The 7 certs
|
||||
# cluster within +0.030..+0.060 SAP — this is the spec-precision
|
||||
# floor for the publicly-documented cascade.
|
||||
#
|
||||
# At rounded (integer SAP) precision, all 7 cascade integers match
|
||||
# the lodged values exactly (residual = 0, pinned in
|
||||
# `_GOLDEN_EXPECTATIONS`).
|
||||
|
||||
_API_0350_JSON = (
|
||||
Path(__file__).parents[3]
|
||||
/ "domain/sap10_calculator/rdsap/tests/fixtures/golden"
|
||||
/ "0350-2968-2650-2796-5255.json"
|
||||
)
|
||||
_API_3800_JSON = (
|
||||
Path(__file__).parents[3]
|
||||
/ "domain/sap10_calculator/rdsap/tests/fixtures/golden"
|
||||
/ "3800-8515-0922-3398-3563.json"
|
||||
)
|
||||
_API_9285_JSON = (
|
||||
Path(__file__).parents[3]
|
||||
/ "domain/sap10_calculator/rdsap/tests/fixtures/golden"
|
||||
/ "9285-3062-0205-7766-7200.json"
|
||||
)
|
||||
|
||||
_ASHP_COHORT_CHAIN_TOLERANCE: float = 0.07
|
||||
"""SAP-precision floor for the 7-cert ASHP cohort — see handover."""
|
||||
|
||||
|
||||
def test_api_0380_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568, semi-detached bungalow age D.
|
||||
doc = json.loads(_API_0380_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 88.5104) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_0350_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568.
|
||||
doc = json.loads(_API_0350_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 84.1367) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_2225_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568, with PV. Slice 102f-prep.8
|
||||
# closed the shower_outlets=None default.
|
||||
doc = json.loads(_API_2225_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 88.7921) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_2636_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568, with cantilever + alt wall.
|
||||
# Slice 102f-prep.9 (cantilever) + 102f-prep.10 (alt-wall openings).
|
||||
doc = json.loads(_API_2636_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 86.2641) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_3800_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568.
|
||||
doc = json.loads(_API_3800_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 86.1458) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_9285_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Mitsubishi PUZ-WM50VHA PCDB 104568.
|
||||
doc = json.loads(_API_9285_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 84.1369) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_api_9418_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Daikin Altherma EDLQ05CAV3 PCDB 102421, heating_duration_code='24'
|
||||
# (continuous, all days at Th). Slice 102f-prep.7 closed Table N4.
|
||||
doc = json.loads(_API_9418_JSON.read_text())
|
||||
epc = EpcPropertyDataMapper.from_api_response(doc)
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
assert abs(result.sap_score_continuous - 84.6305) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Mapper-vs-hand-built EpcPropertyData diff tests
|
||||
# ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue