Skip to content
Snippets Groups Projects
test_esipp_problem.py 269 KiB
Newer Older
  • Learn to ignore specific revisions
  •         mynet.identify_node_types()
    
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                networks={"mynet": mynet},
                converters={},
                time_frame=tf,
                static_losses_mode=True,  # just to reach a line,
                mandatory_arcs=[],
                max_number_parallel_arcs={},
                assessment_weights=assessment_weights,
                simplify_problem=True
            )
            
    
            assert ipp.has_peak_total_assessments()
            assert ipp.results["Problem"][0]["Number of constraints"] == 28 # 42
            assert ipp.results["Problem"][0]["Number of variables"] == 25 # 38
            assert ipp.results["Problem"][0]["Number of nonzeros"] == 51 # 87
    
    
            # *********************************************************************
    
            # validation
            # arc amplitude should be two
            assert math.isclose(
                pyo.value(ipp.instance.var_v_amp_gllj[("mynet", node_IMP, node_A, 0)]),
                2.5,
                abs_tol=0.01,
            )
            # capex should be four
            assert math.isclose(pyo.value(ipp.instance.var_capex), 4.5, abs_tol=1e-3)
            # sdncf_q[0] should be -5.7
    
            # assert math.isclose(pyo.value(ipp.instance.var_sdncf_q[0]), -5.7, abs_tol=1e-3)
    
            # the objective function should be -10.80213032963115 (or -10.8027723516153)
            assert math.isclose(pyo.value(ipp.instance.obj_f), -10.80213032963115, abs_tol=3e-3)
            
        # *************************************************************************
        # *************************************************************************
        
        # problem with two symmetrical nodes and one undirected arc
        # problem with symmetrical nodes and one undirected arc with diff. tech.
        # problem with symmetrical nodes and one undirected arc, irregular steps
        # same problem as the previous one, except with interface variables
        # problem with two symmetrical nodes and one undirected arc, w/ simple sos1
            
        def test_isolated_undirected_network(self):
            
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,)},
                reporting_period_durations={q: (365 * 24 * 3600,)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5],
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5],
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
            # undirected arc
            arc_tech_AB = ArcsWithoutStaticLosses(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=True,  # just to reach a line,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
    
            assert ipp.has_peak_total_assessments() # TODO: make sure this is true
    
            assert ipp.results["Problem"][0]["Number of constraints"] == 34
            assert ipp.results["Problem"][0]["Number of variables"] == 28
            assert ipp.results["Problem"][0]["Number of nonzeros"] == 105
        
            # *********************************************************************
            # *********************************************************************
        
            # validation
        
            # the arc should be installed since it is the only feasible solution
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # there should be no opex (imports or exports), only capex from arcs
            assert pyo.value(ipp.instance.var_sdncf_q[q]) == 0
            assert pyo.value(ipp.instance.var_capex) > 0
            assert (
                pyo.value(
                    ipp.instance.var_capex_arc_gllj[("mynet", node_A, node_B, arc_key_AB_und)]
                )
                > 0
            )
            
        # *************************************************************************
        # *************************************************************************
        
        def test_isolated_undirected_network_diff_tech(self):
            
            # time frame
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,)},
                reporting_period_durations={q: (365 * 24 * 3600,)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5]
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
        
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1.25, 1, -0.625, 0.5]
                base_flow={(0, 0): -1.25, (0, 1): 1.0, (0, 2): -0.625, (0, 3): 0.5},
            )
        
            # add arcs
            # undirected arc
            arc_tech_AB = ArcsWithoutStaticLosses(
                name="any",
                # efficiency=[0.8, 1.0, 0.8, 1.0],
                efficiency={(0, 0): 0.8, (0, 1): 1.0, (0, 2): 0.8, (0, 3): 1.0},
                efficiency_reverse=None,
                capacity=[1.25, 2.5],
                minimum_cost=[10, 15],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
    
            assert ipp.has_peak_total_assessments()
    
            assert ipp.results["Problem"][0]["Number of constraints"] == 34
            assert ipp.results["Problem"][0]["Number of variables"] == 24
            assert ipp.results["Problem"][0]["Number of nonzeros"] == 77
        
            # *********************************************************************
            # *********************************************************************
        
            # validation
        
            # the arc should be installed since it is the only feasible solution
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # there should be no opex (imports or exports), only capex from arcs
            assert pyo.value(ipp.instance.var_sdncf_q[q]) == 0
            assert pyo.value(ipp.instance.var_capex) > 0
            assert (
                pyo.value(
                    ipp.instance.var_capex_arc_gllj[("mynet", node_A, node_B, arc_key_AB_und)]
                )
                > 0
            )
        
            # *********************************************************************
            # *********************************************************************
            
        # *************************************************************************
        # *************************************************************************
    
        
        # preexisting, reference
        # capacity is instantaneous
        # use dedicated method for preexisting arcs
        # capacity is instantaneous, using dedicated method
        # use different technologies for the undirected arc
        # use different technologies for the undirected arc, capacity is instant.
        # use different technologies for the undirected arc, using specific method
        # same as before but assuming the capacity is instantaneous
    
        def test_isolated_preexisting_undirected_network(self):
    
            capacity_is_instantaneous = False
    
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
    
                reporting_periods={q: (0,)},
                reporting_period_durations={q: (365 * 24 * 3600,)},
    
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5]
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
    
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
    
                # base_flow=[-1, 1, -0.5, 0.5],
    
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
    
            # isotropic
            mynet.add_preexisting_undirected_arc(
                node_key_a=node_A,
                node_key_b=node_B,
    
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
    
                capacity=1.0,
                capacity_is_instantaneous=capacity_is_instantaneous,
    
            # identify node types
            mynet.identify_node_types()
    
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
            # validation
            # there should be no opex (imports or exports) and no capex
            assert pyo.value(ipp.instance.var_sdncf_q[q]) == 0
            assert pyo.value(ipp.instance.var_capex) == 0
                            
        # *************************************************************************
        # *************************************************************************
    
        def test_isolated_preexisting_undirected_network_diff_tech(self):
            
            capacity_is_instantaneous = False
            
            # assessment
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,)},
                reporting_period_durations={q: (365 * 24 * 3600,)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5]
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
    
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5],
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
            # anisotropic
            mynet.add_preexisting_undirected_arc(
                node_key_a=node_A,
                node_key_b=node_B,
                # efficiency=[0.9, 1, 0.9, 1],
                efficiency={(0, 0): 0.9, (0, 1): 1, (0, 2): 0.9, (0, 3): 1},
                capacity=1.0,
                capacity_is_instantaneous=capacity_is_instantaneous,
                # efficiency_reverse=[1, 0.9, 1, 0.9],
                efficiency_reverse={(0, 0): 1, (0, 1): 0.9, (0, 2): 1, (0, 3): 0.9},
                static_loss=None,
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
            # validation
            # there should be no opex (imports or exports) and no capex
            assert pyo.value(ipp.instance.var_sdncf_q[q]) == 0
            assert pyo.value(ipp.instance.var_capex) == 0
        
        # *************************************************************************
        # *************************************************************************
            
        def test_nonisolated_undirected_network(self):
            
            # scenario
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0, 1)},
                reporting_period_durations={q: (365 * 24 * 3600, 365 * 24 * 3600)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
        
            mynet = Network()
        
            # import node    
    
            mynet.add_import_node(
                node_key=imp_node_key,
                prices={
                    qpk: ResourcePrice(prices=1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # export node    
    
            mynet.add_export_node(
                node_key=exp_node_key,
                prices={
                    qpk: ResourcePrice(prices=0.1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5]
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5]
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
        
            # import arc
            arc_tech_IA = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
            )
            mynet.add_directed_arc(
                node_key_a=imp_node_key, node_key_b=node_A, arcs=arc_tech_IA
            )
        
            # export arc
        
            arc_tech_BE = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
            )
            mynet.add_directed_arc(
                node_key_a=node_B, node_key_b=exp_node_key, arcs=arc_tech_BE
            )
    
        
            # undirected arc
            arc_tech_AB = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10.0, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
    
            assert ipp.has_peak_total_assessments()
    
            assert ipp.results["Problem"][0]["Number of constraints"] == 80
            assert ipp.results["Problem"][0]["Number of variables"] == 84
            assert ipp.results["Problem"][0]["Number of nonzeros"] == 253
        
            # **************************************************************************
        
            # validation
            # network is still isolated
            # the import arc was not installed
        
            assert (
                True
                not in ipp.networks["mynet"]
                .edges[(imp_node_key, node_A, 0)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # the export arc was not installed
        
            assert (
                True
                not in ipp.networks["mynet"]
                .edges[(node_B, exp_node_key, 0)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # the undirected arc was installed
        
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # the opex should be zero
        
            assert math.isclose(pyo.value(ipp.instance.var_sdncf_q[q]), 0, abs_tol=1e-6)
        
            # the capex should be positive
        
            assert pyo.value(ipp.instance.var_capex) > 0
        
        
            # *********************************************************************
            # *********************************************************************
            
        # *************************************************************************
        # *************************************************************************
                
        def test_nonisolated_undirected_network_diff_tech(self):
            
            # scenario
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,1)},
                reporting_period_durations={q: (365 * 24 * 3600,365 * 24 * 3600)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # import node
    
            mynet.add_import_node(
                node_key=imp_node_key,
                prices={
                    qpk: ResourcePrice(prices=1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # export node
    
            mynet.add_export_node(
                node_key=exp_node_key,
                prices={
                    qpk: ResourcePrice(prices=0.1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5]
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
        
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5]
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
            # import arc
            arc_tech_IA = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
            )
            mynet.add_directed_arc(
                node_key_a=imp_node_key, node_key_b=node_A, arcs=arc_tech_IA
            )
        
            # export arc
            arc_tech_BE = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
            )
            mynet.add_directed_arc(
                node_key_a=node_B, node_key_b=exp_node_key, arcs=arc_tech_BE
            )
            
            # undirected arc
            arc_tech_AB = Arcs(
                name="any",
                # efficiency=[0.95, 0.95, 0.95, 0.95],
                efficiency={(0, 0): 0.95, (0, 1): 0.95, (0, 2): 0.95, (0, 3): 0.95},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
                # efficiency_reverse=[0.85, 0.85, 0.85, 0.85],
                efficiency_reverse={(0, 0): 0.85, (0, 1): 0.85, (0, 2): 0.85, (0, 3): 0.85},
                static_loss=None,
                validate=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={}
            )
            
    
            assert ipp.has_peak_total_assessments()
    
            assert ipp.results["Problem"][0]["Number of constraints"] == 80
            assert ipp.results["Problem"][0]["Number of variables"] == 84
            assert ipp.results["Problem"][0]["Number of nonzeros"] == 253
        
            # *********************************************************************
            # *********************************************************************
        
            # validation
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
    
            # the directed arc from the import should also be installed since node
            # B cannot fullfil all the demand since it has an efficiency of 0.85<1
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(imp_node_key, node_A, 0)][Network.KEY_ARC_TECH]
                .options_selected
            )
    
            # there should be no opex (imports or exports), only capex from arcs
            assert pyo.value(ipp.instance.var_sdncf_q[q]) < 0
            assert pyo.value(ipp.instance.var_capex) > 0
            assert (
                pyo.value(
                    ipp.instance.var_capex_arc_gllj[
                        ("mynet", node_A, node_B, arc_key_AB_und)
                    ]
                )
                > 0
            )
            assert (
                pyo.value(
                    ipp.instance.var_capex_arc_gllj[("mynet", imp_node_key, node_A, 0)]
                )
                > 0
            )
        
            # *********************************************************************
            # *********************************************************************
    
        # *************************************************************************
        # *************************************************************************
        
        def test_nonisolated_network_preexisting_directed_arcs(self):
            
            # time frame
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,1)},
                reporting_period_durations={q: (365 * 24 * 3600,365 * 24 * 3600)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # import node
    
            mynet.add_import_node(
                node_key=imp_node_key,
                prices={
                    qpk: ResourcePrice(prices=1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # export node
    
            mynet.add_export_node(
                node_key=exp_node_key,
                prices={
                    qpk: ResourcePrice(prices=0.1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5],
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5],
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
            # import arc
            arc_tech_IA = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_tech_IA.options_selected[0] = True
            mynet.add_directed_arc(node_key_a=imp_node_key, node_key_b=node_A, arcs=arc_tech_IA)
        
            # export arc
            arc_tech_BE = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_tech_BE.options_selected[0] = True
            mynet.add_directed_arc(node_key_a=node_B, node_key_b=exp_node_key, arcs=arc_tech_BE)
        
            # undirected arc
            # isotropic arc
            arc_tech_AB = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10.0, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
                solver_options={},
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={},
            )
        
            # *********************************************************************
        
            # validation
            # network is still isolated
            # the undirected arc was installed
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
    
            # the opex should be zero
            assert math.isclose(pyo.value(ipp.instance.var_sdncf_q[q]), 0, abs_tol=1e-3)
    
            # the capex should be positive
            assert pyo.value(ipp.instance.var_capex) > 0
        
            # *********************************************************************
            # *********************************************************************
            
        # *************************************************************************
        # *************************************************************************
        
        def test_nonisolated_network_preexisting_directed_arcs_diff_tech(self):
            
            # time frame
            q = 0
            tf = EconomicTimeFrame(
                discount_rate=3.5/100,
                reporting_periods={q: (0,1)},
                reporting_period_durations={q: (365 * 24 * 3600,365 * 24 * 3600)},
                time_intervals={q: (0,1,2,3)},
                time_interval_durations={q: (1,1,1,1)},
            )
        
            # 4 nodes: one import, one export, two supply/demand nodes
            mynet = Network()
        
            # import node
    
            mynet.add_import_node(
                node_key=imp_node_key,
                prices={
                    qpk: ResourcePrice(prices=1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # export node
    
            mynet.add_export_node(
                node_key=exp_node_key,
                prices={
                    qpk: ResourcePrice(prices=0.1+i*0.05, volumes=None)
                    for i, qpk in enumerate(tf.qpk())
                },
            )
        
            # other nodes
            node_A = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_A,
                # base_flow=[1, -1, 0.5, -0.5],
                base_flow={(0, 0): 1, (0, 1): -1, (0, 2): 0.5, (0, 3): -0.5},
            )
            node_B = generate_pseudo_unique_key(mynet.nodes())
            mynet.add_source_sink_node(
                node_key=node_B,
                # base_flow=[-1, 1, -0.5, 0.5],
                base_flow={(0, 0): -1, (0, 1): 1, (0, 2): -0.5, (0, 3): 0.5},
            )
        
            # add arcs
            # import arc
            arc_tech_IA = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_tech_IA.options_selected[0] = True
            mynet.add_directed_arc(node_key_a=imp_node_key, node_key_b=node_A, arcs=arc_tech_IA)
        
            # export arc
            arc_tech_BE = Arcs(
                name="any",
                # efficiency=[1, 1, 1, 1],
                efficiency={(0, 0): 1, (0, 1): 1, (0, 2): 1, (0, 3): 1},
                efficiency_reverse=None,
                static_loss=None,
                validate=False,
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_tech_BE.options_selected[0] = True
            mynet.add_directed_arc(node_key_a=node_B, node_key_b=exp_node_key, arcs=arc_tech_BE)
        
            # undirected arc
            # anisotropic arc
            arc_tech_AB = Arcs(
                name="any",
                # efficiency=[0.95, 0.95, 0.95, 0.95],
                efficiency={(0, 0): 0.95, (0, 1): 0.95, (0, 2): 0.95, (0, 3): 0.95},
                capacity=[0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
                minimum_cost=[10, 10.1, 10.2, 10.3, 10.4, 10.5],
                # efficiency_reverse=[0.85, 0.85, 0.85, 0.85],
                efficiency_reverse={(0, 0): 0.85, (0, 1): 0.85, (0, 2): 0.85, (0, 3): 0.85},
                static_loss=None,
                validate=False,
                specific_capacity_cost=1,
                capacity_is_instantaneous=False,
            )
            arc_key_AB_und = mynet.add_undirected_arc(
                node_key_a=node_A, node_key_b=node_B, arcs=arc_tech_AB
            )
        
            # identify node types
            mynet.identify_node_types()
        
            # no sos, regular time intervals
            ipp = self.build_solve_ipp(
    
                perform_analysis=False,
                plot_results=False,  # True,
                print_solver_output=False,
                time_frame=tf,
                networks={"mynet": mynet},
                static_losses_mode=InfrastructurePlanningProblem.STATIC_LOSS_MODE_DEP,
                mandatory_arcs=[],
                max_number_parallel_arcs={},
            )
        
            # **************************************************************************
        
            # validation
            # the undirected arc should be installed since it is cheaper tham imp.
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(node_A, node_B, arc_key_AB_und)][Network.KEY_ARC_TECH]
                .options_selected
            )
        
            # the directed arc from the import should also be installed since node
            # B cannot fullfil all the demand since it has an efficiency of 0.85<1
        
            assert (
                True
                in ipp.networks["mynet"]
                .edges[(imp_node_key, node_A, 0)][Network.KEY_ARC_TECH]
                .options_selected
            )