import pytest from unittest.mock import Mock from backend.Property import Property from etl.epc.Record import EPCRecord from recommendations.RoofRecommendations import RoofRecommendations from recommendations.tests.test_data.materials import materials class TestRoofRecommendations: def test_null_roof_description(self): epc_record = EPCRecord(county="Cambridgeshire") property_instance = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance.age_band = "F" property_instance.insulation_floor_area = 100 property_instance.roof = { 'original_description': None, 'clean_description': None, 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': None } property_instance.already_installed = [] roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) roof_recommender.recommend(phase=0) assert not roof_recommender.recommendations def test_loft_insulation_recommendation_no_insulation(self): epc_record = EPCRecord(county="Cambridgeshire") property_instance = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance.age_band = "F" property_instance.insulation_floor_area = 100 property_instance.roof = { 'original_description': 'Pitched, no insulation (assumed)', 'clean_description': 'Pitched, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance.already_installed = [] roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) assert not roof_recommender.recommendations roof_recommender.recommend(phase=0) assert len(roof_recommender.recommendations) == 3 assert roof_recommender.recommendations[0]["parts"][0]["depth"] == 300 def test_loft_insulation_recommendation_50mm_insulation(self): epc_record = EPCRecord(county="Kent", **{"roof_energy_eff": "Very Poor"}) property_instance2 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance2.age_band = "F" property_instance2.insulation_floor_area = 100 property_instance2.roof = { 'original_description': 'Pitched, 50mm loft insulation (assumed)', 'clean_description': 'Pitched, 50mm loft insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance2.already_installed = [] roof_recommender2 = RoofRecommendations(property_instance=property_instance2, materials=materials) assert not roof_recommender2.recommendations roof_recommender2.recommend(phase=0) assert len(roof_recommender2.recommendations) == 3 assert roof_recommender2.recommendations[0]["total"] == 2100 assert roof_recommender2.recommendations[0]["new_u_value"] == 0.13 assert float(roof_recommender2.recommendations[0]["starting_u_value"]) == 0.68 assert roof_recommender2.recommendations[0]["parts"][0]["depth"] == 300 epc_record = EPCRecord(county="Greater London Authority", **{"roof_energy_eff": "Very Poor"}) property_instance3 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance3.age_band = "F" property_instance3.insulation_floor_area = 100 property_instance3.roof = { 'original_description': 'Pitched, 50mm loft insulation (assumed)', 'clean_description': 'Pitched, 50mm loft insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance3.already_installed = [] roof_recommender3 = RoofRecommendations(property_instance=property_instance3, materials=materials) assert not roof_recommender3.recommendations roof_recommender3.recommend(phase=0) assert roof_recommender3.recommendations assert len(roof_recommender3.recommendations) == 3 assert roof_recommender3.recommendations[0]["parts"][0]["depth"] == 300.0 def test_loft_insulation_recommendation_150mm_insulation(self): epc_record = EPCRecord(county="North East Lincolnshire", **{"roof_energy_eff": "Good"}) property_instance4 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance4.age_band = "F" property_instance4.insulation_floor_area = 100 property_instance4.roof = { 'original_description': 'Pitched, 150mm loft insulation (assumed)', 'clean_description': 'Pitched, 150mm loft insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance4.already_installed = [] roof_recommender4 = RoofRecommendations(property_instance=property_instance4, materials=materials) assert not roof_recommender4.recommendations roof_recommender4.recommend(phase=0, default_u_values=True) assert len(roof_recommender4.recommendations) == 3 assert roof_recommender4.recommendations[0]["total"] == 2100.0 assert float(roof_recommender4.recommendations[0]["new_u_value"]) == 0.14 assert float(roof_recommender4.recommendations[0]["starting_u_value"]) == 0.3 assert roof_recommender4.recommendations[0]["parts"][0]["depth"] == 300 epc_record = EPCRecord(county="Somerset", **{"roof_energy_eff": "Good"}) property_instance5 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance5.age_band = "F" property_instance5.insulation_floor_area = 100 property_instance5.roof = { 'original_description': 'Pitched, 150mm loft insulation (assumed)', 'clean_description': 'Pitched, 150mm loft insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance5.already_installed = [] roof_recommender5 = RoofRecommendations(property_instance=property_instance5, materials=materials) assert not roof_recommender5.recommendations roof_recommender5.recommend(phase=0) assert roof_recommender5.recommendations assert len(roof_recommender5.recommendations) == 3 assert roof_recommender5.recommendations[0]["parts"][0]["depth"] == 300 def test_loft_insulation_recommendation_270mm_insulation(self): epc_record = EPCRecord(county="Portsmouth") property_instance6 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance6.age_band = "F" property_instance6.insulation_floor_area = 100 property_instance6.roof = { 'original_description': 'Pitched, 270mm loft insulation (assumed)', 'clean_description': 'Pitched, 270mm loft insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': '270', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance6.already_installed = [] roof_recommender6 = RoofRecommendations(property_instance=property_instance6, materials=materials) assert not roof_recommender6.recommendations roof_recommender6.recommend(phase=0) assert len(roof_recommender6.recommendations) == 0 def test_uninsulated_room_in_roof(self): epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor") property_instance7 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance7.age_band = "F" property_instance7.insulation_floor_area = 100 property_instance7.roof = { 'original_description': 'Room-in-roof, no insulation (assumed)', 'clean_description': 'Room-in-roof, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none' } property_instance7.already_installed = [] property_instance7.pitched_roof_area = 110 roof_recommender7 = RoofRecommendations(property_instance=property_instance7, materials=materials) assert not roof_recommender7.recommendations roof_recommender7.recommend(phase=0) assert len(roof_recommender7.recommendations) == 1 assert roof_recommender7.recommendations[0]["new_u_value"] == 0.18 assert roof_recommender7.recommendations[0]["starting_u_value"] == 0.8 assert roof_recommender7.recommendations[0]["description"] == "Insulate room in roof at rafters and re-decorate" # Ensure all tests are room in roof assert all(rec["measure_type"] == "room_roof_insulation" for rec in roof_recommender7.recommendations) def test_ceiling_insulated_room_in_roof(self): epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor") property_instance8 = Property(id=8, address="fake", postcode="fake", epc_record=epc_record) property_instance8.age_band = "F" property_instance8.insulation_floor_area = 100 property_instance8.roof = { 'original_description': 'Roof room(s), ceiling insulated', 'clean_description': 'Roof room(s), ceiling insulated', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average' } property_instance8.already_installed = [] property_instance8.pitched_roof_area = 110 roof_recommender8 = RoofRecommendations(property_instance=property_instance8, materials=materials) assert not roof_recommender8.recommendations roof_recommender8.recommend(phase=0) # No recommendations in this case assert not roof_recommender8.recommendations def test_insulated_room_in_roof(self): epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor") property_instance9 = Property(id=9, address="fake", postcode="fake", epc_record=epc_record) property_instance9.age_band = "F" property_instance9.insulation_floor_area = 100 property_instance9.roof = { 'original_description': 'Roof room(s), insulated (assumed)', 'clean_description': 'Roof room(s), insulated', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average' } property_instance9.already_installed = [] property_instance9.pitched_roof_area = 110 property_instance9.data = {"county": "Rutland"} roof_recommender9 = RoofRecommendations(property_instance=property_instance9, materials=materials) assert not roof_recommender9.recommendations roof_recommender9.recommend(phase=0) # No recommendations in this case assert not roof_recommender9.recommendations def test_limited_insulated_room_in_roof(self): epc_record = EPCRecord(county="Westmorland", roof_energy_eff="Poor") property_instance10 = Property(id=10, address="fake", postcode="fake", epc_record=epc_record) property_instance10.age_band = "F" property_instance10.insulation_floor_area = 100 property_instance10.roof = { 'original_description': 'Roof room(s), limited insulation (assumed)', 'clean_description': 'Roof room(s), limited insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average' } property_instance10.already_installed = [] property_instance10.pitched_roof_area = 110 roof_recommender10 = RoofRecommendations(property_instance=property_instance10, materials=materials) assert not roof_recommender10.recommendations roof_recommender10.recommend(phase=0) assert len(roof_recommender10.recommendations) == 1 assert roof_recommender10.recommendations[0]["new_u_value"] == 0.17 assert roof_recommender10.recommendations[0]["starting_u_value"] == 0.68 assert (roof_recommender10.recommendations[0]["description"] == 'Insulate room in roof at rafters and re-decorate') def test_flat_no_insulation(self): epc_record = EPCRecord(county="Swindon") property_instance11 = Property(id=11, address="fake", postcode="fake", epc_record=epc_record) property_instance11.age_band = "D" property_instance11.insulation_floor_area = 33.5 property_instance11.perimeter = 24 property_instance11.roof = { 'original_description': 'Flat, no insulation (assumed)', 'clean_description': 'Flat, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': False, 'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none' } property_instance11.already_installed = [] roof_recommender11 = RoofRecommendations(property_instance=property_instance11, materials=materials) assert not roof_recommender11.recommendations roof_recommender11.recommend(phase=0) assert len(roof_recommender11.recommendations) == 1 assert roof_recommender11.recommendations[0]["parts"][0]["depth"] == 150 assert roof_recommender11.recommendations[0]["total"] == 6532.5 assert roof_recommender11.recommendations[0]["new_u_value"] == 0.14 assert roof_recommender11.recommendations[0]["starting_u_value"] == 2.3 assert roof_recommender11.recommendations[0]["description"] == \ "Insulate the home's flat roof with 150mm of Ecotherm Eco-Versal General Purpose Insulation Board" def test_flat_insulated(self): epc_record = EPCRecord(county="Thurrock") property_instance12 = Property(id=12, address="fake", postcode="fake", epc_record=epc_record) property_instance12.age_band = "D" property_instance12.insulation_floor_area = 40 property_instance12.perimeter = 30 property_instance12.roof = { 'original_description': 'Flat, insulated (assumed)', 'clean_description': 'Flat, insulated', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': False, 'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average' } property_instance12.already_installed = [] roof_recommender12 = RoofRecommendations(property_instance=property_instance12, materials=materials) assert not roof_recommender12.recommendations roof_recommender12.recommend(phase=0) assert not roof_recommender12.recommendations def test_flat_limited_insulation(self): epc_record = EPCRecord(county="Tyne and Wear") property_instance13 = Property(id=12, address="fake", postcode="fake", epc_record=epc_record) property_instance13.age_band = "D" property_instance13.insulation_floor_area = 40 property_instance13.perimeter = 40 property_instance13.roof = { 'original_description': 'Flat, limited insulation (assumed)', 'clean_description': 'Flat, limited insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False, 'is_roof_room': False, 'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average' } property_instance13.already_installed = [] roof_recommender13 = RoofRecommendations(property_instance=property_instance13, materials=materials) assert not roof_recommender13.recommendations roof_recommender13.recommend(phase=0) assert len(roof_recommender13.recommendations) == 1 assert roof_recommender13.recommendations[0]["parts"][0]["depth"] == 150 assert roof_recommender13.recommendations[0]["total"] == 7800 assert roof_recommender13.recommendations[0]["new_u_value"] == 0.14 assert roof_recommender13.recommendations[0]["starting_u_value"] == 2.3 assert roof_recommender13.recommendations[0]["description"] == \ "Insulate the home's flat roof with 150mm of Ecotherm Eco-Versal General Purpose Insulation Board" def test_property_above(self): epc_record = EPCRecord(county="Suffolk") property_instance14 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record) property_instance14.age_band = "F" property_instance14.insulation_floor_area = 100 property_instance14.roof = { 'original_description': '(other premises above)', 'clean_description': '(other premises above)', 'thermal_transmittance': 0, 'thermal_transmittance_unit': 'w/m-¦k', 'is_pitched': False, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': True, 'is_valid': True, 'insulation_thickness': None } property_instance14.already_installed = [] roof_recommender14 = RoofRecommendations(property_instance=property_instance14, materials=materials) assert not roof_recommender14.recommendations roof_recommender14.recommend(phase=0) assert not roof_recommender14.recommendations # ~~~~~~~~~~~~ Sloping Ceiling Insulation ~~~~~~~~~~~~ @pytest.mark.parametrize( "roof, has_sloping_ceiling_recommendation, primary_roof_looks_sloped, insulation_thickness, " "has_loft_insulation_recommendation, expected_result", [ ( { 'original_description': 'Pitched, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none' }, True, True, "none", False, True, ), ( { 'original_description': 'Pitched, insulated (assumed)', 'clean_description': 'Pitched, insulated', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average' }, False, False, "average", False, False ) ] ) def test_is_sloping_ceiling_appropriate( self, roof, has_sloping_ceiling_recommendation, primary_roof_looks_sloped, insulation_thickness, has_loft_insulation_recommendation, expected_result ): assert RoofRecommendations.is_sloping_ceiling_appropriate( is_flat=bool(roof["is_flat"]), is_pitched=bool(roof["is_pitched"]), is_loft=bool(roof["is_loft"]), is_assumed=bool(roof["is_assumed"]), has_sloping_ceiling_recommendation=has_sloping_ceiling_recommendation, primary_roof_looks_sloped=primary_roof_looks_sloped, insulation_thickness=insulation_thickness, has_loft_insulation_recommendation=has_loft_insulation_recommendation ) == expected_result def test_sloping_ceiling_pitched_no_insulation(self): property_instance = Mock( id=0, roof={ 'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none' }, roof_area=64.085, data={"county": None, "local-authority-label": "Manchester"}, age_band="D", already_installed=[], non_invasive_recommendations=[ {'type': 'flat_roof_insulation', 'sap_points': 9, 'survey': True}, {'type': 'sloping_ceiling_insulation', 'sap_points': 9, 'survey': True}, {'type': 'cavity_wall_insulation', 'sap_points': 6, 'survey': True}, {'type': 'suspended_floor_insulation', 'sap_points': 2, 'survey': True}, {'type': 'roomstat_programmer_trvs', 'sap_points': 3, 'survey': True}, {'type': 'time_temperature_zone_control', 'sap_points': 3, 'survey': True}, {'type': 'solar_pv', 'sap_points': 5, 'survey': True, 'suitable': True} ], find_my_epc_components=[ {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, limited insulation', 'efficiency': 'Very poor', 'appearance_index': 1}, {'component_name': 'Window', 'description': 'Some multiple glazing', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating control', 'description': 'Programmer, room thermostat and TRVs', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Lighting', 'description': 'Low energy lighting in 28% of fixed outlets', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A', 'appearance_index': 0}, {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A', 'appearance_index': 0} ] ) roof_recommender = RoofRecommendations(property_instance=property_instance, materials=[]) assert not roof_recommender.recommendations roof_recommender.recommend(phase=0) assert len(roof_recommender.recommendations) == 1 assert roof_recommender.recommendations[0]["type"] == "sloping_ceiling_insulation" assert roof_recommender.recommendations[0]["measure_type"] == "sloping_ceiling_insulation" assert ( roof_recommender.recommendations[0]["description"] == "Insulate sloping ceilings at the rafters and re-decorate" ) assert roof_recommender.recommendations[0]["simulation_config"] == { 'roof_insulation_thickness_ending': 'average', 'roof_thermal_transmittance_ending': 0.5, 'roof_energy_eff_ending': 'Average' } assert roof_recommender.recommendations[0]["description_simulation"] == { 'roof-description': 'Pitched, insulated', 'roof-energy-eff': 'Average' } def test_ambiguous_sloping_ceiling_or_loft(self): # In this case, we actually expect loft insulation to be recommended property_instance = Mock( id=0, roof={ # Roof looks like it could be a sloping ceiling but it's actually a loft 'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none' }, roof_area=197.748, data={"county": None, "local-authority-label": "Manchester"}, already_installed=[], find_my_epc_components=[ {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, limited insulation', 'efficiency': 'Very poor', 'appearance_index': 1}, {'component_name': 'Window', 'description': 'Some multiple glazing', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating control', 'description': 'Programmer, room thermostat and TRVs', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Lighting', 'description': 'Low energy lighting in 28% of fixed outlets', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A', 'appearance_index': 0}, {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A', 'appearance_index': 0} ], age_band="B", non_invasive_recommendations=[ {'type': 'loft_insulation', 'sap_points': 3, 'survey': True}, {'type': 'flat_roof_insulation', 'sap_points': 2, 'survey': True}, {'type': 'sloping_ceiling_insulation', 'sap_points': 2, 'survey': True}, {'type': 'internal_wall_insulation', 'sap_points': 9, 'survey': True}, {'type': 'draught_proofing', 'sap_points': 1, 'survey': True}, {'type': 'low_energy_lighting', 'sap_points': 1, 'survey': True}, {'type': 'solar_water_heating', 'sap_points': 1, 'survey': True}, {'type': 'double_glazing', 'sap_points': 3, 'survey': True}, {'type': 'solar_pv', 'sap_points': 4, 'survey': True, 'suitable': True} ], insulation_floor_area=162 ) roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) assert not roof_recommender.recommendations roof_recommender.recommend(phase=0) assert len(roof_recommender.recommendations) == 3 # Should all be loft insulation recommendations assert all( rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations ) def test_no_access_pitched_roof_assumed(self): """ In this case, the roof will have been surveyed as pitched, but the surveyor won't have gotten access to the property to check the insulation. Therefore, we recommend loft insulation. We assume that the roof is a locked off loft :return: """ property_instance = Mock( id=0, roof={ 'original_description': 'Pitched, limited insulation (assumed)', 'clean_description': 'Pitched, limited insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average' }, roof_area=73.24, data={"county": None, "local-authority-label": "Manchester"}, already_installed=[], find_my_epc_components=[ {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Wall', 'description': 'System built, as built, no insulation (assumed)', 'efficiency': 'Poor', 'appearance_index': 1}, {'component_name': 'Wall', 'description': 'Cavity wall, filled cavity', 'efficiency': 'Average', 'appearance_index': 2}, {'component_name': 'Roof', 'description': 'Pitched, limited insulation (assumed)', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating control', 'description': 'Programmer and room thermostat', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Lighting', 'description': 'Low energy lighting in 75% of fixed outlets', 'efficiency': 'Very good', 'appearance_index': 0}, {'component_name': 'Roof', 'description': '(another dwelling above)', 'efficiency': 'N/A', 'appearance_index': 1}, {'component_name': 'Floor', 'description': 'Suspended, no insulation (assumed)', 'efficiency': 'N/A', 'appearance_index': 0}, {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A', 'appearance_index': 1}, {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A', 'appearance_index': 0} ], age_band="B", non_invasive_recommendations=[ {'type': 'internal_wall_insulation', 'sap_points': 2, 'survey': True}, {'type': 'suspended_floor_insulation', 'sap_points': 2, 'survey': True}, {'type': 'solid_floor_insulation', 'sap_points': 1, 'survey': True}, {'type': 'low_energy_lighting', 'sap_points': 0, 'survey': True} ], insulation_floor_area=60 ) roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) assert not roof_recommender.recommendations roof_recommender.recommend(phase=0) assert len(roof_recommender.recommendations) == 3 # Should all be loft insulation recommendations assert all( rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations ) def test_traditional_loft_insulation(self): property_instance = Mock( id=0, roof={ 'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none' }, roof_area=48.82666666666667, data={"county": None, "local-authority-label": "Manchester"}, already_installed=[], find_my_epc_components=[ {'component_name': 'Wall', 'description': 'Cavity wall, filled cavity', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating control', 'description': 'TRVs and bypass', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Lighting', 'description': 'Low energy lighting in all fixed outlets', 'efficiency': 'Very good', 'appearance_index': 0}, {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A', 'appearance_index': 0}, {'component_name': 'Secondary heating', 'description': 'Room heaters, electric', 'efficiency': 'N/A', 'appearance_index': 0} ], age_band="F", non_invasive_recommendations=[ {'type': 'loft_insulation', 'sap_points': 9, 'survey': True}, {'type': 'solid_floor_insulation', 'sap_points': 2, 'survey': True}, {'type': 'solar_water_heating', 'sap_points': 1, 'survey': True}, {'type': 'solar_pv', 'sap_points': 11, 'survey': True, 'suitable': True} ], insulation_floor_area=40.0 ) roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) assert not roof_recommender.recommendations roof_recommender.recommend(0) assert len(roof_recommender.recommendations) == 3 # should all be loft insulation recommendations assert all(rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations) def sloping_ceiling_limited_insulation(self): property_instance = Mock( id=0, roof={ "original_description": 'Pitched, limited insulation (assumed)', 'clean_description': 'Pitched, limited insulation', 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average' }, roof_area=35, data={"county": None, "local-authority-label": "Manchester"}, already_installed=[], find_my_epc_components=[ {'component_name': 'Wall', 'description': 'Cavity wall, as built, no insulation (assumed)', 'efficiency': 'poor', 'appearance_index': 0}, {'component_name': 'Roof', 'description': 'Pitched, limited insulation (assumed)', 'efficiency': 'Very poor', 'appearance_index': 0}, {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Main heating control', 'description': 'TRVs and bypass', 'efficiency': 'Average', 'appearance_index': 0}, {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good', 'appearance_index': 0}, {'component_name': 'Lighting', 'description': 'Low energy lighting in all fixed outlets', 'efficiency': 'Very good', 'appearance_index': 0}, {'component_name': 'Floor', 'description': '(another dwelling below)', 'efficiency': 'N/A', 'appearance_index': 0}, {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A', 'appearance_index': 0} ], age_band="B", non_invasive_recommendations=[ {'type': 'sloping_ceiling_insulation', 'sap_points': 2, 'survey': True}, {'type': 'flat_roof_insulation', 'sap_points': 2, 'survey': True}, ], ) # We expect a sloping ceiling insulation recommendation roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials) assert not roof_recommender.recommendations roof_recommender.recommend(phase=0) assert len(roof_recommender.recommendations) == 1 assert roof_recommender.recommendations[0]["type"] == "sloping_ceiling_insulation" assert roof_recommender.recommendations[0]["measure_type"] == "sloping_ceiling_insulation" assert roof_recommender.recommendations[0]["description"] == \ "Insulate sloping ceilings at the rafters and re-decorate" assert roof_recommender.recommendations[0]["simulation_config"] == { 'roof_insulation_thickness_ending': 'average', 'roof_thermal_transmittance_ending': 0.5, 'roof_energy_eff_ending': 'Average' } assert roof_recommender.recommendations[0]["description_simulation"] == { 'roof-description': 'Pitched, insulated', 'roof-energy-eff': 'Average' }