diff --git a/model_data/app.py b/model_data/app.py index 9f84c396..e6caa5cf 100644 --- a/model_data/app.py +++ b/model_data/app.py @@ -104,11 +104,8 @@ def handler(): [{"address1": p.address1, **p.walls} for p in input_properties] ) - # Key values - # This is based on the standards set out by part L of the building regulations - WALLS_MAX_U_VALUE = 0.18 - input_properties[1].data["address1"] + input_properties[1].data["postcode"] walls_df["address1"].values[1] walls_df["original_description"].values[1] # Walls @@ -121,6 +118,10 @@ def handler(): # if building built after 1990 + we're able to identify U-value + U-value less than 0.18 # and if in or close to a conversation area, recommend internal wall insulation # Property 1 + # 'Flat 14 Godley V C House', Solid brick, as built, no insulation (assumed) + # Since the wall is solid brick (therefore no cavity), we can recommend the following: + # External wall insulation + # Internal wall insulation from model_data.recommendations.WallRecommendations import WallRecommendations self = WallRecommendations(property_instance=input_properties[0]) diff --git a/model_data/recommendations/WallRecommendations.py b/model_data/recommendations/WallRecommendations.py index 2b754d65..08b2c16f 100644 --- a/model_data/recommendations/WallRecommendations.py +++ b/model_data/recommendations/WallRecommendations.py @@ -1,13 +1,98 @@ -import math +import pint from model_data.Property import Property import pandas as pd +external_wall_insulation_parts = [ + { + # Example product + # https://insulationgo.co.uk/100mm-rockwool-external-wall-insulation-dual-density-slabs-a1-non-combustible + # -slab-ewi-render-fire/ + "type": "external_wall_insulation", + "description": "Mineral Wool External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Expanded Polystyrene External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Phenolic Foam External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Polyisocyanurate Foam External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Woof Fiber External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Aerogel External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + }, + { + "type": "external_wall_insulation", + "description": "Vacuum Insulation Panels External Wall Insulation", + "depths": [], + "depth_unit": "mm", + "cost": None, + # The u-value here is just a placehoder for now and we probably want to have multiple + # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types + # and costs + "u_value": None + } +] + wall_parts = [ { "id": 1, "type": "internal_wall_insulation", "description": "Internal wall insulation", + "depth": None, + "depth_unit": "mm", "cost": None, # The u-value here is just a placehoder for now and we probably want to have multiple # options for internal wall insulation (e.g. 50mm, 100mm, 150mm), with different material types @@ -27,6 +112,10 @@ class WallRecommendations: # we still consider it as an option U_VALUE_ERROR = 0.01 + DEFAULT_U_VALUES = { + "solid_brick": 2, + } + def __init__(self, property_instance: Property): self.property = property_instance self.year_built = self._year_property_was_built() @@ -67,11 +156,14 @@ class WallRecommendations: _, new_u_value = self.calculate_u_value_uplift(u_value, part["u_value"]) new_u_value = round(new_u_value, 2) - self.recommendations.append( - { - **part, "new_u_value": new_u_value, - } - ) + # We allow a small tolerance for error so we don't discount the recommendation entirely + # if it's close, since this is an estimated new u-value + if new_u_value - self.U_VALUE_ERROR <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: + self.recommendations.append( + { + **part, "new_u_value": new_u_value, + } + ) raise NotImplementedError("Not implemented yet") @@ -104,3 +196,25 @@ class WallRecommendations: u_value_uplift = u_value - new_u_value return u_value_uplift, new_u_value + + @staticmethod + def convert_r_value_to_mm(r_value_wmk): + """ + Converts an R-value from units of W/m·K to per millimeter (mm). + + :param r_value_wmk: R-value in units of W/m·K. + :type r_value_wmk: float + + :return: Converted R-value per mm. + :rtype: float + + :notes: + - This function utilizes the 'pint' library to handle units and perform the conversion. + """ + + ureg = pint.UnitRegistry() + + r_value = r_value_wmk * ureg.watt / (ureg.meter * ureg.kelvin) + r_value_per_mm = r_value.to(1 / ureg.millimeter) + + return r_value_per_mm.magnitude diff --git a/model_data/requirements.txt b/model_data/requirements.txt index a21cdf6e..0b3cd265 100644 --- a/model_data/requirements.txt +++ b/model_data/requirements.txt @@ -10,4 +10,5 @@ pytest-mock fuzzywuzzy python-Levenshtein dbfread -pyproj \ No newline at end of file +pyproj +pint \ No newline at end of file