def update_pandapower( self, net: pandapowerNet, source: str, target: str, ): """Update a pandapower model by adding the cable itself. Args: net: a pandapower network model. source: a bus of the cable, corresponding to ``source`` in ``networkx`` edge. target: another bus of the cable, corresponding to ``source`` in ``networkx`` edge. """ from_bus = pp.get_element_index(net, "bus", source) to_bus = pp.get_element_index(net, "bus", target) pp.create_line_from_parameters( net, name=self.name, from_bus=from_bus, to_bus=to_bus, length_km=self.length_km, r_ohm_per_km=self.r_ohm, x_ohm_per_km=self.x_ohm, c_nf_per_km=self.c_nf, max_i_ka=self.max_i_ka, parallel=self.parallel, )
def update_pandapower( self, net: pandapowerNet, source: str, target: str, ): """Update a pandapower model by adding the transformer itself. Args: net: a pandapower network model. source: a bus of the transformer, corresponding to ``source`` in ``networkx`` edge. target: another bus of the transformer, corresponding to ``source`` in ``networkx`` edge. """ hv_bus = pp.get_element_index(net, "bus", source) lv_bus = pp.get_element_index(net, "bus", target) pp.create_transformer( net, name=self.name, hv_bus=hv_bus, lv_bus=lv_bus, std_type=self.std_type, parallel=self.parallel, )
def create_controllers(net, ds): load1= pp.get_element_index(net, "load", 'load1') sgen1 = pp.get_element_index(net, "sgen", 'sgen1') ConstControl(net, element='load', variable='p_mw', element_index=[load1], data_source=ds, profile_name=["load1_p"]) ConstControl(net, element='sgen', variable='p_mw', element_index=[sgen1], data_source=ds, profile_name=["sgen1_p"]) return net
def create_pp_transfomer(self, trafo): hv_bus = pp.get_element_index( self.net, "bus", trafo["connections"][0]['connectivityNodeId']) lv_bus = pp.get_element_index( self.net, "bus", trafo["connections"][1]['connectivityNodeId']) pp.create_transformer(self.net, hv_bus=hv_bus, lv_bus=lv_bus, std_type="0.4 MVA 20/0.4 kV")
def create_pp_lines(self): conductors = self.assets_df[self.assets_df['type'] == "Conductor"] for _, conductor in conductors.iterrows(): from_cn_id = conductor["connections"][0]['connectivityNodeId'] to_cn_id = conductor["connections"][1]['connectivityNodeId'] from_bus = pp.get_element_index(self.net, "bus", from_cn_id) to_bus = pp.get_element_index(self.net, "bus", to_cn_id) length = conductor["length"] if length == 0: length = self.min_line_length_km line_name = from_cn_id + "-" + to_cn_id pp.create_line(net=self.net, name=line_name, from_bus=from_bus, to_bus=to_bus, length_km=length, std_type="NAYY 4x50 SE") return self.net.line
def add_transformer( self, net, name, hv_bus_id, lv_bus_id, type ): lv_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[lv_bus_id] ) hv_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[hv_bus_id] ) pp.create_transformer( net = net, hv_bus = hv_bus, lv_bus = lv_bus, std_type = type, name = name )
def add_switch( self, net, name, from_bus_id, to_bus_id, type ): from_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[from_bus_id] ) to_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[to_bus_id] ) pp.create_switch( net = net, bus = from_bus, element = to_bus, et = 'b', closed = True, type = type, name = name )
def line_discon_low(net, n_time_steps, output_dir): _net = net index_line_5_6 = pp.get_element_index(_net, 'line', 'Line 5 to 6') _net.line.in_service[index_line_5_6] = False profiles, ds = create_data_source(_net, mode='Low Load', n_timesteps=n_time_steps) _net = create_controllers(_net, ds) time_steps = range(0, n_time_steps) ow = create_output_writer(_net, time_steps, output_dir) run_timeseries(_net, time_steps, calculate_voltage_angles=True) _net.line.in_service[index_line_5_6] = True
def add_ext_grid( self, net, name, bus_id ): bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[bus_id] ) pp.create_ext_grid( net = net, bus = bus, name = name )
def add_line( self, net, name, from_bus_id, to_bus_id, type, c_nf_per_km, r_ohm_per_km, x_ohm_per_km, max_i_ka, length_km, geodata ): from_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[from_bus_id] ) to_bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[to_bus_id] ) line_geodata = [ [ c.x, c.y ] for c in geodata ] line_type = None if type == 'cable': line_type = 'cs' elif type == 'line': line_type = 'ol' else: warnings.warn( 'unknown line type: {}'.format( type ), RuntimeWarning ) pp.create_line_from_parameters( net = net, from_bus = from_bus, to_bus = to_bus, length_km = length_km, type = line_type, c_nf_per_km = c_nf_per_km, r_ohm_per_km = r_ohm_per_km, x_ohm_per_km = x_ohm_per_km, max_i_ka = max_i_ka, name = name, geodata = line_geodata )
def add_load( self, net, name, bus_id, p_kw, q_kvar ): bus = pp.get_element_index( net, 'bus', self.bus_ids_and_names[bus_id] ) pp.create_load( net = net, bus = bus, p_kw = p_kw, q_kvar = q_kvar, name = name )
def update_pandapower( self, net: pandapowerNet, name: str, bus: str, ): """Update a pandapower model by adding the transformer itself. Args: net: a pandapower network model. name: name of the external grid. bus: the bus to which the external grid is attached. """ bus_idx = pp.get_element_index(net, "bus", bus) pp.create_ext_grid(net, name=name, bus=bus_idx)
def update_pandapower( self, net: pandapowerNet, name: str, bus: str, ): """Update a pandapower model by adding the capacitor itself. Args: net: a pandapower network model. name: name of the external grid. bus: the bus to which the external grid is attached. """ bus_idx = pp.get_element_index(net, "bus", bus) pp.create_shunt_as_capacitor( net, name=name, bus=bus_idx, q_mvar=self.q_mvar, loss_factor=self.loss_factor, )
def update_pandapower( self, net: pandapowerNet, name: str, bus: str, ): """Update a pandapower model by adding the ejection itself. Note: When the value of ``p_mw`` is negative, a generator without voltage control ability is added. Args: net: a pandapower network model. name: name of the external grid. bus: the bus to which the external grid is attached. """ bus_idx = pp.get_element_index(net, "bus", bus) if self.p_mw > 0: pp.create_load( net, name=name, bus=bus_idx, p_mw=self.p_mw, q_mvar=self.q_mvar, const_i_percent=0, const_z_percent=0, in_service=True, ) elif self.p_mw < 0: pp.create_sgen( net, name=name, bus=bus_idx, p_mw=self.p_mw, q_mvar=self.q_mvar, )
def build_pandapower(self, ac_line_segment_list_topology, busbar_section_list_topology, power_transformer_list_topology, synchronous_machine_list_topology, shunt_compensator_list_topology, energy_consumer_list_topology, breaker_list_topology): # Create buses in pandapower network from the internal data structure for bb_top in busbar_section_list_topology: pp.create_bus(self.net, bb_top.u_nom_kv, name=bb_top.name) # Create lines in pandapower network from the internal data structure for al_top in ac_line_segment_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == al_top.bus_1_id: from_bus = pp.get_element_index(self.net, 'bus', bb_top.name) if bb_top.id_ == al_top.bus_2_id: to_bus = pp.get_element_index(self.net, 'bus', bb_top.name) pp.create_line_from_parameters(self.net, from_bus, to_bus, al_top.length_km, al_top.r_ohm, al_top.x_ohm, 0.0, al_top.i_max_ka, name=al_top.name) # Create transformers in pandapower network from the internal data structure for tr_top in power_transformer_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == tr_top.bus_hv_id: hv_bus = pp.get_element_index(self.net, 'bus', bb_top.name) for bb_top in busbar_section_list_topology: if bb_top.id_ == tr_top.bus_lv_id: lv_bus = pp.get_element_index(self.net, 'bus', bb_top.name) # From the transformer documentation power_transformer_z = (tr_top.r**2 + tr_top.x**2)**0.5 power_transformer_vsc = 100 * power_transformer_z * tr_top.s_nom_mva power_transformer_vscr = 100 * tr_top.r * tr_top.s_nom_mva # Neglect the iron losses if ('hv_bus' or 'lv_bus') in locals(): pp.create_transformer_from_parameters(self.net, hv_bus, lv_bus, tr_top.s_nom_mva, tr_top.hv_nom_kv, tr_top.lv_nom_kv, power_transformer_vscr, power_transformer_vsc, 0, 0, name=tr_top.name) del hv_bus del lv_bus # Create generators in pandapower network from the internal data structure for sm_top in synchronous_machine_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == sm_top.bus_id: sm_bus = pp.get_element_index(self.net, 'bus', bb_top.name) pp.create_gen(self.net, sm_bus, sm_top.p_rated, name=sm_top.name) # Create shunt in pandapower network from the internal data structure for sh_top in shunt_compensator_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == sh_top.bus_id: sh_bus = pp.get_element_index(self.net, 'bus', bb_top.name) pp.create_shunt(self.net, sh_bus, sh_top.q_rated_mvar, vn_kv=sh_top.u_nom_kv, name=sh_top.name) # Create loads in pandapower network from the internal data structure for ec_top in energy_consumer_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == ec_top.bus_id: ec_bus = pp.get_element_index(self.net, 'bus', bb_top.name) pp.create_load(self.net, ec_bus, ec_top.p, ec_top.q, name=ec_top.name) # Comment this part if the extended XML files are used # Create switches for br_top in breaker_list_topology: for bb_top in busbar_section_list_topology: if bb_top.id_ == br_top.bus_id: br_bb = pp.get_element_index(self.net, 'bus', bb_top.name) for al_top in ac_line_segment_list_topology: if al_top.id_ == br_top.element_id: br_el = pp.get_element_index( self.net, 'line', al_top.name) pp.create_switch(self.net, br_bb, br_el, et='l', name=br_top.name) for tr_top in power_transformer_list_topology: if tr_top.id_ == br_top.element_id: br_el = pp.get_element_index( self.net, 'trafo', tr_top.name) pp.create_switch(self.net, br_bb, br_el, et='t', name=br_top.name) print('Pandapower network has been created')
def toogle_capacitor_status(self, capSwitchName): switchIndex = pp.get_element_index(self.power_grid, "switch", capSwitchName) currentState = self.power_grid.switch.closed.loc[switchIndex] self.power_grid.switch.closed.loc[switchIndex] = not currentState
def change_capacitor_status(self, capSwitchName, closed): switchIndex = pp.get_element_index(self.power_grid, "switch", capSwitchName) self.power_grid.switch.closed.loc[switchIndex] = closed
def from_ppc(ppc, f_hz=50, validate_conversion=False, **kwargs): """ This function converts pypower case files to pandapower net structure. INPUT: **ppc** : The pypower case file. OPTIONAL: **f_hz** (float, 50) - The frequency of the network. **validate_conversion** (bool, False) - If True, validate_from_ppc is run after conversion. For running the validation, the ppc must already contain the pypower powerflow results or pypower must be importable. ****kwargs** keyword arguments for validate_from_ppc if validate_conversion is True OUTPUT: **net** : pandapower net. EXAMPLE: import pandapower.converter as pc from pypower import case4gs ppc_net = case4gs.case4gs() net = pc.from_ppc(ppc_net, f_hz=60) """ # --- catch common failures if Series(ppc['bus'][:, BASE_KV] <= 0).any(): logger.info('There are false baseKV given in the pypower case file.') # --- general_parameters baseMVA = ppc['baseMVA'] # MVA omega = pi * f_hz # 1/s MAX_VAL = 99999. net = pp.create_empty_network(f_hz=f_hz, sn_mva=baseMVA) # --- bus data -> create buses, sgen, load, shunt for i in range(len(ppc['bus'])): # create buses pp.create_bus(net, name=int(ppc['bus'][i, 0]), vn_kv=ppc['bus'][i, 9], type="b", zone=ppc['bus'][i, 6], in_service=bool(ppc['bus'][i, 1] != 4), max_vm_pu=ppc['bus'][i, 11], min_vm_pu=ppc['bus'][i, 12]) # create sgen, load if ppc['bus'][i, 2] > 0: pp.create_load(net, i, p_mw=ppc['bus'][i, 2], q_mvar=ppc['bus'][i, 3], controllable=False) elif ppc['bus'][i, 2] < 0: pp.create_sgen(net, i, p_mw=-ppc['bus'][i, 2], q_mvar=-ppc['bus'][i, 3], type="", controllable=False) elif ppc['bus'][i, 3] != 0: pp.create_load(net, i, p_mw=ppc['bus'][i, 2], q_mvar=ppc['bus'][i, 3], controllable=False) # create shunt if ppc['bus'][i, 4] != 0 or ppc['bus'][i, 5] != 0: pp.create_shunt(net, i, p_mw=ppc['bus'][i, 4], q_mvar=-ppc['bus'][i, 5]) # unused data of ppc: Vm, Va (partwise: in ext_grid), zone # --- gen data -> create ext_grid, gen, sgen gen_lookup = DataFrame(nan, columns=['element', 'element_type'], index=range(len(ppc['gen'][:, 0]))) # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array if len(ppc["gen"].shape) == 1: ppc["gen"] = array(ppc["gen"], ndmin=2) for i in range(len(ppc['gen'][:, 0])): current_bus_type, current_bus_idx, same_bus_gen_idx, first_same_bus_in_service_gen_idx, \ last_same_bus_in_service_gen_idx = _gen_bus_info(ppc, i) # create ext_grid if current_bus_type == 3: if i == first_same_bus_in_service_gen_idx: gen_lookup.element.loc[i] = pp.create_ext_grid( net, bus=current_bus_idx, vm_pu=ppc['gen'][last_same_bus_in_service_gen_idx, 5], va_degree=ppc['bus'][current_bus_idx, 8], in_service=bool(ppc['gen'][i, 7] > 0), max_p_mw=ppc['gen'][i, PMAX], min_p_mw=ppc['gen'][i, PMIN], max_q_mvar=ppc['gen'][i, QMAX], min_q_mvar=ppc['gen'][i, QMIN]) gen_lookup.element_type.loc[i] = 'ext_grid' if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_mvar of gen %d must be less than max_q_mvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_mw of gen %d must be less than min_p_mw but is not.' % i) else: current_bus_type = 1 # create gen elif current_bus_type == 2: if i == first_same_bus_in_service_gen_idx: gen_lookup.element.loc[i] = pp.create_gen( net, bus=current_bus_idx, vm_pu=ppc['gen'][last_same_bus_in_service_gen_idx, 5], p_mw=ppc['gen'][i, 1], in_service=bool(ppc['gen'][i, 7] > 0), controllable=True, max_p_mw=ppc['gen'][i, PMAX], min_p_mw=ppc['gen'][i, PMIN], max_q_mvar=ppc['gen'][i, QMAX], min_q_mvar=ppc['gen'][i, QMIN]) gen_lookup.element_type.loc[i] = 'gen' if ppc['gen'][i, 1] < 0: logger.info( 'p_mw of gen %d must be less than zero but is not.' % i) if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_mvar of gen %d must be less than max_q_mvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_mw of gen %d must be less than min_p_mw but is not.' % i) else: current_bus_type = 1 # create sgen if current_bus_type == 1: gen_lookup.element.loc[i] = pp.create_sgen( net, bus=current_bus_idx, p_mw=ppc['gen'][i, 1], q_mvar=ppc['gen'][i, 2], type="", in_service=bool(ppc['gen'][i, 7] > 0), max_p_mw=ppc['gen'][i, PMAX], min_p_mw=ppc['gen'][i, PMIN], max_q_mvar=ppc['gen'][i, QMAX], min_q_mvar=ppc['gen'][i, QMIN], controllable=True) gen_lookup.element_type.loc[i] = 'sgen' if ppc['gen'][i, 1] < 0: logger.info( 'p_mw of sgen %d must be less than zero but is not.' % i) if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_mvar of gen %d must be less than max_q_mvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_mw of gen %d must be less than min_p_mw but is not.' % i) # unused data of ppc: Vg (partwise: in ext_grid and gen), mBase, Pc1, Pc2, Qc1min, Qc1max, # Qc2min, Qc2max, ramp_agc, ramp_10, ramp_30,ramp_q, apf # --- branch data -> create line, trafo for i in range(len(ppc['branch'])): from_bus = pp.get_element_index(net, 'bus', name=int(ppc['branch'][i, 0])) to_bus = pp.get_element_index(net, 'bus', name=int(ppc['branch'][i, 1])) from_vn_kv = ppc['bus'][from_bus, 9] to_vn_kv = ppc['bus'][to_bus, 9] if (from_vn_kv == to_vn_kv) & ((ppc['branch'][i, 8] == 0) | (ppc['branch'][i, 8] == 1)) & \ (ppc['branch'][i, 9] == 0): # create line Zni = ppc['bus'][to_bus, 9]**2 / baseMVA # ohm max_i_ka = ppc['branch'][i, 5] / ppc['bus'][to_bus, 9] / sqrt(3) if max_i_ka == 0.0: max_i_ka = MAX_VAL logger.debug( "ppc branch rateA is zero -> Using MAX_VAL instead to calculate " + "maximum branch flow") pp.create_line_from_parameters( net, from_bus=from_bus, to_bus=to_bus, length_km=1, r_ohm_per_km=ppc['branch'][i, 2] * Zni, x_ohm_per_km=ppc['branch'][i, 3] * Zni, c_nf_per_km=ppc['branch'][i, 4] / Zni / omega * 1e9 / 2, max_i_ka=max_i_ka, type='ol', max_loading_percent=100, in_service=bool(ppc['branch'][i, 10])) else: # create transformer if from_vn_kv >= to_vn_kv: hv_bus = from_bus vn_hv_kv = from_vn_kv lv_bus = to_bus vn_lv_kv = to_vn_kv tap_side = 'hv' else: hv_bus = to_bus vn_hv_kv = to_vn_kv lv_bus = from_bus vn_lv_kv = from_vn_kv tap_side = 'lv' if from_vn_kv == to_vn_kv: logger.warning( 'The pypower branch %d (from_bus, to_bus)=(%d, %d) is considered' ' as a transformer because of a ratio != 0 | 1 but it connects ' 'the same voltage level', i, ppc['branch'][i, 0], ppc['branch'][i, 1]) rk = ppc['branch'][i, 2] xk = ppc['branch'][i, 3] zk = (rk**2 + xk**2)**0.5 sn = ppc['branch'][i, 5] if sn == 0.0: sn = MAX_VAL logger.debug( "ppc branch rateA is zero -> Using MAX_VAL instead to calculate " + "apparent power") ratio_1 = 0 if ppc['branch'][i, 8] == 0 else (ppc['branch'][i, 8] - 1) * 100 i0_percent = -ppc['branch'][i, 4] * 100 * baseMVA / sn if i0_percent < 0: logger.info( 'A transformer always behaves inductive consumpting but the ' 'susceptance of pypower branch %d (from_bus, to_bus)=(%d, %d) is ' 'positive.', i, ppc['branch'][i, 0], ppc['branch'][i, 1]) pp.create_transformer_from_parameters( net, hv_bus=hv_bus, lv_bus=lv_bus, sn_mva=sn, vn_hv_kv=vn_hv_kv, vn_lv_kv=vn_lv_kv, vk_percent=sign(xk) * zk * sn * 100 / baseMVA, vkr_percent=rk * sn * 100 / baseMVA, max_loading_percent=100, pfe_kw=0, i0_percent=i0_percent, shift_degree=ppc['branch'][i, 9], tap_step_percent=abs(ratio_1) if ratio_1 else nan, tap_pos=sign(ratio_1) if ratio_1 else nan, tap_side=tap_side if ratio_1 else None, tap_neutral=0 if ratio_1 else nan) # unused data of ppc: rateB, rateC # --- gencost -> create polynomial_cost, piecewise_cost if 'gencost' in ppc: if len(ppc['gencost'].shape) == 1: # reshape gencost if only one gencost is given -> no indexError ppc['gencost'] = ppc['gencost'].reshape((1, -1)) if ppc['gencost'].shape[0] <= gen_lookup.shape[0]: idx_p = range(ppc['gencost'].shape[0]) idx_q = [] elif ppc['gencost'].shape[0] > gen_lookup.shape[0]: idx_p = range(gen_lookup.shape[0]) idx_q = range(gen_lookup.shape[0], ppc['gencost'].shape[0]) if ppc['gencost'].shape[0] >= 2 * gen_lookup.shape[0]: idx_p = range(gen_lookup.shape[0]) idx_q = range(gen_lookup.shape[0], 2 * gen_lookup.shape[0]) for idx in idx_p: _create_costs(net, ppc, gen_lookup, 'p', idx) for idx in idx_q: _create_costs(net, ppc, gen_lookup, 'q', idx) # areas are unconverted if validate_conversion: logger.setLevel(logging.DEBUG) if not validate_from_ppc(ppc, net, **kwargs): logger.error("Validation failed.") return net
def validate_from_ppc( ppc_net, net, pf_type="runpp", max_diff_values={ "bus_vm_pu": 1e-6, "bus_va_degree": 1e-5, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6, "gen_p_mw": 1e-6, "gen_q_mvar": 1e-6 }, run=True): """ This function validates the pypower case files to pandapower net structure conversion via a \ comparison of loadflow calculation results. (Hence the opf cost conversion is not validated.) INPUT: **ppc_net** - The pypower case file, which must already contain the pypower powerflow results or pypower must be importable. **net** - The pandapower network. OPTIONAL: **pf_type** ("runpp", string) - Type of validated power flow. Possible are ("runpp", "rundcpp", "runopp", "rundcopp") **max_diff_values** - Dict of maximal allowed difference values. The keys must be 'vm_pu', 'va_degree', 'p_branch_mw', 'q_branch_mvar', 'p_gen_mw' and 'q_gen_mvar' and the values floats. **run** (True, bool or list of two bools) - changing the value to False avoids trying to run (optimal) loadflows. Giving a list of two bools addresses first pypower and second pandapower. OUTPUT: **conversion_success** - conversion_success is returned as False if pypower or pandapower cannot calculate a powerflow or if the maximum difference values (max_diff_values ) cannot be hold. EXAMPLE: import pandapower.converter as pc net = cv.from_ppc(ppc_net, f_hz=50) conversion_success = cv.validate_from_ppc(ppc_net, net) NOTE: The user has to take care that the loadflow results already are included in the provided \ ppc_net or pypower is importable. """ # check in case of optimal powerflow comparison whether cost information exist if "opp" in pf_type: if not (len(net.polynomial_cost) | len(net.piecewise_linear_cost)): if "gencost" in ppc_net: if not len(ppc_net["gencost"]): logger.debug( 'ppc and pandapower net do not include cost information.' ) return True else: logger.error( 'The pandapower net does not include cost information.' ) return False else: logger.debug( 'ppc and pandapower net do not include cost information.') return True # guarantee run parameter as list, for pypower and pandapower (optimal) powerflow run run = [run, run] if isinstance(run, bool) else run # --- check pypower powerflow success, if possible if pypower_import and run[0]: try: if pf_type == "runpp": ppc_net = runpf.runpf(ppc_net, ppopt)[0] elif pf_type == "rundcpp": ppc_net = rundcpf.rundcpf(ppc_net, ppopt)[0] elif pf_type == "runopp": ppc_net = runopf.runopf(ppc_net, ppopt) elif pf_type == "rundcopp": ppc_net = rundcopf.rundcopf(ppc_net, ppopt) else: raise ValueError("The pf_type %s is unknown" % pf_type) except: logger.debug("The pypower run did not work.") ppc_success = True if 'success' in ppc_net.keys(): if ppc_net['success'] != 1: ppc_success = False logger.error( "The given ppc data indicates an unsuccessful pypower powerflow: " + "'ppc_net['success'] != 1'") if (ppc_net['branch'].shape[1] < 17): ppc_success = False logger.error( "The shape of given ppc data indicates missing pypower powerflow results." ) # --- try to run a pandapower powerflow if run[1]: if pf_type == "runpp": try: pp.runpp(net, init="dc", calculate_voltage_angles=True, trafo_model="pi") except pp.LoadflowNotConverged: try: pp.runpp(net, calculate_voltage_angles=True, init="flat", trafo_model="pi") except pp.LoadflowNotConverged: try: pp.runpp(net, trafo_model="pi", calculate_voltage_angles=False) if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] logger.info("voltage_angles could be calculated.") except pp.LoadflowNotConverged: logger.error( 'The pandapower powerflow does not converge.') elif pf_type == "rundcpp": try: pp.rundcpp(net, trafo_model="pi") except pp.LoadflowNotConverged: logger.error('The pandapower dc powerflow does not converge.') elif pf_type == "runopp": try: pp.runopp(net, init="flat", calculate_voltage_angles=True) except pp.OPFNotConverged: try: pp.runopp(net, init="pf", calculate_voltage_angles=True) except (pp.OPFNotConverged, pp.LoadflowNotConverged, KeyError): try: pp.runopp(net, init="flat", calculate_voltage_angles=False) logger.info("voltage_angles could be calculated.") if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] except pp.OPFNotConverged: try: pp.runopp(net, init="pf", calculate_voltage_angles=False) if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] logger.info("voltage_angles could be calculated.") except (pp.OPFNotConverged, pp.LoadflowNotConverged, KeyError): logger.error( 'The pandapower optimal powerflow does not converge.' ) elif pf_type == "rundcopp": try: pp.rundcopp(net) except pp.LoadflowNotConverged: logger.error( 'The pandapower dc optimal powerflow does not converge.') else: raise ValueError("The pf_type %s is unknown" % pf_type) # --- prepare powerflow result comparison by reordering pp results as they are in ppc results if not ppc_success: return False if "opp" in pf_type: if not net.OPF_converged: return elif not net.converged: return False # --- store pypower powerflow results ppc_res = dict.fromkeys(ppc_elms) ppc_res["branch"] = ppc_net['branch'][:, 13:17] ppc_res["bus"] = ppc_net['bus'][:, 7:9] ppc_res["gen"] = ppc_net['gen'][:, 1:3] # --- pandapower bus result table pp_res = dict.fromkeys(ppc_elms) pp_res["bus"] = array(net.res_bus.sort_index()[['vm_pu', 'va_degree']]) # --- pandapower gen result table pp_res["gen"] = zeros([1, 2]) # consideration of parallel generators via storing how much generators have been considered # each node # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array if len(ppc_net["gen"].shape) == 1: ppc_net["gen"] = array(ppc_net["gen"], ndmin=2) GENS = DataFrame(ppc_net['gen'][:, [0]].astype(int)) GEN_uniq = GENS.drop_duplicates() already_used_gen = Series(zeros(GEN_uniq.shape[0]).astype(int), index=[int(v) for v in GEN_uniq.values]) change_q_compare = [] for i, j in GENS.iterrows(): current_bus_type, current_bus_idx, same_bus_gen_idx, first_same_bus_in_service_gen_idx, \ last_same_bus_in_service_gen_idx = _gen_bus_info(ppc_net, i) if current_bus_type == 3 and i == first_same_bus_in_service_gen_idx: pp_res["gen"] = append( pp_res["gen"], array(net.res_ext_grid[net.ext_grid.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]]).reshape((1, 2)), 0) elif current_bus_type == 2 and i == first_same_bus_in_service_gen_idx: pp_res["gen"] = append( pp_res["gen"], array(net.res_gen[net.gen.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]]).reshape((1, 2)), 0) else: pp_res["gen"] = append( pp_res["gen"], array(net.res_sgen[net.sgen.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]])[already_used_gen.at[int(j)]].reshape((1, 2)), 0) already_used_gen.at[int(j)] += 1 change_q_compare += [int(j)] pp_res["gen"] = pp_res["gen"][1:, :] # delete initial zero row # --- pandapower branch result table pp_res["branch"] = zeros([1, 4]) # consideration of parallel branches via storing how often branches were considered # each node-to-node-connection try: init1 = concat([net.line.from_bus, net.line.to_bus], axis=1, sort=True).drop_duplicates() init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1, sort=True).drop_duplicates() except TypeError: # legacy pandas < 0.21 init1 = concat([net.line.from_bus, net.line.to_bus], axis=1).drop_duplicates() init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1).drop_duplicates() init1['hv_bus'] = nan init1['lv_bus'] = nan init2['from_bus'] = nan init2['to_bus'] = nan try: already_used_branches = concat([init1, init2], axis=0, sort=True) except TypeError: # pandas < 0.21 legacy already_used_branches = concat([init1, init2], axis=0) already_used_branches['number'] = zeros( [already_used_branches.shape[0], 1]).astype(int) BRANCHES = DataFrame(ppc_net['branch'][:, [0, 1, 8, 9]]) for i in BRANCHES.index: from_bus = pp.get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 0])) to_bus = pp.get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 1])) from_vn_kv = ppc_net['bus'][from_bus, 9] to_vn_kv = ppc_net['bus'][to_bus, 9] ratio = BRANCHES[2].at[i] angle = BRANCHES[3].at[i] # from line results if (from_vn_kv == to_vn_kv) & ((ratio == 0) | (ratio == 1)) & (angle == 0): pp_res["branch"] = append( pp_res["branch"], array(net.res_line[(net.line.from_bus == from_bus) & (net.line.to_bus == to_bus)][[ 'p_from_mw', 'q_from_mvar', 'p_to_mw', 'q_to_mvar' ]]) [int(already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)].values)].reshape( 1, 4), 0) already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)] += 1 # from trafo results else: if from_vn_kv >= to_vn_kv: pp_res["branch"] = append( pp_res["branch"], array(net.res_trafo[(net.trafo.hv_bus == from_bus) & (net.trafo.lv_bus == to_bus)] [['p_hv_mw', 'q_hv_mvar', 'p_lv_mw', 'q_lv_mvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)] += 1 else: # switch hv-lv-connection of pypower connection buses pp_res["branch"] = append( pp_res["branch"], array(net.res_trafo[(net.trafo.hv_bus == to_bus) & (net.trafo.lv_bus == from_bus)] [['p_lv_mw', 'q_lv_mvar', 'p_hv_mw', 'q_hv_mvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)] += 1 pp_res["branch"] = pp_res["branch"][1:, :] # delete initial zero row # --- do the powerflow result comparison diff_res = dict.fromkeys(ppc_elms) diff_res["bus"] = ppc_res["bus"] - pp_res["bus"] diff_res["bus"][:, 1] -= diff_res["bus"][0, 1] # remove va_degree offset diff_res["branch"] = ppc_res["branch"] - pp_res["branch"] diff_res["gen"] = ppc_res["gen"] - pp_res["gen"] # comparison of buses with several generator units only as q sum for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index: next_is = GEN_uniq.index[GEN_uniq.index > i] if len(next_is) > 0: next_i = next_is[0] else: next_i = GENS.index[-1] + 1 if (next_i - i) > 1: diff_res["gen"][i:next_i, 1] = sum(diff_res["gen"][i:next_i, 1]) # logger info logger.debug( "Maximum voltage magnitude difference between pypower and pandapower: " "%.2e pu" % max_(abs(diff_res["bus"][:, 0]))) logger.debug( "Maximum voltage angle difference between pypower and pandapower: " "%.2e degree" % max_(abs(diff_res["bus"][:, 1]))) logger.debug( "Maximum branch flow active power difference between pypower and pandapower: " "%.2e MW" % max_(abs(diff_res["branch"][:, [0, 2]]))) logger.debug( "Maximum branch flow reactive power difference between pypower and " "pandapower: %.2e MVAr" % max_(abs(diff_res["branch"][:, [1, 3]]))) logger.debug( "Maximum active power generation difference between pypower and pandapower: " "%.2e MW" % max_(abs(diff_res["gen"][:, 0]))) logger.debug( "Maximum reactive power generation difference between pypower and pandapower: " "%.2e MVAr" % max_(abs(diff_res["gen"][:, 1]))) if _validate_diff_res(diff_res, {"bus_vm_pu": 1e-3, "bus_va_degree": 1e-3, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6}) and \ (max_(abs(diff_res["gen"])) > 1e-1).any(): logger.debug( "The active/reactive power generation difference possibly results " "because of a pypower error. Please validate " "the results via pypower loadflow." ) # this occurs e.g. at ppc case9 # give a return if isinstance(max_diff_values, dict): return _validate_diff_res(diff_res, max_diff_values) else: logger.debug("'max_diff_values' must be a dict.")
def execute_my_script(EQ_file, SSH_file): #Next step is to create a tree by parsing the XML file referenced # We are here using ENTSO-E model files used in Interoperability testing EQ_tree = ET.parse(EQ_file) SSH_tree = ET.parse(SSH_file) # We can access the root (raiz) of the tree and print it EQ_microgrid = EQ_tree.getroot() SSH_microgrid = SSH_tree.getroot() # To make working with the file easier, it may be useful to store the # namespace identifiers in strings and reuse when you search for tags ns = {'cim':'http://iec.ch/TC57/2013/CIM-schema-cim16#', 'entsoe':'http://entsoe.eu/CIM/SchemaExtension/3/1#', 'rdf':'{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'} #create an empty network net = pp.create_empty_network() #to see al the elements in our system: EQ_tag=[] for eq in EQ_microgrid: if (ns['cim'] in eq.tag): equipment = eq.tag.replace("{"+ns['cim']+"}","") if equipment not in EQ_tag : EQ_tag.append(equipment) print(EQ_tag) print("---------------------------------------------------------") # My goal here it's to create a dictionary that links voltage level with their respective ID # I want to to avoid repetition in the loop when finding the match voltage level of the equipment voltage_levels_dic = {} for voltage_level in EQ_microgrid.findall('cim:VoltageLevel', ns): voltage_name = float(voltage_level.find('cim:IdentifiedObject.name', ns).text) voltage_levels_dic[voltage_level.attrib.get(ns['rdf']+'ID')] = voltage_name print(voltage_levels_dic) # Create buses in the pandapower system from the XML file data adquired for bus in EQ_microgrid.findall('cim:BusbarSection', ns): # Extracting the name from the BusbarSection element bus_name = bus.find('cim:IdentifiedObject.name', ns).text # I the next line of code we want to obtain the Equipment.EquipmentContainer ID of each busbar section and take with it the corresponding bus # voltage level relation that we have previously determined in the dictionary bus_voltage_level = voltage_levels_dic[bus.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '')] pp.create_bus(net, bus_voltage_level, name=bus_name) print(net.bus) print("---------------------------------------------------------") # Create lines in the pandapower system from the XML file data adquired for line in EQ_microgrid.findall('cim:ACLineSegment', ns): #I want to get the ID of each line line_id = line.attrib.get(ns['rdf'] + 'ID') print (line_id) # next step will be retrieving the name of the line line_name = line.find('cim:IdentifiedObject.name', ns).text print (line_name) # Now I want to get the length of the line line_length = float(line.find('cim:Conductor.length', ns).text) print (line_length) # get the resistance of the line line_resistance_per_km = float(line.find('cim:ACLineSegment.r', ns).text)/line_length # get the reactance of the line line_rectance_per_km = float(line.find('cim:ACLineSegment.x', ns).text)/line_length # I want to find the ID of the terminals where the line is connected to # Basically we want to know to wich 2 terminals each line is connected to in order to later define # from/to which buses the lines are connected to for terminal in EQ_microgrid.findall('cim:Terminal', ns): line_Te_CE = terminal.find('cim:Terminal.ConductingEquipment', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') line_sequence_number = terminal.find('cim:ACDCTerminal.sequenceNumber', ns).text if line_id == line_Te_CE: # We do this in order to select the terminals related to the lines if line_sequence_number == '1': #This is because for each line we have 2 terminals, the one with sequence number 1 and the other with seq number 2 # Gets the connectivity node ID from the terminals line_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == line_Te_CN: CN_id = CN.attrib.get(ns['rdf'] + 'ID') CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: Line_Te1 = BusBar.find('cim:IdentifiedObject.name', ns).text elif line_sequence_number == '2': # Gets the connectivity node ID from the terminals line_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == line_Te_CN: CN_id = CN.attrib.get(ns['rdf'] + 'ID') CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: Line_Te2 = BusBar.find('cim:IdentifiedObject.name', ns).text Line_from_Bus = pp.get_element_index(net, "bus", Line_Te1) Line_to_Bus = pp.get_element_index(net, "bus", Line_Te2) pp.create_line(net, Line_from_Bus, Line_to_Bus, length_km=line_length,std_type='NAYY 4x50 SE', name=line_name)# parallel=hv_line.parallel) # show line table print(net.line) print("---------------------------------------------------------") # Create transformers in the pandapower system from the XML file data adquired for transformers in EQ_microgrid.findall('cim:PowerTransformer', ns): #I want to get the ID of each transformer transformer_id = transformers.attrib.get(ns['rdf'] + 'ID') # next step will be retrieving the name of the transformer transformers_name = transformers.find('cim:IdentifiedObject.name', ns).text print(transformers_name) # I want to find the ID of the terminals where the transformer is connected to for transformer_end in EQ_microgrid.findall('cim:PowerTransformerEnd', ns): transformer_end_id = transformer_end.find('cim:PowerTransformerEnd.PowerTransformer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # Find the side of the power transformer if transformer_id == transformer_end_id: transformer_end_number = transformer_end.find('cim:TransformerEnd.endNumber', ns).text # I want to find the value of the TransformerEnd.endNumber because it will give you the information about if # it is the HV(=1) or LV(=2) print(transformer_end_number) if transformer_end_number == '1': # As we did previously for the lines we use did if in order to create 2 paths, one will define the # parameters of HV side and the other the parameters of the LV side # I am taking the information of the transformer, Power rating of the transformer # The parameters are taking on the HV(=1) side because is where the data about r,x is stored at the XML file transformer_S = float(transformer_end.find('cim:PowerTransformerEnd.ratedS', ns).text) transformer_hv_kv = float(transformer_end.find('cim:PowerTransformerEnd.ratedU', ns).text) transformer_r = float(transformer_end.find('cim:PowerTransformerEnd.r', ns).text) transformer_x = float(transformer_end.find('cim:PowerTransformerEnd.x', ns).text) transformer_z = (transformer_r ** 2 + transformer_x ** 2) ** (1/2) # I am going to neglect the iron losses, the open loop losses, shift degree # Find the terminal the transformer end is connected to transformer_end_terminal = transformer_end.find('cim:TransformerEnd.Terminal', ns).attrib.get(ns['rdf'] + 'resource').replace('#','') for terminal in EQ_microgrid.findall('cim:Terminal', ns): terminal_id = terminal.attrib.get(ns['rdf'] + 'ID') if terminal_id == transformer_end_terminal: # Take the connectivity node's ID from the terminal transformer_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == line_Te_CN: transformer_CN_id = CN.attrib.get(ns['rdf'] + 'ID') transformer_CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: transformer_Te1 = BusBar.find('cim:IdentifiedObject.name', ns).text # Now we want to do the same for the LV side elif transformer_end_number == '2': transformer_lv_kv = float(transformer_end.find('cim:PowerTransformerEnd.ratedU', ns).text) # Find the terminal the transformer end is connected to transformer_end_terminal = transformer_end.find('cim:TransformerEnd.Terminal', ns).attrib.get(ns['rdf'] + 'resource').replace('#','') for terminal in EQ_microgrid.findall('cim:Terminal', ns): terminal_id = terminal.attrib.get(ns['rdf'] + 'ID') if terminal_id == transformer_end_terminal: # Take the connectivity node's ID from the terminal transformer_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == line_Te_CN: transformer_CN_id = CN.attrib.get(ns['rdf'] + 'ID') transformer_CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: transformer_Te2 = BusBar.find('cim:IdentifiedObject.name', ns).text hv_bus = pp.get_element_index(net, "bus", transformer_Te1) lv_bus = pp.get_element_index(net, "bus", transformer_Te2) pp.create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva=transformer_S, vn_hv_kv=transformer_hv_kv, vn_lv_kv=transformer_lv_kv, vkr_percent=0.06, vk_percent=8, pfe_kw=0, i0_percent=0, tp_pos=0, shift_degree=0, name=transformers_name) print(net.trafo) # show trafo table print("---------------------------------------------------------") # Create Loads in the pandapower system from the XML file (SSH) data adquired # In order to do this, firs we will take the name and ID of the loads from the EQ file, afterwards we will use this # Id that we have obtained before to look for its corresponding P & Q data stored in the SSH file for load in EQ_microgrid.findall('cim:EnergyConsumer', ns): #I want to get the ID of each load eq_load_id = load.attrib.get(ns['rdf'] + 'ID') # next step will be retrieving the name of the load load_name = load.find('cim:IdentifiedObject.name', ns).text print(load_name) for ssh_load in SSH_microgrid.findall('cim:EnergyConsumer', ns): ssh_load_id = ssh_load.attrib.get(ns['rdf'] + 'about').replace('#', '') print(ssh_load_id) if ssh_load_id == eq_load_id: P_load = float(ssh_load.find('cim:EnergyConsumer.p', ns).text) Q_load = float(ssh_load.find('cim:EnergyConsumer.q', ns).text) # After we got the P & Q for each load, now I want to find the terminal associated to each load (from the EQ file again) for terminal in EQ_microgrid.findall('cim:Terminal', ns): load_Te_CE = terminal.find('cim:Terminal.ConductingEquipment', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') if eq_load_id == load_Te_CE: # We do this in order to select the terminals related to the loads load_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == load_Te_CN: CN_id = CN.attrib.get(ns['rdf'] + 'ID') CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: Load_Te = BusBar.find('cim:IdentifiedObject.name', ns).text bus_idx = pp.get_element_index(net, "bus", Load_Te) pp.create_load(net, bus_idx, p_mw=P_load, q_mvar=Q_load, name=load_name) # show load table print(net.load) print("---------------------------------------------------------") # Create generators in pandapower, for generator in EQ_microgrid.findall('cim:GeneratingUnit', ns): generator_id = generator.attrib.get(ns['rdf'] + 'ID') generator_name = generator.find('cim:IdentifiedObject.name', ns).text generator_initial_P = float(generator.find('cim:GeneratingUnit.initialP', ns).text) # Looking for the SynchronousMachine related to the generator unit for synch_machine in EQ_microgrid.findall('cim:SynchronousMachine', ns): synch_machine_id = synch_machine.attrib.get(ns['rdf'] + 'ID') if synch_machine.find('cim:RotatingMachine.GeneratingUnit', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == generator_id: synch_machine_ratedU = float(synch_machine.find('cim:RotatingMachine.ratedU', ns).text) # print(synch_machine_ratedU) synch_machine_id = synch_machine.attrib.get(ns['rdf'] + 'ID') synch_machine_equip_cont = synch_machine.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): BusBar_equip_cont = BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') if BusBar_equip_cont == synch_machine_equip_cont: generator_busbar = BusBar.find('cim:IdentifiedObject.name', ns).text bus_voltage = voltage_levels_dic[BusBar_equip_cont] # print(bus_voltage) vm_pu = synch_machine_ratedU / bus_voltage print(vm_pu) pp.create_gen(net, pp.get_element_index(net, "bus", generator_busbar), generator_initial_P, vm_pu, name=generator_name) # vm_pu=1.0 this is because there is no extra info about vm_pu in the xml file. Thus, as the rated voltage # of the synch.machine is exactly the same as the bus which it is connected # Find the terminal the generator is connected to print(net.gen) print("---------------------------------------------------------") # Create shunt capacitors in pandapower. # To define shunt in pandapower we need: the bus that is connected to, p_mw=0, q_mvar, name. for shunt in EQ_microgrid.findall('cim:LinearShuntCompensator', ns): shunt_id = shunt.attrib.get(ns['rdf'] + 'ID') shunt_name = shunt.find('cim:IdentifiedObject.name', ns).text shunt_b = float(shunt.find('cim:LinearShuntCompensator.bPerSection', ns).text) shunt_nom_U = float(shunt.find('cim:ShuntCompensator.nomU', ns).text) # In a shunt capacitor, Q = b*(Unom^2) because g = 0 shunt_Q = shunt_b*(shunt_nom_U**2) shunt_equip_cont = shunt.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): BusBar_equip_cont = BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') if BusBar_equip_cont == shunt_equip_cont: shunt_busbar = BusBar.find('cim:IdentifiedObject.name', ns).text pp.create_shunt(net, pp.get_element_index(net, "bus", shunt_busbar), p_mw=0, q_mvar=shunt_Q, name=shunt_name) print(net.shunt) print("---------------------------------------------------------") # Create breakers in pandapower. for breaker in EQ_microgrid.findall('cim:Breaker', ns): breaker_id = breaker.attrib.get(ns['rdf'] + 'ID') breaker_name = breaker.find('cim:IdentifiedObject.name', ns).text breaker_position = breaker.find('cim:Switch.normalOpen', ns).text # Breaker position in the EQ.xml file determines if the sitch is open(=TRUE), but for pandapower # the parameteres examines if the switch is closed(=FALSE), thi is why we need to create # an if condition to readjust this as we want if breaker_position == 'false': breaker_position = True elif breaker_position == 'true': breaker_position = False # I want to find the ID of the terminals where the breaker is connected to # Basically we want to know to wich 2 terminals each breaker is connected to in order to later define # from/to which buses the breaker are connected to for terminal in EQ_microgrid.findall('cim:Terminal', ns): breaker_Te_CE = terminal.find('cim:Terminal.ConductingEquipment', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') breaker_sequence_number = terminal.find('cim:ACDCTerminal.sequenceNumber', ns).text if breaker_id == breaker_Te_CE: if breaker_sequence_number == '1': # Take the connectivity node's ID from the terminal breaker_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == breaker_Te_CN: CN_id = CN.attrib.get(ns['rdf'] + 'ID') CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: breaker_Te1 = BusBar.find('cim:IdentifiedObject.name', ns).text print(breaker_Te1) elif breaker_sequence_number == '2': # Gets the connectivity node ID from the terminals breaker_Te_CN = terminal.find('cim:Terminal.ConnectivityNode', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # With this new for loop the objective is to find the ConnectivityNode associaton, in other words # I want to obtain for each connectivitynode their corresponding id and container association for CN in EQ_microgrid.findall('cim:ConnectivityNode', ns): if CN.attrib.get(ns['rdf'] + 'ID') == line_Te_CN: CN_id = CN.attrib.get(ns['rdf'] + 'ID') CN_container = CN.find('cim:ConnectivityNode.ConnectivityNodeContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') # I want now to stablish a connection between the ConnectivityNode.ConnectivityNodeContainer # and the corresponding busbarsection for BusBar in EQ_microgrid.findall('cim:BusbarSection', ns): if BusBar.find('cim:Equipment.EquipmentContainer', ns).attrib.get(ns['rdf'] + 'resource').replace('#', '') == CN_container: breaker_Te2 = BusBar.find('cim:IdentifiedObject.name', ns).text print(breaker_Te2) print("---------------------------------------------------------") from_bus = pp.get_element_index(net, "bus", breaker_Te1) to_bus = pp.get_element_index(net, "bus", breaker_Te2) pp.create_switch(net, from_bus, to_bus, et='b', closed=breaker_position, type='CB', name=breaker_name) print(net.switch) plot.to_html(net, 'plot_system.html') #plot.simple_plot(net, respect_switches=False, line_width=1.0, bus_size=1.0, ext_grid_size=1.0, trafo_size=1.0, plot_loads=False, plot_sgens=False, load_size=1.0, sgen_size=1.0, switch_size=2.0, # switch_distance=1.0, plot_line_switches=False, scale_size=True, bus_color='b', line_color='grey', trafo_color='k', ext_grid_color='y', switch_color='k', library='igraph', show_plot=True, ax=None) #execute_my_script('MicroGridTestConfiguration_T1_BE_EQ_V2.xml', 'MicroGridTestConfiguration_T1_BE_SSH_V2.xml')
def from_ppc(ppc, f_hz=50, validate_conversion=False): """ This function converts pypower case files to pandapower net structure. INPUT: **ppc** - The pypower case file. OPTIONAL: **f_hz** - The frequency of the network. OUTPUT: **net** EXAMPLE: import pandapower.converter as pc from pypower import case4gs ppc_net = case4gs.case4gs() pp_net = cv.from_ppc(ppc_net, f_hz=60) """ # --- catch common failures if Series(ppc['bus'][:, 9] <= 0).any(): logger.info('There are false baseKV given in the pypower case file.') # --- general_parameters baseMVA = ppc['baseMVA'] # MVA omega = pi * f_hz # 1/s MAX_VAL = 99999. net = pp.create_empty_network(f_hz=f_hz) # --- bus data -> create buses, sgen, load, shunt for i in range(len(ppc['bus'])): # create buses pp.create_bus(net, name=int(ppc['bus'][i, 0]), vn_kv=ppc['bus'][i, 9], type="b", zone=ppc['bus'][i, 6], in_service=bool(ppc['bus'][i, 1] != 4), max_vm_pu=ppc['bus'][i, 11], min_vm_pu=ppc['bus'][i, 12]) # create sgen, load if ppc['bus'][i, 2] > 0: pp.create_load(net, i, p_kw=ppc['bus'][i, 2] * 1e3, q_kvar=ppc['bus'][i, 3] * 1e3) elif ppc['bus'][i, 2] < 0: pp.create_sgen(net, i, p_kw=ppc['bus'][i, 2] * 1e3, q_kvar=ppc['bus'][i, 3] * 1e3, type="") elif ppc['bus'][i, 3] != 0: pp.create_load(net, i, p_kw=ppc['bus'][i, 2] * 1e3, q_kvar=ppc['bus'][i, 3] * 1e3) # create shunt if ppc['bus'][i, 4] != 0 or ppc['bus'][i, 5] != 0: pp.create_shunt(net, i, p_kw=ppc['bus'][i, 4] * 1e3, q_kvar=-ppc['bus'][i, 5] * 1e3) # unused data of ppc: Vm, Va (partwise: in ext_grid), zone # --- gen data -> create ext_grid, gen, sgen for i in range(len(ppc['gen'])): # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array if len(ppc["gen"].shape) == 1: ppc["gen"] = array(ppc["gen"], ndmin=2) current_bus_idx = pp.get_element_index(net, 'bus', name=int(ppc['gen'][i, 0])) current_bus_type = int(ppc['bus'][current_bus_idx, 1]) # create ext_grid if current_bus_type == 3: if len(pp.get_connected_elements(net, 'ext_grid', current_bus_idx)) > 0: logger.info('At bus %d an ext_grid already exists. ' % current_bus_idx + 'Because of that generator %d ' % i + 'is converted not as an ext_grid but as a sgen') current_bus_type = 1 else: pp.create_ext_grid(net, bus=current_bus_idx, vm_pu=ppc['gen'][i, 5], va_degree=ppc['bus'][current_bus_idx, 8], in_service=bool(ppc['gen'][i, 7] > 0), max_p_kw=-ppc['gen'][i, 9] * 1e3, min_p_kw=-ppc['gen'][i, 8] * 1e3, max_q_kvar=ppc['gen'][i, 3] * 1e3, min_q_kvar=ppc['gen'][i, 4] * 1e3) if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_kvar of gen %d must be less than max_q_kvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_kw of gen %d must be less than min_p_kw but is not.' % i) # create gen elif current_bus_type == 2: pp.create_gen(net, bus=current_bus_idx, vm_pu=ppc['gen'][i, 5], p_kw=-ppc['gen'][i, 1] * 1e3, in_service=bool(ppc['gen'][i, 7] > 0), max_p_kw=-ppc['gen'][i, 9] * 1e3, min_p_kw=-ppc['gen'][i, 8] * 1e3, max_q_kvar=ppc['gen'][i, 3] * 1e3, min_q_kvar=ppc['gen'][i, 4] * 1e3, controllable=True) if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_kvar of gen %d must be less than max_q_kvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_kw of gen %d must be less than min_p_kw but is not.' % i) # create sgen if current_bus_type == 1: pp.create_sgen(net, bus=current_bus_idx, p_kw=-ppc['gen'][i, 1] * 1e3, q_kvar=-ppc['gen'][i, 2] * 1e3, type="", in_service=bool(ppc['gen'][i, 7] > 0), max_p_kw=-ppc['gen'][i, 9] * 1e3, min_p_kw=-ppc['gen'][i, 8] * 1e3, max_q_kvar=ppc['gen'][i, 3] * 1e3, min_q_kvar=ppc['gen'][i, 4] * 1e3, controllable=True) if ppc['gen'][i, 4] > ppc['gen'][i, 3]: logger.info( 'min_q_kvar of gen %d must be less than max_q_kvar but is not.' % i) if -ppc['gen'][i, 9] < -ppc['gen'][i, 8]: logger.info( 'max_p_kw of gen %d must be less than min_p_kw but is not.' % i) # unused data of ppc: Vg (partwise: in ext_grid and gen), mBase, Pc1, Pc2, Qc1min, Qc1max, # Qc2min, Qc2max, ramp_agc, ramp_10, ramp_30,ramp_q, apf # --- branch data -> create line, trafo for i in range(len(ppc['branch'])): from_bus = pp.get_element_index(net, 'bus', name=int(ppc['branch'][i, 0])) to_bus = pp.get_element_index(net, 'bus', name=int(ppc['branch'][i, 1])) from_vn_kv = ppc['bus'][from_bus, 9] to_vn_kv = ppc['bus'][to_bus, 9] if (from_vn_kv == to_vn_kv) & ((ppc['branch'][i, 8] == 0) | (ppc['branch'][i, 8] == 1)) & \ (ppc['branch'][i, 9] == 0): Zni = ppc['bus'][to_bus, 9]**2 / baseMVA # ohm max_i_ka = ppc['branch'][i, 5] / ppc['bus'][to_bus, 9] if max_i_ka == 0.0: max_i_ka = MAX_VAL logger.debug( "ppc branch rateA is zero -> Using MAX_VAL instead to calculate " + "maximum branch flow") pp.create_line_from_parameters( net, from_bus=from_bus, to_bus=to_bus, length_km=1, r_ohm_per_km=ppc['branch'][i, 2] * Zni, x_ohm_per_km=ppc['branch'][i, 3] * Zni, c_nf_per_km=ppc['branch'][i, 4] / Zni / omega * 1e9 / 2, max_i_ka=max_i_ka, type='ol', in_service=bool(ppc['branch'][i, 10])) else: if from_vn_kv >= to_vn_kv: hv_bus = from_bus vn_hv_kv = from_vn_kv lv_bus = to_bus vn_lv_kv = to_vn_kv tp_side = 'hv' else: hv_bus = to_bus vn_hv_kv = to_vn_kv lv_bus = from_bus vn_lv_kv = from_vn_kv tp_side = 'lv' if from_vn_kv == to_vn_kv: logger.warning( 'The pypower branch %d (from_bus, to_bus)=(%d, %d) is considered' ' as a transformer because of a ratio != 0 | 1 but it connects ' 'the same voltage level', i, ppc['branch'][i, 0], ppc['branch'][i, 1]) rk = ppc['branch'][i, 2] xk = ppc['branch'][i, 3] zk = (rk**2 + xk**2)**0.5 sn = ppc['branch'][i, 5] * 1e3 if sn == 0.0: sn = MAX_VAL logger.debug( "ppc branch rateA is zero -> Using MAX_VAL instead to calculate " + "apparent power") ratio_1 = 0 if ppc['branch'][i, 8] == 0 else (ppc['branch'][i, 8] - 1) * 100 i0_percent = -ppc['branch'][i, 4] * 100 * baseMVA * 1e3 / sn if i0_percent < 0: logger.info( 'A transformer always behaves inductive consumpting but the ' 'susceptance of pypower branch %d (from_bus, to_bus)=(%d, %d) is ' 'positive.', i, ppc['branch'][i, 0], ppc['branch'][i, 1]) pp.create_transformer_from_parameters( net, hv_bus=hv_bus, lv_bus=lv_bus, sn_kva=sn, vn_hv_kv=vn_hv_kv, vn_lv_kv=vn_lv_kv, vsc_percent=zk * sn / 1e3, vscr_percent=rk * sn / 1e3, pfe_kw=0, i0_percent=i0_percent, shift_degree=ppc['branch'][i, 9], tp_st_percent=abs(ratio_1) if ratio_1 else nan, tp_pos=sign(ratio_1) if ratio_1 else nan, tp_side=tp_side if ratio_1 else None, tp_mid=0 if ratio_1 else nan) # unused data of ppc: rateB, rateC # ToDo: gencost, areas are currently unconverted if validate_conversion: # set logger level to debug logger.setLevel(10) if not validate_from_ppc(ppc, net): logger.error("Validation failed.") return net
def example_multivoltage(): """ Returns the multivoltage example network from the pandapower tutorials. OUTPUT: net - multivoltage example network EXAMPLE: >>> import pandapower.networks >>> net = pandapower.networks.example_multivoltage() """ net = pp.create_empty_network() # --- Busses # HV # Double busbar pp.create_bus(net, name='Double Busbar 1', vn_kv=380, type='b') pp.create_bus(net, name='Double Busbar 2', vn_kv=380, type='b') for i in range(10): pp.create_bus(net, name='Bus DB T%s' % i, vn_kv=380, type='n') for i in range(1, 5): pp.create_bus(net, name='Bus DB %s' % i, vn_kv=380, type='n') # Single busbar pp.create_bus(net, name='Single Busbar', vn_kv=110, type='b') for i in range(1, 6): pp.create_bus(net, name='Bus SB %s' % i, vn_kv=110, type='n') for i in range(1, 6): for j in [1, 2]: pp.create_bus(net, name='Bus SB T%s.%s' % (i, j), vn_kv=110, type='n') # Remaining for i in range(1, 5): pp.create_bus(net, name='Bus HV%s' % i, vn_kv=110, type='n') # MV pp.create_bus(net, name='Bus MV0 20kV', vn_kv=20, type='n') for i in range(8): pp.create_bus(net, name='Bus MV%s' % i, vn_kv=10, type='n') # LV pp.create_bus(net, name='Bus LV0', vn_kv=0.4, type='n') for i in range(1, 6): pp.create_bus(net, name='Bus LV1.%s' % i, vn_kv=0.4, type='m') for i in range(1, 5): pp.create_bus(net, name='Bus LV2.%s' % i, vn_kv=0.4, type='m') pp.create_bus(net, name='Bus LV2.2.1', vn_kv=0.4, type='m') pp.create_bus(net, name='Bus LV2.2.2', vn_kv=0.4, type='m') # --- Lines # HV hv_lines = pd.DataFrame() hv_lines['line_name'] = ['HV Line%s' % i for i in range(1, 7)] hv_lines['from_bus'] = [ 'Bus SB 2', 'Bus HV1', 'Bus HV2', 'Bus HV1', 'Bus HV3', 'Bus SB 3' ] hv_lines['to_bus'] = [ 'Bus HV1', 'Bus HV2', 'Bus HV4', 'Bus HV4', 'Bus HV4', 'Bus HV3' ] hv_lines['std_type'] = '184-AL1/30-ST1A 110.0' hv_lines['length'] = [30, 20, 30, 15, 25, 30] hv_lines['parallel'] = [1, 1, 1, 1, 1, 2] for _, hv_line in hv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", hv_line.from_bus) to_bus = pp.get_element_index(net, "bus", hv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=hv_line.length, std_type=hv_line.std_type, name=hv_line.line_name, parallel=hv_line.parallel) # MV mv_lines = pd.DataFrame() mv_lines['line_name'] = ['MV Line%s' % i for i in range(1, 9)] mv_lines['from_bus'] = ['Bus MV%s' % i for i in list(range(7)) + [0]] mv_lines['to_bus'] = ['Bus MV%s' % i for i in list(range(1, 8)) + [7]] mv_lines['length'] = 1.5 mv_lines['std_type'] = 'NA2XS2Y 1x185 RM/25 12/20 kV' for _, mv_line in mv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", mv_line.from_bus) to_bus = pp.get_element_index(net, "bus", mv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=mv_line.length, std_type=mv_line.std_type, name=mv_line.line_name) # LV lv_lines = pd.DataFrame() lv_line_idx = [ '1.1', '1.2', '1.3', '1.4', '1.6', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] lv_lines['line_name'] = ['LV Line%s' % i for i in lv_line_idx] lv_line_idx = [ '0', '1.1', '1.2', '1.3', '1.4', '0', '2.1', '2.2', '2.3', '2.2', '2.2.1' ] lv_lines['from_bus'] = ['Bus LV%s' % i for i in lv_line_idx] lv_line_idx = [ '1.1', '1.2', '1.3', '1.4', '1.5', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] lv_lines['to_bus'] = ['Bus LV%s' % i for i in lv_line_idx] lv_lines['length'] = [0.08] * 5 + [0.12] * 6 lv_lines['std_type'] = ['NAYY 4x120 SE'] * 7 + ['15-AL1/3-ST1A 0.4'] * 4 for _, lv_line in lv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", lv_line.from_bus) to_bus = pp.get_element_index(net, "bus", lv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=lv_line.length, std_type=lv_line.std_type, name=lv_line.line_name) # --- Transformer hv_bus = pp.get_element_index(net, "bus", "Bus DB 2") lv_bus = pp.get_element_index(net, "bus", "Bus SB 1") pp.create_transformer_from_parameters(net, hv_bus, lv_bus, sn_kva=300000, vn_hv_kv=380, vn_lv_kv=110, vscr_percent=0.06, vsc_percent=8, pfe_kw=0, i0_percent=0, tp_pos=0, shift_degree=0, name='EHV-HV-Trafo') hv_bus = pp.get_element_index(net, "bus", "Bus MV4") lv_bus = pp.get_element_index(net, "bus", "Bus LV0") pp.create_transformer_from_parameters(net, hv_bus, lv_bus, sn_kva=400, vn_hv_kv=10, vn_lv_kv=0.4, vscr_percent=1.325, vsc_percent=4, pfe_kw=0.95, i0_percent=0.2375, tp_side="hv", tp_mid=0, tp_min=-2, tp_max=2, tp_st_percent=2.5, tp_pos=0, shift_degree=150, name='MV-LV-Trafo') # Trafo3w hv_bus = pp.get_element_index(net, "bus", "Bus HV2") mv_bus = pp.get_element_index(net, "bus", "Bus MV0 20kV") lv_bus = pp.get_element_index(net, "bus", "Bus MV0") pp.create_transformer3w_from_parameters(net, hv_bus, mv_bus, lv_bus, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10, sn_hv_kva=40000, sn_mv_kva=15000, sn_lv_kva=25000, vsc_hv_percent=10.1, vsc_mv_percent=10.1, vsc_lv_percent=10.1, vscr_hv_percent=0.266667, vscr_mv_percent=0.033333, vscr_lv_percent=0.04, pfe_kw=0, i0_percent=0, shift_mv_degree=30, shift_lv_degree=30, tp_side="hv", tp_mid=0, tp_min=-8, tp_max=8, tp_st_percent=1.25, tp_pos=0, name='HV-MV-MV-Trafo') # --- Static generators # HV pp.create_sgen(net, pp.get_element_index(net, "bus", 'Bus SB 5'), p_kw=-20000, q_kvar=-4000, sn_kva=45000, type='WP', name='Wind Park') # MV mv_sgens = pd.DataFrame() mv_sgens['sgen_name'] = [ 'Biogas plant', 'Further MV Generator', 'Industry Generator', 'PV Park' ] mv_sgens['bus'] = ['Bus MV6', 'Bus MV0', 'Bus MV0 20kV', 'Bus MV5'] mv_sgens['p'] = [-500, -500, -15000, -2000] mv_sgens['q'] = [0, -50, -3000, -100] mv_sgens['sn'] = [750, 1000, 20000, 5000] mv_sgens['type'] = ['SGEN', 'SGEN', 'SGEN', 'PV'] for _, sgen in mv_sgens.iterrows(): bus_idx = pp.get_element_index(net, "bus", sgen.bus) pp.create_sgen(net, bus_idx, p_kw=sgen.p, q_kvar=sgen.q, sn_kva=sgen.sn, type=sgen.type, name=sgen.sgen_name) # LV lv_sgens = pd.DataFrame() lv_sgens['sgen_name'] = ['PV'] + ['PV(%s)' % i for i in range(1, 6)] lv_sgens['bus'] = [ 'Bus LV%s' % i for i in ['1.1', '1.3', '2.3', '2.4', '2.2.1', '2.2.2'] ] lv_sgens['p'] = [-6, -5, -5, -5, -5, -5] lv_sgens['q'] = 0 lv_sgens['sn'] = [12, 10, 10, 10, 10, 10] lv_sgens['type'] = 'PV' for _, sgen in lv_sgens.iterrows(): bus_idx = pp.get_element_index(net, "bus", sgen.bus) pp.create_sgen(net, bus_idx, p_kw=sgen.p, q_kvar=sgen.q, sn_kva=sgen.sn, type=sgen.type, name=sgen.sgen_name) # --- Loads # HV hv_loads = pd.DataFrame() hv_loads['load_name'] = ['MV Net %s' % i for i in range(5)] hv_loads['bus'] = ['Bus SB 4', 'Bus HV1', 'Bus HV2', 'Bus HV3', 'Bus HV4'] hv_loads['p'] = 38000 hv_loads['q'] = 6000 for _, load in hv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # MV mv_loads = pd.DataFrame() mv_loads['load_name'] = ['Further MV-Rings', 'Industry Load' ] + ['LV Net %s' % i for i in [1, 2, 3, 5, 6, 7]] mv_loads['bus'] = ['Bus MV0', 'Bus MV0 20kV' ] + ['Bus MV%s' % i for i in [1, 2, 3, 5, 6, 7]] mv_loads['p'] = [6000, 18000, 400, 400, 400, 400, 400, 400] mv_loads['q'] = [2000, 4000, 100, 60, 60, 60, 60, 60] for _, load in mv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # LV lv_loads = pd.DataFrame() idx = ['', '(1)', '(2)', '(3)', '(4)', '(5)'] lv_loads['load_name'] = ['Further LV-Feeders Load'] + [ 'Residential Load%s' % i for i in idx[0:5] ] + ['Rural Load%s' % i for i in idx[0:6]] lv_loads['bus'] = [ 'Bus LV%s' % i for i in [ '0', '1.1', '1.2', '1.3', '1.4', '1.5', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] ] lv_loads['p'] = [100] + [10] * 11 lv_loads['q'] = [10] + [3] * 11 for _, load in lv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # --- Other # Shunt pp.create_shunt(net, pp.get_element_index(net, "bus", 'Bus HV1'), p_kw=0, q_kvar=-960, name='Shunt') # ExtGrids pp.create_ext_grid(net, pp.get_element_index(net, "bus", 'Double Busbar 1'), vm_pu=1.03, va_degree=0, name='External grid', s_sc_max_mva=10000, rx_max=0.1, rx_min=0.1) # Gen pp.create_gen(net, pp.get_element_index(net, "bus", 'Bus HV4'), vm_pu=1.03, p_kw=-1e5, name='Gas turbine') # Impedance pp.create_impedance(net, pp.get_element_index(net, "bus", 'Bus HV3'), pp.get_element_index(net, "bus", 'Bus HV1'), rft_pu=0.074873, xft_pu=0.198872, sn_kva=100000, name='Impedance') # xwards pp.create_xward(net, pp.get_element_index(net, "bus", 'Bus HV3'), ps_kw=23942, qs_kvar=-12241.87, pz_kw=2814.571, qz_kvar=0, r_ohm=0, x_ohm=12.18951, vm_pu=1.02616, name='XWard 1') pp.create_xward(net, pp.get_element_index(net, "bus", 'Bus HV1'), ps_kw=3776, qs_kvar=-7769.979, pz_kw=9174.917, qz_kvar=0, r_ohm=0, x_ohm=50.56217, vm_pu=1.024001, name='XWard 2') # --- Switches # HV # Bus-bus switches hv_bus_sw = pd.DataFrame() hv_bus_sw['bus_name'] = ['DB DS%s' % i for i in range(14)] + \ ['DB CB%s' % i for i in range(5)] + \ ['SB DS%s.%s' % (i, j) for i in range(1, 6) for j in range(1, 3)] + \ ['SB CB%s' % i for i in range(1, 6)] hv_bus_sw['from_bus'] = ['Double Busbar %s' % i for i in [2, 1, 2, 1, 2, 1, 2, 1, 2, 1]] + \ ['Bus DB T%s' % i for i in [2, 4, 6, 8, 0, 3, 5, 7, 9]] + \ ['Bus SB T1.1', 'Single Busbar', 'Bus SB T2.1', 'Single Busbar', 'Bus SB T3.1', 'Single Busbar', 'Bus SB T4.1', 'Single Busbar', 'Bus SB T5.1', 'Single Busbar'] + \ ['Bus SB T%s.2' % i for i in range(1, 6)] hv_bus_sw['to_bus'] = ['Bus DB %s' % i for i in ['T0', 'T1', 'T3', 'T3', 'T5', 'T5', 'T7', 'T7', 'T9', 'T9', '1', '2', '3', '4', 'T1', 'T2', 'T4', 'T6', 'T8']] + \ ['Bus SB %s' % i for i in ['1', 'T1.2', '2', 'T2.2', '3', 'T3.2', '4', 'T4.2', '5', 'T5.2']] + \ ['Bus SB T%s.1' % i for i in range(1, 6)] hv_bus_sw['type'] = ['DS'] * 14 + ['CB'] * 5 + ['DS'] * 10 + ['CB'] * 5 hv_bus_sw['et'] = 'b' hv_bus_sw['closed'] = [ bool(i) for i in [1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] + [1] * 15 ] for _, switch in hv_bus_sw.iterrows(): from_bus = pp.get_element_index(net, "bus", switch.from_bus) to_bus = pp.get_element_index(net, "bus", switch.to_bus) pp.create_switch(net, from_bus, to_bus, et=switch.et, closed=switch.closed, type=switch.type, name=switch.bus_name) # Bus-Line switches hv_buses = net.bus[(net.bus.vn_kv == 380) | (net.bus.vn_kv == 110)].index hv_ls = net.line[(net.line.from_bus.isin(hv_buses)) & (net.line.to_bus.isin(hv_buses))] for _, line in hv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) # MV # Bus-line switches mv_buses = net.bus[(net.bus.vn_kv == 10) | (net.bus.vn_kv == 20)].index mv_ls = net.line[(net.line.from_bus.isin(mv_buses)) & (net.line.to_bus.isin(mv_buses))] for _, line in mv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) open_switch_id = net.switch[( net.switch.name == 'Switch Bus MV5 - MV Line5')].index net.switch.closed.loc[open_switch_id] = False # LV # Bus-line switches lv_buses = net.bus[net.bus.vn_kv == 0.4].index lv_ls = net.line[(net.line.from_bus.isin(lv_buses)) & (net.line.to_bus.isin(lv_buses))] for _, line in lv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) # Trafoswitches # HV pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus DB 2'), pp.get_element_index(net, "trafo", 'EHV-HV-Trafo'), et='t', closed=True, type='LBS', name='Switch DB2 - EHV-HV-Trafo') pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus SB 1'), pp.get_element_index(net, "trafo", 'EHV-HV-Trafo'), et='t', closed=True, type='LBS', name='Switch SB1 - EHV-HV-Trafo') # LV pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus MV4'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch MV4 - MV-LV-Trafo') pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus LV0'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch LV0 - MV-LV-Trafo') # --- Powerflow # run power flow and generate result tables pp.runpp(net, init='dc', calculate_voltage_angles=True, Numba=False) return net
for elementa in range(len(BreakerValue)): for elementb in range(len(NodeValue)): for elementc in range(len(NodeValue[elementb].conn_eqp)): if BreakerValue[elementa].name == NodeValue[elementb].conn_eqp[ elementc]: CB_element.append(NodeValue[elementb].name) ''' Now I have the list of circuit breaker connected to particular nodes, since there are nine Circuit breakers in the system, and each has two connections/sides so to get the values from the list, each increment will show one connected to particular circuit breaker, each increment indentifies the buses connected to that end. ''' for elementa in range(len(BreakerValue)): name = BreakerValue[elementa].name if elementa == 0: connection1 = pp.get_element_index(net, "bus", CB_element[elementa]) connection2 = pp.get_element_index(net, "bus", CB_element[elementa + 1]) if elementa == 1: connection1 = pp.get_element_index(net, "bus", CB_element[elementa + 1]) connection2 = pp.get_element_index(net, "bus", CB_element[elementa + 2]) if elementa == 2: connection1 = pp.get_element_index(net, "bus", CB_element[elementa + 2])
def sim_request(data): is_three_phase = utils.get_or_error("3phase", data) elements_dict = utils.get_or_error("elements", data) buses = {} # Used for matching bus UUIDs to index def process_potential_bus(key, value): """ Inner method for processing a positional argument that could be a bus This function checks if the value is in the bus keys. This should never cause issues so long as UUID's aren't used for any other purpose except for bus identification and as long as there are no UUID collisions. Both of those cases seem exceptionally unlikely, so this should work fine. """ if value in buses.keys(): return buses[value] else: return value bus_list = [(uuid, element) for uuid, element in elements_dict.items() if utils.get_or_error("etype", element) == "bus"] element_list = [(uuid, element) for uuid, element in elements_dict.items() if utils.get_or_error("etype", element) != "bus" and utils.get_or_error("etype", element) != "switch"] switch_list = [(uuid, element) for uuid, element in elements_dict.items() if utils.get_or_error("etype", element) == "switch"] net = pp.create_empty_network() for uuid, bus in bus_list: element_type = "bus" req_props = utils.required_props[element_type] positional_args = [ value for key, value in bus.items() if key in req_props ] optional_args = { key: value for key, value in bus.items() if (not key in req_props) and (not key == "etype")} index = pp.create_bus(net, *positional_args, **optional_args, name=uuid) buses[uuid] = index for uuid, element in element_list: element_type = utils.get_or_error("etype", element) req_props = utils.required_props[element_type] positional_args = [process_potential_bus(key, value) for key, value in element.items() if key in req_props] optional_args = { key: value for key, value in element.items() if (not key in req_props) and (not key == "etype")} if element_type == "load": pp.create_load(net, *positional_args, **optional_args, name=uuid) elif element_type == "gen": pp.create_gen(net, *positional_args, **optional_args, name=uuid) elif element_type == "ext_grid": pp.create_ext_grid(net, *positional_args, **optional_args, name=uuid) elif element_type == "line": pp.create_line(net, *positional_args, *optional_args, name=uuid) elif element_type == "trafo": pp.create_transformer_from_parameters(net, *positional_args, **optional_args, name=uuid) elif element_type == "storage": pp.create_storage(net, *positional_args, **optional_args, name=uuid) else: raise InvalidError(f"Element type {element_type} is invalid or not implemented!") for uuid, switch in switch_list: element_type = "switch" req_props = utils.required_props[element_type] positional_args = [process_potential_bus(key, value) for key, value in element.items() if key in req_props] optional_args = { key: value for key, value in element.items() if (not key in req_props) and (not key == "etype")} et = positional_args[2] if et == "b": pass # This is handled by process_potential_buses if et == "l": positional_args[1] = pp.get_element_index(net, "line", positional_args[1]) elif et == "t": positional_args[1] = pp.get_element_index(net, "trafo", positional_args[1]) elif et == "t3": positional_args[1] = pp.get_element_index(net, "trafo3w", positional_args[1]) else: raise InvalidError(f"Invalid element type {et}. Must be b,l,t, or t3.") pp.create_switch(net, *positional_args, **optional_args, name=uuid) try: if is_three_phase: pp.runpp_3ph(net) else: pp.runpp(net) except LoadflowNotConverged: report = pp.diagnostic(net, report_style="compact", warnings_only=True) raise ConvError("Load flow did not converge.") except (KeyError, ValueError) as e: raise PPError(str(e)) except Exception as e: raise PPError("Unknown exception has occured: " + str(e)) message = {} message["status"] = "SIM_RESULT" results = {} for uuid,element in elements_dict.items(): element_type = elements_dict[uuid]["etype"] if element_type == "switch": continue net["res_" + element_type] = net["res_" + element_type].fillna(0) results[uuid] = {} results[uuid]["etype"] = element_type index = pp.get_element_index(net, element_type, uuid, exact_match=True) results[uuid].update(net["res_" + element_type].iloc[index].to_dict()) message["elements"] = results return json.dumps(message)
# Remaining buses for i in range(1, 5): pp.create_bus(net, name='Bus HV%s' % i, vn_kv=110, type='n') # show bustable net.bus hv_lines = pd.read_csv('example_advanced/hv_lines.csv', sep=';', header=0, decimal=',') hv_lines # create lines for _, hv_line in hv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", hv_line.from_bus) to_bus = pp.get_element_index(net, "bus", hv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=hv_line.length, std_type=hv_line.std_type, name=hv_line.line_name, parallel=hv_line.parallel) # show line table net.line hv_bus = pp.get_element_index(net, "bus", "Bus DB 2") lv_bus = pp.get_element_index(net, "bus", "Bus SB 1") pp.create_transformer_from_parameters(net,
for voltage in base_voltage_list: baseVol = voltage.ID base_voltage = voltage.name base_volt_dict[baseVol] = base_voltage # BUS for bus in busbar_list: pp.create_bus(net, name=bus.name, vn_kv=bus.voltage, type="b") # Transformer for transformer in power_transformer_list: bus_list, way_terminals = find_attached_busbar(transformer) for bus, wt in zip(bus_list, way_terminals): if terminal_volt_dict[wt].end_number == '1': bus_high = bus hv_bus = pp.get_element_index(net, "bus", bus.name) vn = terminal_volt_dict[wt].baseVol vn_hv_kv = base_volt_dict[vn[1:]] sn_mva = terminal_volt_dict[wt].s elif terminal_volt_dict[wt].end_number == '2': bus_low = bus lv_bus = pp.get_element_index(net, "bus", bus.name) vn = terminal_volt_dict[wt].baseVol vn_lv_kv = base_volt_dict[vn[1:]] pp.create_transformer_from_parameters(net, name=transformer.name, hv_bus=hv_bus, lv_bus=lv_bus, sn_mva=sn_mva, vn_hv_kv=vn_hv_kv,
def create_network(): network = pp.create_empty_network() sn_vn_transformer_data = { "sn_mva": 1, "vn_hv_kv": 20, "vn_lv_kv": 0.4, "vk_percent": 5, "vkr_percent": 1.1, "pfe_kw": 1.95, "i0_percent": 0.27, "shift_degree": 0 } pp.create_std_type(network, sn_vn_transformer_data, "SN/NN 1MVA", element='trafo') slack_bus = pp.create_bus(network, vn_kv=110, name="Slack Bus") busNodes = [] lowVoltageBusNodes = [] pp.create_ext_grid(network, bus=slack_bus, vm_pu=1.01, name="Grid Connection") mediumVoltageBusNode = pp.create_bus(network, vn_kv=20, name="MV slack side") pp.create_transformer(network, hv_bus=slack_bus, lv_bus=mediumVoltageBusNode, std_type="40 MVA 110/20 kV", name="VN/SN Transformer") for i in range(0, 100): busNodes.append( pp.create_bus(network, vn_kv=20, name="Bus_" + str(i + 1))) lowVoltageBusNodes.append( pp.create_bus(network, vn_kv=0.4, name="LowVoltageBus_" + str(i + 1))) pp.create_load(network, bus=lowVoltageBusNodes[i], p_mw=0.14, q_mvar=0.05, name="Load_" + str(i + 1)) pp.create_transformer(network, hv_bus=busNodes[i], lv_bus=lowVoltageBusNodes[i], std_type="SN/NN 1MVA", name="Transformer_" + str(i + 1)) pp.create_line(network, from_bus=mediumVoltageBusNode, to_bus=busNodes[0], length_km=0.2, name="Line_0", std_type="NA2XS2Y 1x150 RM/25 12/20 kV") for i in range(0, 99): pp.create_line(network, from_bus=busNodes[i], to_bus=busNodes[i + 1], length_km=0.6, name="Line_" + str(i + 1), std_type="NA2XS2Y 1x150 RM/25 12/20 kV") # Add capacitors with regulating switches pp.create_bus(network, vn_kv=20, name="Bus_Cap1") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_13'), pp.get_element_index(network, "bus", 'Bus_Cap1'), et="b", closed=False, type="LBS", name="CapSwitch1") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap1'), 0.125, 0, name="Cap1") pp.create_bus(network, vn_kv=20, name="Bus_Cap2") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_39'), pp.get_element_index(network, "bus", 'Bus_Cap2'), et="b", closed=False, type="LBS", name="CapSwitch2") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap2'), 0.8, 0, name="Cap2") pp.create_bus(network, vn_kv=20, name="Bus_Cap3") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_85'), pp.get_element_index(network, "bus", 'Bus_Cap3'), et="b", closed=False, type="LBS", name="CapSwitch3") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap3'), 0.125, 0, name="Cap3") pp.create_bus(network, vn_kv=20, name="Bus_Cap4") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_28'), pp.get_element_index(network, "bus", 'Bus_Cap4'), et="b", closed=False, type="LBS", name="CapSwitch4") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap4'), 3, 0, name="Cap4") pp.create_bus(network, vn_kv=20, name="Bus_Cap5") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_59'), pp.get_element_index(network, "bus", 'Bus_Cap5'), et="b", closed=False, type="LBS", name="CapSwitch5") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap5'), 0.25, 0, name="Cap5") pp.create_bus(network, vn_kv=20, name="Bus_Cap6") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_70'), pp.get_element_index(network, "bus", 'Bus_Cap6'), et="b", closed=False, type="LBS", name="CapSwitch6") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap6'), 0.8, 0, name="Cap6") pp.create_bus(network, vn_kv=20, name="Bus_Cap7") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_48'), pp.get_element_index(network, "bus", 'Bus_Cap7'), et="b", closed=False, type="LBS", name="CapSwitch7") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap7'), 0.25, 0, name="Cap7") pp.create_bus(network, vn_kv=20, name="Bus_Cap8") pp.create_switch(network, pp.get_element_index(network, "bus", 'Bus_95'), pp.get_element_index(network, "bus", 'Bus_Cap8'), et="b", closed=False, type="LBS", name="CapSwitch8") pp.create_shunt_as_capacitor(network, pp.get_element_index(network, "bus", 'Bus_Cap8'), 0.25, 0, name="Cap8") return network
def get_res_value(net, table, name, res_col): obj = pp.get_element_index(net, table, name) df = getattr(net, "res_" + table) return df.loc[obj, res_col]
def validate_from_ppc( ppc_net, pp_net, max_diff_values={ "vm_pu": 1e-6, "va_degree": 1e-5, "p_branch_kw": 1e-3, "q_branch_kvar": 1e-3, "p_gen_kw": 1e-3, "q_gen_kvar": 1e-3 }): """ This function validates the pypower case files to pandapower net structure conversion via a \ comparison of loadflow calculations. INPUT: **ppc_net** - The pypower case file. **pp_net** - The pandapower network. OPTIONAL: **max_diff_values** - Dict of maximal allowed difference values. The keys must be 'vm_pu', 'va_degree', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw' and 'q_gen_kvar' and the values floats. OUTPUT: **conversion_success** - conversion_success is returned as False if pypower or pandapower cannot calculate a power flow or if the maximum difference values (max_diff_values ) cannot be hold. EXAMPLE: import pandapower.converter as pc from pypower import case4gs ppc_net = case4gs.case4gs() pp_net = cv.from_ppc(ppc_net, f_hz=60) cv.validate_from_ppc(ppc_net, pp_net) """ # --- run a pypower power flow without print output ppopt = ppoption.ppoption(VERBOSE=0, OUT_ALL=0) ppc_res = runpf.runpf(ppc_net, ppopt)[0] # --- store pypower power flow results ppc_res_branch = ppc_res['branch'][:, 13:17] ppc_res_bus = ppc_res['bus'][:, 7:9] ppc_res_gen = ppc_res['gen'][:, 1:3] # --- try to run a pandapower power flow try: pp.runpp(pp_net, init="dc", calculate_voltage_angles=True, trafo_model="pi") except: try: pp.runpp(pp_net, calculate_voltage_angles=True, init="flat", trafo_model="pi") except: try: pp.runpp(pp_net, trafo_model="pi") except: if (ppc_res['success'] == 1) & (~pp_net.converged): logger.error( 'The validation of ppc conversion fails because the pandapower net' ' power flow does not converge.') elif (ppc_res['success'] != 1) & (pp_net.converged): logger.error( 'The validation of ppc conversion fails because the power flow of ' 'the pypower case does not converge.') elif (ppc_res['success'] != 1) & (~pp_net.converged): logger.error( 'The power flow of both, the pypower case and the pandapower net, ' 'do not converge.') return False # --- prepare power flow result comparison by reordering pp results as they are in ppc results if (ppc_res['success'] == 1) & (pp_net.converged): # --- pandapower bus result table pp_res_bus = array(pp_net.res_bus[['vm_pu', 'va_degree']]) # --- pandapower gen result table pp_res_gen = zeros([1, 2]) # consideration of parallel generators via storing how much generators have been considered # each node already_used_gen = Series(zeros([pp_net.bus.shape[0]]), index=pp_net.bus.index).astype(int) GENS = DataFrame(ppc_res['gen'][:, [0]].astype(int)) change_q_compare = [] for i, j in GENS.iterrows(): current_bus_idx = pp.get_element_index(pp_net, 'bus', name=j[0]) current_bus_type = int(ppc_res['bus'][current_bus_idx, 1]) # ext_grid if current_bus_type == 3: if already_used_gen.at[current_bus_idx] == 0: pp_res_gen = append( pp_res_gen, array(pp_net.res_ext_grid[ pp_net.ext_grid.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape( (1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 else: pp_res_gen = append( pp_res_gen, array(pp_net.res_sgen[ pp_net.sgen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx] - 1].reshape((1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 change_q_compare += [j[0]] # gen elif current_bus_type == 2: pp_res_gen = append( pp_res_gen, array(pp_net.res_gen[pp_net.gen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)), 0) if already_used_gen.at[current_bus_idx] > 0: change_q_compare += [j[0]] already_used_gen.at[current_bus_idx] += 1 # sgen elif current_bus_type == 1: pp_res_gen = append( pp_res_gen, array(pp_net.res_sgen[pp_net.sgen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 pp_res_gen = pp_res_gen[1:, :] # delete initial zero row # --- pandapower branch result table pp_res_branch = zeros([1, 4]) # consideration of parallel branches via storing how much branches have been considered # each node-to-node-connection init1 = concat([pp_net.line.from_bus, pp_net.line.to_bus], axis=1).drop_duplicates() init2 = concat([pp_net.trafo.hv_bus, pp_net.trafo.lv_bus], axis=1).drop_duplicates() init1['hv_bus'] = nan init1['lv_bus'] = nan init2['from_bus'] = nan init2['to_bus'] = nan already_used_branches = concat([init1, init2], axis=0) already_used_branches['number'] = zeros( [already_used_branches.shape[0], 1]).astype(int) BRANCHES = DataFrame(ppc_res['branch'][:, [0, 1, 8, 9]]) for i in BRANCHES.index: from_bus = pp.get_element_index(pp_net, 'bus', name=int(ppc_res['branch'][i, 0])) to_bus = pp.get_element_index(pp_net, 'bus', name=int(ppc_res['branch'][i, 1])) from_vn_kv = ppc_res['bus'][from_bus, 9] to_vn_kv = ppc_res['bus'][to_bus, 9] ratio = BRANCHES[2].at[i] angle = BRANCHES[3].at[i] # from line results if (from_vn_kv == to_vn_kv) & ((ratio == 0) | (ratio == 1)) & (angle == 0): pp_res_branch = append( pp_res_branch, array( pp_net.res_line[(pp_net.line.from_bus == from_bus) & (pp_net.line.to_bus == to_bus)] [['p_from_kw', 'q_from_kvar', 'p_to_kw', 'q_to_kvar']])[int(already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)] += 1 # from trafo results else: if from_vn_kv >= to_vn_kv: pp_res_branch = append( pp_res_branch, array(pp_net.res_trafo[ (pp_net.trafo.hv_bus == from_bus) & (pp_net.trafo.lv_bus == to_bus)][[ 'p_hv_kw', 'q_hv_kvar', 'p_lv_kw', 'q_lv_kvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)] += 1 else: # switch hv-lv-connection of pypower connection buses pp_res_branch = append( pp_res_branch, array(pp_net.res_trafo[ (pp_net.trafo.hv_bus == to_bus) & (pp_net.trafo.lv_bus == from_bus)][[ 'p_lv_kw', 'q_lv_kvar', 'p_hv_kw', 'q_hv_kvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)] += 1 pp_res_branch = pp_res_branch[1:, :] # delete initial zero row # --- do the power flow result comparison diff_res_bus = ppc_res_bus - pp_res_bus diff_res_branch = ppc_res_branch - pp_res_branch * 1e-3 diff_res_gen = ppc_res_gen + pp_res_gen * 1e-3 # comparison of buses with several generator units only as q sum GEN_uniq = GENS.drop_duplicates() for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index: next_is = GEN_uniq.index[GEN_uniq.index > i] if len(next_is) > 0: next_i = next_is[0] else: next_i = GENS.index[-1] + 1 if (next_i - i) > 1: diff_res_gen[i:next_i, 1] = sum(diff_res_gen[i:next_i, 1]) # logger info logger.debug( "Maximum voltage magnitude difference between pypower and pandapower: " "%.2e pu" % max(abs(diff_res_bus[:, 0]))) logger.debug( "Maximum voltage angle difference between pypower and pandapower: " "%.2e degree" % max(abs(diff_res_bus[:, 1]))) logger.debug( "Maximum branch flow active power difference between pypower and pandapower: " "%.2e kW" % max(abs(diff_res_branch[:, [0, 2]] * 1e3))) logger.debug( "Maximum branch flow reactive power difference between pypower and " "pandapower: %.2e kVAr" % max(abs(diff_res_branch[:, [1, 3]] * 1e3))) logger.debug( "Maximum active power generation difference between pypower and pandapower: " "%.2e kW" % max(abs(diff_res_gen[:, 0] * 1e3))) logger.debug( "Maximum reactive power generation difference between pypower and pandapower: " "%.2e kVAr" % max(abs(diff_res_gen[:, 1] * 1e3))) if (max(abs(diff_res_bus[:, 0])) < 1e-3) & (max(abs(diff_res_bus[:, 1])) < 1e-3) & \ (max(abs(diff_res_branch[:, [0, 2]])) < 1e-3) & \ (max(abs(diff_res_branch[:, [1, 3]])) < 1e-3) & \ (max(abs(diff_res_gen)) > 1e-1).any(): logger.debug( "The active/reactive power generation difference possibly results " "because of a pypower error. Please validate " "the results via pypower loadflow." ) # this occurs e.g. at ppc case9 # give a return if type(max_diff_values) == dict: if Series([ 'q_gen_kvar', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw', 'va_degree', 'vm_pu' ]).isin(Series(list(max_diff_values.keys()))).all(): if (max(abs(diff_res_bus[:, 0])) < max_diff_values['vm_pu']) & \ (max(abs(diff_res_bus[:, 1])) < max_diff_values['va_degree']) & \ (max(abs(diff_res_branch[:, [0, 2]])) < max_diff_values['p_branch_kw'] / 1e3) & \ (max(abs(diff_res_branch[:, [1, 3]])) < max_diff_values['q_branch_kvar'] / 1e3) & \ (max(abs(diff_res_gen[:, 0])) < max_diff_values['p_gen_kw'] / 1e3) & \ (max(abs(diff_res_gen[:, 1])) < max_diff_values['q_gen_kvar'] / 1e3): return True else: return False else: logger.debug('Not all requried dict keys are provided.') else: logger.debug("'max_diff_values' must be a dict.")
def create_pp_load(self, element): bus = pp.get_element_index( self.net, "bus", element["connections"][0]['connectivityNodeId']) pp.create_load(self.net, bus=bus, p_mw=0)