diff --git a/model_data/analysis/UvalueEstimations.py b/model_data/analysis/UvalueEstimations.py index 61236278..551e60b2 100644 --- a/model_data/analysis/UvalueEstimations.py +++ b/model_data/analysis/UvalueEstimations.py @@ -100,7 +100,56 @@ class UvalueEstimations: :param cleaner: An instance of the EpcClean class used for cleaning data. """ - pass + floors_columns = [ + "local-authority", "property-type", "floor-description", "floor-energy-eff", "floor-env-eff", + "built-form", + "total-floor-area", "number-habitable-rooms", "number-heated-rooms" + ] + + floors_df = self.data[self.data["floor-description"].str.contains("Average thermal transmittance")] + + # Take just the columns we want + floors_df = floors_df[floors_columns] + floors_df["total-floor-area"] = floors_df["total-floor-area"].astype(float) + + floors_df, decile_labels, decile_boundaries = self.classify_into_deciles(floors_df, "total-floor-area") + + # We now get the U-values + floors_df = floors_df.merge( + pd.DataFrame(cleaner.cleaned['floor-description'])[["original_description", "thermal_transmittance"]], + how="left", + right_on="original_description", + left_on="floor-description" + ) + + u_value_summary = floors_df.groupby( + [ + "local-authority", + "property-type", + "floor-energy-eff", + "floor-env-eff", + "built-form", + "number-habitable-rooms", + "number-heated-rooms", + "total-floor-area_group" + ], + observed=True + ).agg({"thermal_transmittance": ["median", "size"]}).reset_index() + + u_value_summary.columns = [ + "local-authority", + "property-type", + "floor-energy-eff", + "floor-env-eff", + "built-form", + "number-habitable-rooms", + "number-heated-rooms", + "total-floor-area_group", + "median_thermal_transmittance", + "n_samples" + ] + + self.floors = u_value_summary @staticmethod def classify_into_deciles(df: pd.DataFrame, column: str) -> (pd.DataFrame, list, list): diff --git a/model_data/app.py b/model_data/app.py index e03df4b6..b804745b 100644 --- a/model_data/app.py +++ b/model_data/app.py @@ -123,13 +123,13 @@ def handler(): [{"address1": p.address1, **p.floor} for p in input_properties] ) - input_properties[0].data["address1"] - input_properties[0].data["postcode"] - floors_df["address1"].values[0] - floors_df["original_description"].values[0] + input_properties[2].data["address1"] + input_properties[2].data["postcode"] + floors_df["address1"].values[2] + floors_df["original_description"].values[2] from model_data.recommendations.FloorRecommendations import FloorRecommendations - self = FloorRecommendations(property_instance=input_properties[0], uvalue_estimates=uvalue_estimates) + self = FloorRecommendations(property_instance=input_properties[2], uvalue_estimates=uvalue_estimates) # We need to deduce a U-value for "Good" energy effieciency diff --git a/model_data/recommendations/FloorRecommendations.py b/model_data/recommendations/FloorRecommendations.py index 122d3647..1a20c432 100644 --- a/model_data/recommendations/FloorRecommendations.py +++ b/model_data/recommendations/FloorRecommendations.py @@ -4,6 +4,12 @@ from model_data.analysis.UvalueEstimations import UvalueEstimations class FloorRecommendations(BaseUtility): + # part L building regulations indicate that any rennovations on an existing property's walls should + # achieve a U-value of no higher than 0.3 + BUILDING_REGULATIONS_PART_L_MAX_U_VALUE = 0.25 + # We don't recommend measures that are too low because it becomes expensive, therefore we aim to avoid + # diminishing returns. This value should be verified with Osmosis (TODO) + DIMINISHING_RETURNS_U_VALUE = 0.2 def __init__(self, property_instance: Property, uvalue_estimates: UvalueEstimations): self.property = property_instance @@ -15,5 +21,22 @@ class FloorRecommendations(BaseUtility): self.recommendations = [] def recommend(self): + is_suspended = self.property.floor["is_suspended"] + insulation_thickness = self.property.floor["insulation_thickness"] + self.property.year_built + self.property.data["floor-energy-eff"] + self.property.data["floor-env-eff"] - if self.property.floor + if self.property.floor["another_property_below"]: + # If there's another property below, it's likely impractical to recommend a floor upgrade + return + + if is_suspended: + if insulation_thickness == "none": + uvalue = None + else: + uvalue = self.uvalue_estimates.get_estimate( + component="floor", + description="", + thickness=insulation_thickness + )