diff --git a/model_data/Property.py b/model_data/Property.py index 82bb80ba..bf128e6b 100644 --- a/model_data/Property.py +++ b/model_data/Property.py @@ -1,3 +1,5 @@ +import pandas as pd +import re from epc_api.client import EpcClient from model_data.config import EPC_AUTH_TOKEN from model_data.OpenUprnClient import OpenUprnClient @@ -135,3 +137,22 @@ class Property(BaseUtility): self.in_conservation_area = ConservationAreaClient.IN_CONSERVATION_AREA else: self.in_conservation_area = ConservationAreaClient.UNKNOWN + + def set_year_built(self): + """ + Estimates when the property was built based on as much available data as possible. + + """ + + if self.full_sap_epc: + return pd.to_datetime(self.full_sap_epc["lodgement-date"]).year + + if self.data["construction-age-band"] not in self.DATA_ANOMALY_MATCHES: + # Take the lower limit. If we're pessimistic about the age of the property, that at least means we have + # more options for recommendations if that age falls before the year that insulation in walls became + # common practice + band = [int(x) for x in re.findall(r'\b\d{4}\b', self.data["construction-age-band"])] + return band[0] + + # We don't know when the property was built + return None diff --git a/model_data/app.py b/model_data/app.py index 289b2a67..3ad7f736 100644 --- a/model_data/app.py +++ b/model_data/app.py @@ -37,6 +37,7 @@ def handler(): for p in input_properties: p.search_address_epc() + p.set_year_built() uprns = [p.data['uprn'] for p in input_properties] @@ -118,14 +119,14 @@ def handler(): # Now, given the components, we want to idenfity upgrade options import pandas as pd - walls_df = pd.DataFrame( - [{"address1": p.address1, **p.walls} for p in input_properties] + floors_df = pd.DataFrame( + [{"address1": p.address1, **p.floor} for p in input_properties] ) - input_properties[7].data["address1"] - input_properties[7].data["postcode"] - walls_df["address1"].values[7] - walls_df["original_description"].values[7] + input_properties[0].data["address1"] + input_properties[0].data["postcode"] + floors_df["address1"].values[0] + floors_df["original_description"].values[0] from model_data.recommendations.WallRecommendations import WallRecommendations self = WallRecommendations(property_instance=input_properties[7], uvalue_estimates=uvalue_estimates) diff --git a/model_data/recommendations/FloorRecommendations.py b/model_data/recommendations/FloorRecommendations.py new file mode 100644 index 00000000..df79184e --- /dev/null +++ b/model_data/recommendations/FloorRecommendations.py @@ -0,0 +1,15 @@ +from model_data.BaseUtility import BaseUtility +from model_data.Property import Property +from model_data.analysis.UvalueEstimations import UvalueEstimations + + +class FloorRecommendations(BaseUtility): + + def __init__(self, property_instance: Property, uvalue_estimates: UvalueEstimations): + self.property = property_instance + self.uvalue_estimates = uvalue_estimates + # For audit purposes, when estimating u values we'll store it + self.estimated_u_value = None + + # Will contains a list of recommended measures + self.recommendations = [] diff --git a/model_data/recommendations/WallRecommendations.py b/model_data/recommendations/WallRecommendations.py index 7c7e3bb9..7db865b0 100644 --- a/model_data/recommendations/WallRecommendations.py +++ b/model_data/recommendations/WallRecommendations.py @@ -215,7 +215,6 @@ class WallRecommendations(BaseUtility): def __init__(self, property_instance: Property, uvalue_estimates: UvalueEstimations): self.property = property_instance - self.year_built = self._year_property_was_built() self.uvalue_estimates = uvalue_estimates # For audit purposes, when estimating u values we'll store it self.estimated_u_value = None @@ -236,25 +235,6 @@ class WallRecommendations(BaseUtility): return True - def _year_property_was_built(self): - """ - Estimates when the property was built based on as much available data as possible. - - """ - - if self.property.full_sap_epc: - return pd.to_datetime(self.property.full_sap_epc["lodgement-date"]).year - - if self.property.data["construction-age-band"] not in self.DATA_ANOMALY_MATCHES: - # Take the lower limit. If we're pessimistic about the age of the property, that at least means we have - # more options for recommendations if that age falls before the year that insulation in walls became - # common practice - band = [int(x) for x in re.findall(r'\b\d{4}\b', self.property.data["construction-age-band"])] - return band[0] - - # We don't know when the property was built - return None - def recommend(self): # 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, @@ -277,7 +257,7 @@ class WallRecommendations(BaseUtility): # We can't detect it's a cavity wall, but it was built after 1990 so likely built with insulation already # + it already has a U-value WORSE than the building regulations, so we recommend either internal or # external wall insulation - if (not is_cavity_wall) and (self.year_built >= self.YEAR_WALLS_BUILT_WITH_INSULATION) and ( + if (not is_cavity_wall) and (self.property.year_built >= self.YEAR_WALLS_BUILT_WITH_INSULATION) and ( u_value >= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE ): # Recommend insulation @@ -286,7 +266,7 @@ class WallRecommendations(BaseUtility): # We can't detect it's a cavity wall, but it was built after 1990 so likely built with insulation already # + it already has a U-value better than the building regulations, so we don't need to recommend anything - if (not is_cavity_wall) and (self.year_built >= self.YEAR_WALLS_BUILT_WITH_INSULATION) and ( + if (not is_cavity_wall) and (self.property.year_built >= self.YEAR_WALLS_BUILT_WITH_INSULATION) and ( u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE ): # Recommend nothing diff --git a/model_data/tests/test_wall_recommendations.py b/model_data/tests/test_wall_recommendations.py index 1d8a5807..8d0eb4d1 100644 --- a/model_data/tests/test_wall_recommendations.py +++ b/model_data/tests/test_wall_recommendations.py @@ -44,8 +44,6 @@ class TestWallRecommendations: assert obj.property assert obj.uvalue_estimates - assert obj.year_built == 2014 - def test_uvalue_0_16(self, input_properties, uvalue_estimates): """ This tests the wall description Average thermal transmittance 0.16 W/m-¦K @@ -55,9 +53,9 @@ class TestWallRecommendations: Since properties built after 1990 are typically built with insulation and this property already has really good insulation, we do NOT recommend any measures for this property """ + input_properties[0].year_built = 2014 recommender = WallRecommendations(property_instance=input_properties[0], uvalue_estimates=uvalue_estimates) assert recommender.property.walls["original_description"] == "Average thermal transmittance 0.16 W/m-¦K" - assert recommender.year_built == 2014 recommender.recommend() # This should be empty assert recommender.recommendations == [] @@ -71,9 +69,9 @@ class TestWallRecommendations: This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation """ + input_properties[1].year_built = 1930 recommender = WallRecommendations(property_instance=input_properties[1], uvalue_estimates=uvalue_estimates) assert recommender.property.walls["original_description"] == "Solid brick, as built, no insulation (assumed)" - assert recommender.year_built == 1930 assert not recommender.ewi_valid assert recommender.property.in_conservation_area == "not_in_conservation_area" assert recommender.property.data["property-type"] == "Flat" @@ -105,10 +103,11 @@ class TestWallRecommendations: This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation """ + + input_properties[6].year_built = 1991 recommender = WallRecommendations(property_instance=input_properties[6], uvalue_estimates=uvalue_estimates) assert recommender.property.walls["original_description"] == "Solid brick, as built, insulated (assumed)" - assert recommender.year_built == 1991 assert not recommender.ewi_valid assert recommender.property.in_conservation_area == "not_in_conservation_area" assert recommender.property.data["property-type"] == "Flat"