mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
handling odd heating systems
This commit is contained in:
parent
38eaa52e6c
commit
6bd66d83f5
6 changed files with 85 additions and 48 deletions
|
|
@ -9,7 +9,6 @@ from etl.epc.Dataset import TrainingDataset
|
|||
from etl.epc.Record import EPCRecord
|
||||
from etl.epc.settings import LATEST_FIELD, MANDATORY_FIXED_FEATURES
|
||||
from etl.epc_clean.epc_attributes.all_cleaners import all_cleaner_map
|
||||
from etl.solar.SolarPhotoSupply import SolarPhotoSupply
|
||||
from utils.logger import setup_logger
|
||||
from utils.s3 import read_dataframe_from_s3_parquet
|
||||
from etl.epc.settings import DATA_ANOMALY_MATCHES
|
||||
|
|
@ -18,11 +17,11 @@ from recommendations.recommendation_utils import (
|
|||
estimate_perimeter,
|
||||
get_wall_type,
|
||||
estimate_external_wall_area,
|
||||
esimtate_pitched_roof_area,
|
||||
estimate_windows,
|
||||
)
|
||||
from backend.ml_models.AnnualBillSavings import AnnualBillSavings
|
||||
from backend.app.utils import sap_to_epc
|
||||
import backend.app.assumptions as assumptions
|
||||
|
||||
ENVIRONMENT = os.environ.get("ENVIRONMENT", "dev")
|
||||
DATA_BUCKET = os.environ.get(
|
||||
|
|
@ -1184,11 +1183,20 @@ class Property:
|
|||
|
||||
if set(self.heating_energy_source) == {'Electricity', 'Natural Gas'}:
|
||||
# It means they have mixed heating so we take the primary one, based on main fuel
|
||||
if self.main_fuel["clean_description"] == "Mains gas not community":
|
||||
# This will probably happen in the case of an extension
|
||||
if self.main_fuel["clean_description"] in ["Mains gas not community", "Mains gas community"]:
|
||||
self.heating_energy_source = ['Natural Gas']
|
||||
else:
|
||||
self.heating_energy_source = ['Electricity']
|
||||
|
||||
if set(self.heating_energy_source) == {'Natural Gas', 'Wood Logs'}:
|
||||
# It means they have mixed heating so we take the primary one, based on main fuel
|
||||
# This will probably happen in the case of an extension
|
||||
if self.main_fuel["clean_description"] in ["Mains gas not community", "Mains gas community"]:
|
||||
self.heating_energy_source = ['Natural Gas']
|
||||
else:
|
||||
self.heating_energy_source = ['Wood Logs']
|
||||
|
||||
if len(self.heating_energy_source) == 0 or len(self.heating_energy_source) > 1:
|
||||
raise Exception("Investigate me")
|
||||
|
||||
|
|
@ -1216,6 +1224,10 @@ class Property:
|
|||
|
||||
if fuel in ['Main System', "Community Scheme"]:
|
||||
self.hot_water_energy_source = self.heating_energy_source
|
||||
elif fuel in ['Secondary System']:
|
||||
# Check the secondary heating system
|
||||
secondary_heating = self.data["secondheat-description"]
|
||||
self.hot_water_energy_source = assumptions.DESCRIPTIONS_TO_FUEL_TYPES[secondary_heating]["fuel"]
|
||||
else:
|
||||
raise Exception("Investiage me")
|
||||
|
||||
|
|
@ -1273,7 +1285,10 @@ class Property:
|
|||
return self.current_energy_consumption
|
||||
|
||||
# If the property currently has an electric boiler, it will still benefit from the ASHP efficiency gain
|
||||
remap_fuel_sources = ["Natural Gas", "LPG", "Wood Logs", "Oil", "Electricity"]
|
||||
remap_fuel_sources = [
|
||||
"Natural Gas", "LPG", "Wood Logs", "Oil", "Electricity", "Coal", "Smokeless Fuel",
|
||||
"Natural Gas + Solar Thermal", "Anthracite", "Wood Pellets",
|
||||
]
|
||||
|
||||
heating_energy_source = self.heating_energy_source
|
||||
hot_water_energy_source = self.hot_water_energy_source
|
||||
|
|
@ -1281,11 +1296,11 @@ class Property:
|
|||
hotwater_consumption = self.energy_consumption_estimates["unadjusted"]["hot_water"]
|
||||
|
||||
if (heating_energy_source not in remap_fuel_sources) or (
|
||||
hot_water_energy_source not in remap_fuel_sources
|
||||
hot_water_energy_source not in remap_fuel_sources + ["Electricity + Solar Thermal"]
|
||||
):
|
||||
raise NotImplementedError("Have not implemented estimating electrical consumption for this fuel type")
|
||||
|
||||
if heating_energy_source in ["Natural Gas", "LPG", "Wood Logs"]:
|
||||
if heating_energy_source in remap_fuel_sources:
|
||||
# Adjust the heating consumption to reflect the expected efficiency of an ASHP
|
||||
heating_consumption = heating_consumption / (assumed_ashp_efficiency / 100)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,3 +6,39 @@ AVERAGE_ASHP_EFFICIENCY = 300
|
|||
# Conservative estimate of the proportion of electricity that will be consumed, whereas the rest will
|
||||
# be exported
|
||||
SOLAR_CONSUMPTION_PROPORTION = 0.5
|
||||
|
||||
DESCRIPTIONS_TO_FUEL_TYPES = {
|
||||
"Air source heat pump, radiators, electric": {
|
||||
"fuel": "Electricity", "cop": AVERAGE_ASHP_EFFICIENCY / 100
|
||||
},
|
||||
"Boiler and radiators, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
'Electric storage heaters': {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric immersion, off-peak": {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric storage heaters, radiators": {"fuel": 'Electricity', "cop": 1},
|
||||
"Room heaters, electric": {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric immersion, standard tariff": {"fuel": 'Electricity', "cop": 1},
|
||||
"Portable electric heaters assumed for most rooms": {"fuel": 'Electricity', "cop": 1},
|
||||
"Boiler and radiators, LPG": {"fuel": 'LPG', "cop": 0.9},
|
||||
"Room heaters, dual fuel (mineral and wood)": {"fuel": 'Wood Logs', "cop": 1},
|
||||
"Room heaters, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Warm air, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Boiler, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Gas multipoint": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Warm air, Electricaire": {"fuel": "Electricity", "cop": 1},
|
||||
"Gas boiler/circulator": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Boiler and underfloor heating, mains gas": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"No system present: electric heaters assumed": {"fuel": "Electricity", "cop": 1},
|
||||
"Electric instantaneous at point of use": {"fuel": "Electricity", "cop": 1},
|
||||
"Boiler and radiators, oil": {"fuel": "Oil", "cop": 0.9},
|
||||
"Electric storage heaters, Electric storage heaters": {"fuel": "Electricity", "cop": 1},
|
||||
"Boiler and radiators, electric": {"fuel": "Electricity", "cop": 0.9},
|
||||
"Gas boiler/circulator, no cylinder thermostat": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Boiler and radiators, dual fuel (mineral and wood)": {"fuel": "Wood Logs", "cop": 0.9},
|
||||
"Electric immersion, standard tariff, plus solar": {"fuel": "Electricity + Solar Thermal", "cop": 1},
|
||||
"From main system, flue gas heat recovery": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Electric underfloor heating": {"fuel": "Electricity", "cop": 1},
|
||||
"No system present: electric immersion assumed": {"fuel": "Electricity", "cop": 1},
|
||||
"Air source heat pump, underfloor, electric": {
|
||||
"fuel": "Electricity", "cop": AVERAGE_ASHP_EFFICIENCY / 100
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -508,7 +508,6 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
logger.info("Getting spatial data")
|
||||
input_properties = OpenUprnClient.set_spatial_data(input_properties, bucket_name=get_settings().DATA_BUCKET)
|
||||
|
||||
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")
|
||||
|
||||
|
|
@ -520,6 +519,13 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
# basic estimate of roof area
|
||||
|
||||
# TODO: Debug this
|
||||
for p in input_properties:
|
||||
if p.uprn in [10002634631, 100031601798, 10009574286, 10007366417]:
|
||||
continue
|
||||
p.estimate_electrical_consumption(
|
||||
assumed_ashp_efficiency=assumptions.AVERAGE_ASHP_EFFICIENCY, exclusions=body.exclusions
|
||||
)
|
||||
|
||||
building_ids = [
|
||||
{
|
||||
"building_id": p.building_id,
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ class AnnualBillSavings:
|
|||
)
|
||||
return (kwh / cop) * cost_per_kwh
|
||||
|
||||
if fuel == "Wood Logs":
|
||||
if fuel in ["Wood Logs", "Wood Pellets"]:
|
||||
price_data = cls.FUEL_DATA[cls.FUEL_DATA["Fuel"] == "Pellets (Bagged)"].squeeze()
|
||||
cost_per_kwh = cls.cost_per_kwh(
|
||||
price_data["Price (p)"], price_data["Energy Content, Net Calorific value (kWh/unit)"]
|
||||
|
|
@ -296,4 +296,19 @@ class AnnualBillSavings:
|
|||
)
|
||||
return (kwh / cop) * cost_per_kwh
|
||||
|
||||
if fuel in ["Smokeless Fuel", "Anthracite"]:
|
||||
price_data = cls.FUEL_DATA[cls.FUEL_DATA["Fuel"] == "Smokeless fuel"].squeeze()
|
||||
cost_per_kwh = cls.cost_per_kwh(
|
||||
price_data["Price (p)"], price_data["Energy Content, Net Calorific value (kWh/unit)"]
|
||||
)
|
||||
return (kwh / cop) * cost_per_kwh
|
||||
|
||||
# We use coal's values for
|
||||
if fuel == "Coal":
|
||||
price_data = cls.FUEL_DATA[cls.FUEL_DATA["Fuel"] == "Coal"].squeeze()
|
||||
cost_per_kwh = cls.cost_per_kwh(
|
||||
price_data["Price (p)"], price_data["Energy Content, Net Calorific value (kWh/unit)"]
|
||||
)
|
||||
return (kwh / cop) * cost_per_kwh
|
||||
|
||||
raise Exception("Fuel not recognised")
|
||||
|
|
|
|||
|
|
@ -19,41 +19,6 @@ from backend.apis.GoogleSolarApi import GoogleSolarApi
|
|||
import backend.app.assumptions as assumptions
|
||||
|
||||
ASHP_COP = 3
|
||||
DESCRIPTIONS_TO_FUEL_TYPES = {
|
||||
"Air source heat pump, radiators, electric": {
|
||||
"fuel": "Electricity", "cop": assumptions.AVERAGE_ASHP_EFFICIENCY / 100
|
||||
},
|
||||
"Boiler and radiators, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
'Electric storage heaters': {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric immersion, off-peak": {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric storage heaters, radiators": {"fuel": 'Electricity', "cop": 1},
|
||||
"Room heaters, electric": {"fuel": 'Electricity', "cop": 1},
|
||||
"Electric immersion, standard tariff": {"fuel": 'Electricity', "cop": 1},
|
||||
"Portable electric heaters assumed for most rooms": {"fuel": 'Electricity', "cop": 1},
|
||||
"Boiler and radiators, LPG": {"fuel": 'LPG', "cop": 0.9},
|
||||
"Room heaters, dual fuel (mineral and wood)": {"fuel": 'Wood Logs', "cop": 1},
|
||||
"Room heaters, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Warm air, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Boiler, mains gas": {"fuel": 'Natural Gas', "cop": 0.9},
|
||||
"Gas multipoint": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Warm air, Electricaire": {"fuel": "Electricity", "cop": 1},
|
||||
"Gas boiler/circulator": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Boiler and underfloor heating, mains gas": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"No system present: electric heaters assumed": {"fuel": "Electricity", "cop": 1},
|
||||
"Electric instantaneous at point of use": {"fuel": "Electricity", "cop": 1},
|
||||
"Boiler and radiators, oil": {"fuel": "Oil", "cop": 0.9},
|
||||
"Electric storage heaters, Electric storage heaters": {"fuel": "Electricity", "cop": 1},
|
||||
"Boiler and radiators, electric": {"fuel": "Electricity", "cop": 0.9},
|
||||
"Gas boiler/circulator, no cylinder thermostat": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Boiler and radiators, dual fuel (mineral and wood)": {"fuel": "Wood Logs", "cop": 0.9},
|
||||
"Electric immersion, standard tariff, plus solar": {"fuel": "Electricity + Solar Thermal", "cop": 1},
|
||||
"From main system, flue gas heat recovery": {"fuel": "Natural Gas", "cop": 0.9},
|
||||
"Electric underfloor heating": {"fuel": "Electricity", "cop": 1},
|
||||
"No system present: electric immersion assumed": {"fuel": "Electricity", "cop": 1},
|
||||
"Air source heat pump, underfloor, electric": {
|
||||
"fuel": "Electricity", "cop": assumptions.AVERAGE_ASHP_EFFICIENCY / 100
|
||||
},
|
||||
}
|
||||
STARTING_DUMMY_ID_VALUE = -9999
|
||||
|
||||
|
||||
|
|
@ -551,7 +516,7 @@ class Recommendations:
|
|||
}
|
||||
raise NotImplementedError("Handle this case")
|
||||
|
||||
mapped = DESCRIPTIONS_TO_FUEL_TYPES[heating_description]
|
||||
mapped = assumptions.DESCRIPTIONS_TO_FUEL_TYPES[heating_description]
|
||||
heating_fuel = mapped["fuel"]
|
||||
|
||||
if hotwater_description in [
|
||||
|
|
|
|||
|
|
@ -514,8 +514,8 @@ FLOOR_LEVEL_MAP = {
|
|||
"top floor": 5,
|
||||
"20+": 20,
|
||||
"21st or above": 21,
|
||||
**{str(i).zfill(2): i for i in range(0, 21)},
|
||||
**{ordinal(i): i for i in range(-1, 21)},
|
||||
**{str(i): i for i in range(-1, 21)},
|
||||
**{i: i for i in range(-1, 21)},
|
||||
**{str(i).zfill(2): i for i in range(0, 51)},
|
||||
**{ordinal(i): i for i in range(-1, 51)},
|
||||
**{str(i): i for i in range(-1, 51)},
|
||||
**{i: i for i in range(-1, 51)},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue