diff --git a/recommendations/optimiser/funding_optimiser.py b/recommendations/optimiser/funding_optimiser.py index 324e2c74..69a6bc48 100644 --- a/recommendations/optimiser/funding_optimiser.py +++ b/recommendations/optimiser/funding_optimiser.py @@ -655,6 +655,11 @@ def optimise_with_scenarios( 1) With air source heat pump AND required insulation """ + # Universally handle zero gain + if target_gain is not None: + if target_gain <= 0: + return pd.DataFrame([]) + solutions = [] paths = [] # Produce the unique list of measure types @@ -770,6 +775,11 @@ def optimise_with_scenarios( for fixed in fixed_selections: + if target_gain is not None: + if target_gain <= 0: + # If we don't have any gain, we don't actually need to do this + continue + # fixed = [(gi, oi, opt), ...] fixed_items = [opt for (_, _, opt) in fixed] fixed_groups = {gi for (gi, _, _) in fixed} diff --git a/recommendations/tests/test_optimiser_functions.py b/recommendations/tests/test_optimiser_functions.py index debd2d88..08541c21 100644 --- a/recommendations/tests/test_optimiser_functions.py +++ b/recommendations/tests/test_optimiser_functions.py @@ -3,9 +3,19 @@ import numpy as np from types import SimpleNamespace from recommendations.tests.test_data.measures_to_optimise import measures_to_optimise from recommendations.optimiser import optimiser_functions +from recommendations.optimiser.funding_optimiser import optimise_with_scenarios from recommendations.optimiser.GainOptimiser import GainOptimiser from recommendations.optimiser.CostOptimiser import CostOptimiser -from recommendations.optimiser.StrategicOptimiser import StrategicOptimiser, Strategies +from recommendations.optimiser.StrategicOptimiser import StrategicOptimiser + + +@pytest.fixture +def property_instance(): + return SimpleNamespace( + id="P1", + has_ventilation=False, + data={"current-energy-efficiency": "52"}, + ) class TestPrepareInputMeasures: @@ -48,8 +58,9 @@ class TestPrepareInputMeasures: def test_filters_out_negative_cost_savings(self): recs = [ [{"recommendation_id": "bad1", "type": "loft_insulation", "total": 200, "kwh_savings": 100, - "energy_cost_savings": -5, "has_battery": False, - "partial_project_funding": 0, "partial_project_score": 0, "uplift_project_score": 0, }], + "energy_cost_savings": -100, "has_battery": False, + "partial_project_funding": 0, "partial_project_score": 0, "uplift_project_score": 0, + "measure_type": "roof_insulation"}], ] measures = optimiser_functions.prepare_input_measures(recs, goal="Energy Savings", needs_ventilation=False) assert measures == [] # should skip negative cost saving recs @@ -572,3 +583,262 @@ class TestCheckNeedsVentilation: ) assert result == False + + +class TestOptimiseWithScenarios: + + def test_zero_gain(self, property_instance): + input_measures = [[{'id': '0_phase=0', 'cost': 16901.01977922431, 'gain': np.float64(2.0), + 'type': 'internal_wall_insulation+mechanical_ventilation', 'innovation_uplift': 0, + 'cost_minus_uplift': 16901.01977922431, 'raw_cost': 16341.019779224309, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}], + [{'id': '1_phase=1', 'cost': 1197.0, 'gain': 0, 'type': 'loft_insulation', + 'innovation_uplift': 0, 'cost_minus_uplift': 1197.0, 'raw_cost': 1197.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}, + {'id': '2_phase=1', 'cost': 1026.0, 'gain': 0, 'type': 'loft_insulation', + 'innovation_uplift': 0, 'cost_minus_uplift': 1026.0, 'raw_cost': 1026.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}, + {'id': '3_phase=1', 'cost': 855.0, 'gain': 0, 'type': 'loft_insulation', + 'innovation_uplift': 0, 'cost_minus_uplift': 855.0, 'raw_cost': 855.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}], + [{'id': '5_phase=3', 'cost': 5343.75, 'gain': 1, 'type': 'suspended_floor_insulation', + 'innovation_uplift': 0, 'cost_minus_uplift': 5343.75, 'raw_cost': 5343.75, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}], + [{'id': '6_phase=4', 'cost': 1009.5600000000001, 'gain': np.float64(0.9000000000000057), + 'type': 'time_temperature_zone_control', 'innovation_uplift': 0, + 'cost_minus_uplift': 1009.5600000000001, 'raw_cost': 1009.5600000000001, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}, + {'id': '7_phase=4', 'cost': 18979.9, 'gain': np.float64(6.9), 'type': 'air_source_heat_pump', + 'innovation_uplift': 0, 'cost_minus_uplift': 18979.9, 'raw_cost': 18979.9, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 0}], + [{'id': '8_phase=5', 'cost': 5420.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5420.0, 'raw_cost': 5420.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.6}, + {'id': '9_phase=5', 'cost': 6210.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6210.0, 'raw_cost': 6210.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.6}, + {'id': '10_phase=5', 'cost': 6820.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6820.0, 'raw_cost': 6820.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.6}, + {'id': '11_phase=5', 'cost': 7202.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7202.0, 'raw_cost': 7202.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.915}, + {'id': '12_phase=5', 'cost': 6495.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6495.0, 'raw_cost': 6495.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.92}, + {'id': '13_phase=5', 'cost': 7285.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7285.0, 'raw_cost': 7285.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.92}, + {'id': '14_phase=5', 'cost': 7895.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7895.0, 'raw_cost': 7895.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.92}, + {'id': '15_phase=5', 'cost': 5520.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5520.0, 'raw_cost': 5520.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.0}, + {'id': '16_phase=5', 'cost': 6310.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6310.0, 'raw_cost': 6310.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.0}, + {'id': '17_phase=5', 'cost': 6920.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6920.0, 'raw_cost': 6920.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.0}, + {'id': '18_phase=5', 'cost': 5840.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5840.0, 'raw_cost': 5840.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.2}, + {'id': '19_phase=5', 'cost': 6630.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6630.0, 'raw_cost': 6630.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.2}, + {'id': '20_phase=5', 'cost': 7240.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7240.0, 'raw_cost': 7240.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.2}, + {'id': '21_phase=5', 'cost': 8630.0, 'gain': np.float64(14.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8630.0, 'raw_cost': 8630.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.655}, + {'id': '22_phase=5', 'cost': 7660.0, 'gain': np.float64(14.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7660.0, 'raw_cost': 7660.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.66}, + {'id': '23_phase=5', 'cost': 8470.0, 'gain': np.float64(14.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8470.0, 'raw_cost': 8470.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.66}, + {'id': '24_phase=5', 'cost': 9090.0, 'gain': np.float64(14.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 9090.0, 'raw_cost': 9090.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.66}, + {'id': '25_phase=5', 'cost': 7240.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7240.0, 'raw_cost': 7240.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.79}, + {'id': '26_phase=5', 'cost': 8050.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8050.0, 'raw_cost': 8050.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.79}, + {'id': '27_phase=5', 'cost': 8660.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8660.0, 'raw_cost': 8660.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.79}, + {'id': '28_phase=5', 'cost': 5740.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5740.0, 'raw_cost': 5740.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.8}, + {'id': '29_phase=5', 'cost': 6530.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6530.0, 'raw_cost': 6530.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.8}, + {'id': '30_phase=5', 'cost': 7140.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7140.0, 'raw_cost': 7140.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.8}, + {'id': '31_phase=5', 'cost': 8360.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8360.0, 'raw_cost': 8360.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.22}, + {'id': '32_phase=5', 'cost': 7470.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7470.0, 'raw_cost': 7470.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.22}, + {'id': '33_phase=5', 'cost': 8280.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8280.0, 'raw_cost': 8280.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.22}, + {'id': '34_phase=5', 'cost': 8890.0, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8890.0, 'raw_cost': 8890.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 5.22}, + {'id': '35_phase=5', 'cost': 5892.21, 'gain': np.float64(13.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5892.21, 'raw_cost': 5892.21, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 5.34}, + {'id': '36_phase=5', 'cost': 5320.0, 'gain': np.float64(8.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5320.0, 'raw_cost': 5320.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.2}, + {'id': '37_phase=5', 'cost': 6110.0, 'gain': np.float64(8.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6110.0, 'raw_cost': 6110.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.2}, + {'id': '38_phase=5', 'cost': 6720.0, 'gain': np.float64(8.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6720.0, 'raw_cost': 6720.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.2}, + {'id': '39_phase=5', 'cost': 6932.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6932.0, 'raw_cost': 6932.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.48}, + {'id': '40_phase=5', 'cost': 6295.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6295.0, 'raw_cost': 6295.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 3.48}, + {'id': '41_phase=5', 'cost': 7085.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7085.0, 'raw_cost': 7085.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.48}, + {'id': '42_phase=5', 'cost': 7695.0, 'gain': np.float64(9.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7695.0, 'raw_cost': 7695.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 3.48}, + {'id': '43_phase=5', 'cost': 5640.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5640.0, 'raw_cost': 5640.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.4}, + {'id': '44_phase=5', 'cost': 6430.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6430.0, 'raw_cost': 6430.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.4}, + {'id': '45_phase=5', 'cost': 7040.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7040.0, 'raw_cost': 7040.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.4}, + {'id': '46_phase=5', 'cost': 8090.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8090.0, 'raw_cost': 8090.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.785}, + {'id': '47_phase=5', 'cost': 7240.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7240.0, 'raw_cost': 7240.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.79}, + {'id': '48_phase=5', 'cost': 8050.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8050.0, 'raw_cost': 8050.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.79}, + {'id': '49_phase=5', 'cost': 8660.0, 'gain': np.float64(12.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8660.0, 'raw_cost': 8660.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.79}, + {'id': '50_phase=5', 'cost': 5520.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5520.0, 'raw_cost': 5520.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.0}, + {'id': '51_phase=5', 'cost': 6310.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6310.0, 'raw_cost': 6310.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.0}, + {'id': '52_phase=5', 'cost': 6920.0, 'gain': np.float64(10.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6920.0, 'raw_cost': 6920.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.0}, + {'id': '53_phase=5', 'cost': 7820.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7820.0, 'raw_cost': 7820.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.35}, + {'id': '54_phase=5', 'cost': 6675.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6675.0, 'raw_cost': 6675.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.35}, + {'id': '55_phase=5', 'cost': 7485.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7485.0, 'raw_cost': 7485.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.35}, + {'id': '56_phase=5', 'cost': 8095.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 8095.0, 'raw_cost': 8095.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.35}, + {'id': '57_phase=5', 'cost': 5640.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5640.0, 'raw_cost': 5640.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.4}, + {'id': '58_phase=5', 'cost': 6430.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 6430.0, 'raw_cost': 6430.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.4}, + {'id': '59_phase=5', 'cost': 7040.0, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 7040.0, 'raw_cost': 7040.0, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': True, 'array_size': 4.4}, + {'id': '60_phase=5', 'cost': 5692.21, 'gain': np.float64(11.0), 'type': 'solar_pv', + 'innovation_uplift': 0, 'cost_minus_uplift': 5692.21, 'raw_cost': 5692.21, + 'partial_project_funding': 0, 'partial_project_score': 0, 'uplift_project_score': 0, + 'already_installed': False, 'has_battery': False, 'array_size': 4.45}]] + + solutions = optimise_with_scenarios( + p=property_instance, + input_measures=input_measures, + budget=None, + target_gain=0, + enforce_heat_pump_insulation=True, + enforce_fabric_first=False, + already_installed_sap=0, # To be passed to output + ) + + assert solutions.empty diff --git a/recommendations/tests/test_recommendations.py b/recommendations/tests/test_recommendations.py index 747b0b2e..2218cd16 100644 --- a/recommendations/tests/test_recommendations.py +++ b/recommendations/tests/test_recommendations.py @@ -401,7 +401,7 @@ def test_adjust_ventilation_sap(sap_impact, limit, expected): ) == expected -def test_get_previous_phase_values_starting_phase(property_instance): +def test_get_previous_phase_values_phase_0_starting_phase_0(property_instance): result = Recommendations._get_previous_phase_values( rec_phase=0, starting_phase=0, @@ -411,6 +411,7 @@ def test_get_previous_phase_values_starting_phase(property_instance): assert result == { "sap": 65.0, + "sap_prediction": 65.0, "carbon": 2.4, "heat_demand": 284.0, } @@ -441,8 +442,8 @@ def test_get_previous_phase_values_single_rep(property_instance): def test_get_previous_phase_values_median(property_instance): impact_summary = [ - {"phase": 1, "representative": True, "sap": 70, "carbon": 2.0, "heat_demand": 250}, - {"phase": 1, "representative": True, "sap": 74, "carbon": 1.6, "heat_demand": 230}, + {"phase": 1, "representative": True, "sap": 70, "carbon": 2.0, "heat_demand": 250, "sap_prediction": 70}, + {"phase": 1, "representative": True, "sap": 74, "carbon": 1.6, "heat_demand": 230, "sap_prediction": 74}, ] result = Recommendations._get_previous_phase_values(