diff --git a/src/topupopt/problems/esipp/blocks/prices.py b/src/topupopt/problems/esipp/blocks/prices.py index 2af7aa3b810b0c280b2d1a2bbdf1397f37766448..097e9356cbb2541b84513690ea91fd50475fef8f 100644 --- a/src/topupopt/problems/esipp/blocks/prices.py +++ b/src/topupopt/problems/esipp/blocks/prices.py @@ -137,53 +137,54 @@ def price_other_block( # ********************************************************************* # non-convex price functions - # TODO: fix the variables if the function is convex - # delta variables - b.var_active_segment_s = pyo.Var(b.set_S, within=pyo.Binary) - - # segments must be empty if the respective delta variable is zero - def rule_constr_empty_segment_if_delta_zero(b, s): - if len(b.set_S) == 1 or b.param_price_function_is_convex: - # single segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - b.var_trans_flows_s[s] <= - b.param_v_max_s[s]*b.var_active_segment_s[s] + if not b.param_price_function_is_convex: + + # delta variables + b.var_active_segment_s = pyo.Var(b.set_S, within=pyo.Binary) + + # segments must be empty if the respective delta variable is zero + def rule_constr_empty_segment_if_delta_zero(b, s): + if len(b.set_S) == 1 or b.param_price_function_is_convex: + # single segment, skip + # convex, skip + return pyo.Constraint.Skip + return ( + b.var_trans_flows_s[s] <= + b.param_v_max_s[s]*b.var_active_segment_s[s] + ) + b.constr_empty_segment_if_delta_zero = pyo.Constraint( + b.set_S, rule=rule_constr_empty_segment_if_delta_zero ) - b.constr_empty_segment_if_delta_zero = pyo.Constraint( - b.set_S, rule=rule_constr_empty_segment_if_delta_zero - ) - - # if delta var is one, previous ones must be one too - # if delta var is zero, the next ones must also be zero - def rule_constr_delta_summing_logic(b, s): - if s == len(b.set_S)-1 or b.param_price_function_is_convex: - # last segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - b.var_active_segment_s[s] >= - b.var_active_segment_s[s+1] + + # if delta var is one, previous ones must be one too + # if delta var is zero, the next ones must also be zero + def rule_constr_delta_summing_logic(b, s): + if s == len(b.set_S)-1 or b.param_price_function_is_convex: + # last segment, skip + # convex, skip + return pyo.Constraint.Skip + return ( + b.var_active_segment_s[s] >= + b.var_active_segment_s[s+1] + ) + b.constr_delta_summing_logic = pyo.Constraint( + b.set_S, rule=rule_constr_delta_summing_logic ) - b.constr_delta_summing_logic = pyo.Constraint( - b.set_S, rule=rule_constr_delta_summing_logic - ) - - # if a segment is not completely used, the next ones must remain empty - def rule_constr_fill_up_segment_before_next(b, s): - if s == len(b.set_S)-1 or b.param_price_function_is_convex: - # last segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - b.var_trans_flows_s[s] >= - b.var_active_segment_s[s+1]* - b.param_v_max_s[s] + + # if a segment is not completely used, the next ones must remain empty + def rule_constr_fill_up_segment_before_next(b, s): + if s == len(b.set_S)-1 or b.param_price_function_is_convex: + # last segment, skip + # convex, skip + return pyo.Constraint.Skip + return ( + b.var_trans_flows_s[s] >= + b.var_active_segment_s[s+1]* + b.param_v_max_s[s] + ) + b.constr_fill_up_segment_before_next = pyo.Constraint( + b.set_S, rule=rule_constr_fill_up_segment_before_next ) - b.constr_fill_up_segment_before_next = pyo.Constraint( - b.set_S, rule=rule_constr_fill_up_segment_before_next - ) # ********************************************************************* # ********************************************************************* diff --git a/tests/test_esipp.py b/tests/test_esipp.py new file mode 100644 index 0000000000000000000000000000000000000000..1d74c881ef43c0e775fb53eff44d44d92ead0161 --- /dev/null +++ b/tests/test_esipp.py @@ -0,0 +1,224 @@ +# imports + +# local +# import numpy as np +# import networkx as nx +from src.topupopt.problems.esipp.problem import InfrastructurePlanningProblem +from src.topupopt.problems.esipp.network import Network +from src.topupopt.problems.esipp.time import EconomicTimeFrame + +# ***************************************************************************** +# ***************************************************************************** + +def build_solve_ipp( + solver: str = 'glpk', + solver_options: dict = None, + use_sos_arcs: bool = False, + arc_sos_weight_key: str = InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE, + arc_use_real_variables_if_possible: bool = False, + use_sos_sense: bool = False, + sense_sos_weight_key: int = ( + InfrastructurePlanningProblem.SOS1_SENSE_WEIGHT_NOMINAL_HIGHER + ), + sense_use_real_variables_if_possible: bool = False, + sense_use_arc_interfaces: bool = False, + perform_analysis: bool = False, + plot_results: bool = False, + print_solver_output: bool = False, + time_frame: EconomicTimeFrame = None, + networks: dict = None, + converters: dict = None, + static_losses_mode=None, + mandatory_arcs: list = None, + max_number_parallel_arcs: dict = None, + arc_groups_dict: dict = None, + init_aux_sets: bool = False, + # discount_rates: dict = None, + assessment_weights: dict = None, + simplify_problem: bool = False, + use_prices_block: bool = False +): + + if type(assessment_weights) != dict: + assessment_weights = {} # default + + if type(converters) != dict: + converters = {} + + # time weights + + # relative weight of time period + + # one interval twice as long as the average is worth twice + # one interval half as long as the average is worth half + + # time_weights = [ + # [time_period_duration/average_time_interval_duration + # for time_period_duration in intraperiod_time_interval_duration] + # for p in range(number_periods)] + + time_weights = None # nothing yet + + normalised_time_interval_duration = None # nothing yet + + # create problem object + + ipp = InfrastructurePlanningProblem( + # discount_rates=discount_rates, + time_frame=time_frame, + # reporting_periods=time_frame.reporting_periods, + # time_intervals=time_frame.time_interval_durations, + time_weights=time_weights, + normalised_time_interval_duration=normalised_time_interval_duration, + assessment_weights=assessment_weights, + use_prices_block=use_prices_block + ) + + # add networks and systems + + for netkey, net in networks.items(): + ipp.add_network(network_key=netkey, network=net) + + # add converters + + for cvtkey, cvt in converters.items(): + ipp.add_converter(converter_key=cvtkey, converter=cvt) + + # define arcs as mandatory + + if type(mandatory_arcs) == list: + for full_arc_key in mandatory_arcs: + ipp.make_arc_mandatory(full_arc_key[0], full_arc_key[1:]) + + # if make_all_arcs_mandatory: + + # for network_key in ipp.networks: + + # for arc_key in ipp.networks[network_key].edges(keys=True): + + # # preexisting arcs are no good + + # if ipp.networks[network_key].edges[arc_key][ + # Network.KEY_ARC_TECH].has_been_selected(): + + # continue + + # ipp.make_arc_mandatory(network_key, arc_key) + + # set up the use of sos for arc selection + + if use_sos_arcs: + for network_key in ipp.networks: + for arc_key in ipp.networks[network_key].edges(keys=True): + if ( + ipp.networks[network_key] + .edges[arc_key][Network.KEY_ARC_TECH] + .has_been_selected() + ): + # skip arcs that have already been selected (pre-existing) + continue + + ipp.use_sos1_for_arc_selection( + network_key, + arc_key, + use_real_variables_if_possible=( + arc_use_real_variables_if_possible + ), + sos1_weight_method=arc_sos_weight_key, + ) + + # set up the use of sos for flow sense determination + + if use_sos_sense: + for network_key in ipp.networks: + for arc_key in ipp.networks[network_key].edges(keys=True): + if not ipp.networks[network_key].edges[arc_key][ + Network.KEY_ARC_UND + ]: + continue + + ipp.use_sos1_for_flow_senses( + network_key, + arc_key, + use_real_variables_if_possible=( + sense_use_real_variables_if_possible + ), + use_interface_variables=sense_use_arc_interfaces, + sos1_weight_method=sense_sos_weight_key, + ) + + elif sense_use_arc_interfaces: # set up the use of arc interfaces w/o sos1 + for network_key in ipp.networks: + for arc_key in ipp.networks[network_key].edges(keys=True): + if ( + ipp.networks[network_key] + .edges[arc_key][Network.KEY_ARC_TECH] + .has_been_selected() + ): + continue + + ipp.use_interface_variables_for_arc_selection(network_key, arc_key) + + # static losses + + if static_losses_mode == ipp.STATIC_LOSS_MODE_ARR: + ipp.place_static_losses_arrival_node() + + elif static_losses_mode == ipp.STATIC_LOSS_MODE_DEP: + ipp.place_static_losses_departure_node() + + elif static_losses_mode == ipp.STATIC_LOSS_MODE_US: + ipp.place_static_losses_upstream() + + elif static_losses_mode == ipp.STATIC_LOSS_MODE_DS: + ipp.place_static_losses_downstream() + + else: + raise ValueError("Unknown static loss modelling mode.") + + # ********************************************************************* + + # groups + + if type(arc_groups_dict) != type(None): + for key in arc_groups_dict: + ipp.create_arc_group(arc_groups_dict[key]) + + # ********************************************************************* + + # maximum number of parallel arcs + + for key in max_number_parallel_arcs: + ipp.set_maximum_number_parallel_arcs( + network_key=key[0], + node_a=key[1], + node_b=key[2], + limit=max_number_parallel_arcs[key], + ) + + # ********************************************************************* + + if simplify_problem: + ipp.simplify_peak_total_assessments() + + # ********************************************************************* + + # instantiate (disable the default case v-a-v fixed losses) + + # ipp.instantiate(place_fixed_losses_upstream_if_possible=False) + + ipp.instantiate(initialise_ancillary_sets=init_aux_sets) + # ipp.instance.pprint() + # optimise + ipp.optimise( + solver_name=solver, + solver_options=solver_options, + output_options={}, + print_solver_output=print_solver_output, + ) + # ipp.instance.pprint() + # return the problem object + return ipp + +# ***************************************************************************** +# ***************************************************************************** \ No newline at end of file diff --git a/tests/test_esipp_prices.py b/tests/test_esipp_prices.py index a7c6d59d9f707a88b8d6f9b66b150c4d2b187d37..9745b6855f5ea7d7873e42c448e7c351932eb513 100644 --- a/tests/test_esipp_prices.py +++ b/tests/test_esipp_prices.py @@ -19,230 +19,12 @@ from src.topupopt.problems.esipp.resource import ResourcePrice from src.topupopt.problems.esipp.utils import statistics from src.topupopt.problems.esipp.time import EconomicTimeFrame # from src.topupopt.problems.esipp.converter import Converter +from test_esipp import build_solve_ipp # ***************************************************************************** # ***************************************************************************** class TestESIPPProblem: - - solver = 'glpk' - # solver = 'scip' - # solver = 'cbc' - - def build_solve_ipp( - self, - solver: str = None, - solver_options: dict = None, - use_sos_arcs: bool = False, - arc_sos_weight_key: str = (InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE), - arc_use_real_variables_if_possible: bool = False, - use_sos_sense: bool = False, - sense_sos_weight_key: int = ( - InfrastructurePlanningProblem.SOS1_SENSE_WEIGHT_NOMINAL_HIGHER - ), - sense_use_real_variables_if_possible: bool = False, - sense_use_arc_interfaces: bool = False, - perform_analysis: bool = False, - plot_results: bool = False, - print_solver_output: bool = False, - time_frame: EconomicTimeFrame = None, - networks: dict = None, - converters: dict = None, - static_losses_mode=None, - mandatory_arcs: list = None, - max_number_parallel_arcs: dict = None, - arc_groups_dict: dict = None, - init_aux_sets: bool = False, - # discount_rates: dict = None, - assessment_weights: dict = None, - simplify_problem: bool = False, - use_prices_block: bool = False - ): - if type(solver) == type(None): - solver = self.solver - - if type(assessment_weights) != dict: - assessment_weights = {} # default - - if type(converters) != dict: - converters = {} - - # time weights - - # relative weight of time period - - # one interval twice as long as the average is worth twice - # one interval half as long as the average is worth half - - # time_weights = [ - # [time_period_duration/average_time_interval_duration - # for time_period_duration in intraperiod_time_interval_duration] - # for p in range(number_periods)] - - time_weights = None # nothing yet - - normalised_time_interval_duration = None # nothing yet - - # create problem object - - ipp = InfrastructurePlanningProblem( - # discount_rates=discount_rates, - time_frame=time_frame, - # reporting_periods=time_frame.reporting_periods, - # time_intervals=time_frame.time_interval_durations, - time_weights=time_weights, - normalised_time_interval_duration=normalised_time_interval_duration, - assessment_weights=assessment_weights, - use_prices_block=use_prices_block - ) - - # add networks and systems - - for netkey, net in networks.items(): - ipp.add_network(network_key=netkey, network=net) - - # add converters - - for cvtkey, cvt in converters.items(): - ipp.add_converter(converter_key=cvtkey, converter=cvt) - - # define arcs as mandatory - - if type(mandatory_arcs) == list: - for full_arc_key in mandatory_arcs: - ipp.make_arc_mandatory(full_arc_key[0], full_arc_key[1:]) - - # if make_all_arcs_mandatory: - - # for network_key in ipp.networks: - - # for arc_key in ipp.networks[network_key].edges(keys=True): - - # # preexisting arcs are no good - - # if ipp.networks[network_key].edges[arc_key][ - # Network.KEY_ARC_TECH].has_been_selected(): - - # continue - - # ipp.make_arc_mandatory(network_key, arc_key) - - # set up the use of sos for arc selection - - if use_sos_arcs: - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if ( - ipp.networks[network_key] - .edges[arc_key][Network.KEY_ARC_TECH] - .has_been_selected() - ): - continue - - ipp.use_sos1_for_arc_selection( - network_key, - arc_key, - use_real_variables_if_possible=( - arc_use_real_variables_if_possible - ), - sos1_weight_method=arc_sos_weight_key, - ) - - # set up the use of sos for flow sense determination - - if use_sos_sense: - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if not ipp.networks[network_key].edges[arc_key][ - Network.KEY_ARC_UND - ]: - continue - - ipp.use_sos1_for_flow_senses( - network_key, - arc_key, - use_real_variables_if_possible=( - sense_use_real_variables_if_possible - ), - use_interface_variables=sense_use_arc_interfaces, - sos1_weight_method=sense_sos_weight_key, - ) - - elif sense_use_arc_interfaces: # set up the use of arc interfaces w/o sos1 - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if ( - ipp.networks[network_key] - .edges[arc_key][Network.KEY_ARC_TECH] - .has_been_selected() - ): - continue - - ipp.use_interface_variables_for_arc_selection(network_key, arc_key) - - # static losses - - if static_losses_mode == ipp.STATIC_LOSS_MODE_ARR: - ipp.place_static_losses_arrival_node() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_DEP: - ipp.place_static_losses_departure_node() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_US: - ipp.place_static_losses_upstream() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_DS: - ipp.place_static_losses_downstream() - - else: - raise ValueError("Unknown static loss modelling mode.") - - # ********************************************************************* - - # groups - - if type(arc_groups_dict) != type(None): - for key in arc_groups_dict: - ipp.create_arc_group(arc_groups_dict[key]) - - # ********************************************************************* - - # maximum number of parallel arcs - - for key in max_number_parallel_arcs: - ipp.set_maximum_number_parallel_arcs( - network_key=key[0], - node_a=key[1], - node_b=key[2], - limit=max_number_parallel_arcs[key], - ) - - # ********************************************************************* - - if simplify_problem: - ipp.simplify_peak_total_assessments() - - # ********************************************************************* - - # instantiate (disable the default case v-a-v fixed losses) - - # ipp.instantiate(place_fixed_losses_upstream_if_possible=False) - - ipp.instantiate(initialise_ancillary_sets=init_aux_sets) - # ipp.instance.pprint() - # optimise - ipp.optimise( - solver_name=solver, - solver_options=solver_options, - output_options={}, - print_solver_output=print_solver_output, - ) - # ipp.instance.pprint() - # return the problem object - return ipp - - # ********************************************************************* - # ********************************************************************* # ************************************************************************* # ************************************************************************* @@ -293,7 +75,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -397,7 +179,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -412,10 +194,13 @@ class TestESIPPProblem: ) assert not ipp.has_peak_total_assessments() + # print(ipp.results["Problem"][0]["Number of constraints"]) + # print(ipp.results["Problem"][0]["Number of variables"]) + # print(ipp.results["Problem"][0]["Number of nonzeros"]) assert ipp.results["Problem"][0]["Number of constraints"] == 14 # 10 prior to nonconvex block assert ipp.results["Problem"][0]["Number of variables"] == 13 # 11 prior to nonconvex block assert ipp.results["Problem"][0]["Number of nonzeros"] == 28 # 20 prior to nonconvex block - + # ********************************************************************* # ********************************************************************* @@ -504,7 +289,7 @@ class TestESIPPProblem: error_raised = False try: # no sos, regular time intervals - self.build_solve_ipp( + build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -573,7 +358,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_A, node_key_b=node_EXP, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -680,7 +465,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_A, node_key_b=node_EXP, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -790,7 +575,7 @@ class TestESIPPProblem: error_raised = False try: # no sos, regular time intervals - self.build_solve_ipp( + build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -887,7 +672,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_A, node_key_b=node_EXP, arcs=arc_tech_AE) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1038,7 +823,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, diff --git a/tests/test_esipp_problem.py b/tests/test_esipp_problem.py index 511b874aa72c49202f2e425d9e52c927bfe55374..3289150f82a3413f4fda276985de9dacb73d3b6c 100644 --- a/tests/test_esipp_problem.py +++ b/tests/test_esipp_problem.py @@ -4,8 +4,7 @@ import math # local -# import numpy as np -# import networkx as nx +import pytest import pyomo.environ as pyo # import src.topupopt.problems.esipp.utils as utils @@ -18,234 +17,26 @@ from src.topupopt.problems.esipp.resource import ResourcePrice from src.topupopt.problems.esipp.utils import statistics from src.topupopt.problems.esipp.time import EconomicTimeFrame # from src.topupopt.problems.esipp.converter import Converter +from test_esipp import build_solve_ipp # ***************************************************************************** # ***************************************************************************** class TestESIPPProblem: - - solver = 'glpk' - # solver = 'scip' - # solver = 'cbc' - - def build_solve_ipp( - self, - solver: str = None, - solver_options: dict = None, - use_sos_arcs: bool = False, - arc_sos_weight_key: str = (InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE), - arc_use_real_variables_if_possible: bool = False, - use_sos_sense: bool = False, - sense_sos_weight_key: int = ( - InfrastructurePlanningProblem.SOS1_SENSE_WEIGHT_NOMINAL_HIGHER - ), - sense_use_real_variables_if_possible: bool = False, - sense_use_arc_interfaces: bool = False, - perform_analysis: bool = False, - plot_results: bool = False, - print_solver_output: bool = False, - time_frame: EconomicTimeFrame = None, - networks: dict = None, - converters: dict = None, - static_losses_mode=None, - mandatory_arcs: list = None, - max_number_parallel_arcs: dict = None, - arc_groups_dict: dict = None, - init_aux_sets: bool = False, - # discount_rates: dict = None, - assessment_weights: dict = None, - simplify_problem: bool = False, - ): - if type(solver) == type(None): - solver = self.solver - - if type(assessment_weights) != dict: - assessment_weights = {} # default - - if type(converters) != dict: - converters = {} - - # time weights - - # relative weight of time period - - # one interval twice as long as the average is worth twice - # one interval half as long as the average is worth half - - # time_weights = [ - # [time_period_duration/average_time_interval_duration - # for time_period_duration in intraperiod_time_interval_duration] - # for p in range(number_periods)] - - time_weights = None # nothing yet - - normalised_time_interval_duration = None # nothing yet - - # create problem object - - ipp = InfrastructurePlanningProblem( - # discount_rates=discount_rates, - time_frame=time_frame, - # reporting_periods=time_frame.reporting_periods, - # time_intervals=time_frame.time_interval_durations, - time_weights=time_weights, - normalised_time_interval_duration=normalised_time_interval_duration, - assessment_weights=assessment_weights, - ) - - # add networks and systems - - for netkey, net in networks.items(): - ipp.add_network(network_key=netkey, network=net) - - # add converters - - for cvtkey, cvt in converters.items(): - ipp.add_converter(converter_key=cvtkey, converter=cvt) - - # define arcs as mandatory - - if type(mandatory_arcs) == list: - for full_arc_key in mandatory_arcs: - ipp.make_arc_mandatory(full_arc_key[0], full_arc_key[1:]) - - # if make_all_arcs_mandatory: - - # for network_key in ipp.networks: - - # for arc_key in ipp.networks[network_key].edges(keys=True): - - # # preexisting arcs are no good - - # if ipp.networks[network_key].edges[arc_key][ - # Network.KEY_ARC_TECH].has_been_selected(): - - # continue - - # ipp.make_arc_mandatory(network_key, arc_key) - - # set up the use of sos for arc selection - - if use_sos_arcs: - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if ( - ipp.networks[network_key] - .edges[arc_key][Network.KEY_ARC_TECH] - .has_been_selected() - ): - continue - - ipp.use_sos1_for_arc_selection( - network_key, - arc_key, - use_real_variables_if_possible=( - arc_use_real_variables_if_possible - ), - sos1_weight_method=arc_sos_weight_key, - ) - - # set up the use of sos for flow sense determination - - if use_sos_sense: - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if not ipp.networks[network_key].edges[arc_key][ - Network.KEY_ARC_UND - ]: - continue - - ipp.use_sos1_for_flow_senses( - network_key, - arc_key, - use_real_variables_if_possible=( - sense_use_real_variables_if_possible - ), - use_interface_variables=sense_use_arc_interfaces, - sos1_weight_method=sense_sos_weight_key, - ) - - elif sense_use_arc_interfaces: # set up the use of arc interfaces w/o sos1 - for network_key in ipp.networks: - for arc_key in ipp.networks[network_key].edges(keys=True): - if ( - ipp.networks[network_key] - .edges[arc_key][Network.KEY_ARC_TECH] - .has_been_selected() - ): - continue - - ipp.use_interface_variables_for_arc_selection(network_key, arc_key) - - # static losses - - if static_losses_mode == ipp.STATIC_LOSS_MODE_ARR: - ipp.place_static_losses_arrival_node() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_DEP: - ipp.place_static_losses_departure_node() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_US: - ipp.place_static_losses_upstream() - - elif static_losses_mode == ipp.STATIC_LOSS_MODE_DS: - ipp.place_static_losses_downstream() - - else: - raise ValueError("Unknown static loss modelling mode.") - - # ********************************************************************* - - # groups - - if type(arc_groups_dict) != type(None): - for key in arc_groups_dict: - ipp.create_arc_group(arc_groups_dict[key]) - - # ********************************************************************* - - # maximum number of parallel arcs - - for key in max_number_parallel_arcs: - ipp.set_maximum_number_parallel_arcs( - network_key=key[0], - node_a=key[1], - node_b=key[2], - limit=max_number_parallel_arcs[key], - ) - - # ********************************************************************* - - if simplify_problem: - ipp.simplify_peak_total_assessments() - - # ********************************************************************* - - # instantiate (disable the default case v-a-v fixed losses) - - # ipp.instantiate(place_fixed_losses_upstream_if_possible=False) - - ipp.instantiate(initialise_ancillary_sets=init_aux_sets) - - # optimise - ipp.optimise( - solver_name=solver, - solver_options=solver_options, - output_options={}, - print_solver_output=print_solver_output, - ) - - # return the problem object - - return ipp - - # ********************************************************************* - # ********************************************************************* # ************************************************************************* # ************************************************************************* - - def test_single_network_single_arc_problem(self): + + @pytest.mark.parametrize( + "use_sos_arcs, arc_sos_weight_key", + [(True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_CAP), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_COST), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_SPEC_CAP), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_SPEC_COST), + (False, None)] + ) + def test_single_network_single_arc_problem(self, use_sos_arcs, arc_sos_weight_key): # assessment q = 0 @@ -292,8 +83,10 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, + use_sos_arcs=use_sos_arcs, + arc_sos_weight_key=arc_sos_weight_key, perform_analysis=False, plot_results=False, # True, print_solver_output=False, @@ -358,7 +151,7 @@ class TestESIPPProblem: # ************************************************************************* # ************************************************************************* - + def test_single_network_two_arcs_problem(self): # TODO: test simplifying this problem @@ -433,8 +226,10 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_A, node_key_b=node_EXP, arcs=arc_tech_AE) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, + # use_sos_arcs=use_sos_arcs, + # arc_sos_weight_key=arc_sos_weight_key, perform_analysis=False, plot_results=False, # True, print_solver_output=False, @@ -501,7 +296,16 @@ class TestESIPPProblem: # ************************************************************************* # ************************************************************************* - def test_single_network_single_arc_problem_simpler(self): + @pytest.mark.parametrize( + "use_sos_arcs, arc_sos_weight_key", + [(True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_CAP), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_COST), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_SPEC_CAP), + (True, InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_SPEC_COST), + (False, None)] + ) + def test_single_network_single_arc_problem_simpler(self, use_sos_arcs, arc_sos_weight_key): # assessment q = 0 @@ -549,7 +353,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -653,7 +457,7 @@ class TestESIPPProblem: # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -773,7 +577,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -856,7 +660,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -979,7 +783,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=node_IMP, node_key_b=node_A, arcs=arc_tech_IA) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1069,7 +873,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1159,7 +963,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, @@ -1260,7 +1064,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1327,7 +1131,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1452,7 +1256,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1619,7 +1423,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1781,7 +1585,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -1919,7 +1723,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={},solver='scip', perform_analysis=False, plot_results=False, # True, @@ -2146,7 +1950,7 @@ class TestESIPPProblem: solver_options["relative_mip_gap"] = 0 solver_options["absolute_mip_gap"] = 1e-4 - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options=solver_options, use_sos_arcs=False, arc_sos_weight_key=None, @@ -2480,7 +2284,7 @@ class TestESIPPProblem: solver_options["relative_mip_gap"] = 0 solver_options["absolute_mip_gap"] = 1e-4 - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options=solver_options, use_sos_arcs=False, arc_sos_weight_key=None, @@ -2765,7 +2569,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options=solver_options, use_sos_arcs=False, arc_sos_weight_key=None, @@ -3073,7 +2877,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options=solver_options, perform_analysis=False, plot_results=False, # True, @@ -3241,7 +3045,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -3425,7 +3229,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, use_sos_arcs=False, arc_sos_weight_key=None, @@ -3812,7 +3616,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, use_sos_arcs=False, arc_sos_weight_key=None, @@ -4203,7 +4007,7 @@ class TestESIPPProblem: for static_losses_mode in InfrastructurePlanningProblem.STATIC_LOSS_MODES: - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -4825,7 +4629,7 @@ class TestESIPPProblem: for static_losses_mode in InfrastructurePlanningProblem.STATIC_LOSS_MODES: - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -5394,7 +5198,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, @@ -5541,7 +5345,7 @@ class TestESIPPProblem: InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP ]: # TODO: make this work with GLPK and SCIP - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver='cbc', # does not work with GLPK nor SCIP solver_options={}, perform_analysis=False, @@ -5690,7 +5494,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -5964,7 +5768,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -6244,7 +6048,7 @@ class TestESIPPProblem: Network.KEY_ARC_TECH].options_selected.index(True) ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -6519,7 +6323,7 @@ class TestESIPPProblem: # Network.KEY_ARC_TECH].options_selected.index(True) # ] = False - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -6824,7 +6628,7 @@ class TestESIPPProblem: # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, plot_results=False, # True, print_solver_output=False, @@ -6989,7 +6793,7 @@ class TestESIPPProblem: # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver='cbc', # TODO: make this work with other solvers solver_options={}, plot_results=False, # True, @@ -7129,7 +6933,7 @@ class TestESIPPProblem: mynet.add_directed_arc(node_key_a=imp_node_key, node_key_b=node_A, arcs=arcs_ia2) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver='cbc', # TODO: make this work with other solvers solver_options={}, plot_results=False, # True, @@ -7256,7 +7060,7 @@ class TestESIPPProblem: ) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver='cbc', # TODO: make this work with other solvers solver_options={}, plot_results=False, # True, @@ -7417,7 +7221,7 @@ class TestESIPPProblem: # # no sos, regular time intervals - # ipp = self.build_solve_ipp( + # ipp = build_solve_ipp( # solver_options={}, # perform_analysis=False, # plot_results=False, # True, @@ -7581,7 +7385,7 @@ class TestESIPPProblem: mynet.add_directed_arc(*node_pair, arcs=new_arc_tech) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -7724,7 +7528,7 @@ class TestESIPPProblem: mynet.add_directed_arc(*node_pair, arcs=new_arc_tech) # no sos, regular time intervals - ipp = self.build_solve_ipp( + ipp = build_solve_ipp( solver_options={}, perform_analysis=False, plot_results=False, # True, diff --git a/tests/test_solvers.py b/tests/test_solvers.py index 7f0a728322c65e460f30796ddecb72760290b8a4..44a28c895df299ea944f2c03b8563fc8a67c9f73 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -12,6 +12,7 @@ import random # ***************************************************************************** # ***************************************************************************** +# TODO: use pytest to parameterise the tests to use different solvers class TestSolvers: # *************************************************************************