mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Merge pull request #519 from Hestia-Homes/eco-eligiblity-bug
Eco eligiblity bug
This commit is contained in:
commit
cfa49fe3d0
7 changed files with 781 additions and 616 deletions
|
|
@ -418,7 +418,20 @@ class SearchEpc:
|
|||
address, [", ".join([r["address"]]) for r in rows], score_cutoff=0
|
||||
)
|
||||
# Pick the largest score
|
||||
if best_match1[1] >= best_match2[1]:
|
||||
if best_match1[1] == best_match2[1]:
|
||||
# if thery're the same, we'll work under the assumption that the addresses are the same and we'll
|
||||
# take whichever has the newest EPC
|
||||
rows_filtered = [
|
||||
r for r in rows
|
||||
if (", ".join([r["address"], r["posttown"]]) == best_match1[0]) or
|
||||
(r["address"] == best_match2[0])
|
||||
]
|
||||
rows_filtered = [
|
||||
r for r in rows_filtered
|
||||
if r["lodgement-datetime"] == max([x["lodgement-datetime"] for x in rows_filtered])
|
||||
]
|
||||
|
||||
elif best_match1[1] > best_match2[1]:
|
||||
# Get all of the scores
|
||||
rows_filtered = [r for r in rows if ", ".join([r["address"], r["posttown"]]) == best_match1[0]]
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ innovation_scenarios = [
|
|||
# 1) Innovation PV, non-eligible heating system in place, EPC D - not eligible
|
||||
{
|
||||
"description": "Innovation PV, non-eligible heating system in place, EPC D",
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}],
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Electric storage heaters",
|
||||
"heating_control_description": "Manual charge control",
|
||||
|
|
@ -16,7 +16,7 @@ innovation_scenarios = [
|
|||
# 2) Innovation PV, eligible heating system in place, EPC D - eligible
|
||||
{
|
||||
"description": "Innovation PV, eligible heating system in place, EPC D",
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}],
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
"heating_control_description": "Programmer, room thermostat and TRVs",
|
||||
|
|
@ -29,8 +29,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV + HHRSH upgrade, EPC E",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": True, "uplift": 0.1}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": False, "innovation_uplift": 0}
|
||||
],
|
||||
"starting_sap": 50,
|
||||
"mainheat_description": "Electric storage heaters",
|
||||
|
|
@ -44,8 +44,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV + HHRSH upgrade, EPC E",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": True, "uplift": 0.1}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": False, "innovation_uplift": 0}
|
||||
],
|
||||
"starting_sap": 50,
|
||||
"mainheat_description": "Electric storage heaters",
|
||||
|
|
@ -58,7 +58,7 @@ innovation_scenarios = [
|
|||
# 5) Innovation PV, needs wall insulation, no wall insulation measure - not eligible
|
||||
{
|
||||
"description": "Innovation PV, wall insulation recommended, but not installed",
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}],
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
"heating_control_description": "Programmer, room thermostat and TRVs",
|
||||
|
|
@ -71,8 +71,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV, wall insulation recommended and installed",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0.25}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0.25}
|
||||
],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
|
|
@ -85,7 +85,7 @@ innovation_scenarios = [
|
|||
# 7) Innovation PV, needs roof insulation, no roof insulation measure - not eligible
|
||||
{
|
||||
"description": "Innovation PV, roof insulation recommended, not installed",
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}],
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
"heating_control_description": "Programmer, room thermostat and TRVs",
|
||||
|
|
@ -98,8 +98,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV, roof insulation recommended and installed",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0}
|
||||
],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
|
|
@ -112,7 +112,7 @@ innovation_scenarios = [
|
|||
# 9) Innovation PV, needs both roof + wall insulation, no insulation - not eligible
|
||||
{
|
||||
"description": "Innovation PV, both insulations recommended, none installed",
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}],
|
||||
"measures": [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
"heating_control_description": "Programmer, room thermostat and TRVs",
|
||||
|
|
@ -125,8 +125,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV, both insulations recommended, only wall done",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0.25}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0.25}
|
||||
],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
|
|
@ -140,8 +140,8 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV, both insulations recommended, only roof done",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0}
|
||||
],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
|
|
@ -155,9 +155,9 @@ innovation_scenarios = [
|
|||
{
|
||||
"description": "Innovation PV, both insulations recommended and installed",
|
||||
"measures": [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0.25},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0.25},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0}
|
||||
],
|
||||
"starting_sap": 60,
|
||||
"mainheat_description": "Air source heat pump, radiators",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ def test_eco4_prs_eligible_with_swi(
|
|||
# 3) is getting a solid was measure
|
||||
# so it's eligible for ECO4
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=50, # EPC E
|
||||
|
|
@ -162,7 +162,7 @@ def test_eco4_prs_not_eligible_high_epc(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=72, # EPC C (too high)
|
||||
|
|
@ -203,7 +203,7 @@ def test_gbis_prs_general_eligibility(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=65, # EPC D
|
||||
|
|
@ -244,7 +244,7 @@ def test_gbis_prs_low_income_caveat(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "cavity_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "cavity_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -290,7 +290,7 @@ def test_eco4_sh_epc_e_eligible(
|
|||
tenure="Social",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=50, # EPC E
|
||||
|
|
@ -330,7 +330,7 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
tenure="Social",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -365,7 +365,7 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
gbis_private_solid_abs_rate=28,
|
||||
tenure="Social",
|
||||
)
|
||||
measures2 = [{"type": "internal_wall_insulation", "is_innovation": True, "uplift": 0.25}]
|
||||
measures2 = [{"type": "internal_wall_insulation", "is_innovation": True, "innovation_uplift": 0.25}]
|
||||
funding2.check_funding(
|
||||
measures=measures2,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -403,7 +403,7 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
gbis_private_solid_abs_rate=28,
|
||||
tenure="Social",
|
||||
)
|
||||
measures3 = [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}]
|
||||
measures3 = [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}]
|
||||
funding3.check_funding(
|
||||
measures=measures3,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -439,7 +439,7 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
tenure="Social",
|
||||
)
|
||||
|
||||
measures4 = [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}, ]
|
||||
measures4 = [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}, ]
|
||||
funding4.check_funding(
|
||||
measures=measures4,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -476,8 +476,8 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
)
|
||||
|
||||
measures5 = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "high_heat_retention_storage_heater", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
funding5.check_funding(
|
||||
measures=measures5,
|
||||
|
|
@ -516,7 +516,7 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
)
|
||||
|
||||
measures6 = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
]
|
||||
funding6.check_funding(
|
||||
measures=measures6,
|
||||
|
|
@ -556,9 +556,9 @@ def test_eco4_sh_epc_d_requires_innovation(
|
|||
tenure="Social",
|
||||
)
|
||||
measures7 = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "uplift": 0.25},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "innovation_uplift": 0.25},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
funding7.check_funding(
|
||||
measures=measures7,
|
||||
|
|
@ -599,7 +599,7 @@ def test_eco4_sh_solar_pv_requires_heating(
|
|||
tenure="Social",
|
||||
)
|
||||
|
||||
measures = [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}]
|
||||
measures = [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=60, # EPC D
|
||||
|
|
@ -641,8 +641,8 @@ def test_eco4_sh_solar_pv_with_heating_is_ok(
|
|||
)
|
||||
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
|
|
@ -684,7 +684,7 @@ def test_eco4_upgrade_requirement_e_to_c_pass(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
|
||||
# E (SAP 50) → C (SAP 70) meets upgrade rule
|
||||
funding.check_funding(
|
||||
|
|
@ -727,7 +727,7 @@ def test_eco4_upgrade_requirement_e_to_d_fail(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
|
||||
# E (SAP 50) → D (SAP 65) does NOT meet ECO4 upgrade rule
|
||||
funding.check_funding(
|
||||
|
|
@ -770,7 +770,7 @@ def test_eco4_upgrade_requirement_f_to_d_pass(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
|
||||
# F (SAP 35) → D (SAP 60) is OK for ECO4
|
||||
funding.check_funding(
|
||||
|
|
@ -813,7 +813,7 @@ def test_eco4_upgrade_requirement_f_to_e_fail(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0}]
|
||||
measures = [{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0}]
|
||||
|
||||
# F (SAP 35) → E (SAP 50) does NOT meet ECO4 rule
|
||||
funding.check_funding(
|
||||
|
|
@ -859,7 +859,7 @@ def test_epc_d_social_no_innovation_no_heating(
|
|||
)
|
||||
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -905,10 +905,10 @@ def test_epc_d_social_with_heating_and_insulation(
|
|||
|
||||
# Should NOT be eligible as the ASHP is not an innovation measure
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -954,9 +954,9 @@ def test_epc_d_social_solar_with_only_minimum_insulation_should_fail(
|
|||
|
||||
# Solar PV innovation with insulation, but no heating system upgrade => not eligible
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -1002,8 +1002,8 @@ def test_epc_d_social_solar_with_ashp_and_no_insulation_should_fail(
|
|||
|
||||
# Solar PV innovation with heating, but no insulation when insulation is recommended => not eligible
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -1050,10 +1050,10 @@ def test_epc_d_social_solar_with_heating_and_minimum_insulation_should_pass(
|
|||
# Innovation solar + insulation measures + eligible heating upgrade = not valid because the heat pump isn;t
|
||||
# an innovation measure
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0}
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -1095,10 +1095,10 @@ def test_epc_d_social_solar_with_heating_and_minimum_insulation_should_pass(
|
|||
# Innovation solar + insulation measures + eligible heating upgrade = should be valid because the
|
||||
# heat pump is an innovation measure
|
||||
measures2 = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": True, "uplift": 0.25}
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": True, "innovation_uplift": 0.25}
|
||||
]
|
||||
|
||||
funding2.check_funding(
|
||||
|
|
@ -1203,11 +1203,11 @@ def test_uplift(
|
|||
# # TODO: Add a scenario with multiple measures, where some are innovation, some are not and we have
|
||||
# TODO: Make sure private works too
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "uplift": 0.25},
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "internal_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "innovation_uplift": 0.25},
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
@ -1229,7 +1229,7 @@ def test_uplift(
|
|||
)
|
||||
|
||||
assert funding.eco4_funding == 5302.3949999999995
|
||||
assert funding.full_project_abs == 392.77 # is 280 + the 112.77 innovation uplift
|
||||
assert funding.full_project_abs == 280 # Doesn't include the eco4 uplift
|
||||
assert funding.eco4_uplift == 112.77
|
||||
|
||||
|
||||
|
|
@ -1311,7 +1311,7 @@ def test_private_epc_e_solar_needs_heating(
|
|||
tenure="Private",
|
||||
)
|
||||
|
||||
measures = [{"type": "solar_pv", "is_innovation": True, "uplift": 0.45}]
|
||||
measures = [{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45}]
|
||||
funding.check_funding(
|
||||
measures=measures,
|
||||
starting_sap=54, # EPC E - eligible for private on EPC
|
||||
|
|
@ -1360,10 +1360,10 @@ def test_private_epc_e_solar_with_heating_and_minimum_insulation_produces_uplift
|
|||
)
|
||||
|
||||
measures = [
|
||||
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
|
||||
{"type": "solar_pv", "is_innovation": True, "innovation_uplift": 0.45},
|
||||
{"type": "air_source_heat_pump", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "cavity_wall_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
{"type": "loft_insulation", "is_innovation": False, "innovation_uplift": 0},
|
||||
]
|
||||
|
||||
funding.check_funding(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,7 +26,7 @@ class TestSearchEpcIntegration:
|
|||
# Test case 2: Another valid address and postcode
|
||||
# In this case, the newest EPC, does not have a uprn associated to it. If we did a search by
|
||||
# uprn, we would get an old EPC
|
||||
("Flat 8, Hainton House", "DN32 9AQ", 10090082018, True,
|
||||
("Flat 8, Hainton House", "DN32 9AQ", "", True,
|
||||
"bd1149a20a73397184f07a9955f872424826e70f4870c058d71be887766ee1f8", 2),
|
||||
# Test case 3: When we make a request to the API for this property, we get back results for
|
||||
# flats 1, 2 and 3. We have some logic to handle the response so that we get back flat 1
|
||||
|
|
@ -56,7 +56,6 @@ class TestSearchEpcIntegration:
|
|||
|
||||
# We check that we have the correct epc
|
||||
assert epc_searcher.newest_epc["lmk-key"] == lmk_key
|
||||
assert epc_searcher.newest_epc["uprn"] == uprn
|
||||
assert len(epc_searcher.older_epcs) == n_old_epcs
|
||||
|
||||
def test_search_housenumber(self):
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ class TestPrepareInputMeasures:
|
|||
recs = [
|
||||
[ # loft insulation measure
|
||||
{"recommendation_id": "loft1", "type": "loft_insulation", "total": 100, "kwh_savings": 200,
|
||||
"energy_cost_savings": 10, "has_battery": False, "measure_type": "loft_insulation"},
|
||||
"energy_cost_savings": 10, "has_battery": False, "measure_type": "loft_insulation",
|
||||
"partial_project_funding": 0, "partial_project_score": 0,
|
||||
"uplift_project_score": 0,
|
||||
},
|
||||
],
|
||||
]
|
||||
measures = optimiser_functions.prepare_input_measures(recs, goal="Energy Savings", needs_ventilation=False)
|
||||
|
|
@ -27,9 +30,12 @@ class TestPrepareInputMeasures:
|
|||
["internal_wall_insulation"])
|
||||
recs = [
|
||||
[{"recommendation_id": "wall1", "type": "internal_wall_insulation", "total": 500, "kwh_savings": 300,
|
||||
"energy_cost_savings": 5, "has_battery": False, "measure_type": "internal_wall_insulation"}],
|
||||
"energy_cost_savings": 5, "has_battery": False, "measure_type": "internal_wall_insulation",
|
||||
"partial_project_funding": 0, "partial_project_score": 0, "uplift_project_score": 0,
|
||||
}],
|
||||
[{"recommendation_id": "vent1", "type": "mechanical_ventilation", "total": 50, "kwh_savings": 30,
|
||||
"energy_cost_savings": 5, "has_battery": False, "measure_type": "mechanical_ventilation"}],
|
||||
"energy_cost_savings": 5, "has_battery": False, "measure_type": "mechanical_ventilation",
|
||||
"partial_project_funding": 0, "partial_project_score": 0, "uplift_project_score": 0, }],
|
||||
]
|
||||
measures = optimiser_functions.prepare_input_measures(recs, goal="Energy Savings", needs_ventilation=True)
|
||||
wall_option = measures[0][0]
|
||||
|
|
@ -40,7 +46,8 @@ class TestPrepareInputMeasures:
|
|||
def test_filters_out_negative_cost_savings(self):
|
||||
recs = [
|
||||
[{"recommendation_id": "bad1", "type": "loft_insulation", "total": 200, "kwh_savings": 100,
|
||||
"energy_cost_savings": -5, "has_battery": False}],
|
||||
"energy_cost_savings": -5, "has_battery": False,
|
||||
"partial_project_funding": 0, "partial_project_score": 0, "uplift_project_score": 0, }],
|
||||
]
|
||||
measures = optimiser_functions.prepare_input_measures(recs, goal="Energy Savings", needs_ventilation=False)
|
||||
assert measures == [] # should skip negative cost saving recs
|
||||
|
|
@ -149,14 +156,14 @@ class TestIncreasingEpcE2e:
|
|||
|
||||
@pytest.fixture
|
||||
def setup_case(self):
|
||||
# ✅ Dummy property object
|
||||
# Dummy property object
|
||||
p = SimpleNamespace(
|
||||
id="P1",
|
||||
has_ventilation=False,
|
||||
data={"current-energy-efficiency": "52"},
|
||||
)
|
||||
|
||||
# ✅ Dummy request body
|
||||
# Dummy request body
|
||||
body = SimpleNamespace(
|
||||
goal="Increasing EPC",
|
||||
goal_value="C",
|
||||
|
|
@ -165,9 +172,6 @@ class TestIncreasingEpcE2e:
|
|||
simulate_sap_10=False,
|
||||
required_measures=[]
|
||||
)
|
||||
|
||||
# ✅ Use your massive measures_to_optimise list
|
||||
|
||||
recommendations = {"P1": measures_to_optimise}
|
||||
|
||||
return p, body, recommendations
|
||||
|
|
@ -190,6 +194,18 @@ class TestIncreasingEpcE2e:
|
|||
|
||||
assert needs_ventilation
|
||||
|
||||
# Input the various things we need - set all to 0
|
||||
for group in measures_to_optimise:
|
||||
for r in group:
|
||||
(
|
||||
r["partial_project_score"],
|
||||
r["partial_project_funding"],
|
||||
r["innovation_uplift"],
|
||||
r["uplift_project_score"],
|
||||
) = (
|
||||
0, 0, 0, 0
|
||||
)
|
||||
|
||||
input_measures = optimiser_functions.prepare_input_measures(measures_to_optimise, body.goal, needs_ventilation)
|
||||
|
||||
assert input_measures, "Expected measures to optimise"
|
||||
|
|
|
|||
|
|
@ -144,6 +144,15 @@ class DummyProp:
|
|||
self.has_ventilation = False
|
||||
self.floor_area = 70.0
|
||||
self.main_heating_controls = {"clean_description": "time and temperature zone control"}
|
||||
self.walls = {'original_description': 'Solid brick, as built, no insulation (assumed)',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None, 'is_cavity_wall': False, 'is_filled_cavity': False,
|
||||
'is_solid_brick': True,
|
||||
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
|
||||
'is_as_built': True,
|
||||
'is_cob': False, 'is_assumed': True, 'is_sandstone_or_limestone': False,
|
||||
'insulation_thickness': 'none',
|
||||
'external_insulation': False, 'internal_insulation': False}
|
||||
|
||||
self.main_heating = {
|
||||
'original_description': 'Boiler and radiators, mains gas',
|
||||
|
|
@ -230,6 +239,7 @@ def property_recommendations():
|
|||
'quantity_unit': 'm2', 'total': 19090.810139104888,
|
||||
'labour_hours': 0.0, 'labour_days': 0.0}],
|
||||
'type': 'external_wall_insulation', 'measure_type': 'external_wall_insulation',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install 150mm EWI Pro EPS external wall insulation system with Brick '
|
||||
'Slip finish on external walls',
|
||||
'starting_u_value': 1.7, 'new_u_value': 0.32, 'already_installed': False,
|
||||
|
|
@ -258,6 +268,7 @@ def property_recommendations():
|
|||
'quantity_unit': 'm2', 'total': 5694.929118083911, 'labour_hours': 134.37473199973275,
|
||||
'labour_days': 4.199210374991648}], 'type': 'internal_wall_insulation',
|
||||
'measure_type': 'internal_wall_insulation',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install 95mm '
|
||||
'SWIP EcoBatt & '
|
||||
'Plastered '
|
||||
|
|
@ -314,6 +325,7 @@ def property_recommendations():
|
|||
'quantity_unit': 'm2', 'total': 645.0, 'labour_hours': 8,
|
||||
'labour_days': 1}], 'type': 'loft_insulation',
|
||||
'measure_type': 'loft_insulation',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install 300mm of Knauf Loft Roll 44 glass fibre roll in your loft',
|
||||
'starting_u_value': 2.3, 'new_u_value': 2.3, 'sap_points': np.float64(2.4),
|
||||
'already_installed': False,
|
||||
|
|
@ -338,6 +350,7 @@ def property_recommendations():
|
|||
'plant_cost': 0.0, 'total_cost': 350.0, 'notes': None, 'is_installer_quote': True, 'total': 700.0,
|
||||
'quantity': 2,
|
||||
'quantity_unit': 'part'}], 'type': 'mechanical_ventilation', 'measure_type': 'mechanical_ventilation',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install 2 '
|
||||
'Mechanical '
|
||||
'Extract '
|
||||
|
|
@ -387,6 +400,7 @@ def property_recommendations():
|
|||
'labour_hours': 70.08999999999999,
|
||||
'labour_days': 2.920416666666666}],
|
||||
'type': 'suspended_floor_insulation', 'measure_type': 'suspended_floor_insulation',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install 75mm Q-bot underfloor insulation insulation in suspended '
|
||||
'floor',
|
||||
'starting_u_value': 0.83, 'new_u_value': 0.22, 'sap_points': 2, 'survey': True,
|
||||
|
|
@ -401,6 +415,7 @@ def property_recommendations():
|
|||
'energy_cost_savings': np.float64(76.04936470588231)}], [
|
||||
{'phase': 4, 'parts': [], 'type': 'low_energy_lighting',
|
||||
'measure_type': 'low_energy_lighting',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install low energy lighting in -886 outlets', 'starting_u_value': None,
|
||||
'new_u_value': None, 'already_installed': False, 'sap_points': 2,
|
||||
'kwh_savings': -48508.5, 'energy_cost_savings': -12481.237049999998,
|
||||
|
|
@ -413,6 +428,7 @@ def property_recommendations():
|
|||
'recommendation_id': '5_phase=4', 'efficiency': -1705.5500000000002,
|
||||
'heat_demand': np.float64(5.099999999999994)}], [
|
||||
{'type': 'heating', 'phase': 5, 'measure_type': 'time_temperature_zone_control',
|
||||
"innovation_rate": 0,
|
||||
'parts': [],
|
||||
'description': 'Upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control)',
|
||||
|
|
@ -431,6 +447,7 @@ def property_recommendations():
|
|||
'energy_cost_savings': np.float64(65.29581176470589)}], [
|
||||
{'phase': 6, 'parts': [], 'type': 'secondary_heating',
|
||||
'measure_type': 'secondary_heating',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Remove the secondary heating system', 'starting_u_value': None,
|
||||
'new_u_value': None, 'sap_points': np.float64(3.6), 'already_installed': False,
|
||||
'total': 30.0, 'subtotal': 25.0, 'vat': 5.0, 'labour_hours': 3.0,
|
||||
|
|
@ -443,6 +460,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(196.29999999999927),
|
||||
'energy_cost_savings': np.float64(14.61857647058821)}], [
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 4.0 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(13.0),
|
||||
'already_installed': False, 'total': 6013.139999999999, 'subtotal': 5010.95, 'vat': 0,
|
||||
|
|
@ -455,6 +473,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(2040.8566307499998),
|
||||
'energy_cost_savings': np.float64(525.1124110919749)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 4.0 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(13.0),
|
||||
'already_installed': False, 'total': 10537.008, 'subtotal': 8780.84, 'vat': 0,
|
||||
|
|
@ -467,6 +486,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(2857.1992830499994),
|
||||
'energy_cost_savings': np.float64(735.1573755287648)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 3.6 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(12.0),
|
||||
'already_installed': False, 'total': 5826.491999999999, 'subtotal': 4855.41, 'vat': 0,
|
||||
|
|
@ -478,6 +498,7 @@ def property_recommendations():
|
|||
'heat_demand': np.float64(83.69999999999999), 'kwh_savings': np.float64(1846.33397),
|
||||
'energy_cost_savings': np.float64(475.0617304809999)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 3.6 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(12.0),
|
||||
'already_installed': False, 'total': 10350.359999999999, 'subtotal': 8625.3, 'vat': 0,
|
||||
|
|
@ -489,6 +510,7 @@ def property_recommendations():
|
|||
'heat_demand': np.float64(83.69999999999999), 'kwh_savings': np.float64(2584.867558),
|
||||
'energy_cost_savings': np.float64(665.0864226734)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 3.2 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(11.0),
|
||||
'already_installed': False, 'total': 5642.604, 'subtotal': 4702.17, 'vat': 0,
|
||||
|
|
@ -500,6 +522,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(1650.2708274),
|
||||
'energy_cost_savings': np.float64(424.61468389001993)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 3.2 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(11.0),
|
||||
'already_installed': False, 'total': 10166.472, 'subtotal': 8472.06, 'vat': 0,
|
||||
|
|
@ -511,6 +534,7 @@ def property_recommendations():
|
|||
'heat_demand': np.float64(78.3), 'kwh_savings': np.float64(2310.3791583599996),
|
||||
'energy_cost_savings': np.float64(594.4605574460278)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.8 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(9.0),
|
||||
'already_installed': False, 'total': 5458.727999999999, 'subtotal': 4548.94, 'vat': 0,
|
||||
|
|
@ -522,6 +546,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(1453.5933906),
|
||||
'energy_cost_savings': np.float64(374.00957940138)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.8 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(9.0),
|
||||
'already_installed': False, 'total': 9982.596, 'subtotal': 8318.83, 'vat': 0,
|
||||
|
|
@ -533,6 +558,7 @@ def property_recommendations():
|
|||
'heat_demand': np.float64(64.0), 'kwh_savings': np.float64(2035.03074684),
|
||||
'energy_cost_savings': np.float64(523.6134111619319)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.4 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(8.0),
|
||||
'already_installed': False, 'total': 5274.852, 'subtotal': 4395.71, 'vat': 0,
|
||||
|
|
@ -544,6 +570,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(1255.12594),
|
||||
'energy_cost_savings': np.float64(322.94390436199996)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.4 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(8.0),
|
||||
'already_installed': False, 'total': 9798.72, 'subtotal': 8165.6, 'vat': 0,
|
||||
|
|
@ -555,6 +582,7 @@ def property_recommendations():
|
|||
'heat_demand': np.float64(54.3), 'kwh_savings': np.float64(1757.1763159999998),
|
||||
'energy_cost_savings': np.float64(452.1214661067999)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.0 kilowatt-peak (kWp) solar panel system.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(7.0),
|
||||
'already_installed': False, 'total': 5090.976, 'subtotal': 4242.48, 'vat': 0,
|
||||
|
|
@ -566,6 +594,7 @@ def property_recommendations():
|
|||
'kwh_savings': np.float64(1048.341318),
|
||||
'energy_cost_savings': np.float64(269.7382211214)},
|
||||
{'phase': 7, 'parts': [], 'type': 'solar_pv', 'measure_type': 'solar_pv',
|
||||
"innovation_rate": 0,
|
||||
'description': 'Install a 2.0 kilowatt-peak (kWp) solar panel system, with a battery.',
|
||||
'starting_u_value': None, 'new_u_value': None, 'sap_points': np.float64(7.0),
|
||||
'already_installed': False, 'total': 9614.844, 'subtotal': 8012.369999999999, 'vat': 0,
|
||||
|
|
@ -586,10 +615,20 @@ def _attach_costs_and_uplifts(recs, funding, p):
|
|||
for group in out:
|
||||
for r in group:
|
||||
if r["type"] in ["mechanical_ventilation", "low_energy_lighting", "secondary_heating"]:
|
||||
r["innovation_uplift"] = 0
|
||||
(
|
||||
r["partial_project_score"],
|
||||
r["partial_project_funding"],
|
||||
r["innovation_uplift"],
|
||||
r["uplift_project_score"],
|
||||
) = (
|
||||
0, 0, 0, 0
|
||||
)
|
||||
continue
|
||||
r["uplift"] = 0.0 # fixed for determinism in test
|
||||
r["innovation_uplift"] = funding.get_innovation_uplift(
|
||||
|
||||
(
|
||||
r["partial_project_score"], r["partial_project_funding"], r["innovation_uplift"],
|
||||
r["uplift_project_score"]
|
||||
) = funding.get_innovation_uplift(
|
||||
measure=r,
|
||||
starting_sap=55,
|
||||
floor_area=70.0,
|
||||
|
|
@ -663,3 +702,100 @@ def test_social_fabric_only_returns_only_fabric_types(p, funding, property_recom
|
|||
unfunded_rows = solutions[
|
||||
solutions["path"].apply(lambda x: isinstance(x, dict) and x.get("reference") == "unfunded:all")]
|
||||
assert not unfunded_rows.empty
|
||||
|
||||
|
||||
def test_private_solid_wall_no_innovation_epc_d(p, funding, mock_project_scores_matrix, mock_partial_scores_matrix):
|
||||
"""
|
||||
We have a specific test for this case which was implemented incorrectly originally.
|
||||
This is an EPC D property and so shouldn't be eligible for ECO4. Instead, only GBIS should be considered.
|
||||
"""
|
||||
|
||||
# Overwrite the data - copied from real example
|
||||
p2 = deepcopy(p)
|
||||
p2.data = {
|
||||
"current-energy-rating": "D",
|
||||
"current-energy-efficiency": 68,
|
||||
"mainheat-energy-eff": "Good",
|
||||
}
|
||||
p2.walls = {'original_description': 'Sandstone or limestone, as built, no insulation (assumed)',
|
||||
'clean_description': 'Sandstone or limestone, as built, no insulation', 'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None, 'is_cavity_wall': False, 'is_filled_cavity': False,
|
||||
'is_solid_brick': False, 'is_system_built': False, 'is_timber_frame': False,
|
||||
'is_granite_or_whinstone': False, 'is_as_built': True, 'is_cob': False, 'is_assumed': True,
|
||||
'is_sandstone_or_limestone': True, 'is_park_home': False, 'insulation_thickness': 'none',
|
||||
'external_insulation': False, 'internal_insulation': False}
|
||||
|
||||
funding2 = Funding(
|
||||
tenure="Private",
|
||||
project_scores_matrix=mock_project_scores_matrix,
|
||||
partial_project_scores_matrix=mock_partial_scores_matrix,
|
||||
whlg_eligible_postcodes=pd.DataFrame([{"Postcode": "ab12cd"}]),
|
||||
eco4_social_cavity_abs_rate=12.5,
|
||||
eco4_social_solid_abs_rate=17,
|
||||
eco4_private_cavity_abs_rate=12.5,
|
||||
eco4_private_solid_abs_rate=17,
|
||||
gbis_social_cavity_abs_rate=21,
|
||||
gbis_social_solid_abs_rate=25,
|
||||
gbis_private_cavity_abs_rate=21,
|
||||
gbis_private_solid_abs_rate=28,
|
||||
)
|
||||
|
||||
input_measures = [
|
||||
[{'id': '0_phase=0', 'cost': np.float64(4441.202499013676), 'gain': np.float64(3.4000000000000057),
|
||||
'type': 'internal_wall_insulation+mechanical_ventilation', 'innovation_uplift': np.float64(0.0),
|
||||
'cost_minus_uplift': np.float64(4441.202499013676), 'raw_cost': 3881.2024990136756,
|
||||
'partial_project_funding': np.float64(2300.1000000000004), 'partial_project_score': np.float64(135.3),
|
||||
'uplift_project_score': np.float64(0.0)}], [
|
||||
{'id': '2_phase=2', 'cost': np.float64(2280.0), 'gain': np.float64(0.4), 'type': 'secondary_glazing',
|
||||
'innovation_uplift': np.float64(0.0), 'cost_minus_uplift': np.float64(2280.0),
|
||||
'raw_cost': np.float64(2280.0), 'partial_project_funding': np.float64(1421.1999999999998),
|
||||
'partial_project_score': np.float64(83.6), 'uplift_project_score': np.float64(0.0)}], [
|
||||
{'id': '3_phase=3', 'cost': np.float64(604.5840000000001), 'gain': np.float64(1.2),
|
||||
'type': 'time_temperature_zone_control', 'innovation_uplift': np.float64(0.0),
|
||||
'cost_minus_uplift': np.float64(604.5840000000001), 'raw_cost': 604.5840000000001,
|
||||
'partial_project_funding': np.float64(702.0999999999999), 'partial_project_score': np.float64(41.3),
|
||||
'uplift_project_score': np.float64(0.0)}], [
|
||||
{'id': '4_phase=4', 'cost': 60.0, 'gain': np.float64(0.0), 'type': 'secondary_heating',
|
||||
'innovation_uplift': 0, 'cost_minus_uplift': 60.0, 'raw_cost': 60.0, 'partial_project_funding': 0,
|
||||
'partial_project_score': 0, 'uplift_project_score': 0}]
|
||||
]
|
||||
|
||||
solutions = optimise_with_funding_paths(
|
||||
p=p2,
|
||||
input_measures=input_measures,
|
||||
housing_type="Private",
|
||||
budget=None,
|
||||
target_gain=1.5,
|
||||
funding=funding2
|
||||
)
|
||||
|
||||
# 3) basic shape assertions
|
||||
assert isinstance(solutions, pd.DataFrame)
|
||||
assert not solutions.empty
|
||||
|
||||
# We should have 2 rows
|
||||
assert solutions.shape[0] == 2
|
||||
|
||||
# We should only have None or GBIS
|
||||
assert set(solutions["scheme"].unique()) == {"none", "gbis"}
|
||||
|
||||
meets_upgrade_gbis = solutions[solutions["meets_upgrade_target"] & solutions["is_eligible"]]
|
||||
assert meets_upgrade_gbis.shape[0] == 1
|
||||
|
||||
# Check exact result
|
||||
assert meets_upgrade_gbis.squeeze().to_dict() == {
|
||||
'fixed_ids': ['0_phase=0'], 'items': [
|
||||
{'id': '0_phase=0', 'cost': 3881.2024990136756, 'gain': np.float64(3.4000000000000057),
|
||||
'type': 'internal_wall_insulation+mechanical_ventilation', 'innovation_uplift': np.float64(0.0),
|
||||
'cost_minus_uplift': np.float64(4441.202499013676), 'raw_cost': 3881.2024990136756,
|
||||
'partial_project_funding': np.float64(2300.1000000000004), 'partial_project_score': np.float64(135.3),
|
||||
'uplift_project_score': np.float64(0.0)}], 'total_cost': 3881.2024990136756,
|
||||
'total_gain': 3.4000000000000057, 'path': [{'AND': ['internal_wall_insulation+mechanical_ventilation'],
|
||||
'reference':
|
||||
'internal_wall_insulation+mechanical_ventilation:gbis'}],
|
||||
'scheme': 'gbis', 'is_eligible': True, 'unfunded_items': [], 'meets_upgrade_target': True, 'starting_sap': 68,
|
||||
'floor_area': 70.0, 'ending_sap': 71.4, 'starting_band': 'High_D', 'ending_band': 'Low_C',
|
||||
'floor_area_band': '0-72', 'project_score': 540.0, 'full_project_funding': 0.0,
|
||||
'partial_project_funding': 2300.1000000000004, 'partial_project_score': 135.3, 'total_uplift': 0.0,
|
||||
'total_uplift_score': 0.0
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue