From d703447c6a9ee2b600ce5c1949f864903adde016 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Fri, 17 Nov 2023 15:39:51 +0000 Subject: [PATCH] Adding new materials to Materials enum --- .idea/Model.iml | 2 +- .idea/misc.xml | 2 +- backend/app/db/models/materials.py | 3 + backend/app/plan/temp_script_for_flight.py | 176 --------------------- recommendations/RoofRecommendations.py | 17 +- 5 files changed, 12 insertions(+), 188 deletions(-) delete mode 100644 backend/app/plan/temp_script_for_flight.py diff --git a/.idea/Model.iml b/.idea/Model.iml index b0f9c00d..4413bb06 100644 --- a/.idea/Model.iml +++ b/.idea/Model.iml @@ -7,7 +7,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 1122b380..6f308057 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/backend/app/db/models/materials.py b/backend/app/db/models/materials.py index 1dc47276..812c1ebb 100644 --- a/backend/app/db/models/materials.py +++ b/backend/app/db/models/materials.py @@ -15,6 +15,9 @@ class MaterialType(enum.Enum): cavity_wall_insulation = "cavity_wall_insulation" mechanical_ventilation = "mechanical_ventilation" loft_insulation = "loft_insulation" + exposed_floor_insulation = "exposed_floor_insulation" + flat_roof_insulation = "flat_roof_insulation" + room_roof_insulation = "room_roof_insulation" class DepthUnit(enum.Enum): diff --git a/backend/app/plan/temp_script_for_flight.py b/backend/app/plan/temp_script_for_flight.py deleted file mode 100644 index 9170b4c1..00000000 --- a/backend/app/plan/temp_script_for_flight.py +++ /dev/null @@ -1,176 +0,0 @@ -from datetime import datetime - -import pandas as pd -from epc_api.client import EpcClient -from fastapi import APIRouter, Depends -from sqlalchemy.exc import IntegrityError, OperationalError -from sqlalchemy.orm import sessionmaker -from starlette.responses import Response - -from backend.app.config import get_settings -from backend.app.db.connection import db_engine -from backend.app.db.functions.materials_functions import get_materials -from backend.app.db.functions.portfolio_functions import aggregate_portfolio_recommendations -from backend.app.db.functions.property_functions import ( - create_property, create_property_details_epc, create_property_targets, update_property_data -) -from backend.app.db.functions.recommendations_functions import ( - create_plan, create_plan_recommendations, upload_recommendations -) -from backend.app.db.models.portfolio import rating_lookup -from backend.app.dependencies import validate_token -from backend.app.plan.schemas import PlanTriggerRequest -from backend.app.plan.utils import ( - create_recommendation_scoring_data, filter_materials, get_cleaned, insert_temp_recommendation_id -) -from backend.app.utils import epc_to_sap_lower_bound, read_csv_from_s3, read_parquet_from_s3 - -from backend.ml_models.sap_change_model.api import SAPChangeModelAPI -from backend.Property import Property -from etl.epc.DataProcessor import DataProcessor -from etl.epc.settings import COLUMNS_TO_MERGE_ON -from recommendations.FloorRecommendations import FloorRecommendations -from recommendations.optimiser.CostOptimiser import CostOptimiser -from recommendations.optimiser.GainOptimiser import GainOptimiser -from recommendations.optimiser.optimiser_functions import prepare_input_measures -from recommendations.WallRecommendations import WallRecommendations -from utils.logger import setup_logger -from utils.s3 import read_dataframe_from_s3_parquet - -logger = setup_logger() - -import pickle - -with open('local_data.pickle', 'rb') as f: - local_data = pickle.load(f) - -with open("property_dimensions.pickle", "rb") as f: - property_dimensions = pickle.load(f) - -with open("sap_change_dataset.pickle", "rb") as f: - sap_change_dataset = pickle.load(f) - -created_at = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") - -plan_input = local_data["plan_input"] -uprn_filenames = local_data["uprn_filenames"] -local_property_data = local_data["local_property_data"] -materials = local_data["materials"] -materials_by_type = filter_materials(materials) -cleaned = local_data["cleaned"] -cleaning_data = local_data["cleaning_data"] - -# Need to find some proper materials -materials_by_type["walls"] += [ - {'id': 4, 'type': 'cavity_wall_insulation', 'description': 'Example Material 1', - 'depths': None, - 'depth_unit': None, 'cost': 20, - 'cost_unit': 'gbp_sq_meter', 'r_value_per_mm': 0.0278, 'r_value_unit': 'square_meter_kelvin_per_watt', - 'thermal_conductivity': 0.036, 'thermal_conductivity_unit': 'watt_per_meter_kelvin', - 'link': None, 'created_at': None, 'is_active': True}, - {'id': 10, 'type': "cavity_wall_insulation", 'description': 'Example Material 2', - 'depths': None, 'depth_unit': None, 'cost': 25, 'cost_unit': 'gbp_sq_meter', - 'r_value_per_mm': 0.02631579, 'r_value_unit': 'square_meter_kelvin_per_watt', 'thermal_conductivity': 0.038, - 'thermal_conductivity_unit': 'watt_per_meter_kelvin', - 'link': None, - 'created_at': None, 'is_active': True} -] - -epc_client = EpcClient(auth_token="NO-TOKEN") - -input_properties = [] -for i, config in enumerate(plan_input): - property_id = local_property_data[i]["id"] - input_properties.append( - Property( - postcode=config['postcode'], - address1=config['address'], - epc_client=epc_client, - id=property_id - ) - ) - -logger.info("Getting EPC, and spatial data") -for i, p in enumerate(input_properties): - p.data = local_property_data[i]["data"] - p.uprn = local_property_data[i]["uprn"] - p.id = local_property_data[i]["id"] - p.full_sap_epc = local_property_data[i]["full_sap_epc"] - p.old_data = local_property_data[i]["old_data"] - p.is_listed = False - p.in_conservation_area = False - p.is_heritage = False - - p.set_year_built() - - # TODO: TESTING - p.data['number-habitable-rooms'] = 3 - -recommendations = {} -recommendations_scoring_data = [] - -for p in input_properties: - property_recommendations = [] - - # Property recommendations - p.get_components(cleaned) - - # Floor recommendations - floor_recommender = FloorRecommendations( - property_instance=p, - materials=materials_by_type["floor"], - ) - floor_recommender.recommend() - - if floor_recommender.recommendations: - property_recommendations.append(floor_recommender.recommendations) - - # Wall recommendations - - wall_recomender = WallRecommendations( - property_instance=p, - materials=materials_by_type["walls"] - ) - wall_recomender.recommend() - - if wall_recomender.recommendations: - property_recommendations.append(wall_recomender.recommendations) - - # We insert temporary ids into the recommendations which is important for the optimiser later - property_recommendations = insert_temp_recommendation_id(property_recommendations) - - if not property_recommendations: - continue - - recommendations[p.id] = property_recommendations - - # Finally, we'll prepare data for predicting the impact on SAP - # TODO: We should use the cleaned data from get_components in the data rather than the raw - # values. We should create a method in Property which takes the EPC data and inserts the cleaned - # data - - data_processor = DataProcessor(None, newdata=True) - data_processor.insert_data(pd.DataFrame([p.data.copy()])) - data_processor.pre_process() - - starting_epc_data = data_processor.get_component_features(suffix="_STARTING") - ending_epc_data = data_processor.get_component_features(suffix="_ENDING") - fixed_data = data_processor.get_fixed_features() - - # We update the ending record with the recommended updates and we set lodgement date to today - ending_epc_data["LODGEMENT_DATE_ENDING"] = created_at - - for recommendations_by_type in property_recommendations: - for rec in recommendations_by_type: - scoring_dict = create_recommendation_scoring_data( - property=p, - recommendation=rec, - starting_epc_data=starting_epc_data, - ending_epc_data=ending_epc_data, - fixed_data=fixed_data, - ) - - recommendations_scoring_data.append(scoring_dict) - -# cleanup -del data_processor diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index 283370ac..e5200904 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -47,7 +47,8 @@ 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 >= self.MINIMUM_LOFT_ISULATION_MM: + # This only holds true for pitched roofs + if (insulation_thickness >= self.MINIMUM_LOFT_ISULATION_MM) and self.property.roof["is_pitched"]: return # If we have a u-value already, need to implement this @@ -61,7 +62,7 @@ class RoofRecommendations: return if self.property.roof["is_roof_room"]: - self.recommend_room_roof_insulation(u_value, insulation_thickness) + self.recommend_room_roof_insulation(u_value) return raise NotImplementedError("Implement me") @@ -125,8 +126,9 @@ class RoofRecommendations: 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: + # loft is already partially insulated. + # Note: This requirement is only for loft insulation + if ((depth + insulation_thickness) < self.MINIMUM_LOFT_ISULATION_MM) and roof["is_pitched"]: continue part_u_value = r_value_per_mm_to_u_value(depth, material["r_value_per_mm"]) @@ -178,7 +180,7 @@ class RoofRecommendations: self.recommendations = recommendations - def recommend_room_roof_insulation(self, u_value, insulation_thickness): + def recommend_room_roof_insulation(self, u_value): """ This method recommends room in roof insulation for properties that have been identified to possess a room in roof. @@ -217,7 +219,6 @@ class RoofRecommendations: - Flat ceilings can be insulated like a standard loft. :param u_value: Current u-value of the roof - :param insulation_thickness: Current insulation thickness of the roof :return: """ @@ -232,10 +233,6 @@ class RoofRecommendations: recommendations = [] for material in roof_roof_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"])