diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39026b162..51f9d85f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,8 @@ Change Log - [ADDED] Static Var Compensator with Voltage Control - [ADDED] pf2pp: min/max q_mvar and min/max p_mw limits for sgens and gen will be converted - [ADDED] Static Var Compensator with Voltage Control +- [FIXED] replacing deprecated in1d with isin +- [ADDED] A switch to disable updating the vk and vkr values for trafo3w - [FIXED] cast the column to the correct type before assigning values - [FIXED] replacement for deprecated namespaces scipy.sparse.csc and scipy.sparse.csr - [FIXED] copy array element to standard python scalar @@ -85,6 +87,7 @@ Change Log - [CHANGED] accelerate _integrate_power_elements_connected_with_switch_buses() in get_equivalent() - [CHANGED] accelerate distributed slack power flow calculation by using sparse-aware operations in _subnetworks() - [ADDED] Discrete shunt controller for local voltage regulation with shunt steps +- [ADDED] cim2pp converter: Using lxml to parse XML files (better performance) [2.14.7] - 2024-06-14 ------------------------------- diff --git a/pandapower/build_branch.py b/pandapower/build_branch.py index 4c5dfbfd5..f48cb2371 100644 --- a/pandapower/build_branch.py +++ b/pandapower/build_branch.py @@ -10,7 +10,6 @@ import numpy as np import pandas as pd -from pandapower import DC_BUS_TYPE from pandapower.auxiliary import get_values from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_R, BR_X, BR_B, BR_G, TAP, SHIFT, BR_STATUS, RATE_A, \ @@ -22,13 +21,13 @@ GAMMA, EPSILON, T_AMBIENT_C, T_REF_C, branch_cols_tdpf from pandapower.pypower.idx_brch_sc import branch_cols_sc from pandapower.pypower.idx_bus import BASE_KV, VM, VA, BUS_TYPE, BUS_AREA, ZONE, VMAX, VMIN, PQ -from pandapower.pypower.idx_bus_dc import DC_BUS_AREA, DC_VM, DC_ZONE, DC_VMAX, DC_VMIN, DC_P, DC_BASE_KV +from pandapower.pypower.idx_bus_dc import DC_BUS_AREA, DC_VM, DC_ZONE, DC_VMAX, DC_VMIN, DC_P, DC_BASE_KV, DC_BUS_TYPE from pandapower.pypower.idx_bus_sc import C_MIN, C_MAX from pandapower.pypower.idx_tcsc import TCSC_F_BUS, TCSC_T_BUS, TCSC_X_L, TCSC_X_CVAR, TCSC_SET_P, \ TCSC_THYRISTOR_FIRING_ANGLE, TCSC_STATUS, TCSC_CONTROLLABLE, tcsc_cols, TCSC_MIN_FIRING_ANGLE, TCSC_MAX_FIRING_ANGLE -def _build_branch_ppc(net, ppc): +def _build_branch_ppc(net, ppc, update_vk_values: bool=True): """ Takes the empty ppc network and fills it with the branch values. The branch datatype will be np.complex 128 afterwards. @@ -65,9 +64,9 @@ def _build_branch_ppc(net, ppc): if "line" in lookup: _calc_line_parameter(net, ppc) if "trafo" in lookup: - _calc_trafo_parameter(net, ppc) + _calc_trafo_parameter(net, ppc, update_vk_values=update_vk_values) if "trafo3w" in lookup: - _calc_trafo3w_parameter(net, ppc) + _calc_trafo3w_parameter(net, ppc, update_vk_values=update_vk_values) if "impedance" in lookup: _calc_impedance_parameter(net, ppc) if "xward" in lookup: @@ -141,17 +140,18 @@ def _initialize_branch_lookup(net, dc=False): return end -def _calc_trafo3w_parameter(net, ppc): +def _calc_trafo3w_parameter(net, ppc, update_vk_values: bool=True): bus_lookup = net["_pd2ppc_lookups"]["bus"] branch = ppc["branch"] f, t = net["_pd2ppc_lookups"]["branch"]["trafo3w"] - trafo_df = _trafo_df_from_trafo3w(net) + trafo_df = _trafo_df_from_trafo3w(net, update_vk_values=update_vk_values) hv_bus = get_trafo_values(trafo_df, "hv_bus").astype(np.int64) lv_bus = get_trafo_values(trafo_df, "lv_bus").astype(np.int64) in_service = get_trafo_values(trafo_df, "in_service").astype(np.int64) branch[f:t, F_BUS] = bus_lookup[hv_bus] branch[f:t, T_BUS] = bus_lookup[lv_bus] - r, x, g, b, g_asym, b_asym, ratio, shift = _calc_branch_values_from_trafo_df(net, ppc, trafo_df) + r, x, g, b, g_asym, b_asym, ratio, shift = _calc_branch_values_from_trafo_df(net, ppc, trafo_df, + update_vk_values=update_vk_values) branch[f:t, BR_R] = r branch[f:t, BR_X] = x branch[f:t, BR_G] = g @@ -329,7 +329,7 @@ def _calc_line_dc_parameter(net, ppc, elm="line_dc", ppc_elm="branch_dc"): branch_dc[f:t, DC_RATE_A] = max_load / 100. * max_i_ka * df * parallel * vr -def _calc_trafo_parameter(net, ppc): +def _calc_trafo_parameter(net, ppc, update_vk_values: bool=True): ''' Calculates the transformer parameter in per unit. @@ -350,7 +350,7 @@ def _calc_trafo_parameter(net, ppc): parallel = trafo["parallel"].values branch[f:t, F_BUS] = bus_lookup[trafo["hv_bus"].values] branch[f:t, T_BUS] = bus_lookup[trafo["lv_bus"].values] - r, x, g, b, g_asym, b_asym, ratio, shift = _calc_branch_values_from_trafo_df(net, ppc) + r, x, g, b, g_asym, b_asym, ratio, shift = _calc_branch_values_from_trafo_df(net, ppc, update_vk_values=update_vk_values) branch[f:t, BR_R] = r branch[f:t, BR_X] = x branch[f:t, BR_G] = g @@ -377,7 +377,7 @@ def get_trafo_values(trafo_df, par): return trafo_df[par].values -def _calc_branch_values_from_trafo_df(net, ppc, trafo_df=None, sequence=1): +def _calc_branch_values_from_trafo_df(net, ppc, trafo_df=None, sequence=1, update_vk_values=True): """ Calculates the MAT/PYPOWER-branch-attributes from the pandapower trafo dataframe. @@ -420,16 +420,18 @@ def _calc_branch_values_from_trafo_df(net, ppc, trafo_df=None, sequence=1): vn_trafo_hv, vn_trafo_lv, shift = _calc_tap_from_dataframe(net, trafo_df) ratio = _calc_nominal_ratio_from_dataframe(ppc, trafo_df, vn_trafo_hv, vn_trafo_lv, bus_lookup) - r, x, g, b, g_asym, b_asym = _calc_r_x_y_from_dataframe(net, trafo_df, vn_trafo_lv, vn_lv, ppc, sequence=sequence) + r, x, g, b, g_asym, b_asym = _calc_r_x_y_from_dataframe(net, trafo_df, vn_trafo_lv, vn_lv, ppc, sequence=sequence, + update_vk_values=update_vk_values) return r, x, g, b, g_asym, b_asym, ratio, shift -def _calc_r_x_y_from_dataframe(net, trafo_df, vn_trafo_lv, vn_lv, ppc, sequence=1): +def _calc_r_x_y_from_dataframe(net, trafo_df, vn_trafo_lv, vn_lv, ppc, sequence=1, update_vk_values=True): mode = net["_options"]["mode"] trafo_model = net["_options"]["trafo_model"] r, x = _calc_r_x_from_dataframe(mode, trafo_df, vn_lv, vn_trafo_lv, net.sn_mva, - sequence=sequence, characteristic=net.get("characteristic")) + sequence=sequence, characteristic=net.get("characteristic"), + update_vk_values=update_vk_values) if mode == "sc": if net._options.get("use_pre_fault_voltage", False): @@ -654,7 +656,7 @@ def _get_vk_values(trafo_df, characteristic, trafotype="2W"): vk_value = get_trafo_values(trafo_df, vk_var) if use_tap_dependent_impedance and vk_var in char_columns: vals += (_calc_tap_dependent_value( - trafo_df, tap_pos, vk_value, vk_var, tap_dependent_impedance, + tap_pos, vk_value, tap_dependent_impedance, characteristic, all_characteristic_idx[:, index_column[vk_var]]),) else: vals += (vk_value,) @@ -662,27 +664,33 @@ def _get_vk_values(trafo_df, characteristic, trafotype="2W"): return vals -def _calc_tap_dependent_value(trafo_df, tap_pos, value, variable, tap_dependent_impedance, - characteristic, characteristic_idx): +def _calc_tap_dependent_value(tap_pos, value, tap_dependent_impedance, characteristic, characteristic_idx): # we skip the trafos with NaN characteristics even if tap_dependent_impedance is True (we already checked for missing characteristics) relevant_idx = tap_dependent_impedance & ~np.isnan(characteristic_idx) vk_characteristic = np.zeros_like(tap_dependent_impedance, dtype="object") vk_characteristic[relevant_idx] = characteristic.loc[characteristic_idx[relevant_idx], 'object'].values # here dtype must be float otherwise the load flow calculation will fail - return np.where(relevant_idx, - [c(t).item() if f else np.nan for f, t, c in zip(relevant_idx, tap_pos, vk_characteristic)], - value)#.astype(np.float64) # astype not necessary, but if it fails then uncommenting this may help + def custom_func(f, t, c): + return c(t).item() if f else np.nan -def _calc_r_x_from_dataframe(mode, trafo_df, vn_lv, vn_trafo_lv, sn_mva, sequence=1, - characteristic=None): + custom_func_vec = np.vectorize(custom_func) + return np.where(relevant_idx, custom_func_vec(relevant_idx, tap_pos, vk_characteristic), value) + + +def _calc_r_x_from_dataframe(mode, trafo_df, vn_lv, vn_trafo_lv, sn_mva, sequence=1, characteristic=None, + update_vk_values=True): """ Calculates (Vectorized) the resitance and reactance according to the transformer values """ parallel = get_trafo_values(trafo_df, "parallel") if sequence == 1: - vk_percent, vkr_percent = _get_vk_values(trafo_df, characteristic) + if update_vk_values: + vk_percent, vkr_percent = _get_vk_values(trafo_df, characteristic) + else: + vk_percent = get_trafo_values(trafo_df, "vk_percent") + vkr_percent = get_trafo_values(trafo_df, "vkr_percent") elif sequence == 0: vk_percent = get_trafo_values(trafo_df, "vk0_percent") @@ -706,7 +714,6 @@ def _calc_r_x_from_dataframe(mode, trafo_df, vn_lv, vn_trafo_lv, sn_mva, sequenc def _calc_nominal_ratio_from_dataframe(ppc, trafo_df, vn_hv_kv, vn_lv_kv, bus_lookup): """ Calculates (Vectorized) the off nominal tap ratio:: - (vn_hv_kv / vn_lv_kv) / (ub1_in_kv / ub2_in_kv) INPUT: @@ -966,8 +973,8 @@ def _branches_with_oos_buses(net, ppc, dc=False): t_bus = line_buses[:, 1] # determine on which side of the line the oos bus is located - mask_from = np.in1d(f_bus, bus_oos) - mask_to = np.in1d(t_bus, bus_oos) + mask_from = np.isin(f_bus, bus_oos) + mask_to = np.isin(t_bus, bus_oos) mask_and = mask_to & mask_from if np.any(mask_and): @@ -986,7 +993,7 @@ def _branches_with_oos_buses(net, ppc, dc=False): ls_info = np.zeros((n_oos_buses_at_lines, 3), dtype=np.int64) ls_info[:, 0] = mask_to[mask_or] & ~mask_from[mask_or] ls_info[:, 1] = oos_buses_at_lines - ls_info[:, 2] = np.nonzero(np.in1d(net[line_table].index, line_is_idx[mask_or]))[0] + ls_info[:, 2] = np.nonzero(np.isin(net[line_table].index, line_is_idx[mask_or]))[0] # ls_info = list(map(mapfunc, # line_switches["bus"].values, @@ -1156,7 +1163,7 @@ def get_is_lines(net): _is_elements["line"] = net["line"][net["line"]["in_service"].values.astype(bool)] -def _trafo_df_from_trafo3w(net, sequence=1): +def _trafo_df_from_trafo3w(net, sequence=1, update_vk_values=True): trafo2 = dict() sides = ["hv", "mv", "lv"] mode = net._options["mode"] @@ -1169,7 +1176,7 @@ def _trafo_df_from_trafo3w(net, sequence=1): if sequence==1: mode_tmp = "type_c" if mode == "sc" and net._options.get("use_pre_fault_voltage", False) else mode _calculate_sc_voltages_of_equivalent_transformers(t3, trafo2, mode_tmp, characteristic=net.get( - 'characteristic')) + 'characteristic'), update_vk_values=update_vk_values) elif sequence==0: if mode != "sc": raise NotImplementedError( @@ -1203,8 +1210,12 @@ def _trafo_df_from_trafo3w(net, sequence=1): return {var: np.concatenate([trafo2[var][side] for side in sides]) for var in trafo2.keys()} -def _calculate_sc_voltages_of_equivalent_transformers(t3, t2, mode, characteristic): - vk_hv, vkr_hv, vk_mv, vkr_mv, vk_lv, vkr_lv = _get_vk_values(t3, characteristic, "3W") +def _calculate_sc_voltages_of_equivalent_transformers(t3, t2, mode, characteristic, update_vk_values=True): + if update_vk_values: + vk_hv, vkr_hv, vk_mv, vkr_mv, vk_lv, vkr_lv = _get_vk_values(t3, characteristic, "3W") + else: + vk_hv, vkr_hv, vk_mv, vkr_mv, vk_lv, vkr_lv = (t3['vk_hv_percent'], t3['vkr_hv_percent'], t3['vk_mv_percent'], + t3['vkr_mv_percent'], t3['vk_lv_percent'], t3['vkr_lv_percent']) vk_3w = np.stack([vk_hv, vk_mv, vk_lv]) vkr_3w = np.stack([vkr_hv, vkr_mv, vkr_lv]) diff --git a/pandapower/converter/cim/cim_classes.py b/pandapower/converter/cim/cim_classes.py index 685d2c6ac..80cd72eab 100644 --- a/pandapower/converter/cim/cim_classes.py +++ b/pandapower/converter/cim/cim_classes.py @@ -12,8 +12,7 @@ from typing import Dict, List import pandas as pd import numpy as np -import xml.etree.ElementTree -import xml.etree.cElementTree as xmlET +from lxml import etree from .other_classes import ReportContainer, Report, LogLevel, ReportCode from .cim_tools import get_cim_schema @@ -389,7 +388,7 @@ def _parse_element(self, element, parsed=None): def _get_df(self, items): return pd.DataFrame([self._parse_element(child) for child in iter(items)]) - def _get_cgmes_profile_from_xml(self, root: xml.etree.ElementTree.Element, ignore_errors: bool = False, + def _get_cgmes_profile_from_xml(self, root: etree.Element, ignore_errors: bool = False, default_profile: str = 'unknown') -> str: """ Get the CGMES profile from the XML file. @@ -486,17 +485,16 @@ def _parse_source_file(self, file: str, output: dict, encoding: str, profile_nam temp_dir.cleanup() del temp_dir, temp_dir_path return - with open(file, mode='r', encoding=encoding, errors='ignore') as f: - cim_str = f.read() - xml_tree = xmlET.fromstring(cim_str) + parser = etree.XMLParser(encoding=encoding, resolve_entities=False) + xml_tree = etree.parse(file, parser) if profile_name is None: - prf = self._get_cgmes_profile_from_xml(xml_tree) + prf = self._get_cgmes_profile_from_xml(xml_tree.getroot()) else: prf = profile_name self.file_names[prf] = file - self._parse_xml_tree(xml_tree, prf, output) + self._parse_xml_tree(xml_tree.getroot(), prf, output) - def _parse_xml_tree(self, xml_tree: xmlET, profile_name: str, output: Dict | None = None): + def _parse_xml_tree(self, xml_tree: etree.ElementTree, profile_name: str, output: Dict | None = None): output = self.cim if output is None else output # get all CIM elements to parse element_types = pd.Series([ele.tag for ele in list(xml_tree)]) @@ -507,6 +505,8 @@ def _parse_xml_tree(self, xml_tree: xmlET, profile_name: str, output: Dict | Non if prf not in ns_dict.keys(): ns_dict[prf] = dict() for _, element_type in element_types.items(): + if not isinstance(element_type, str): + continue element_type_c = re.sub('{.*}', '', element_type) prf_content[element_type_c] = self._get_df(xml_tree.findall(element_type)) # rename the columns (remove the namespaces) diff --git a/pandapower/converter/powerfactory/pp_import_functions.py b/pandapower/converter/powerfactory/pp_import_functions.py index 73626a425..c6be0dda4 100644 --- a/pandapower/converter/powerfactory/pp_import_functions.py +++ b/pandapower/converter/powerfactory/pp_import_functions.py @@ -178,35 +178,35 @@ def from_pf(dict_net, pv_as_slack=True, pf_variable_p_loads='plini', pf_variable for n, fuse in enumerate(dict_net['RelFuse'], 1): create_coup(net=net, item=fuse, is_fuse=True) if n > 0: logger.info('imported %d fuses' % n) - + logger.debug('creating shunts') # create shunts (ElmShnt): n = 0 for n, shunt in enumerate(dict_net['ElmShnt'], 1): create_shunt(net=net, item=shunt) if n > 0: logger.info('imported %d shunts' % n) - + logger.debug('creating impedances') # create zpu (ElmZpu): n = 0 for n, zpu in enumerate(dict_net['ElmZpu'], 1): create_zpu(net=net, item=zpu) if n > 0: logger.info('imported %d impedances' % n) - + logger.debug('creating series inductivity as impedance') # create series inductivity as impedance (ElmSind): n = 0 for n, sind in enumerate(dict_net['ElmSind'], 1): create_sind(net=net, item=sind) if n > 0: logger.info('imported %d SIND' % n) - + logger.debug('creating series capacity as impedance') # create series capacity as impedance (ElmScap): n = 0 for n, scap in enumerate(dict_net['ElmScap'], 1): create_scap(net=net, item=scap) if n > 0: logger.info('imported %d SCAP' % n) - + logger.debug('creating static var compensator') # create static var compensator (SVC) with control same as voltage controlled synchron machine (ElmSvs): n = 0 @@ -214,7 +214,7 @@ def from_pf(dict_net, pv_as_slack=True, pf_variable_p_loads='plini', pf_variable create_svc(net=net, item=svc, pv_as_slack=pv_as_slack, pf_variable_p_gen=pf_variable_p_gen, dict_net=dict_net) if n > 0: logger.info('imported %d SVC' % n) - + # create vac (ElmVac): n = 0 for n, vac in enumerate(dict_net['ElmVac'], 1): @@ -637,10 +637,10 @@ def create_connection_switches(net, item, number_switches, et, buses, elements): cd = pp.create_switch(net, bus=buses[i], element=elements[i], et=et, closed=switch_is_closed, type=switch_usage, name=switch_name) net.res_switch.loc[cd, ['pf_closed', 'pf_in_service']] = switch_is_closed, True - + new_switch_idx.append(cd) new_switch_closed.append(switch_is_closed) - + return new_switch_idx, new_switch_closed @@ -774,11 +774,11 @@ def create_line(net, item, flag_graphics, create_sections, is_unbalanced): new_elements = (sid_list[0], sid_list[-1]) new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 'l', (params['bus1'], params['bus2']), new_elements) - # correct in_service of lines if station switch is open - # update_in_service_depending_station_switch(net, element_type="line", - # new_elements=new_elements, + # correct in_service of lines if station switch is open + # update_in_service_depending_station_switch(net, element_type="line", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, - # new_switch_closed=new_switch_closed) + # new_switch_closed=new_switch_closed) logger.debug('line <%s> created' % params['name']) @@ -1717,10 +1717,10 @@ def create_load(net, item, pf_variable_p_loads, dict_net, is_unbalanced): load_type.kqu] if (pf_params[:3]!=pf_params[3:]) or \ (pf_params[:2]!=[0,1]) or (pf_params[2] not in (0,2)) or \ - (pf_params[3:5]!=[0,1]) or (pf_params[5] not in (0,2)): + (pf_params[3:5]!=[0,1]) or (pf_params[5] not in (0,2)): # (pf_params[:3]!=[0,1,2]) or \ - # (pf_params[3:]!=[0,1,2]): - raise UserWarning(f"Load {item.loc_name} ({load_class}) unsupported voltage dependency configuration") + # (pf_params[3:]!=[0,1,2]): + raise UserWarning(f"Load {item.loc_name} ({load_class}) unsupported voltage dependency configuration") else: i_p = 0 z_p = 0 @@ -1734,14 +1734,14 @@ def create_load(net, item, pf_variable_p_loads, dict_net, is_unbalanced): i_p += 100 * c_p elif e_p == 2: z_p += 100 * c_p - + c_q = ga(load_type, cc_q) e_q = ga(load_type, ee_q) if e_q == 1: i_q += 100 * c_q elif e_q == 2: z_q += 100 * c_q - + params["const_i_p_percent"] = i_p params["const_z_p_percent"] = z_p params["const_i_q_percent"] = i_q @@ -1966,7 +1966,7 @@ def create_sgen_genstat(net, item, pv_as_slack, pf_variable_p_gen, dict_net, is_ # create... pstac = item.c_pstac # "None" if station controller is not available - if pstac is not None and pstac.outserv==0 and export_ctrl: + if pstac is not None and not pstac.outserv and export_ctrl: if pstac.i_droop: av_mode = 'constq' else: @@ -1989,13 +1989,13 @@ def create_sgen_genstat(net, item, pv_as_slack, pf_variable_p_gen, dict_net, is_ logger.debug('av_mode: %s - creating as gen' % av_mode) params.vm_pu = item.usetp del params['q_mvar'] - + # add reactive and active power limits params.min_q_mvar = item.cQ_min params.max_q_mvar = item.cQ_max params.min_p_mw = item.Pmin_uc params.max_p_mw = item.Pmax_uc - + sg = pp.create_gen(net, **params) element = 'gen' else: @@ -2008,7 +2008,7 @@ def create_sgen_genstat(net, item, pv_as_slack, pf_variable_p_gen, dict_net, is_ params.max_q_mvar = item.cQ_max params.min_p_mw = item.Pmin_uc params.max_p_mw = item.Pmax_uc - + sg = pp.create_sgen(net, **params) element = 'sgen' logger.debug('created sgen at index <%d>' % sg) @@ -2191,7 +2191,7 @@ def create_sgen_sym(net, item, pv_as_slack, pf_variable_p_gen, dict_net, export_ pstac = item.c_pstac # "None" if station controller is not available - if pstac is not None and pstac.outserv==0 and export_ctrl: + if pstac is not None and not pstac.outserv and export_ctrl: if pstac.i_droop: av_mode = 'constq' else: @@ -2214,31 +2214,31 @@ def create_sgen_sym(net, item, pv_as_slack, pf_variable_p_gen, dict_net, export_ logger.debug('creating sym %s as gen' % name) vm_pu = item.usetp if item.iqtype == 1: - type = item.typ_id + type = item.typ_id sid = pp.create_gen(net, bus=bus1, p_mw=p_mw, vm_pu=vm_pu, - min_q_mvar=type.Q_min, max_q_mvar=type.Q_max, + min_q_mvar=type.Q_min, max_q_mvar=type.Q_max, min_p_mw=item.Pmin_uc, max_p_mw=item.Pmax_uc, name=name, type=cat, in_service=in_service, scaling=global_scaling) else: sid = pp.create_gen(net, bus=bus1, p_mw=p_mw, vm_pu=vm_pu, - min_q_mvar=item.cQ_min, max_q_mvar=item.cQ_max, + min_q_mvar=item.cQ_min, max_q_mvar=item.cQ_max, min_p_mw=item.Pmin_uc, max_p_mw=item.Pmax_uc, - name=name, type=cat, in_service=in_service, scaling=global_scaling) + name=name, type=cat, in_service=in_service, scaling=global_scaling) element = 'gen' elif av_mode == 'constq': q_mvar = ngnum * item.qgini * multiplier if item.iqtype == 1: - type = item.typ_id + type = item.typ_id sid = pp.create_sgen(net, bus=bus1, p_mw=p_mw, q_mvar=q_mvar, - min_q_mvar=type.Q_min, max_q_mvar=type.Q_max, + min_q_mvar=type.Q_min, max_q_mvar=type.Q_max, min_p_mw=item.Pmin_uc, max_p_mw=item.Pmax_uc, name=name, type=cat, in_service=in_service, scaling=global_scaling) else: sid = pp.create_sgen(net, bus=bus1, p_mw=p_mw, q_mvar=q_mvar, - min_q_mvar=item.cQ_min, max_q_mvar=item.cQ_max, + min_q_mvar=item.cQ_min, max_q_mvar=item.cQ_max, min_p_mw=item.Pmin_uc, max_p_mw=item.Pmax_uc, - name=name, type=cat, in_service=in_service, scaling=global_scaling) - + name=name, type=cat, in_service=in_service, scaling=global_scaling) + element = 'sgen' if sid is None or element is None: @@ -2465,15 +2465,15 @@ def create_trafo(net, item, export_controller=True, tap_opt="nntap", is_unbalanc # adding switches # False if open, True if closed, None if no switch #create_connection_switches(net, item, 2, 't', (bus1, bus2), (tid, tid)) - + new_elements = (tid, tid) - new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 't', (bus1, bus2), + new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 't', (bus1, bus2), new_elements) - # correct in_service of trafo if station switch is open - # update_in_service_depending_station_switch(net, element_type="trafo", - # new_elements=new_elements, + # correct in_service of trafo if station switch is open + # update_in_service_depending_station_switch(net, element_type="trafo", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, - # new_switch_closed=new_switch_closed) + # new_switch_closed=new_switch_closed) # adding tap changer if (export_controller and pf_type.itapch and item.HasAttribute('ntrcn') and @@ -2648,12 +2648,12 @@ def create_trafo3w(net, item, tap_opt='nntap'): new_elements = (tid, tid, tid) new_switch_idx, new_switch_closed = create_connection_switches(net, item, 3, 't3', (bus1, bus2, bus3), new_elements) - - # correct in_service of trafo3w if station switch is open - # update_in_service_depending_station_switch(net, element_type="trafo3w", - # new_elements=new_elements, + + # correct in_service of trafo3w if station switch is open + # update_in_service_depending_station_switch(net, element_type="trafo3w", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, - # new_switch_closed=new_switch_closed) + # new_switch_closed=new_switch_closed) logger.debug('successfully created trafo3w from parameters: %d' % tid) # testen @@ -2910,7 +2910,7 @@ def create_zpu(net, item): } logger.debug('params = %s' % params) - + # create auxilary buses aux_bus1 = pp.create_bus(net, vn_kv=net.bus.vn_kv.at[bus1], name=net.bus.name.at[bus1]+'_aux', geodata=net.bus.geo.at[bus1], type="b", zone=net.bus.zone.at[bus1], @@ -2920,16 +2920,16 @@ def create_zpu(net, item): geodata=net.bus.geo.at[bus2], type="b", zone=net.bus.zone.at[bus2], in_service=True) params['to_bus'] = aux_bus2 - + xid = pp.create_impedance(net, **params) add_additional_attributes(item, net, element='impedance', element_id=xid, attr_list=["cpSite.loc_name"], attr_dict={"cimRdfId": "origin_id"}) - + # consider and create station switches new_elements = (aux_bus1, aux_bus2) new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 'b', (bus1, bus2), new_elements) - + if len(new_switch_idx)==0: net.impedance.loc[xid, 'from_bus'] = bus1 net.impedance.loc[xid, 'to_bus'] = bus2 @@ -2945,13 +2945,13 @@ def create_zpu(net, item): net.impedance.loc[xid, 'from_bus'] = bus1 # drop one auxilary bus, where no switch exists, not needed pp.drop_buses(net, buses=[aux_bus1]) - - # correct in_service of series reactor if station switch is open - # update_in_service_depending_station_switch(net, element_type="impedance", - # new_elements=new_elements, + + # correct in_service of series reactor if station switch is open + # update_in_service_depending_station_switch(net, element_type="impedance", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, # new_switch_closed=new_switch_closed) - + logger.debug('created ZPU %s as impedance at index %d' % (net.impedance.at[xid, 'name'], xid)) @@ -2965,7 +2965,7 @@ def create_vac(net, item): except IndexError: logger.error("Cannot add VAC '%s': not connected" % item.loc_name) return - + in_service = monopolar_in_service(item) params = { 'name': item.loc_name, @@ -3047,7 +3047,7 @@ def create_sind(net, item): except IndexError: logger.error("Cannot add Sind '%s': not connected" % item.loc_name) return - + # create auxilary buses aux_bus1 = pp.create_bus(net, vn_kv=net.bus.vn_kv.at[bus1], name=net.bus.name.at[bus1]+'_aux', geodata=net.bus.geo.at[bus1], type="b", zone=net.bus.zone.at[bus1], @@ -3055,17 +3055,17 @@ def create_sind(net, item): aux_bus2 = pp.create_bus(net, vn_kv=net.bus.vn_kv.at[bus2], name=net.bus.name.at[bus2]+'_aux', geodata=net.bus.geo.at[bus2], type="b", zone=net.bus.zone.at[bus2], in_service=True) - - sind = pp.create_series_reactor_as_impedance(net, from_bus=aux_bus1, to_bus=aux_bus2, + + sind = pp.create_series_reactor_as_impedance(net, from_bus=aux_bus1, to_bus=aux_bus2, r_ohm=item.rrea, x_ohm=item.xrea, sn_mva=item.Sn, name=item.loc_name, in_service=not bool(item.outserv)) - + # consider and create station switches new_elements = (aux_bus1, aux_bus2) new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 'b', (bus1, bus2), new_elements) - + if len(new_switch_idx)==0: net.impedance.loc[sind, 'from_bus'] = bus1 net.impedance.loc[sind, 'to_bus'] = bus2 @@ -3081,13 +3081,13 @@ def create_sind(net, item): net.impedance.loc[sind, 'from_bus'] = bus1 # drop one auxilary bus, where no switch exists, not needed pp.drop_buses(net, buses=[aux_bus1]) - - # correct in_service of series reactor if station switch is open - # update_in_service_depending_station_switch(net, element_type="impedance", - # new_elements=new_elements, + + # correct in_service of series reactor if station switch is open + # update_in_service_depending_station_switch(net, element_type="impedance", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, # new_switch_closed=new_switch_closed) - + logger.debug('created series reactor %s as per unit impedance at index %d' % (net.impedance.at[sind, 'name'], sind)) @@ -3105,25 +3105,25 @@ def create_scap(net, item): else: r_ohm = item.gcap/(item.gcap**2 + item.bcap**2) x_ohm = -item.bcap/(item.gcap**2 + item.bcap**2) - - # create auxilary buses + + # create auxilary buses aux_bus1 = pp.create_bus(net, vn_kv=net.bus.vn_kv.at[bus1], name=net.bus.name.at[bus1]+'_aux', geodata=net.bus.geo.at[bus1], type="b", zone=net.bus.zone.at[bus1], in_service=True) aux_bus2 = pp.create_bus(net, vn_kv=net.bus.vn_kv.at[bus2], name=net.bus.name.at[bus2]+'_aux', geodata=net.bus.geo.at[bus2], type="b", zone=net.bus.zone.at[bus2], in_service=True) - + scap = pp.create_series_reactor_as_impedance(net, from_bus=aux_bus1, to_bus=aux_bus2, r_ohm=r_ohm, x_ohm=x_ohm, sn_mva=item.Sn, name=item.loc_name, in_service=not bool(item.outserv)) - + # consider and create station switches new_elements = (aux_bus1, aux_bus2) new_switch_idx, new_switch_closed = create_connection_switches(net, item, 2, 'b', (bus1, bus2), new_elements) - + if len(new_switch_idx)==0: net.impedance.loc[scap, 'from_bus'] = bus1 net.impedance.loc[scap, 'to_bus'] = bus2 @@ -3139,32 +3139,32 @@ def create_scap(net, item): net.impedance.loc[scap, 'from_bus'] = bus1 # drop one auxilary bus, where no switch exists, not needed pp.drop_buses(net, buses=[aux_bus1]) - - # correct in_service of series capacitor if station switch is open - # update_in_service_depending_station_switch(net, element_type="impedance", - # new_elements=new_elements, + + # correct in_service of series capacitor if station switch is open + # update_in_service_depending_station_switch(net, element_type="impedance", + # new_elements=new_elements, # new_switch_idx=new_switch_idx, # new_switch_closed=new_switch_closed) logger.debug('created series capacitor %s as per unit impedance at index %d' % (net.impedance.at[scap, 'name'], scap)) - + def create_svc(net, item, pv_as_slack, pf_variable_p_gen, dict_net): # SVC is voltage controlled and therefore modelled the same way as a voltage controlled synchron machine (gen) # TODO: at least implement a uncontrolled svc as synchron machine with const. Q - # TODO: transfer item entries for usage of pp.create_svc, x_l_ohm, x_cvar_ohm, + # TODO: transfer item entries for usage of pp.create_svc, x_l_ohm, x_cvar_ohm, # thyristor_firing_angle must be computed name = item.loc_name sid = None element = None logger.debug('>> creating synchronous machine <%s>' % name) - + try: bus1 = get_connection_nodes(net, item, 1) except IndexError: logger.error("Cannot add SVC '%s': not connected" % name) return - + if item.i_ctrl==1: # 0: no control, 1: voltage control, 2: reactive power control logger.debug('creating SVC %s as gen' % name) vm_pu = item.usetp @@ -3172,15 +3172,15 @@ def create_svc(net, item, pv_as_slack, pf_variable_p_gen, dict_net): svc = pp.create_gen(net, bus=bus1[0], p_mw=0, vm_pu=vm_pu, name=name, type="SVC", in_service=in_service) element = 'gen' - + if svc is None or element is None: logger.error('Error! SVC not created') logger.debug('created svc at index <%s>' % svc) - + net[element].loc[svc, 'description'] = ' \n '.join(item.desc) if len(item.desc) > 0 else '' add_additional_attributes(item, net, element, svc, attr_dict={"for_name": "equipment"}, attr_list=["sernum", "chr_name", "cpSite.loc_name"]) - + if item.HasResults(0): # 'm' results... logger.debug('<%s> has results' % name) net['res_' + element].at[svc, "pf_p"] = ga(item, 'm:P:bus1') #* multiplier @@ -3188,7 +3188,7 @@ def create_svc(net, item, pv_as_slack, pf_variable_p_gen, dict_net): else: net['res_' + element].at[svc, "pf_p"] = np.nan net['res_' + element].at[svc, "pf_q"] = np.nan - else: + else: logger.info('not creating SVC for %s' % item.loc_name) @@ -3352,7 +3352,7 @@ def create_stactrl(net, item): #raise UserWarning("error while creating station controller: sgen names must be unique") else: duplicated_sgen_names = False - + gen_types = [] for s in machines: if s.ip_ctrl == 1: @@ -3388,11 +3388,11 @@ def create_stactrl(net, item): gen_element = gen_types[0] gen_element_index = [] - if duplicated_sgen_names==False: + if duplicated_sgen_names==False: for s in machines: gen_element_index.append(net[gen_element].loc[net[gen_element].name == s.loc_name].index.values[0]) else: - # check if gen_element has set controller + # check if gen_element has set controller for s in machines: gen_element_index_try = net[gen_element].loc[net[gen_element].name == s.loc_name].index.values if len(gen_element_index_try)==1: @@ -3404,7 +3404,7 @@ def create_stactrl(net, item): raise UserWarning("error while creating station controller: sgen and controler names must be unique") else: gen_element_index.append(gen_element_index_try_again[0]) - + if len(gen_element_index) != len(machines): raise UserWarning("station controller: could not properly identify the machines") @@ -3418,12 +3418,12 @@ def create_stactrl(net, item): elif m is not None and not isinstance(item.cvqq, list): distribution.append(item.cvqq / 100) i = i + 1 - + + if item.imode > 2: + raise NotImplementedError(f"{item}: reactive power distribution {item.imode=} not implemented") + if sum(distribution)!=1: logger.info(f'{item}: sum of reactive power dstribution is unequal to 1 but will be normalized in binary search control.') - - if item.imode>2: #!= 0: - raise NotImplementedError(f"{item}: reactive power distribution {item.imode} not implemented") phase = item.i_phase if phase != 0: diff --git a/pandapower/diagnostic.py b/pandapower/diagnostic.py index c52431dc6..29a32157f 100644 --- a/pandapower/diagnostic.py +++ b/pandapower/diagnostic.py @@ -8,7 +8,6 @@ import pandas as pd import numpy as np import pandapower as pp -from pandapower import replace_xward_by_ward try: import pandaplan.core.pplog as logging @@ -21,7 +20,7 @@ from pandapower.auxiliary import (LoadflowNotConverged, OPFNotConverged, ControllerNotConverged, NetCalculationNotConverged) from pandapower.run import runpp -from pandapower.toolbox import get_connected_elements +from pandapower.toolbox import get_connected_elements, replace_xward_by_ward from pandapower.diagnostic_reports import diagnostic_report # separator between log messages diff --git a/pandapower/io_utils.py b/pandapower/io_utils.py index 6058b0e08..63b49c55a 100644 --- a/pandapower/io_utils.py +++ b/pandapower/io_utils.py @@ -21,7 +21,7 @@ import pandas.errors from deepdiff.diff import DeepDiff from packaging.version import Version -from pandapower import __version__ +from pandapower._version import __version__ import networkx import numpy import geojson diff --git a/pandapower/networks/ieee_europen_lv_asymmetric.py b/pandapower/networks/ieee_europen_lv_asymmetric.py index 14292bd70..24a9f996d 100644 --- a/pandapower/networks/ieee_europen_lv_asymmetric.py +++ b/pandapower/networks/ieee_europen_lv_asymmetric.py @@ -5,7 +5,7 @@ import os import pandapower as pp -from pandapower import pp_dir +from pandapower.__init__ import pp_dir def ieee_european_lv_asymmetric(scenario="on_peak_566", **kwargs): diff --git a/pandapower/networks/lv_schutterwald.py b/pandapower/networks/lv_schutterwald.py index 714ba6e63..01839e84c 100644 --- a/pandapower/networks/lv_schutterwald.py +++ b/pandapower/networks/lv_schutterwald.py @@ -9,7 +9,7 @@ import pandapower as pp import pandapower.topology as top import pandapower.plotting.geo as geo -from pandapower import pp_dir +from pandapower.__init__ import pp_dir def lv_schutterwald(separation_by_sub=False, include_heat_pumps=False, **kwargs): diff --git a/pandapower/networks/mv_oberrhein.py b/pandapower/networks/mv_oberrhein.py index 4b566f549..c43abe314 100644 --- a/pandapower/networks/mv_oberrhein.py +++ b/pandapower/networks/mv_oberrhein.py @@ -10,8 +10,7 @@ import pandapower as pp import pandapower.topology as top -import pandapower.plotting.geo as geo -from pandapower import pp_dir +from pandapower.__init__ import pp_dir def mv_oberrhein(scenario="load", cosphi_load=0.98, cosphi_pv=1.0, include_substations=False, diff --git a/pandapower/networks/power_system_test_cases.py b/pandapower/networks/power_system_test_cases.py index 4854ee107..596ea0381 100644 --- a/pandapower/networks/power_system_test_cases.py +++ b/pandapower/networks/power_system_test_cases.py @@ -8,7 +8,8 @@ import pandapower as pp import pandapower.toolbox -from pandapower import pp_dir +from pandapower.file_io import from_json +from pandapower.__init__ import pp_dir import pandapower.plotting.geo as geo @@ -61,7 +62,7 @@ def _change_ref_bus(net, ref_bus_idx, ext_grid_p=0): def sorted_from_json(path, **kwargs): - net = pp.from_json(path, **kwargs) + net = from_json(path, **kwargs) for elm in pandapower.toolbox.pp_elements(): net[elm].sort_index(inplace=True) return net diff --git a/pandapower/pd2ppc.py b/pandapower/pd2ppc.py index 6992dc378..c72577a99 100644 --- a/pandapower/pd2ppc.py +++ b/pandapower/pd2ppc.py @@ -93,7 +93,7 @@ def _check_slack_at_vsc_bus(ppci): "this configuration is not implemented.") -def _pd2ppc(net, sequence=None): +def _pd2ppc(net, sequence=None, **kwargs): """ Converter Flow: 1. Create an empty pypower datatructure @@ -153,8 +153,10 @@ def _pd2ppc(net, sequence=None): # Calculates ppc0 branch impedances from branch elements _build_branch_ppc_zero(net, ppc) else: + # get config if trafo3w vk and vkr values should be recalculated + update_vk_values = kwargs.get("update_vk_values", True) # Calculates ppc1/ppc2 branch impedances from branch elements - _build_branch_ppc(net, ppc) + _build_branch_ppc(net, ppc, update_vk_values) _build_branch_dc_ppc(net, ppc) _build_tcsc_ppc(net, ppc, mode) diff --git a/pandapower/pd2ppc_zero.py b/pandapower/pd2ppc_zero.py index 8be6f32d2..e34ce4f90 100644 --- a/pandapower/pd2ppc_zero.py +++ b/pandapower/pd2ppc_zero.py @@ -11,7 +11,7 @@ from itertools import product import pandapower.auxiliary as aux -from pandapower import DC_NONE, DC_BUS_TYPE +from pandapower.pypower.idx_bus_dc import DC_NONE, DC_BUS_TYPE from pandapower.build_bus import _build_bus_ppc, _build_svc_ppc, _build_ssc_ppc, _build_vsc_ppc, _build_bus_dc_ppc from pandapower.build_gen import _build_gen_ppc # from pandapower.pd2ppc import _ppc2ppci, _init_ppc diff --git a/pandapower/pf/run_bfswpf.py b/pandapower/pf/run_bfswpf.py index 2f077ba8a..e73cafad7 100644 --- a/pandapower/pf/run_bfswpf.py +++ b/pandapower/pf/run_bfswpf.py @@ -73,8 +73,8 @@ def _make_bibc_bcbv(bus, branch, graph): # if multiple networks get subnetwork branches if norefs > 1: - branches_sub_mask = (np.in1d(branches_arr[:, 0], buses_ordered_bfs) & - np.in1d(branches_arr[:, 1], buses_ordered_bfs)) + branches_sub_mask = (np.isin(branches_arr[:, 0], buses_ordered_bfs) & + np.isin(branches_arr[:, 1], buses_ordered_bfs)) branches = np.sort(branches_arr[branches_sub_mask, :], axis=1) else: branches = np.sort(branches_arr, axis=1) @@ -252,7 +252,7 @@ def _bfswpf(DLF, bus, gen, branch, baseMVA, Ybus, Sbus, V0, ref, pv, pq, buses_o Ysh = _makeYsh_bfsw(bus, branch, baseMVA) # detect generators on PV buses which have status ON - gen_pv = np.in1d(gen[:, GEN_BUS], pv) & (gen[:, GEN_STATUS] > 0) + gen_pv = np.isin(gen[:, GEN_BUS], pv) & (gen[:, GEN_STATUS] > 0) qg_lim = np.zeros(ngen, dtype=bool) # initialize generators which violated Q limits Iinj = np.conj(Sbus / V0) - Ysh * V0 # Initial current injections diff --git a/pandapower/plotting/collections.py b/pandapower/plotting/collections.py index 02674e4b5..04f77cd5e 100644 --- a/pandapower/plotting/collections.py +++ b/pandapower/plotting/collections.py @@ -36,8 +36,7 @@ class TextPath: # so that the test does not fail pass -from pandapower import pandapowerNet -from pandapower.auxiliary import soft_dependency_error +from pandapower.auxiliary import soft_dependency_error, pandapowerNet from pandapower.plotting.patch_makers import load_patches, node_patches, gen_patches, \ sgen_patches, ext_grid_patches, trafo_patches, storage_patches, ward_patches, xward_patches, vsc_patches from pandapower.plotting.plotting_toolbox import _rotate_dim2, coords_from_node_geodata, \ diff --git a/pandapower/plotting/geo.py b/pandapower/plotting/geo.py index 36e673201..52926f3d1 100644 --- a/pandapower/plotting/geo.py +++ b/pandapower/plotting/geo.py @@ -18,7 +18,7 @@ from numpy import array import pandapower -from pandapower.auxiliary import soft_dependency_error +from pandapower.auxiliary import soft_dependency_error, pandapowerNet # get logger (same as in simple_plot) try: @@ -231,7 +231,7 @@ def convert_epsg_bus_geodata(net, epsg_in=4326, epsg_out=31467): return net -def convert_crs(net: pandapower.pandapowerNet or 'pandapipes.pandapipesNet', epsg_in=4326, epsg_out=31467): +def convert_crs(net: pandapowerNet or 'pandapipes.pandapipesNet', epsg_in=4326, epsg_out=31467): """ This function works for pandapowerNet and pandapipesNet. Documentation will refer to names from pandapower. Converts bus and line geodata in net from epsg_in to epsg_out @@ -285,7 +285,7 @@ def _geo_branch_transformer(r): def dump_to_geojson( - net: pandapower.pandapowerNet or 'pandapipes.pandapipesNet', + net: pandapowerNet or 'pandapipes.pandapipesNet', nodes: Union[bool, List[int]] = False, branches: Union[bool, List[int]] = False, switches: Union[bool, List[int]] = False, @@ -501,7 +501,7 @@ def update_props(r: pd.Series) -> None: def convert_geodata_to_geojson( - net: pandapower.pandapowerNet or 'pandapipes.pandapipesNet', + net: pandapowerNet or 'pandapipes.pandapipesNet', delete: bool = True, lonlat: bool = False) -> None: """ @@ -566,7 +566,7 @@ def convert_geodata_to_geojson( def convert_gis_to_geojson( - net: pandapower.pandapowerNet or 'pandapipes.pandapipesNet', + net: pandapowerNet or 'pandapipes.pandapipesNet', delete: bool = True) -> None: """ Transforms the bus and line geodataframes of a net into a geojson object. diff --git a/pandapower/plotting/plotly/mapbox_plot.py b/pandapower/plotting/plotly/mapbox_plot.py index bbb8795aa..d1ee39021 100644 --- a/pandapower/plotting/plotly/mapbox_plot.py +++ b/pandapower/plotting/plotly/mapbox_plot.py @@ -91,7 +91,7 @@ def geo_data_to_latlong(net, projection): def set_mapbox_token(token): - from pandapower import pp_dir + from pandapower.__init__ import pp_dir path = os.path.join(pp_dir, "plotting", "plotly") filename = os.path.join(path, 'mapbox_token.txt') with open(filename, "w") as mapbox_file: @@ -99,7 +99,7 @@ def set_mapbox_token(token): def _get_mapbox_token(): - from pandapower import pp_dir + from pandapower.__init__ import pp_dir path = os.path.join(pp_dir, "plotting", "plotly") filename = os.path.join(path, 'mapbox_token.txt') with open(filename, "r") as mapbox_file: diff --git a/pandapower/powerflow.py b/pandapower/powerflow.py index 574f21e56..243a04ebb 100644 --- a/pandapower/powerflow.py +++ b/pandapower/powerflow.py @@ -59,7 +59,7 @@ def _powerflow(net, **kwargs): "branch": array([], dtype=int64), "branch_dc": array([], dtype=int64)} # convert pandapower net to ppc - ppc, ppci = _pd2ppc(net) + ppc, ppci = _pd2ppc(net, **kwargs) # store variables net["_ppc"] = ppc @@ -81,6 +81,7 @@ def _recycled_powerflow(net, **kwargs): algorithm = options["algorithm"] ac = options["ac"] recycle = options["recycle"] + update_vk_values = kwargs.get("update_vk_values", True) ppci = {"bus": net["_ppc"]["internal"]["bus"], "gen": net["_ppc"]["internal"]["gen"], "branch": net["_ppc"]["internal"]["branch"], @@ -104,9 +105,9 @@ def _recycled_powerflow(net, **kwargs): # update trafo in branch and Ybus lookup = net._pd2ppc_lookups["branch"] if "trafo" in lookup: - _calc_trafo_parameter(net, ppc) + _calc_trafo_parameter(net, ppc, update_vk_values=update_vk_values) if "trafo3w" in lookup: - _calc_trafo3w_parameter(net, ppc) + _calc_trafo3w_parameter(net, ppc, update_vk_values=update_vk_values) if "gen" in recycle and recycle["gen"]: # updates the ppc["gen"] part diff --git a/pandapower/pypower/newtonpf.py b/pandapower/pypower/newtonpf.py index 6a4003635..a22fee238 100644 --- a/pandapower/pypower/newtonpf.py +++ b/pandapower/pypower/newtonpf.py @@ -14,19 +14,18 @@ from numpy import float64, array, angle, sqrt, square, exp, linalg, conj, r_, inf, arange, zeros, \ max, zeros_like, column_stack, flatnonzero, nan_to_num from pandapower.pypower.bustypes import bustypes_dc -from pandapower.pypower.idx_brch_dc import DC_BR_R, DC_PF, DC_IF, DC_PT, DC_IT, DC_BR_STATUS +from pandapower.pypower.idx_brch_dc import DC_BR_R, DC_PF, DC_IF, DC_PT, DC_IT, DC_BR_STATUS, DC_F_BUS, DC_T_BUS from scipy.sparse import csr_matrix, eye, vstack from scipy.sparse.linalg import spsolve from pandapower.auxiliary import _sum_by_group -from pandapower import VSC_STATUS, VSC_BUS, VSC_INTERNAL_BUS, DC_F_BUS, DC_T_BUS from pandapower.pf.iwamoto_multiplier import _iwamoto_step from pandapower.pf.makeYbus_facts import makeYbus_svc, makeYft_tcsc, calc_y_svc_pu, \ makeYbus_ssc_vsc, make_Ybus_facts, make_Yft_facts -from pandapower.pypower.idx_bus_dc import DC_PD, DC_VM, DC_BUS_TYPE, DC_NONE, DC_BUS_I, DC_REF, DC_P, DC_B2B, DC_BASE_KV +from pandapower.pypower.idx_bus_dc import DC_PD, DC_VM, DC_BUS_TYPE, DC_NONE, DC_BUS_I, DC_REF, DC_P from pandapower.pypower.idx_vsc import VSC_CONTROLLABLE, VSC_MODE_AC, VSC_VALUE_AC, VSC_MODE_DC, VSC_VALUE_DC, VSC_R, \ VSC_X, VSC_Q, VSC_P, VSC_BUS_DC, VSC_P_DC, VSC_MODE_AC_SL, VSC_MODE_AC_V, VSC_MODE_AC_Q, VSC_MODE_DC_P, \ - VSC_MODE_DC_V, VSC_INTERNAL_BUS_DC, VSC_R_DC, VSC_PL_DC + VSC_MODE_DC_V, VSC_INTERNAL_BUS_DC, VSC_R_DC, VSC_PL_DC, VSC_STATUS, VSC_BUS, VSC_INTERNAL_BUS from pandapower.pypower.makeSbus import makeSbus from pandapower.pf.create_jacobian import create_jacobian_matrix, get_fastest_jacobian_function from pandapower.pypower.idx_gen import PG diff --git a/pandapower/results_bus.py b/pandapower/results_bus.py index 3fbde81e0..4981d35e3 100644 --- a/pandapower/results_bus.py +++ b/pandapower/results_bus.py @@ -7,7 +7,6 @@ import numpy as np import pandas as pd from numpy import complex128 -from pandapower import VSC_INTERNAL_BUS from pandapower.auxiliary import _sum_by_group, sequence_to_phase, _sum_by_group_nvals from pandapower.pypower.idx_bus import VM, VA, PD, QD, LAM_P, LAM_Q, BASE_KV, NONE, BS, BUS_TYPE, BUS_I from pandapower.pypower.idx_bus_dc import DC_VM, DC_BUS_TYPE, DC_NONE, DC_PD, DC_BUS_I @@ -16,7 +15,7 @@ from pandapower.build_bus import _get_motor_pq, _get_symmetric_pq_of_unsymetric_element from pandapower.pypower.idx_ssc import SSC_X_CONTROL_VM, SSC_X_CONTROL_VA, SSC_Q, SSC_INTERNAL_BUS from pandapower.pypower.idx_svc import SVC_THYRISTOR_FIRING_ANGLE, SVC_Q, SVC_X_PU -from pandapower.pypower.idx_vsc import VSC_Q, VSC_P, VSC_P_DC, VSC_BUS_DC, VSC_INTERNAL_BUS_DC +from pandapower.pypower.idx_vsc import VSC_Q, VSC_P, VSC_P_DC, VSC_BUS_DC, VSC_INTERNAL_BUS_DC, VSC_INTERNAL_BUS try: import pandaplan.core.pplog as logging diff --git a/pandapower/run.py b/pandapower/run.py index 456a9b9eb..e026ca67d 100644 --- a/pandapower/run.py +++ b/pandapower/run.py @@ -225,6 +225,7 @@ def runpp(net, algorithm='nr', calculate_voltage_angles=True, init="auto", **tdpf_update_r_theta** (bool, True) - TDPF parameter, whether to update R_Theta in Newton-Raphson or to assume a constant R_Theta (either from net.line.r_theta, if set, or from a calculation based on the thermal model of Ngoko et.al.) + **update_vk_values** (bool, True) - If True vk and vkr values of trafo3w are recalculated based on characteristics, otherwise the values from the table are used. Can improve performance for large models. """ # if dict 'user_pf_options' is present in net, these options overrule the net._options diff --git a/pandapower/shortcircuit/ppc_conversion.py b/pandapower/shortcircuit/ppc_conversion.py index c31d469bb..923297a73 100644 --- a/pandapower/shortcircuit/ppc_conversion.py +++ b/pandapower/shortcircuit/ppc_conversion.py @@ -25,7 +25,7 @@ def _get_is_ppci_bus(net, bus): - is_bus = bus[np.in1d(bus, net._is_elements_final["bus_is_idx"])] + is_bus = bus[np.isin(bus, net._is_elements_final["bus_is_idx"])] ppci_bus = np.unique(net._pd2ppc_lookups["bus"][is_bus]) return ppci_bus diff --git a/pandapower/shortcircuit/toolbox.py b/pandapower/shortcircuit/toolbox.py index 8c93fb6ee..47529d50d 100644 --- a/pandapower/shortcircuit/toolbox.py +++ b/pandapower/shortcircuit/toolbox.py @@ -77,10 +77,10 @@ def detect_power_station_unit(net, mode="auto", # Check parallel trafo if not len(np.intersect1d(connected_bus_at_lv_side, trafo_lv_bus)) == 1: raise UserWarning("Failure in power station units detection! Parallel trafos on generator detected!") - if np.in1d(required_gen_bus, gen_bus_at_lv_side).sum() > 1: + if np.isin(required_gen_bus, gen_bus_at_lv_side).sum() > 1: logger.info("More than 1 gen detected at the lv side of a power station trafo! Will not be considered as power station unit") continue - net.gen.loc[np.in1d(net.gen.bus.values, gen_bus_at_lv_side), + net.gen.loc[np.isin(net.gen.bus.values, gen_bus_at_lv_side), "power_station_trafo"] = t_ix diff --git a/pandapower/test/__init__.py b/pandapower/test/__init__.py index 7b985f732..0611f8b4b 100644 --- a/pandapower/test/__init__.py +++ b/pandapower/test/__init__.py @@ -1,5 +1,5 @@ import os -from pandapower import pp_dir +from pandapower.__init__ import pp_dir test_path = os.path.join(pp_dir, 'test') tutorials_path = os.path.join(os.path.dirname(pp_dir), 'tutorials') diff --git a/pandapower/test/loadflow/test_results.py b/pandapower/test/loadflow/test_results.py index 9f5c98e8a..58dc709ed 100644 --- a/pandapower/test/loadflow/test_results.py +++ b/pandapower/test/loadflow/test_results.py @@ -6,7 +6,7 @@ import pandas as pd import pytest import numpy as np -from numpy import in1d, isnan, isclose, allclose +from numpy import isin, isnan, isclose, allclose import pandapower as pp import pandapower.control @@ -815,7 +815,7 @@ def test_shunt_split(result_test_network, v_tol=1e-6, i_tol=1e-6, s_tol=5e-3, l_ def test_open(result_test_network): net = result_test_network buses = net.bus[net.bus.zone == "two_open_switches_on_deactive_line"] - lines = net['line'][in1d(net['line'].from_bus, buses.index) | in1d(net['line'].to_bus, buses.index)] + lines = net['line'][isin(net['line'].from_bus, buses.index) | isin(net['line'].to_bus, buses.index)] assert isnan(net['res_line'].at[lines.index[1], "i_ka"]) diff --git a/pandapower/test/loadflow/test_runpp.py b/pandapower/test/loadflow/test_runpp.py index f36d88161..e6c7e764b 100644 --- a/pandapower/test/loadflow/test_runpp.py +++ b/pandapower/test/loadflow/test_runpp.py @@ -578,6 +578,17 @@ def test_bsfw_algorithm_with_branch_loops(): assert np.allclose(va_nr, va_alg) +def test_disabling_vk_update(): + net = example_simple() + pp.runpp(net, calculate_voltage_angles="auto") + net.trafo.loc[:, "vk_percent"] = 100. + net.trafo.loc[:, "vkr_percent"] = 100. + + pp.runpp(net, calculate_voltage_angles="auto", update_vk_values=False) + + assert net.res_trafo.loc[0, 'loading_percent'] > 70. + + @pytest.mark.slow def test_pypower_algorithms_iter(): alg_to_test = ['fdbx', 'fdxb', 'gs'] diff --git a/pandapower/timeseries/read_batch_results.py b/pandapower/timeseries/read_batch_results.py index 3f6f1c352..44cf62346 100644 --- a/pandapower/timeseries/read_batch_results.py +++ b/pandapower/timeseries/read_batch_results.py @@ -2,7 +2,7 @@ from numpy import real, vectorize, deg2rad, maximum, sqrt, empty, zeros, nan, int64 -from pandapower import F_BUS, T_BUS +from pandapower.pypower.idx_brch import F_BUS, T_BUS from pandapower.pf.pfsoln_numba import calc_branch_flows_batch from pandapower.pypower.idx_bus import BASE_KV from pandapower.results_branch import _get_trafo3w_lookups diff --git a/pandapower/timeseries/run_time_series.py b/pandapower/timeseries/run_time_series.py index 5822b8d98..d382cb8cd 100644 --- a/pandapower/timeseries/run_time_series.py +++ b/pandapower/timeseries/run_time_series.py @@ -7,8 +7,7 @@ import tqdm import pandapower as pp -from pandapower import LoadflowNotConverged, OPFNotConverged -from pandapower.auxiliary import ControllerNotConverged, NetCalculationNotConverged +from pandapower.auxiliary import ControllerNotConverged from pandapower.control import prepare_run_ctrl, run_control from pandapower.control.util.diagnostic import control_diagnostic from pandapower.timeseries.output_writer import OutputWriter diff --git a/pandapower/toolbox/element_selection.py b/pandapower/toolbox/element_selection.py index a473b80c6..dc606e7dd 100644 --- a/pandapower/toolbox/element_selection.py +++ b/pandapower/toolbox/element_selection.py @@ -12,7 +12,7 @@ from pandapower.auxiliary import ets_to_element_types -from pandapower import __version__ +from pandapower._version import __version__ try: import pandaplan.core.pplog as logging diff --git a/pandapower/topology/create_graph.py b/pandapower/topology/create_graph.py index 0b1d07cab..cc6b06f69 100644 --- a/pandapower/topology/create_graph.py +++ b/pandapower/topology/create_graph.py @@ -148,7 +148,7 @@ def create_nxgraph(net, respect_switches=True, include_lines=True, include_imped mask = (net.switch.et.values == "l") & open_sw if mask.any(): open_lines = net.switch.element.values[mask] - open_lines_mask = np.in1d(indices[:, INDEX], open_lines) + open_lines_mask = np.isin(indices[:, INDEX], open_lines) in_service &= ~open_lines_mask parameter[:, WEIGHT] = line.length_km.values @@ -221,7 +221,7 @@ def create_nxgraph(net, respect_switches=True, include_lines=True, include_imped mask = (net.switch.et.values == "t") & open_sw if mask.any(): open_trafos = net.switch.element.values[mask] - open_trafos_mask = np.in1d(indices[:, INDEX], open_trafos) + open_trafos_mask = np.isin(indices[:, INDEX], open_trafos) in_service &= ~open_trafos_mask if calc_branch_impedances: @@ -264,7 +264,7 @@ def create_nxgraph(net, respect_switches=True, include_lines=True, include_imped if respect_switches and len(open_trafo3w): for BUS in [F_BUS, T_BUS]: - open_switch = np.in1d(indices[:, INDEX] + indices[:, BUS] * 1j, + open_switch = np.isin(indices[:, INDEX] + indices[:, BUS] * 1j, open_trafo3w) in_service &= ~open_switch if calc_branch_impedances: diff --git a/pyproject.toml b/pyproject.toml index 06b2411a8..e55eee3ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ dependencies = [ "tqdm", "deepdiff", "geojson", + "lxml", "typing_extensions~=4.9", ] keywords = [