From aa64859706e5f6b807ad5489deb1b2e080592511 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 20 Sep 2023 15:16:20 +0100 Subject: [PATCH] moved new functions to correct places --- model_data/cleaner_app.py | 255 +----------------------- recommendations/rdsap_tables.py | 182 +++++++++++++++++ recommendations/recommendation_utils.py | 60 +++++- 3 files changed, 242 insertions(+), 255 deletions(-) diff --git a/model_data/cleaner_app.py b/model_data/cleaner_app.py index 26fc0ac5..5c895091 100644 --- a/model_data/cleaner_app.py +++ b/model_data/cleaner_app.py @@ -79,262 +79,9 @@ def app(): # Finally, we attach u-values to the descriptions for walls, roofs and floors - wall_types = [ - "Stone: granite or whinstone as built", - "Stone: sandstone or limestone as built", - "Solid brick as built", - "Stone/solid brick with 50 mm external or internal insulation", - "Stone/solid brick with 100 mm external or internal insulation", - "Stone/solid brick with 150 mm external or internal insulation", - "Stone/solid brick with 200 mm external or internal insulation", - "Cob as built", - "Cob with 50 mm external or internal insulation", - "Cob with 100 mm external or internal insulation", - "Cob with 150 mm external or internal insulation", - "Cob with 200 mm external or internal insulation", - "Cavity as built", - "Unfilled cavity with 50 mm external or internal insulation", - "Unfilled cavity with 100 mm external or internal insulation", - "Unfilled cavity with 150 mm external or internal insulation", - "Unfilled cavity with 200 mm external or internal insulation", - "Filled cavity", - "Filled cavity with 50 mm external or internal insulation", - "Filled cavity with 100 mm external or internal insulation", - "Filled cavity with 150 mm external or internal insulation", - "Filled cavity with 200 mm external or internal insulation", - "Timber frame as built", - "Timber frame with internal insulation", - "System build as built", - "System build with 50 mm external or internal insulation", - "System build with 100 mm external or internal insulation", - "System build with 150 mm external or internal insulation", - "System build with 200 mm external or internal insulation", - ] - - u_values = [ - ["a", "a", "a", "a", "1.7b", "1.0", "0.6", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["a", "a", "a", "a", "1.7b", "1.0", "0.6", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["1.7", "1.7", "1.7", "1.7", "1.7", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["0.55", "0.55", "0.55", "0.55", "0.55", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], - ["0.32", "0.32", "0.32", "0.32", "0.32", "0.28", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], - ["0.23", "0.23", "0.23", "0.23", "0.23", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], - ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], - ["0.80", "0.80", "0.80", "0.80", "0.80", "0.80", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["0.40", "0.40", "0.40", "0.40", "0.40", "0.40", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], - ["0.26", "0.26", "0.26", "0.26", "0.26", "0.26", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], - ["0.20", "0.20", "0.20", "0.20", "0.20", "0.20", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], - ["0.16", "0.16", "0.16", "0.16", "0.16", "0.16", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], - ["1.5", "1.5", "1.5", "1.5", "1.5", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["0.53", "0.53", "0.53", "0.53", "0.53", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], - ["0.32", "0.32", "0.32", "0.32", "0.32", "0.30", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], - ["0.23", "0.23", "0.23", "0.23", "0.23", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], - ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], - ["0.7", "0.7", "0.7", "0.7", "0.7", "0.40", "0.35", "0.35", "0.45", "0.35", "0.30", "0.28"], - ["0.37", "0.37", "0.37", "0.37", "0.37", "0.27", "0.25", "0.25", "0.25", "0.25", "0.21", "0.21"], - ["0.25", "0.25", "0.25", "0.25", "0.25", "0.20", "0.19", "0.19", "0.19", "0.19", "0.17", "0.16"], - ["0.19", "0.19", "0.19", "0.19", "0.19", "0.16", "0.15", "0.15", "0.15", "0.15", "0.14", "0.14"], - ["0.16", "0.16", "0.16", "0.16", "0.16", "0.13", "0.13", "0.13", "0.13", "0.13", "0.12", "0.12"], - ["2.5", "1.9", "1.9", "1.0", "0.80", "0.45", "0.40", "0.40", "0.40", "0.35", "0.30", "0.28"], - ["0.60", "0.55", "0.55", "0.40", "0.40", "0.40", "0.40", "0.40", "0.40", "0.35", "0.30", "0.28"], - ["2.0", "2.0", "2.0", "2.0", "1.7", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], - ["0.60", "0.60", "0.60", "0.60", "0.55", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], - ["0.35", "0.35", "0.35", "0.35", "0.35", "0.32", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], - ["0.25", "0.25", "0.25", "0.25", "0.25", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], - ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], - ] - - age_bands = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"] - - wall_uvalues = [] - for i, wall_type in enumerate(wall_types): - row = {"Wall_type": wall_type} - for j, age_band in enumerate(age_bands): - row[age_band] = u_values[i][j] - wall_uvalues.append(row) - - parkhome_wall_uvalues = [ - {"Wall_type": "Park home as built", "F": "1.7", "G": "1.2", "I": "0.7", "K": "0.6"}, - {"Wall_type": "Park home with additional insulation", "F": "s1.1.2", "G": "s1.1.2", "I": "s1.1.2", - "K": "s1.1.2"} - ] - - wall_uvalues.extend(parkhome_wall_uvalues) - - wall_uvalues_df = pd.DataFrame(wall_uvalues) - - # This maps the descriptions in the EPC data to the descriptions in the table - epc_wall_description_map = { - ############################ - # Cavity wall mappings - ############################ - "Cavity wall, as built, partial insulation": "Filled cavity", - "Cavity wall, filled cavity": "Filled cavity", - "Cavity wall, as built, no insulation": "Cavity as built", - "Cavity wall, as built, insulated": "Unfilled cavity with 100 mm external or internal insulation", - "Cavity wall, with external insulation": "Unfilled cavity with 100 mm external or internal insulation", - "Cavity wall, insulated": "Unfilled cavity with 100 mm external or internal insulation", - 'Cavity wall, partial insulation': "Unfilled cavity with 50 mm external or internal insulation", - - "Cavity wall,": "Cavity as built", # General case of cavity wall without further details - "Cavity wall, filled cavity and external insulation": - "Filled cavity with 100 mm external or internal insulation", - "Cavity wall, filled cavity and internal insulation": - "Filled cavity with 100 mm external or internal insulation", - "Cavity wall, with internal insulation": "Unfilled cavity with 100 mm external or internal insulation", - "Cavity wall, no insulation": "Cavity as built", - - ############################ - # Solid brick wall mappings - ############################ - "Solid brick, as built, no insulation": "Solid brick as built", - "Solid brick, with internal insulation": "Stone/solid brick with 100 mm external or internal insulation", - "Solid brick, as built, insulated": "Stone/solid brick with 100 mm external or internal insulation", - "Solid brick, with external insulation": "Stone/solid brick with 100 mm external or internal insulation", - "Solid brick, as built, partial insulation": "Stone/solid brick with 50 mm external or internal insulation", - - ############################ - # Timber frame wall mappings - ############################ - # These mappings are perhaps the most dubious due to the lack of timber options in the RdSAP table - "Timber frame, as built, insulated": "Timber frame with internal insulation", - "Timber frame, with additional insulation": "Timber frame with internal insulation", - "Timber frame, as built, partial insulation": "Timber frame as built", - "Timber frame, as built, no insulation": "Timber frame as built", - "Timber frame, with external insulation": "Timber frame with internal insulation", - - ############################ - # Sandstone/limestones wall mappings - ############################ - "Sandstone or limestone, as built, no insulation": "Stone: sandstone or limestone as built", - "Sandstone or limestone, with internal insulation": - "Stone/solid brick with 100 mm external or internal insulation", - "Sandstone or limestone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal " - "insulation", - "Sandstone, as built, no insulation": "Stone: sandstone or limestone as built", - "Sandstone or limestone, as built, insulated": - "Stone/solid brick with 100 mm external or internal insulation", - "Sandstone, as built, insulated": "Stone/solid brick with 100 mm external or internal insulation", - "Sandstone, with internal insulation": "Stone/solid brick with 100 mm external or internal insulation", - "Sandstone or limestone, with external insulation": "Stone/solid brick with 100 mm external or internal " - "insulation", - "Sandstone, with external insulation": "Stone/solid brick with 100 mm external or internal insulation", - "Sandstone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal insulation", - - ############################ - # Granite/whinstone wall mappings - ############################ - "Granite or whinstone, as built, no insulation": "Stone: granite or whinstone as built", - "Granite or whinstone, with internal insulation": "Stone/solid brick with 100 mm external or internal " - "insulation", - "Granite or whinstone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal " - "insulation", - "Granite or whinstone, as built, insulated": "Stone/solid brick with 100 mm external or internal " - "insulation", - "Granite or whinstone, with external insulation": "Stone/solid brick with 100 mm external or internal " - "insulation", - - ############################ - # System built wall mappings - ############################ - "System built, as built, no insulation": "System build as built", - "System built, as built, partial insulation": "System build with 50 mm external or internal insulation", - "System built, with internal insulation": "System build with 100 mm external or internal insulation", - "System built, with external insulation": "System build with 100 mm external or internal insulation", - "System built, as built, insulated": "System build with 100 mm external or internal insulation", - - ############################ - # Cob wall mappings - ############################ - "Cob, as built": "Cob as built", - "Cob, with external insulation": "Cob with 100 mm external or internal insulation", - "Cob, with internal insulation": "Cob with 100 mm external or internal insulation", - 'Cob,': "Cob as built", - - ############################ - # Park home mappings - ############################ - "Park home wall, as built": "Park home as built", - "Park home wall, with external insulation": "Park home with additional insulation", - "Park home wall, with internal insulation": "Park home with additional insulation", - } - - from recommendations.rdsap_tables import default_wall_thickness - - def apply_formula_s_5_1_1(is_granite_or_whinstone, is_sandstone_or_limestone, age_band): - """ - As the u-value table in https://bregroup.com/wp-content/uploads/2019/09/RdSAP_2012_9.94-20-09-2019.pdf - on page 19, certain u-values as indicated by an "a", should be populated using a formula as defined in section - S.5.1.1 - :param wall_type: - :return: - """ - - stone_wall_thickness = [x for x in default_wall_thickness if x["type"] == "stone"][0] - - thickness = stone_wall_thickness["J_K_L"] if age_band in ["J", "L", "L"] else stone_wall_thickness[age_band] - - if is_granite_or_whinstone: - return 3.3 - 0.002 * thickness - - if is_sandstone_or_limestone: - return 3 - 0.002 * thickness - - for i, wall in enumerate(cleaned_data["walls-description"]): - if wall["thermal_transmittance"] is not None or "Average thermal transmittance" in wall["clean_description"]: - continue - - # TODO: Patched this already - if wall["original_description"] in "Sandstone, as built, no insulation (assumed)": - wall["is_sandstone_or_limestone"] = True - - description = wall["clean_description"] - # Remove (assumed) - description = description.replace("(assumed)", "").rstrip() - - # TODO: Patched this already: - if description == 'Cob with external insulation': - description = 'Cob, with external insulation' - - if description == "Cavity wall": - description = 'Cavity wall, as built, no insulation' - - mapped_description = epc_wall_description_map[description] - - if "Park home" in description: - age_bands_loop = ["F", "G", "I", "K"] - else: - age_bands_loop = age_bands - - # Get the u-value - for ab in age_bands_loop: - mapped_value = wall_uvalues_df[wall_uvalues_df["Wall_type"] == mapped_description][ab].values[0] - if mapped_value == "a": - # The rdSap documentation indicateswe should use a formula to calculate the u-value - uvalue = float( - apply_formula_s_5_1_1( - is_granite_or_whinstone=wall["is_granite_or_whinstone"], - is_sandstone_or_limestone=wall["is_sandstone_or_limestone"], - age_band=ab - ) - ) - elif "b" in mapped_value: - potential_uvalue = float(mapped_value.replace("b", "")) - formula_uvalue = float(apply_formula_s_5_1_1( - is_granite_or_whinstone=wall["is_granite_or_whinstone"], - is_sandstone_or_limestone=wall["is_sandstone_or_limestone"], - age_band=ab - )) - uvalue = min(potential_uvalue, formula_uvalue) - elif mapped_value == "s1.1.2": - uvalue = None - else: - uvalue = float(mapped_value) - - df = pd.DataFrame(cleaned_data["walls-description"]) + df = pd.DataFrame(cleaned_data["roof-description"]) df = df[pd.isnull(df["thermal_transmittance"])] - df["clean_description"].values - # We store a singular file however we could store the data under the following file path: # cleaned_epc_data/{component}/{original_description}/cleaned.bson # where component is one of the keys of cleaned_data. If we store it against the original data, this diff --git a/recommendations/rdsap_tables.py b/recommendations/rdsap_tables.py index c9204f34..8d303819 100644 --- a/recommendations/rdsap_tables.py +++ b/recommendations/rdsap_tables.py @@ -3,6 +3,7 @@ This script contains standard tables which are defined in rdsap. The most recent based on the 2012 version, however the government is currently working on releasing a new version, and there we will need to re-visit this """ +import pandas as pd age_band_data = [ { @@ -123,3 +124,184 @@ default_wall_thickness = [ "H": None, "I": 75, "J_K_L": 100 }, ] + +# This wall u-value table is defined in the rdsap documentation on page 19 +# https://bregroup.com/wp-content/uploads/2019/09/RdSAP_2012_9.94-20-09-2019.pdf +wall_types = [ + "Stone: granite or whinstone as built", + "Stone: sandstone or limestone as built", + "Solid brick as built", + "Stone/solid brick with 50 mm external or internal insulation", + "Stone/solid brick with 100 mm external or internal insulation", + "Stone/solid brick with 150 mm external or internal insulation", + "Stone/solid brick with 200 mm external or internal insulation", + "Cob as built", + "Cob with 50 mm external or internal insulation", + "Cob with 100 mm external or internal insulation", + "Cob with 150 mm external or internal insulation", + "Cob with 200 mm external or internal insulation", + "Cavity as built", + "Unfilled cavity with 50 mm external or internal insulation", + "Unfilled cavity with 100 mm external or internal insulation", + "Unfilled cavity with 150 mm external or internal insulation", + "Unfilled cavity with 200 mm external or internal insulation", + "Filled cavity", + "Filled cavity with 50 mm external or internal insulation", + "Filled cavity with 100 mm external or internal insulation", + "Filled cavity with 150 mm external or internal insulation", + "Filled cavity with 200 mm external or internal insulation", + "Timber frame as built", + "Timber frame with internal insulation", + "System build as built", + "System build with 50 mm external or internal insulation", + "System build with 100 mm external or internal insulation", + "System build with 150 mm external or internal insulation", + "System build with 200 mm external or internal insulation", +] + +u_values = [ + ["a", "a", "a", "a", "1.7b", "1.0", "0.6", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["a", "a", "a", "a", "1.7b", "1.0", "0.6", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["1.7", "1.7", "1.7", "1.7", "1.7", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["0.55", "0.55", "0.55", "0.55", "0.55", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], + ["0.32", "0.32", "0.32", "0.32", "0.32", "0.28", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], + ["0.23", "0.23", "0.23", "0.23", "0.23", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], + ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], + ["0.80", "0.80", "0.80", "0.80", "0.80", "0.80", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["0.40", "0.40", "0.40", "0.40", "0.40", "0.40", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], + ["0.26", "0.26", "0.26", "0.26", "0.26", "0.26", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], + ["0.20", "0.20", "0.20", "0.20", "0.20", "0.20", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], + ["0.16", "0.16", "0.16", "0.16", "0.16", "0.16", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], + ["1.5", "1.5", "1.5", "1.5", "1.5", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["0.53", "0.53", "0.53", "0.53", "0.53", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], + ["0.32", "0.32", "0.32", "0.32", "0.32", "0.30", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], + ["0.23", "0.23", "0.23", "0.23", "0.23", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], + ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], + ["0.7", "0.7", "0.7", "0.7", "0.7", "0.40", "0.35", "0.35", "0.45", "0.35", "0.30", "0.28"], + ["0.37", "0.37", "0.37", "0.37", "0.37", "0.27", "0.25", "0.25", "0.25", "0.25", "0.21", "0.21"], + ["0.25", "0.25", "0.25", "0.25", "0.25", "0.20", "0.19", "0.19", "0.19", "0.19", "0.17", "0.16"], + ["0.19", "0.19", "0.19", "0.19", "0.19", "0.16", "0.15", "0.15", "0.15", "0.15", "0.14", "0.14"], + ["0.16", "0.16", "0.16", "0.16", "0.16", "0.13", "0.13", "0.13", "0.13", "0.13", "0.12", "0.12"], + ["2.5", "1.9", "1.9", "1.0", "0.80", "0.45", "0.40", "0.40", "0.40", "0.35", "0.30", "0.28"], + ["0.60", "0.55", "0.55", "0.40", "0.40", "0.40", "0.40", "0.40", "0.40", "0.35", "0.30", "0.28"], + ["2.0", "2.0", "2.0", "2.0", "1.7", "1.0", "0.60", "0.60", "0.45", "0.35", "0.30", "0.28"], + ["0.60", "0.60", "0.60", "0.60", "0.55", "0.45", "0.35", "0.35", "0.30", "0.25", "0.21", "0.21"], + ["0.35", "0.35", "0.35", "0.35", "0.35", "0.32", "0.24", "0.24", "0.21", "0.19", "0.17", "0.16"], + ["0.25", "0.25", "0.25", "0.25", "0.25", "0.21", "0.18", "0.18", "0.17", "0.15", "0.14", "0.14"], + ["0.18", "0.18", "0.18", "0.18", "0.18", "0.17", "0.15", "0.15", "0.14", "0.13", "0.12", "0.12"], +] + +age_bands = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"] + +wall_uvalues = [] +for i, wall_type in enumerate(wall_types): + row = {"Wall_type": wall_type} + for j, age_band in enumerate(age_bands): + row[age_band] = u_values[i][j] + wall_uvalues.append(row) + +parkhome_wall_uvalues = [ + {"Wall_type": "Park home as built", "F": "1.7", "G": "1.2", "I": "0.7", "K": "0.6"}, + {"Wall_type": "Park home with additional insulation", "F": "s1.1.2", "G": "s1.1.2", "I": "s1.1.2", + "K": "s1.1.2"} +] + +wall_uvalues.extend(parkhome_wall_uvalues) + +wall_uvalues_df = pd.DataFrame(wall_uvalues) + +# This maps the descriptions in the EPC data to the descriptions in the RdSAP table +epc_wall_description_map = { + ############################ + # Cavity wall mappings + ############################ + "Cavity wall, as built, partial insulation": "Filled cavity", + "Cavity wall, filled cavity": "Filled cavity", + "Cavity wall, as built, no insulation": "Cavity as built", + "Cavity wall, as built, insulated": "Unfilled cavity with 100 mm external or internal insulation", + "Cavity wall, with external insulation": "Unfilled cavity with 100 mm external or internal insulation", + "Cavity wall, insulated": "Unfilled cavity with 100 mm external or internal insulation", + 'Cavity wall, partial insulation': "Unfilled cavity with 50 mm external or internal insulation", + + "Cavity wall,": "Cavity as built", # General case of cavity wall without further details + "Cavity wall, filled cavity and external insulation": + "Filled cavity with 100 mm external or internal insulation", + "Cavity wall, filled cavity and internal insulation": + "Filled cavity with 100 mm external or internal insulation", + "Cavity wall, with internal insulation": "Unfilled cavity with 100 mm external or internal insulation", + "Cavity wall, no insulation": "Cavity as built", + + ############################ + # Solid brick wall mappings + ############################ + "Solid brick, as built, no insulation": "Solid brick as built", + "Solid brick, with internal insulation": "Stone/solid brick with 100 mm external or internal insulation", + "Solid brick, as built, insulated": "Stone/solid brick with 100 mm external or internal insulation", + "Solid brick, with external insulation": "Stone/solid brick with 100 mm external or internal insulation", + "Solid brick, as built, partial insulation": "Stone/solid brick with 50 mm external or internal insulation", + + ############################ + # Timber frame wall mappings + ############################ + # These mappings are perhaps the most dubious due to the lack of timber options in the RdSAP table + "Timber frame, as built, insulated": "Timber frame with internal insulation", + "Timber frame, with additional insulation": "Timber frame with internal insulation", + "Timber frame, as built, partial insulation": "Timber frame as built", + "Timber frame, as built, no insulation": "Timber frame as built", + "Timber frame, with external insulation": "Timber frame with internal insulation", + + ############################ + # Sandstone/limestones wall mappings + ############################ + "Sandstone or limestone, as built, no insulation": "Stone: sandstone or limestone as built", + "Sandstone or limestone, with internal insulation": + "Stone/solid brick with 100 mm external or internal insulation", + "Sandstone or limestone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal " + "insulation", + "Sandstone, as built, no insulation": "Stone: sandstone or limestone as built", + "Sandstone or limestone, as built, insulated": + "Stone/solid brick with 100 mm external or internal insulation", + "Sandstone, as built, insulated": "Stone/solid brick with 100 mm external or internal insulation", + "Sandstone, with internal insulation": "Stone/solid brick with 100 mm external or internal insulation", + "Sandstone or limestone, with external insulation": "Stone/solid brick with 100 mm external or internal " + "insulation", + "Sandstone, with external insulation": "Stone/solid brick with 100 mm external or internal insulation", + "Sandstone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal insulation", + + ############################ + # Granite/whinstone wall mappings + ############################ + "Granite or whinstone, as built, no insulation": "Stone: granite or whinstone as built", + "Granite or whinstone, with internal insulation": "Stone/solid brick with 100 mm external or internal " + "insulation", + "Granite or whinstone, as built, partial insulation": "Stone/solid brick with 50 mm external or internal " + "insulation", + "Granite or whinstone, as built, insulated": "Stone/solid brick with 100 mm external or internal " + "insulation", + "Granite or whinstone, with external insulation": "Stone/solid brick with 100 mm external or internal " + "insulation", + + ############################ + # System built wall mappings + ############################ + "System built, as built, no insulation": "System build as built", + "System built, as built, partial insulation": "System build with 50 mm external or internal insulation", + "System built, with internal insulation": "System build with 100 mm external or internal insulation", + "System built, with external insulation": "System build with 100 mm external or internal insulation", + "System built, as built, insulated": "System build with 100 mm external or internal insulation", + + ############################ + # Cob wall mappings + ############################ + "Cob, as built": "Cob as built", + "Cob, with external insulation": "Cob with 100 mm external or internal insulation", + "Cob, with internal insulation": "Cob with 100 mm external or internal insulation", + 'Cob,': "Cob as built", + + ############################ + # Park home mappings + ############################ + "Park home wall, as built": "Park home as built", + "Park home wall, with external insulation": "Park home with additional insulation", + "Park home wall, with internal insulation": "Park home with additional insulation", +} diff --git a/recommendations/recommendation_utils.py b/recommendations/recommendation_utils.py index e53aeb17..e1f8eaf7 100644 --- a/recommendations/recommendation_utils.py +++ b/recommendations/recommendation_utils.py @@ -1,7 +1,7 @@ from copy import deepcopy from backend.Property import Property from statistics import mean -import random +from recommendations.rdsap_tables import epc_wall_description_map, wall_uvalues_df, default_wall_thickness def r_value_per_mm_to_u_value(depth_mm: int, r_value_per_mm: float): @@ -172,3 +172,61 @@ def get_uvalue_estimate(uvalue_estimates, property: Property, total_floor_area_g return mean( [x["median_thermal_transmittance"] for x in heated_rooms_filter if x["median_thermal_transmittance"]] ) + + +def apply_formula_s_5_1_1(is_granite_or_whinstone, is_sandstone_or_limestone, age_band): + """ + As the u-value table in https://bregroup.com/wp-content/uploads/2019/09/RdSAP_2012_9.94-20-09-2019.pdf + on page 19, certain u-values as indicated by an "a", should be populated using a formula as defined in section + S.5.1.1 + """ + + stone_wall_thickness = [x for x in default_wall_thickness if x["type"] == "stone"][0] + + thickness = stone_wall_thickness["J_K_L"] if age_band in ["J", "L", "L"] else stone_wall_thickness[age_band] + + if is_granite_or_whinstone: + return 3.3 - 0.002 * thickness + + if is_sandstone_or_limestone: + return 3 - 0.002 * thickness + + raise ValueError("This should only be called when is_granite_or_whinstone or is_sandstone_or_limestone is True") + + +def get_wall_u_value(clean_description, age_band, is_granite_or_whinstone, is_sandstone_or_limestone): + """ + Given some features about a wall, this function will query the wall u-value table and return the u-value + :param clean_description: Cleaned up description of the wall from the EPC data + :param age_band: age band of the property from the EPC data + :param is_granite_or_whinstone: Boolean indicating if the wall is made of granite or whinstone + :param is_sandstone_or_limestone: Boolean indicating if the wall is made of sandstone or limestone + :return: + """ + + mapped_description = epc_wall_description_map[clean_description] + + mapped_value = wall_uvalues_df[wall_uvalues_df["Wall_type"] == mapped_description][age_band].values[0] + if mapped_value == "a": + # The rdSap documentation indicateswe should use a formula to calculate the u-value + return float( + apply_formula_s_5_1_1( + is_granite_or_whinstone=is_granite_or_whinstone, + is_sandstone_or_limestone=is_sandstone_or_limestone, + age_band=age_band + ) + ) + + if "b" in mapped_value: + potential_uvalue = float(mapped_value.replace("b", "")) + formula_uvalue = float(apply_formula_s_5_1_1( + is_granite_or_whinstone=is_granite_or_whinstone, + is_sandstone_or_limestone=is_sandstone_or_limestone, + age_band=age_band + )) + return min(potential_uvalue, formula_uvalue) + + if mapped_value == "s1.1.2": + return None + + return float(mapped_value)