Model/recommendations/VentilationRecommendations.py
2025-06-25 14:08:22 +01:00

124 lines
4.6 KiB
Python

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
"""
def __init__(
self,
property_instance: Property,
materials
):
self.property = property_instance
self.has_ventilaion = None
self.recommendation = None
self.materials = [part for part in materials if part["type"] == "mechanical_ventilation"]
def recommend(self, phase):
"""
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.property.identify_ventilation()
if self.property.has_ventilation:
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()
already_installed = "cavity_wall_insulation" in self.property.already_installed
estimated_cost = n_units * part[0]["total_cost"] if not already_installed else 0
labour_hours = 4 * n_units if not already_installed else 0
labour_days = 4 * n_units / 8.0 if not already_installed else 0
part[0]["total"] = estimated_cost
part[0]["quantity"] = n_units
part[0]["quantity_unit"] = "part"
# We recommend installing two mechanical ventilation systems
self.recommendation = [
{
"phase": phase,
"parts": part,
"type": part[0]["type"],
"measure_type": "mechanical_ventilation",
"description": f"Install {n_units} {part[0]['description']} units",
"starting_u_value": None,
"new_u_value": None,
"already_installed": already_installed,
"sap_points": 0,
"heat_demand": 0,
"kwh_savings": 0,
"co2_equivalent_savings": 0,
"energy_cost_savings": 0,
"total": estimated_cost,
# We use a very simple and rough estimate of 4 hours per unit
"labour_hours": labour_hours,
"labour_days": labour_days, # Assume 8 hour day
"simulation_config": {
"mechanical_ventilation_ending": "mechanical, extract only",
},
"description_simulation": {
"mechanical-ventilation": "mechanical, extract only"
}
}
]
def recommend_trickle_vents(self):
"""
This is not something that we can identify completely non-invasively, however a recommendation which may come
about as a result of an energy assessment is the installation of trickle vents. This function handles that
"""
trickle_vents_recommendation_config = next(
(r for r in self.property.non_invasive_recommendations if r["type"] == "trickle_vents"), {}
)
if not trickle_vents_recommendation_config:
return
description = (
"Install trickle vents on your windows" if
not trickle_vents_recommendation_config.get("description")
else trickle_vents_recommendation_config["description"]
)
return [
{
"phase": None,
"parts": [],
"type": "trickle_vents",
"measure_type": "trickle_vents",
"description": description,
"starting_u_value": None,
"new_u_value": None,
"already_installed": False,
"sap_points": 0,
"heat_demand": 0,
"kwh_savings": 0,
"co2_equivalent_savings": 0,
"energy_cost_savings": 0,
"total": trickle_vents_recommendation_config["cost"],
# We use a very simple and rough estimate of 4 hours per unit
"labour_hours": trickle_vents_recommendation_config.get("labour_hours", 8),
"labour_days": trickle_vents_recommendation_config.get("labour_days", 1), # Assume 8 hour day
"survey": True
}
]