mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
P5.12: align per-end-use primary energy to §11 sketch (per-m²)
P5.9 exposed the four primary-energy components as absolute kWh/yr keys (space_heating_primary_kwh_per_yr, …). HANDOVER_SYSTEMATIC_REVIEW §11 specifies these as `_pe_kwh_per_m2` because primary energy enters the rating equation per floor area. Renamed to match the sketch: - space_heating_pe_kwh_per_m2 - hot_water_pe_kwh_per_m2 - other_pe_kwh_per_m2 - pv_pe_offset_kwh_per_m2 Chain check now verifies max(0, sum − pv_offset) ≈ result.primary_energy_kwh_per_m2 (the top-level per-m² field). Absolute kWh/yr values remain recoverable via tfa_m2 on `intermediate`.
This commit is contained in:
parent
550b1fbcd0
commit
f09e83b6a1
2 changed files with 31 additions and 27 deletions
|
|
@ -380,10 +380,10 @@ def calculate_sap_from_inputs(inputs: CalculatorInputs) -> SapResult:
|
|||
"deflator": ENERGY_COST_DEFLATOR,
|
||||
"delivered_fuel_kwh_per_yr": delivered_fuel_kwh,
|
||||
"co2_factor_kg_per_kwh": inputs.co2_factor_kg_per_kwh,
|
||||
"space_heating_primary_kwh_per_yr": space_heating_primary_kwh,
|
||||
"hot_water_primary_kwh_per_yr": hot_water_primary_kwh,
|
||||
"other_primary_kwh_per_yr": other_primary_kwh,
|
||||
"pv_primary_offset_kwh_per_yr": pv_primary_offset_kwh,
|
||||
"space_heating_pe_kwh_per_m2": space_heating_primary_kwh / tfa if tfa > 0 else 0.0,
|
||||
"hot_water_pe_kwh_per_m2": hot_water_primary_kwh / tfa if tfa > 0 else 0.0,
|
||||
"other_pe_kwh_per_m2": other_primary_kwh / tfa if tfa > 0 else 0.0,
|
||||
"pv_pe_offset_kwh_per_m2": pv_primary_offset_kwh / tfa if tfa > 0 else 0.0,
|
||||
"floor_area_offset_m2": FLOOR_AREA_OFFSET_M2,
|
||||
"ecf_log_threshold": ECF_LOG_THRESHOLD,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -311,41 +311,45 @@ def test_calculate_exposes_co2_chain() -> None:
|
|||
def test_calculate_exposes_primary_energy_breakdown() -> None:
|
||||
# Arrange — P5 trace mode: primary energy splits across three PEFs
|
||||
# (space-heating, hot-water, other) and a PV offset at the other-PEF
|
||||
# (Appendix M). Exposing the four components makes the top-level
|
||||
# primary_energy_kwh_per_yr auditable, including whether the
|
||||
# floor-at-zero was hit when PV exceeded gross primary.
|
||||
# (Appendix M). The §11 sketch in HANDOVER_SYSTEMATIC_REVIEW lists
|
||||
# these as `_kwh_per_m2` because primary energy enters the rating
|
||||
# equation per-floor-area; absolute values are recoverable via tfa_m2.
|
||||
inputs = _baseline_inputs()
|
||||
|
||||
# Act
|
||||
result = calculate_sap_from_inputs(inputs)
|
||||
|
||||
# Assert
|
||||
space_heating_primary = (
|
||||
result.main_heating_fuel_kwh_per_yr + result.secondary_heating_fuel_kwh_per_yr
|
||||
) * inputs.space_heating_primary_factor
|
||||
hot_water_primary = inputs.hot_water_kwh_per_yr * inputs.hot_water_primary_factor
|
||||
other_primary = (
|
||||
inputs.pumps_fans_kwh_per_yr + inputs.lighting_kwh_per_yr
|
||||
) * inputs.other_primary_factor
|
||||
pv_offset = inputs.pv_generation_kwh_per_yr * inputs.other_primary_factor
|
||||
tfa = inputs.dimensions.total_floor_area_m2
|
||||
space_heating_pe = (
|
||||
(result.main_heating_fuel_kwh_per_yr + result.secondary_heating_fuel_kwh_per_yr)
|
||||
* inputs.space_heating_primary_factor
|
||||
/ tfa
|
||||
)
|
||||
hot_water_pe = inputs.hot_water_kwh_per_yr * inputs.hot_water_primary_factor / tfa
|
||||
other_pe = (
|
||||
(inputs.pumps_fans_kwh_per_yr + inputs.lighting_kwh_per_yr)
|
||||
* inputs.other_primary_factor
|
||||
/ tfa
|
||||
)
|
||||
pv_offset_pe = inputs.pv_generation_kwh_per_yr * inputs.other_primary_factor / tfa
|
||||
|
||||
assert result.intermediate["space_heating_primary_kwh_per_yr"] == pytest.approx(
|
||||
space_heating_primary, rel=1e-9
|
||||
assert result.intermediate["space_heating_pe_kwh_per_m2"] == pytest.approx(
|
||||
space_heating_pe, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["hot_water_primary_kwh_per_yr"] == pytest.approx(
|
||||
hot_water_primary, rel=1e-9
|
||||
assert result.intermediate["hot_water_pe_kwh_per_m2"] == pytest.approx(
|
||||
hot_water_pe, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["other_primary_kwh_per_yr"] == pytest.approx(
|
||||
other_primary, rel=1e-9
|
||||
assert result.intermediate["other_pe_kwh_per_m2"] == pytest.approx(other_pe, rel=1e-9)
|
||||
assert result.intermediate["pv_pe_offset_kwh_per_m2"] == pytest.approx(
|
||||
pv_offset_pe, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["pv_primary_offset_kwh_per_yr"] == pytest.approx(
|
||||
pv_offset, rel=1e-9
|
||||
expected_total_per_m2 = max(
|
||||
0.0, space_heating_pe + hot_water_pe + other_pe - pv_offset_pe
|
||||
)
|
||||
expected_total = max(
|
||||
0.0,
|
||||
space_heating_primary + hot_water_primary + other_primary - pv_offset,
|
||||
assert result.primary_energy_kwh_per_m2 == pytest.approx(
|
||||
expected_total_per_m2, rel=1e-9
|
||||
)
|
||||
assert result.primary_energy_kwh_per_yr == pytest.approx(expected_total, rel=1e-9)
|
||||
|
||||
|
||||
def test_calculate_exposes_pv_export_credit() -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue