mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
wrote complete loft insulation recommendations
This commit is contained in:
parent
57c8788a37
commit
0a549e6916
3 changed files with 168 additions and 4 deletions
|
|
@ -121,7 +121,7 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
|
||||
# TODO: Move this to a class. We probably want a Recommender class which takes the injects the optimisers
|
||||
# in as a dependency and then the optimisers can take the input measures in as part of the setup() method
|
||||
|
||||
|
||||
# import pickle
|
||||
# with open("input_properties.pickle", "rb") as f:
|
||||
# input_properties = pickle.load(f)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ class RoofRecommendations:
|
|||
|
||||
DIMINISHING_RETURNS_U_VALUE = 0.14
|
||||
|
||||
# It is recommended that lofts should have at least 270mm of insulation
|
||||
MINIMUM_LOFT_ISULATION_MM = 270
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
property_instance: Property,
|
||||
|
|
@ -41,7 +44,7 @@ class RoofRecommendations:
|
|||
|
||||
# Building regulations part L recommend installing at least 270mm of insulation, however generally we
|
||||
# experience diminishing returns in terms of SAP once we go beyond around 150mm of insulation
|
||||
if insulation_thickness < 270:
|
||||
if insulation_thickness >= self.MINIMUM_LOFT_ISULATION_MM:
|
||||
return
|
||||
|
||||
# If we have a u-value already, need to implement this
|
||||
|
|
@ -52,7 +55,7 @@ class RoofRecommendations:
|
|||
|
||||
if self.property.roof["is_pitched"]:
|
||||
# We recommend loft insulation
|
||||
self.recommend_loft_insulation(u_value)
|
||||
self.recommend_loft_insulation(u_value, insulation_thickness)
|
||||
return
|
||||
|
||||
raise NotImplementedError("Implement me")
|
||||
|
|
@ -61,10 +64,12 @@ class RoofRecommendations:
|
|||
def make_loft_insulation_description(material, depth):
|
||||
return f"Install {depth}{material['depth_unit']} of {material['description']}"
|
||||
|
||||
def recommend_loft_insulation(self, u_value):
|
||||
def recommend_loft_insulation(self, u_value, insulation_thickness):
|
||||
|
||||
"""
|
||||
This method will recommend which insulation materials to use
|
||||
:param u_value: U-value of the roof before any retrofit measures have been installed
|
||||
:param insulation_thickness: Existing Insulation thickness of the loft
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
|
@ -79,6 +84,10 @@ class RoofRecommendations:
|
|||
for material in loft_insulation_materials:
|
||||
|
||||
for depth, cost_per_unit in zip(material["depths"], material["cost"]):
|
||||
# We make sure we hit a depth of 270mm. We should factor in any existing insulation if the
|
||||
# loft is already partially insulated
|
||||
if (depth + insulation_thickness) < self.MINIMUM_LOFT_ISULATION_MM:
|
||||
continue
|
||||
|
||||
part_u_value = r_value_per_mm_to_u_value(depth, material["r_value_per_mm"])
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,28 @@ loft_insulation_materials = [
|
|||
}
|
||||
]
|
||||
|
||||
loft_insulation_materials_50mm_existing = [
|
||||
{
|
||||
'id': 18, 'type': 'loft_insulation', 'description': 'Iso Spacesaver Mineral Wool insulation',
|
||||
'depths': [220, 210], 'depth_unit': 'mm', 'cost': [9, 10], 'cost_unit': 'gbp_sq_meter',
|
||||
'r_value_per_mm': 0.022727273, 'r_value_unit': 'square_meter_kelvin_per_watt',
|
||||
'thermal_conductivity': 0.044, 'thermal_conductivity_unit': 'watt_per_meter_kelvin',
|
||||
'link': 'https://flooringwarehousedirect.co.uk/product/isover-spacesaver-roll-100mm-x-1160mm-x-12-18m-14-13m2/',
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
loft_insulation_materials_150mm_existing = [
|
||||
{
|
||||
'id': 18, 'type': 'loft_insulation', 'description': 'Iso Spacesaver Mineral Wool insulation',
|
||||
'depths': [130, 119], 'depth_unit': 'mm', 'cost': [9, 10], 'cost_unit': 'gbp_sq_meter',
|
||||
'r_value_per_mm': 0.022727273, 'r_value_unit': 'square_meter_kelvin_per_watt',
|
||||
'thermal_conductivity': 0.044, 'thermal_conductivity_unit': 'watt_per_meter_kelvin',
|
||||
'link': 'https://flooringwarehousedirect.co.uk/product/isover-spacesaver-roll-100mm-x-1160mm-x-12-18m-14-13m2/',
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
class TestRoofRecommendations:
|
||||
|
||||
|
|
@ -37,3 +59,136 @@ class TestRoofRecommendations:
|
|||
roof_recommender.recommend()
|
||||
|
||||
assert len(roof_recommender.recommendations)
|
||||
|
||||
def test_loft_insulation_recommendation_50mm_insulation(self):
|
||||
property_instance2 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock())
|
||||
property_instance2.age_band = "F"
|
||||
property_instance2.floor_area = 100
|
||||
property_instance2.roof = {
|
||||
'original_description': 'Pitched, 50mm loft insulation (assumed)',
|
||||
'clean_description': 'Pitched, 50mm loft insulation',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
|
||||
}
|
||||
|
||||
roof_recommender2 = RoofRecommendations(
|
||||
property_instance=property_instance2, materials=loft_insulation_materials
|
||||
)
|
||||
|
||||
assert not roof_recommender2.recommendations
|
||||
|
||||
roof_recommender2.recommend()
|
||||
|
||||
assert len(roof_recommender2.recommendations) == 1
|
||||
|
||||
assert roof_recommender2.recommendations[0]["cost"] == 900
|
||||
assert roof_recommender2.recommendations[0]["new_u_value"] == 0.14
|
||||
assert roof_recommender2.recommendations[0]["starting_u_value"] == 0.68
|
||||
|
||||
property_instance3 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock())
|
||||
property_instance3.age_band = "F"
|
||||
property_instance3.floor_area = 100
|
||||
property_instance3.roof = {
|
||||
'original_description': 'Pitched, 50mm loft insulation (assumed)',
|
||||
'clean_description': 'Pitched, 50mm loft insulation',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
|
||||
}
|
||||
|
||||
roof_recommender3 = RoofRecommendations(
|
||||
property_instance=property_instance3, materials=loft_insulation_materials_50mm_existing
|
||||
)
|
||||
|
||||
assert not roof_recommender3.recommendations
|
||||
|
||||
roof_recommender3.recommend()
|
||||
|
||||
# The 220mm insulation should be selected, not the 210
|
||||
assert roof_recommender3.recommendations
|
||||
assert len(roof_recommender3.recommendations) == 1
|
||||
assert roof_recommender3.recommendations[0]["parts"][0]["depths"] == [220]
|
||||
|
||||
def test_loft_insulation_recommendation_150mm_insulation(self):
|
||||
property_instance4 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock())
|
||||
property_instance4.age_band = "F"
|
||||
property_instance4.floor_area = 100
|
||||
property_instance4.roof = {
|
||||
'original_description': 'Pitched, 150mm loft insulation (assumed)',
|
||||
'clean_description': 'Pitched, 150mm loft insulation',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
|
||||
}
|
||||
|
||||
roof_recommender4 = RoofRecommendations(
|
||||
property_instance=property_instance4, materials=loft_insulation_materials
|
||||
)
|
||||
|
||||
assert not roof_recommender4.recommendations
|
||||
|
||||
roof_recommender4.recommend()
|
||||
|
||||
assert len(roof_recommender4.recommendations) == 1
|
||||
|
||||
assert roof_recommender4.recommendations[0]["cost"] == 900
|
||||
assert roof_recommender4.recommendations[0]["new_u_value"] == 0.11
|
||||
assert roof_recommender4.recommendations[0]["starting_u_value"] == 0.3
|
||||
|
||||
property_instance5 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock())
|
||||
property_instance5.age_band = "F"
|
||||
property_instance5.floor_area = 100
|
||||
property_instance5.roof = {
|
||||
'original_description': 'Pitched, 150mm loft insulation (assumed)',
|
||||
'clean_description': 'Pitched, 150mm loft insulation',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
|
||||
}
|
||||
|
||||
roof_recommender5 = RoofRecommendations(
|
||||
property_instance=property_instance5, materials=loft_insulation_materials_150mm_existing
|
||||
)
|
||||
|
||||
assert not roof_recommender5.recommendations
|
||||
|
||||
roof_recommender5.recommend()
|
||||
|
||||
# The 130mm insulation should be selected, not the 110
|
||||
assert roof_recommender5.recommendations
|
||||
assert len(roof_recommender5.recommendations) == 1
|
||||
assert roof_recommender5.recommendations[0]["parts"][0]["depths"] == [130]
|
||||
|
||||
def test_loft_insulation_recommendation_270mm_insulation(self):
|
||||
# We shouldn't recommend anything in this case
|
||||
property_instance6 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock())
|
||||
property_instance6.age_band = "F"
|
||||
property_instance6.floor_area = 100
|
||||
property_instance6.roof = {
|
||||
'original_description': 'Pitched, 270mm loft insulation (assumed)',
|
||||
'clean_description': 'Pitched, 270mm loft insulation',
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': '270', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
|
||||
}
|
||||
|
||||
roof_recommender6 = RoofRecommendations(
|
||||
property_instance=property_instance6, materials=loft_insulation_materials
|
||||
)
|
||||
|
||||
assert not roof_recommender6.recommendations
|
||||
|
||||
roof_recommender6.recommend()
|
||||
|
||||
assert len(roof_recommender6.recommendations) == 0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue