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() # pdb.set_trace() self.rewardClass = L2RPNReward self.reward_helper = self.rewardClass() self.obsClass = CompleteObservation self.parameters = Parameters() # powergrid self.backend = PandaPowerBackend() self.path_matpower = PATH_DATA_TEST_PP self.case_file = "test_case14.json" # chronics self.path_chron = os.path.join(PATH_CHRONICS, "chronics_with_forecast") self.chronics_handler = ChronicsHandler( chronicsClass=GridStateFromFileWithForecasts, path=self.path_chron) self.tolvect = 1e-2 self.tol_one = 1e-5 self.id_chron_to_back_load = np.array( [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]) # force the verbose backend self.backend.detailed_infos_for_cascading_failures = True self.names_chronics_to_backend = { "loads": { "2_C-10.61": 'load_1_0', "3_C151.15": 'load_2_1', "14_C63.6": 'load_13_2', "4_C-9.47": 'load_3_3', "5_C201.84": 'load_4_4', "6_C-6.27": 'load_5_5', "9_C130.49": 'load_8_6', "10_C228.66": 'load_9_7', "11_C-138.89": 'load_10_8', "12_C-27.88": 'load_11_9', "13_C-13.33": 'load_12_10' }, "lines": { '1_2_1': '0_1_0', '1_5_2': '0_4_1', '9_10_16': '8_9_2', '9_14_17': '8_13_3', '10_11_18': '9_10_4', '12_13_19': '11_12_5', '13_14_20': '12_13_6', '2_3_3': '1_2_7', '2_4_4': '1_3_8', '2_5_5': '1_4_9', '3_4_6': '2_3_10', '4_5_7': '3_4_11', '6_11_11': '5_10_12', '6_12_12': '5_11_13', '6_13_13': '5_12_14', '4_7_8': '3_6_15', '4_9_9': '3_8_16', '5_6_10': '4_5_17', '7_8_14': '6_7_18', '7_9_15': '6_8_19' }, "prods": { "1_G137.1": 'gen_0_4', "3_G36.31": "gen_2_1", "6_G63.29": "gen_5_2", "2_G-56.47": "gen_1_0", "8_G40.43": "gen_7_3" }, } # _parameters for the environment self.env_params = Parameters() self.env = Environment( init_grid_path=os.path.join(self.path_matpower, self.case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=self.env_params, names_chronics_to_backend=self.names_chronics_to_backend, rewardClass=self.rewardClass) self.dict_ = { 'name_gen': ['gen_1_0', 'gen_2_1', 'gen_5_2', 'gen_7_3', 'gen_0_4'], 'name_load': [ 'load_1_0', 'load_2_1', 'load_13_2', 'load_3_3', 'load_4_4', 'load_5_5', 'load_8_6', 'load_9_7', 'load_10_8', 'load_11_9', 'load_12_10' ], 'name_line': [ '0_1_0', '0_4_1', '8_9_2', '8_13_3', '9_10_4', '11_12_5', '12_13_6', '1_2_7', '1_3_8', '1_4_9', '2_3_10', '3_4_11', '5_10_12', '5_11_13', '5_12_14', '3_6_15', '3_8_16', '4_5_17', '6_7_18', '6_8_19' ], 'name_sub': [ 'sub_0', 'sub_1', 'sub_10', 'sub_11', 'sub_12', 'sub_13', 'sub_2', 'sub_3', 'sub_4', 'sub_5', 'sub_6', 'sub_7', 'sub_8', 'sub_9' ], 'sub_info': [3, 6, 4, 6, 5, 6, 3, 2, 5, 3, 3, 3, 4, 3], 'load_to_subid': [1, 2, 13, 3, 4, 5, 8, 9, 10, 11, 12], 'gen_to_subid': [1, 2, 5, 7, 0], 'line_or_to_subid': [0, 0, 8, 8, 9, 11, 12, 1, 1, 1, 2, 3, 5, 5, 5, 3, 3, 4, 6, 6], 'line_ex_to_subid': [ 1, 4, 9, 13, 10, 12, 13, 2, 3, 4, 3, 4, 10, 11, 12, 6, 8, 5, 7, 8 ], 'load_to_sub_pos': [5, 3, 2, 5, 4, 5, 4, 2, 2, 2, 3], 'gen_to_sub_pos': [4, 2, 4, 1, 2], 'line_or_to_sub_pos': [0, 1, 0, 1, 1, 0, 1, 1, 2, 3, 1, 2, 0, 1, 2, 3, 4, 3, 1, 2], 'line_ex_to_sub_pos': [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 2, 1, 1, 2, 0, 2, 3, 0, 3], 'load_pos_topo_vect': [8, 12, 55, 18, 23, 29, 39, 42, 45, 48, 52], 'gen_pos_topo_vect': [7, 11, 28, 34, 2], 'line_or_pos_topo_vect': [ 0, 1, 35, 36, 41, 46, 50, 4, 5, 6, 10, 15, 24, 25, 26, 16, 17, 22, 31, 32 ], 'line_ex_pos_topo_vect': [ 3, 19, 40, 53, 43, 49, 54, 9, 13, 20, 14, 21, 44, 47, 51, 30, 37, 27, 33, 38 ], 'subtype': 'Observation.CompleteObservation' } self.dtypes = np.array([ dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('float64'), dtype('bool'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64'), dtype('int64') ], dtype=object) self.shapes = np.array([ 1, 1, 1, 1, 1, 1, 5, 5, 5, 11, 11, 11, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 56, 20, 20, 14, 20, 20, 20 ])
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() # pdb.set_trace() self.rewardClass = L2RPNReward self.reward_helper = self.rewardClass() self.obsClass = CompleteObservation self.parameters = Parameters() # powergrid self.backend = PandaPowerBackend() self.path_matpower = PATH_DATA_TEST_PP self.case_file = "test_case14.json" # chronics self.path_chron = os.path.join(PATH_CHRONICS, "chronics_with_hazards") self.chronics_handler = ChronicsHandler( chronicsClass=GridStateFromFile, path=self.path_chron) self.tolvect = 1e-2 self.tol_one = 1e-5 self.id_chron_to_back_load = np.array( [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]) # force the verbose backend self.backend.detailed_infos_for_cascading_failures = True self.names_chronics_to_backend = { "loads": { "2_C-10.61": 'load_1_0', "3_C151.15": 'load_2_1', "14_C63.6": 'load_13_2', "4_C-9.47": 'load_3_3', "5_C201.84": 'load_4_4', "6_C-6.27": 'load_5_5', "9_C130.49": 'load_8_6', "10_C228.66": 'load_9_7', "11_C-138.89": 'load_10_8', "12_C-27.88": 'load_11_9', "13_C-13.33": 'load_12_10' }, "lines": { '1_2_1': '0_1_0', '1_5_2': '0_4_1', '9_10_16': '8_9_2', '9_14_17': '8_13_3', '10_11_18': '9_10_4', '12_13_19': '11_12_5', '13_14_20': '12_13_6', '2_3_3': '1_2_7', '2_4_4': '1_3_8', '2_5_5': '1_4_9', '3_4_6': '2_3_10', '4_5_7': '3_4_11', '6_11_11': '5_10_12', '6_12_12': '5_11_13', '6_13_13': '5_12_14', '4_7_8': '3_6_15', '4_9_9': '3_8_16', '5_6_10': '4_5_17', '7_8_14': '6_7_18', '7_9_15': '6_8_19' }, "prods": { "1_G137.1": 'gen_0_4', "3_G36.31": "gen_2_1", "6_G63.29": "gen_5_2", "2_G-56.47": "gen_1_0", "8_G40.43": "gen_7_3" }, } # _parameters for the environment self.env_params = Parameters() self.env = Environment( init_grid_path=os.path.join(self.path_matpower, self.case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=self.env_params, names_chronics_to_backend=self.names_chronics_to_backend, rewardClass=self.rewardClass)
def setUp(self): # powergrid self.backend = PandaPowerBackend() self.path_matpower = PATH_DATA_TEST_PP self.case_file = "test_case14.json" # chronics self.path_chron = os.path.join(PATH_CHRONICS, "chronics") self.chronics_handler = ChronicsHandler( chronicsClass=GridStateFromFile, path=self.path_chron) self.tolvect = 1e-2 self.tol_one = 1e-5 self.id_chron_to_back_load = np.array( [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]) # force the verbose backend self.backend.detailed_infos_for_cascading_failures = True self.names_chronics_to_backend = { "loads": { "2_C-10.61": 'load_1_0', "3_C151.15": 'load_2_1', "14_C63.6": 'load_13_2', "4_C-9.47": 'load_3_3', "5_C201.84": 'load_4_4', "6_C-6.27": 'load_5_5', "9_C130.49": 'load_8_6', "10_C228.66": 'load_9_7', "11_C-138.89": 'load_10_8', "12_C-27.88": 'load_11_9', "13_C-13.33": 'load_12_10' }, "lines": { '1_2_1': '0_1_0', '1_5_2': '0_4_1', '9_10_16': '8_9_2', '9_14_17': '8_13_3', '10_11_18': '9_10_4', '12_13_19': '11_12_5', '13_14_20': '12_13_6', '2_3_3': '1_2_7', '2_4_4': '1_3_8', '2_5_5': '1_4_9', '3_4_6': '2_3_10', '4_5_7': '3_4_11', '6_11_11': '5_10_12', '6_12_12': '5_11_13', '6_13_13': '5_12_14', '4_7_8': '3_6_15', '4_9_9': '3_8_16', '5_6_10': '4_5_17', '7_8_14': '6_7_18', '7_9_15': '6_8_19' }, "prods": { "1_G137.1": 'gen_0_4', "3_G36.31": "gen_2_1", "6_G63.29": "gen_5_2", "2_G-56.47": "gen_1_0", "8_G40.43": "gen_7_3" }, } # _parameters for the environment self.env_params = Parameters() self.env = Environment( init_grid_path=os.path.join(self.path_matpower, self.case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=self.env_params, names_chronics_to_backend=self.names_chronics_to_backend)
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]
class TestEnvPerformsCorrectCascadingFailures(unittest.TestCase): """ Test the "next_grid_state" method of the back-end """ def setUp(self): self.backend = PandaPowerBackend( detailed_infos_for_cascading_failures=True) 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) self.lines_flows_init = np.array([ 638.28966637, 305.05042301, 17658.9674809, 26534.04334098, 10869.23856329, 4686.71726729, 15612.65903298, 300.07915572, 229.8060832, 169.97292682, 100.40192958, 265.47505664, 21193.86923911, 21216.44452327, 49701.1565287, 124.79684388, 67.59759985, 192.19424706, 666.76961936, 1113.52773632 ]) # _parameters for the environment self.env_params = Parameters() # used for init an env too self.chronics_handler = ChronicsHandler() self.id_first_line_disco = 8 # due to hard overflow self.id_2nd_line_disco = 11 # due to soft overflow def next_grid_state_no_overflow(self): # first i test that, when there is no overflow, i dont do a cascading failure env = Environment(init_grid_path=os.path.join(self.path_matpower, self.case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=self.env_params) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert not infos def test_next_grid_state_1overflow(self): # second i test that, when is one line on hard overflow it is disconnected case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=env_params) self.backend.load_grid(self.path_matpower, case_file) thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert len(infos) == 1 # check that i have only one overflow assert np.sum(disco) == 1 def test_next_grid_state_1overflow_envNoCF(self): # third i test that, if a line is on hard overflow, but i'm on a "no cascading failure" mode, # i don't simulate a cascading failure self.env_params.NO_OVERFLOW_DISCONNECTION = True case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=self.env_params) self.backend.load_grid(self.path_matpower, case_file) thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert not infos # check that don't simulate a cascading failure assert np.sum(disco) == 0 def test_nb_timestep_overflow_disc0(self): # on this _grid, first line with id 5 is overheated, # it is disconnected # then powerline 16 have a relative flow of 1.5916318201096937 # in this scenario i don't have a second line disconnection. case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env_params.NB_TIMESTEP_POWERFLOW_ALLOWED = 0 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=env_params) self.backend.load_grid(self.path_matpower, case_file) thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 thermal_limit[self.id_2nd_line_disco] = 400 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert len( infos) == 2 # check that there is a cascading failure of length 2 assert disco[self.id_first_line_disco] assert disco[self.id_2nd_line_disco] assert np.sum(disco) == 2 def test_nb_timestep_overflow_nodisc(self): # on this _grid, first line with id 18 is overheated, # it is disconnected # then powerline 16 have a relative flow of 1.5916318201096937 # in this scenario i don't have a second line disconnection because # the overflow is a soft overflow and the powerline is presumably overflow since 0 # timestep case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=env_params) self.backend.load_grid(self.path_matpower, case_file) env.timestep_overflow[self.id_2nd_line_disco] = 0 thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 thermal_limit[self.id_2nd_line_disco] = 400 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert len(infos) == 1 # check that don't simulate a cascading failure assert disco[self.id_first_line_disco] assert np.sum(disco) == 1 def test_nb_timestep_overflow_nodisc_2(self): # on this _grid, first line with id 18 is overheated, # it is disconnected # then powerline 16 have a relative flow of 1.5916318201096937 # in this scenario i don't have a second line disconnection because # the overflow is a soft overflow and the powerline is presumably overflow since only 1 # timestep case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=env_params) self.backend.load_grid(self.path_matpower, case_file) env.timestep_overflow[self.id_2nd_line_disco] = 1 thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 thermal_limit[self.id_2nd_line_disco] = 400 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert len(infos) == 1 # check that don't simulate a cascading failure assert disco[self.id_first_line_disco] assert np.sum(disco) == 1 def test_nb_timestep_overflow_disc2(self): # on this _grid, first line with id 18 is overheated, # it is disconnected # then powerline 16 have a relative flow of 1.5916318201096937 # in this scenario I have a second disconnection, because the powerline is allowed to be on overflow for 2 # timestep and is still on overflow here. case_file = self.case_file env_params = copy.deepcopy(self.env_params) env_params.HARD_OVERFLOW_THRESHOLD = 1.5 env_params.NB_TIMESTEP_POWERFLOW_ALLOWED = 2 env = Environment(init_grid_path=os.path.join(self.path_matpower, case_file), backend=self.backend, chronics_handler=self.chronics_handler, parameters=env_params) self.backend.load_grid(self.path_matpower, case_file) env.timestep_overflow[self.id_2nd_line_disco] = 2 thermal_limit = 10 * self.lines_flows_init thermal_limit[self.id_first_line_disco] = self.lines_flows_init[ self.id_first_line_disco] / 2 thermal_limit[self.id_2nd_line_disco] = 400 self.backend.set_thermal_limit(thermal_limit) disco, infos = self.backend.next_grid_state(env, is_dc=False) assert len( infos) == 2 # check that there is a cascading failure of length 2 assert disco[self.id_first_line_disco] assert disco[self.id_2nd_line_disco] assert np.sum(disco) == 2 for i, grid_tmp in enumerate(infos): assert (not grid_tmp.get_line_status()[self.id_first_line_disco]) if i == 1: assert (not grid_tmp.get_line_status()[self.id_2nd_line_disco])
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
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