Example #1
0
    def __init__(self, nb_env, env):
        GridObjects.__init__(self)
        # self.init_grid(env)
        self.imported_env = env
        self.nb_env = nb_env

        self._remotes, self._work_remotes = zip(
            *[Pipe() for _ in range(self.nb_env)])

        env_params = [env.get_kwargs() for _ in range(self.nb_env)]
        for el in env_params:
            el["backendClass"] = type(env.backend)
        self._ps = [
            RemoteEnv(env_params=env_,
                      remote=work_remote,
                      parent_remote=remote,
                      name="env: {}".format(i),
                      seed=np.random.randint(np.iinfo(np.uint32).max))
            for i, (work_remote, remote, env_) in enumerate(
                zip(self._work_remotes, self._remotes, env_params))
        ]

        for p in self._ps:
            p.daemon = True  # if the main process crashes, we should not cause things to hang
            p.start()
        for remote in self._work_remotes:
            remote.close()

        self._waiting = True
Example #2
0
    def __init__(self, detailed_infos_for_cascading_failures=False):
        """
        Initialize an instance of Backend. This does nothing per se. Only the call to :func:`Backend.load_grid`
        should guarantee the backend is properly configured.

        :param detailed_infos_for_cascading_failures: Whether to be detailed (but slow) when computing cascading failures
        :type detailed_infos_for_cascading_failures: :class:`bool`

        """
        GridObjects.__init__(self)

        # the following parameter is used to control the amount of verbosity when computing a cascading failure
        # if it's set to true, it returns all intermediate _grid states. This can slow down the computation!
        self.detailed_infos_for_cascading_failures = detailed_infos_for_cascading_failures

        # the power _grid manipulated. One powergrid per backend.
        self._grid = None

        # thermal limit setting, in ampere, at the same "side" of the powerline than self.get_line_overflow
        self.thermal_limit_a = None
Example #3
0
    def __init__(self,
                 substation_layout,
                 observation_space,
                 radius_sub=20.,
                 load_prod_dist=70.,
                 bus_radius=6.):
        if substation_layout is None:
            raise PlotError(
                "Impossible to use plotting abilities without specifying a layout (coordinates) "
                "of the substations.")

        if len(substation_layout) != observation_space.n_sub:
            raise PlotError(
                "You provided a layout with {} elements while there are {} substations on the powergrid. "
                "Your layout is invalid".format(len(substation_layout),
                                                observation_space.n_sub))
        GridObjects.__init__(self)
        self.init_grid(observation_space)

        self.observation_space = observation_space
        self._layout = {}
        self._layout["substations"] = self._get_sub_layout(substation_layout)

        self.radius_sub = radius_sub
        self.load_prod_dist = load_prod_dist  # distance between load and generator to the center of the substation
        self.bus_radius = bus_radius

        self.subs_elements = [None for _ in self.observation_space.sub_info]

        # get the element in each substation
        for sub_id in range(self.observation_space.sub_info.shape[0]):
            this_sub = {}
            objs = self.observation_space.get_obj_connect_to(
                substation_id=sub_id)

            for c_id in objs["loads_id"]:
                c_nm = self._get_load_name(sub_id, c_id)
                this_load = {}
                this_load["type"] = "load"
                this_load["sub_pos"] = self.observation_space.load_to_sub_pos[
                    c_id]
                this_sub[c_nm] = this_load

            for g_id in objs["generators_id"]:
                g_nm = self._get_gen_name(sub_id, g_id)
                this_gen = {}
                this_gen["type"] = "gen"
                this_gen["sub_pos"] = self.observation_space.gen_to_sub_pos[
                    g_id]
                this_sub[g_nm] = this_gen

            for lor_id in objs["lines_or_id"]:
                ext_id = self.observation_space.line_ex_to_subid[lor_id]
                l_nm = self._get_line_name(sub_id, ext_id, lor_id)
                this_line = {}
                this_line["type"] = "line"
                this_line[
                    "sub_pos"] = self.observation_space.line_or_to_sub_pos[
                        lor_id]
                this_sub[l_nm] = this_line

            for lex_id in objs["lines_ex_id"]:
                or_id = self.observation_space.line_or_to_subid[lex_id]
                l_nm = self._get_line_name(or_id, sub_id, lex_id)
                this_line = {}
                this_line["type"] = "line"
                this_line[
                    "sub_pos"] = self.observation_space.line_ex_to_sub_pos[
                        lex_id]
                this_sub[l_nm] = this_line
            self.subs_elements[sub_id] = this_sub
        self._compute_layout()
Example #4
0
    def setUp(self):
        """
        The case file is a representation of the case14 as found in the ieee14 powergrid.
        :return:
        """
        self.tolvect = 1e-2
        self.tol_one = 1e-5
        self.game_rules = GameRules()
        self.gridobj = GridObjects()
        self.gridobj.init_grid_vect(
            name_prod=["gen_{}".format(i) for i in range(5)],
            name_load=["load_{}".format(i) for i in range(11)],
            name_line=["line_{}".format(i) for i in range(20)],
            name_sub=["sub_{}".format(i) for i in range(14)],
            sub_info=np.array([3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3],
                              dtype=np.int),
            load_to_subid=np.array([1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13]),
            gen_to_subid=np.array([0, 1, 2, 5, 7]),
            line_or_to_subid=np.array(
                [0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 8, 8, 9, 11,
                 12]),
            line_ex_to_subid=np.array([
                1, 4, 2, 3, 4, 3, 4, 6, 8, 5, 10, 11, 12, 7, 8, 9, 13, 10, 12,
                13
            ]),  #####
            load_to_sub_pos=np.array([4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1]),
            gen_to_sub_pos=np.array([2, 5, 3, 5, 1]),
            line_or_to_sub_pos=np.array(
                [0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2, 3, 0, 0, 1]),
            line_ex_to_sub_pos=np.array(
                [0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0,
                 0]),  #####
            load_pos_topo_vect=np.array(
                [7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54]),
            gen_pos_topo_vect=np.array([2, 8, 12, 29, 34]),
            line_or_pos_topo_vect=np.array([
                0, 1, 4, 5, 6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38,
                40, 46, 50
            ]),
            line_ex_pos_topo_vect=np.array([
                3, 19, 9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42,
                55, 43, 49, 53
            ]))
        # pdb.set_trace()
        self.helper_action = HelperAction(
            self.gridobj, legal_action=self.game_rules.legal_action)

        self.helper_action_env = HelperAction(
            self.gridobj,
            legal_action=self.game_rules.legal_action,
            actionClass=Action)

        self.res = {
            'name_gen': ['gen_0', 'gen_1', 'gen_2', 'gen_3', 'gen_4'],
            'name_load': [
                'load_0', 'load_1', 'load_2', 'load_3', 'load_4', 'load_5',
                'load_6', 'load_7', 'load_8', 'load_9', 'load_10'
            ],
            'name_line': [
                'line_0', 'line_1', 'line_2', 'line_3', 'line_4', 'line_5',
                'line_6', 'line_7', 'line_8', 'line_9', 'line_10', 'line_11',
                'line_12', 'line_13', 'line_14', 'line_15', 'line_16',
                'line_17', 'line_18', 'line_19'
            ],
            'name_sub': [
                'sub_0', 'sub_1', 'sub_2', 'sub_3', 'sub_4', 'sub_5', 'sub_6',
                'sub_7', 'sub_8', 'sub_9', 'sub_10', 'sub_11', 'sub_12',
                'sub_13'
            ],
            'sub_info': [3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3],
            'load_to_subid': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13],
            'gen_to_subid': [0, 1, 2, 5, 7],
            'line_or_to_subid':
            [0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 8, 8, 9, 11, 12],
            'line_ex_to_subid': [
                1, 4, 2, 3, 4, 3, 4, 6, 8, 5, 10, 11, 12, 7, 8, 9, 13, 10, 12,
                13
            ],
            'load_to_sub_pos': [4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1],
            'gen_to_sub_pos': [2, 5, 3, 5, 1],
            'line_or_to_sub_pos':
            [0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2, 3, 0, 0, 1],
            'line_ex_to_sub_pos':
            [0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0, 0],
            'load_pos_topo_vect': [7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54],
            'gen_pos_topo_vect': [2, 8, 12, 29, 34],
            'line_or_pos_topo_vect': [
                0, 1, 4, 5, 6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38,
                40, 46, 50
            ],
            'line_ex_pos_topo_vect': [
                3, 19, 9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42,
                55, 43, 49, 53
            ],
            'gen_type':
            None,
            'gen_pmin':
            None,
            'gen_pmax':
            None,
            'gen_redispatchable':
            None,
            'gen_max_ramp_up':
            None,
            'gen_max_ramp_down':
            None,
            'gen_min_uptime':
            None,
            'gen_min_downtime':
            None,
            'gen_cost_per_MW':
            None,
            'gen_startup_cost':
            None,
            'gen_shutdown_cost':
            None,
            'subtype':
            'Action.Action'
        }

        self.size_act = 229
Example #5
0
class TestLoadingBackendFunc(unittest.TestCase):
    def setUp(self):
        """
        The case file is a representation of the case14 as found in the ieee14 powergrid.
        :return:
        """
        self.tolvect = 1e-2
        self.tol_one = 1e-5
        self.game_rules = GameRules()
        self.gridobj = GridObjects()
        self.gridobj.init_grid_vect(
            name_prod=["gen_{}".format(i) for i in range(5)],
            name_load=["load_{}".format(i) for i in range(11)],
            name_line=["line_{}".format(i) for i in range(20)],
            name_sub=["sub_{}".format(i) for i in range(14)],
            sub_info=np.array([3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3],
                              dtype=np.int),
            load_to_subid=np.array([1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13]),
            gen_to_subid=np.array([0, 1, 2, 5, 7]),
            line_or_to_subid=np.array(
                [0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 8, 8, 9, 11,
                 12]),
            line_ex_to_subid=np.array([
                1, 4, 2, 3, 4, 3, 4, 6, 8, 5, 10, 11, 12, 7, 8, 9, 13, 10, 12,
                13
            ]),  #####
            load_to_sub_pos=np.array([4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1]),
            gen_to_sub_pos=np.array([2, 5, 3, 5, 1]),
            line_or_to_sub_pos=np.array(
                [0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2, 3, 0, 0, 1]),
            line_ex_to_sub_pos=np.array(
                [0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0,
                 0]),  #####
            load_pos_topo_vect=np.array(
                [7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54]),
            gen_pos_topo_vect=np.array([2, 8, 12, 29, 34]),
            line_or_pos_topo_vect=np.array([
                0, 1, 4, 5, 6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38,
                40, 46, 50
            ]),
            line_ex_pos_topo_vect=np.array([
                3, 19, 9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42,
                55, 43, 49, 53
            ]))
        # pdb.set_trace()
        self.helper_action = HelperAction(
            self.gridobj, legal_action=self.game_rules.legal_action)

        self.helper_action_env = HelperAction(
            self.gridobj,
            legal_action=self.game_rules.legal_action,
            actionClass=Action)

        self.res = {
            'name_gen': ['gen_0', 'gen_1', 'gen_2', 'gen_3', 'gen_4'],
            'name_load': [
                'load_0', 'load_1', 'load_2', 'load_3', 'load_4', 'load_5',
                'load_6', 'load_7', 'load_8', 'load_9', 'load_10'
            ],
            'name_line': [
                'line_0', 'line_1', 'line_2', 'line_3', 'line_4', 'line_5',
                'line_6', 'line_7', 'line_8', 'line_9', 'line_10', 'line_11',
                'line_12', 'line_13', 'line_14', 'line_15', 'line_16',
                'line_17', 'line_18', 'line_19'
            ],
            'name_sub': [
                'sub_0', 'sub_1', 'sub_2', 'sub_3', 'sub_4', 'sub_5', 'sub_6',
                'sub_7', 'sub_8', 'sub_9', 'sub_10', 'sub_11', 'sub_12',
                'sub_13'
            ],
            'sub_info': [3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3],
            'load_to_subid': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13],
            'gen_to_subid': [0, 1, 2, 5, 7],
            'line_or_to_subid':
            [0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 8, 8, 9, 11, 12],
            'line_ex_to_subid': [
                1, 4, 2, 3, 4, 3, 4, 6, 8, 5, 10, 11, 12, 7, 8, 9, 13, 10, 12,
                13
            ],
            'load_to_sub_pos': [4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1],
            'gen_to_sub_pos': [2, 5, 3, 5, 1],
            'line_or_to_sub_pos':
            [0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2, 3, 0, 0, 1],
            'line_ex_to_sub_pos':
            [0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0, 0],
            'load_pos_topo_vect': [7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54],
            'gen_pos_topo_vect': [2, 8, 12, 29, 34],
            'line_or_pos_topo_vect': [
                0, 1, 4, 5, 6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38,
                40, 46, 50
            ],
            'line_ex_pos_topo_vect': [
                3, 19, 9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42,
                55, 43, 49, 53
            ],
            'gen_type':
            None,
            'gen_pmin':
            None,
            'gen_pmax':
            None,
            'gen_redispatchable':
            None,
            'gen_max_ramp_up':
            None,
            'gen_max_ramp_down':
            None,
            'gen_min_uptime':
            None,
            'gen_min_downtime':
            None,
            'gen_cost_per_MW':
            None,
            'gen_startup_cost':
            None,
            'gen_shutdown_cost':
            None,
            'subtype':
            'Action.Action'
        }

        self.size_act = 229

    def tearDown(self):
        pass
        # self.backend._grid.delete()

    def compare_vect(self, pred, true):
        return np.max(np.abs(pred - true)) <= self.tolvect

    def test_instanciate_action(self):
        """
        test i can instanciate an action without crashing
        :return:
        """
        action = self.helper_action()

    def test_size(self):
        action = self.helper_action()
        action.size()

    def test_proper_size(self):
        action = self.helper_action()
        assert action.size() == self.size_act

    def test_size_action_space(self):
        assert self.helper_action.size() == self.size_act

    def test_print_notcrash(self):
        """
        test the conversion to str does not crash
        :return:
        """
        action = self.helper_action({})
        a = "{}".format(action)

    def test_change_p(self):
        """

        :return:
        """
        new_vect = np.random.randn(self.helper_action.n_load)
        action = self.helper_action({"injection": {"load_p": new_vect}})
        self.compare_vect(action._dict_inj["load_p"], new_vect)
        for i in range(self.helper_action.n_load):
            assert action.effect_on(load_id=i)["new_p"] == new_vect[i]

    def test_change_v(self):
        """

        :return:
        """
        new_vect = np.random.randn(self.helper_action.n_gen)
        action = self.helper_action({"injection": {"prod_v": new_vect}})
        self.compare_vect(action._dict_inj["prod_v"], new_vect)
        for i in range(self.helper_action.n_gen):
            assert action.effect_on(gen_id=i)["new_v"] == new_vect[i]

    def test_change_p_q(self):
        """

        :return:
        """
        new_vect = np.random.randn(self.helper_action.n_load)
        new_vect2 = np.random.randn(self.helper_action.n_load)
        action = self.helper_action(
            {"injection": {
                "load_p": new_vect,
                "load_q": new_vect2
            }})
        assert self.compare_vect(action._dict_inj["load_p"], new_vect)
        assert self.compare_vect(action._dict_inj["load_q"], new_vect2)
        for i in range(self.helper_action.n_load):
            assert action.effect_on(load_id=i)["new_p"] == new_vect[i]
            assert action.effect_on(load_id=i)["new_q"] == new_vect2[i]

    def test_update_disconnection_1(self):
        """
        Test if the disconnection is working properly
        :return:
        """
        for i in range(self.helper_action.n_line):
            disco = np.full(shape=self.helper_action.n_line,
                            fill_value=0,
                            dtype=np.int)
            disco[i] = 1
            action = self.helper_action({"set_line_status": disco})
            for j in range(self.helper_action.n_line):
                assert action.effect_on(line_id=j)["set_line_status"] == disco[
                    j], "problem with line {} if line {} is disconnected".format(
                        j, i)
                assert action.effect_on(
                    line_id=j)["change_line_status"] == False

    def test_update_disconnection_m1(self):
        """
        Test if the disconnection is working properly
        :return:
        """
        for i in range(self.helper_action.n_line):
            disco = np.full(shape=self.helper_action.n_line,
                            fill_value=0,
                            dtype=np.int)
            disco[i] = -1
            action = self.helper_action({"set_line_status": disco})
            for j in range(self.helper_action.n_line):
                assert action.effect_on(line_id=j)["set_line_status"] == disco[
                    j], "problem with line {} if line {} is disconnected".format(
                        j, i)
                assert action.effect_on(
                    line_id=j)["change_line_status"] == False

    def test_update_hazard(self):
        """
        Same test as above, but with hazard
        :return:
        """
        for i in range(self.helper_action.n_line):
            disco = np.full(shape=self.helper_action.n_line,
                            fill_value=False,
                            dtype=np.bool)
            disco[i] = True
            action = self.helper_action({"hazards": disco})
            for j in range(self.helper_action.n_line):
                expected_res = -1 if j == i else 0
                assert action.effect_on(
                    line_id=j
                )["set_line_status"] == expected_res, "problem with line {} if line {} is disconnected".format(
                    j, i)
                assert action.effect_on(
                    line_id=j)["change_line_status"] == False

    def test_update_status(self):
        for i in range(self.helper_action.n_line):
            disco = np.full(shape=self.helper_action.n_line,
                            fill_value=False,
                            dtype=np.bool)
            disco[i] = True
            action = self.helper_action({"change_line_status": disco})
            for j in range(self.helper_action.n_line):
                expected_res = j == i
                assert action.effect_on(line_id=j)["set_line_status"] == 0
                assert action.effect_on(
                    line_id=j)["change_line_status"] == expected_res

    def test_update_set_topo_by_dict_obj(self):
        action = self.helper_action({"set_bus": {"loads_id": [(1, 3)]}})
        assert action.effect_on(load_id=1)["set_bus"] == 3
        assert action.effect_on(load_id=1)["change_bus"] == False
        assert action.effect_on(load_id=0)["set_bus"] == 0
        assert action.effect_on(load_id=0)["change_bus"] == False

    def test_update_set_topo_by_dict_sub(self):
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        action = self.helper_action(
            {"set_bus": {
                "substations_id": [(1, arr)]
            }})
        assert action.effect_on(line_id=2)["set_bus_or"] == 1
        assert action.effect_on(line_id=3)["set_bus_or"] == 1
        assert action.effect_on(line_id=4)["set_bus_or"] == 2
        assert action.effect_on(line_id=0)["set_bus_ex"] == 1
        assert action.effect_on(load_id=0)["set_bus"] == 2
        assert action.effect_on(gen_id=1)["set_bus"] == 2

        assert action.effect_on(load_id=1)["set_bus"] == 0
        assert action.effect_on(gen_id=0)["set_bus"] == 0

    def test_update_set_topo_by_dict_sub2(self):
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        arr3 = np.array([1, 2, 1, 2, 1, 2], dtype=np.int)
        action = self.helper_action(
            {"set_bus": {
                "substations_id": [(3, arr3), (1, arr)]
            }})
        assert action.effect_on(line_id=2)["set_bus_or"] == 1
        assert action.effect_on(line_id=3)["set_bus_or"] == 1
        assert action.effect_on(line_id=4)["set_bus_or"] == 2
        assert action.effect_on(line_id=0)["set_bus_ex"] == 1
        assert action.effect_on(load_id=0)["set_bus"] == 2
        assert action.effect_on(gen_id=1)["set_bus"] == 2

        assert action.effect_on(load_id=1)["set_bus"] == 0
        assert action.effect_on(gen_id=0)["set_bus"] == 0

    def test_update_change_bus_by_dict_obj(self):
        action = self.helper_action({"change_bus": {"loads_id": [1]}})
        assert action.effect_on(load_id=1)["set_bus"] == 0
        assert action.effect_on(load_id=1)["change_bus"] == True
        assert action.effect_on(load_id=0)["set_bus"] == 0
        assert action.effect_on(load_id=0)["change_bus"] == False

    def test_update_change_bus_by_dict_sub(self):
        arr = np.array([True, True, True, False, False, False], dtype=np.bool)
        action = self.helper_action(
            {"change_bus": {
                "substations_id": [(1, arr)]
            }})
        assert action.effect_on(line_id=2)["change_bus_or"] == True
        assert action.effect_on(line_id=3)["change_bus_or"] == True
        assert action.effect_on(line_id=4)["change_bus_or"] == False
        assert action.effect_on(line_id=0)["change_bus_ex"] == True
        assert action.effect_on(load_id=0)["change_bus"] == False
        assert action.effect_on(gen_id=1)["change_bus"] == False

        assert action.effect_on(load_id=1)["change_bus"] == False
        assert action.effect_on(gen_id=0)["change_bus"] == False

    def test_update_change_bus_by_dict_sub2(self):
        arr = np.array([True, True, True, False, False, False], dtype=np.bool)
        arr3 = np.array([True, False, True, False, True, False], dtype=np.bool)
        action = self.helper_action(
            {"change_bus": {
                "substations_id": [(3, arr3), (1, arr)]
            }})
        assert action.effect_on(line_id=2)["change_bus_or"] == True
        assert action.effect_on(line_id=3)["change_bus_or"] == True
        assert action.effect_on(line_id=4)["change_bus_or"] == False
        assert action.effect_on(line_id=0)["change_bus_ex"] == True
        assert action.effect_on(load_id=0)["change_bus"] == False
        assert action.effect_on(gen_id=1)["change_bus"] == False

        assert action.effect_on(load_id=1)["change_bus"] == False
        assert action.effect_on(gen_id=0)["change_bus"] == False

    def test_ambiguity_topo(self):
        action = self.helper_action({"change_bus": {
            "lines_or_id": [1]
        }})  # i switch the bus of the origin of powerline 1
        action.update({"set_bus": {
            "lines_or_id": [(1, 1)]
        }})  # i set the origin of powerline 1 to bus 1
        try:
            action()
            raise RuntimeError(
                "This should hav thrown an InvalidBusStatus error")
        except InvalidBusStatus as e:
            pass

    def test_ambiguity_line_status_when_set_and_change(self):
        arr = np.zeros(self.helper_action.n_line)
        arr[1] = -1
        action = self.helper_action(
            {"set_line_status":
             arr})  # i switch set the status of powerline 1 to "disconnected"
        action.update({"change_line_status":
                       [1]})  # i asked to change this status
        try:
            action()
            raise RuntimeError(
                "This should hav thrown an InvalidBusStatus error")
        except InvalidLineStatus as e:
            pass

    def test_ambiguity_line_reconnected_without_bus(self):
        arr = np.zeros(self.helper_action.n_line)
        arr[1] = 1
        action = self.helper_action(
            {"set_line_status":
             arr})  # i switch set the status of powerline 1 to "connected"
        # and i don't say on which bus to connect it
        try:
            action()
            raise RuntimeError(
                "This should have thrown an InvalidBusStatus error")
        except InvalidLineStatus as e:
            pass

    def test_set_status_and_setbus_isambiguous(self):
        """

        :return:
        """
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        id_ = 2
        action = self.helper_action(
            {"set_bus": {
                "substations_id": [(1, arr)]
            }})
        arr2 = np.zeros(self.helper_action.n_line)
        arr2[id_] = -1
        action.update({"set_line_status": arr2})
        try:
            action()
            raise RuntimeError(
                "This should have thrown an InvalidBusStatus error")
        except InvalidLineStatus as e:
            pass

    def test_hazard_overides_setbus(self):
        """

        :return:
        """
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        id_ = 2
        action = self.helper_action(
            {"set_bus": {
                "substations_id": [(1, arr)]
            }})
        assert action.effect_on(line_id=id_)["set_bus_or"] == 1
        action.update({"hazards": [id_]})
        assert action.effect_on(line_id=id_)["set_bus_or"] == 0
        assert action.effect_on(line_id=id_)["set_line_status"] == -1
        assert action.effect_on(line_id=id_)["set_bus_ex"] == 0

    def test_action_str(self):
        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        id_1 = 1
        id_2 = 12
        action = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        res = action.__str__()
        act_str = 'This action will:\n\t - NOT change anything to the injections\n\t - NOT perform any redispatching ' \
                  'action\n\t - NOT force any line status\n\t - NOT switch any line status\n\t - Change the bus of the ' \
                  'following element:\n\t \t - switch bus of line (origin) 4 [on substation 1]\n\t \t - switch bus of ' \
                  'load 0 [on substation 1]\n\t \t - switch bus of generator 1 [on substation 1]\n\t - Set the bus of ' \
                  'the following element:\n\t \t - assign bus 1 to line (extremity) 18 [on substation 12]\n\t \t - ' \
                  'assign bus 1 to line (origin) 19 [on substation 12]\n\t \t - assign bus 2 to load 9 ' \
                  '[on substation 12]\n\t \t - assign bus 2 to line (extremity) 12 [on substation 12]'
        assert res == act_str

    def test_to_vect(self):
        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        id_1 = 1
        id_2 = 12
        action = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        res = action.to_vect()
        tmp = np.array([
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 1., 1., 2., 2., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0., 0.
        ])
        assert np.all(res[np.isfinite(tmp)] == tmp[np.isfinite(tmp)])
        assert np.all(np.isfinite(res) == np.isfinite(tmp))

    def test__eq__(self):
        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        id_1 = 1
        id_2 = 12
        action1 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        action2 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        action3 = self.helper_action()
        assert action1 == action2
        assert action1 != action3

    def test_from_vect(self):
        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        id_1 = 1
        id_2 = 12
        action1 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        action2 = self.helper_action({})

        vect_act1 = action1.to_vect()
        action2.from_vect(vect_act1)
        # pdb.set_trace()
        # if i load an action with from_vect it's equal to the original one
        assert action1 == action2
        vect_act2 = action2.to_vect()

        # if i convert it back to a vector, it's equal to the original converted vector
        assert np.all(vect_act1[np.isfinite(vect_act2)] == vect_act2[
            np.isfinite(vect_act2)])
        assert np.all(np.isfinite(vect_act1) == np.isfinite(vect_act2))

    def test_call_change_set(self):
        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        id_1 = 1
        id_2 = 12
        new_vect = np.random.randn(self.helper_action.n_load)
        new_vect2 = np.random.randn(self.helper_action.n_load)

        change_status_orig = np.random.randint(
            0, 2, self.helper_action.n_line).astype(np.bool)
        set_status_orig = np.random.randint(-1, 2, self.helper_action.n_line)
        set_status_orig[change_status_orig] = 0

        change_topo_vect_orig = np.random.randint(
            0, 2, self.helper_action.dim_topo).astype(np.bool)
        # powerline that are set to be reconnected, can't be moved to another bus
        change_topo_vect_orig[self.helper_action.line_or_pos_topo_vect[
            set_status_orig == 1]] = False
        change_topo_vect_orig[self.helper_action.line_ex_pos_topo_vect[
            set_status_orig == 1]] = False
        # powerline that are disconnected, can't be moved to the other bus
        change_topo_vect_orig[self.helper_action.line_or_pos_topo_vect[
            set_status_orig == -1]] = False
        change_topo_vect_orig[self.helper_action.line_ex_pos_topo_vect[
            set_status_orig == -1]] = False

        set_topo_vect_orig = np.random.randint(0, 3,
                                               self.helper_action.dim_topo)
        set_topo_vect_orig[
            change_topo_vect_orig] = 0  # don't both change and set
        # I need to make sure powerlines that are reconnected are indeed reconnected to a bus
        set_topo_vect_orig[self.helper_action.line_or_pos_topo_vect[
            set_status_orig == 1]] = 1
        set_topo_vect_orig[self.helper_action.line_ex_pos_topo_vect[
            set_status_orig == 1]] = 1
        # I need to make sure powerlines that are disconnected are not assigned to a bus
        set_topo_vect_orig[self.helper_action.line_or_pos_topo_vect[
            set_status_orig == -1]] = 0
        set_topo_vect_orig[self.helper_action.line_ex_pos_topo_vect[
            set_status_orig == -1]] = 0

        action = self.helper_action({
            "change_bus": change_topo_vect_orig,
            "set_bus": set_topo_vect_orig,
            "injection": {
                "load_p": new_vect,
                "load_q": new_vect2
            },
            "change_line_status": change_status_orig,
            "set_line_status": set_status_orig
        })
        dict_injection, set_status, change_status, set_topo_vect, switcth_topo_vect, redispatching = action(
        )
        assert "load_p" in dict_injection
        assert np.all(dict_injection["load_p"] == new_vect)
        assert "load_q" in dict_injection
        assert np.all(dict_injection["load_q"] == new_vect2)

        assert np.all(set_status == set_status_orig)
        assert np.all(change_status == change_status_orig)
        assert np.all(set_topo_vect == set_topo_vect_orig)
        assert np.all(switcth_topo_vect == change_topo_vect_orig)

    def test_get_topological_impact(self):
        id_1 = 1
        id_2 = 12
        id_line = 17
        id_line2 = 15

        arr1 = np.array([False, False, False, True, True, True], dtype=np.bool)
        arr2 = np.array([1, 1, 2, 2], dtype=np.int)
        arr_line1 = np.full(self.helper_action.n_line,
                            fill_value=False,
                            dtype=np.bool)
        arr_line1[id_line] = True
        arr_line2 = np.full(self.helper_action.n_line,
                            fill_value=0,
                            dtype=np.int)
        arr_line2[id_line2] = 2

        do_nothing = self.helper_action({})
        aff_lines, aff_subs = do_nothing.get_topological_impact()
        assert np.sum(aff_lines) == 0
        assert np.sum(aff_subs) == 0

        act_sub1 = self.helper_action(
            {"change_bus": {
                "substations_id": [(id_1, arr1)]
            }})
        aff_lines, aff_subs = act_sub1.get_topological_impact()
        assert np.sum(aff_lines) == 0
        assert np.sum(aff_subs) == 1
        assert aff_subs[id_1]

        act_sub1_sub12 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            }
        })
        aff_lines, aff_subs = act_sub1_sub12.get_topological_impact()
        assert np.sum(aff_lines) == 0
        assert np.sum(aff_subs) == 2
        assert aff_subs[id_1]
        assert aff_subs[id_2]

        act_sub1_sub12_line1 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            },
            "change_line_status":
            arr_line1
        })
        aff_lines, aff_subs = act_sub1_sub12_line1.get_topological_impact()
        assert np.sum(aff_lines) == 1
        assert aff_lines[id_line] == 1
        assert np.sum(aff_subs) == 2
        assert aff_subs[id_1]
        assert aff_subs[id_2]

        act_sub1_sub12_line1_line2 = self.helper_action({
            "change_bus": {
                "substations_id": [(id_1, arr1)]
            },
            "set_bus": {
                "substations_id": [(id_2, arr2)]
            },
            "change_line_status":
            arr_line1,
            "set_line_status":
            arr_line2
        })
        aff_lines, aff_subs = act_sub1_sub12_line1_line2.get_topological_impact(
        )
        assert np.sum(aff_lines) == 2
        assert aff_lines[id_line] == 1
        assert aff_lines[id_line2] == 1
        assert np.sum(aff_subs) == 2
        assert aff_subs[id_1]
        assert aff_subs[id_2]

    def test_to_dict(self):
        dict_ = self.helper_action.to_dict()
        assert dict_ == self.res

    def test_from_dict(self):
        res = HelperAction.from_dict(self.res)
        assert np.all(res.name_gen == self.helper_action.name_gen)
        assert np.all(res.name_load == self.helper_action.name_load)
        assert np.all(res.name_line == self.helper_action.name_line)
        assert np.all(res.sub_info == self.helper_action.sub_info)
        assert np.all(res.load_to_subid == self.helper_action.load_to_subid)
        assert np.all(res.gen_to_subid == self.helper_action.gen_to_subid)
        assert np.all(
            res.line_or_to_subid == self.helper_action.line_or_to_subid)
        assert np.all(
            res.line_ex_to_subid == self.helper_action.line_ex_to_subid)
        assert np.all(
            res.load_to_sub_pos == self.helper_action.load_to_sub_pos)
        assert np.all(res.gen_to_sub_pos == self.helper_action.gen_to_sub_pos)
        assert np.all(
            res.line_or_to_sub_pos == self.helper_action.line_or_to_sub_pos)
        assert np.all(
            res.line_ex_to_sub_pos == self.helper_action.line_ex_to_sub_pos)
        assert np.all(
            res.load_pos_topo_vect == self.helper_action.load_pos_topo_vect)
        assert np.all(
            res.gen_pos_topo_vect == self.helper_action.gen_pos_topo_vect)
        assert np.all(res.line_or_pos_topo_vect ==
                      self.helper_action.line_or_pos_topo_vect)
        assert np.all(res.line_ex_pos_topo_vect ==
                      self.helper_action.line_ex_pos_topo_vect)
        # pdb.set_trace()
        assert np.all(res.actionClass == self.helper_action.actionClass)

    def test_json_serializable(self):
        dict_ = self.helper_action.to_dict()
        res = json.dumps(obj=dict_, indent=4, sort_keys=True)

    def test_json_loadable(self):
        dict_ = self.helper_action.to_dict()
        tmp = json.dumps(obj=dict_, indent=4, sort_keys=True)
        res = HelperAction.from_dict(json.loads(tmp))

        assert np.all(res.name_gen == self.helper_action.name_gen)
        assert np.all(res.name_load == self.helper_action.name_load)
        assert np.all(res.name_line == self.helper_action.name_line)
        assert np.all(res.sub_info == self.helper_action.sub_info)
        assert np.all(res.load_to_subid == self.helper_action.load_to_subid)
        assert np.all(res.gen_to_subid == self.helper_action.gen_to_subid)
        assert np.all(
            res.line_or_to_subid == self.helper_action.line_or_to_subid)
        assert np.all(
            res.line_ex_to_subid == self.helper_action.line_ex_to_subid)
        assert np.all(
            res.load_to_sub_pos == self.helper_action.load_to_sub_pos)
        assert np.all(res.gen_to_sub_pos == self.helper_action.gen_to_sub_pos)
        assert np.all(
            res.line_or_to_sub_pos == self.helper_action.line_or_to_sub_pos)
        assert np.all(
            res.line_ex_to_sub_pos == self.helper_action.line_ex_to_sub_pos)
        assert np.all(
            res.load_pos_topo_vect == self.helper_action.load_pos_topo_vect)
        assert np.all(
            res.gen_pos_topo_vect == self.helper_action.gen_pos_topo_vect)
        assert np.all(res.line_or_pos_topo_vect ==
                      self.helper_action.line_or_pos_topo_vect)
        assert np.all(res.line_ex_pos_topo_vect ==
                      self.helper_action.line_ex_pos_topo_vect)
        assert np.all(res.actionClass == self.helper_action.actionClass)

    def test_as_dict(self):
        act = self.helper_action_env({})
        dict_ = act.as_dict()
        assert dict_ == {}

    def test_to_from_vect_action(self):
        act = self.helper_action_env({})
        vect_ = act.to_vect()
        act2 = self.helper_action_env.from_vect(vect_)
        assert act == act2

    def test_sum_shape_equal_size(self):
        act = self.helper_action_env({})
        assert act.size() == np.sum(act.shape())

    def test_shape_correct(self):
        act = self.helper_action_env({})
        assert act.shape().shape == act.dtype().shape

    def test_redispatching(self):
        act = self.helper_action_env({"redispatch": [1, 10]})
        act = self.helper_action_env({"redispatch": [(1, 10), (2, 100)]})
        act = self.helper_action_env(
            {"redispatch": np.array([10, 20, 30, 40, 50])})
Example #6
0
    def __init__(
        self,
        parameters,
        thermal_limit_a=None,
        epsilon_poly=1e-2,
        tol_poly=1e-6,
    ):
        GridObjects.__init__(self)

        # specific to power system
        if not isinstance(parameters, Parameters):
            raise Grid2OpException(
                "Parameter \"parameters\" used to build the Environment should derived form the "
                "grid2op.Parameters class, type provided is \"{}\"".format(
                    type(parameters)))
        self.parameters = parameters

        # some timers
        self._time_apply_act = 0
        self._time_powerflow = 0
        self._time_extract_obs = 0

        # data relative to interpolation
        self._epsilon_poly = epsilon_poly
        self._tol_poly = tol_poly

        # define logger
        self.logger = None

        # and calendar data
        self.time_stamp = None
        self.nb_time_step = 0

        # observation
        self.current_obs = None

        # type of power flow to play
        # if True, then it will not disconnect lines above their thermal limits
        self.no_overflow_disconnection = self.parameters.NO_OVERFLOW_DISCONNECTION
        self.timestep_overflow = None
        self.nb_timestep_overflow_allowed = None

        # store actions "cooldown"
        self.times_before_line_status_actionable = None
        self.max_timestep_line_status_deactivated = self.parameters.NB_TIMESTEP_LINE_STATUS_REMODIF

        self.times_before_topology_actionable = None
        self.max_timestep_topology_deactivated = self.parameters.NB_TIMESTEP_TOPOLOGY_REMODIF

        # for maintenance operation
        self.time_next_maintenance = None
        self.duration_next_maintenance = None

        # hazard (not used outside of this class, information is given in `time_remaining_before_line_reconnection`
        self._hazard_duration = None

        # hard overflow part
        self.hard_overflow_threshold = self.parameters.HARD_OVERFLOW_THRESHOLD
        self.time_remaining_before_line_reconnection = None
        self.env_dc = self.parameters.ENV_DC

        # redispatching data
        self.target_dispatch = None
        self.actual_dispatch = None
        self.gen_uptime = None
        self.gen_downtime = None
        self.gen_activeprod_t = None

        self._thermal_limit_a = thermal_limit_a

        # maintenance / hazards
        self.time_next_maintenance = None
        self.duration_next_maintenance = None
        self.time_remaining_before_reconnection = None

        # store environment modifications
        self._injection = None
        self._maintenance = None
        self._hazards = None
        self.env_modification = None

        # to use the data
        self.done = False
        self.current_reward = None
        self.helper_action_env = None
        self.chronics_handler = None
        self.game_rules = None
        self.helper_action_player = None

        self.rewardClass = None
        self.actionClass = None
        self.observationClass = None
        self.legalActClass = None
        self.helper_observation = None
        self.names_chronics_to_backend = None
        self.reward_helper = None
        self.reward_range = None, None

        # backend
        self.init_grid_path = None

        # specific to Basic Env, do not change
        self.backend = None
        self.__is_init = False
Example #7
0
    def setUp(self):
        """
        The case file is a representation of the case14 as found in the ieee14 powergrid.
        :return:
        """
        # from ADNBackend import ADNBackend
        # self.backend = ADNBackend()
        # self.path_matpower = "/home/donnotben/Documents/RL4Grid/RL4Grid/data"
        # self.case_file = "ieee14_ADN.xml"
        # self.backend.load_grid(self.path_matpower, self.case_file)
        self.tolvect = 1e-2
        self.tol_one = 1e-5
        self.game_rules = GameRules()
        self.gridobj = GridObjects()
        self.gridobj.init_grid_vect(name_prod=["gen_{}".format(i) for i in range(5)],
                                          name_load=["load_{}".format(i) for i in range(11)],
                                          name_line=["line_{}".format(i) for i in range(20)],
                                          name_sub=["sub_{}".format(i) for i in range(14)],
                                          sub_info=np.array([3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3], dtype=np.int),
                                          load_to_subid=np.array([1,  2,  3,  4,  5,  8,  9, 10, 11, 12, 13]),
                                          gen_to_subid=np.array([0, 1, 2, 5, 7]),
                                          line_or_to_subid=np.array([ 0,  0,  1,  1,  1,  2,  3,  3,  3,  4,  5,  5,
                                                                       5,  6,  6,  8,  8, 9, 11, 12]),
                                          line_ex_to_subid=np.array([ 1,  4,  2,  3,  4,  3,  4,  6,  8,  5, 10, 11,
                                                                       12,  7,  8,  9, 13, 10, 12, 13]),  #####
                                          load_to_sub_pos=np.array([4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1]),
                                          gen_to_sub_pos=np.array([2, 5, 3, 5, 1]),
                                          line_or_to_sub_pos=np.array([0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2,
                                                                        3, 0, 0, 1]),
                                          line_ex_to_sub_pos=np.array([0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0, 0]),  #####
                                          load_pos_topo_vect=np.array([ 7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54]),
                                          gen_pos_topo_vect=np.array([ 2,  8, 12, 29, 34]),
                                          line_or_pos_topo_vect=np.array([ 0,  1,  4,  5,  6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38, 40, 46, 50]),
                                          line_ex_pos_topo_vect=np.array([ 3, 19,  9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42, 55, 43, 49, 53]))
        # pdb.set_trace()
        self.helper_action = HelperAction(self.gridobj,
                                          game_rules=self.game_rules)


        self.helper_action_env = HelperAction(self.gridobj,
                                              game_rules=self.game_rules,
                                              actionClass=Action)

        self.res = {'name_gen': ['gen_0', 'gen_1', 'gen_2', 'gen_3', 'gen_4'],
               'name_load': ['load_0', 'load_1', 'load_2', 'load_3', 'load_4', 'load_5', 'load_6',
                             'load_7', 'load_8', 'load_9', 'load_10'],
               'name_line': ['line_0', 'line_1', 'line_2', 'line_3', 'line_4', 'line_5', 'line_6', 'line_7',
                             'line_8', 'line_9', 'line_10', 'line_11', 'line_12', 'line_13', 'line_14', 'line_15',
                             'line_16', 'line_17', 'line_18', 'line_19'],
                'name_sub': ["sub_0", "sub_1", "sub_2", "sub_3", "sub_4", "sub_5", "sub_6", "sub_7", "sub_8", "sub_9",
                             "sub_10", "sub_11", "sub_12", "sub_13"],
               'sub_info': [3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3],
               'load_to_subid': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13],
               'gen_to_subid': [0, 1, 2, 5, 7],
               'line_or_to_subid': [0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 8, 8, 9, 11, 12],
               'line_ex_to_subid': [1, 4, 2, 3, 4, 3, 4, 6, 8, 5, 10, 11, 12, 7, 8, 9, 13, 10, 12, 13],
               'load_to_sub_pos': [4, 2, 5, 4, 4, 4, 1, 1, 1, 2, 1], 'gen_to_sub_pos': [2, 5, 3, 5, 1],
               'line_or_to_sub_pos': [0, 1, 1, 2, 3, 1, 2, 3, 4, 3, 1, 2, 3, 1, 2, 2, 3, 0, 0, 1],
               'line_ex_to_sub_pos': [0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 2, 2, 0, 0, 0],
               'load_pos_topo_vect': [7, 11, 18, 23, 28, 39, 41, 44, 47, 51, 54],
               'gen_pos_topo_vect': [2, 8, 12, 29, 34],
               'line_or_pos_topo_vect': [0, 1, 4, 5, 6, 10, 15, 16, 17, 22, 25, 26, 27, 31, 32, 37, 38, 40, 46, 50],
               'line_ex_pos_topo_vect': [3, 19, 9, 13, 20, 14, 21, 30, 35, 24, 45, 48, 52, 33, 36, 42, 55, 43, 49, 53],
               'subtype': 'Action.Action'}