mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
added floor uvalue unit tests
This commit is contained in:
parent
dcb2f7caba
commit
87e7cce075
5 changed files with 122 additions and 18 deletions
|
|
@ -5,7 +5,7 @@ from datatypes.enums import QuantityUnits
|
|||
from backend.Property import Property
|
||||
from recommendations.recommendation_utils import (
|
||||
r_value_per_mm_to_u_value, calculate_u_value_uplift, is_diminishing_returns, update_lowest_selected_u_value,
|
||||
get_recommended_part, estimate_perimeter, estimate_perimeter_2_rooms, get_wall_type,
|
||||
get_recommended_part, estimate_perimeter, get_wall_type,
|
||||
get_floor_u_value
|
||||
)
|
||||
|
||||
|
|
@ -103,12 +103,7 @@ class FloorRecommendations(Definitions):
|
|||
else:
|
||||
raise NotImplementedError("Implement me")
|
||||
|
||||
scaled_num_rooms = number_of_rooms / num_floors
|
||||
|
||||
if scaled_num_rooms <= 2.5:
|
||||
estimated_perimeter = estimate_perimeter_2_rooms(total_floor_area / num_floors)
|
||||
else:
|
||||
estimated_perimeter = estimate_perimeter(total_floor_area / num_floors, scaled_num_rooms)
|
||||
estimated_perimeter = estimate_perimeter(total_floor_area / num_floors, number_of_rooms / num_floors)
|
||||
|
||||
wall_type = get_wall_type(**self.property.walls)
|
||||
|
||||
|
|
|
|||
|
|
@ -300,6 +300,16 @@ def get_roof_u_value(
|
|||
|
||||
|
||||
def estimate_perimeter(floor_area, num_rooms):
|
||||
"""
|
||||
Uses a basic methodology to attempt to estimate perimeter. Works better for
|
||||
:param floor_area: floor area of the home
|
||||
:param num_rooms: number of rooms in the home
|
||||
:return: estimated perimeter
|
||||
"""
|
||||
if floor_area < 0:
|
||||
raise ValueError("Floor area cannot be negative.")
|
||||
if num_rooms <= 0:
|
||||
raise ValueError("Number of rooms must be greater than zero.")
|
||||
# Compute average room size based on total floor area and number of rooms
|
||||
avg_room_size = floor_area / num_rooms
|
||||
|
||||
|
|
@ -319,16 +329,6 @@ def estimate_perimeter(floor_area, num_rooms):
|
|||
return perimeter
|
||||
|
||||
|
||||
def estimate_perimeter_2_rooms(floor_area):
|
||||
# Assuming a square layout for the entire floor area to get a first-order approximation of the perimeter
|
||||
side_length = math.sqrt(floor_area)
|
||||
|
||||
# Calculating the perimeter of the square layout
|
||||
perimeter = 4 * side_length
|
||||
|
||||
return perimeter
|
||||
|
||||
|
||||
def get_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
|
||||
|
|
|
|||
32
recommendations/tests/test_data/floor_uvalue_test_cases.py
Normal file
32
recommendations/tests/test_data/floor_uvalue_test_cases.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
floor_uvalue_test_cases = [
|
||||
# Test with solid floor, no insulation
|
||||
{
|
||||
"floor_type": "solid",
|
||||
"area": 100,
|
||||
"perimeter": 40,
|
||||
"age_band": "A",
|
||||
"wall_type": "cavity",
|
||||
"insulation_thickness": None,
|
||||
"expected": 0.62,
|
||||
},
|
||||
# Test with suspended floor, with insulation
|
||||
{
|
||||
"floor_type": "suspended",
|
||||
"area": 120,
|
||||
"perimeter": 44,
|
||||
"age_band": "B",
|
||||
"wall_type": "solid brick",
|
||||
"insulation_thickness": "50mm",
|
||||
"expected": 0.33,
|
||||
},
|
||||
# Test with invalid floor type
|
||||
{
|
||||
"floor_type": "invalid",
|
||||
"area": 100,
|
||||
"perimeter": 40,
|
||||
"age_band": "A",
|
||||
"wall_type": "cavity",
|
||||
"insulation_thickness": None,
|
||||
"expected": ValueError,
|
||||
},
|
||||
]
|
||||
|
|
@ -128,7 +128,7 @@ class TestWallRecommendations:
|
|||
assert recommender.estimated_u_value is None
|
||||
recommender.recommend()
|
||||
assert recommender.property.floor["is_suspended"]
|
||||
assert recommender.estimated_u_value == 0.51
|
||||
assert recommender.estimated_u_value == 0.52
|
||||
assert recommender.recommendations
|
||||
|
||||
types = {part["type"] for x in recommender.recommendations for part in x["parts"]}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import pytest
|
||||
import math
|
||||
from unittest.mock import MagicMock
|
||||
from recommendations import recommendation_utils
|
||||
from datatypes.enums import QuantityUnits
|
||||
from recommendations.tests.test_data.wall_uvalue_test_cases import wall_uvalue_test_cases
|
||||
from recommendations.tests.test_data.floor_uvalue_test_cases import floor_uvalue_test_cases
|
||||
|
||||
|
||||
class TestRecommendationUtils:
|
||||
|
|
@ -227,3 +229,78 @@ class TestRecommendationUtils:
|
|||
del inputs["uvalue"]
|
||||
uvalue = recommendation_utils.get_wall_u_value(**inputs)
|
||||
assert expected_uvalue == uvalue, f"Expected u value {expected_uvalue}, recieved {uvalue}"
|
||||
|
||||
@pytest.mark.parametrize("test_input", floor_uvalue_test_cases)
|
||||
def test_get_floor_u_value(self, test_input):
|
||||
if not isinstance(test_input["expected"], float):
|
||||
with pytest.raises(test_input["expected"]):
|
||||
recommendation_utils.get_floor_u_value(
|
||||
test_input["floor_type"],
|
||||
test_input["area"],
|
||||
test_input["perimeter"],
|
||||
test_input["age_band"],
|
||||
test_input["wall_type"],
|
||||
test_input["insulation_thickness"],
|
||||
)
|
||||
else:
|
||||
result = recommendation_utils.get_floor_u_value(
|
||||
floor_type=test_input["floor_type"],
|
||||
area=test_input["area"],
|
||||
perimeter=test_input["perimeter"],
|
||||
age_band=test_input["age_band"],
|
||||
wall_type=test_input["wall_type"],
|
||||
insulation_thickness=test_input["insulation_thickness"],
|
||||
)
|
||||
assert result == pytest.approx(test_input["expected"], abs=1e-2)
|
||||
|
||||
# Test with wall_type not in default_wall_thickness
|
||||
def test_wall_type_not_in_default_wall_thickness(self):
|
||||
with pytest.raises(IndexError):
|
||||
recommendation_utils.get_floor_u_value(
|
||||
floor_type="solid",
|
||||
area=100,
|
||||
perimeter=40,
|
||||
age_band="A",
|
||||
wall_type="InvalidWallType",
|
||||
insulation_thickness=None,
|
||||
)
|
||||
|
||||
# Test with age_band not in s11
|
||||
def test_age_band_not_in_s11(self):
|
||||
with pytest.raises(IndexError):
|
||||
recommendation_utils.get_floor_u_value(
|
||||
floor_type="solid",
|
||||
area=100,
|
||||
perimeter=40,
|
||||
age_band="Z",
|
||||
wall_type="Cavity",
|
||||
insulation_thickness=None,
|
||||
)
|
||||
|
||||
|
||||
def test_estimate_perimeter_regular_inputs():
|
||||
assert math.isclose(
|
||||
recommendation_utils.estimate_perimeter(100, 5), 40.24922359499622,
|
||||
rel_tol=1e-2
|
||||
)
|
||||
assert math.isclose(
|
||||
recommendation_utils.estimate_perimeter(123, 5), 44.63854836349408,
|
||||
rel_tol=1e-2
|
||||
)
|
||||
|
||||
|
||||
def test_estimate_perimeter_zero_floor_area():
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
recommendation_utils.estimate_perimeter(0, 5)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
assert recommendation_utils.estimate_perimeter(0, 0) == 0
|
||||
|
||||
|
||||
def test_estimate_perimeter_invalid_inputs():
|
||||
with pytest.raises(ValueError):
|
||||
recommendation_utils.estimate_perimeter(100, 0)
|
||||
with pytest.raises(ValueError):
|
||||
recommendation_utils.estimate_perimeter(-100, 5)
|
||||
with pytest.raises(ValueError):
|
||||
recommendation_utils.estimate_perimeter(100, -5)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue