Skip to content

Commit

Permalink
Merge pull request #2211 from SteffenMeinecke/develop
Browse files Browse the repository at this point in the history
toolbox and auxiliary functions
  • Loading branch information
rbolgaryn authored Mar 26, 2024
2 parents 82a5a9b + a25061c commit f7d0f1c
Show file tree
Hide file tree
Showing 19 changed files with 184 additions and 93 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Change Log
- [FIXED] avoid attaching elements as duplicates to a group where some of the elements already exist
- [ADDED] the function :code:`run_contingency` can raise a captured error if parameter :code:`raise_errors` is passed
- [FIXED] bugfix for tap dependent impedance characteristics so that not all characteristics columns are necessary
- [ADDED] add kwargs passing of get_equivalent() to runpp_fct()
- [ADDED] auxiliary functions ets_to_element_types() and element_types_to_ets() as well as toolbox function get_connected_buses_at_switches() and extension to get_connected_switches()
- [FIXED] in function :code:`toolbox.replace_zero_branches_with_switches`, use absolute for the parameters of impedance elements in case they are negative nonzero values
- [FIXED] in :code:`reindex_elements`: fixed index error when reindexing line_geodata
- [FIXED] bug in :code:`cim2pp`: Changed zero prioritized generators with voltage controller to sgens (like PowerFactory does)
Expand Down
23 changes: 23 additions & 0 deletions pandapower/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,29 @@ def plural_s(number):
else:
return ""


def ets_to_element_types(ets=None):
ser = pd.Series(["bus", "line", "trafo", "trafo3w", "impedance"],
index=["b", "l", "t", "t3", "i"])
if ets is None:
return ser
elif isinstance(ets, str):
return ser.at[ets]
else:
return list(ser.loc[ets])


def element_types_to_ets(element_types=None):
ser1 = ets_to_element_types()
ser2 = pd.Series(ser1.index, index=list(ser1))
if element_types is None:
return ser2
elif isinstance(ets, str):
return ser2.at[element_types]
else:
return list(ser2.loc[element_types])


def _preserve_dtypes(df, dtypes):
for item, dtype in list(dtypes.items()):
if df.dtypes.at[item] != dtype:
Expand Down
7 changes: 2 additions & 5 deletions pandapower/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -2689,7 +2689,7 @@ def create_transformer(net, hv_bus, lv_bus, std_type, name=None, tap_pos=nan, in
_set_value_if_not_nan(net, index, xn_ohm, "xn_ohm", "trafo")

# tap_phase_shifter default False
net.trafo.tap_phase_shifter.fillna(False, inplace=True)
net.trafo.tap_phase_shifter = net.trafo.tap_phase_shifter.fillna(False)
if "tap2_phase_shifter" in net.trafo.columns:
net.trafo.tap2_phase_shifter = net.trafo.tap2_phase_shifter.fillna(False).astype(bool_)

Expand Down Expand Up @@ -5046,10 +5046,7 @@ def check_entry(val):
net[table][col] = val

# extend the table by the frame we just created
try:
net[table] = pd.concat([net[table], dd], sort=False)
except ValueError:
net[table] = pd.concat([net[table], dd[dd.columns]], sort=False)
net[table] = pd.concat([net[table], dd[dd.columns[~dd.isnull().all()]]], sort=False)


# and preserve dtypes
Expand Down
11 changes: 6 additions & 5 deletions pandapower/grid_equivalents/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def _runpp_except_voltage_angles(net, **kwargs):

def add_ext_grids_to_boundaries(net, boundary_buses, adapt_va_degree=False,
runpp_fct=_runpp_except_voltage_angles,
calc_volt_angles=True, allow_net_change_for_convergence=False):
calc_volt_angles=True, allow_net_change_for_convergence=False,
**kwargs):
"""
adds ext_grids for the given network. If the bus results are
available, ext_grids are created according to the given bus results;
Expand Down Expand Up @@ -77,7 +78,7 @@ def add_ext_grids_to_boundaries(net, boundary_buses, adapt_va_degree=False,
net.gen.slack = False
try:
runpp_fct(net, calculate_voltage_angles=calc_volt_angles,
max_iteration=100)
max_iteration=100, **kwargs)
except pp.LoadflowNotConverged as e:
if allow_net_change_for_convergence:

Expand All @@ -89,7 +90,7 @@ def add_ext_grids_to_boundaries(net, boundary_buses, adapt_va_degree=False,
for no, idx in enumerate(imp_neg):
net.impedance.loc[idx, ["rft_pu", "rtf_pu", "xft_pu", "xtf_pu"]] *= -1
try:
runpp_fct(net, calculate_voltage_angles=True, max_iteration=100)
runpp_fct(net, calculate_voltage_angles=True, max_iteration=100, **kwargs)
logger.warning("The sign of these impedances were changed to enable a power"
f" flow: {imp_neg[:no]}")
break
Expand All @@ -109,7 +110,7 @@ def add_ext_grids_to_boundaries(net, boundary_buses, adapt_va_degree=False,
if changes:
try:
runpp_fct(net, calculate_voltage_angles=calc_volt_angles,
max_iteration=100)
max_iteration=100, **kwargs)
logger.warning("Reactances of these impedances has been increased to "
f"enable a power flow: {is2small}")
except pp.LoadflowNotConverged as e:
Expand All @@ -132,7 +133,7 @@ def add_ext_grids_to_boundaries(net, boundary_buses, adapt_va_degree=False,
va_ave = va.sum() / va.shape[0]
net.ext_grid.va_degree.loc[add_eg] -= va_ave
runpp_fct(net, calculate_voltage_angles=calc_volt_angles,
max_iteration=100)
max_iteration=100, **kwargs)
return orig_slack_gens


Expand Down
5 changes: 3 additions & 2 deletions pandapower/grid_equivalents/get_equivalent.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ def get_equivalent(net, eq_type, boundary_buses, internal_buses,
# --- create reference buses
orig_slack_gens = add_ext_grids_to_boundaries(
net, boundary_buses, adapt_va_degree, calc_volt_angles=calculate_voltage_angles,
allow_net_change_for_convergence=allow_net_change_for_convergence, runpp_fct=runpp_fct)
allow_net_change_for_convergence=allow_net_change_for_convergence, runpp_fct=runpp_fct,
**kwargs)

# --- replace ward and xward elements by internal elements (load, shunt, impedance, gen)
ext_buses_with_ward = net.ward.bus[net.ward.bus.isin(all_external_buses)]
Expand All @@ -169,7 +170,7 @@ def get_equivalent(net, eq_type, boundary_buses, internal_buses,
# --- switch from ward injection to ward addmittance if requested
if eq_type in ["ward", "xward"] and ward_type == "ward_admittance":
create_passive_external_net_for_ward_admittance(
net, all_external_buses, boundary_buses, runpp_fct=runpp_fct)
net, all_external_buses, boundary_buses, runpp_fct=runpp_fct, **kwargs)

# --- rei calculations
if eq_type == "rei":
Expand Down
16 changes: 8 additions & 8 deletions pandapower/grid_equivalents/rei_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def _create_net_zpbn(net, boundary_buses, all_internal_buses, all_external_buses

net_internal, net_external = _get_internal_and_external_nets(
net, boundary_buses, all_internal_buses, all_external_buses,
show_computing_time, calc_volt_angles=calc_volt_angles, runpp_fct=runpp_fct)
show_computing_time, calc_volt_angles=calc_volt_angles, runpp_fct=runpp_fct, **kwargs)
net_zpbn = net_external
# --- remove buses without power flow results in net_eq
pp.drop_buses(net_zpbn, net_zpbn.res_bus.index[net_zpbn.res_bus.vm_pu.isnull()])
Expand Down Expand Up @@ -510,7 +510,7 @@ def _create_bus_lookups(net_zpbn, boundary_buses, all_internal_buses,
def _get_internal_and_external_nets(net, boundary_buses, all_internal_buses,
all_external_buses, show_computing_time=False,
calc_volt_angles=True,
runpp_fct=_runpp_except_voltage_angles):
runpp_fct=_runpp_except_voltage_angles, **kwargs):
"This function identifies the internal area and the external area"
t_start = time.perf_counter()
if not all_internal_buses:
Expand All @@ -531,11 +531,11 @@ def _get_internal_and_external_nets(net, boundary_buses, all_internal_buses,
drop_measurements_and_controllers(net_external, net_external.bus.index.tolist())
pp.drop_buses(net_external, all_internal_buses)
replace_motor_by_load(net_external, all_external_buses)
# add_ext_grids_to_boundaries(net_external, boundary_buses, runpp_fct=runpp_fct)
# runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles)
# add_ext_grids_to_boundaries(net_external, boundary_buses, runpp_fct=runpp_fct, **kwargs)
# runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles, **kwargs)
_integrate_power_elements_connected_with_switch_buses(net, net_external,
all_external_buses) # for sgens, gens, and loads
runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles)
runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles, **kwargs)
t_end = time.perf_counter()
if show_computing_time:
logger.info("\"get_int_and_ext_nets\" " +
Expand Down Expand Up @@ -605,7 +605,7 @@ def _calclate_equivalent_element_params(net_zpbn, Ybus_eq, bus_lookups,
def _replace_ext_area_by_impedances_and_shunts(
net_eq, bus_lookups, impedance_params, shunt_params, net_internal,
return_internal, show_computing_time=False, calc_volt_angles=True, imp_threshold=1e-8,
runpp_fct=_runpp_except_voltage_angles):
runpp_fct=_runpp_except_voltage_angles, **kwargs):
"""
This function implements the parameters of the equivalent shunts and equivalent impedance
"""
Expand All @@ -616,7 +616,7 @@ def _replace_ext_area_by_impedances_and_shunts(

try:
runpp_fct(net_eq, calculate_voltage_angles=calc_volt_angles,
tolerance_mva=1e-6, max_iteration=100)
tolerance_mva=1e-6, max_iteration=100, **kwargs)
except:
logger.error("The power flow did not converge.")

Expand Down Expand Up @@ -684,7 +684,7 @@ def _replace_ext_area_by_impedances_and_shunts(
raise ValueError(msg)

runpp_fct(net_eq, calculate_voltage_angles=calc_volt_angles,
tolerance_mva=1e-6, max_iteration=100)
tolerance_mva=1e-6, max_iteration=100, **kwargs)


def _integrate_power_elements_connected_with_switch_buses(net, net_external, all_external_buses):
Expand Down
18 changes: 9 additions & 9 deletions pandapower/grid_equivalents/ward_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _calculate_ward_and_impedance_parameters(Ybus_eq, bus_lookups, show_computin
return ward_parameter, impedance_parameter


def _calculate_xward_and_impedance_parameters(net_external, Ybus_eq, bus_lookups,
def _calculate_xward_and_impedance_parameters(net_external, Ybus_eq, bus_lookups,
show_computing_time, power_eq=0):
"""calculates the xwards and the equivalent impedance"""
t_start = time.perf_counter()
Expand All @@ -76,7 +76,7 @@ def _calculate_xward_and_impedance_parameters(net_external, Ybus_eq, bus_lookups

def create_passive_external_net_for_ward_admittance(
net, all_external_buses, boundary_buses, calc_volt_angles=True,
runpp_fct=_runpp_except_voltage_angles):
runpp_fct=_runpp_except_voltage_angles, **kwargs):
"""
This function replace the wards and xward in external network by internal
elements, and replace the power injections in external area by shunts
Expand Down Expand Up @@ -105,20 +105,20 @@ def create_passive_external_net_for_ward_admittance(
for elm in ["sgen", "gen", "load", "storage"]:
target_idx = net[elm].index[net[elm].bus.isin(all_external_buses)]
net[elm].drop(target_idx, inplace=True)
runpp_fct(net, calculate_voltage_angles=calc_volt_angles)
runpp_fct(net, calculate_voltage_angles=calc_volt_angles, **kwargs)


def _replace_external_area_by_wards(net_external, bus_lookups, ward_parameter_no_power,
impedance_parameter, ext_buses_with_xward,
show_computing_time, calc_volt_angles=True,
runpp_fct=_runpp_except_voltage_angles):
runpp_fct=_runpp_except_voltage_angles, **kwargs):
t_start = time.perf_counter()
"""replaces the external networks by wards and equivalent impedance"""
# --- drop all external elements
e_buses_pd = bus_lookups["bus_lookup_pd"]["e_area_buses"]
pp.drop_buses(net_external, e_buses_pd)
drop_internal_branch_elements(net_external, bus_lookups["boundary_buses_inclusive_bswitch"])
# runpp_fct(net_external, calculate_voltage_angles=True)
# runpp_fct(net_external, calculate_voltage_angles=True, **kwargs)

# --- drop shunt elements attached to boundary buses
traget_shunt_idx = net_external.shunt.index[net_external.shunt.bus.isin(bus_lookups[
Expand Down Expand Up @@ -166,7 +166,7 @@ def _replace_external_area_by_wards(net_external, bus_lookups, ward_parameter_no
eq_power.loc[len(eq_power)] = new_eq_power
assert len(eq_power.bus) == len(set(eq_power.bus)) # only one slack at individual bus

runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles)
runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles, **kwargs)

eq_power.p_mw -= \
pd.concat([net_external.res_ext_grid.p_mw, net_external.res_gen.p_mw[slack_gen]])
Expand All @@ -193,8 +193,8 @@ def _replace_external_area_by_wards(net_external, bus_lookups, ward_parameter_no

def _replace_external_area_by_xwards(net_external, bus_lookups, xward_parameter_no_power,
impedance_parameter, ext_buses_with_xward,
show_computing_time, calc_volt_angles=True,
runpp_fct=_runpp_except_voltage_angles):
show_computing_time, calc_volt_angles=True,
runpp_fct=_runpp_except_voltage_angles, **kwargs):
"""replaces the external networks by xwards and equivalent impedance"""
t_start = time.perf_counter()
# --- drop all external elements
Expand Down Expand Up @@ -250,7 +250,7 @@ def _replace_external_area_by_xwards(net_external, bus_lookups, xward_parameter_
assert len(eq_power.bus) == len(set(eq_power.bus)) # only one slack at individual bus

runpp_fct(net_external, calculate_voltage_angles=calc_volt_angles,
tolerance_mva=1e-6, max_iteration=100)
tolerance_mva=1e-6, max_iteration=100, **kwargs)

eq_power.p_mw -= \
pd.concat([net_external.res_ext_grid.p_mw, net_external.res_gen.p_mw[slack_gen]])
Expand Down
14 changes: 7 additions & 7 deletions pandapower/networks/cigre_networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Copyright (c) 2016-2023 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.


import io
from pandas import read_json
from numpy import nan
import pandapower as pp
Expand Down Expand Up @@ -127,12 +127,12 @@ def create_cigre_network_hv(length_km_6a_6b=0.1):
pp.create_shunt(net_cigre_hv, bus6a, p_mw=0.0, q_mvar=-180, name='Shunt 6a')

# Bus geo data
net_cigre_hv.bus_geodata = read_json(
net_cigre_hv.bus_geodata = read_json(io.StringIO(
"""{"x":{"0":4,"1":8,"2":20,"3":16,"4":12,"5":8,"6":12,"7":4,"8":20,"9":0,"10":8,"11":24,
"12":16},"y":{"0":8.0,"1":8.0,"2":8.0,"3":8.0,"4":8.0,"5":6.0,"6":4.5,"7":1.0,"8":1.0,
"9":8.0,"10":12.0,"11":8.0,"12":4.5},
"coords":{"0":NaN,"1":NaN,"2":NaN,"3":NaN,"4":NaN,"5":NaN,"6":NaN,"7":NaN,"8":NaN,
"9":NaN,"10":NaN,"11":NaN,"12":NaN}}""")
"9":NaN,"10":NaN,"11":NaN,"12":NaN}}"""))
# Match bus.index
net_cigre_hv.bus_geodata = net_cigre_hv.bus_geodata.loc[net_cigre_hv.bus.index]
return net_cigre_hv
Expand Down Expand Up @@ -285,13 +285,13 @@ def create_cigre_network_mv(with_der=False):
name='Residential fuel cell 2', type='Residential fuel cell')

# Bus geo data
net_cigre_mv.bus_geodata = read_json(
net_cigre_mv.bus_geodata = read_json(io.StringIO(
"""{"x":{"0":7.0,"1":4.0,"2":4.0,"3":4.0,"4":2.5,"5":1.0,"6":1.0,"7":8.0,"8":8.0,"9":6.0,
"10":4.0,"11":4.0,"12":10.0,"13":10.0,"14":10.0},
"y":{"0":16,"1":15,"2":13,"3":11,"4":9,
"5":7,"6":3,"7":3,"8":5,"9":5,"10":5,"11":7,"12":15,"13":11,"14":5},
"coords":{"0":NaN,"1":NaN,"2":NaN,"3":NaN,"4":NaN,"5":NaN,"6":NaN,"7":NaN,"8":NaN,
"9":NaN,"10":NaN,"11":NaN,"12":NaN,"13":NaN,"14":NaN}}""")
"9":NaN,"10":NaN,"11":NaN,"12":NaN,"13":NaN,"14":NaN}}"""))
# Match bus.index
net_cigre_mv.bus_geodata = net_cigre_mv.bus_geodata.loc[net_cigre_mv.bus.index]
return net_cigre_mv
Expand Down Expand Up @@ -513,7 +513,7 @@ def create_cigre_network_lv():
pp.create_switch(net_cigre_lv, bus0, busC0, et='b', closed=True, type='CB', name='S3')

# Bus geo data
net_cigre_lv.bus_geodata = read_json(
net_cigre_lv.bus_geodata = read_json(io.StringIO(
"""{"x":{"0":0.2,"1":0.2,"2":-1.4583333333,"3":-1.4583333333,"4":-1.4583333333,
"5":-1.9583333333,"6":-2.7083333333,"7":-2.7083333333,"8":-3.2083333333,"9":-3.2083333333,
"10":-3.2083333333,"11":-3.7083333333,"12":-0.9583333333,"13":-1.2083333333,
Expand All @@ -532,7 +532,7 @@ def create_cigre_network_lv():
"9":NaN,"10":NaN,"11":NaN,"12":NaN,"13":NaN,"14":NaN,"15":NaN,"16":NaN,"17":NaN,
"18":NaN,"19":NaN,"20":NaN,"21":NaN,"22":NaN,"23":NaN,"24":NaN,"25":NaN,"26":NaN,
"27":NaN,"28":NaN,"29":NaN,"30":NaN,"31":NaN,"32":NaN,"33":NaN,"34":NaN,"35":NaN,
"36":NaN,"37":NaN,"38":NaN,"39":NaN,"40":NaN,"41":NaN,"42":NaN,"43":NaN}}""")
"36":NaN,"37":NaN,"38":NaN,"39":NaN,"40":NaN,"41":NaN,"42":NaN,"43":NaN}}"""))
# Match bus.index
net_cigre_lv.bus_geodata = net_cigre_lv.bus_geodata.loc[net_cigre_lv.bus.index]
return net_cigre_lv
2 changes: 1 addition & 1 deletion pandapower/networks/create_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def example_multivoltage():
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
net.switch.loc[open_switch_id, "closed"] = False

# LV
# Bus-line switches
Expand Down
4 changes: 2 additions & 2 deletions pandapower/opf/validate_opf_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def _check_necessary_opf_parameters(net, logger):
net[element_type].controllable.fillna(True, inplace=True)
else: # 'sgen', 'load', 'storage'
net[element_type].controllable.fillna(False, inplace=True)
controllables = net[element_type].index[net[element_type].controllable.astype(
bool)]
controllables = net[element_type].index[net[
element_type].controllable.astype(bool)]
else:
controllables = net[element_type].index if element_type == 'gen' else []

Expand Down
2 changes: 1 addition & 1 deletion pandapower/protection/run_protection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def calculate_protection_times(net, scenario="sc"):
if scenario != "sc" and scenario != "pp":
raise ValueError("scenario must be either sc or op")

protection_devices = net.protection.query("in_service").object.values
protection_devices = net.protection.loc[net.protection.in_service, "object"].values
protection_results = []

for p in protection_devices:
Expand Down
4 changes: 2 additions & 2 deletions pandapower/test/api/test_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def test_detach_and_compare():
pp.detach_from_group(net, 3, "trafo", 1)
assert pp.group_element_lists(net, 3)[0] == ["trafo"]
assert pp.group_element_lists(net, 3)[1] == [typed_list([0, 2], type_)]
assert pp.group_element_lists(net, 3)[2] == [None if type_ is int else "name"]
assert pp.group_element_lists(net, 3)[2] == [np.nan if type_ is int else "name"]


def test_res_power():
Expand Down Expand Up @@ -466,4 +466,4 @@ def test_elements_connected_to_group():


if __name__ == "__main__":
pytest.main([__file__, "-xs"])
pytest.main([__file__, "-xs"])
Loading

0 comments on commit f7d0f1c

Please sign in to comment.