mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
starting to tidy up tweaks to optimiser
This commit is contained in:
parent
7111f1a43a
commit
b35d021db9
6 changed files with 79 additions and 36 deletions
|
|
@ -3,7 +3,7 @@ STANDARD_BUILT_FORMS = {
|
|||
# Houses
|
||||
"end-terrace", "semi-detached", "detached", "mid-terrace",
|
||||
# Flats
|
||||
"ground floor", "mid-floor", "top-floor"
|
||||
"ground floor", "mid-floor", "top-floor", "basement"
|
||||
}
|
||||
|
||||
BUILT_FORM_MAPPINGS = {
|
||||
|
|
@ -16,5 +16,29 @@ BUILT_FORM_MAPPINGS = {
|
|||
'Maisonette': 'unknown',
|
||||
'Flat': 'unknown',
|
||||
'First Floor Flat General': 'mid-floor',
|
||||
'Bungalow (Semi)': 'semi-detached'
|
||||
'Bungalow (Semi)': 'semi-detached',
|
||||
|
||||
'Detached House': 'detached',
|
||||
'End Terraced House': 'end-terrace',
|
||||
'Studio (Ground floor)': 'ground floor',
|
||||
'Mid Terraced House': 'mid-terrace',
|
||||
'Ground Floor Flat': 'ground floor',
|
||||
'Semi Detached House': 'semi-detached',
|
||||
'Detached Property': 'detached',
|
||||
'Level not confirmed': 'unknown',
|
||||
'Bedsit': 'unknown',
|
||||
'Cottage': 'detached',
|
||||
'Terraced House': 'mid-terrace',
|
||||
'Studio (1st Floor)': 'ground floor',
|
||||
'Standard Maisonette': 'unknown',
|
||||
'Third Floor Flat or Above': 'top-floor',
|
||||
'Town House': 'end-terrace',
|
||||
'Guest room in a complex': 'unknown',
|
||||
'Back To Back House': 'mid-terrace',
|
||||
'PIMSS EMPTY': 'unknown',
|
||||
'Flat Basement': 'basement',
|
||||
'House': 'unknown',
|
||||
'Second Floor Flat': 'mid-floor',
|
||||
'First Floor Flat': 'ground floor',
|
||||
'Room Only': 'unknown'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,27 @@ PROPERTY_MAPPING = {
|
|||
'House (Mid terrace)': 'house',
|
||||
'Bungalow (Semi)': 'bungalow',
|
||||
'Ground Floor Flat General': 'flat',
|
||||
'House (Semi)': 'house'
|
||||
|
||||
'House (Semi)': 'house',
|
||||
'Detached House': 'house',
|
||||
'Bedsit': 'bedsit',
|
||||
'Terraced House': 'house',
|
||||
'Standard Maisonette': 'maisonette',
|
||||
'End Terraced House': 'house',
|
||||
'Third Floor Flat or Above': 'flat',
|
||||
'Town House': 'house',
|
||||
'Mid Terraced House': 'house',
|
||||
'Back To Back House': 'house',
|
||||
'Flat Basement': 'flat',
|
||||
'Ground Floor Flat': 'flat',
|
||||
'Semi Detached House': 'house',
|
||||
'Second Floor Flat': 'flat',
|
||||
'First Floor Flat': 'flat',
|
||||
'Level not confirmed': 'flat',
|
||||
'Cottage': 'house',
|
||||
'Studio (1st Floor)': 'flat',
|
||||
'Studio (Ground floor)': 'flat',
|
||||
'Guest room in a complex': 'other',
|
||||
'PIMSS EMPTY': 'bedsit',
|
||||
'Room Only': 'other',
|
||||
'Detached Property': 'house'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,5 +134,6 @@ WALL_CONSTRUCTION_MAPPINGS = {
|
|||
'Cavity CWI required': 'uninsulated cavity',
|
||||
'Solid brick EWI installed': 'insulated solid brick',
|
||||
'Cavity Cavity batts': 'filled cavity',
|
||||
'Cavity CWI Completed by Dyson': 'filled cavity'
|
||||
'Cavity CWI Completed by Dyson': 'filled cavity',
|
||||
None: "unknown"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,3 +59,9 @@ DESCRIPTIONS_TO_FUEL_TYPES = {
|
|||
"Boiler and radiators, coal": {"fuel": "Coal", "cop": 0.85},
|
||||
"From main system, no cylinderstat": {"fuel": "Natural Gas", "cop": 0.85},
|
||||
}
|
||||
|
||||
# These are the measure types where if there is a ventilation recommendation, we force the inclusion of it
|
||||
# if one of these has been recommended.
|
||||
measures_needing_ventilation = [
|
||||
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from backend.app.dependencies import validate_token
|
|||
from backend.app.plan.schemas import PlanTriggerRequest
|
||||
from backend.app.plan.utils import get_cleaned
|
||||
from backend.app.utils import epc_to_sap_lower_bound, sap_to_epc
|
||||
import backend.app.assumptions as assumptions
|
||||
|
||||
from backend.ml_models.api import ModelApi
|
||||
from backend.Property import Property
|
||||
|
|
@ -707,32 +708,25 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
# we need to double unlist because we have a list of lists
|
||||
property_measure_types = {rec["type"] for recs in recommendations[p.id] for rec in recs}
|
||||
|
||||
measures_to_optimise = recommendations[p.id]
|
||||
property_required_measures = []
|
||||
if body.required_measures:
|
||||
property_required_measures = [
|
||||
m for m in measures_to_optimise if m[0]["type"] in body.required_measures
|
||||
]
|
||||
measures_to_optimise = [
|
||||
m for m in measures_to_optimise if m[0]["type"] not in body.required_measures
|
||||
]
|
||||
property_required_measures = [
|
||||
m for m in recommendations[p.id] if m[0]["type"] in body.required_measures
|
||||
]
|
||||
measures_to_optimise = [
|
||||
m for m in recommendations[p.id] if m[0]["type"] not in body.required_measures
|
||||
]
|
||||
|
||||
# If we have a wall insulation measure, we MUST include mechanical ventilation
|
||||
# Additionally, if we have required measures, they should also be included. Therefore
|
||||
# we can discount the number of points required to get to the target SAP band (or increase)
|
||||
# in the case of ventilation
|
||||
measures_needing_ventilation = [
|
||||
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"
|
||||
]
|
||||
needs_ventilation = any(x in property_measure_types for x in measures_needing_ventilation)
|
||||
needs_ventilation = any(x in property_measure_types for x in assumptions.measures_needing_ventilation)
|
||||
|
||||
input_measures = prepare_input_measures(
|
||||
measures_to_optimise, body.goal, needs_ventilation, measures_needing_ventilation
|
||||
)
|
||||
input_measures = prepare_input_measures(measures_to_optimise, body.goal, needs_ventilation)
|
||||
|
||||
if not input_measures[0]:
|
||||
# This means that we have no defaults
|
||||
selected_recommendations = {}
|
||||
solution = []
|
||||
else:
|
||||
|
||||
fixed_gain = 0
|
||||
|
|
@ -755,7 +749,7 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
# if the property needs ventilation, but the measure we optimise didn't include
|
||||
# venilation we add the points for ventilation as a fixed gain
|
||||
if needs_ventilation and any(
|
||||
r in property_required_measure_types for r in measures_needing_ventilation
|
||||
r in property_required_measure_types for r in assumptions.measures_needing_ventilation
|
||||
):
|
||||
fixed_gain += next(
|
||||
(r[0]["sap_points"] for r in recommendations[p.id] if
|
||||
|
|
@ -823,9 +817,7 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
)
|
||||
|
||||
# If wall insulation is selected, we also include mechanical ventilation as a best practice measure
|
||||
if any(x in [r["type"] for r in solution] for x in [
|
||||
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"
|
||||
]):
|
||||
if any(x in [r["type"] for r in solution] for x in assumptions.measures_needing_ventilation):
|
||||
ventilation_rec = next(
|
||||
(r[0] for r in recommendations[p.id] if r[0]["type"] == "mechanical_ventilation"),
|
||||
None
|
||||
|
|
@ -854,14 +846,9 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
]
|
||||
|
||||
# We'll also unlist the recommendations so they're a bit easier to handle from here onwards
|
||||
final_recommendations = [
|
||||
recommendations[p.id] = [
|
||||
rec for recommendations_by_type in final_recommendations for rec in recommendations_by_type
|
||||
]
|
||||
# Get defaults
|
||||
defaults = [r for r in final_recommendations if r["default"]]
|
||||
sum([r['sap_points'] for r in defaults])
|
||||
|
||||
recommendations[p.id] = final_recommendations
|
||||
|
||||
# when we have buildings, we tweak our solar PV recommendations as if one unit needs it, we apply it to all
|
||||
# of them
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
def prepare_input_measures(property_recommendations, goal, needs_ventilation, measures_needing_ventilation):
|
||||
import backend.app.assumptions as assumptions
|
||||
|
||||
|
||||
def prepare_input_measures(property_recommendations, goal, needs_ventilation):
|
||||
"""
|
||||
Basic function to convert recommendations_to_upload to a format that is
|
||||
suitable for the optimiser - large
|
||||
|
|
@ -6,7 +9,6 @@ def prepare_input_measures(property_recommendations, goal, needs_ventilation, me
|
|||
:param goal: goal to be optimised for, should be one of the keys in gain_map. E.g. if the gain is SAP points,
|
||||
the goal should reflect that desired gain
|
||||
:param needs_ventilation: boolean to indicate if the property needs ventilation
|
||||
:param measures_needing_ventilation: list of measures that need ventilation
|
||||
:return: Nested list of input measures
|
||||
"""
|
||||
|
||||
|
|
@ -44,18 +46,20 @@ def prepare_input_measures(property_recommendations, goal, needs_ventilation, me
|
|||
for rec in recs:
|
||||
# We bundle the impact of ventilation with the measure
|
||||
total = (
|
||||
rec["total"] + ventilation_recommendation["total"] if rec["type"] in measures_needing_ventilation
|
||||
rec["total"] + ventilation_recommendation["total"]
|
||||
if rec["type"] in assumptions.measures_needing_ventilation
|
||||
else rec["total"]
|
||||
)
|
||||
gain = (
|
||||
rec[goal_key] + ventilation_recommendation[goal_key] if rec["type"] in measures_needing_ventilation
|
||||
rec[goal_key] + ventilation_recommendation[goal_key]
|
||||
if rec["type"] in assumptions.measures_needing_ventilation
|
||||
else rec[goal_key]
|
||||
)
|
||||
|
||||
rec_type = (
|
||||
"+".join(
|
||||
[rec["type"], ventilation_recommendation["type"]]
|
||||
) if rec["type"] in measures_needing_ventilation
|
||||
) if rec["type"] in assumptions.measures_needing_ventilation
|
||||
else rec["type"]
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue