diff --git a/recommendations/FloorRecommendations.py b/recommendations/FloorRecommendations.py index ee5a9db5..8a5e9cf3 100644 --- a/recommendations/FloorRecommendations.py +++ b/recommendations/FloorRecommendations.py @@ -61,113 +61,6 @@ class FloorRecommendations(Definitions): part for part in self.materials if part["type"] == "solid_floor_insulation" ] - def _estimate_suspended_floor_u_value( - self, floor_area, number_of_rooms, insulation_thickness, wall_type, region, age_band - ): - """ - Estimate the u-value of a suspended floor, based on RdSap methodology - Default U-value for UNINSULATED suspended floor, based on RdSAP methodology - https://files.bregroup.com/bre-co-uk-file-library-copy/filelibrary/SAP/2012/RdSAP-9.93/RdSAP_2012_9.93.pdf - - w = wall thickness, where these estimates are based on the RD SAP methodology, as in table S3 - A = floor area - Exposed perimeter = P - soil type clas thermal conductivity lambda_g = 1.5 W/mK - Rsi = 0.17m^2K/W - Rse = 0.04m^2K/W - Rf = 0.001 * d_ins / 0.035 where d_ins is the insulation thickness in mm - height above external ground h = 0.3m - average wind speed at 10m height v=5m/s - wind sheilding factor fw = 0.05 - vantilation factor E = 0.003 m^2/m - U-value of walls to underfloor space Uw = 1.5 W/m^2K - - # Calulations for suspended ground floors, example for 5 bedroom house with permiter estimated at - 44.36214602563767 - 1) dg = w + lambda_g x (Rsi + Rse) = 0.5 + 1.5 * (0.17 + 0.04) = 0.615 - 2) B = 2 * A/P = 2 * 123.0 / 44.36214602563767 = 5.545268253204708 - 3) Ug = 2 * lambda_g * log(pi * B/dg + 1)/(pi * B + dg) = - 2 * 1.5 * log(3.141592653589793 * 5.545268253204708/0.615 + 1) / (3.141592653589793 * 5.545268253204708 - + 0.615) = 0.5619604457160708 - 4) Ux = (2 * h * Uw /B) + (1450 * E * v * fw/B) = (2 * 0.3 * 1.5 / 5.545268253204708) + (1450 * 0.003 * 5 * - 0.05/5.545268253204708) = 0.35841367978030436 - 5) U = 1/ (2 * Rsi + Rf + 1/(Ug + Ux)) = 1 / (2 * 0.17 + 0 + 1/(0.5619604457160708 + 0.35841367978030436)) = - 0.701 - """ - age_band_letter = [x for x in age_band_data if x[region] == age_band][0]["age_band"] - - defaults = { - # We need width in meters - "w": [x[age_band_letter] for x in default_wall_thickness if x["type"] == wall_type][0] / 1000, - "lambda_g": 1.5, - "Rsi": 0.17, - "Rse": 0.04, - "Rf": 0.001 * insulation_thickness / 0.035, - "h": 0.3, - "v": 5, - "fw": 0.05, - "E": 0.003, - "Uw": 1.5, - } - - dg = defaults["w"] + defaults["lambda_g"] * (defaults["Rsi"] + defaults["Rse"]) - - # P is the exposed perimeter, which we estimate as we not have this data - if number_of_rooms <= 2: - p = estimate_perimeter_2_rooms(floor_area=floor_area) - else: - p = estimate_perimeter(floor_area=floor_area, num_rooms=number_of_rooms) - b = 2 * floor_area / p - u_g = 2 * defaults["lambda_g"] * math.log(math.pi * b / dg + 1) / (math.pi * b + dg) - u_x = (2 * defaults["h"] * defaults["Uw"] / b) + (1450 * defaults["E"] * defaults["v"] * defaults["fw"] / b) - # This is the final estimated U-value - u = 1 / (2 * defaults["Rsi"] + defaults["Rf"] + 1 / (u_g + u_x)) - - return u - - def _estimate_solid_floor_u_value(self): - """ - 1. dt =w + g × (Rsi + Rf + Rse) - 2. B = 2 × A/P - 3. if dt < B, U = 2 × g × ln( × B/dt + 1)/( × B + dt) - 4. if dt >= B, U = g / (0.457 × B + dt) - :return: - """ - - # TODO: complete - insulation_thickness = 0 - age_band_letter = "E" - wall_type = "cavity" - floor_area = 37.26 - perimeter = 16.2 - - # age_band_letter = [x for x in age_band_data if x[region] == age_band][0]["age_band"] - - defaults = { - # We need width in meters - "w": [x[age_band_letter] for x in default_wall_thickness if x["type"] == wall_type][0] / 1000, - "lambda_g": 1.5, - "Rsi": 0.17, - "Rse": 0.04, - "Rf": 0.001 * insulation_thickness / 0.035, - "h": 0.3, - "v": 5, - "fw": 0.05, - "E": 0.003, - "Uw": 1.5, - } - - dt = defaults["w"] + defaults["lambda_g"] * (defaults["Rsi"] + defaults["Rse"] + defaults["Rf"]) - - # perimeter = self._estimate_perimeter(floor_area, number_of_rooms) - - B = 2 * floor_area / perimeter - - if dt < B: - U = 2 * defaults["lambda_g"] * math.log(math.pi * B / dt + 1) / (math.pi * B + dt) - else: - print("implement me") - def recommend(self): u_value = self.property.floor["thermal_transmittance"] is_suspended = self.property.floor["is_suspended"] diff --git a/recommendations/rdsap_tables.py b/recommendations/rdsap_tables.py index 717c243e..748d4034 100644 --- a/recommendations/rdsap_tables.py +++ b/recommendations/rdsap_tables.py @@ -433,3 +433,30 @@ s10_list = [ table_s9 = pd.DataFrame(s9_list) table_s10 = pd.DataFrame(s10_list) + +######################################################################################################################## +# Table s11 is used for assigning the u-values of floors when the insulation thickness is unknown +# which can be found on page 25 of the BRE document +# https://bregroup.com/wp-content/uploads/2019/09/RdSAP_2012_9.94-20-09-2019.pdf +######################################################################################################################## + +s11_list = [ + {"Age_band": "A, B", "Floor_construction": "suspended timber", "England_Wales": 0, "Scotland": 0, + "Northern_Ireland": 0, "Park_home": 0}, + {"Age_band": "C to F", "Floor_construction": "solid", "England_Wales": 0, "Scotland": 0, + "Northern_Ireland": 0, "Park_home": 0}, + {"Age_band": "G", "Floor_construction": "solid", "England_Wales": 0, "Scotland": 0, + "Northern_Ireland": 0, "Park_home": "25"}, + {"Age_band": "H", "Floor_construction": "solid", "England_Wales": 0, "Scotland": "25", + "Northern_Ireland": "25", "Park_home": 0}, + {"Age_band": "I", "Floor_construction": "solid", "England_Wales": "25", "Scotland": "50", + "Northern_Ireland": "50", "Park_home": "50"}, + {"Age_band": "J", "Floor_construction": "solid", "England_Wales": "75", "Scotland": "75", + "Northern_Ireland": 0, "Park_home": 0}, + {"Age_band": "K", "Floor_construction": "solid", "England_Wales": "100", "Scotland": "100", + "Northern_Ireland": "100", "Park_home": "70"}, + {"Age_band": "L", "Floor_construction": "solid", "England_Wales": "100", "Scotland": "120", + "Northern_Ireland": "100", "Park_home": 0}, +] + +table_s11 = pd.DataFrame(s11_list) diff --git a/recommendations/recommendation_utils.py b/recommendations/recommendation_utils.py index d6209e0e..d1d90de9 100644 --- a/recommendations/recommendation_utils.py +++ b/recommendations/recommendation_utils.py @@ -3,7 +3,8 @@ from copy import deepcopy from backend.Property import Property from statistics import mean from recommendations.rdsap_tables import ( - epc_wall_description_map, wall_uvalues_df, default_wall_thickness, table_s9 as s9, table_s10 as s10 + epc_wall_description_map, wall_uvalues_df, default_wall_thickness, table_s9 as s9, table_s10 as s10, + table_s11 as s11 ) @@ -368,21 +369,55 @@ def estimate_perimeter_2_rooms(floor_area): return perimeter -import math +def calculate_floor_u_value(floor_type, area, perimeter, age_band, wall_type, insulation_thickness=None): + """ + Estimate the u-value of a suspended floor, based on RdSap methodology + Default U-value for UNINSULATED suspended floor, based on RdSAP methodology + https://files.bregroup.com/bre-co-uk-file-library-copy/filelibrary/SAP/2012/RdSAP-9.93/RdSAP_2012_9.93.pdf + w = wall thickness, where these estimates are based on the RD SAP methodology, as in table S3 + A = floor area + Exposed perimeter = P + soil type clas thermal conductivity lambda_g = 1.5 W/mK + Rsi = 0.17m^2K/W + Rse = 0.04m^2K/W + Rf = 0.001 * d_ins / 0.035 where d_ins is the insulation thickness in mm + height above external ground h = 0.3m + average wind speed at 10m height v=5m/s + wind sheilding factor fw = 0.05 + vantilation factor E = 0.003 m^2/m + U-value of walls to underfloor space Uw = 1.5 W/m^2K + + # Calulations for suspended ground floors, example for 5 bedroom house with permiter estimated at + 44.36214602563767 + 1) dg = w + lambda_g x (Rsi + Rse) = 0.5 + 1.5 * (0.17 + 0.04) = 0.615 + 2) B = 2 * A/P = 2 * 123.0 / 44.36214602563767 = 5.545268253204708 + 3) Ug = 2 * lambda_g * log(pi * B/dg + 1)/(pi * B + dg) = + 2 * 1.5 * log(3.141592653589793 * 5.545268253204708/0.615 + 1) / (3.141592653589793 * 5.545268253204708 + + 0.615) = 0.5619604457160708 + 4) Ux = (2 * h * Uw /B) + (1450 * E * v * fw/B) = (2 * 0.3 * 1.5 / 5.545268253204708) + (1450 * 0.003 * 5 * + 0.05/5.545268253204708) = 0.35841367978030436 + 5) U = 1/ (2 * Rsi + Rf + 1/(Ug + Ux)) = 1 / (2 * 0.17 + 0 + 1/(0.5619604457160708 + 0.35841367978030436)) = + 0.701 + """ -def calculate_floor_u_value(floor_type, area, perimeter, wall_thickness, insulation_thickness=None): # Define constants lambda_g = 1.5 # thermal conductivity of soil in W/m·K Rsi = 0.17 # in m²K/W Rse = 0.04 # in m²K/W lambda_ins = 0.035 # thermal conductivity of floor insulation in W/m·K + wall_thickness = [x[age_band] for x in default_wall_thickness if x["type"] == wall_type][0] / 1000 + + if insulation_thickness is None: + insulation_lookup = s11[s11["Age_band"].str.contains(age_band) & s11["Floor_construction"] == floor_type] + if insulation_lookup.empty: + insulation_thickness = 0 + else: + insulation_thickness = insulation_lookup["England_Wales"].values[0] + # Calculate Rf for insulated floors - if insulation_thickness is not None: - Rf = 0.001 * insulation_thickness / lambda_ins - else: - Rf = 0 + Rf = 0.001 * insulation_thickness / lambda_ins # Calculate B B = 2 * area / perimeter @@ -413,7 +448,7 @@ def calculate_floor_u_value(floor_type, area, perimeter, wall_thickness, insulat Ux = (2 * h * Uw / B) + (1450 * epsilon * v * fw / B) # Calculate final U value for suspended floors - if insulation_thickness is not None: + if insulation_thickness > 0: Rf += 0.2 # adding thermal resistance of floor deck else: Rf = 0.2 # thermal resistance of uninsulated floor deck