mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Merge pull request #349 from Hestia-Homes/renewables-recommendations
Renewables recommendations
This commit is contained in:
commit
eadd015308
13 changed files with 337 additions and 272 deletions
|
|
@ -69,7 +69,7 @@ class GoogleSolarApi:
|
|||
self.floor_area = None
|
||||
self.roof_area = None
|
||||
self.roof_segment_indexes = None
|
||||
self.panel_area = None
|
||||
self.panel_area = assumptions.RDSAP_AREA_PER_PANEL
|
||||
self.panel_wattage = None
|
||||
self.panel_performance = None
|
||||
|
||||
|
|
@ -166,10 +166,6 @@ class GoogleSolarApi:
|
|||
|
||||
self.roof_area = self.insights_data["solarPotential"]["wholeRoofStats"]['areaMeters2']
|
||||
self.floor_area = self.insights_data["solarPotential"]["wholeRoofStats"]['groundAreaMeters2']
|
||||
self.panel_area = (
|
||||
self.insights_data["solarPotential"]["panelHeightMeters"] *
|
||||
self.insights_data["solarPotential"]["panelWidthMeters"]
|
||||
)
|
||||
self.panel_wattage = self.insights_data["solarPotential"]["panelCapacityWatts"]
|
||||
if self.panel_wattage != 400:
|
||||
# In the API documentation, it claims that the default output is 250W, however we've only seen 400W, so if
|
||||
|
|
@ -450,8 +446,8 @@ class GoogleSolarApi:
|
|||
|
||||
# We want max roi, minimal generation deficit, and max generation value - we create a ranking score
|
||||
# Assign equal weights to each metric
|
||||
weights = {'roi': 0.6, 'generation_value': 0.2, 'generation_deficit': 0.2}
|
||||
metrics = panel_performance[['roi', 'generation_value', 'generation_deficit']]
|
||||
weights = {'roi': 0.8, 'generation_value': 0.2}
|
||||
metrics = panel_performance[['roi', 'generation_value']].copy()
|
||||
|
||||
# Normalize the columns (0 to 1 scale)
|
||||
scaler = MinMaxScaler()
|
||||
|
|
@ -459,12 +455,11 @@ class GoogleSolarApi:
|
|||
|
||||
# Convert normalized metrics back to a dataframe
|
||||
normalized_metrics_df = pd.DataFrame(
|
||||
normalized_metrics, columns=['roi', 'generation_value', 'generation_deficit']
|
||||
normalized_metrics, columns=['roi', 'generation_value']
|
||||
)
|
||||
normalized_metrics_df['combined_score'] = (
|
||||
normalized_metrics_df['roi'] * weights['roi'] +
|
||||
normalized_metrics_df['generation_value'] * weights['generation_value'] +
|
||||
(1 - normalized_metrics_df['generation_deficit']) * weights['generation_deficit']
|
||||
normalized_metrics_df['generation_value'] * weights['generation_value']
|
||||
)
|
||||
|
||||
panel_performance['combined_score'] = normalized_metrics_df['combined_score'].values
|
||||
|
|
@ -799,7 +794,6 @@ class GoogleSolarApi:
|
|||
"panel_performance": solar_api_client.panel_performance,
|
||||
"unit_share_of_energy": 1
|
||||
},
|
||||
roof_area=solar_api_client.roof_area
|
||||
)
|
||||
|
||||
return input_properties
|
||||
|
|
@ -825,7 +819,7 @@ class GoogleSolarApi:
|
|||
n_panels=10, has_battery=False, n_floors=property_instance.number_of_floors
|
||||
)["total"],
|
||||
'weighted_ratio': None,
|
||||
'panneled_roof_area': 10 * 1.8,
|
||||
'panneled_roof_area': 10 * assumptions.RDSAP_AREA_PER_PANEL,
|
||||
'array_wattage': 4000,
|
||||
'initial_ac_kwh_per_year': 4000 * 0.95, # Assumed 95% efficient wattage -> ac
|
||||
'lifetime_ac_kwh': None,
|
||||
|
|
@ -845,7 +839,7 @@ class GoogleSolarApi:
|
|||
n_panels=6, has_battery=False, n_floors=property_instance.number_of_floors
|
||||
)["total"],
|
||||
'weighted_ratio': None,
|
||||
'panneled_roof_area': 6 * 1.8,
|
||||
'panneled_roof_area': 6 * assumptions.RDSAP_AREA_PER_PANEL,
|
||||
'array_wattage': 2400,
|
||||
'initial_ac_kwh_per_year': 2400 * 0.95, # Assumed 95% efficient wattage -> ac
|
||||
'lifetime_ac_kwh': None,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ AVERAGE_ASHP_EFFICIENCY = 250
|
|||
# be exported
|
||||
SOLAR_CONSUMPTION_PROPORTION = 0.5
|
||||
|
||||
# Typically, each solar panel takes up around 3.4 m2 of roof space under RdSAP. This was been verified in Elmhurst
|
||||
RDSAP_AREA_PER_PANEL = 3.4
|
||||
|
||||
SOCIAL_TENURES = ["Rented (social)", "rental (social)"]
|
||||
|
||||
DESCRIPTIONS_TO_FUEL_TYPES = {
|
||||
"Air source heat pump, radiators, electric": {
|
||||
"fuel": "Electricity", "cop": AVERAGE_ASHP_EFFICIENCY / 100
|
||||
|
|
|
|||
|
|
@ -631,27 +631,38 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
for p in input_properties:
|
||||
if not recommendations.get(p.id):
|
||||
continue
|
||||
|
||||
input_measures = prepare_input_measures(recommendations[p.id], body.goal)
|
||||
|
||||
current_sap_points = int(p.data["current-energy-efficiency"])
|
||||
target_sap_points = epc_to_sap_lower_bound(body.goal_value)
|
||||
sap_gain = CostOptimiser.calculate_sap_gain_with_slack(target_sap_points - current_sap_points)
|
||||
|
||||
if body.budget:
|
||||
optimiser = GainOptimiser(
|
||||
input_measures, max_cost=body.budget, max_gain=sap_gain if sap_gain > 0 else 0
|
||||
)
|
||||
if not body.optimise:
|
||||
if body.goal != "Increasing EPC":
|
||||
raise NotImplementedError("Only EPC optimisation is currently supported")
|
||||
solution = []
|
||||
for sub_list in input_measures:
|
||||
# Select the entry with the highest gain, and if tied, choose the one with the lowest cost
|
||||
best_measure = max(sub_list, key=lambda x: (x['gain'], -x['cost']))
|
||||
solution.append(best_measure)
|
||||
else:
|
||||
# The minimum gain is the minimum number of SAP points required to get to the target SAP band
|
||||
# If the gain is negative, the optimiser will return an empty solution
|
||||
optimiser = CostOptimiser(
|
||||
input_measures,
|
||||
min_gain=sap_gain
|
||||
)
|
||||
|
||||
optimiser.setup()
|
||||
optimiser.solve()
|
||||
solution = optimiser.solution
|
||||
if body.budget:
|
||||
optimiser = GainOptimiser(
|
||||
input_measures, max_cost=body.budget, max_gain=sap_gain if sap_gain > 0 else 0
|
||||
)
|
||||
else:
|
||||
# The minimum gain is the minimum number of SAP points required to get to the target SAP band
|
||||
# If the gain is negative, the optimiser will return an empty solution
|
||||
optimiser = CostOptimiser(
|
||||
input_measures,
|
||||
min_gain=sap_gain
|
||||
)
|
||||
|
||||
optimiser.setup()
|
||||
optimiser.solve()
|
||||
solution = optimiser.solution
|
||||
|
||||
selected_recommendations = {r["id"] for r in solution}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ class PlanTriggerRequest(BaseModel):
|
|||
# exists in the portfolio, it will be ignored
|
||||
multi_plan: Optional[bool] = False
|
||||
|
||||
# if False, allows optimisation to be switched off
|
||||
optimise: Optional[bool] = False
|
||||
|
||||
_allowed_goals = {"Increasing EPC"}
|
||||
|
||||
_allowed_housing_types = {"Social", "Private"}
|
||||
|
|
|
|||
|
|
@ -841,7 +841,7 @@ class Costs:
|
|||
"labour_days": labour_days,
|
||||
}
|
||||
|
||||
def high_heat_electric_storage_heaters(self, number_heated_rooms):
|
||||
def high_heat_electric_storage_heaters(self, number_heated_rooms, needs_cylinder):
|
||||
|
||||
"""
|
||||
We base the estimates for the cost of electric storage heaters on the cost per room as estimated by the
|
||||
|
|
@ -852,7 +852,12 @@ class Costs:
|
|||
:param number_heated_rooms: int, number of rooms to be heated
|
||||
"""
|
||||
|
||||
total_cost = 1500 * number_heated_rooms
|
||||
if needs_cylinder:
|
||||
# 1000 is the cost of a new hot water cylinder
|
||||
total_cost = 1200 * number_heated_rooms + 1000
|
||||
else:
|
||||
# 500 is the cost of a dual immersion heater - a rough estimate
|
||||
total_cost = 1200 * number_heated_rooms + 500
|
||||
subtotal_before_vat = total_cost / (1 + self.VAT_RATE)
|
||||
vat = total_cost - subtotal_before_vat
|
||||
|
||||
|
|
@ -1143,7 +1148,7 @@ class Costs:
|
|||
"labour_days": labour_days,
|
||||
}
|
||||
|
||||
def air_source_heat_pump(self):
|
||||
def air_source_heat_pump(self, ashp_size):
|
||||
"""
|
||||
Based on the region and type of property, this function will produce a cost estimation for an air source heat
|
||||
pump. This cost will include the boiler upgrade scheme grant
|
||||
|
|
@ -1151,14 +1156,19 @@ class Costs:
|
|||
"""
|
||||
|
||||
# This is the average cost of a project, we'll add some additional contingency
|
||||
regional_cost = MCS_AIR_SOURCE_HEAT_PUMP_COST_DATA[self.region]
|
||||
|
||||
total_cost = regional_cost * (1 + self.CONTINGENCY) - BOILER_UPGRADE_SCHEME_ASHP_VALUE
|
||||
if ashp_size is None:
|
||||
cost = [x for x in INSTALLER_ASHP_COSTS if x["capacity_kw"] is None][0]["cost"]
|
||||
else:
|
||||
cost = [x for x in INSTALLER_ASHP_COSTS if x][0]["cost"]
|
||||
|
||||
# We add some contingency since there are additional costs such as resizing radiators, that could be required
|
||||
total_cost = cost * (1 + self.CONTINGENCY)
|
||||
subtotal_before_vat = total_cost / (1 + self.VAT_RATE)
|
||||
vat = total_cost - subtotal_before_vat
|
||||
|
||||
# We assume 3 days installation
|
||||
labour_days = 3
|
||||
# We assume 5 days installation
|
||||
labour_days = 5
|
||||
labour_hours = labour_days * 8
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import re
|
||||
import backend.app.assumptions as assumptions
|
||||
from recommendations.Costs import Costs, BOILER_UPGRADE_SCHEME_ASHP_VALUE
|
||||
from recommendations.recommendation_utils import (
|
||||
check_simulation_difference, override_costs, combine_recommendation_configs
|
||||
|
|
@ -368,6 +370,75 @@ class HeatingRecommender:
|
|||
description = ("Replace the existing boiler and cylinder without a thermostat with a new electric combi "
|
||||
"boiler")
|
||||
|
||||
def size_heat_pump(self):
|
||||
"""
|
||||
Given the methodology by installers (SCIS) this function will perform a basic heat loss calculation and
|
||||
produce a recommendation for the size of the heat pump
|
||||
:return:
|
||||
"""
|
||||
|
||||
floor_area = self.property.floor_area
|
||||
|
||||
# We use the default heat loss W/m2 values are specified by the insaller, depending on the property type
|
||||
|
||||
def remap_to_heat_loss(construction_age_band):
|
||||
if "before 1900" in construction_age_band:
|
||||
return "Pre 1900 (solid stone)"
|
||||
elif "1900-1929" in construction_age_band:
|
||||
return "Early 1900s (solid brick)"
|
||||
elif re.search(r'1930|1949|1950|1966|1967|1975', construction_age_band):
|
||||
return "1950-1980 (cavity void)"
|
||||
elif re.search(r'1976|1982|1983|1990', construction_age_band):
|
||||
return "Post 1980 (cavity wall construction)"
|
||||
elif re.search(r'1991|1995|1996|2002|2003|2011', construction_age_band):
|
||||
return "2000-2018"
|
||||
elif "2012 onwards" in construction_age_band:
|
||||
return "New build (2018+)"
|
||||
else:
|
||||
return None
|
||||
|
||||
def select_heatpump_size(heat_loss_calculation):
|
||||
"""
|
||||
This function calculates the size of the heat pump based on the heat loss calculation, mapping
|
||||
the heat loss calculation to the size of the heat pump in KW
|
||||
:param heat_loss_calculation: This is calcualted as the floor area multipled by the heat loss constant,
|
||||
divided by 1000
|
||||
"""
|
||||
if heat_loss_calculation < 5:
|
||||
return 5
|
||||
elif 5 <= heat_loss_calculation < 6:
|
||||
return 6
|
||||
elif 6 <= heat_loss_calculation < 8.5:
|
||||
return 8.5
|
||||
elif 8.5 <= heat_loss_calculation < 11.2:
|
||||
return 11.2
|
||||
elif 11.2 <= heat_loss_calculation < 14:
|
||||
return 14
|
||||
elif 14 <= heat_loss_calculation < 17:
|
||||
return 17
|
||||
elif 17 <= heat_loss_calculation < 20:
|
||||
return 20
|
||||
else:
|
||||
return None
|
||||
|
||||
heat_loss_constants = {
|
||||
"New build (2018+)": 35,
|
||||
"2000-2018": 50,
|
||||
"Post 1980 (cavity wall construction)": 60,
|
||||
"1950-1980 (cavity void)": 70,
|
||||
"Early 1900s (solid brick)": 80,
|
||||
"Pre 1900 (solid stone)": 90
|
||||
}
|
||||
|
||||
heat_loss_group = remap_to_heat_loss(self.property.construction_age_band)
|
||||
heat_loss_constant = heat_loss_constants[heat_loss_group]
|
||||
|
||||
heat_loss_calculation = floor_area * heat_loss_constant / 1000
|
||||
|
||||
heat_pump_size = select_heatpump_size(heat_loss_calculation)
|
||||
|
||||
return heat_pump_size
|
||||
|
||||
def recommend_air_source_heat_pump(self, phase, has_cavity_or_loft_recommendations, _return=False):
|
||||
"""
|
||||
This method will implement the recommendation for an air source heat pump
|
||||
|
|
@ -383,8 +454,9 @@ class HeatingRecommender:
|
|||
|
||||
controls_recommender = HeatingControlRecommender(self.property)
|
||||
controls_recommender.recommend(heating_description="Air source heat pump, radiators, electric")
|
||||
ashp_size = self.size_heat_pump()
|
||||
|
||||
ashp_costs = self.costs.air_source_heat_pump()
|
||||
ashp_costs = self.costs.air_source_heat_pump(ashp_size)
|
||||
if non_intrusive_recommendation:
|
||||
# Update with non-intrusive recommendation
|
||||
if non_intrusive_recommendation.get("cost"):
|
||||
|
|
@ -413,11 +485,13 @@ class HeatingRecommender:
|
|||
# This is a map from the heating controls description to the description of the air source heat pump set up
|
||||
ashp_descriptions = {
|
||||
"Time and temperature zone control": (
|
||||
"Install an air source heat pump, and upgrade heating controls to Smart Thermostats, "
|
||||
"room sensors and smart radiator valves (time & temperature zone control)."
|
||||
f"Install a {ashp_size}KW air source heat pump, and upgrade heating controls to Smart Thermostats, "
|
||||
"room sensors and smart radiator valves (time & temperature zone control). Ensure you have an 18 or "
|
||||
"24 hour tariff"
|
||||
),
|
||||
"Programmer, TRVs and bypass": (
|
||||
"Install an air source heat pump, with programmer, TRVs and a Bypass valve."
|
||||
f"Install a {ashp_size}KW air source heat pump, with programmer, TRVs and a Bypass valve. Ensure you "
|
||||
"have an 18 or 24 hour tariff"
|
||||
),
|
||||
}
|
||||
|
||||
|
|
@ -434,7 +508,7 @@ class HeatingRecommender:
|
|||
ashp_costs_with_controls[key] += controls_rec[key]
|
||||
|
||||
if controls_rec is None:
|
||||
description = "Install a Mitsubish air source heat pump."
|
||||
description = f"Install a {ashp_size}KW Air source heat pump. Ensure you have an 18 or 24 hour tariff"
|
||||
elif already_installed:
|
||||
description = "The property already has an air source heat pump, no further action needed."
|
||||
else:
|
||||
|
|
@ -443,17 +517,16 @@ class HeatingRecommender:
|
|||
# If the property does not have existing cavity and loft insulation, we include a note that the cost
|
||||
# includes the boiler upgrade scheme and that the cavity and loft need to be treated, to ensure access
|
||||
# to the funding
|
||||
if not non_intrusive_recommendation:
|
||||
if not non_intrusive_recommendation and self.property.data["tenure"] not in assumptions.SOCIAL_TENURES:
|
||||
if has_cavity_or_loft_recommendations:
|
||||
description = description + (
|
||||
f" The cost includes the £"
|
||||
f"{BOILER_UPGRADE_SCHEME_ASHP_VALUE} boiler upgrade scheme grant. "
|
||||
f"You must ensure that the property has an insulated cavity and "
|
||||
f"270mm+ loft insulation to qualify for the grant"
|
||||
f" You must ensure that the property has an insulated cavity and "
|
||||
f"270mm+ loft insulation to qualify for the grant, to claim £"
|
||||
f"{BOILER_UPGRADE_SCHEME_ASHP_VALUE} of funding from the boiler upgrade scheme grant. "
|
||||
)
|
||||
else:
|
||||
description = description + (
|
||||
f" The cost includes the £{BOILER_UPGRADE_SCHEME_ASHP_VALUE} boiler upgrade scheme grant"
|
||||
f" £{BOILER_UPGRADE_SCHEME_ASHP_VALUE} of funding can be claimed from the boiler upgrade scheme"
|
||||
)
|
||||
|
||||
simulation_config = {
|
||||
|
|
@ -739,20 +812,37 @@ class HeatingRecommender:
|
|||
new_heating_description = self.DUAL_HEATING_DESCRIPTIONS[
|
||||
self.property.main_heating["clean_description"]
|
||||
]["hhr"]["mainheating_description"]
|
||||
new_hot_water_description = self.property.hotwater["clean_description"] # We keep the hot water system
|
||||
else:
|
||||
new_heating_description = "Electric storage heaters"
|
||||
new_hot_water_description = "Electric immersion, off-peak"
|
||||
|
||||
# Set up artefacts, suitable for the simulation and regardless of controls
|
||||
heating_ending_config = MainHeatAttributes(new_heating_description).process()
|
||||
heating_simulation_config = check_simulation_difference(
|
||||
new_config=heating_ending_config, old_config=self.property.main_heating
|
||||
)
|
||||
|
||||
hot_water_end_config = HotWaterAttributes(new_hot_water_description).process()
|
||||
hot_water_simulation_config = check_simulation_difference(
|
||||
new_config=hot_water_end_config, old_config=self.property.hotwater
|
||||
)
|
||||
|
||||
heating_simulation_config = {
|
||||
**heating_simulation_config,
|
||||
**hot_water_simulation_config
|
||||
}
|
||||
# This upgrade will only take the heating system to average energy efficiency
|
||||
if self.property.data["mainheat-energy-eff"] in ["Very Poor", "Poor"]:
|
||||
if self.property.data["mainheat-energy-eff"] in ["Very Poor", "Poor"] and not self.dual_heating:
|
||||
heating_simulation_config["mainheat_energy_eff_ending"] = "Average"
|
||||
else:
|
||||
heating_simulation_config["mainheat_energy_eff_ending"] = self.property.data["mainheat-energy-eff"]
|
||||
|
||||
if self.property.data["hot-water-energy-eff"] in ["Very Poor", "Poor"]:
|
||||
heating_simulation_config["hot_water_energy_eff_ending"] = "Average"
|
||||
else:
|
||||
heating_simulation_config["hot_water_energy_eff_ending"] = self.property.data["hot-water-energy-eff"]
|
||||
|
||||
# If the property is off-gas and has no heating system in place, the number of heated rooms will actually
|
||||
# be 0, so we use the number of rooms as the figure
|
||||
number_heated_rooms = (
|
||||
|
|
@ -768,7 +858,8 @@ class HeatingRecommender:
|
|||
|
||||
# Upgrade to electric storage heaters
|
||||
costs = self.costs.high_heat_electric_storage_heaters(
|
||||
number_heated_rooms=number_heated_rooms
|
||||
number_heated_rooms=number_heated_rooms,
|
||||
needs_cylinder=self.property.hotwater["system_type"] == "from main system"
|
||||
)
|
||||
if self.dual_heating:
|
||||
description = self.DUAL_HEATING_DESCRIPTIONS[
|
||||
|
|
@ -776,7 +867,7 @@ class HeatingRecommender:
|
|||
]["hhr"]["recommendation_description"]
|
||||
|
||||
else:
|
||||
description = "Install high heat retention electric storage heaters."
|
||||
description = "Install high heat retention electric storage heaters with an appropriate off-peak tariff."
|
||||
|
||||
# We check the existing heating system and controls
|
||||
if (
|
||||
|
|
@ -790,6 +881,8 @@ class HeatingRecommender:
|
|||
heating_description_simulation = {
|
||||
"mainheat-description": new_heating_description,
|
||||
"mainheat-energy-eff": heating_simulation_config["mainheat_energy_eff_ending"],
|
||||
"hotwater-description": new_hot_water_description,
|
||||
"hot-water-energy-eff": heating_simulation_config["hot_water_energy_eff_ending"]
|
||||
}
|
||||
|
||||
recommendations = self.combine_heating_and_controls(
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ class RoofRecommendations:
|
|||
if proposed_depth >= 300:
|
||||
new_efficiency = "Very Good"
|
||||
else:
|
||||
if self.property.data["walls-energy-eff"] not in ["Good", "Very Good"]:
|
||||
if self.property.data["roof-energy-eff"] not in ["Good", "Very Good"]:
|
||||
new_efficiency = "Good"
|
||||
else:
|
||||
new_efficiency = "Very Good"
|
||||
|
|
@ -416,7 +416,7 @@ class RoofRecommendations:
|
|||
|
||||
self.recommendations = recommendations
|
||||
|
||||
def recommend_room_roof_insulation(self, u_value, phase):
|
||||
def recommend_room_roof_insulation(self, u_value, phase, default_u_values):
|
||||
"""
|
||||
This method recommends room in roof insulation for properties that have been identified
|
||||
to possess a room in roof.
|
||||
|
|
@ -455,6 +455,8 @@ class RoofRecommendations:
|
|||
- Flat ceilings can be insulated like a standard loft.
|
||||
|
||||
:param u_value: Current u-value of the roof
|
||||
:param phase: Phase of the recommendation
|
||||
:param default_u_values: Use default u-values
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
|
@ -495,7 +497,7 @@ class RoofRecommendations:
|
|||
sap_points = rir_non_invasive_recommendation.get("sap_points", None)
|
||||
|
||||
# Could also be Roof room(s), ceiling insulated
|
||||
new_descriptin = "Pitched, insulated at rafters"
|
||||
new_descriptin = "Roof room(s), insulated"
|
||||
roof_ending_config = RoofAttributes(new_descriptin).process()
|
||||
roof_simulation_config = check_simulation_difference(
|
||||
new_config=roof_ending_config, old_config=self.property.roof, prefix="roof_"
|
||||
|
|
@ -505,6 +507,19 @@ class RoofRecommendations:
|
|||
else:
|
||||
new_efficiency = self.property.data["roof-energy-eff"]
|
||||
|
||||
if default_u_values:
|
||||
new_u_value = get_roof_u_value(
|
||||
insulation_thickness="average",
|
||||
has_dwelling_above=self.property.roof["has_dwelling_above"],
|
||||
is_loft=self.property.roof["is_loft"],
|
||||
is_roof_room=self.property.roof["is_roof_room"],
|
||||
is_thatched=self.property.roof["is_thatched"],
|
||||
age_band=self.property.age_band,
|
||||
is_flat=self.property.roof["is_flat"],
|
||||
is_pitched=self.property.roof["is_pitched"],
|
||||
is_at_rafters=self.property.roof["is_at_rafters"],
|
||||
)
|
||||
|
||||
simulation_config = {
|
||||
**roof_simulation_config,
|
||||
"roof_thermal_transmittance_ending": new_u_value,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class SolarPvRecommendations:
|
|||
MAX_SYSTEM_WATTAGE = 6000
|
||||
MIN_SYSTEM_WATTAGE = 1000
|
||||
|
||||
MAX_ROOF_AREA_PERCENTAGE = 0.7
|
||||
|
||||
def __init__(self, property_instance):
|
||||
"""
|
||||
:param property_instance: Instance of the Property class, for the home associated to property_id
|
||||
|
|
@ -187,15 +189,20 @@ class SolarPvRecommendations:
|
|||
)
|
||||
else:
|
||||
# TODO: There may be some instances where we don't want to use the solar API so we should cover for them
|
||||
panel_performance = self.property.solar_panel_configuration["panel_performance"]
|
||||
panel_performance = self.property.solar_panel_configuration["panel_performance"].copy()
|
||||
# We don't allow for more than 70% of the roof to be covered
|
||||
panel_performance = panel_performance[
|
||||
panel_performance["panneled_roof_area"] / self.property.roof_area <= self.MAX_ROOF_AREA_PERCENTAGE
|
||||
]
|
||||
|
||||
roof_area = self.property.roof_area
|
||||
solar_configurations = panel_performance.head(3).reset_index(drop=True)
|
||||
|
||||
# We combine each of these configurations with estimates with and without a battery
|
||||
for rank, recommendation_config in solar_configurations.iterrows():
|
||||
roof_coverage_percent = round(recommendation_config["panneled_roof_area"] / roof_area * 100)
|
||||
# We round up to the nearest 10
|
||||
roof_coverage_percent = np.ceil(roof_coverage_percent / 10) * 10
|
||||
# We round up to the nearest 5
|
||||
roof_coverage_percent = np.ceil(roof_coverage_percent / 5) * 5
|
||||
for has_battery in [False, True]:
|
||||
cost_result = self.costs.solar_pv(
|
||||
has_battery=has_battery,
|
||||
|
|
|
|||
|
|
@ -282,11 +282,14 @@ def get_u_value_from_s9(
|
|||
):
|
||||
"""Get the U-value from table S9 based on the insulation thickness."""
|
||||
|
||||
if thickness in ["below average", "average", "above average", "none", None, "0", 0] or (
|
||||
if thickness in ["below average", "average", "above average", "none", None] or (
|
||||
not is_loft and not is_roof_room and not is_at_rafters
|
||||
):
|
||||
return None
|
||||
|
||||
if thickness in [0, "0"] and is_loft:
|
||||
return None
|
||||
|
||||
# Determine the column to refer based on the roof type
|
||||
column = (
|
||||
"Thatched_roof_U_value_W_m2K"
|
||||
|
|
@ -294,8 +297,11 @@ def get_u_value_from_s9(
|
|||
else "Slates_or_tiles_U_value_W_m2K"
|
||||
)
|
||||
|
||||
# Get the correct U-value based on the insulation thickness
|
||||
return s9[s9["Insulation_thickness_mm"] >= thickness][column].iloc[0]
|
||||
if thickness in [0, "0"] and is_roof_room:
|
||||
return s9[pd.isnull(s9["Insulation_thickness_mm"])][column].iloc[0]
|
||||
else:
|
||||
# Get the correct U-value based on the insulation thickness
|
||||
return s9[s9["Insulation_thickness_mm"] >= thickness][column].iloc[0]
|
||||
|
||||
|
||||
def get_roof_u_value(
|
||||
|
|
|
|||
|
|
@ -39,15 +39,8 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 10.0, 'low-energy-fixed-light-count': 7.0, 'uprn': 100110195416.0,
|
||||
'uprn-source': 'Address Matched'
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
"Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and "
|
||||
"smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade "
|
||||
"scheme grant",
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
"Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & "
|
||||
"temperature zone control)"
|
||||
],
|
||||
"heating_measure_types": ["air_source_heat_pump"],
|
||||
"heating_controls_measure_types": ["time_temperature_zone_control"],
|
||||
"notes": "This property has a boiler, radiators & mains gas with good efficiency so the only recommendation"
|
||||
"we expect here is for an air source heat pump. The heating controls are a programmer, room thermostat"
|
||||
"and TRVs and so we should expect a TTZC recommendation"
|
||||
|
|
@ -93,11 +86,10 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 10012342725.0,
|
||||
'uprn-source': 'Address Matched',
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
"Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention "
|
||||
"Storage Heater Controls"
|
||||
"heating_measure_types": [
|
||||
"high_heat_retention_storage_heater",
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has electric room heaters and is off gas so a boiler recommendation is not appropriate."
|
||||
"We would expect a high heat retention storage recommendation. The property is a flat and therefore"
|
||||
"we don't expect an air source heat pump recommendation. We also wouldn't expect a specific heating"
|
||||
|
|
@ -144,16 +136,8 @@ testing_examples = [
|
|||
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': 6.0, 'low-energy-fixed-light-count': 4.0,
|
||||
'uprn': 100090311351.0, 'uprn-source': 'Address Matched', 'property-type_y': None, 'built-form_y': None,
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. The current electric heaters may be retrofit with '
|
||||
'high heat retention storage controls however this is dependent on the existing system and may not be '
|
||||
'possible. Upgrade heating controls to High Heat Retention Storage Heater Controls',
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant'
|
||||
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_measure_types": ['high_heat_retention_storage_heater', 'air_source_heat_pump'],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This test has electric storage heaters with automatic charge control - we recommend hhr storage"
|
||||
"heaters in this case, but because there are already electic storage heaters in place, we "
|
||||
"note, in the description of the recommendation, that this upgrade may be possible by retrofitting"
|
||||
|
|
@ -197,13 +181,10 @@ testing_examples = [
|
|||
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None,
|
||||
'uprn': 100021560521.0, 'uprn-source': 'Address Matched',
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler.'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
'Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & '
|
||||
'temperature zone control)'
|
||||
"heating_measure_types": ['boiler_upgrade'],
|
||||
"heating_controls_measure_types": [
|
||||
'roomstat_programmer_trvs',
|
||||
'time_temperature_zone_control',
|
||||
],
|
||||
"notes": "Because of this property is a maisonette, which already has a boiler (but an inefficient one due to "
|
||||
"the current water heating efficiency) the only recommendation we expect is for "
|
||||
|
|
@ -250,12 +231,10 @@ testing_examples = [
|
|||
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': 9.0, 'low-energy-fixed-light-count': 5.0,
|
||||
'uprn': 100021936225.0, 'uprn-source': 'Address Matched',
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
'Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & '
|
||||
'temperature zone control)'
|
||||
"heating_measure_types": [],
|
||||
"heating_controls_measure_types": [
|
||||
'roomstat_programmer_trvs',
|
||||
'time_temperature_zone_control',
|
||||
],
|
||||
"notes": "Because this property already has a boiler, we don't recommend HHR. We don't recommend an ashp "
|
||||
"because the home is mid-terraced. Because the heating controls are "
|
||||
|
|
@ -302,11 +281,10 @@ testing_examples = [
|
|||
'tenure': 'rental (private)', 'fixed-lighting-outlets-count': 7.0, 'low-energy-fixed-light-count': 6.0,
|
||||
'uprn': 43088770.0, 'uprn-source': 'Address Matched',
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property is a flat so we don't have an ASHP recommendation. It also doesn't have access to the "
|
||||
"mains and so it can't have a gas boiler. We don't expect any controls recommendations"
|
||||
},
|
||||
|
|
@ -348,16 +326,10 @@ testing_examples = [
|
|||
'tenure': 'owner-occupied', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None,
|
||||
'uprn': 100080513604.0, 'uprn-source': 'Address Matched'
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
'Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & '
|
||||
'temperature zone control)'
|
||||
|
||||
"heating_measure_types": ['air_source_heat_pump'],
|
||||
"heating_controls_measure_types": [
|
||||
'roomstat_programmer_trvs',
|
||||
'time_temperature_zone_control',
|
||||
],
|
||||
"notes": "This has a very efficient boiler and is a detached bungalow, but only has "
|
||||
"Programmer and room thermostat for heating controls so we'd expect an ASHP heating recommendation"
|
||||
|
|
@ -404,14 +376,12 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 10.0, 'low-energy-fixed-light-count': 9.0, 'uprn': 100070358594,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater',
|
||||
'boiler_upgrade'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has assumed electric heating and is mid-terrace house. It has a mains gas connection."
|
||||
"We can recommend a boiler upgrade and high heat retention storage heaters"
|
||||
},
|
||||
|
|
@ -453,15 +423,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 42.0, 'low-energy-fixed-light-count': 13.0, 'uprn': 100070985545,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has an oil boiler and doesn't have a mains gas connection so we can only recommend"
|
||||
"an air source heat pump and HHR (since if the home has a non-gas boiler, we recommend HHR)"
|
||||
},
|
||||
|
|
@ -505,17 +471,13 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 2465031849,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control)'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater',
|
||||
'air_source_heat_pump',
|
||||
'boiler_upgrade' # TTZs
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has room heaters, from the mains gas supply. We recommend a boiler upgrade as"
|
||||
"well as an air source heat pump and HHR (since the home has a room heater set up)"
|
||||
},
|
||||
|
|
@ -558,14 +520,12 @@ testing_examples = [
|
|||
'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has assumed electric heaters. Boiler upgrade, HHR are recommended. We don't recommend"
|
||||
"an ASHP off of the bat because it's mid-terrace."
|
||||
},
|
||||
|
|
@ -607,14 +567,12 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 10.0, 'low-energy-fixed-light-count': None, 'uprn': 100071089116,
|
||||
'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control)'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater',
|
||||
'boiler_upgrade'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This has a form of assumed electric heating and has a mains connection so we recommend HHR, boiler"
|
||||
"upgrade and ASHP"
|
||||
},
|
||||
|
|
@ -657,15 +615,12 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 100030352255,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)',
|
||||
'Install high heat retention electric storage heaters. The current electric heaters may be retrofit with '
|
||||
'high heat retention storage controls however this is dependent on the existing system and may not be '
|
||||
'possible. Upgrade heating controls to High Heat Retention Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property already has storage heaters with manual charge control. The home is mid terrace so"
|
||||
"the ashp is not suitable"
|
||||
},
|
||||
|
|
@ -709,14 +664,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 10009573249,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant'
|
||||
"heating_measure_types": [
|
||||
'high_heat_retention_storage_heater',
|
||||
'air_source_heat_pump',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has an LFG boiler but it doesn't have a mains gas connection so we can only recommend"
|
||||
"an air source heat pump and hhr storage"
|
||||
},
|
||||
|
|
@ -758,14 +710,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 8.0, 'low-energy-fixed-light-count': None, 'uprn': 10013181470,
|
||||
'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls',
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant'
|
||||
"heating_measure_types": [
|
||||
'high_heat_retention_storage_heater',
|
||||
'air_source_heat_pump',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has electric boilers in place, but does not have a mains connection so we don't "
|
||||
"recommend a boiler upgrade. We recommend HHR and ASHP"
|
||||
},
|
||||
|
|
@ -809,14 +758,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 11.0, 'low-energy-fixed-light-count': 7.0, 'uprn': 452047507,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has a dual fuel boiler and no mains gas connection. We recommend ASHP and HHR, but"
|
||||
"no gas condensing boiler"
|
||||
},
|
||||
|
|
@ -857,14 +803,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 16.0, 'low-energy-fixed-light-count': 4.0, 'uprn': 100030309413,
|
||||
'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has a coal boiler and no mains gas connection. We recommend ASHP and HHR, but"
|
||||
"no gas condensing boiler"
|
||||
},
|
||||
|
|
@ -908,15 +851,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 10007366417,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has a smokeless fuel boiler and no mains gas connection. We recommend ASHP and HHR, but"
|
||||
"no gas condensing boiler"
|
||||
},
|
||||
|
|
@ -958,15 +897,11 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 100030256931,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has a wood pellets boiler and no mains gas connection. We recommend ASHP and HHR, but"
|
||||
"no gas condensing boiler"
|
||||
},
|
||||
|
|
@ -1009,11 +944,10 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 10000460605,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'high_heat_retention_storage_heater',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This is an end-terrace house, without mains gas connection, so all we recommend is HHR"
|
||||
},
|
||||
{
|
||||
|
|
@ -1054,8 +988,8 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None, 'uprn': 100031045596,
|
||||
'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_measure_types": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property already has an ashp. We don't recommend any heating upgrades"
|
||||
},
|
||||
{
|
||||
|
|
@ -1095,17 +1029,12 @@ testing_examples = [
|
|||
'tenure': 'Rented (social)', 'fixed-lighting-outlets-count': 11.0, 'low-energy-fixed-light-count': None,
|
||||
'uprn': 90041166, 'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters alongside the boiler. The current electric heaters '
|
||||
'may be retrofit with high heat retention storage controls however this is dependent on the existing '
|
||||
'system and may not be possible. Upgrade heating controls to High Heat Retention Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
'Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & '
|
||||
'temperature zone control)'
|
||||
"heating_controls_measure_types": [
|
||||
'time_temperature_zone_control',
|
||||
],
|
||||
"notes": "This property has dual heating. A boiler and electric storage heaters. The heating is efficient so"
|
||||
"we recommend ASHP and HHR. We also recommend upgrading the heating controls for the boiler"
|
||||
|
|
@ -1147,20 +1076,14 @@ testing_examples = [
|
|||
'tenure': 'Rented (social)', 'fixed-lighting-outlets-count': 11.0, 'low-energy-fixed-light-count': None,
|
||||
'uprn': 90041166, 'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Upgrade the existing boiler to a new, more efficient condensing boiler. ',
|
||||
'Upgrade both the existing boiler to a new condensing boiler and upgrade storage heaters to high heat '
|
||||
'retention storage heaters.',
|
||||
'Install high heat retention electric storage heaters alongside the boiler. The current electric heaters '
|
||||
'may be retrofit with high heat retention storage controls however this is dependent on the existing '
|
||||
'system and may not be possible. Upgrade heating controls to High Heat Retention Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade+high_heat_retention_storage_heater',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [
|
||||
'Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & '
|
||||
'temperature zone control)'
|
||||
"heating_controls_measure_types": [
|
||||
'time_temperature_zone_control'
|
||||
],
|
||||
"notes": "This property is a modified version of the previous dual heating property, where we lower the"
|
||||
"starting heating efficiency so that we a combined heating upgrade to both the boiler and the electric"
|
||||
|
|
@ -1204,14 +1127,11 @@ testing_examples = [
|
|||
'tenure': 'rental (social)', 'fixed-lighting-outlets-count': None, 'low-energy-fixed-light-count': None,
|
||||
'uprn': 10009574286, 'uprn-source': 'Address Matched', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has anthracite heating without mains. "
|
||||
"We recommend ASHP and HHR, but no gas condensing boiler"
|
||||
},
|
||||
|
|
@ -1254,14 +1174,12 @@ testing_examples = [
|
|||
'fixed-lighting-outlets-count': 8.0, 'low-energy-fixed-light-count': None, 'uprn': 100031556691,
|
||||
'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has room heaters with two different fuel sources, so we recommend HHR, ASHP, and a "
|
||||
"boiler upgrade"
|
||||
},
|
||||
|
|
@ -1302,11 +1220,10 @@ testing_examples = [
|
|||
'uprn': 100070685908, 'uprn-source': 'Address Matched', 'sheating-energy-eff': None,
|
||||
'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property is a flag, without mains gas connection. Currently has underfloor electric heating"
|
||||
"so we recommend HHR"
|
||||
},
|
||||
|
|
@ -1348,17 +1265,13 @@ testing_examples = [
|
|||
'uprn': 100071209105, 'uprn-source': 'Address Matched', 'sheating-energy-eff': None,
|
||||
'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
|
||||
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
|
||||
'scheme grant',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)',
|
||||
'Install high heat retention electric storage heaters. Upgrade heating controls to High Heat Retention '
|
||||
'Storage Heater Controls'
|
||||
"heating_measure_types": [
|
||||
'air_source_heat_pump',
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade',
|
||||
'high_heat_retention_storage_heater'
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "The property has warm air electricaire heating, so we recommend ASHP and HHR. It also has a mains"
|
||||
"connection so we recommend a gas condensing boiler"
|
||||
},
|
||||
|
|
@ -1402,12 +1315,11 @@ testing_examples = [
|
|||
'uprn': 100070955137, 'uprn-source': 'Address Matched', 'sheating-energy-eff': None,
|
||||
'sheating-env-eff': None
|
||||
},
|
||||
"heating_recommendation_descriptions": [
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Room thermostat, programmer and TRVs',
|
||||
'Upgrade to a new condensing boiler. Upgrade heating controls to Smart Thermostats, room sensors and smart '
|
||||
'radiator valves (time & temperature zone control)'
|
||||
"heating_measure_types": [
|
||||
'boiler_upgrade',
|
||||
'boiler_upgrade',
|
||||
],
|
||||
"heating_controls_recommendation_descriptions": [],
|
||||
"heating_controls_measure_types": [],
|
||||
"notes": "This property has warm air mains gas heating, so we recommend a gas condensing boiler"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -96,19 +96,19 @@ class TestHeatingRecommendations:
|
|||
|
||||
recommender.recommend(has_cavity_or_loft_recommendations=False)
|
||||
|
||||
assert len(recommender.heating_recommendations) == len(test_case["heating_recommendation_descriptions"])
|
||||
assert len(recommender.heating_recommendations) == len(test_case["heating_measure_types"])
|
||||
assert (
|
||||
len(recommender.heating_control_recommendations) ==
|
||||
len(test_case["heating_controls_recommendation_descriptions"])
|
||||
len(test_case["heating_controls_measure_types"])
|
||||
)
|
||||
|
||||
# Check the exact descriptions
|
||||
# Check the exact measure types
|
||||
assert (
|
||||
{x["description"] for x in recommender.heating_recommendations} ==
|
||||
set(test_case["heating_recommendation_descriptions"])
|
||||
{x["measure_type"] for x in recommender.heating_recommendations} ==
|
||||
set(test_case["heating_measure_types"])
|
||||
)
|
||||
|
||||
assert (
|
||||
{x["description"] for x in recommender.heating_control_recommendations} ==
|
||||
set(test_case["heating_controls_recommendation_descriptions"])
|
||||
{x["measure_type"] for x in recommender.heating_control_recommendations} ==
|
||||
set(test_case["heating_controls_measure_types"])
|
||||
)
|
||||
|
|
|
|||
|
|
@ -231,6 +231,15 @@ class TestRecommendationUtils:
|
|||
expected_uvalue = test_case["uvalue"]
|
||||
inputs = test_case.copy()
|
||||
del inputs["uvalue"]
|
||||
# insulation_thickness = inputs["insulation_thickness"]
|
||||
# has_dwelling_above = inputs["has_dwelling_above"]
|
||||
# is_loft = inputs["is_loft"]
|
||||
# is_roof_room = inputs["is_roof_room"]
|
||||
# is_thatched = inputs["is_thatched"]
|
||||
# age_band = inputs["age_band"]
|
||||
# is_flat = inputs["is_flat"]
|
||||
# is_pitched = inputs["is_pitched"]
|
||||
# is_at_rafters = inputs["is_at_rafters"]
|
||||
uvalue = recommendation_utils.get_roof_u_value(**inputs)
|
||||
assert expected_uvalue == uvalue, f"Expected u value {expected_uvalue}, recieved {uvalue}"
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class TestRoofRecommendations:
|
|||
|
||||
def test_loft_insulation_recommendation_50mm_insulation(self):
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {"county": "Kent"}
|
||||
epc_record.prepared_epc = {"county": "Kent", "roof-energy-eff": "Very Poor"}
|
||||
property_instance2 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
|
||||
property_instance2.age_band = "F"
|
||||
property_instance2.insulation_floor_area = 100
|
||||
|
|
@ -63,7 +63,7 @@ class TestRoofRecommendations:
|
|||
assert roof_recommender2.recommendations[0]["parts"][0]["depth"] == 270
|
||||
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {"county": "Greater London Authority"}
|
||||
epc_record.prepared_epc = {"county": "Greater London Authority", "roof-energy-eff": "Very Poor"}
|
||||
property_instance3 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
|
||||
property_instance3.age_band = "F"
|
||||
property_instance3.insulation_floor_area = 100
|
||||
|
|
@ -89,7 +89,7 @@ class TestRoofRecommendations:
|
|||
|
||||
def test_loft_insulation_recommendation_150mm_insulation(self):
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {"county": "North East Lincolnshire"}
|
||||
epc_record.prepared_epc = {"county": "North East Lincolnshire", "roof-energy-eff": "Good"}
|
||||
property_instance4 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
|
||||
property_instance4.age_band = "F"
|
||||
property_instance4.insulation_floor_area = 100
|
||||
|
|
@ -117,7 +117,7 @@ class TestRoofRecommendations:
|
|||
assert roof_recommender4.recommendations[0]["parts"][0]["depth"] == 200
|
||||
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {"county": "Somerset"}
|
||||
epc_record.prepared_epc = {"county": "Somerset", "roof-energy-eff": "Good"}
|
||||
property_instance5 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
|
||||
property_instance5.age_band = "F"
|
||||
property_instance5.insulation_floor_area = 100
|
||||
|
|
@ -189,8 +189,8 @@ class TestRoofRecommendations:
|
|||
roof_recommender7.recommend(phase=0)
|
||||
|
||||
assert len(roof_recommender7.recommendations) == 1
|
||||
assert roof_recommender7.recommendations[0]["new_u_value"] == 0.23
|
||||
assert roof_recommender7.recommendations[0]["starting_u_value"] == 1.5
|
||||
assert roof_recommender7.recommendations[0]["new_u_value"] == 0.24
|
||||
assert roof_recommender7.recommendations[0]["starting_u_value"] == 2.3
|
||||
assert roof_recommender7.recommendations[0]["description"] == "Insulate room in roof at rafters and re-decorate"
|
||||
|
||||
def test_ceiling_insulated_room_in_roof(self):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue