From 3920ad413208067c822ec4db73c643c6da526eec Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 12 Aug 2024 15:15:56 +0100 Subject: [PATCH] revising scenarios, fixing setting of energy sources --- backend/Property.py | 8 ++- backend/app/plan/router.py | 8 +-- backend/app/plan/schemas.py | 2 +- etl/bill_savings/KwhData.py | 3 +- etl/customers/newhaven/newhaven_study.py | 71 +++++++++++++++--------- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/backend/Property.py b/backend/Property.py index bcb24325..e7341c4d 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -1171,7 +1171,9 @@ class Property: 'has_exhaust_source_heat_pump': 'Electricity', 'has_community_heat_pump': 'Electricity', 'has_wood_pellets': 'Wood Pellets', - 'has_community_scheme': 'Varied (Community Scheme)' + 'has_community_scheme': 'Varied (Community Scheme)', + "has_dual_fuel_mineral_and_wood": 'Wood Logs', + "has_electricaire": 'Electricity', } # Hot water @@ -1197,9 +1199,9 @@ class Property: 'community scheme': 'Community Scheme' } - self.heating_energy_source = [ + self.heating_energy_source = list({ fuel for key, fuel in heating_fuel_mapping.items() if self.main_heating.get(key, False) - ] + }) if len(self.heating_energy_source) == 0 or len(self.heating_energy_source) > 1: raise Exception("Investigate me") diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index 53a6d813..8001e6ef 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -320,11 +320,11 @@ def extract_propert_on_site_recommendations(config, already_installed, non_invas # Because we have some non-invasive recommendations that match on address and postcode, but not UPRN # we need to check existence of uprn - has_uprn = "non_invasive_recommendations" in non_invasive_recommendations[0] + has_uprn = "uprn" in non_invasive_recommendations[0] if has_uprn: property_non_invasive_recommendations = next(( x for x in non_invasive_recommendations if - (x["uprn"] == uprn) + (str(x["uprn"]) == str(uprn)) ), {}) # We patch the non-invasive recs that are ['cavity_extract_and_refill'] @@ -334,7 +334,7 @@ def extract_propert_on_site_recommendations(config, already_installed, non_invas (x["address"] == config["address"]) and (x["postcode"] == config["postcode"]) ), {}) - if isinstance(property_non_invasive_recommendations["recommendations"], str): + if isinstance(property_non_invasive_recommendations.get("recommendations"), str): import ast property_non_invasive_recommendations["recommendations"] = ast.literal_eval( property_non_invasive_recommendations["recommendations"] @@ -498,8 +498,8 @@ async def trigger_plan(body: PlanTriggerRequest): logger.info("Setting property features") [p.set_features(cleaned=cleaned, kwh_client=kwh_client, kwh_predictions=kwh_preds) for p in input_properties] - logger.info("Performing solar analysis") + # TODO: Tidy this up # TODO: If a property is semi-detached, we might get roof surfaces for the main building + the neighbour # TODO: If we can't get high image quality, should we use the solar API? Maybe just for semi-detached units with diff --git a/backend/app/plan/schemas.py b/backend/app/plan/schemas.py index 082f46d3..bbcd5a57 100644 --- a/backend/app/plan/schemas.py +++ b/backend/app/plan/schemas.py @@ -34,7 +34,7 @@ class PlanTriggerRequest(BaseModel): # Specific measures "air_source_heat_pump", "internal_wall_insulation", - "external_wall_insulation" + "external_wall_insulation", } _allowed_goals = {"Increasing EPC"} diff --git a/etl/bill_savings/KwhData.py b/etl/bill_savings/KwhData.py index 5563014b..6b5f594a 100644 --- a/etl/bill_savings/KwhData.py +++ b/etl/bill_savings/KwhData.py @@ -25,7 +25,8 @@ class KwhData: "county", "windows-description", "windows-energy-eff", "flat-top-storey", "flat-storey-count", "unheated-corridor-length", "solar-water-heating-flag", "mechanical-ventilation", - "low-energy-lighting", "environment-impact-current", "energy-tariff", "current-energy-rating" + "low-energy-lighting", "environment-impact-current", "energy-tariff", "current-energy-rating", + "floor-level" ] NUMERICAL_COLUMNS = [ diff --git a/etl/customers/newhaven/newhaven_study.py b/etl/customers/newhaven/newhaven_study.py index 4092dd87..9faf6a26 100644 --- a/etl/customers/newhaven/newhaven_study.py +++ b/etl/customers/newhaven/newhaven_study.py @@ -11,7 +11,7 @@ EPC_DIRECTORY = Path(src_file_path).parent / "local_data" / "all-domestic-certif CUSTOMER_DATA_DIRECTORY = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Newhaven/Data" USER_ID = 8 -PORTFOLIO_ID = 88 +PORTFOLIO_ID = 89 def make_asset_list(): @@ -88,20 +88,20 @@ def make_asset_list(): columns={"Wall Area [m^2]": "insulation_wall_area", "Building Area [m^2]": "floor_area"} ) - had_an_epc = asset_list[~pd.isnull(asset_list["current-energy-efficiency"])] - below_b = asset_list[asset_list["current-energy-efficiency"].astype(float) <= 80].shape - below_c = asset_list[asset_list["current-energy-efficiency"].astype(float) <= 69].shape - had_an_epc["energy-efficiency-rating"].value_counts() - asset_list["current-energy-rating"].value_counts() - asset_list["co2-emissions-current"].mean() - # Get the underlying data of a histograme - import matplotlib.pyplot as plt - n, bins, patches = plt.hist(asset_list["co2-emissions-current"], bins=100, color="blue", alpha=0.7) - - bins = np.arange(0, asset_list["co2-emissions-current"].max(), 1) # Bins from 50 to 150 with a step of 10 - - # Step 3: Calculate the frequency of data in each bin - hist, bin_edges = np.histogram(asset_list["co2-emissions-current"], bins=bins) + # had_an_epc = asset_list[~pd.isnull(asset_list["current-energy-efficiency"])] + # below_b = asset_list[asset_list["current-energy-efficiency"].astype(float) <= 80].shape + # below_c = asset_list[asset_list["current-energy-efficiency"].astype(float) <= 69].shape + # had_an_epc["energy-efficiency-rating"].value_counts() + # asset_list["current-energy-rating"].value_counts() + # asset_list["co2-emissions-current"].mean() + # # Get the underlying data of a histograme + # import matplotlib.pyplot as plt + # n, bins, patches = plt.hist(asset_list["co2-emissions-current"], bins=100, color="blue", alpha=0.7) + # + # bins = np.arange(0, asset_list["co2-emissions-current"].max(), 1) # Bins from 50 to 150 with a step of 10 + # + # # Step 3: Calculate the frequency of data in each bin + # hist, bin_edges = np.histogram(asset_list["co2-emissions-current"], bins=bins) # Take properties below a B - there are 2844 units asset_list = asset_list[asset_list["current-energy-efficiency"].astype(float) <= 80] @@ -110,7 +110,7 @@ def make_asset_list(): asset_list = asset_list[~pd.isnull(asset_list["current-energy-efficiency"])] # Take a 10% sample, for properties that have an EPC, with a seed - asset_list = asset_list.sample(frac=0.1, random_state=42) + asset_list = asset_list.sample(frac=0.25, random_state=42) AVG_FLOOR_HEIGHT = asset_list["floor-height"].median() @@ -119,11 +119,11 @@ def make_asset_list(): ): if address_base_property_description == "Self Contained Flat (Includes Maisonette / Apartment)": - if epc_property_type == "Flat": + if epc_property_type in ["Flat"]: return 1 if epc_property_type == "Maisonette": return 2 - raise NotImplementedError("Implement me") + return None if pd.isnull(floor_height): return np.round(building_height / AVG_FLOOR_HEIGHT) @@ -140,6 +140,8 @@ def make_asset_list(): ), axis=1 ) + # Drop any entires with null floors because that means the ordnance survey data doesn't align with the epc data + asset_list = asset_list[~pd.isnull(asset_list["number_of_floors"])] # D 0.419929 # C 0.391459 @@ -262,16 +264,16 @@ def make_asset_list(): "already_installed_file_path": "", "patches_file_path": "", "non_invasive_recommendations_file_path": non_invasive_recommendations_filename, - "scenario_name": "Demand Reduction - no solid wall", + "scenario_name": "Demand Reduction - no solid wall, windows, LEDs", "multi_plan": True, "exclusions": [ - "internal_wall_insulation", "external_wall_insulation", "floor_insulation", "heating", "solar_pv" + "internal_wall_insulation", "external_wall_insulation", "floor_insulation", "heating", "solar_pv", + "lighting", "windows" ], "budget": None, } print(body1) - # Scenario B body2 = { "portfolio_id": str(PORTFOLIO_ID), "housing_type": "Private", @@ -281,15 +283,34 @@ def make_asset_list(): "already_installed_file_path": "", "patches_file_path": "", "non_invasive_recommendations_file_path": non_invasive_recommendations_filename, - "scenario_name": "Demand Reduction, Heating Systems, Solar PV - no solid wall", + "scenario_name": "Demand Reduction - no solid wall, floors or heating", "multi_plan": True, - "exclusions": ["internal_wall_insulation", "external_wall_insulation", "floor_insulation"], + "exclusions": [ + "internal_wall_insulation", "external_wall_insulation", "floor_insulation", "heating", "solar_pv", + ], "budget": None, } print(body2) - # Scenario C - deep fabric, no exclusions + # Scenario B body3 = { + "portfolio_id": str(PORTFOLIO_ID), + "housing_type": "Private", + "goal": "Increasing EPC", + "goal_value": "A", + "trigger_file_path": filename, + "already_installed_file_path": "", + "patches_file_path": "", + "non_invasive_recommendations_file_path": non_invasive_recommendations_filename, + "scenario_name": "Demand Reduction, Heating Systems, Solar PV - no solid wall or floors", + "multi_plan": True, + "exclusions": ["internal_wall_insulation", "external_wall_insulation", "floor_insulation"], + "budget": None, + } + print(body3) + + # Scenario 4 - deep fabric, no IWI, floor + body4 = { "portfolio_id": str(PORTFOLIO_ID), "housing_type": "Private", "goal": "Increasing EPC", @@ -302,4 +323,4 @@ def make_asset_list(): "multi_plan": True, "budget": None, } - print(body3) + print(body4)