Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into facts_statcom
Browse files Browse the repository at this point in the history
  • Loading branch information
BaraaUniKassel committed Jun 6, 2023
2 parents 3a3e87a + d927f2f commit 8bdcb6d
Show file tree
Hide file tree
Showing 17 changed files with 497 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/github_test_action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install .["all"]
if ${{ matrix.python-version == '3.9' }}; then python -m pip install pypower; fi
if ${{ matrix.python-version != '3.9' && matrix.python-version != '3.11' }}; then python -m pip install numba; fi
if ${{ matrix.python-version != '3.9' }}; then python -m pip install numba; fi
if ${{ matrix.python-version == '3.8' || matrix.python-version == '3.10' }}; then python -m pip install lightsim2grid; fi
- name: Install Julia
if: ${{ matrix.python-version == '3.9' }}
Expand Down Expand Up @@ -83,7 +83,7 @@ jobs:
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install .
pip install matplotlib
if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi
if ${{ matrix.python-version != '3.9' }}; then python -m pip install numba; fi
- name: Install pandapipes and simbench
run: |
python -m pip install git+https://github.com/e2nIEE/pandapipes@develop#egg=pandapipes
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
if ( '${{ matrix.python-version }}' -eq '3.9' ) { python -m pip install pypower }
if ( '${{ matrix.python-version }}' -ne '3.9' -and '${{ matrix.python-version }}' -ne '3.11' ) { python -m pip install numba }
if ( '${{ matrix.python-version }}' -ne '3.9' ) { python -m pip install numba }
if ( '${{ matrix.python-version }}' -eq '3.8' -or '${{ matrix.python-version }}' -eq '3.10' ) { python -m pip install lightsim2grid }
- name: Install specific dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
if ${{ matrix.python-version == '3.9' }}; then python -m pip install pypower; fi
if ${{ matrix.python-version != '3.9' && matrix.python-version != '3.11' }}; then python -m pip install numba; fi
if ${{ matrix.python-version != '3.9' }}; then python -m pip install numba; fi
if ${{ matrix.python-version == '3.8' || matrix.python-version == '3.10' }}; then python -m pip install lightsim2grid; fi
- name: Install Julia
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.9'
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ Change Log

[upcoming release] - 2023-..-..
-------------------------------
- [ADDED] feature: Function to run powerflow using the power-grid-model library
- [FIXED] short-circuit calculation: wrong results when :code:`ext_grid` and :code:`gen` elements are connected to the same bus
- [ADDED] comparison of "dict" attributes in :code:`pandapower.toolbox.comparisons.nets_equal` with :code:`DeepDiff`
- [FIXED] loading net from xlsx with MultiIndex
- [FIXED] numba version check
- [FIXED] deprecation warnings for numba (set nopython=True in jit calls)
- [FIXED] setting MultiIndex when loading empty DataFrame from JSON, getting next index from DataFrame with MultiIndex
- [FIXED] some fixes and small updates at cim2pp
- [CHANGED] add numba in the dependencies for Python 3.11 for GitHub test and release actions
- [FIXED] fixed bug in :code:`pp.select_subnet` when using tap dependent impedance


[2.13.1] - 2023-05-12
Expand Down
72 changes: 64 additions & 8 deletions doc/shortcircuit/currents.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,82 @@
Short-Circuit Currents
=======================

The short-circuit currents are calculated with the equivalent voltage source at the fault location.
For an explanation of the theory behind short-circuit calculations according to IEC 60909
please refer to the norm or secondary literature:
The short-circuit currents are calculated according to the **IEC 60909** international standard. `pandapower` supports two different calculation methods, in accordance with the IEC 60909 standard:

1. equivalent voltage source method (i.e. by introducing the Thevenin's voltage source) at the fault location and
2. superposition method that considers the pre-fault voltage vector.

For both methods, the possiboility to use LU factorization is implemented (option inverse_y=False). This improves the performance of the short-circuit calculation and reduces the required RAM, especially for large grid models, if the number of fault buses is low.

For a detailed explanation of the theory behind short-circuit calculations according to IEC 60909
please refer to the mentioned normative document or secondary literature:

.. seealso::

`IEC 60909-0:2016 <https://webstore.iec.ch/publication/24100>`_ Short-circuit currents in three-phase a.c. systems

Note: `pandapower` currently implements three-phase (symmetrical), two-phase (asymmetrical), and single-phase (Line-to-Ground) faults. Two-phase fault with earthing is not yet available.

**Ad 1)** The pandapower short-circuit calculation supports following elements:

* `sgen` (as motor, or as full converter generator, or as asynchronous machine, or as doubly-fed asynchronous machine),
* `gen` (as synchronous generator),
* `ext_grid` (external network equivalent),
* `line` (transmission line or cable),
* `trafo` (two-winding transformer),
* `trafo3w` (three-winding transformer),
* `impedance` (arbitrary impedance),

with the associated correction factors as defined in IEC 60909. Loads and shunts are neglected as per standard. The pandapower switch model is fully integrated into the short-circuit calculation. The calculation, furthermore, enables computing maximum (case="max") and minimum (case="min") short-circuit currents by furnishing the appropriate value for the "case" argument in the "calc_sc" function call.

Calculations are available for the meshed as well as for the radial networks. pandapower includes a meshing detection that automatically detects the meshing (topology="auto") for each short-circuit location during the "calc_sc" function call. Alternatively, the topology can be set to "radial" or "meshed" in order to circumvent the check and shorten the computation time (for large networks). This is achieved by appropriately setting the "topology" argument in the "calc_sc" function call.

It is also possible to specify a fault impedance in the short-circuit calculation, by providing the values for parameters "r_fault_ohm" and/or "x_fault_ohm" in the "calc_sc" function call, which, respectively, define resistance and reactance parts of the impedance at the point of the short-circuit. For the phase-to-phase (i.e. three-phase and two-phase) short-circuits this will be the arc resistance.

The power system units can be considered by setting the parameters "power_station_unit" and "oltc" of the transformer (:code:`net.trafo`) and "power_station_trafo" of generator (:code:`net.gen`).

Note that the short-circuit currents are calculated in the complex domain, which allows obtaining the branch-related values for current magnitude and phase angle. In the case of transformers with rated voltage values unequal to the bus rated voltage values, only the current results are available because the voltage results are not valid in this case. For such configurations, only the superposition method can be used to obtain voltage, active and reactive power results (see below).

**Ad 2)** The superposition method (per IEC 60909) considers the pre-fault voltage vector. This method is activated by passing the argument "use_pre_fault_voltage" as True to the "calc_sc" function call. The superposition method is only inplemented for three-phase symmetric fault (fault="3ph").

pandapower currently implements symmetrical and two-phase faults. One phase faults and two-phase faults with earthing are not yet available.
Note that the user needs to explicitly carry out the power flow calculation (i.e. by invoking the "runpp" function call) on the network, before proceeding to the short-circuit calculation with the superposition method. We rely on the user to execute this step explicitly so that the user is fully aware that a power flow calculation is executed, and also has control over all the relevant options for the power flow calculation. Results provide branch currents magnitude and angle, along with active and reactive power flows, and bus voltages magnitude and angle values.

Note that the currents are calculated as complex domain, which allows obtaining the branch-related values for current magnitude and current angle.
In the case of the superposition method, the values of shunt impedance of inverter-based generators and loads are considered, which are calculated based on their pre-fault current values. The following differences to the worst-case scenario calculation apply:

We implemented the superposition method that considers pre-fault voltage vector. This method is activated by passing the parameter "use_pre_fault_voltage" as True.
In this case, the values of shunt impedance of inverter-based generators and loads are considered, which are calculated based on their pre-fault current values.
- transformer correction factor is not applied,
- load, sgen are additionally modelled as shunt admittances (calculated based on their pre-fault currents),
- the grid must contain the results of a successful power flow calculation.

The results for all elements and different short-circuit currents have been tested against commercial software to ensure that correction factors are correctly applied.

Both methods allow following short-circuit currents to be calculated:

* ikss (i.e. Initial symmetrical short-circuit current),
* ip (i.e. Peak short-circuit current),
* ith (i.e. Equivalent thermal short-circuit current),

either as:

- symmetrical three-phase or
- asymmetrical two-phase

short-circuit currents. Currents "ip" and "ith" are only implemented for short-circuits far from the synchronous generators.

.. toctree::
:maxdepth: 1

ikss
ip
ith
ith

Kindly follow the tutorial on the basics of the Short-Circuit Analysis for more details:
https://github.com/e2nIEE/pandapower/blob/develop/tutorials/shortcircuit/shortcircuit.ipynb


**Results**

The results of the short-circuit calculations are stored in the dedicated results tables:

:code:`net.res_bus_sc` for the results for fault buses, :code:`net.res_line_sc` for line results, :code:`net.res_trafo_sc` and :code:`net.res_trafo3w_sc` for transformer results.
The branch results include, in addition to the short-circuit current, the voltage magnitude and angle at the connected buses, and the active and reactive power flowing in and out of the branch.
Only the currents are shown for three-winding transformers at the moment.
9 changes: 5 additions & 4 deletions pandapower/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import pandas as pd
import scipy as sp
import numbers
from packaging import version
from packaging.version import Version

from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_STATUS
from pandapower.pypower.idx_bus import BUS_I, BUS_TYPE, NONE, PD, QD, VM, VA, REF, VMIN, VMAX, PV
Expand All @@ -45,7 +45,7 @@

try:
from numba import jit
from numba._version import version_version as numba_version
from numba import __version__ as numba_version
except ImportError:
from .pf.no_numba import jit

Expand Down Expand Up @@ -315,7 +315,8 @@ def get_free_id(df):
"""
Returns next free ID in a dataframe
"""
return np.int64(0) if len(df) == 0 else df.index.values.max() + 1
index_values = df.index.get_level_values(0) if isinstance(df.index, pd.MultiIndex) else df.index.values
return np.int64(0) if len(df) == 0 else index_values.max() + 1


class ppException(Exception):
Expand Down Expand Up @@ -942,7 +943,7 @@ def _check_if_numba_is_installed(numba):

try:
# get numba Version (in order to use it it must be > 0.25)
if version.parse(numba_version) < version.parse("0.2.5"):
if Version(numba_version) < Version("0.25"):
logger.warning('Warning: numba version too old -> Upgrade to a version > 0.25.\n' +
numba_warning_str)
numba = False
Expand Down
3 changes: 3 additions & 0 deletions pandapower/converter/cim/cim2pp/build_pp_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,9 @@ def _create_trafo_characteristics(self, trafo_type, trafo_df_origin):
how='left', on=sc['pte_id'] + '_lv')
], ignore_index=True, sort=False)
# remove elements with mor than one tap changer per trafo
trafo_df = trafo_df.loc[(~trafo_df.duplicated(subset=['PowerTransformer', 'tabular_step'], keep=False)) | (
~trafo_df.RatioTapChangerTable.isna())]
# remove elements with mor than one tap changer per trafo
trafo_df = trafo_df.loc[(~trafo_df.duplicated(subset=['PowerTransformer', 'tabular_step'], keep=False)) | (
~trafo_df.RatioTapChangerTable.isna())]
fillna_list = ['tabular_step']
Expand Down
8 changes: 5 additions & 3 deletions pandapower/converter/cim/other_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ def from_value(cls, value):


class Report:
def __init__(self, message: str, code: ReportCode, level: LogLevel):
self.timestamp = datetime.datetime.now().isoformat()
def __init__(self, message: str, code: ReportCode, level: LogLevel, timestamp: datetime.datetime = None):
self.timestamp = datetime.datetime.now()
if timestamp is not None:
self.timestamp = timestamp
self.message = message
self.code = code
self.level = level

def to_dict(self) -> Dict:
return {
"timestamp": self.timestamp,
"timestamp": self.timestamp.isoformat(),
"message": self.message,
"code": self.code.value,
"level": self.level.value
Expand Down
23 changes: 15 additions & 8 deletions pandapower/io_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def to_dict_of_dfs(net, include_results=False, include_std_types=True, include_p
if len(value) > 0:
dodfs["user_pf_options"] = pd.DataFrame(value, index=[0])
continue
elif isinstance(value, (int, float, bool, str)):
elif isinstance(value, (int, float, bool, str, numbers.Number)):
# attributes of primitive types are just stored in a DataFrame "parameters"
parameters[item] = net[item]
continue
Expand Down Expand Up @@ -244,7 +244,8 @@ def from_dict_of_dfs(dodfs, net=None):
if json_column in table.columns:
table[json_column] = table[json_column].apply(
lambda x: json.loads(x, cls=PPJSONDecoder))
table.rename_axis(net[item].index.name, inplace=True)
if not isinstance(table.index, pd.MultiIndex):
table.rename_axis(net[item].index.name, inplace=True)
net[item] = table
# set the index to be Int
try:
Expand Down Expand Up @@ -487,8 +488,10 @@ def Series(self):
ser.index.name = index_name
if is_multiindex:
try:
ser.index = pd.MultiIndex.from_tuples(pd.Series(ser.index).apply(
literal_eval).tolist())
if len(ser) == 0:
ser.index = pd.MultiIndex.from_tuples([], names=index_names, dtype=np.int64)
else:
ser.index = pd.MultiIndex.from_tuples(pd.Series(ser.index).apply(literal_eval).tolist())
except:
logger.warning("Converting index to multiindex failed.")
else:
Expand Down Expand Up @@ -526,8 +529,10 @@ def DataFrame(self):
df.columns.name = column_name
if is_multiindex:
try:
df.index = pd.MultiIndex.from_tuples(pd.Series(df.index).apply(
literal_eval).tolist())
if len(df) == 0:
df.index = pd.MultiIndex.from_frame(pd.DataFrame(columns=index_names, dtype=np.int64))
else:
df.index = pd.MultiIndex.from_tuples(pd.Series(df.index).apply(literal_eval).tolist())
# slower alternative code:
# df.index = pd.MultiIndex.from_tuples([literal_eval(idx) for idx in df.index])
except:
Expand All @@ -537,8 +542,10 @@ def DataFrame(self):
df.index.names = index_names
if is_multicolumn:
try:
df.columns = pd.MultiIndex.from_tuples(pd.Series(df.columns).apply(
literal_eval).tolist())
if len(df) == 0:
df.columns = pd.MultiIndex.from_frame(pd.DataFrame(columns=column_names, dtype=np.int64))
else:
df.columns = pd.MultiIndex.from_tuples(pd.Series(df.columns).apply(literal_eval).tolist())
except:
logger.warning("Converting columns to multiindex failed.")
else:
Expand Down
2 changes: 1 addition & 1 deletion pandapower/pypower/makeLODF.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from .idx_brch import F_BUS, T_BUS


@jit
@jit(nopython=True)
def update_LODF_diag(LODF): # pragma: no cover
for ix in range(LODF.shape[0]):
# To preserve the data type of diagnol elments
Expand Down
Loading

0 comments on commit 8bdcb6d

Please sign in to comment.