fixing unit tests

This commit is contained in:
Khalim Conn-Kowlessar 2025-05-14 20:17:42 +01:00
parent 53f70ab14d
commit 66d6266002
5 changed files with 57 additions and 146 deletions

View file

@ -185,17 +185,24 @@ class HeatingRecommender:
self.property.main_heating["clean_description"]
]["dual"]["types"]
recommendation_system_types = list(set([x["system_type"] for x in self.heating_recommendations]))
heating_measures = [
m for m in self.heating_recommendations if
m["measure_type"] not in ["time_temperature_zone_control", "roomstat_programmer_trvs"]
]
recommendation_system_types = list(
set([x["system_type"] for x in heating_measures])
)
# We check if we have the required type
if not any([x in recommendation_system_types for x in dual_heating_description]):
return
type_1_recommendations = [
x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[0]
x for x in heating_measures if x["system_type"] == dual_heating_description[0]
]
type_2_recommendations = [
x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[1]
x for x in heating_measures if x["system_type"] == dual_heating_description[1]
]
# we combine the two recommendations
combined_recommendations = []

View file

@ -39,8 +39,7 @@ testing_examples = [
'fixed-lighting-outlets-count': 10.0, 'low-energy-fixed-light-count': 7.0, 'uprn': 100110195416.0,
'uprn-source': 'Address Matched'
},
"heating_measure_types": ["air_source_heat_pump"],
"heating_controls_measure_types": ["time_temperature_zone_control"],
"heating_measure_types": ["air_source_heat_pump", "time_temperature_zone_control"],
"notes": "This property has a boiler, radiators & mains gas with good efficiency so the only recommendation"
"we expect here is for an air source heat pump. The heating controls are a programmer, room thermostat"
"and TRVs and so we should expect a TTZC recommendation"
@ -89,7 +88,6 @@ testing_examples = [
"heating_measure_types": [
"high_heat_retention_storage_heater",
],
"heating_controls_measure_types": [],
"notes": "This property has electric room heaters and is off gas so a boiler recommendation is not appropriate."
"We would expect a high heat retention storage recommendation. The property is a flat and therefore"
"we don't expect an air source heat pump recommendation. We also wouldn't expect a specific heating"
@ -137,7 +135,6 @@ testing_examples = [
'uprn': 100090311351.0, 'uprn-source': 'Address Matched', 'property-type_y': None, 'built-form_y': None,
},
"heating_measure_types": ['high_heat_retention_storage_heater', 'air_source_heat_pump'],
"heating_controls_measure_types": [],
"notes": "This test has electric storage heaters with automatic charge control - we recommend hhr storage"
"heaters in this case, but because there are already electic storage heaters in place, we "
"note, in the description of the recommendation, that this upgrade may be possible by retrofitting"
@ -181,8 +178,8 @@ testing_examples = [
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None,
'uprn': 100021560521.0, 'uprn-source': 'Address Matched',
},
"heating_measure_types": ['boiler_upgrade'],
"heating_controls_measure_types": [
"heating_measure_types": [
'boiler_upgrade',
'roomstat_programmer_trvs',
'time_temperature_zone_control',
],
@ -231,10 +228,9 @@ testing_examples = [
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': 9.0, 'low-energy-fixed-light-count': 5.0,
'uprn': 100021936225.0, 'uprn-source': 'Address Matched',
},
"heating_measure_types": [],
"heating_controls_measure_types": [
"heating_measure_types": [
'roomstat_programmer_trvs',
'time_temperature_zone_control',
'time_temperature_zone_control'
],
"notes": "Because this property already has a boiler, we don't recommend HHR. We don't recommend an ashp "
"because the home is mid-terraced. Because the heating controls are "
@ -284,7 +280,6 @@ testing_examples = [
"heating_measure_types": [
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property is a flat so we don't have an ASHP recommendation. It also doesn't have access to the "
"mains and so it can't have a gas boiler. We don't expect any controls recommendations"
},
@ -326,8 +321,8 @@ testing_examples = [
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None,
'uprn': 100080513604.0, 'uprn-source': 'Address Matched'
},
"heating_measure_types": ['air_source_heat_pump'],
"heating_controls_measure_types": [
"heating_measure_types": [
'air_source_heat_pump',
'roomstat_programmer_trvs',
'time_temperature_zone_control',
],
@ -381,7 +376,6 @@ testing_examples = [
'high_heat_retention_storage_heater',
'boiler_upgrade'
],
"heating_controls_measure_types": [],
"notes": "This property has assumed electric heating and is mid-terrace house. It has a mains gas connection."
"We can recommend a boiler upgrade and high heat retention storage heaters"
},
@ -427,7 +421,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property has an oil boiler and doesn't have a mains gas connection so we can only recommend"
"an air source heat pump and HHR (since if the home has a non-gas boiler, we recommend HHR)"
},
@ -477,7 +470,6 @@ testing_examples = [
'air_source_heat_pump',
'boiler_upgrade' # TTZs
],
"heating_controls_measure_types": [],
"notes": "This property has room heaters, from the mains gas supply. We recommend a boiler upgrade as"
"well as an air source heat pump and HHR (since the home has a room heater set up)"
},
@ -525,7 +517,6 @@ testing_examples = [
'boiler_upgrade',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property has assumed electric heaters. Boiler upgrade, HHR are recommended. We don't recommend"
"an ASHP off of the bat because it's mid-terrace."
},
@ -572,7 +563,6 @@ testing_examples = [
'high_heat_retention_storage_heater',
'boiler_upgrade'
],
"heating_controls_measure_types": [],
"notes": "This has a form of assumed electric heating and has a mains connection so we recommend HHR, boiler"
"upgrade and ASHP"
},
@ -620,7 +610,6 @@ testing_examples = [
'boiler_upgrade',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property already has storage heaters with manual charge control. The home is mid terrace so"
"the ashp is not suitable"
},
@ -668,7 +657,6 @@ testing_examples = [
'high_heat_retention_storage_heater',
'air_source_heat_pump',
],
"heating_controls_measure_types": [],
"notes": "This property has an LFG boiler but it doesn't have a mains gas connection so we can only recommend"
"an air source heat pump and hhr storage"
},
@ -714,7 +702,6 @@ testing_examples = [
'high_heat_retention_storage_heater',
'air_source_heat_pump',
],
"heating_controls_measure_types": [],
"notes": "This property has electric boilers in place, but does not have a mains connection so we don't "
"recommend a boiler upgrade. We recommend HHR and ASHP"
},
@ -762,7 +749,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [],
"notes": "This property has a dual fuel boiler and no mains gas connection. We recommend ASHP and HHR, but"
"no gas condensing boiler"
},
@ -807,7 +793,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property has a coal boiler and no mains gas connection. We recommend ASHP and HHR, but"
"no gas condensing boiler"
},
@ -855,7 +840,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property has a smokeless fuel boiler and no mains gas connection. We recommend ASHP and HHR, but"
"no gas condensing boiler"
},
@ -901,7 +885,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater',
],
"heating_controls_measure_types": [],
"notes": "This property has a wood pellets boiler and no mains gas connection. We recommend ASHP and HHR, but"
"no gas condensing boiler"
},
@ -948,7 +931,6 @@ testing_examples = [
'high_heat_retention_storage_heater',
'air_source_heat_pump',
],
"heating_controls_measure_types": [],
"notes": "This is an end-terrace house, without mains gas connection, so we recommend is HHR & ASHP"
},
{
@ -990,7 +972,6 @@ testing_examples = [
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
},
"heating_measure_types": [],
"heating_controls_measure_types": [],
"notes": "This property already has an ashp. We don't recommend any heating upgrades"
},
{
@ -1032,9 +1013,7 @@ testing_examples = [
},
"heating_measure_types": [
'air_source_heat_pump',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [
'high_heat_retention_storage_heater',
'time_temperature_zone_control',
],
"notes": "This property has dual heating. A boiler and electric storage heaters. The heating is efficient so"
@ -1081,9 +1060,7 @@ testing_examples = [
'air_source_heat_pump',
'boiler_upgrade',
'boiler_upgrade+high_heat_retention_storage_heater',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [
'high_heat_retention_storage_heater',
'time_temperature_zone_control'
],
"notes": "This property is a modified version of the previous dual heating property, where we lower the"
@ -1132,7 +1109,6 @@ testing_examples = [
'air_source_heat_pump',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [],
"notes": "This property has anthracite heating without mains. "
"We recommend ASHP and HHR, but no gas condensing boiler"
},
@ -1180,7 +1156,6 @@ testing_examples = [
'boiler_upgrade',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [],
"notes": "This property has room heaters with two different fuel sources, so we recommend HHR, ASHP, and a "
"boiler upgrade"
},
@ -1224,7 +1199,6 @@ testing_examples = [
"heating_measure_types": [
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [],
"notes": "This property is a flag, without mains gas connection. Currently has underfloor electric heating"
"so we recommend HHR"
},
@ -1272,7 +1246,6 @@ testing_examples = [
'boiler_upgrade',
'high_heat_retention_storage_heater'
],
"heating_controls_measure_types": [],
"notes": "The property has warm air electricaire heating, so we recommend ASHP and HHR. It also has a mains"
"connection so we recommend a gas condensing boiler"
},
@ -1320,89 +1293,6 @@ testing_examples = [
'boiler_upgrade',
'boiler_upgrade',
],
"heating_controls_measure_types": [],
"notes": "This property has warm air mains gas heating, so we recommend a gas condensing boiler"
}
]
# import random
# from pathlib import Path
# import inspect
# import pandas as pd
#
# # this can be used to get example data to build the test cases
# src_file_path = inspect.getfile(lambda: None)
# EPC_DIRECTORY = Path(src_file_path).parent / "local_data" / "all-domestic-certificates"
# epc_directories = [entry for entry in EPC_DIRECTORY.iterdir() if entry.is_dir()]
# directory = random.sample(epc_directories, 1)[0]
# data = pd.read_csv(directory / "certificates.csv", low_memory=False)
# # Rename the columns to the same format as the api returns
# data.columns = [c.replace("_", "-").lower() for c in data.columns]
# data["floor-height"] = data["floor-height"].fillna(2.45)
#
# used_examples = pd.DataFrame(
# [
# {
# "mainheat-description": x["epc"]["mainheat-description"],
# "mainheat-energy-eff": x["epc"]["mainheat-energy-eff"],
# "property-type": x["epc"]["property-type"],
# "built-form": x["epc"]["built-form"],
# "used": True
# } for x in testing_examples
# ]
# )
#
# data = data.merge(
# used_examples, how="left", on=["mainheat-description", "mainheat-energy-eff", "built-form", "property-type"]
# )
# data = data[pd.isnull(data["used"])].drop(columns=["used"])
#
# eg = data.sample(1).to_dict("records")[0]
# print(eg["mainheat-description"])
# print(eg["mainheat-energy-eff"])
# print(eg["property-type"])
# print(eg["built-form"])
# print(eg["mainheatcont-description"])
#
# ### We also use the Midlands EPC F/G portfolio to get examples to create tests
#
# completed_descriptions = [
# "Portable electric heaters assumed for most rooms",
# "Boiler and radiators, oil",
# "Boiler and radiators, mains gas",
# "Room heaters, mains gas",
# "No system present: electric heaters assumed",
# "Room heaters, electric",
# "Electric storage heaters",
# "Boiler and radiators, LPG",
# "Boiler and radiators, electric",
# "Boiler and radiators, dual fuel (mineral and wood)",
# "Boiler and radiators, coal",
# "Boiler and radiators, smokeless fuel",
# "Boiler and radiators, wood pellets",
# "Room heaters, dual fuel (mineral and wood)",
# "Air source heat pump, radiators, electric",
# "Portable electric heaters assumed for most rooms, Room heaters, electric",
# "Boiler and radiators, mains gas, Electric storage heaters",
# "Room heaters, anthracite",
# "Room heaters, mains gas, Room heaters, dual fuel (mineral and wood)",
# "Electric underfloor heating",
# "Warm air, Electricaire"
# ]
#
# portfolio = pd.read_excel(
# "/Users/khalimconn-kowlessar/Documents/hestia/Customers/sfr/20240820 portfolio_epc_data.xlsx"
# )
# portfolio.columns = [c.replace("_", "-").lower() for c in portfolio.columns]
# portfolio = portfolio[~portfolio["mainheat-description"].isin(completed_descriptions)]
# portfolio['sheating-energy-eff'] = None
# portfolio['sheating-env-eff'] = None
# portfolio["lodgement-datetime"] = portfolio["lodgement-datetime"].astype(str)
#
# print(portfolio["mainheat-description"].value_counts())
#
# eg = portfolio[
# (portfolio["mainheat-description"] == "Warm air, mains gas")
# ].sample(1)
# eg = eg.squeeze().to_dict()
# print(eg)

View file

@ -1,6 +1,30 @@
import datetime
materials = [
{
'id': 2484,
'type': 'room_roof_insulation',
'description': 'Room in roof insulation',
'depth': 100,
'depth_unit': 'mm',
'cost_unit': 'gbp_per_m2',
'r_value_per_mm': 0.038,
'r_value_unit': 'square_meter_kelvin_per_watt',
'thermal_conductivity': 0.022,
'thermal_conductivity_unit': 'watt_per_meter_kelvin',
'link': 'SCIS',
'created_at': '2025-03-16 15:26:22.379',
'cost': None,
'is_active': True,
'prime_material_cost': None,
'material_cost': 0.0,
'labour_cost': 0.0,
'labour_hours_per_unit': 0.0,
'plant_cost': 0.0,
'total_cost': 210.0,
'notes': None,
'is_installer_quote': True
},
{'id': 1997, 'type': 'cavity_wall_insulation', 'description': 'Imperial Bead cavity wall insulation', 'depth': 75.0,
'depth_unit': 'mm', 'cost': None, 'cost_unit': 'gbp_per_m2', 'r_value_per_mm': 0.030303031,
'r_value_unit': 'square_meter_kelvin_per_watt', 'thermal_conductivity': 0.033,

View file

@ -92,23 +92,13 @@ class TestHeatingRecommendations:
recommender = HeatingRecommender(property_instance=p)
# Check they're empty
assert not recommender.heating_recommendations
assert not recommender.heating_control_recommendations
recommender.recommend(has_cavity_or_loft_recommendations=False)
assert len(recommender.heating_recommendations) == len(test_case["heating_measure_types"])
assert (
len(recommender.heating_control_recommendations) ==
len(test_case["heating_controls_measure_types"])
)
# Check the exact measure types
assert (
{x["measure_type"] for x in recommender.heating_recommendations} ==
set(test_case["heating_measure_types"])
)
assert (
{x["measure_type"] for x in recommender.heating_control_recommendations} ==
set(test_case["heating_controls_measure_types"])
)

View file

@ -41,18 +41,18 @@ class TestLightingRecommendations:
assert len(lr.recommendation) == 1
assert lr.recommendation == [
{
'phase': 0, 'parts': [], 'type': 'low_energy_lighting', 'measure_type': 'low_energy_lighting',
'description': 'Install low energy lighting in 4 outlets', 'starting_u_value': None,
'new_u_value': None,
'already_installed': False, 'sap_points': 0.4, 'kwh_savings': 219.0, 'co2_equivalent_savings': 0.035478,
'description_simulation': {
'lighting-energy-eff': 'Very Good',
'lighting-description': 'Low energy lighting in all fixed outlets',
'low-energy-lighting': 100
},
'total': 240.24, 'subtotal': 200.20000000000002,
'vat': 40.040000000000006, 'contingency': 14.3, 'preliminaries': 14.3, 'material': 80.0, 'profit': 28.6,
'labour_hours': 3.2, 'labour_days': 0.4, 'labour_cost': 63.0, 'survey': False
}
{'phase': 0, 'parts': [], 'type': 'low_energy_lighting', 'measure_type': 'low_energy_lighting',
'description': 'Install low energy lighting in 4 outlets', 'starting_u_value': None, 'new_u_value': None,
'already_installed': False, 'sap_points': 0.4, 'kwh_savings': 219.0, 'energy_cost_savings': 54.4434,
'co2_equivalent_savings': 0.035478, 'description_simulation': {
'lighting-energy-eff': 'Very Good',
'lighting-description': 'Low energy '
'lighting in all '
'fixed outlets',
'low-energy-lighting': 100
},
'total': 240.24,
'subtotal': 200.20000000000002, 'vat': 40.040000000000006, 'contingency': 14.3, 'preliminaries': 14.3,
'material': 80.0, 'profit': 28.6, 'labour_hours': 3.2, 'labour_days': 0.4, 'labour_cost': 63.0,
'survey': False}
]