mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
P5.9: SapResult.intermediate exposes primary-energy breakdown
Lifts the inlined primary-energy sum into four named components: space-heating (main + secondary × space_heating PEF), hot water, other (pumps_fans + lighting × other PEF), and the PV offset at other PEF (Appendix M). Together with the top-level primary_energy_kwh_per_yr they make whether the floor-at-zero clipped visible.
This commit is contained in:
parent
537e18bc2e
commit
3d56898944
2 changed files with 56 additions and 8 deletions
|
|
@ -328,19 +328,23 @@ def calculate_sap_from_inputs(inputs: CalculatorInputs) -> SapResult:
|
|||
sap_cont = sap_rating(ecf=ecf)
|
||||
co2 = delivered_fuel_kwh * inputs.co2_factor_kg_per_kwh
|
||||
|
||||
primary_energy_kwh = (
|
||||
main_fuel_kwh * inputs.space_heating_primary_factor
|
||||
+ secondary_fuel_kwh * inputs.space_heating_primary_factor
|
||||
+ inputs.hot_water_kwh_per_yr * inputs.hot_water_primary_factor
|
||||
+ (inputs.pumps_fans_kwh_per_yr + inputs.lighting_kwh_per_yr)
|
||||
* inputs.other_primary_factor
|
||||
)
|
||||
space_heating_primary_kwh = (
|
||||
main_fuel_kwh + secondary_fuel_kwh
|
||||
) * inputs.space_heating_primary_factor
|
||||
hot_water_primary_kwh = inputs.hot_water_kwh_per_yr * inputs.hot_water_primary_factor
|
||||
other_primary_kwh = (
|
||||
inputs.pumps_fans_kwh_per_yr + inputs.lighting_kwh_per_yr
|
||||
) * inputs.other_primary_factor
|
||||
# PV offsets primary energy at the same PEF (Appendix M: export PEF =
|
||||
# standard-electricity PEF for ratings, since the displaced grid kWh
|
||||
# would have been imported electricity).
|
||||
pv_primary_offset_kwh = inputs.pv_generation_kwh_per_yr * inputs.other_primary_factor
|
||||
primary_energy_kwh = max(
|
||||
0.0,
|
||||
primary_energy_kwh - inputs.pv_generation_kwh_per_yr * inputs.other_primary_factor,
|
||||
space_heating_primary_kwh
|
||||
+ hot_water_primary_kwh
|
||||
+ other_primary_kwh
|
||||
- pv_primary_offset_kwh,
|
||||
)
|
||||
primary_energy_per_m2 = primary_energy_kwh / tfa if tfa > 0 else 0.0
|
||||
|
||||
|
|
@ -373,6 +377,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,
|
||||
}
|
||||
|
||||
return SapResult(
|
||||
|
|
|
|||
|
|
@ -308,6 +308,46 @@ def test_calculate_exposes_co2_chain() -> None:
|
|||
) == pytest.approx(result.co2_kg_per_yr, rel=1e-9)
|
||||
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
assert result.intermediate["space_heating_primary_kwh_per_yr"] == pytest.approx(
|
||||
space_heating_primary, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["hot_water_primary_kwh_per_yr"] == pytest.approx(
|
||||
hot_water_primary, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["other_primary_kwh_per_yr"] == pytest.approx(
|
||||
other_primary, rel=1e-9
|
||||
)
|
||||
assert result.intermediate["pv_primary_offset_kwh_per_yr"] == pytest.approx(
|
||||
pv_offset, rel=1e-9
|
||||
)
|
||||
expected_total = max(
|
||||
0.0,
|
||||
space_heating_primary + hot_water_primary + other_primary - pv_offset,
|
||||
)
|
||||
assert result.primary_energy_kwh_per_yr == pytest.approx(expected_total, rel=1e-9)
|
||||
|
||||
|
||||
def test_higher_main_heating_efficiency_reduces_fuel_use() -> None:
|
||||
# Arrange — Direction check: doubling the boiler efficiency must halve
|
||||
# the main-heating fuel kWh, holding everything else constant.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue