mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +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
|
# Houses
|
||||||
"end-terrace", "semi-detached", "detached", "mid-terrace",
|
"end-terrace", "semi-detached", "detached", "mid-terrace",
|
||||||
# Flats
|
# Flats
|
||||||
"ground floor", "mid-floor", "top-floor"
|
"ground floor", "mid-floor", "top-floor", "basement"
|
||||||
}
|
}
|
||||||
|
|
||||||
BUILT_FORM_MAPPINGS = {
|
BUILT_FORM_MAPPINGS = {
|
||||||
|
|
@ -16,5 +16,29 @@ BUILT_FORM_MAPPINGS = {
|
||||||
'Maisonette': 'unknown',
|
'Maisonette': 'unknown',
|
||||||
'Flat': 'unknown',
|
'Flat': 'unknown',
|
||||||
'First Floor Flat General': 'mid-floor',
|
'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',
|
'House (Mid terrace)': 'house',
|
||||||
'Bungalow (Semi)': 'bungalow',
|
'Bungalow (Semi)': 'bungalow',
|
||||||
'Ground Floor Flat General': 'flat',
|
'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',
|
'Cavity CWI required': 'uninsulated cavity',
|
||||||
'Solid brick EWI installed': 'insulated solid brick',
|
'Solid brick EWI installed': 'insulated solid brick',
|
||||||
'Cavity Cavity batts': 'filled cavity',
|
'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},
|
"Boiler and radiators, coal": {"fuel": "Coal", "cop": 0.85},
|
||||||
"From main system, no cylinderstat": {"fuel": "Natural Gas", "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.schemas import PlanTriggerRequest
|
||||||
from backend.app.plan.utils import get_cleaned
|
from backend.app.plan.utils import get_cleaned
|
||||||
from backend.app.utils import epc_to_sap_lower_bound, sap_to_epc
|
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.ml_models.api import ModelApi
|
||||||
from backend.Property import Property
|
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
|
# 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}
|
property_measure_types = {rec["type"] for recs in recommendations[p.id] for rec in recs}
|
||||||
|
|
||||||
measures_to_optimise = recommendations[p.id]
|
property_required_measures = [
|
||||||
property_required_measures = []
|
m for m in recommendations[p.id] if m[0]["type"] in body.required_measures
|
||||||
if body.required_measures:
|
]
|
||||||
property_required_measures = [
|
measures_to_optimise = [
|
||||||
m for m in measures_to_optimise if m[0]["type"] in body.required_measures
|
m for m in recommendations[p.id] if m[0]["type"] not in body.required_measures
|
||||||
]
|
]
|
||||||
measures_to_optimise = [
|
|
||||||
m for m in measures_to_optimise if m[0]["type"] not in body.required_measures
|
|
||||||
]
|
|
||||||
|
|
||||||
# If we have a wall insulation measure, we MUST include mechanical ventilation
|
# If we have a wall insulation measure, we MUST include mechanical ventilation
|
||||||
# Additionally, if we have required measures, they should also be included. Therefore
|
# 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)
|
# we can discount the number of points required to get to the target SAP band (or increase)
|
||||||
# in the case of ventilation
|
# in the case of ventilation
|
||||||
measures_needing_ventilation = [
|
needs_ventilation = any(x in property_measure_types for x in assumptions.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)
|
|
||||||
|
|
||||||
input_measures = prepare_input_measures(
|
input_measures = prepare_input_measures(measures_to_optimise, body.goal, needs_ventilation)
|
||||||
measures_to_optimise, body.goal, needs_ventilation, measures_needing_ventilation
|
|
||||||
)
|
|
||||||
|
|
||||||
if not input_measures[0]:
|
if not input_measures[0]:
|
||||||
# This means that we have no defaults
|
# This means that we have no defaults
|
||||||
selected_recommendations = {}
|
selected_recommendations = {}
|
||||||
|
solution = []
|
||||||
else:
|
else:
|
||||||
|
|
||||||
fixed_gain = 0
|
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
|
# if the property needs ventilation, but the measure we optimise didn't include
|
||||||
# venilation we add the points for ventilation as a fixed gain
|
# venilation we add the points for ventilation as a fixed gain
|
||||||
if needs_ventilation and any(
|
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(
|
fixed_gain += next(
|
||||||
(r[0]["sap_points"] for r in recommendations[p.id] if
|
(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 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 [
|
if any(x in [r["type"] for r in solution] for x in assumptions.measures_needing_ventilation):
|
||||||
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"
|
|
||||||
]):
|
|
||||||
ventilation_rec = next(
|
ventilation_rec = next(
|
||||||
(r[0] for r in recommendations[p.id] if r[0]["type"] == "mechanical_ventilation"),
|
(r[0] for r in recommendations[p.id] if r[0]["type"] == "mechanical_ventilation"),
|
||||||
None
|
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
|
# 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
|
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
|
# when we have buildings, we tweak our solar PV recommendations as if one unit needs it, we apply it to all
|
||||||
# of them
|
# 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
|
Basic function to convert recommendations_to_upload to a format that is
|
||||||
suitable for the optimiser - large
|
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,
|
: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
|
the goal should reflect that desired gain
|
||||||
:param needs_ventilation: boolean to indicate if the property needs ventilation
|
: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
|
:return: Nested list of input measures
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -44,18 +46,20 @@ def prepare_input_measures(property_recommendations, goal, needs_ventilation, me
|
||||||
for rec in recs:
|
for rec in recs:
|
||||||
# We bundle the impact of ventilation with the measure
|
# We bundle the impact of ventilation with the measure
|
||||||
total = (
|
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"]
|
else rec["total"]
|
||||||
)
|
)
|
||||||
gain = (
|
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]
|
else rec[goal_key]
|
||||||
)
|
)
|
||||||
|
|
||||||
rec_type = (
|
rec_type = (
|
||||||
"+".join(
|
"+".join(
|
||||||
[rec["type"], ventilation_recommendation["type"]]
|
[rec["type"], ventilation_recommendation["type"]]
|
||||||
) if rec["type"] in measures_needing_ventilation
|
) if rec["type"] in assumptions.measures_needing_ventilation
|
||||||
else rec["type"]
|
else rec["type"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue