From 57f92e60602abdf232be22f8ed2d1cc97a42cc67 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 19 Dec 2023 19:27:33 +0000 Subject: [PATCH] completed estimate windows function, though it needs more testing --- .idea/Model.iml | 2 +- .idea/misc.xml | 2 +- recommendations/recommendation_utils.py | 61 +++++++++++++ .../tests/test_recommendation_utils.py | 91 +++++++++++++++++++ 4 files changed, 154 insertions(+), 2 deletions(-) diff --git a/.idea/Model.iml b/.idea/Model.iml index 4413bb06..b0f9c00d 100644 --- a/.idea/Model.iml +++ b/.idea/Model.iml @@ -7,7 +7,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 6f308057..1122b380 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/recommendations/recommendation_utils.py b/recommendations/recommendation_utils.py index 100ecb15..7cfe023e 100644 --- a/recommendations/recommendation_utils.py +++ b/recommendations/recommendation_utils.py @@ -652,3 +652,64 @@ def esimtate_pitched_roof_area(floor_area: float, floor_height: float) -> float: area = 2 * (slope * wall_width) return area + + +def estimate_windows( + property_type, built_form, construction_age_band, floor_area, number_habitable_rooms, extension_count +): + # Base window count based on habitable rooms + window_count = number_habitable_rooms + + # Additional windows for non-habitable rooms (e.g., kitchen, bathroom) + # Assuming most houses will have at least one kitchen and one bathroom + # Scale non-habitable windows with the number of habitable rooms + non_habitable_base = 2 # Base for kitchen and bathroom + extra_non_habitable = max(0, (number_habitable_rooms - 3) // 2) # Extra for large houses + window_count += non_habitable_base + extra_non_habitable + + # Adjustments based on built form and property type + if property_type in ["House", "Bungalow"] and built_form in ["Semi-Detached", "Detached"]: + built_form_lookup = { + "Semi-Detached": 3, + "Detached": 4, + } + else: + # For Flats and Maisonettes, adjustments might be less + built_form_lookup = { + "Mid-Terrace": 0, + "End-Terrace": 1, + "Semi-Detached": 1, + "Detached": 2, + } + window_count += built_form_lookup.get(built_form, 0) + + # Adjust for floor area (larger floor area might indicate more rooms/windows) + if floor_area < 85: # Small to medium properties + # Standard window count likely sufficient + pass + elif 85 <= floor_area <= 120: # Medium to large properties + # More rooms or larger rooms likely, potentially more windows + window_count += 1 + elif floor_area > 120: # Very large properties + # Likely to have significantly more or larger rooms + window_count += 2 + + # Adjust for construction age band + if construction_age_band in ["England and Wales: before 1900", "England and Wales: 1900-1929"]: + # Older houses with smaller, more numerous windows + window_count += 1 + + # Adjust for extensions (each extension might add windows) + window_count += extension_count + + # Adjustments for specific property types + if property_type in ["Flat", "Maisontte"]: + # Flats might have fewer windows due to shared walls + # Maisonettes might follow a similar pattern to flats or small houses + window_count -= 1 + + # Ensure window count is not negative + if window_count < 0: + raise ValueError("Window count cannot be negative.") + + return window_count diff --git a/recommendations/tests/test_recommendation_utils.py b/recommendations/tests/test_recommendation_utils.py index aefc70b0..7c29bbb0 100644 --- a/recommendations/tests/test_recommendation_utils.py +++ b/recommendations/tests/test_recommendation_utils.py @@ -427,3 +427,94 @@ def test_external_wall_area(): for num_floors, floor_height, perimeter, built_form, expected in test_cases: result = recommendation_utils.estimate_external_wall_area(num_floors, floor_height, perimeter, built_form) assert result == expected, f"Test failed for {built_form}: Expected {expected}, got {result}" + + +def test_estimate_windows(): + # Based on data from an EPR that has 4 windows + windows_case_1 = recommendation_utils.estimate_windows( + property_type="Flat", + built_form="Semi-Detached", + construction_age_band="England and Wales: 1976-1982", + floor_area=37, + number_habitable_rooms=2, + extension_count=0, + ) + + assert windows_case_1 == 4, f"Expected 4 windows, got {windows_case_1}" + + # Based on data from an EPR that has 7 winows, however two of the windows were very small, having areas of + # 0.21m^2 and 0.3m^2 respectively. We see 6 as a reasonable estimate for the number of windows + windows_case_2 = recommendation_utils.estimate_windows( + property_type="House", + built_form="Mid-Terrace", + construction_age_band="England and Wales: 1950-1966", + floor_area=69, + number_habitable_rooms=4, + extension_count=0, + ) + + assert windows_case_2 == 6, f"Expected 6 windows, got {windows_case_2}" + + # Based on data from an EPR on a bungalow, that has 6 windows. Two of the windows are small, both have a 0.4m^2 area + # and so 5 windows is an acceptable estimate + windows_case_3 = recommendation_utils.estimate_windows( + property_type="Bungalow", + built_form="Mid-Terrace", + construction_age_band="England and Wales: 1967-1975", + floor_area=56, + number_habitable_rooms=3, + extension_count=0, + ) + + assert windows_case_3 == 5, f"Expected 5 windows, got {windows_case_3}" + + # Based on data from an EPR on a end terrace house that has 8 windows. One of the windows is very small, with an + # area of 0.25 m^2 and so 7 windows is an acceptable estimate + windows_case_4 = recommendation_utils.estimate_windows( + property_type="House", + built_form="End-Terrace", + construction_age_band="England and Wales: 1967-1975", + floor_area=77.28, + number_habitable_rooms=4, + extension_count=0, + ) + + assert windows_case_4 == 7, f"Expected 7 windows, got {windows_case_4}" + + # Based on data from an EPR on a Semi-detatched house that has 11 windows based on the associated condition report + # Right now, we estimate 12 windows for this property + windows_case_5 = recommendation_utils.estimate_windows( + property_type="House", + built_form="Semi-Detached", + construction_age_band="England and Wales: 1950-1966", + floor_area=88.4, + number_habitable_rooms=5, + extension_count=0, + ) + + assert windows_case_5 == 12, f"Expected 12 windows, got {windows_case_5}" + + # Based on Khalim's flat which has 3 windows. There is no construction age band on the EPC. The windows are large + # so an estimate of 5 windows is a reasonable estimate + windows_case_6 = recommendation_utils.estimate_windows( + property_type="Flat", + built_form="", + construction_age_band="", + floor_area=100, + number_habitable_rooms=3, + extension_count=0, + ) + + assert windows_case_6 == 5, f"Expected 5 windows, got {windows_case_6}" + + # Based on an EPR semi detatched house though we don't have the exact number of windows. We estimate 10 + windows_case_7 = recommendation_utils.estimate_windows( + property_type="House", + built_form="Semi-Detached", + construction_age_band="England and Wales: 1967-1975", + floor_area=85, + number_habitable_rooms=4, + extension_count=0, + ) + + assert windows_case_7 == 10, f"Expected 10 windows, got {windows_case_7}"