Skip to content

Commit

Permalink
Merge branch 'develop' into deprecate/store_index_names
Browse files Browse the repository at this point in the history
  • Loading branch information
rbolgaryn authored Oct 26, 2023
2 parents 98a3592 + 3544151 commit 230c111
Show file tree
Hide file tree
Showing 79 changed files with 9,811 additions and 2,286 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/github_test_action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,11 @@ jobs:
python -m pip install --upgrade pip
python -m pip install pytest nbmake pytest-xdist igraph numba seaborn
./.install_julia.sh 1.8
pip install julia
python -m pip install julia
python ./.install_pycall.py
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install .["all"]
python -m pip install .["all"]
python -m pip install lightsim2grid
- name: List all installed packages
run: |
pip list
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ Change Log
- [FIXED] in converter from PowerFactory, collect all buses (even not relevant for the calculation) for connectivity issues
- [FIXED] bug in coords conversion in cim2pp, small fixes
- [CHANGED] cim2pp: added support for multi diagram usage for DL profiles
- [CHANGED] cim2pp: made build_pp_net modular by introducing classes
- [FIXED] error handling in :code:`plotly/mapbox_plot.py` not raising :code`ImportError` if :code:`geopy` or :code:`pyproj` are missing
- [FIXED] powerfactory2pandapower-converter error if a line has two identical coordinates
- [ADDED] logger messages about the probabilistic load flow calculation (simultaneities) in the powerfactory2pandapower-converter for low voltage loads
- [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
- [FIXED] :code:`convert_format.py`: update the attributes of the characteristic objects to match the new characteristic


[2.13.1] - 2023-05-12
Expand Down Expand Up @@ -113,6 +117,7 @@ Change Log
- [CHANGED] Compatibility with pandas 1.5, dropped "six" dependency
- [CHANGED] from_ppc(): revision of indexing and naming of elements
- [CHANGED] Complete revision of validate_from_ppc()
- [ADDED] helper functions for contingency calculation
- [CHANGED] Improve defaults, add docstrings and rename parameters of plot_voltage_profile() and plot_loading()
- [CHANGED] merge_nets(): revised for groups and new behavior regarding indexing; reindex_elements(): revised for groups, don't overwrite column "index" and feature parameter lookup
- [FIXED] Bug with user_pf_options: _init_runpp_options in auxiliary.py ignored user_pf_options when performing sanity checks
Expand Down
17 changes: 17 additions & 0 deletions doc/contingency.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#####################
Contingency analysis
#####################

We can define N-1 cases to be analysed as contingencies. This means that indices of net.line, net.trafo, net.trafo3w can be defined as contingencies, which are switched off one at a time. The power system is analyzed with power flow calculations, and the min/max values among all the N-1 cases are obtained for relevant variables.

A tutorial that introduces this feature with an example is available at `Contingency analysis <https://github.com/e2nIEE/pandapower/tree/develop/tutorials/contingency_analysis.ipynb>`_

.. autofunction:: pandapower.contingency.run_contingency

.. autofunction:: pandapower.contingency.run_contingency_ls2g

.. autofunction:: pandapower.contingency.get_element_limits

.. autofunction:: pandapower.contingency.check_elements_within_limits

.. autofunction:: pandapower.contingency.report_contingency_results
2 changes: 1 addition & 1 deletion doc/elements/trafo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Input Parameters
:delim: ;
:widths: 15, 10, 25, 40

\*necessary for executing a balanced power flow calculation |br| \*\*optimal power flow parameter |br| \*\*\*necessary for executing a three phase power flow / single phase short circuit
\*necessary for executing a balanced power flow calculation |br| \*\*optimal power flow parameter |br| \*\*\*necessary for executing a three phase power flow / single phase short circuit |br| \*\*\*\*optional, for modeling a second tap changer

.. note:: The transformer loading constraint for the optimal power flow corresponds to the option trafo_loading="current":

Expand Down
8 changes: 8 additions & 0 deletions doc/elements/trafo_par.csv
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ df;float;1 :math:`\geq` df :math:`>` 0;derating factor: maximal current of trans
in_service*;boolean;True / False;specifies if the transformer is in service
oltc*;boolean;True / False; specifies if the transformer has an OLTC (short-circuit relevant)
power_station_unit*;boolean;True / False; specifies if the transformer is part of a power_station_unit (short-circuit relevant).
tap2_side****;string;"""hv"", ""lv""";defines if tap changer is at the high- or low voltage side
tap2_neutral****;integer;;rated tap position
tap2_min****;integer;;minimum tap position
tap2_max****;integer;;maximum tap position
tap2_step_percent****;float;:math:`>` 0;tap step size for voltage magnitude [%]
tap2_step_degree****;float;:math:`\geq` 0;tap step size for voltage angle
tap2_pos****;integer;;current position of tap changer
tap2_phase_shifter****;bool;;defines whether the transformer is an ideal phase shifter
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Operation at the Fraunhofer Institute for Energy Economics and Energy System Tec
elements
std_types
powerflow
contingency
opf
shortcircuit
estimation
Expand Down
2 changes: 1 addition & 1 deletion pandapower/_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "2.13.1"
__format_version__ = "2.12.0"
__format_version__ = "2.13.1"
8 changes: 3 additions & 5 deletions pandapower/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -1352,9 +1352,7 @@ def _init_runpp_options(net, algorithm, calculate_voltage_angles, init,

default_max_iteration = {"nr": 10, "iwamoto_nr": 10, "bfsw": 100, "gs": 10000, "fdxb": 30,
"fdbx": 30}
with_ssc = len(net.ssc.query("in_service & controllable")) > 0
with_facts = len(net.svc.query("in_service & controllable")) > 0 or \
len(net.tcsc.query("in_service & controllable")) > 0 or with_ssc
with_facts = net.svc.in_service.any() or net.tcsc.in_service.any() or net.ssc.in_service.any()
if max_iteration == "auto":
# tdpf is an option rather than algorithm; svc need more iterations to converge
max_iteration = 30 if tdpf or with_facts else default_max_iteration[algorithm]
Expand All @@ -1371,10 +1369,10 @@ def _init_runpp_options(net, algorithm, calculate_voltage_angles, init,
init_vm_pu = None
init_va_degree = None

# SSC devices can lead to the grid having isolated buses from the point of view of DC power flow, so choose 'flat'
# FACTS devices can lead to the grid having isolated buses from the point of view of DC power flow, so choose 'flat'
if init == "auto":
if init_va_degree is None or (isinstance(init_va_degree, str) and init_va_degree == "auto"):
init_va_degree = "dc" if calculate_voltage_angles and not with_ssc else "flat"
init_va_degree = "dc" if calculate_voltage_angles and not with_facts else "flat"
if init_vm_pu is None or (isinstance(init_vm_pu, str) and init_vm_pu == "auto"):
init_vm_pu = (net.ext_grid.vm_pu.values.sum() + net.gen.vm_pu.values.sum()) / \
(len(net.ext_grid.vm_pu.values) + len(net.gen.vm_pu.values))
Expand Down
75 changes: 39 additions & 36 deletions pandapower/build_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,42 +412,45 @@ def _calc_tap_from_dataframe(net, trafo_df):
if mode == "sc" and not net._options.get("use_pre_fault_voltage", False): # todo type c?
return vnh, vnl, trafo_shift

tap_pos = get_trafo_values(trafo_df, "tap_pos")
tap_neutral = get_trafo_values(trafo_df, "tap_neutral")
tap_diff = tap_pos - tap_neutral
tap_phase_shifter = get_trafo_values(trafo_df, "tap_phase_shifter")
tap_side = get_trafo_values(trafo_df, "tap_side")
tap_step_percent = get_trafo_values(trafo_df, "tap_step_percent")
tap_step_degree = get_trafo_values(trafo_df, "tap_step_degree")

cos = lambda x: np.cos(np.deg2rad(x))
sin = lambda x: np.sin(np.deg2rad(x))
arctan = lambda x: np.rad2deg(np.arctan(x))

for side, vn, direction in [("hv", vnh, 1), ("lv", vnl, -1)]:
phase_shifters = tap_phase_shifter & (tap_side == side)
tap_complex = np.isfinite(tap_step_percent) & np.isfinite(tap_pos) & (tap_side == side) & \
~phase_shifters
if tap_complex.any():
tap_steps = tap_step_percent[tap_complex] * tap_diff[tap_complex] / 100
tap_angles = _replace_nan(tap_step_degree[tap_complex])
u1 = vn[tap_complex]
du = u1 * _replace_nan(tap_steps)
vn[tap_complex] = np.sqrt((u1 + du * cos(tap_angles)) ** 2 + (du * sin(tap_angles)) ** 2)
trafo_shift[tap_complex] += (arctan(direction * du * sin(tap_angles) /
(u1 + du * cos(tap_angles))))
if phase_shifters.any():
degree_is_set = _replace_nan(tap_step_degree[phase_shifters]) != 0
percent_is_set = _replace_nan(tap_step_percent[phase_shifters]) != 0
if (degree_is_set & percent_is_set).any():
raise UserWarning(
"Both tap_step_degree and tap_step_percent set for ideal phase shifter")
trafo_shift[phase_shifters] += np.where(
(degree_is_set),
(direction * tap_diff[phase_shifters] * tap_step_degree[phase_shifters]),
(direction * 2 * np.rad2deg(np.arcsin(tap_diff[phase_shifters] * \
tap_step_percent[phase_shifters] / 100 / 2)))
)
for t in ("", "2"):
if f"tap{t}_pos" not in trafo_df:
continue
tap_pos = get_trafo_values(trafo_df, f"tap{t}_pos")
tap_neutral = get_trafo_values(trafo_df, f"tap{t}_neutral")
tap_diff = tap_pos - tap_neutral
tap_phase_shifter = get_trafo_values(trafo_df, f"tap{t}_phase_shifter")
tap_side = get_trafo_values(trafo_df, f"tap{t}_side")
tap_step_percent = get_trafo_values(trafo_df, f"tap{t}_step_percent")
tap_step_degree = get_trafo_values(trafo_df, f"tap{t}_step_degree")

cos = lambda x: np.cos(np.deg2rad(x))
sin = lambda x: np.sin(np.deg2rad(x))
arctan = lambda x: np.rad2deg(np.arctan(x))

for side, vn, direction in [("hv", vnh, 1), ("lv", vnl, -1)]:
phase_shifters = tap_phase_shifter & (tap_side == side)
tap_complex = np.isfinite(tap_step_percent) & np.isfinite(tap_pos) & (tap_side == side) & \
~phase_shifters
if tap_complex.any():
tap_steps = tap_step_percent[tap_complex] * tap_diff[tap_complex] / 100
tap_angles = _replace_nan(tap_step_degree[tap_complex])
u1 = vn[tap_complex]
du = u1 * _replace_nan(tap_steps)
vn[tap_complex] = np.sqrt((u1 + du * cos(tap_angles)) ** 2 + (du * sin(tap_angles)) ** 2)
trafo_shift[tap_complex] += (arctan(direction * du * sin(tap_angles) /
(u1 + du * cos(tap_angles))))
if phase_shifters.any():
degree_is_set = _replace_nan(tap_step_degree[phase_shifters]) != 0
percent_is_set = _replace_nan(tap_step_percent[phase_shifters]) != 0
if (degree_is_set & percent_is_set).any():
raise UserWarning(
"Both tap_step_degree and tap_step_percent set for ideal phase shifter")
trafo_shift[phase_shifters] += np.where(
(degree_is_set),
(direction * tap_diff[phase_shifters] * tap_step_degree[phase_shifters]),
(direction * 2 * np.rad2deg(np.arcsin(tap_diff[phase_shifters] * \
tap_step_percent[phase_shifters] / 100 / 2)))
)
return vnh, vnl, trafo_shift


Expand Down
1 change: 1 addition & 0 deletions pandapower/contingency/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from pandapower.contingency.contingency import *
Loading

0 comments on commit 230c111

Please sign in to comment.