diff --git a/.idea/Model.iml b/.idea/Model.iml
index b0f9c00d..4413bb06 100644
--- a/.idea/Model.iml
+++ b/.idea/Model.iml
@@ -7,7 +7,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index ca0e1cd9..3b05c6ac 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/backend/app/db/models/materials.py b/backend/app/db/models/materials.py
index 09d7369d..cf6dd971 100644
--- a/backend/app/db/models/materials.py
+++ b/backend/app/db/models/materials.py
@@ -13,6 +13,7 @@ class MaterialType(enum.Enum):
external_wall_insulation = "external_wall_insulation"
internal_wall_insulation = "internal_wall_insulation"
cavity_wall_insulation = "cavity_wall_insulation"
+ mechanical_ventilation = "mechanical_ventilation"
class DepthUnit(enum.Enum):
@@ -21,6 +22,7 @@ class DepthUnit(enum.Enum):
class CostUnit(enum.Enum):
gbp_sq_meter = "gbp_sq_meter"
+ gbp_per_unit = "gbp_per_unit"
class RValueUnit(enum.Enum):
diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py
index 400b2dee..135b877d 100644
--- a/backend/app/plan/router.py
+++ b/backend/app/plan/router.py
@@ -30,6 +30,7 @@ from backend.Property import Property
from etl.epc.DataProcessor import DataProcessor
from etl.epc.settings import COLUMNS_TO_MERGE_ON
from recommendations.FloorRecommendations import FloorRecommendations
+from recommendations.VentilationRecommendations import VentilationRecommendations
from recommendations.optimiser.CostOptimiser import CostOptimiser
from recommendations.optimiser.GainOptimiser import GainOptimiser
from recommendations.optimiser.optimiser_functions import prepare_input_measures
@@ -125,9 +126,6 @@ async def trigger_plan(body: PlanTriggerRequest):
#
# with open("cleaned.pickle", "rb") as f:
# cleaned = pickle.load(f)
- #
- # with open("materials_by_type.pickle", "wb") as f:
- # materials_by_type = pickle.load(f)
recommendations = {}
recommendations_scoring_data = []
@@ -160,6 +158,16 @@ async def trigger_plan(body: PlanTriggerRequest):
if wall_recomender.recommendations:
property_recommendations.append(wall_recomender.recommendations)
+ # Ventilation recommendations
+ ventilation_recomender = VentilationRecommendations(
+ property_instance=p,
+ materials=materials_by_type["ventilation"]
+ )
+ ventilation_recomender.recommend()
+
+ if ventilation_recomender.recommendation:
+ property_recommendations.append(ventilation_recomender.recommendation)
+
# We insert temporary ids into the recommendations which is important for the optimiser later
property_recommendations = insert_temp_recommendation_id(property_recommendations)
diff --git a/backend/app/plan/utils.py b/backend/app/plan/utils.py
index 85a02b61..0a1eaa72 100644
--- a/backend/app/plan/utils.py
+++ b/backend/app/plan/utils.py
@@ -15,7 +15,8 @@ def filter_materials(materials):
mapping = {
"walls": ["internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"],
- "floor": ["suspended_floor_insulation", "solid_floor_insulation"]
+ "floor": ["suspended_floor_insulation", "solid_floor_insulation"],
+ "ventilation": ["mechanical_ventilation"],
}
materials = [row2dict(material) for material in materials]
@@ -164,9 +165,13 @@ def create_recommendation_scoring_data(
if scoring_dict["floor_insulation_thickness_ENDING"] is None:
scoring_dict["floor_insulation_thickness_ENDING"] = "none"
- if recommendation["type"] not in ["wall_insulation", "floor_insulation"]:
+ if recommendation["type"] == "mechanical_ventilation":
+ scoring_dict["MECHANICAL_VENTILATION_ENDING"] = 'mechanical, extract only'
+
+ if recommendation["type"] not in ["wall_insulation", "floor_insulation", "mechanical_ventilation"]:
raise NotImplementedError("Implement me")
+ # Fill missing roof u-values - this fill is not based on recommended upgrades
if scoring_dict["roof_thermal_transmittance_ENDING"] is None:
scoring_dict["roof_thermal_transmittance_ENDING"] = get_roof_u_value(
insulation_thickness=property.roof["insulation_thickness"],
diff --git a/recommendations/VentilationRecommendations.py b/recommendations/VentilationRecommendations.py
new file mode 100644
index 00000000..35de9b3b
--- /dev/null
+++ b/recommendations/VentilationRecommendations.py
@@ -0,0 +1,70 @@
+import pandas as pd
+from BaseUtility import Definitions
+from backend.Property import Property
+
+
+class VentilationRecommendations(Definitions):
+ """
+ For properties that do not have ventilation, we recommend installing ventilaion
+ This is particularly important for properties that have insulated walls and is also
+ crucial for prevent overheating risks in warmer months
+ """
+
+ VENTILATION_DESCRIPTIONS = [
+ 'mechanical, extract only',
+ 'mechanical, supply and extract'
+ ]
+
+ def __init__(
+ self,
+ property_instance: Property,
+ materials
+ ):
+ self.property = property_instance
+
+ self.has_ventilaion = None
+ self.recommendation = None
+ self.materials = materials
+
+ def identify_ventilation(self):
+ self.has_ventilaion = self.property.data["mechanical-ventilation"] in self.VENTILATION_DESCRIPTIONS
+
+ def recommend(self):
+ """
+ If there is no ventilation, we recommend installing ventilation
+
+ Generally, best practice is to install controlled ventilation for insulated walls so we still recommend
+ ventilation if there is natural ventilation
+ :return:
+ """
+
+ self.identify_ventilation()
+ if self.has_ventilaion:
+ return
+
+ if len(self.materials) != 1:
+ raise NotImplementedError("Only handled the case of having one venilation option")
+
+ # We recommend installing 2 units
+ n_units = 2
+
+ part = self.materials.copy()
+
+ estimated_cost = n_units * part[0]["cost"]
+
+ part[0]["estimated_cost"] = estimated_cost
+ part[0]["quantity"] = n_units
+ part[0]["quantity_unit"] = None
+
+ # We recommend installing two mechanical ventilation systems
+ self.recommendation = [
+ {
+ "parts": part,
+ "type": part[0]["type"],
+ "description": "Install %s" % part[0]["description"],
+ "starting_u_value": None,
+ "new_u_value": None,
+ "sap_points": None,
+ "cost": estimated_cost,
+ }
+ ]
diff --git a/recommendations/WallRecommendations.py b/recommendations/WallRecommendations.py
index b3eea7e0..ad2ca861 100644
--- a/recommendations/WallRecommendations.py
+++ b/recommendations/WallRecommendations.py
@@ -1,4 +1,3 @@
-import itertools
import math
from typing import List