Ejemplo n.º 1
0
class TestTopoAction(unittest.TestCase):
    # Cette méthode sera appelée avant chaque test.
    def setUp(self):
        self.backend = PandaPowerBackend()
        self.path_matpower = PATH_DATA_TEST
        self.case_file = "test_case14.json"
        self.backend.load_grid(self.path_matpower, self.case_file)
        self.tolvect = 1e-2
        self.tol_one = 1e-5

        self.game_rules = GameRules()
        self.helper_action = HelperAction(
            gridobj=self.backend, legal_action=self.game_rules.legal_action)

    # Cette méthode sera appelée après chaque test.
    def tearDown(self):
        pass

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

    def test_topo_set1sub(self):
        # retrieve some initial data to be sure only a subpart of the _grid is modified
        conv = self.backend.runpf()
        init_amps_flow = self.backend.get_line_flow()

        # check that maintenance vector is properly taken into account
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        id_ = 1
        action = self.helper_action(
            {"set_bus": {
                "substations_id": [(id_, arr)]
            }})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.load_pos_topo_vect[load_ids]] ==
                      arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.line_or_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.line_or_pos_topo_vect[lor_ids]] ==
                      arr[self.backend.line_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.line_ex_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.line_ex_pos_topo_vect[lex_ids]] ==
                      arr[self.backend.line_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] ==
                      arr[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow_th = np.array([
            6.38865247e+02, 3.81726828e+02, 1.78001287e+04, 2.70742428e+04,
            1.06755055e+04, 4.71160165e+03, 1.52265925e+04, 3.37755751e+02,
            3.00535519e+02, 5.01164454e-13, 7.01900962e+01, 1.73874580e+02,
            2.08904697e+04, 2.11757439e+04, 4.93863382e+04, 1.31935835e+02,
            6.99779475e+01, 1.85068609e+02, 7.47283039e+02, 1.14125596e+03
        ])

        after_amps_flow_th = np.array([
            596.58386539, 342.31364678, 18142.87789987, 27084.37162086,
            10155.86483194, 4625.93022957, 15064.92626615, 322.59381855,
            273.6977149, 82.21908229, 80.91290202, 206.04740125,
            20480.81970337, 21126.22533095, 49275.71520428, 128.04429617,
            69.00661266, 188.44754187, 688.1371226, 1132.42521887
        ])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(
                np.abs(q_subs)
            ) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten(
            ))) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

    def test_topo_change1sub(self):
        # check that switching the bus of 3 object is equivalent to set them to bus 2 (as above)
        conv = self.backend.runpf()
        init_amps_flow = self.backend.get_line_flow()

        # check that maintenance vector is properly taken into account
        arr = np.array([False, False, False, True, True, True], dtype=np.bool)
        id_ = 1
        action = self.helper_action(
            {"change_bus": {
                "substations_id": [(id_, arr)]
            }})

        # apply the action here
        self.backend.apply_action(action)

        # run the powerflow
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1 +
            arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.line_or_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.line_or_pos_topo_vect[lor_ids]] == 1 +
            arr[self.backend.line_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.line_ex_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.line_ex_pos_topo_vect[lex_ids]] == 1 +
            arr[self.backend.line_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1 +
                      arr[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow_th = np.array([
            596.58386539, 342.31364678, 18142.87789987, 27084.37162086,
            10155.86483194, 4625.93022957, 15064.92626615, 322.59381855,
            273.6977149, 82.21908229, 80.91290202, 206.04740125,
            20480.81970337, 21126.22533095, 49275.71520428, 128.04429617,
            69.00661266, 188.44754187, 688.1371226, 1132.42521887
        ])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(
                np.abs(q_subs)
            ) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten(
            ))) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

    def test_topo_change_1sub_twice(self):
        # check that switching the bus of 3 object is equivalent to set them to bus 2 (as above)
        # and that setting it again is equivalent to doing nothing
        conv = self.backend.runpf()
        init_amps_flow = np.array([el for el in self.backend.get_line_flow()])

        # check that maintenance vector is properly taken into account
        arr = np.array([False, False, False, True, True, True], dtype=np.bool)
        id_ = 1
        action = self.helper_action(
            {"change_bus": {
                "substations_id": [(id_, arr)]
            }})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1 +
            arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.line_or_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.line_or_pos_topo_vect[lor_ids]] == 1 +
            arr[self.backend.line_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.line_ex_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.line_ex_pos_topo_vect[lex_ids]] == 1 +
            arr[self.backend.line_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1 +
                      arr[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow_th = np.array([
            596.58386539, 342.31364678, 18142.87789987, 27084.37162086,
            10155.86483194, 4625.93022957, 15064.92626615, 322.59381855,
            273.6977149, 82.21908229, 80.91290202, 206.04740125,
            20480.81970337, 21126.22533095, 49275.71520428, 128.04429617,
            69.00661266, 188.44754187, 688.1371226, 1132.42521887
        ])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)
        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(
                np.abs(q_subs)
            ) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten(
            ))) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

        action = self.helper_action(
            {"change_bus": {
                "substations_id": [(id_, arr)]
            }})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv

        after_amps_flow = self.backend.get_line_flow()
        assert self.compare_vect(after_amps_flow, init_amps_flow)
        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1
        assert np.max(topo_vect) == 1
        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(
                np.abs(q_subs)
            ) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten(
            ))) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

    def test_topo_change_2sub(self):
        # check that maintenance vector is properly taken into account
        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)]
            }
        })
        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv

        # check the _grid is correct
        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1 +
            arr1[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.line_or_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.line_or_pos_topo_vect[lor_ids]] == 1 +
            arr1[self.backend.line_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.line_ex_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.line_ex_pos_topo_vect[lex_ids]] == 1 +
            arr1[self.backend.line_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_1)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1 +
                      arr1[self.backend.gen_to_sub_pos[gen_ids]])

        load_ids = np.where(self.backend.load_to_subid == id_2)[0]
        assert np.all(topo_vect[self.backend.load_pos_topo_vect[load_ids]] ==
                      arr2[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.line_or_to_subid == id_2)[0]
        assert np.all(topo_vect[self.backend.line_or_pos_topo_vect[lor_ids]] ==
                      arr2[self.backend.line_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.line_ex_to_subid == id_2)[0]
        assert np.all(topo_vect[self.backend.line_ex_pos_topo_vect[lex_ids]] ==
                      arr2[self.backend.line_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_2)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] ==
                      arr2[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow = self.backend.get_line_flow()
        after_amps_flow_th = np.array([
            596.97014348, 342.10559579, 16615.11815357, 31328.50690716,
            11832.77202397, 11043.10650167, 11043.10650167, 322.79533908,
            273.86501458, 82.34066647, 80.89289074, 208.42396413,
            22178.16766548, 27690.51322075, 38684.31540646, 129.44842477,
            70.02629553, 185.67687123, 706.77680037, 1155.45754617
        ])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(
                np.abs(q_subs)
            ) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten(
            ))) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass
Ejemplo n.º 2
0
class TestLoadingBackendFunc(unittest.TestCase):
    # Cette méthode sera appelée avant chaque test.
    def setUp(self):
        self.backend = PandaPowerBackend()
        self.path_matpower = PATH_DATA_TEST
        self.case_file = "test_case14.json"
        self.backend.load_grid(self.path_matpower, self.case_file)
        self.tolvect = 1e-2
        self.tol_one = 1e-5
        self.game_rules = GameRules()
        self.action_env = HelperAction(
            gridobj=self.backend, legal_action=self.game_rules.legal_action)

    # Cette méthode sera appelée après chaque test.
    def tearDown(self):
        pass

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

    def test_runpf(self):
        conv = self.backend.runpf(is_dc=True)
        assert conv

        true_values_ac = np.array([
            1.56882891e+02, 7.55103818e+01, 5.22755247e+00, 9.42638103e+00,
            -3.78532238e+00, 1.61425777e+00, 5.64385098e+00, 7.32375792e+01,
            5.61314959e+01, 4.15162150e+01, -2.32856901e+01, -6.11582304e+01,
            7.35327698e+00, 7.78606702e+00, 1.77479769e+01, 2.80741759e+01,
            1.60797576e+01, 4.40873209e+01, -1.11022302e-14, 2.80741759e+01
        ])
        true_values_dc = np.array([
            147.83859556, 71.16140444, 5.7716542, 9.64132512, -3.2283458,
            1.50735814, 5.25867488, 70.01463596, 55.1518527, 40.9721069,
            -24.18536404, -61.74649065, 6.7283458, 7.60735814, 17.25131674,
            28.36115279, 16.55182652, 42.78702069, 0., 28.36115279
        ])

        p_or, *_ = self.backend.lines_or_info()
        assert self.compare_vect(p_or, true_values_dc)

        conv = self.backend.runpf(is_dc=False)
        assert conv
        p_or, *_ = self.backend.lines_or_info()
        assert self.compare_vect(p_or, true_values_ac)

    def test_voltage_convert_powerlines(self):
        # i have the correct voltages in powerlines if the formula to link mw, mvar, kv and amps is correct
        conv = self.backend.runpf(is_dc=False)
        assert conv

        p_or, q_or, v_or, a_or = self.backend.lines_or_info()
        a_th = np.sqrt(p_or**2 + q_or**2) * 1e3 / (np.sqrt(3) * v_or)
        assert self.compare_vect(a_th, a_or)

        p_ex, q_ex, v_ex, a_ex = self.backend.lines_ex_info()
        a_th = np.sqrt(p_ex**2 + q_ex**2) * 1e3 / (np.sqrt(3) * v_ex)
        assert self.compare_vect(a_th, a_ex)

    def test_voltages_correct_load_gen(self):
        # i have the right voltages to generators and load, if it's the same as the voltage (correct from the above test)
        # of the powerline connected to it.

        conv = self.backend.runpf(is_dc=False)
        load_p, load_q, load_v = self.backend.loads_info()
        gen_p, gen__q, gen_v = self.backend.generators_info()
        p_or, q_or, v_or, a_or = self.backend.lines_or_info()
        p_ex, q_ex, v_ex, a_ex = self.backend.lines_ex_info()

        for c_id, sub_id in enumerate(self.backend.load_to_subid):
            l_id = np.where(self.backend.line_or_to_subid == sub_id)[0]
            if len(l_id):
                l_id = l_id[0]
                assert np.abs(v_or[l_id] - load_v[c_id]
                              ) <= self.tol_one, "problem for load {}".format(
                                  c_id)
                continue

            l_id = np.where(self.backend.line_ex_to_subid == sub_id)[0]
            if len(l_id):
                l_id = l_id[0]
                assert np.abs(v_ex[l_id] - load_v[c_id]
                              ) <= self.tol_one, "problem for load {}".format(
                                  c_id)
                continue
            assert False, "load {} has not been checked".format(c_id)

        for g_id, sub_id in enumerate(self.backend.gen_to_subid):
            l_id = np.where(self.backend.line_or_to_subid == sub_id)[0]
            if len(l_id):
                l_id = l_id[0]
                assert np.abs(
                    v_or[l_id] - gen_v[g_id]
                ) <= self.tol_one, "problem for generator {}".format(g_id)
                continue

            l_id = np.where(self.backend.line_ex_to_subid == sub_id)[0]
            if len(l_id):
                l_id = l_id[0]
                assert np.abs(
                    v_ex[l_id] - gen_v[g_id]
                ) <= self.tol_one, "problem for generator {}".format(g_id)
                continue
            assert False, "generator {} has not been checked".format(g_id)

    def test_copy(self):
        conv = self.backend.runpf(is_dc=False)
        p_or_orig, *_ = self.backend.lines_or_info()
        adn_backend_cpy = self.backend.copy()

        self.backend._disconnect_line(3)
        conv = self.backend.runpf(is_dc=False)
        assert conv
        conv2 = adn_backend_cpy.runpf(is_dc=False)
        assert conv2
        p_or_ref, *_ = self.backend.lines_or_info()
        p_or, *_ = adn_backend_cpy.lines_or_info()
        assert np.abs(p_or_ref[3]) <= self.tol_one
        assert self.compare_vect(p_or_orig, p_or)

    def test_get_line_status(self):
        assert np.all(self.backend.get_line_status())
        self.backend._disconnect_line(3)
        assert np.sum(~self.backend.get_line_status()) == 1
        assert not self.backend.get_line_status()[3]

    def test_get_line_flow(self):
        self.backend.runpf(is_dc=False)
        true_values_ac = np.array([
            -20.40429168, 3.85499114, 4.2191378, 3.61000624, -1.61506292,
            0.75395917, 1.74717378, 3.56020295, -1.5503504, 1.17099786,
            4.47311562, 15.82364194, 3.56047297, 2.50341424, 7.21657539,
            -9.68106571, -0.42761118, 12.47067981, -17.16297051, 5.77869057
        ])
        p_or_orig, q_or_orig, *_ = self.backend.lines_or_info()
        assert self.compare_vect(q_or_orig, true_values_ac)

        self.backend._disconnect_line(3)
        a = self.backend.runpf(is_dc=False)
        true_values_ac = np.array([
            -20.40028207, 3.65600775, 3.77916284, 0., -2.10761554, 1.34025308,
            5.86505081, 3.58514625, -2.28717836, 0.81979017, 3.72328838,
            17.09556423, 3.9548798, 3.18389804, 11.24144925, -11.09660174,
            -1.70423701, 13.14347167, -14.82917601, 2.276297
        ])
        p_or_orig, q_or_orig, *_ = self.backend.lines_or_info()
        assert self.compare_vect(q_or_orig, true_values_ac)

    def test_pf_ac_dc(self):
        true_values_ac = np.array([
            -20.40429168, 3.85499114, 4.2191378, 3.61000624, -1.61506292,
            0.75395917, 1.74717378, 3.56020295, -1.5503504, 1.17099786,
            4.47311562, 15.82364194, 3.56047297, 2.50341424, 7.21657539,
            -9.68106571, -0.42761118, 12.47067981, -17.16297051, 5.77869057
        ])
        conv = self.backend.runpf(is_dc=True)
        assert conv
        p_or_orig, q_or_orig, *_ = self.backend.lines_or_info()
        assert np.all(q_or_orig == 0.)
        conv = self.backend.runpf(is_dc=False)
        assert conv
        p_or_orig, q_or_orig, *_ = self.backend.lines_or_info()
        assert self.compare_vect(q_or_orig, true_values_ac)

    def test_get_thermal_limit(self):
        res = self.backend.get_thermal_limit()
        true_values_ac = np.array([
            42339.01974057, 42339.01974057, 27479652.23546777,
            27479652.23546777, 27479652.23546777, 27479652.23546777,
            27479652.23546777, 42339.01974057, 42339.01974057, 42339.01974057,
            42339.01974057, 42339.01974057, 27479652.23546777,
            27479652.23546777, 27479652.23546777, 42339.01974057,
            42339.01974057, 42339.01974057, 408269.11892695, 408269.11892695
        ])
        assert self.compare_vect(res, true_values_ac)

    def test_disconnect_line(self):
        for i in range(self.backend.n_line):
            if i == 18:
                # powerflow diverge if line 1 is removed, unfortunately
                continue
            backend_cpy = self.backend.copy()
            backend_cpy._disconnect_line(i)
            conv = backend_cpy.runpf()
            assert conv, "Power flow computation does not converge if line {} is removed".format(
                i)
            flows = backend_cpy.get_line_status()
            assert not flows[i]
            assert np.sum(~flows) == 1

    def test_donothing_action(self):
        conv = self.backend.runpf()
        init_flow = self.backend.get_line_flow()
        init_lp, *_ = self.backend.loads_info()
        init_gp, *_ = self.backend.generators_info()
        init_ls = self.backend.get_line_status()

        action = self.action_env({})  # update the action
        self.backend.apply_action(action)
        after_lp, *_ = self.backend.loads_info()
        after_gp, *_ = self.backend.generators_info()
        after_ls = self.backend.get_line_status()
        assert self.compare_vect(init_lp,
                                 after_lp)  # check i didn't modify the loads
        # assert self.compare_vect(init_gp, after_gp)  # check i didn't modify the generators  # TODO here !!! problem with steady state P=C+L
        assert np.all(
            init_ls == after_ls)  # check i didn't disconnect any powerlines

        conv = self.backend.runpf()
        assert conv, "Cannot perform a powerflow after doing nothing"
        after_flow = self.backend.get_line_flow()
        assert self.compare_vect(init_flow, after_flow)

    def test_apply_action_active_value(self):
        # test that i can modify only the load / prod active values of the powergrid
        # to do that i modify the productions and load all of a factor 0.5 and compare that the DC flows are
        # also multiply by 2
        conv = self.backend.runpf(is_dc=True)
        init_flow, *_ = self.backend.lines_or_info()
        init_lp, init_l_q, *_ = self.backend.loads_info()
        init_gp, *_ = self.backend.generators_info()
        init_ls = self.backend.get_line_status()

        ratio = 0.5
        action = self.action_env({
            "injection": {
                "load_p": ratio * init_lp,
                "prod_p": ratio * init_gp * np.sum(init_lp) / np.sum(init_gp)
            }
        })  # update the action

        self.backend.apply_action(action)
        conv = self.backend.runpf(is_dc=True)
        assert conv, "Cannot perform a powerflow after doing nothing"

        after_lp, after_lq, *_ = self.backend.loads_info()
        after_gp, *_ = self.backend.generators_info()
        after_ls = self.backend.get_line_status()
        assert self.compare_vect(ratio * init_lp,
                                 after_lp)  # check i didn't modify the loads
        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            # i'm in DC mode, i can't check for reactive values...
            assert np.max(
                np.abs(p_subs)
            ) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(p_bus.flatten(
            ))) <= self.tolvect, "problem with active values, at a bus"
        except Grid2OpException:
            pass

        assert self.compare_vect(
            ratio * init_gp, after_gp)  # check i didn't modify the generators
        assert np.all(
            init_ls == after_ls)  # check i didn't disconnect any powerlines

        after_flow, *_ = self.backend.lines_or_info()
        assert self.compare_vect(
            ratio * init_flow,
            after_flow)  # probably an error with the DC approx

    def test_apply_action_prod_v(self):
        conv = self.backend.runpf(is_dc=False)
        prod_p_init, prod_q_init, prod_v_init = self.backend.generators_info()
        ratio = 1.05
        action = self.action_env(
            {"injection": {
                "prod_v": ratio * prod_v_init
            }})  # update the action
        self.backend.apply_action(action)
        conv = self.backend.runpf(is_dc=False)
        assert conv, "Cannot perform a powerflow aftermodifying the powergrid"

        prod_p_after, prod_q_after, prod_v_after = self.backend.generators_info(
        )
        assert self.compare_vect(
            ratio * prod_v_init,
            prod_v_after)  # check i didn't modify the generators

    def test_apply_action_maintenance(self):
        # retrieve some initial data to be sure only a subpart of the _grid is modified
        conv = self.backend.runpf()
        init_lp, *_ = self.backend.loads_info()
        init_gp, *_ = self.backend.generators_info()

        # check that maintenance vector is properly taken into account
        maintenance = np.full((self.backend.n_line, ),
                              fill_value=False,
                              dtype=np.bool)
        maintenance[19] = True
        action = self.action_env({"maintenance":
                                  maintenance})  # update the action

        # apply the action here
        self.backend.apply_action(action)

        # compute a load flow an performs more tests
        conv = self.backend.runpf()
        assert conv, "Power does not converge if line {} is removed".format(19)

        # performs basic check
        after_lp, *_ = self.backend.loads_info()
        after_gp, *_ = self.backend.generators_info()
        after_ls = self.backend.get_line_status()
        assert self.compare_vect(init_lp,
                                 after_lp)  # check i didn't modify the loads
        # assert self.compare_vect(init_gp, after_gp)  # check i didn't modify the generators  # TODO here problem with steady state P=C+L
        assert np.all(
            ~maintenance == after_ls
        )  # check i didn't disconnect any powerlines beside the correct one

        flows = self.backend.get_line_status()
        assert np.sum(~flows) == 1
        assert not flows[19]

    def test_apply_action_hazard(self):
        conv = self.backend.runpf()
        init_lp, *_ = self.backend.loads_info()
        init_gp, *_ = self.backend.generators_info()

        # check that maintenance vector is properly taken into account
        maintenance = np.full((self.backend.n_line, ),
                              fill_value=False,
                              dtype=np.bool)
        maintenance[17] = True
        action = self.action_env({"hazards": maintenance})  # update the action

        # apply the action here
        self.backend.apply_action(action)

        # compute a load flow an performs more tests
        conv = self.backend.runpf()
        assert conv, "Power does not converge if line {} is removed".format(19)

        # performs basic check
        after_lp, *_ = self.backend.loads_info()
        after_gp, *_ = self.backend.generators_info()
        after_ls = self.backend.get_line_status()
        assert self.compare_vect(init_lp,
                                 after_lp)  # check i didn't modify the loads
        # assert self.compare_vect(init_gp, after_gp)  # check i didn't modify the generators  # TODO here problem with steady state P=C+L
        assert np.all(
            maintenance == ~after_ls
        )  # check i didn't disconnect any powerlines beside the correct one

    #
    def test_apply_action_disconnection(self):
        # retrieve some initial data to be sure only a subpart of the _grid is modified
        conv = self.backend.runpf()
        init_lp, *_ = self.backend.loads_info()
        init_gp, *_ = self.backend.generators_info()

        # check that maintenance vector is properly taken into account
        maintenance = np.full((self.backend.n_line, ),
                              fill_value=False,
                              dtype=np.bool)
        maintenance[19] = True

        disc = np.full((self.backend.n_line, ),
                       fill_value=False,
                       dtype=np.bool)
        disc[17] = True

        action = self.action_env({
            "hazards": disc,
            "maintenance": maintenance
        })  # update the action
        # apply the action here
        self.backend.apply_action(action)

        # compute a load flow an performs more tests
        conv = self.backend.runpf()
        assert conv, "Power does not converge if lines {} and {} are removed".format(
            17, 19)

        # performs basic check
        after_lp, *_ = self.backend.loads_info()
        after_gp, *_ = self.backend.generators_info()
        after_ls = self.backend.get_line_status()
        assert self.compare_vect(init_lp,
                                 after_lp)  # check i didn't modify the loads
        # assert self.compare_vect(init_gp, after_gp)  # check i didn't modify the generators # TODO here problem with steady state, P=C+L
        assert np.all(
            disc | maintenance == ~after_ls
        )  # check i didn't disconnect any powerlines beside the correct one

        flows = self.backend.get_line_status()
        assert np.sum(~flows) == 2
        assert not flows[19]
        assert not flows[17]
Ejemplo n.º 3
0
class TestTopoAction(unittest.TestCase):
    # Cette méthode sera appelée avant chaque test.
    def setUp(self):
        self.backend = PandaPowerBackend()
        self.path_matpower = PATH_DATA_TEST
        self.case_file = "test_case14.json"
        self.backend.load_grid(self.path_matpower, self.case_file)
        self.tolvect = 1e-2
        self.tol_one = 1e-5

        self.game_rules = GameRules()
        self.helper_action = HelperAction(name_prod=self.backend.name_prods,
                                       name_load=self.backend.name_loads,
                                       name_line=self.backend.name_lines,
                                  subs_info=self.backend.subs_elements,
                                  load_to_subid=self.backend.load_to_subid,
                                  gen_to_subid=self.backend.gen_to_subid,
                                  lines_or_to_subid=self.backend.lines_or_to_subid,
                                  lines_ex_to_subid=self.backend.lines_ex_to_subid, #####
                                  load_to_sub_pos=self.backend.load_to_sub_pos,
                                  gen_to_sub_pos=self.backend.gen_to_sub_pos,
                                  lines_or_to_sub_pos=self.backend.lines_or_to_sub_pos,
                                  lines_ex_to_sub_pos=self.backend.lines_ex_to_sub_pos, #####
                                  load_pos_topo_vect=self.backend.load_pos_topo_vect,
                                  gen_pos_topo_vect=self.backend.gen_pos_topo_vect,
                                  lines_or_pos_topo_vect=self.backend.lines_or_pos_topo_vect,
                                  lines_ex_pos_topo_vect=self.backend.lines_ex_pos_topo_vect,
                                       game_rules=self.game_rules)

    # Cette méthode sera appelée après chaque test.
    def tearDown(self):
        pass

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

    def test_topo_set1sub(self):
        # retrieve some initial data to be sure only a subpart of the _grid is modified
        conv = self.backend.runpf()
        init_amps_flow = self.backend.get_line_flow()

        # check that maintenance vector is properly taken into account
        arr = np.array([1, 1, 1, 2, 2, 2], dtype=np.int)
        id_=1
        action = self.helper_action({"set_bus": {"substations_id": [(id_, arr)]}})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.load_pos_topo_vect[load_ids]] == arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.lines_or_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.lines_or_pos_topo_vect[lor_ids]] == arr[self.backend.lines_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.lines_ex_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.lines_ex_pos_topo_vect[lex_ids]] == arr[self.backend.lines_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == arr[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow_th = np.array([6.38865247e+02, 3.81726828e+02, 1.78001287e+04, 2.70742428e+04,
                                       1.06755055e+04, 4.71160165e+03, 1.52265925e+04, 3.37755751e+02,
                                       3.00535519e+02, 5.01164454e-13, 7.01900962e+01, 1.73874580e+02,
                                       2.08904697e+04, 2.11757439e+04, 4.93863382e+04, 1.31935835e+02,
                                       6.99779475e+01, 1.85068609e+02, 7.47283039e+02, 1.14125596e+03])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(np.abs(p_subs)) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(q_subs)) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten())) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten())) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

    def test_topo_change1sub(self):
        # check that switching the bus of 3 object is equivalent to set them to bus 2 (as above)
        conv = self.backend.runpf()
        init_amps_flow = self.backend.get_line_flow()

        # check that maintenance vector is properly taken into account
        arr = np.array([False, False, False, True, True, True], dtype=np.bool)
        id_ = 1
        action = self.helper_action({"change_bus": {"substations_id": [(id_, arr)]}})

        # apply the action here
        self.backend.apply_action(action)

        # run the powerflow
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1+arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.lines_or_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.lines_or_pos_topo_vect[lor_ids]] == 1+arr[self.backend.lines_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.lines_ex_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.lines_ex_pos_topo_vect[lex_ids]] == 1+arr[self.backend.lines_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid==id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1+arr[self.backend.gen_to_sub_pos[gen_ids]])


        after_amps_flow_th = np.array([6.38865247e+02, 3.81726828e+02, 1.78001287e+04, 2.70742428e+04,
                                       1.06755055e+04, 4.71160165e+03, 1.52265925e+04, 3.37755751e+02,
                                       3.00535519e+02, 5.01164454e-13, 7.01900962e+01, 1.73874580e+02,
                                       2.08904697e+04, 2.11757439e+04, 4.93863382e+04, 1.31935835e+02,
                                       6.99779475e+01, 1.85068609e+02, 7.47283039e+02, 1.14125596e+03])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(np.abs(p_subs)) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(q_subs)) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten())) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten())) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

    def test_topo_change_1sub_twice(self):
        # check that switching the bus of 3 object is equivalent to set them to bus 2 (as above)
        # and that setting it again is equivalent to doing nothing
        conv = self.backend.runpf()
        init_amps_flow = np.array([el for el in self.backend.get_line_flow()])

        # check that maintenance vector is properly taken into account
        arr = np.array([False, False, False, True, True, True], dtype=np.bool)
        id_ = 1
        action = self.helper_action({"change_bus": {"substations_id": [(id_, arr)]}})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv
        after_amps_flow = self.backend.get_line_flow()

        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1+arr[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.lines_or_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.lines_or_pos_topo_vect[lor_ids]] == 1+arr[self.backend.lines_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.lines_ex_to_subid == id_)[0]
        assert np.all(
            topo_vect[self.backend.lines_ex_pos_topo_vect[lex_ids]] == 1+arr[self.backend.lines_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1+arr[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow_th = np.array([6.38865247e+02, 3.81726828e+02, 1.78001287e+04, 2.70742428e+04,
                                       1.06755055e+04, 4.71160165e+03, 1.52265925e+04, 3.37755751e+02,
                                       3.00535519e+02, 5.01164454e-13, 7.01900962e+01, 1.73874580e+02,
                                       2.08904697e+04, 2.11757439e+04, 4.93863382e+04, 1.31935835e+02,
                                       6.99779475e+01, 1.85068609e+02, 7.47283039e+02, 1.14125596e+03])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)
        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(np.abs(p_subs)) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(q_subs)) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten())) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten())) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass

        action = self.helper_action({"change_bus": {"substations_id": [(id_, arr)]}})

        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv


        after_amps_flow = self.backend.get_line_flow()
        assert self.compare_vect(after_amps_flow, init_amps_flow)
        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1
        assert np.max(topo_vect) == 1
        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(np.abs(p_subs)) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(q_subs)) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten())) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten())) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass


    def test_topo_change_2sub(self):
        # check that maintenance vector is properly taken into account
        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)]}})
        # apply the action here
        self.backend.apply_action(action)
        conv = self.backend.runpf()
        assert conv

        # check the _grid is correct
        topo_vect = self.backend.get_topo_vect()
        assert np.min(topo_vect) == 1, "all buses have been changed"
        assert np.max(topo_vect) == 2, "no buses have been changed"

        # check that the objects have been properly moved
        load_ids = np.where(self.backend.load_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == 1+arr1[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.lines_or_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.lines_or_pos_topo_vect[lor_ids]] == 1+arr1[self.backend.lines_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.lines_ex_to_subid == id_1)[0]
        assert np.all(
            topo_vect[self.backend.lines_ex_pos_topo_vect[lex_ids]] == 1+arr1[self.backend.lines_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_1)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == 1+arr1[self.backend.gen_to_sub_pos[gen_ids]])


        load_ids = np.where(self.backend.load_to_subid == id_2)[0]
        assert np.all(
            topo_vect[self.backend.load_pos_topo_vect[load_ids]] == arr2[self.backend.load_to_sub_pos[load_ids]])
        lor_ids = np.where(self.backend.lines_or_to_subid == id_2)[0]
        assert np.all(
            topo_vect[self.backend.lines_or_pos_topo_vect[lor_ids]] == arr2[self.backend.lines_or_to_sub_pos[lor_ids]])
        lex_ids = np.where(self.backend.lines_ex_to_subid == id_2)[0]
        assert np.all(
            topo_vect[self.backend.lines_ex_pos_topo_vect[lex_ids]] == arr2[self.backend.lines_ex_to_sub_pos[lex_ids]])
        gen_ids = np.where(self.backend.gen_to_subid == id_2)[0]
        assert np.all(topo_vect[self.backend.gen_pos_topo_vect[gen_ids]] == arr2[self.backend.gen_to_sub_pos[gen_ids]])

        after_amps_flow = self.backend.get_line_flow()
        after_amps_flow_th = np.array([6.06484526e+02, 3.53118362e+02, 1.31069171e+04, 2.91362693e+04,
                                       1.81182785e+04, 1.36186919e+04, 1.36186919e+04, 3.26671053e+02,
                                       2.79359713e+02, 4.86200936e-13, 7.92740141e+01, 1.87635540e+02,
                                       2.82695392e+04, 3.02581716e+04, 3.25275006e-10, 1.21389438e+02,
                                       6.44646825e+01, 1.43147411e+02, 7.56229924e+02, 1.07504986e+03])
        assert self.compare_vect(after_amps_flow, after_amps_flow_th)

        try:
            p_subs, q_subs, p_bus, q_bus = self.backend.check_kirchoff()
            assert np.max(np.abs(p_subs)) <= self.tolvect, "problem with active values, at substation"
            assert np.max(np.abs(q_subs)) <= self.tolvect, "problem with reactive values, at substation"
            assert np.max(np.abs(p_bus.flatten())) <= self.tolvect, "problem with active values, at a bus"
            assert np.max(np.abs(q_bus.flatten())) <= self.tolvect, "problem with reaactive values, at a load"

        except Grid2OpException:
            pass