Skip to content
Snippets Groups Projects
test_esipp_network.py 78.6 KiB
Newer Older
# imports

# standard

import random

from networkx import binomial_tree, MultiDiGraph

# local

from src.topupopt.problems.esipp.network import Arcs, Network

from src.topupopt.problems.esipp.network import ArcsWithoutLosses

from src.topupopt.problems.esipp.network import ArcsWithoutProportionalLosses

from src.topupopt.problems.esipp.network import ArcsWithoutStaticLosses

from src.topupopt.problems.esipp.resource import ResourcePrice

from src.topupopt.data.misc.utils import generate_pseudo_unique_key

# *****************************************************************************
# *****************************************************************************

class TestNetwork:
    # *************************************************************************
    # *************************************************************************
    def test_arc_technologies_static_losses(self):
        number_time_intervals = 3
        number_scenarios = 2
        number_options = 4
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            (q, k): 0.95
            for q in range(number_scenarios)
            for k in range(number_time_intervals)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            (h, q, k): 1
            for h in range(number_options)
            for q in range(number_scenarios)
            for k in range(number_time_intervals)
        for capacity_is_instantaneous in (True, False):
            arc_tech = Arcs(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency=efficiency_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
                static_loss=static_loss_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
                static_loss=static_loss_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert not arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            # create arc technology with only one option
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
                capacity=(1,),
                minimum_cost=(1,),
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
                static_loss={
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    (0, q, k): 1
                    # for h in range(number_options)
                    for q in range(number_scenarios)
                    for k in range(number_time_intervals)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                },
                validate=True,
            )

            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            # create arc technology for one time interval
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={
                    (q, 0): 0.5
                    for q in range(number_scenarios)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    # for k in range(number_time_intervals)
                },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
                static_loss={
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    (h, q, 0): 1
                    for h in range(number_options)
                    for q in range(number_scenarios)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    # for k in range(number_time_intervals)
                },
                validate=True,
            )

            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            # *********************************************************************
            # TypeError: The static losses should be given as a dict or None.
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss=tuple(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        [k for k in range(number_time_intervals)]
                        for o in range(number_options)
                    ),
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError('The static losses should be specified for each arc
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss={
                        for h in range(number_options)
                        for q in range(number_scenarios)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    },
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError('The static losses must be specified via a list of lists.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss=[
                        tuple(k for k in range(number_time_intervals))
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        for o in range(number_options)
                    ],
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('The static loss values are inconsistent with the number '
            # 'of options, scenarios and intervals.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss={
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (h, q, k): 1
                        for h in range(number_options)
                        for q in range(number_scenarios)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        for k in range(number_time_intervals - 1)
                    },
                    validate=True,
                )

                arc_tech.validate_sizes(
                    number_options=number_options,
                    number_scenarios=number_scenarios,
                    number_intervals=[
                        number_time_intervals for _ in range(number_scenarios)
                    ],
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError('The static losses were not provided as numbers.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss={
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (h, q, k): str(3.54)
                        for h in range(number_options)
                        for q in range(number_scenarios)
                        for k in range(number_time_intervals)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    },
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('The static losses must be positive or zero.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="any",
                    efficiency=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
                    static_loss={
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (h, q, k): -random.randint(0, 1) * random.random()
                        for h in range(number_options)
                        for q in range(number_scenarios)
                        for k in range(number_time_intervals)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    },
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError: The static loss dict keys must be tuples
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    static_loss={k: 1 for k in range(number_time_intervals)},
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError( 'The static loss dict keys must be tuples of size 3.')

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    static_loss={(k, 3): 1 for k in range(number_time_intervals)},
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError(The staticl osses should be given as a dict or None.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=None,
                    efficiency_reverse=None,
                    static_loss=[1 for k in range(number_time_intervals)],
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError(
            #     'No static loss values were provided. There should be one'+
            #     ' value per option, scenario and time interval.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    static_loss={},
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
    # *************************************************************************
    # *************************************************************************

    def test_arc_technologies(self):
        # *********************************************************************
        # create arc technology using instantaneous capacities
        number_scenarios = 2
        number_options = 4
        number_time_intervals = 3
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            (q, k): 0.85
            for q in range(number_scenarios)
            for k in range(number_time_intervals)
        for capacity_is_instantaneous in (True, False):
            arc_tech = Arcs(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert arc_tech.has_constant_efficiency()
            # create arc technology with only one option
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
                static_loss=None,
                capacity=(1,),
                minimum_cost=(1,),
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert arc_tech.has_constant_efficiency()
            # create arc technology for one time interval
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={(0, 0): 0.95},
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert arc_tech.has_constant_efficiency()
            # create arc technology for one time interval and isotropic
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={(0, 0): 0.95},
                efficiency_reverse={(0, 0): 0.95},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert arc_tech.has_constant_efficiency()
            # create arc technology for one time interval and anisotropic
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={(0, 0): 0.95},
                efficiency_reverse={(0, 0): 1},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert not arc_tech.has_constant_efficiency()
            # create arc technology for one time interval and anisotropic
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={(0, 0): 1},
                efficiency_reverse={(0, 0): 0.95},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert not arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert not arc_tech.has_constant_efficiency()
            # create arc technology for one time interval and anisotropic
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="any",
                efficiency={(0, 0): 0.95},
                efficiency_reverse={(0, 0): 0.95},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            assert arc_tech.has_proportional_losses()
            assert not arc_tech.is_infinite_capacity()
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=True)
            assert arc_tech.is_isotropic(reverse_none_means_isotropic=False)
            assert arc_tech.has_constant_efficiency()
            # *****************************************************************
            # *****************************************************************
            # TypeError('The name attribute is not hashable.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name=[1, 2, 3],
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # TypeError:The efficiency dict keys must be (scenario, interval) tuples

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency={k: 1 for k in range(number_time_intervals)},
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError( 'The efficiency dict keys must be tuples of size 2.')

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency={(k, 3, 4): 1 for k in range(number_time_intervals)},
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError(The efficiency should be given as a dict or None.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=[1 for k in range(number_time_intervals)],
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # TypeError('The reverse efficiency has to match the nominal'+
            #     ' one when there are no proportional losses.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=None,
                    efficiency_reverse={},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # TypeError:'The reverse efficiency should be given as a dict or None.'
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=[1 for k in range(number_time_intervals)],
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError(
            #     'No efficiency values were provided. There should be '+
            #     'one value per scenario and time interval.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse={},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # ValueError: The keys for the efficiency dicts do not match.
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (key[1], key[0]): value
                        for key, value in efficiency_dict.items()
                    },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError: Efficiency values must be provided as numeric types.
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (key[0], key[1]): str(value)
                        for key, value in efficiency_dict.items()
                    },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('Efficiency values must be positive.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (key[0], key[1]): -1 for key, value in efficiency_dict.items()
                    },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # TypeError('The capacity should be given as a list or tuple.')

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity={o: 1 + o for o in range(number_options)},
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # TypeError: The minimum cost values should be given as a list or tuple
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost={o: 1 + o for o in range(number_options)},
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # TypeError: The specific capacity cost was not given as a numeric type
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=[1],
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError:The number of capacity and minimum cost entries must match
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options + 1)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError: No entries for capacity and minimum cost were provided.
            # At least one option should be provided.
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
                    static_loss=None,
                    capacity=tuple(),
                    minimum_cost=tuple(),
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError: No entries for efficiency were provided. There should be
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency={},
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError('The number of efficiency values must match the number of
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    (q, k): 0.85
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    for k in range(number_time_intervals + 1)
                },
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                arc_tech.validate_sizes(
                    number_options=number_options,
                    number_scenarios=number_scenarios,
                    number_intervals=[
                        number_time_intervals for _ in range(number_scenarios)
                    ],
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError('The number of efficiency values must match the number of
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (q, k): 0.85
                        for q in range(number_scenarios)
                        for k in range(number_time_intervals)
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        (q, k): 0.85
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                        for k in range(number_time_intervals - 1)
                    },
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
                arc_tech.validate_sizes(
                    number_options=number_options,
                    number_scenarios=number_scenarios,
                    number_intervals=[
                        number_time_intervals for _ in range(number_scenarios)
                    ],
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError('The number of capacity values must match the number of
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="hey",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options + 1)),
                minimum_cost=tuple(1 + o for o in range(number_options + 1)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                arc_tech.validate_sizes(
                    number_options=number_options,
                    number_scenarios=number_scenarios,
                    number_intervals=[
                        number_time_intervals for _ in range(number_scenarios)
                    ],
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            # ValueError: The minimum cost values are inconsistent with the number
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="hey",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options + 1)),
                minimum_cost=tuple(1 + o for o in range(number_options + 1)),
                specific_capacity_cost=1,
                capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                arc_tech.validate_sizes(
                    number_options=number_options,
                    number_scenarios=number_scenarios,
                    number_intervals=[
                        number_time_intervals for _ in range(number_scenarios)
                    ],
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError('Efficiency values must be provided as numeric types.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency={
                        key: str(value) for key, value in efficiency_dict.items()
                    },
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('Efficiency values must be positive.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency={
                        key: -value * random.randint(0, 1)
                        for key, value in efficiency_dict.items()
                    },
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError('Capacity values must be provided as numeric types.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(str(1 + o) for o in range(number_options)),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('Capacity values must be positive.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(
                        -random.randint(0, 1) for o in range(number_options)
                    ),
                    minimum_cost=tuple(1 + o for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
            # TypeError('Minimum cost values must be provided as numeric types.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    efficiency_reverse=None,
                    static_loss=None,
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(str(1 + o) for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except TypeError:
                error_triggered = True
            assert error_triggered
            # ValueError('Minimum cost values must be positive or zero.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

            error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    name="hey",
                    efficiency=efficiency_dict,
                    efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    capacity=tuple(1 + o for o in range(number_options)),
                    minimum_cost=tuple(-1 for o in range(number_options)),
                    specific_capacity_cost=1,
                    capacity_is_instantaneous=capacity_is_instantaneous,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                    validate=True,
                )
            except ValueError:
                error_triggered = True
            assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        # TypeError('The information about capacities being instantaneous or not
        # should be given as a boolean variable.')
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        error_triggered = False
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                name="hey",
                efficiency=efficiency_dict,
                efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                capacity=tuple(1 + o for o in range(number_options)),
                minimum_cost=tuple(1 + o for o in range(number_options)),
                specific_capacity_cost=1,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                validate=True,
            )
        except TypeError:
            error_triggered = True
        assert error_triggered
        # *********************************************************************
        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="AB",
            efficiency=efficiency_dict,
            efficiency_reverse=None,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            capacity=tuple(1 + o for o in range(number_options)),
            minimum_cost=tuple(1 + o for o in range(number_options)),
            specific_capacity_cost=1,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            validate=True,
        )

        assert arc_tech_AB.number_options() == number_options
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_undirected_arc(node_key_a="A", node_key_b="B", arcs=arc_tech_AB)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_directed_arc(node_key_a="A", node_key_b="B", arcs=arc_tech_AB)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key_a="C",
            node_key_b="D",
            efficiency={(i, j): 1 for i in range(3) for j in range(4)},
            static_loss=None,
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key_a="E",
            node_key_b="F",
            efficiency=efficiency_dict,
            static_loss=None,
            capacity=3,
            capacity_is_instantaneous=True,
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key_a="A",
            node_key_b="C",
            efficiency=efficiency_dict,
            efficiency_reverse=efficiency_dict,
            static_loss=None,
            capacity=3,
            capacity_is_instantaneous=True,
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key_a="A",
            node_key_b="C",
            arc_key_ab="AC",
            data_dict={net.KEY_ARC_TECH: arc_tech_AB, net.KEY_ARC_UND: False},
        )

        # *********************************************************************
        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            prices=[random.random() for k in range(number_time_intervals)],
            volumes=[
                *[random.random() for k in range(number_time_intervals - 1)],
                None,
            ],
        )

        net.add_import_node(node_key="G", prices={(0, 0, 0): imp_resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            prices=[random.random() for k in range(number_time_intervals)],
            volumes=[
                *[random.random() for k in range(number_time_intervals - 1)],
                None,
            ],
        )

        net.add_export_node(node_key="H", prices={(0, 0, 0): exp_resource_price})

        net.add_waypoint_node(node_key="Z")

        base_flow = {(i, j): random.random() for i in range(3) for j in range(4)}

        net.add_source_sink_node(node_key="Y", base_flow=base_flow)

        base_flow[(2, 3)] = random.random()

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="Y", node_data={net.KEY_NODE_BASE_FLOW: base_flow}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        assert "Z" in net.waypoint_nodes

        assert "G" in net.import_nodes

        assert "H" in net.export_nodes

        assert "Y" in net.source_sink_nodes

    # *************************************************************************
    # *************************************************************************

    def test_arcs_without_losses(self):
        # test arc without (static and proportional) losses
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="AB",
            capacity=(1, 2, 3),
            minimum_cost=(4, 5, 6),
            specific_capacity_cost=6,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            validate=True,
        )

        assert not arc_tech.has_proportional_losses()
        assert not arc_tech.is_infinite_capacity()
        assert arc_tech.has_constant_efficiency()
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="AB",
            efficiency={(0, 0): 1, (0, 1): 0.9, (0, 2): 0.8},
            efficiency_reverse=None,
            capacity=(1, 2, 3),
            minimum_cost=(4, 5, 6),
            specific_capacity_cost=6,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            validate=True,
        )

        assert arc_tech.has_proportional_losses()
        assert not arc_tech.is_infinite_capacity()
        assert not arc_tech.has_constant_efficiency()
        arc_tech = ArcsWithoutProportionalLosses(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="AB",
            static_loss={
                (0, 0, 0): 0.1,
                (0, 0, 1): 0.2,
                (0, 0, 2): 0.3,
                (1, 0, 0): 0.15,
                (1, 0, 1): 0.25,
                (1, 0, 2): 0.35,
                (2, 0, 0): 0.16,
                (2, 0, 1): 0.26,
                (2, 0, 2): 0.36,
            },
            capacity=(1, 2, 3),
            minimum_cost=(4, 5, 6),
            specific_capacity_cost=6,
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            validate=True,
        )

        assert not arc_tech.has_proportional_losses()
        assert not arc_tech.is_infinite_capacity()
        assert arc_tech.has_constant_efficiency()
    # *************************************************************************
    # *************************************************************************
    def test_modifying_nodes(self):
        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            prices=[random.random() for k in range(number_intervals)],
            volumes=[*[random.random() for k in range(number_intervals - 1)], None],
        )

        base_flow = {(0, k): random.random() for k in range(number_intervals)}

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="hello",
            capacity=[5],
            minimum_cost=[3],
            specific_capacity_cost=3,
            capacity_is_instantaneous=False,
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_import_node(node_key="I_iso", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_import_node(node_key="I", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_import_node(node_key="E_iso", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_export_node(node_key="E", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="A_iso", base_flow=base_flow)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="A_in", base_flow=base_flow)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="A_out", base_flow=base_flow)

        # add normal node with incoming and outgoing arcs
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="A", base_flow=base_flow)

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_directed_arc(node_key_a="I", node_key_b="A_in", arcs=arc_tech)

        net.add_directed_arc(node_key_a="I", node_key_b="A", arcs=arc_tech)

        net.add_directed_arc(node_key_a="A_out", node_key_b="E", arcs=arc_tech)

        net.add_directed_arc(node_key_a="A", node_key_b="E", arcs=arc_tech)

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_iso",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="I",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="E",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_in",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_in",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_in", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_in",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_out",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                net.KEY_NODE_PRICES: resource_price,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_out",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_out", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            node_key="A_out",
            node_data={
                net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_SOURCE_SINK,
                net.KEY_NODE_BASE_FLOW: base_flow,
            },
        )

        # *********************************************************************
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="I",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="E",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="A_out",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="A_in",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="A",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_EXP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="A",
                node_data={
                    net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_IMP,
                    net.KEY_NODE_PRICES: resource_price,
                },
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        # *********************************************************************
        error_triggered = False
        try:
            net.modify_network_node(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key="ABCD", node_data={net.KEY_NODE_TYPE: net.KEY_NODE_TYPE_WAY}
            )
        except ValueError:
            error_triggered = True
        assert error_triggered
        # *********************************************************************
    # *************************************************************************
    # *************************************************************************
    def test_network_disallowed_cases(self):
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            prices=[random.random() for k in range(number_intervals)],
            volumes=[*[random.random() for k in range(number_intervals - 1)], None],
        )

        base_flow = {(0, k): random.random() for k in range(number_intervals)}

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="hello",
            capacity=[5],
            minimum_cost=[3],
            specific_capacity_cost=3,
            capacity_is_instantaneous=False,
        )

        lossy_arcs = ArcsWithoutProportionalLosses(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            name="hello back",
            static_loss={(0, 0, k): random.random() for k in range(number_intervals)},
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            minimum_cost=(5,),
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            capacity_is_instantaneous=False,
        )

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_import_node(node_key="I", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_export_node(node_key="E", prices={(0, 0, 0): resource_price})

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="A", base_flow=base_flow)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_source_sink_node(node_key="B", base_flow=base_flow)

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_directed_arc(node_key_a="I", node_key_b="E", arcs=lossless_arcs)

        # *********************************************************************
        # *********************************************************************
        # trigger errors using pre-identified nodes
        # directed arcs cannot start in an export node: E -> B
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_directed_arc(node_key_a="E", node_key_b="B", arcs=lossless_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered
        # directed arcs cannot end on an import node: A -> I
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_directed_arc(node_key_a="A", node_key_b="I", arcs=lossless_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered
        # import-export nodes cannot have static losses
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_directed_arc(node_key_a="I", node_key_b="E", arcs=lossy_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered
        # undirected arcs cannot involve import nor export nodes
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_undirected_arc(node_key_a="I", node_key_b="A", arcs=lossless_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered
        # undirected arcs cannot involve import nor export nodes
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_undirected_arc(node_key_a="B", node_key_b="E", arcs=lossless_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered
        # undirected arcs cannot involve import nor export nodes

        error_triggered = False
        try:
            net.add_undirected_arc(node_key_a="I", node_key_b="E", arcs=lossy_arcs)
        except ValueError:
            error_triggered = True
        assert error_triggered

        # *********************************************************************
        # trigger errors using non-identified nodes
        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_export_node(node_key="E1", prices={(0, 0, 0): resource_price})

        # create an arc starting in that export node
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_directed_arc(node_key_a="E1", node_key_b="B", arcs=lossless_arcs)
            net.identify_node_types()
        except ValueError:
            error_triggered = True
        assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.remove_edge(u="E1", v="B")

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.add_import_node(node_key="I1", prices={(0, 0, 0): resource_price})

        # create an arc ending in that import node
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
            net.add_directed_arc(node_key_a="A", node_key_b="I1", arcs=lossless_arcs)
            net.identify_node_types()
        except ValueError:
            error_triggered = True
        assert error_triggered
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.remove_edge(u="A", v="I1")

        # *********************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed

        net.arc_is_undirected(("X", "Y", 1))
        
    # *************************************************************************
    # *************************************************************************
            
    def test_undirected_arc_import_error(self):
        
        # network    
        mynet = Network()
    
        # import node    
        imp_node_key = generate_pseudo_unique_key(mynet.nodes())    
        mynet.add_import_node(
            node_key=imp_node_key,
            prices={
                (0, 0, 0): ResourcePrice(prices=1+0.05, volumes=None)
            },
        )
    
        # 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_undirected_arc(
            node_key_a=imp_node_key, node_key_b=node_A, arcs=arc_tech_IA
        )
    
        error_raised = False
        try:
            # identify node types
            mynet.identify_node_types()
        except ValueError:
            error_raised = True
        assert error_raised
    
        # *********************************************************************
        # *********************************************************************
        
    # *************************************************************************
    # *************************************************************************
            
    def test_undirected_arc_export_error(self):
            
        # 4 nodes: one import, one export, two supply/demand nodes
        mynet = Network()
    
        # export node
        exp_node_key = generate_pseudo_unique_key(mynet.nodes())
        mynet.add_export_node(
            node_key=exp_node_key,
            prices={
                (0, 0, 0): ResourcePrice(prices=0.1+0.05, volumes=None)
            },
        )
    
        # other nodes
        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},
        )    
        # 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_undirected_arc(
            node_key_a=node_B, node_key_b=exp_node_key, arcs=arc_tech_BE
        )
        
        error_raised = False
        try:
            # identify node types
            mynet.identify_node_types()
        except ValueError:
            error_raised = True
        assert error_raised
        
    # *************************************************************************
    # *************************************************************************

    def test_tree_topology(self):
        # create a network object with a tree topology
        tree_network = binomial_tree(3, create_using=MultiDiGraph)
        network = Network(incoming_graph_data=tree_network)
        for edge_key in network.edges(keys=True):
            arc = ArcsWithoutLosses(
                name=str(edge_key),
                capacity=[5, 10],
                minimum_cost=[3, 6],
                specific_capacity_cost=0,
                capacity_is_instantaneous=False,
            )
            network.add_edge(*edge_key, **{Network.KEY_ARC_TECH: arc})
        # assert that it does not have a tree topology
        assert not network.has_tree_topology()

        # select all the nodes
        for edge_key in network.edges(keys=True):
            network.edges[edge_key][Network.KEY_ARC_TECH].options_selected[0] = True
        # assert that it has a tree topology
        assert network.has_tree_topology()
    # *************************************************************************
    # *************************************************************************
    def test_pseudo_unique_key_generation(self):
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
        network.add_waypoint_node(node_key="A")

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
        network.add_waypoint_node(node_key="B")

        # identify nodes
        network.identify_node_types()
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
        key_list = [
            "3e225573-4e78-48c8-bb08-efbeeb795c22",
            "f6d30428-15d1-41e9-a952-0742eaaa5a31",
            "8c29b906-2518-41c5-ada8-07b83508b5b8",
            "f9a72a39-1422-4a02-af97-906ce79c32a3",
            "b6941a48-10cc-465d-bf53-178bd2939bd1",
        ]

Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                u_for_edge="A",
                v_for_edge="B",
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                **{network.KEY_ARC_UND: False, network.KEY_ARC_TECH: None}
            )

        # use a seed number to trigger more iterations
        rand = random.Random()
        rand.seed(360)
        uuid.uuid4 = lambda: uuid.UUID(int=rand.getrandbits(128), version=4)
        error_triggered = False
        try:
            _ = network.get_pseudo_unique_arc_key(
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
                node_key_start="A", node_key_end="B", max_iterations=len(key_list) - 1
            )
        except Exception:
            error_triggered = True
        assert error_triggered
        
    # *************************************************************************
    # *************************************************************************
    
    def test_imp_exp_static_losses(self):
                
        # assessment
        q = 0
        # 4 nodes: one import, one export, two supply/demand nodes
        mynet = Network()
    
        # import node
        imp_node_key = generate_pseudo_unique_key(mynet.nodes())
        imp_prices = {
            qpk: ResourcePrice(
                prices=0.5,
                volumes=None,
            )
            for qpk in [(0,0,0),(0,0,1),(0,1,0),(0,1,1)]
            }
        mynet.add_import_node(
            node_key=imp_node_key,
            prices=imp_prices
        )
    
        # export node
        exp_node_key = generate_pseudo_unique_key(mynet.nodes())
        exp_prices = {
            qpk: ResourcePrice(
                prices=1.5,
                volumes=None,
            )
            for qpk in [(0,0,0),(0,0,1),(0,1,0),(0,1,1)]
            }
        mynet.add_export_node(
            node_key=exp_node_key,
            prices=exp_prices,
        )
        
        # add arc with fixed losses from import node to export

        arc_tech_IE_fix = Arcs(
            name="IE_fix",
            # efficiency=[1, 1, 1, 1],
            efficiency={(q, 0): 1, (q, 1): 1},
            efficiency_reverse=None,
            validate=False,
            capacity=[0.5, 1.0, 2.0],
            minimum_cost=[5, 5.1, 5.2],
            specific_capacity_cost=1,
            capacity_is_instantaneous=False,
            # static_losses=[
            #     [0.10, 0.15, 0.20, 0.25],
            #     [0.15, 0.20, 0.25, 0.30],
            #     [0.20, 0.25, 0.30, 0.35]]
            static_loss={
                (0, q, 0): 0.10,
                (0, q, 1): 0.15,
                (1, q, 0): 0.15,
                (1, q, 1): 0.20,
                (2, q, 0): 0.20,
                (2, q, 1): 0.25,
            },
        )

        mynet.add_directed_arc(
            node_key_a=imp_node_key, node_key_b=exp_node_key, arcs=arc_tech_IE_fix
        )
    
        error_raised = False
        try:
            # identify node types
            mynet.identify_node_types()
        except ValueError:
            error_raised = True
        assert error_raised
        
    # *************************************************************************
    # *************************************************************************
    
    def test_antiparallel_arcs(self):
        
        # create network        
        net = Network()
        
        # add nodes
        node_a = 'A'
        net.add_waypoint_node(node_a)
        node_b = 'B'
        net.add_waypoint_node(node_b)
        node_c = 'C'
        net.add_waypoint_node(node_c)
        
        # add arcs
        node_pairs = ((node_a, node_b), (node_b, node_a),)
        
        # test network
        for node_pair in node_pairs:
            net.add_preexisting_directed_arc(
                *node_pair,
                efficiency=None, 
                static_loss=None, 
                capacity=1, 
                capacity_is_instantaneous=False
                )
        # identify the node types
        net.identify_node_types()
        
        # assert that it can detected the selected antiparallel arcs
        assert net.has_selected_antiparallel_arcs()
        # check that it finds the right node pairs
        identified_node_pairs = net.find_selected_antiparallel_arcs()
        assert (node_a, node_b) in identified_node_pairs
        assert (node_b, node_a) in identified_node_pairs
        
    # *************************************************************************
    # *************************************************************************
Pedro L. Magalhães's avatar
Pedro L. Magalhães committed
# *****************************************************************************
# *****************************************************************************