diff --git a/tests/domain/modelling/test_optimiser_goal_objective.py b/tests/domain/modelling/test_optimiser_goal_objective.py index f64371cc4..acd14b3ec 100644 --- a/tests/domain/modelling/test_optimiser_goal_objective.py +++ b/tests/domain/modelling/test_optimiser_goal_objective.py @@ -16,46 +16,25 @@ from datatypes.epc.domain.epc_property_data import ( ) from domain.modelling.measure_type import MeasureType from domain.modelling.optimisation.optimiser import ( - MeasureDependency, OptimisedPackage, ScoredOption, optimise_package, + optimise_package_fabric_first, ) -from domain.modelling.recommendation import Cost, MeasureOption from domain.modelling.scoring.package_scorer import Score -from domain.modelling.simulation import ( - BuildingPartOverlay, - EpcSimulation, - HeatingOverlay, - VentilationOverlay, +from domain.modelling.simulation import BuildingPartOverlay, EpcSimulation +from tests.domain.modelling._optimiser_fixtures import ( + ASHP_OVERLAY, + BOILER_OVERLAY, + WALL_OVERLAY, + scored_option, + selected_types, + ventilation_dependency, ) from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import ( build_epc, ) -_WALL_OVERLAY = EpcSimulation( - building_parts={ - BuildingPartIdentifier.MAIN: BuildingPartOverlay(wall_insulation_type=2) - } -) -_VENT_OVERLAY = EpcSimulation( - ventilation=VentilationOverlay(mechanical_ventilation_kind="EXTRACT_OR_PIV_OUTSIDE") -) - - -def _scored( - measure_type: str, *, gain: float, cost: float, overlay: EpcSimulation -) -> ScoredOption: - return ScoredOption( - option=MeasureOption( - measure_type=MeasureType(measure_type), - description=measure_type, - overlay=overlay, - cost=Cost(total=cost, contingency_rate=0.0), - ), - sap_gain=gain, - ) - class _CarbonScorer: """A stub where the wall is a small carbon win (−20 kg/yr) and a large SAP @@ -89,19 +68,10 @@ def test_dependency_signals_are_priced_in_the_objective_currency() -> None: # pricing the ventilation's −30 SAP would outweigh the wall's +20 signal # and the package would collapse to nothing. groups: list[list[ScoredOption]] = [ - [_scored("cavity_wall_insulation", gain=20.0, cost=1000.0, overlay=_WALL_OVERLAY)], + [scored_option("cavity_wall_insulation", gain=20.0, cost=1000.0, overlay=WALL_OVERLAY)], ] - dependency = MeasureDependency( - triggers=frozenset({MeasureType.CAVITY_WALL_INSULATION}), - required=ScoredOption( - option=MeasureOption( - measure_type=MeasureType.MECHANICAL_VENTILATION, - description="mechanical_ventilation", - overlay=_VENT_OVERLAY, - cost=Cost(total=300.0, contingency_rate=0.0), - ), - sap_gain=0.0, - ), + dependency = ventilation_dependency( + cost=300.0, triggers=frozenset({MeasureType.CAVITY_WALL_INSULATION}) ) # Act — a Reducing-CO2 brief: maximise carbon reduction within budget. @@ -117,22 +87,21 @@ def test_dependency_signals_are_priced_in_the_objective_currency() -> None: # Assert — the wall survives with its ventilation: the dependency is worth # 0 kg CO2, not −30 SAP, so the package is a net +20 kg saving. - assert {s.option.measure_type for s in package.selected} == { + assert selected_types(package.selected) == { "cavity_wall_insulation", "mechanical_ventilation", } assert abs(package.score.co2_kg_per_yr - 480.0) <= 1e-9 +# Internal wall insulation — a distinct fabric overlay so the fabric-first +# phase-1 pick is unambiguous. No shared fixture (the shared WALL_OVERLAY is a +# cavity fill, type 2); this is a solid-wall internal treatment, type 3. _IWI_OVERLAY = EpcSimulation( building_parts={ BuildingPartIdentifier.MAIN: BuildingPartOverlay(wall_insulation_type=3) } ) -_BOILER_OVERLAY = EpcSimulation(heating=HeatingOverlay(sap_main_heating_code=201)) -_ASHP_OVERLAY = EpcSimulation( - heating=HeatingOverlay(main_heating_index_number=13000) -) class _CarbonHeatingScorer: @@ -166,15 +135,11 @@ def test_fabric_first_phase_two_rescores_in_the_objective_currency() -> None: # Arrange — a fabric-first Reducing-CO2 brief. Phase 1 commits the wall; # phase 2 must choose the heating on its post-fabric *carbon* worth, not # its SAP worth. Signals are supplied in kg CO2 saved (the caller's job). - from domain.modelling.optimisation.optimiser import ( - optimise_package_fabric_first, - ) - groups: list[list[ScoredOption]] = [ - [_scored("internal_wall_insulation", gain=10.0, cost=1000.0, overlay=_IWI_OVERLAY)], + [scored_option("internal_wall_insulation", gain=10.0, cost=1000.0, overlay=_IWI_OVERLAY)], [ - _scored("gas_boiler_upgrade", gain=5.0, cost=2000.0, overlay=_BOILER_OVERLAY), - _scored("air_source_heat_pump", gain=50.0, cost=6000.0, overlay=_ASHP_OVERLAY), + scored_option("gas_boiler_upgrade", gain=5.0, cost=2000.0, overlay=BOILER_OVERLAY), + scored_option("air_source_heat_pump", gain=50.0, cost=6000.0, overlay=ASHP_OVERLAY), ], ] @@ -190,7 +155,7 @@ def test_fabric_first_phase_two_rescores_in_the_objective_currency() -> None: # Assert — the wall plus the heat pump (−50 kg), not the SAP-favoured # boiler; the truthful package carbon is 500 − 10 − 50 = 440. - assert {s.option.measure_type for s in package.selected} == { + assert selected_types(package.selected) == { "internal_wall_insulation", "air_source_heat_pump", }