diff --git a/backend/Funding.py b/backend/Funding.py index 05c2921d..50960eb7 100644 --- a/backend/Funding.py +++ b/backend/Funding.py @@ -322,6 +322,10 @@ class Funding: return data["Cost Savings"].values[0] def _calculate_full_project_abs(self, floor_area_band: str, starting_sap_band: str, ending_sap_band: str): + + if starting_sap_band == ending_sap_band: + return 0 + data = self.project_scores_matrix[ (self.project_scores_matrix["Floor Area Segment"] == floor_area_band) & (self.project_scores_matrix["Starting Band"] == starting_sap_band) & @@ -638,6 +642,38 @@ class Funding: # If we don't have a pre heating system, we assume the measure is not applicable return 0 + if measure_type in ["double_glazing", "secondary_glazing"]: + # pps is under the WG_singletodouble Measure_Type + pps = filtered_pps_matrix[ + filtered_pps_matrix["Measure_Type"] == "WG_singletodouble" + ] + return pps.squeeze()["Cost Savings"] + + if measure_type == "roomstat_programmer_trvs": + # We can get funding for TRVs + pps = filtered_pps_matrix[ + filtered_pps_matrix["Measure_Type"] == "TRV" + ] + if pre_heating_system in pps["Pre_Main_Heating_Source"].values: + pps = pps[pps["Pre_Main_Heating_Source"] == pre_heating_system] + if pps.shape[0] != 1: + raise ValueError("something went wrong, more than one pps for TRV") + return pps.squeeze()["Cost Savings"] + # If we don't have a pre heating system, we assume the measure is not applicable + return 0 + + if measure_type == "time_temperature_zone_control": + pps = filtered_pps_matrix[ + filtered_pps_matrix["Measure_Type"] == "TTZC" + ] + if pre_heating_system in pps["Pre_Main_Heating_Source"].values: + pps = pps[pps["Pre_Main_Heating_Source"] == pre_heating_system] + if pps.shape[0] != 1: + raise ValueError("something went wrong, more than one pps for TTZC") + return pps.squeeze()["Cost Savings"] + # If we don't have a pre heating system, we assume the measure is not applicable + return 0 + raise ValueError(f"Invalid measure type for partial project ABS calculation: {measure_type}") # ----------------------- diff --git a/backend/engine/engine.py b/backend/engine/engine.py index d81063a0..e8c5884e 100644 --- a/backend/engine/engine.py +++ b/backend/engine/engine.py @@ -949,7 +949,7 @@ async def model_engine(body: PlanTriggerRequest): total_uplift = optimal_solution["total_uplift"] # This is the funding scheme selected # This is the full project ABS - full_project_score = optimal_solution["full_project_funding"] + full_project_score = optimal_solution["project_score"] # This is the partial project ABS partial_project_score = optimal_solution["partial_project_score"] # This is the uplift score ABS diff --git a/etl/customers/remote_assessments/app.py b/etl/customers/remote_assessments/app.py index df4a16fe..9b5bf7c1 100644 --- a/etl/customers/remote_assessments/app.py +++ b/etl/customers/remote_assessments/app.py @@ -17,15 +17,28 @@ def app(): :return: """ - asset_list = pd.read_excel( - "/Users/khalimconn-kowlessar/Downloads/Energy Information MASTER June 2025 - Standardised.xlsx", - sheet_name="Solar Properties", - ) - asset_list = asset_list[~asset_list["estimated"]] - asset_list["domna_address_1"] = asset_list["domna_address_1"].astype(str) - asset_list = asset_list[["domna_address_1", "domna_postcode", "epc_os_uprn"]].rename( - columns={"domna_address_1": "address", "domna_postcode": "postcode", "epc_os_uprn": "uprn"} - ) + # asset_list = pd.read_excel( + # "/Users/khalimconn-kowlessar/Downloads/Energy Information MASTER June 2025 - Standardised.xlsx", + # sheet_name="Solar Properties", + # ) + # asset_list = asset_list[~asset_list["estimated"]] + # asset_list["domna_address_1"] = asset_list["domna_address_1"].astype(str) + # asset_list = asset_list[["domna_address_1", "domna_postcode", "epc_os_uprn"]].rename( + # columns={"domna_address_1": "address", "domna_postcode": "postcode", "epc_os_uprn": "uprn"} + # ) + + asset_list = [ + { + "address": "7 Crawley Road", + "postcode": "N22 6AN", + "uprn": 100021169757 + }, + { + "address": "7 Crawley Road", + "postcode": "N22 6AN", + "uprn": 100021169757 + }, + ] # Store the asset list in s3 filename = f"{USER_ID}/{PORTFOLIO_ID}/asset_list.csv" diff --git a/etl/epc_clean/EpcClean.py b/etl/epc_clean/EpcClean.py index 10b5095d..4b1beebe 100644 --- a/etl/epc_clean/EpcClean.py +++ b/etl/epc_clean/EpcClean.py @@ -75,6 +75,9 @@ class EpcClean: ] ] + # Average + filtered_data.groupby("lighting-description")["low-energy-lighting"].mean().reset_index() + # Convert low-energy-lighting to float for row in filtered_data: row["low-energy-lighting"] = float(row["low-energy-lighting"]) @@ -88,9 +91,10 @@ class EpcClean: sums[description] += row["low-energy-lighting"] counts[description] += 1 + # Scale to between 0 and 1 averages = [{ - "lighting-description": correct_spelling(description.lower()), - "low-energy-lighting": total / counts[description] + "lighting-description": correct_spelling(description.lower()) / 100, + "low-energy-lighting": total / counts[description] / 100 } for description, total in sums.items()] return averages diff --git a/recommendations/Costs.py b/recommendations/Costs.py index aa6f5a38..fccc2fc8 100644 --- a/recommendations/Costs.py +++ b/recommendations/Costs.py @@ -181,6 +181,7 @@ class Costs: "solid_floor_insulation": 0.26, "low_energy_lighting": 0.26, "high_heat_retention_storage_heaters": 0.1, + "windows_glazing": 0.15, } # Preliminaries are a percentage of the total cost of the work and covers the cost of site-specific costs diff --git a/recommendations/LightingRecommendations.py b/recommendations/LightingRecommendations.py index b96cefb2..6fa93fb8 100644 --- a/recommendations/LightingRecommendations.py +++ b/recommendations/LightingRecommendations.py @@ -100,7 +100,7 @@ class LightingRecommendations: :return: """ - if self.property.lighting["low_energy_proportion"] == 100: + if self.property.lighting["low_energy_proportion"] >= 1: return leds_recommendation_config = next( diff --git a/recommendations/SolarPvRecommendations.py b/recommendations/SolarPvRecommendations.py index dad9530a..cf18e0cd 100644 --- a/recommendations/SolarPvRecommendations.py +++ b/recommendations/SolarPvRecommendations.py @@ -264,7 +264,7 @@ class SolarPvRecommendations: scaffolding_options=self.scaffolding_options, n_floors=self.property.number_of_floors ) - description = f"Install a {solar_pv_product['description']}" + description = solar_pv_product['description'] if self.property.in_conservation_area: description += " Property is in a consevation area - please check with local planning authority."