Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement of toolbox replace functions (e.g. gen replacement by sgens) #2487

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Change Log
- [ADDED] converter for European EHV grid data from JAO, the "Single Allocation Platform (SAP) for all European Transmission System Operators (TSOs) that operate in accordance to EU legislation"
- [ADDED] Add GeographicalRegion and SubGeographicalRegion names and ids to bus df in cim converter
- [CHANGED] Capitalize first letter of columns busbar_id, busbar_name and substation_id in bus df for cim converter
- [CHANGED] toolbox replace functions (e.g. gen replacement by sgens): improved result table implementation and added profiles consideration
- [FIXED] Do not modify pandas options when importing pandapower
- [FIXED] fixed copy-paste error in contingency results "max_limit_nminus1" and "min_limit_nminus1"
- [ADDED] improved lightsim2grid documentation including compatibitliy issues
Expand Down
153 changes: 98 additions & 55 deletions pandapower/toolbox/grid_modification.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,26 +1099,14 @@
_replace_group_member_element_type(net, index, "impedance", new_index, "line",
detach_from_gr=False)
drop_elements_simple(net, "impedance", index)
return new_index

# --- result data
_adapt_result_tables_in_replace_functions(net, "impedance", index, "line", new_index)

def _replace_group_member_element_type(
net, old_elements, old_element_type, new_elements, new_element_type, detach_from_gr=True):
assert not isinstance(old_element_type, set)
assert not isinstance(new_element_type, set)
old_elements = pd.Series(old_elements)
new_elements = pd.Series(new_elements)
# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "impedance", index, "line", new_index)

check_unique_group_rows(net)
gr_et = net.group.loc[net.group.element_type == old_element_type]
for gr_index in gr_et.index:
isin = old_elements.isin(gr_et.at[gr_index, "element_index"])
if any(isin):
attach_to_group(net, gr_index, new_element_type, [new_elements.loc[isin].tolist()],
reference_columns=gr_et.at[gr_index, "reference_column"])
if detach_from_gr:
detach_from_groups(net, old_element_type, old_elements) # sometimes done afterwarts when
# dropping the old elements
return new_index


def replace_line_by_impedance(net, index=None, sn_mva=None, only_valid_replace=True):
Expand Down Expand Up @@ -1180,6 +1168,13 @@
_replace_group_member_element_type(net, index, "line", new_index, "impedance",
detach_from_gr=False)
drop_lines(net, index)

# --- result data
_adapt_result_tables_in_replace_functions(net, "line", index, "impedance", new_index)

# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "line", index, "impedance", new_index)

return new_index


Expand Down Expand Up @@ -1264,12 +1259,11 @@
new_idx, net[table]["element"].dtypes)

# --- result data
if net.res_ext_grid.shape[0]:
in_res = pd.Series(ext_grids).isin(net["res_ext_grid"].index).values
to_add = net.res_ext_grid.loc[pd.Index(ext_grids)[in_res]]
to_add.index = pd.Index(new_idx)[in_res]
net.res_gen = pd.concat([net.res_gen, to_add], sort=True)
net.res_ext_grid = net.res_ext_grid.drop(pd.Index(ext_grids)[in_res])
_adapt_result_tables_in_replace_functions(net, "ext_grid", ext_grids, "gen", new_idx)

# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "ext_grid", ext_grids, "gen", new_idx)

return new_idx


Expand Down Expand Up @@ -1346,12 +1340,11 @@
net[table].loc[to_change, "element"] = new_idx

# --- result data
if net.res_gen.shape[0]:
in_res = pd.Series(gens).isin(net["res_gen"].index).values
to_add = net.res_gen.loc[pd.Index(gens)[in_res]]
to_add.index = pd.Index(new_idx)[in_res]
net.res_ext_grid = pd.concat([net.res_ext_grid, to_add], sort=True)
net.res_gen = net.res_gen.drop(pd.Index(gens)[in_res])
_adapt_result_tables_in_replace_functions(net, "gen", gens, "ext_grid", new_idx)

# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "gen", gens, "ext_grid", new_idx)

return new_idx


Expand Down Expand Up @@ -1431,12 +1424,11 @@
new_idx, net[table]["element"].dtypes)

# --- result data
if net.res_gen.shape[0]:
in_res = pd.Series(gens).isin(net["res_gen"].index).values
to_add = net.res_gen.loc[pd.Index(gens)[in_res]]
to_add.index = pd.Index(new_idx)[in_res]
net.res_sgen = pd.concat([net.res_sgen, to_add], sort=True)
net.res_gen = net.res_gen.drop(pd.Index(gens)[in_res])
_adapt_result_tables_in_replace_functions(net, "gen", gens, "sgen", new_idx)

# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "gen", gens, "sgen", new_idx)

return new_idx


Expand Down Expand Up @@ -1531,13 +1523,12 @@
net[table].loc[to_change, "et"] = "gen"
net[table].loc[to_change, "element"] = new_idx

# --- result data
if net.res_sgen.shape[0]:
in_res = pd.Series(sgens).isin(net["res_sgen"].index).values
to_add = net.res_sgen.loc[pd.Index(sgens)[in_res]]
to_add.index = pd.Index(new_idx)[in_res]
net.res_gen = pd.concat([net.res_gen, to_add], sort=True)
net.res_sgen = net.res_sgen.drop(pd.Index(sgens)[in_res])
# --- adapt result data
_adapt_result_tables_in_replace_functions(net, "sgen", sgens, "gen", new_idx)

# --- adapt profiles
_adapt_profiles_in_replace_functions(net, "sgen", sgens, "gen", new_idx)

return new_idx


Expand Down Expand Up @@ -1652,14 +1643,14 @@
net[table].loc[to_change, "element"] = np.array(
new_idx, net[table]["element"].dtypes)


# --- result data
if net["res_" + old_element_type].shape[0]:
in_res = pd.Series(old_indices).isin(net["res_" + old_element_type].index).values
to_add = net["res_" + old_element_type].loc[pd.Index(old_indices)[in_res]]
to_add.index = pd.Index(new_idx)[in_res]
net["res_" + new_element_type] = pd.concat([net["res_" + new_element_type], to_add], sort=True)
net["res_" + old_element_type] = net["res_" + old_element_type].drop(pd.Index(old_indices)[in_res])
_adapt_result_tables_in_replace_functions(
net, old_element_type, old_indices, new_element_type, new_idx)

# --- adapt profiles
_adapt_profiles_in_replace_functions(
net, old_element_type, old_indices, new_element_type, new_idx)

return new_idx


Expand Down Expand Up @@ -1722,8 +1713,7 @@
drop_elements_simple(net, "ward", wards)


def replace_xward_by_internal_elements(net, xwards=None, set_xward_bus_limits=False,
log_level="warning"):
def replace_xward_by_internal_elements(net, xwards=None, set_xward_bus_limits=False):
"""
Replaces xward by loads, shunts, impedance and generators

Expand All @@ -1735,9 +1725,6 @@
indices of xwards which should be replaced. If None, all xwards are replaced, by default None
set_xward_bus_limits : bool, optional
if True, the buses internal in xwards get vm limits from the connected buses
log_level : str, optional
logging level of the message which element types of net2 got reindexed elements. Options
are, for example "debug", "info", "warning", "error", or None, by default "info"

Returns
-------
Expand Down Expand Up @@ -1775,7 +1762,7 @@
# --- result data
if net.res_xward.shape[0]:
log_to_level("Implementations to move xward results to new internal elements are missing.",
logger, log_level)
logger, "info")
net.res_xward = net.res_xward.drop(xwards)

# --- drop replaced wards
Expand Down Expand Up @@ -1813,6 +1800,9 @@
The function ensures that the group membership and associated element type of the replaced
elements are updated accordingly.
"""
# TODO: parameter `drop` is implemented only to this replace function. needed if yes why not
# implementing at the other replace functions?

index = list(ensure_iterability(index)) if index is not None else list(net.impedance.index)

new_index = []
Expand All @@ -1829,3 +1819,56 @@
else:
net.xward.loc[index, "in_service"] = False
return new_index


def _replace_group_member_element_type(
net, old_elements, old_element_type, new_elements, new_element_type, detach_from_gr=True):
assert not isinstance(old_element_type, set)
assert not isinstance(new_element_type, set)
old_elements = pd.Series(old_elements)
new_elements = pd.Series(new_elements)

check_unique_group_rows(net)
gr_et = net.group.loc[net.group.element_type == old_element_type]
for gr_index in gr_et.index:
isin = old_elements.isin(gr_et.at[gr_index, "element_index"])
if any(isin):
attach_to_group(net, gr_index, new_element_type, [new_elements.loc[isin].tolist()],
reference_columns=gr_et.at[gr_index, "reference_column"])
if detach_from_gr:
detach_from_groups(net, old_element_type, old_elements) # sometimes done afterwarts when
# dropping the old elements


def _adapt_result_tables_in_replace_functions(
net, element_type_old, element_index_old, element_type_new, element_index_new):
et_old, et_new = "res_" + element_type_old, "res_" + element_type_new
idx_old, idx_new = pd.Index(element_index_old), pd.Index(element_index_new)
if net[et_old].shape[0]:
in_res = pd.Series(idx_old).isin(net[et_old].index).values
to_add = net[et_old].loc[idx_old[in_res]]
to_add.index = idx_new[in_res]
net[et_new] = pd.concat([net[et_new], to_add], sort=True)
net[et_old] = net[et_old].drop(idx_old[in_res])


def _adapt_profiles_in_replace_functions(
net, element_type_old, element_index_old, element_type_new, element_index_new
):
if "profiles" not in net or not isinstance(net.profiles, dict):
return
et_old, et_new = element_type_old, element_type_new
idx_old, idx_new = pd.Index(element_index_old), pd.Index(element_index_new)

Check warning on line 1861 in pandapower/toolbox/grid_modification.py

View check run for this annotation

Codecov / codecov/patch

pandapower/toolbox/grid_modification.py#L1860-L1861

Added lines #L1860 - L1861 were not covered by tests

keys_old = [key for key in net.profiles.keys() if (

Check warning on line 1863 in pandapower/toolbox/grid_modification.py

View check run for this annotation

Codecov / codecov/patch

pandapower/toolbox/grid_modification.py#L1863

Added line #L1863 was not covered by tests
key.startswith(f"{et_old}.") or key.startswith(f"res_{et_old}."))]
for key_old in keys_old:
key_new = key_old.replace(et_old, et_new)
in_prof = pd.Series(idx_old).isin(net.profiles[key_old].columns).values
to_add = net.profiles[key_old].loc[:, idx_old[in_prof]]
to_add.columns = idx_new[in_prof]
if key_new in net.profiles.keys():
net.profiles[key_new] = pd.concat([net.profiles[key_new], to_add], sort=True)

Check warning on line 1871 in pandapower/toolbox/grid_modification.py

View check run for this annotation

Codecov / codecov/patch

pandapower/toolbox/grid_modification.py#L1865-L1871

Added lines #L1865 - L1871 were not covered by tests
else:
net.profiles[key_new] = to_add
net.profiles[key_old] = net.profiles[key_old].drop(idx_old[in_prof], axis=1)

Check warning on line 1874 in pandapower/toolbox/grid_modification.py

View check run for this annotation

Codecov / codecov/patch

pandapower/toolbox/grid_modification.py#L1873-L1874

Added lines #L1873 - L1874 were not covered by tests
Loading