From 2093f198e19db77174f4f58aa11f44875a4064f0 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Sat, 9 Aug 2025 21:36:53 +0100 Subject: [PATCH] fixed multiple edge cases --- backend/Funding.py | 29 ++++++++++++++---- backend/tests/test_funding.py | 2 +- .../epc_attributes/MainheatAttributes.py | 4 ++- .../epc_attributes/attribute_utils.py | 6 ++-- .../test_mainheat_attributes_cases.py | 30 +++++++++++++++++++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/backend/Funding.py b/backend/Funding.py index 31f89488..912c0426 100644 --- a/backend/Funding.py +++ b/backend/Funding.py @@ -3,6 +3,7 @@ from typing import List import pandas as pd +from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes from backend.app.plan.schemas import HousingType, WALL_INSULATION_MEASURES, ROOF_INSULATION_MEASURES, MEASURE_MAP @@ -20,7 +21,7 @@ class Funding: SOLID_FUELS = [ 'wood logs', 'manufactured smokeless fuel', 'house coal', 'smokeless coal', 'oil', 'dual fuel mineral wood', - 'anthracite', 'dual fuel appliance mineral and wood', "bulk wood pellets", "wood chips" + 'anthracite', 'dual fuel appliance mineral and wood', "bulk wood pellets", "wood chips", "wood pellets" ] def __init__( @@ -339,6 +340,16 @@ class Funding: # check the larger, more prominent heating systems first and then the smaller ones. We aim # to cover the case where properties have heating systems like # "boiler radiators, mains gas, electric storage heaters" so mixed systems + + is_solid_fuel = (main_fuel["fuel_type"] in self.SOLID_FUELS) or ( + mainheating["has_dual_fuel_mineral_and_wood"] or + mainheating["has_coal"] or + mainheating["has_anthracite"] or + mainheating["has_smokeless_fuel"] or + mainheating["has_mineral_and_wood"] or + mainheating["has_dual_fuel_appliance"] + ) + if mainheating["has_air_source_heat_pump"]: return 'Air to Water ASHP' if mainheating["has_boiler"] and (main_fuel["fuel_type"] == "biomass"): @@ -378,7 +389,7 @@ class Funding: ): return 'Non Condensing LPG Boiler' - if mainheating["has_boiler"] and (main_fuel["fuel_type"] in self.SOLID_FUELS): + if mainheating["has_boiler"] and is_solid_fuel: return 'Solid Fossil Boiler' if mainheating["has_ground_source_heat_pump"] or mainheating["has_water_source_heat_pump"]: @@ -415,9 +426,7 @@ class Funding: if mainheating["has_room_heaters"] and main_fuel["fuel_type"] == "mains gas": return 'Gas Room Heaters' - if mainheating["has_room_heaters"] and ( - main_fuel["fuel_type"] in self.SOLID_FUELS or mainheating["has_coal"] - ): + if mainheating["has_room_heaters"] and is_solid_fuel: return 'Solid Fossil Room Heaters' # Handle the case of no heating system - electric heaters assumed @@ -456,11 +465,19 @@ class Funding: return 'Non Condensing LPG Boiler' # Treat warm air oil as a direct acting oil boiler - if mainheating["has_warm_air"] and main_fuel["fuel_type"] == "lpg": + if mainheating["has_warm_air"] and main_fuel["fuel_type"] == "oil": if mainheat_energy_eff in ["Good", "Very Good"]: return 'Condensing Oil Boiler' return 'Non Condensing Oil Boiler' + fuels_identified = [] + for fuel in MainHeatAttributes.FUEL_TYPES: + fuels_identified.append(mainheating[f"has_{fuel.replace(' ', '_')}"]) + unknown_fuel = main_fuel["fuel_type"] == "unknown" and not any(fuels_identified) + + if mainheating["has_boiler"] and unknown_fuel: + return 'Non Condensing Gas Boiler' + raise ValueError("Invalid pre heating system") def calculate_partial_project_abs( diff --git a/backend/tests/test_funding.py b/backend/tests/test_funding.py index 60629383..872d0f21 100644 --- a/backend/tests/test_funding.py +++ b/backend/tests/test_funding.py @@ -1076,7 +1076,7 @@ for _, x in tqdm(epc_df.iterrows(), total=len(epc_df)): errored_epcs = epc_df[epc_df["LMK_KEY"].isin(errors)] unique_combs = errored_epcs[["MAINHEAT_ENERGY_EFF", "MAINHEAT_DESCRIPTION", "MAIN_FUEL"]].drop_duplicates() -i = 3 +i = 11 x = errored_epcs[ (errored_epcs["MAINHEAT_ENERGY_EFF"] == unique_combs["MAINHEAT_ENERGY_EFF"].values[i]) & (errored_epcs["MAINHEAT_DESCRIPTION"] == unique_combs["MAINHEAT_DESCRIPTION"].values[i]) & diff --git a/etl/epc_clean/epc_attributes/MainheatAttributes.py b/etl/epc_clean/epc_attributes/MainheatAttributes.py index 051db8c2..7d59cd4c 100644 --- a/etl/epc_clean/epc_attributes/MainheatAttributes.py +++ b/etl/epc_clean/epc_attributes/MainheatAttributes.py @@ -18,7 +18,8 @@ class MainHeatAttributes(Definitions): "community heat pump", ] FUEL_TYPES = ["electric", "mains gas", "wood logs", "coal", "oil", "wood pellets", "anthracite", - "dual fuel mineral and wood", "smokeless fuel", "lpg", "b30k"] + "dual fuel mineral and wood", "smokeless fuel", "lpg", "b30k", "mineral and wood", + "dual fuel appliance"] DISTRIBUTION_SYSTEMS = ["radiators", "fan coil units", "pipes in screed above insulation", "pipes in insulated timber floor", "pipes in concrete slab"] OTHERS = ["assumed", "electricaire", "assumed for most rooms"] @@ -72,6 +73,7 @@ class MainHeatAttributes(Definitions): "dim system ar gael, rhagdybir bod gwresogyddion trydan, trydan": "no system present, electric heaters assumed", # Should be handled by edge cases ", trydan": ", electric", + 'awyr gynnes, nwy prif gyflenwad': 'warm air, mains gas' } REMAP = { diff --git a/etl/epc_clean/epc_attributes/attribute_utils.py b/etl/epc_clean/epc_attributes/attribute_utils.py index a5326207..28f958a8 100644 --- a/etl/epc_clean/epc_attributes/attribute_utils.py +++ b/etl/epc_clean/epc_attributes/attribute_utils.py @@ -108,9 +108,9 @@ def process_part(result: Dict[str, Union[str, bool]], part: str, attr_list: List if set(attr_words).issubset(set(part_words)): result[f'{prefix}{attr.replace(" ", "_")}'] = True - at_least_one_attribute_true = any(result.values()) - if not at_least_one_attribute_true: - raise ValueError("No attribute matches found") + # at_least_one_attribute_true = any(result.values()) + # if not at_least_one_attribute_true: + # raise ValueError("No attribute matches found") return result diff --git a/etl/epc_clean/tests/test_data/test_mainheat_attributes_cases.py b/etl/epc_clean/tests/test_data/test_mainheat_attributes_cases.py index 16acdd37..cc95fa23 100644 --- a/etl/epc_clean/tests/test_data/test_mainheat_attributes_cases.py +++ b/etl/epc_clean/tests/test_data/test_mainheat_attributes_cases.py @@ -1707,6 +1707,36 @@ mainheat_cases = [ 'has_dual_fuel_mineral_and_wood': False, 'has_smokeless_fuel': False, 'has_lpg': False, 'has_b30k': False, 'has_assumed': False, 'has_electricaire': False, 'has_assumed_for_most_rooms': False, 'has_underfloor_heating': False + }, + { + "original_description": "Boiler and radiators, dual fuel (mineral and wood)", + 'has_radiators': True, 'has_fan_coil_units': False, 'has_pipes_in_screed_above_insulation': False, + 'has_pipes_in_insulated_timber_floor': False, 'has_pipes_in_concrete_slab': False, 'has_boiler': True, + 'has_air_source_heat_pump': False, 'has_room_heaters': False, 'has_electric_storage_heaters': False, + 'has_warm_air': False, 'has_electric_underfloor_heating': False, 'has_electric_ceiling_heating': False, + 'has_community_scheme': False, 'has_ground_source_heat_pump': False, 'has_no_system_present': False, + 'has_portable_electric_heaters': False, 'has_water_source_heat_pump': False, 'has_electric_heat_pump': False, + 'has_micro-cogeneration': False, 'has_solar_assisted_heat_pump': False, 'has_exhaust_source_heat_pump': False, + 'has_community_heat_pump': False, 'has_electric': False, 'has_mains_gas': False, 'has_wood_logs': False, + 'has_coal': False, 'has_oil': False, 'has_wood_pellets': False, 'has_anthracite': False, + 'has_dual_fuel_mineral_and_wood': True, 'has_smokeless_fuel': False, 'has_lpg': False, 'has_b30k': False, + 'has_mineral_and_wood': True, 'has_assumed': False, 'has_electricaire': False, + 'has_assumed_for_most_rooms': False, 'has_underfloor_heating': False + }, + { + "original_description": "Room heaters, dual fuel appliance", + 'has_radiators': False, 'has_fan_coil_units': False, 'has_pipes_in_screed_above_insulation': False, + 'has_pipes_in_insulated_timber_floor': False, 'has_pipes_in_concrete_slab': False, 'has_boiler': False, + 'has_air_source_heat_pump': False, 'has_room_heaters': True, 'has_electric_storage_heaters': False, + 'has_warm_air': False, 'has_electric_underfloor_heating': False, 'has_electric_ceiling_heating': False, + 'has_community_scheme': False, 'has_ground_source_heat_pump': False, 'has_no_system_present': False, + 'has_portable_electric_heaters': False, 'has_water_source_heat_pump': False, 'has_electric_heat_pump': False, + 'has_micro-cogeneration': False, 'has_solar_assisted_heat_pump': False, 'has_exhaust_source_heat_pump': False, + 'has_community_heat_pump': False, 'has_electric': False, 'has_mains_gas': False, 'has_wood_logs': False, + 'has_coal': False, 'has_oil': False, 'has_wood_pellets': False, 'has_anthracite': False, + 'has_dual_fuel_mineral_and_wood': False, 'has_smokeless_fuel': False, 'has_lpg': False, 'has_b30k': False, + 'has_mineral_and_wood': False, 'has_dual_fuel_appliance': True, 'has_assumed': False, 'has_electricaire': False, + 'has_assumed_for_most_rooms': False, 'has_underfloor_heating': False } ]