Added in logic to allow both external and internal wall insulation as options. Currently lots of recommendation combinations can come through however we will trim them later and make them more relevant to the customer

This commit is contained in:
Khalim Conn-Kowlessar 2023-06-21 12:13:35 +01:00
parent 9965767ae6
commit ee91c8244b

View file

@ -1,8 +1,10 @@
import pint
import re
import itertools
from model_data.Property import Property
import pandas as pd
from copy import deepcopy
external_wall_insulation_parts = [
{
@ -184,6 +186,8 @@ class WallRecommendations:
YEAR_WALLS_BUILT_WITH_INSULATION = 1990
U_VALUE_UNIT = 'w/m-¦k'
BUILDING_REGULATIONS_PART_L_MAX_U_VALUE = 0.18
# Often cited minimum practical u-value
DIMINISHING_RETURNS_U_VALUE = 0.15
# Add some error so that if, for example, a new part we recommend provides a u-value of 0.19,
# we still consider it as an option
@ -229,6 +233,7 @@ class WallRecommendations:
is_cavity_wall = self.property.walls["is_cavity_wall"]
is_solid_brick = self.property.walls["is_solid_brick"]
insulation_thickness = self.property.walls["insulation_thickness"]
if u_value:
if self.property.walls["thermal_transmittance_unit"] != self.U_VALUE_UNIT:
@ -252,17 +257,22 @@ class WallRecommendations:
}
)
if is_solid_brick:
if is_solid_brick and insulation_thickness == "none":
# TODO: what if we recommend both internal and external wall insulation? Individually, they might not
# get the wall to the required u-value, but together they might. We need to handle this case
# This is an estimated figure based on industry standards
u_value = self.DEFAULT_U_VALUES["solid_brick"]
# Recommend external and internal wall insulation
part_types = ["external_wall_insulation", "internal_wall_insulation"] if not self.in_converation_area else \
["internal_wall_insulation"]
ewi_parts = [
part for part in wall_parts if part["type"] == "external_wall_insulation"
] if not self.in_converation_area else []
parts = [part for part in wall_parts if part["type"] in part_types]
for part in parts:
iwi_parts = [part for part in wall_parts if part["type"] == "internal_wall_insulation"]
# Recommend external and internal wall insulation separately
for part in ewi_parts + iwi_parts:
for depth in part["depths"]:
part_u_value = self.r_value_per_mm_to_u_value(depth, part["r_value_per_mm"])
@ -270,17 +280,63 @@ class WallRecommendations:
_, new_u_value = self.calculate_u_value_uplift(u_value, part_u_value)
new_u_value = round(new_u_value, 2)
if new_u_value < self.DIMINISHING_RETURNS_U_VALUE:
# We don't recommend an overkill solution
continue
# We allow a small tolerance for error so we don't discount the recommendation entirely
# if it's close, since this is an estimated new u-value
if new_u_value - self.U_VALUE_ERROR <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE:
self.recommendations.append(
{
**part, "new_u_value": new_u_value,
}
self._get_recommended_part(part, depth, new_u_value)
)
# We also can recommend both internal and external wall insulation together
for ewi_part in ewi_parts:
for iwi_part in iwi_parts:
for ewi_depth, iwi_depth in itertools.product(ewi_part["depths"], iwi_part["depths"]):
ewi_part_u_value = self.r_value_per_mm_to_u_value(ewi_depth, ewi_part["r_value_per_mm"])
iwi_part_u_value = self.r_value_per_mm_to_u_value(iwi_depth, iwi_part["r_value_per_mm"])
# First calculate the new U-value after applying external wall insulation
_, ewi_new_u_value = self.calculate_u_value_uplift(u_value, ewi_part_u_value)
# Then calculate the new U-value after applying internal wall insulation
_, combined_new_u_value = self.calculate_u_value_uplift(ewi_new_u_value, iwi_part_u_value)
combined_new_u_value = round(combined_new_u_value, 2)
if combined_new_u_value < self.DIMINISHING_RETURNS_U_VALUE:
# We don't recommend an overkill solution
continue
# Check if the combined new U-value meets the requirement
if combined_new_u_value - self.U_VALUE_ERROR <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE:
# Here you might want to define a way to add both recommendations together.
# For now, I'm adding them as separate items in the list
recommendation = [
self._get_recommended_part(ewi_part, ewi_depth, combined_new_u_value),
self._get_recommended_part(iwi_part, iwi_depth, combined_new_u_value)
]
self.recommendations.append(recommendation)
raise NotImplementedError("Not implemented yet")
@staticmethod
def _get_recommended_part(part, selected_depth, new_u_value):
"""
Utility function to return a recommended part with the selected depth.
:param part:
:param selected_depth:
:param new_u_value:
:return:
"""
recommended_part = deepcopy(part)
recommended_part["depths"] = [selected_depth]
return {
**recommended_part, "new_u_value": new_u_value,
}
@staticmethod
def calculate_u_value_uplift(u_value, insulation_u_value):
"""