Skip to content

Commit

Permalink
Merge branch 'develop' into remove_pytest_7_limit
Browse files Browse the repository at this point in the history
  • Loading branch information
rbolgaryn authored Nov 21, 2023
2 parents 8ba4490 + 4767992 commit c35eb7b
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Change Log
- [ADDED] matplotlib v3.8.0 support (fixed :code:`plotting_colormaps.ipynb`)
- [CHANGED] PowerFactory converter - name :code:`for_name` as :code:`equipment` for all elements; also add to line
- [ADDED] option to use a second tap changer for the trafo element
- [CHANGED] parameters of function merge_internal_net_and_equivalent_external_net()
- [FIXED] :code:`convert_format.py`: update the attributes of the characteristic objects to match the new characteristic


Expand Down
34 changes: 21 additions & 13 deletions pandapower/grid_equivalents/get_equivalent.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ def get_equivalent(net, eq_type, boundary_buses, internal_buses,
if return_internal:
logger.debug("Merging of internal and equivalent network begins.")
net_eq = merge_internal_net_and_equivalent_external_net(
net_eq, net_internal, eq_type, show_computing_time,
net_eq, net_internal, show_computing_time=show_computing_time,
calc_volt_angles=calculate_voltage_angles)
if len(orig_slack_gens):
net_eq.gen.slack.loc[net_eq.gen.index.intersection(orig_slack_gens)] = True
Expand Down Expand Up @@ -327,8 +327,7 @@ def get_equivalent(net, eq_type, boundary_buses, internal_buses,


def merge_internal_net_and_equivalent_external_net(
net_eq, net_internal, eq_type, show_computing_time=False,
calc_volt_angles=False, **kwargs):
net_eq, net_internal, fuse_bus_column="auto", show_computing_time=False, **kwargs):
"""
Merges the internal network and the equivalent external network.
It is expected that the boundaries occur in both, equivalent net and
Expand All @@ -340,9 +339,11 @@ def merge_internal_net_and_equivalent_external_net(
**net_internal** - internal area
**eq_type** (str) - equivalent type, such as "rei", "ward" or "xward"
OPTIONAL:
**fuse_bus_column** (str, "auto) - the function expects boundary buses to be in net_eq and
in net_internal. These duplicate buses get fused. To identify these buses, the given column is used. Option "auto" provides backward compatibility which is: use "name_equivalent" if
existing and "name" otherwise
**show_computing_time** (bool, False)
****kwargs** - key word arguments for pp.merge_nets()
Expand All @@ -368,17 +369,24 @@ def merge_internal_net_and_equivalent_external_net(
merged_net = pp.merge_nets(
net_internal, net_eq, validate=kwargs.pop("validate", False),
net2_reindex_log_level=kwargs.pop("net2_reindex_log_level", "debug"), **kwargs)
try:
merged_net.gen.max_p_mw[-len(net_eq.gen.max_p_mw):] = net_eq.gen.max_p_mw.values
merged_net.gen.min_p_mw[-len(net_eq.gen.max_p_mw):] = net_eq.gen.min_p_mw.values
except:
pass

# --- fuse or combine the boundary buses in external and internal nets
busname_col = "name_equivalent" if "name_equivalent" in merged_net.bus.columns.tolist() else "name"
if fuse_bus_column == "auto":
if fuse_bus_column in merged_net.bus.columns:
raise ValueError(
f"{fuse_bus_column=} is ambiguous since the column 'auto' exists in net.bus")
if "name_equivalent" in merged_net.bus.columns:
fuse_bus_column = "name_equivalent"
else:
fuse_bus_column = "name"
for bus in boundary_buses_inclusive_bswitch:
name = merged_net.bus[busname_col].loc[bus]
target_buses = merged_net.bus.index[merged_net.bus[busname_col] == name]
try:
name = merged_net.bus[fuse_bus_column].loc[bus]
except:
print(fuse_bus_column)
print(merged_net.bus.columns)
print()
target_buses = merged_net.bus.index[merged_net.bus[fuse_bus_column] == name]
if len(target_buses) != 2:
raise ValueError(
"The code expects all boundary buses to occur double. One because "
Expand Down
6 changes: 5 additions & 1 deletion pandapower/grid_equivalents/rei_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,11 +673,15 @@ def _replace_ext_area_by_impedances_and_shunts(
"p_mw": shunt_params.parameter.values.real * net_eq.sn_mva
}, index=range(max_idx+1, max_idx+1+shunt_params.shape[0]))
new_shunts["name"] = "eq_shunt"
new_shunts["vn_kv"] = net_eq.bus.vn_kv.loc[new_shunts.bus.values].values
isin_sh = new_shunts.bus.isin(net_eq.bus.index)
new_shunts.loc[isin_sh, "vn_kv"] = net_eq.bus.vn_kv.loc[new_shunts.bus.loc[isin_sh]].values
new_shunts["step"] = 1
new_shunts["max_step"] = 1
new_shunts["in_service"] = True
net_eq["shunt"] = pd.concat([net_eq["shunt"], new_shunts])
if n_disconnected_new_eq_shunts := sum(~isin_sh):
msg = f"{n_disconnected_new_eq_shunts=}, missing buses: {new_shunts.bus.loc[~isin_sh]}"
raise ValueError(msg)

runpp_fct(net_eq, calculate_voltage_angles=calc_volt_angles,
tolerance_mva=1e-6, max_iteration=100)
Expand Down
53 changes: 27 additions & 26 deletions pandapower/test/grid_equivalents/test_get_equivalent.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def run_basic_usecases(eq_type, net=None):

# UC3: merge eq_net3 with subnet_rest
eq_net3 = pp.grid_equivalents.merge_internal_net_and_equivalent_external_net(
eq_net3a, subnet_rest, eq_type)
eq_net3a, subnet_rest)
pp.runpp(eq_net3, calculate_voltage_angles=True)
assert pandapower.toolbox.nets_equal(net, create_test_net())
return eq_net1, eq_net2, eq_net3
Expand Down Expand Up @@ -315,7 +315,8 @@ def test_case9_with_slack_generator_in_external_net():
"impedance": 6}, check_all_pp_elements=True)
# merge eq_net with internal net to get a power flow runable net to check the results
eq_net3.gen.slack = True
eq_net4 = pp.grid_equivalents.merge_internal_net_and_equivalent_external_net(eq_net3, ib_net, eq_type)
eq_net4 = pp.grid_equivalents.merge_internal_net_and_equivalent_external_net(
eq_net3, ib_net)
pp.runpp(eq_net4)
check_res_bus(net, eq_net4)
elif "ward" in eq_type:
Expand Down Expand Up @@ -457,7 +458,7 @@ def test_retain_original_internal_indices():
net_eq = pp.grid_equivalents.get_equivalent(net, eq_type, boundary_buses, internal_buses,
calculate_voltage_angles=True,
retain_original_internal_indices=True)

assert net_eq.sgen.index.tolist()[:3] == sgen_idxs[:3]
assert set(net_eq.line.index.tolist()) - set(line_idxs) == set()
assert set(net_eq.bus.index.tolist()[:-2]) - set(bus_idxs) == set()
Expand All @@ -471,14 +472,14 @@ def test_switch_sgens():
pp.create_switch(net, 9, 1, "b")
pp.create_sgen(net, 9, 10, 10)
pp.runpp(net)
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0])
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0])
assert max(net.res_bus.vm_pu[[0, 3, 4, 8]].values - net_eq.res_bus.vm_pu[[0, 3, 4, 8]].values) < 1e-6
assert max(net.res_bus.va_degree[[0, 3, 4, 8]].values - net_eq.res_bus.va_degree[[0, 3, 4, 8]].values) < 1e-6


def test_characteristic():
net = pp.networks.example_multivoltage()
pp.control.create_trafo_characteristics(net, "trafo", [1], 'vk_percent',
pp.control.create_trafo_characteristics(net, "trafo", [1], 'vk_percent',
[[-2,-1,0,1,2]], [[2,3,4,5,6]])
pp.runpp(net)
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [41], [0])
Expand All @@ -490,12 +491,12 @@ def test_controller():
pp.replace_gen_by_sgen(net)
pp.create_load(net, 5, 10, 10)
pp.create_sgen(net, 3, 1, 1)

net.sgen.loc[:, "type"] = "wind"
net.load.loc[:, "type"] = "residential"
net.sgen.name = ["sgen0", "sgen1", "sgen3"]
net.load.name = ["load0", "load1", "load2", "load3"]

# load time series
json_path = os.path.join(pp_dir, "test", "opf", "cigre_timeseries_15min.json")
time_series = pd.read_json(json_path)
Expand All @@ -515,12 +516,12 @@ def test_controller():
ConstControl(net, element="sgen", variable="p_mw",
element_index=net.sgen.index.tolist(), profile_name=net.sgen.index.tolist(),
data_source=DFData(sgen_ts))

pp.runpp(net)

# getting equivalent
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0])

assert net_eq.controller.object[0].__dict__["element_index"] == [0, 2]
assert net_eq.controller.object[0].__dict__["matching_params"]["element_index"] == [0, 2]
for i in net.controller.index:
Expand All @@ -529,7 +530,7 @@ def test_controller():
assert set(net_eq.controller.object[i].__dict__["profile_name"]) - \
set(net.controller.object[i].__dict__["profile_name"]) == set([])

net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
retain_original_internal_indices=True)
assert net_eq.controller.object[0].__dict__["element_index"] == [0, 2]
assert net_eq.controller.object[0].__dict__["matching_params"]["element_index"] == [0, 2]
Expand All @@ -540,7 +541,7 @@ def test_controller():
ConstControl(net, element='load', variable='p_mw', element_index=[li],
data_source=DFData(load_ts), profile_name=[li])
assert len(net.controller) == 4
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
retain_original_internal_indices=True)
assert net_eq.controller.index.tolist() == [0, 2]

Expand All @@ -556,14 +557,14 @@ def test_motor():
pp.runpp(net)
values1 = net.res_bus.vm_pu.values.copy()

for eq in ["rei", "ward", "xward"]:
net_eq = pp.grid_equivalents.get_equivalent(net, eq, [4, 8], [0],
for eq in ["rei", "ward", "xward"]:
net_eq = pp.grid_equivalents.get_equivalent(net, eq, [4, 8], [0],
retain_original_internal_indices=True,
show_computing_time=True)

assert max(net_eq.res_bus.vm_pu[[0,3,4,8]].values - net.res_bus.vm_pu[[0,3,4,8]].values) < 1e-8
assert net_eq.motor.bus.values.tolist() == [3, 4]

replace_motor_by_load(net, net.bus.index.tolist())
assert len(net.motor) == 0
assert len(net.res_motor) == 0
Expand All @@ -572,7 +573,7 @@ def test_motor():
assert net.res_load.loc[4].values.tolist() == [0, 0]
pp.runpp(net)
values2 = net.res_bus.vm_pu.values.copy()
assert max(values1 - values2) < 1e-10
assert max(values1 - values2) < 1e-10


def test_sgen_bswitch():
Expand All @@ -582,11 +583,11 @@ def test_sgen_bswitch():
pp.create_sgen(net, 1, 5, in_service=False)
pp.runpp(net)
net.sgen.name = ["aa", "bb", "cc", "dd"]
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
retain_original_internal_indices=True)
assert net_eq.sgen.name[0] == 'aa//cc//dd-sgen_separate_rei_1'
assert net_eq.sgen.p_mw[0] == 173

net = pp.networks.case9()
pp.replace_gen_by_sgen(net)
pp.create_bus(net, 345)
Expand All @@ -597,24 +598,24 @@ def test_sgen_bswitch():
pp.create_switch(net, 1, 10, "b")
net.sgen.name = ["aa", "bb", "cc", "dd"]
pp.runpp(net)
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0],
retain_original_internal_indices=True)

assert net_eq.sgen.name[0] == 'aa//cc-sgen_separate_rei_1'
assert net_eq.sgen.p_mw[0] == 173

# add some columns for test
net.bus["voltLvl"]=1
net.sgen["col_mixed"] = ["1", 2, None, True]
net.sgen["col_same_str"] = ["str_test", "str_test", "str_test", "str_test"]
net.sgen["col_different_str"] = ["str_1", "str_2", "str_3", "str_4"]
net.sgen["bool"] = [False, True, False, False]
net.sgen["voltLvl"] = [1, 1, 1, 1]
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0])
net_eq = pp.grid_equivalents.get_equivalent(net, "rei", [4, 8], [0])
assert net_eq.sgen["col_mixed"][0] == "mixed data type"
assert net_eq.sgen["col_same_str"][0] == "str_test"
assert net_eq.sgen["col_different_str"][0] == "str_3//str_1"
assert net_eq.sgen["col_different_str"][1] == "str_2"
assert net_eq.sgen["col_different_str"][1] == "str_2"
assert net_eq.sgen["bool"][0] == False
assert net_eq.sgen["bool"][1] == True
assert net_eq.sgen["voltLvl"].values.tolist() == [1, 1]
Expand All @@ -624,12 +625,12 @@ def test_ward_admittance():
net = pp.networks.case9()
pp.runpp(net)
res_bus = net.res_bus.copy()
create_passive_external_net_for_ward_admittance(net, [1, 2, 5, 6, 7],
create_passive_external_net_for_ward_admittance(net, [1, 2, 5, 6, 7],
[4,8], True,
_runpp_except_voltage_angles)
assert len(net.shunt)==3
assert np.allclose(net.res_bus.vm_pu.values, res_bus.vm_pu.values)


if __name__ == "__main__":
pytest.main(['-x', __file__])
2 changes: 1 addition & 1 deletion pandapower/toolbox/grid_modification.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def select_subnet(net, buses, include_switch_buses=False, include_results=False,

def merge_nets(net1, net2, validate=True, merge_results=True, tol=1e-9, **kwargs):
"""Function to concatenate two nets into one data structure. The elements keep their indices
unless both nets have the same indices. In that case, net2 elements get reindex. The reindex
unless both nets have the same indices. In that case, net2 elements get reindexed. The reindex
lookup of net2 elements can be retrieved by passing return_net2_reindex_lookup=True.
Parameters
Expand Down

0 comments on commit c35eb7b

Please sign in to comment.