Model/model_data/tests/test_wall_recommendations.py
Khalim Conn-Kowlessar 9f36efb2a1 Fixed tests
2023-06-23 16:03:40 +01:00

267 lines
12 KiB
Python

import os
import pandas as pd
import pytest
import pickle
import numpy as np
from unittest.mock import Mock, MagicMock
from model_data.recommendations.WallRecommendations import WallRecommendations
from model_data.analysis.UvalueEstimations import UvalueEstimations
from model_data.Property import Property
class TestWallRecommendations:
@pytest.fixture
def input_properties(self):
with open(
os.path.abspath(os.path.dirname(__file__)) + "/test_data/input_properties.pkl", "rb"
) as f:
return pickle.load(f)
@pytest.fixture
def uvalue_estimates(self):
with open(
os.path.abspath(os.path.dirname(__file__)) + "/test_data/uvalue_estimates_walls.pkl", "rb"
) as f:
return pickle.load(f)
@pytest.fixture
def mock_wall_rec_instance(self):
# Creating a mock instance of WallRecommendations with the necessary attributes
property_mock = Mock()
property_mock.full_sap_epc = {"lodgement-date": "2000-01-01"} # or any date you want
property_mock.data = {"construction-age-band": "1950"} # or any other data that fits your tests
uvalue_estimates_mock = Mock()
mock_wall_rec_instance = WallRecommendations(property_mock, uvalue_estimates_mock)
return mock_wall_rec_instance
def test_init(self, input_properties, uvalue_estimates):
obj = WallRecommendations(property_instance=input_properties[0], uvalue_estimates=uvalue_estimates)
assert obj
assert obj.property
assert obj.uvalue_estimates
def test_uvalue_0_16(self, input_properties, uvalue_estimates):
"""
This tests the wall description Average thermal transmittance 0.16 W/m-¦K
The important data for this recommendation is:
- u value of 0.16
- property built in 2014
Since properties built after 1990 are typically built with insulation and this property
already has really good insulation, we do NOT recommend any measures for this property
"""
input_properties[0].year_built = 2014
recommender = WallRecommendations(property_instance=input_properties[0], uvalue_estimates=uvalue_estimates)
assert recommender.property.walls["original_description"] == "Average thermal transmittance 0.16 W/m-¦K"
recommender.recommend()
# This should be empty
assert recommender.recommendations == []
def test_solid_brick_no_insulation(self, input_properties, uvalue_estimates):
"""
This tests a property with a wall description of Solid brick, as built, no insulation (assumed)
The property was built in 1930, right on the threshold for when cavity walls were introduced
However, we're told this property is solid brik so we assume no cavity.
We're also told that it has no insulation, so we will recommend internal/external wall insulation
This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation
"""
input_properties[1].year_built = 1930
recommender = WallRecommendations(property_instance=input_properties[1], uvalue_estimates=uvalue_estimates)
assert recommender.property.walls["original_description"] == "Solid brick, as built, no insulation (assumed)"
assert not recommender.ewi_valid
assert recommender.property.in_conservation_area == "not_in_conservation_area"
assert recommender.property.data["property-type"] == "Flat"
recommender.recommend()
# This should result in some recommendations, all of which should be internal insulation
assert recommender.recommendations
rec_types = {rec["type"] for rec in recommender.recommendations}
assert rec_types == {"internal_wall_insulation"}
# Check the recommendations provide a u value below the minimum
assert all(
rec["new_u_value"] < WallRecommendations.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE for rec in
recommender.recommendations
)
def test_solid_brick_insulation(self, input_properties, uvalue_estimates):
"""
This tests a property with a wall description of Solid brick, as built, insulation (assumed)
The property was built in 1991, after cavity walls were introduced
However, we're told this property is solid brik so we assume no cavity.
We're also told that it has some insulation already
We'll need to estimate the u-value for this property since we don't know what the insulation is
and how thick it is. We'll estimate the u-value based on similar properties, by matching properties
with similar attributes such as the walls energy efficiency rating, the property type, the number of rooms,
etc
This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation
"""
input_properties[6].year_built = 1991
recommender = WallRecommendations(property_instance=input_properties[6], uvalue_estimates=uvalue_estimates)
assert recommender.property.walls["original_description"] == "Solid brick, as built, insulated (assumed)"
assert not recommender.ewi_valid
assert recommender.property.in_conservation_area == "not_in_conservation_area"
assert recommender.property.data["property-type"] == "Flat"
assert recommender.estimated_u_value is None
recommender.recommend()
# We should result in some recommendations, all of which should be internal wall insulation
assert recommender.recommendations
assert recommender.estimated_u_value == 0.45
rec_types = {rec["type"] for rec in recommender.recommendations}
assert rec_types == {"internal_wall_insulation"}
# Check the recommendations provide a u value below the minimum
assert all(
rec["new_u_value"] < WallRecommendations.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE for rec in
recommender.recommendations
)
for rec in recommender.recommendations:
assert rec["new_u_value"] < 0.3
def test_is_diminishing_returns_no_recommendations(self, mock_wall_rec_instance):
# We have no recommendations but the new u value is below the diminishing returns threshold
# however since there are no recommendaions yet, we should include it and say
# it is NOT diminishing
mock_wall_rec_instance.recommendations = []
new_u_value = 0.24
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert not mock_wall_rec_instance._is_diminishing_returns(new_u_value, None)
def test_is_diminishing_returns_diminishing(self, mock_wall_rec_instance):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold and is also lower than the lowest selected u value, so we should say this IS
# diminishing returns
mock_wall_rec_instance.recommendations = [Mock()]
new_u_value = 0.2
lowest_selected_u_value = 0.23
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert mock_wall_rec_instance._is_diminishing_returns(new_u_value, lowest_selected_u_value)
def test_is_diminishing_returns_is_diminishing(self, mock_wall_rec_instance):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold and it's lower than the lowest selected u value, so we should say this IS DIMINISHIN
mock_wall_rec_instance.recommendations = [Mock()]
new_u_value = 0.24
lowest_selected_u_value = 0.26
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert mock_wall_rec_instance._is_diminishing_returns(new_u_value, lowest_selected_u_value)
def test_is_diminishing_returns_not_diminishing(self, mock_wall_rec_instance):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold however it's higher than the lowest selected u value, so we should say this is NOT
# diminishing returns
mock_wall_rec_instance.recommendations = [Mock()]
new_u_value = 0.24
lowest_selected_u_value = 0.22
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert not mock_wall_rec_instance._is_diminishing_returns(new_u_value, lowest_selected_u_value)
def test_is_diminishing_returns_error_in_recommendations(self, mock_wall_rec_instance):
# Testing case where there's an error in recommendations
mock_wall_rec_instance.recommendations = []
with pytest.raises(ValueError):
mock_wall_rec_instance._is_diminishing_returns(0.2, 0.24)
class TestWallRecommendationsBase:
@pytest.fixture
def property_mock(self):
property_mock = MagicMock(spec=Property)
property_mock.full_sap_epc = {"lodgement-date": "1999-12-31"}
property_mock.in_conservation_area = "not_in_conservation_area"
return property_mock
@pytest.fixture
def uvalue_estimations_mock(self):
uvalue_estimations_mock = MagicMock(spec=UvalueEstimations)
uvalue_estimations_mock.walls = pd.DataFrame([
{
'local-authority': 'E09000012',
'property-type': 'Bungalow',
'walls-energy-eff': 'Very Good',
'walls-env-eff': 'Very Good',
'built-form': 'End-Terrace',
'number-habitable-rooms': '', 'number-heated-rooms': '', 'total-floor-area_group': 'Decile 1',
'median_thermal_transmittance': 0.15, 'n_samples': 1
}
])
uvalue_estimations_mock.walls_decile_data = {
'decile_labels': ['Decile 1', 'Decile 2', 'Decile 3', 'Decile 4', 'Decile 5', 'Decile 6', 'Decile 7',
'Decile 8', 'Decile 9', 'Decile 10'],
'decile_boundaries': np.array([11., 49., 52., 56., 63., 70., 74., 79.,
90., 103.8, 1936.])}
uvalue_estimations_mock.classify_decile_newvalues.return_value = ["Decile 1"]
return uvalue_estimations_mock
@pytest.fixture
def wall_recommendations_instance(self, property_mock, uvalue_estimations_mock):
wall_recommendations_instance = WallRecommendations(property_mock, uvalue_estimations_mock)
wall_recommendations_instance.uvalue_estimates.walls_decile_data = {
"decile_labels": MagicMock(),
"decile_boundaries": MagicMock()
}
return wall_recommendations_instance
def test_ewi_valid_in_conservation_area(self, wall_recommendations_instance):
wall_recommendations_instance.property.in_conservation_area = "in_conversation_area"
assert wall_recommendations_instance.ewi_valid is False
def test_ewi_valid_is_flat(self, wall_recommendations_instance):
wall_recommendations_instance.property.data = {"property-type": "flat"}
assert wall_recommendations_instance.ewi_valid is False
def test_ewi_valid_not_in_conservation_area_and_not_flat(self, wall_recommendations_instance):
wall_recommendations_instance.property.in_conservation_area = "not_in_conversation_area"
wall_recommendations_instance.property.data = {"property-type": "house"}
assert wall_recommendations_instance.ewi_valid is True
def test_get_walls_uvalue_estimate(self, wall_recommendations_instance, uvalue_estimations_mock):
wall_recommendations_instance.uvalue_estimates = uvalue_estimations_mock
wall_recommendations_instance.property.data = {
"local-authority": "E09000012",
"property-type": "Bungalow",
"built-form": "End-Terrace",
"walls-energy-eff": "Very Good",
"walls-env-eff": "Very Good",
"total-floor-area": 10,
"number-habitable-rooms": "",
"number-heated-rooms": ""
}
assert wall_recommendations_instance._get_walls_uvalue_estimate() == 0.15
def test_recommend_without_u_value(self, wall_recommendations_instance):
wall_recommendations_instance.property.walls = {
"thermal_transmittance": None,
"is_solid_brick": False,
"is_cavity_wall": False,
"insulation_thickness": "none"
}
with pytest.raises(NotImplementedError):
wall_recommendations_instance.recommend()