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

Fix missing angle constraints #2405

Open
wants to merge 4 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
2 changes: 1 addition & 1 deletion pandapower/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import importlib.metadata

__version__ = importlib.metadata.version("pandapower")
__format_version__ = "3.0.0"
__format_version__ = "3.1.0"
8 changes: 6 additions & 2 deletions pandapower/build_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import pandas as pd

from pandapower.auxiliary import get_values
from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_R, BR_X, BR_B, BR_G, TAP, SHIFT, BR_STATUS, RATE_A, \
BR_R_ASYM, BR_X_ASYM, BR_G_ASYM, BR_B_ASYM, branch_cols
from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_R, BR_X, BR_B, BR_G, TAP, SHIFT, BR_STATUS, ANGMAX, ANGMIN, \
RATE_A, BR_R_ASYM, BR_X_ASYM, BR_G_ASYM, BR_B_ASYM, branch_cols
from pandapower.pypower.idx_brch_dc import branch_dc_cols, DC_RATE_A, DC_RATE_B, DC_RATE_C, DC_BR_STATUS, DC_F_BUS, \
DC_T_BUS, DC_BR_R, DC_BR_G
from pandapower.pypower.idx_brch_tdpf import BR_R_REF_OHM_PER_KM, BR_LENGTH_KM, RATE_I_KA, T_START_C, R_THETA, \
Expand Down Expand Up @@ -207,6 +207,8 @@ def _calc_line_parameter(net, ppc, elm="line", ppc_elm="branch"):
branch[f:t, T_BUS] = to_bus
branch[f:t, BR_R] = line["r_ohm_per_km"].values * length_km / baseR / parallel
branch[f:t, BR_X] = line["x_ohm_per_km"].values * length_km / baseR / parallel
branch[f:t, ANGMAX] = line["max_theta_deg"].values
branch[f:t, ANGMIN] = line["min_theta_deg"].values

if net._options["tdpf"]:
branch[f:t, TDPF] = line["in_service"].values & line["tdpf"].fillna(False).values.astype(bool)
Expand Down Expand Up @@ -360,6 +362,8 @@ def _calc_trafo_parameter(net, ppc, update_vk_values: bool=True):
branch[f:t, TAP] = ratio
branch[f:t, SHIFT] = shift
branch[f:t, BR_STATUS] = trafo["in_service"].values
branch[f:t, ANGMAX] = trafo["max_theta_deg"].values
branch[f:t, ANGMIN] = trafo["min_theta_deg"].values
if any(trafo.df.values <= 0):
raise UserWarning("Rating factor df must be positive. Transformers with false "
"rating factors: %s" % trafo.query('df<=0').index.tolist())
Expand Down
4 changes: 4 additions & 0 deletions pandapower/convert_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ def _add_missing_columns(net, elements_to_deserialize):
for element in update_elements:
if "df" not in net[element]:
net[element]["df"] = 1.0
if "max_theta_deg" not in net[element]:
net[element]["max_theta_deg"] = 360.0
if "min_theta_deg" not in net[element]:
net[element]["min_theta_deg"] = -360.0

if _check_elements_to_deserialize('bus', elements_to_deserialize) \
and _check_elements_to_deserialize('bus_geodata', elements_to_deserialize) \
Expand Down
3 changes: 3 additions & 0 deletions pandapower/converter/pypower/from_ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ def _from_ppc_branch(net, ppc, f_hz, **kwargs):
c_nf_per_km=(ppc['branch'][is_line, BR_B]/Zni[is_line]/omega*1e9/2),
g_us_per_km=(br_g[is_line]/Zni[is_line]*1e6/2),
max_i_ka=max_i_ka[is_line], type='ol', max_loading_percent=100,
max_theta_deg=ppc['branch'][is_line, ANGMAX],
min_theta_deg=ppc['branch'][is_line, ANGMIN],
in_service=ppc['branch'][is_line, BR_STATUS].astype(bool))

# --- create transformer
Expand Down Expand Up @@ -290,6 +292,7 @@ def _from_ppc_branch(net, ppc, f_hz, **kwargs):
net, hv_buses=net.bus.index[hv_bus], lv_buses=net.bus.index[lv_bus], sn_mva=sn,
vn_hv_kv=vn_hv_kv, vn_lv_kv=vn_lv_kv, name=bra_name[is_trafo],
vk_percent=vk_percent, vkr_percent=vkr_percent,
max_theta_deg=ppc['branch'][is_trafo, ANGMAX], min_theta_deg=ppc['branch'][is_trafo, ANGMIN],
max_loading_percent=100, pfe_kw=pfe_kw, i0_percent=i0_percent,
shift_degree=ppc['branch'][is_trafo, SHIFT],
tap_step_percent=np.abs(ratio_1)*100, tap_pos=np.sign(ratio_1),
Expand Down
46 changes: 39 additions & 7 deletions pandapower/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ def create_empty_network(name="", f_hz=50., sn_mva=1, add_stdtypes=True):
("c_nf_per_km", "f8"),
("g_us_per_km", "f8"),
("max_i_ka", "f8"),
("max_theta_deg", "f8"),
("min_theta_deg", "f8"),
("df", "f8"),
("parallel", "u4"),
("type", dtype(object)),
Expand Down Expand Up @@ -245,6 +247,8 @@ def create_empty_network(name="", f_hz=50., sn_mva=1, add_stdtypes=True):
("tap_step_degree", "f8"),
("tap_pos", "i4"),
("tap_phase_shifter", 'bool'),
("max_theta_deg", "f8"),
("min_theta_deg", "f8"),
("parallel", "u4"),
("df", "f8"),
("in_service", 'bool')],
Expand Down Expand Up @@ -2306,7 +2310,8 @@ def create_line(net, from_bus, to_bus, length_km, std_type, name=None, index=Non
v = {
"name": name, "length_km": length_km, "from_bus": from_bus,
"to_bus": to_bus, "in_service": bool(in_service), "std_type": std_type,
"df": df, "parallel": parallel
"df": df, "parallel": parallel,
"max_theta_deg": 360., "min_theta_deg": -360.,
}

lineparam = load_std_type(net, std_type, "line")
Expand Down Expand Up @@ -2569,7 +2574,8 @@ def create_lines(net, from_buses, to_buses, length_km, std_type, name=None, inde

entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km,
"std_type": std_type, "name": name, "df": df, "parallel": parallel,
"in_service": in_service}
"in_service": in_service,
"max_theta_deg": 360., "min_theta_deg": -360.}

# add std type data
if isinstance(std_type, str):
Expand Down Expand Up @@ -2739,6 +2745,7 @@ def create_lines_dc(net, from_buses_dc, to_buses_dc, length_km, std_type, name=N

def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km, x_ohm_per_km,
c_nf_per_km, max_i_ka, name=None, index=None, type=None,
max_theta_deg=360., min_theta_deg=-360.,
geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
max_loading_percent=nan, alpha=nan,
temperature_degree_celsius=nan, r0_ohm_per_km=nan,
Expand Down Expand Up @@ -2780,6 +2787,10 @@ def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km,

**type** (str, None) - type of line ("ol" for overhead line or "cs" for cable system)

**max_theta_deg** (float, 360) - maximal phase angle difference (only needed for OPF)

**min_theta_deg** (float, -360) - minimal phase angle difference (only needed for OPF)

**df** (float, 1) - derating factor: maximal current of line in relation to nominal current\
of line (from 0 to 1)

Expand Down Expand Up @@ -2847,7 +2858,8 @@ def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km,
"to_bus": to_bus, "in_service": bool(in_service), "std_type": None,
"df": df, "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
"c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "parallel": parallel, "type": type,
"g_us_per_km": g_us_per_km
"g_us_per_km": g_us_per_km,
"max_theta_deg": max_theta_deg, "min_theta_deg": min_theta_deg
}

tdpf_columns = ("wind_speed_m_per_s", "wind_angle_degree", "conductor_outer_diameter_m",
Expand Down Expand Up @@ -3011,6 +3023,7 @@ def create_line_dc_from_parameters(net, from_bus_dc, to_bus_dc, length_km, r_ohm

def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per_km, x_ohm_per_km,
c_nf_per_km, max_i_ka, name=None, index=None, type=None,
max_theta_deg=360., min_theta_deg=-360.,
geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
max_loading_percent=nan, alpha=nan,
temperature_degree_celsius=nan, r0_ohm_per_km=nan,
Expand Down Expand Up @@ -3055,6 +3068,10 @@ def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per

**type** (list of string, None) - type of line ("ol" for overhead line or "cs" for cable system)

**max_theta_deg** (list of float, 360) - maximal phase angle difference (only needed for OPF)

**min_theta_deg** (list of float, -360) - minimal phase angle difference (only needed for OPF)

**df** (list of float, 1) - derating factor: maximal current of line in relation to nominal current\
of line (from 0 to 1)

Expand Down Expand Up @@ -3117,7 +3134,8 @@ def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per
entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km, "type": type,
"r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
"c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "g_us_per_km": g_us_per_km,
"name": name, "df": df, "parallel": parallel, "in_service": in_service}
"name": name, "df": df, "parallel": parallel, "in_service": in_service,
"max_theta_deg": max_theta_deg, "min_theta_deg": min_theta_deg}

_add_to_entries_if_not_nan(net, "line", entries, index, "max_loading_percent",
max_loading_percent)
Expand Down Expand Up @@ -3359,7 +3377,8 @@ def create_transformer(net, hv_bus, lv_bus, std_type, name=None, tap_pos=nan, in

v = {
"name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
"in_service": bool(in_service), "std_type": std_type
"in_service": bool(in_service), "std_type": std_type,
"max_theta_deg": 360., "min_theta_deg": -360.
}
ti = load_std_type(net, std_type, "trafo")

Expand Down Expand Up @@ -3425,6 +3444,7 @@ def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn
tap_min=nan, tap_step_percent=nan, tap_step_degree=nan,
tap_pos=nan, tap_phase_shifter=False, in_service=True,
name=None, vector_group=None, index=None,
max_theta_deg=360., min_theta_deg=-360.,
max_loading_percent=nan, parallel=1,
df=1., vk0_percent=nan, vkr0_percent=nan,
mag0_percent=nan, mag0_rx=nan,
Expand Down Expand Up @@ -3510,6 +3530,10 @@ def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn
**index** (int, None) - Force a specified ID if it is available. If None, the index one \
higher than the highest already existing index is selected.

**max_theta_deg** (float, 360) - maximal phase angle difference (only needed for OPF)

**min_theta_deg** (float, -360) - minimal phase angle difference (only needed for OPF)

**max_loading_percent (float)** - maximum current loading (only needed for OPF)

**df** (float) - derating factor: maximal current of transformer in relation to nominal \
Expand Down Expand Up @@ -3588,7 +3612,9 @@ def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn
"tap_max": tap_max, "tap_min": tap_min, "shift_degree": shift_degree,
"tap_side": tap_side, "tap_step_percent": tap_step_percent,
"tap_step_degree": tap_step_degree,
"tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df}
"tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df,
"max_theta_deg": max_theta_deg, "min_theta_deg": min_theta_deg
}

if ("tap_neutral" in v) and (tap_pos is nan):
v["tap_pos"] = v["tap_neutral"]
Expand Down Expand Up @@ -3638,7 +3664,9 @@ def create_transformers_from_parameters(net, hv_buses, lv_buses, sn_mva, vn_hv_k
tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
tap_phase_shifter=False, in_service=True, name=None,
vector_group=None, index=None, max_loading_percent=nan,
vector_group=None, index=None,
max_theta_deg=360., min_theta_deg=-360.,
max_loading_percent=nan,
parallel=1, df=1., vk0_percent=nan, vkr0_percent=nan,
mag0_percent=nan, mag0_rx=nan, si0_hv_partial=nan,
pt_percent=nan, oltc=nan, tap_dependent_impedance=nan,
Expand Down Expand Up @@ -3723,6 +3751,10 @@ def create_transformers_from_parameters(net, hv_buses, lv_buses, sn_mva, vn_hv_k
**index** (int, None) - Force a specified ID if it is available. If None, the index one \
higher than the highest already existing index is selected.

**max_theta_deg** (float, 360) - maximal phase angle difference (only needed for OPF)

**min_theta_deg** (float, -360) - minimal phase angle difference (only needed for OPF)

**max_loading_percent (float)** - maximum current loading (only needed for OPF)

**df** (float) - derating factor: maximal current of transformer in relation to nominal \
Expand Down
8 changes: 4 additions & 4 deletions pandapower/test/plotting/test_geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ def test_dump_to_geojson():
# test exporting branches
result = geo.dump_to_geojson(_net, branches=True)
assert isinstance(result, FeatureCollection)
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "max_theta_deg": 360.0, "min_theta_deg": -360.0, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'

# test exporting both
result = geo.dump_to_geojson(_net, nodes=True, branches=True)
assert isinstance(result, FeatureCollection)
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [1.0, 2.0], "type": "Point"}, "id": "bus-1", "properties": {"in_service": true, "name": "bus2", "pp_index": 1, "pp_type": "bus", "type": "b", "vn_kv": 0.4, "zone": null}, "type": "Feature"}, {"geometry": {"coordinates": [1.0, 3.0], "type": "Point"}, "id": "bus-7", "properties": {"in_service": true, "name": "bus3", "pp_index": 7, "pp_type": "bus", "type": "b", "vn_kv": 0.4, "zone": null}, "type": "Feature"}, {"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [1.0, 2.0], "type": "Point"}, "id": "bus-1", "properties": {"in_service": true, "name": "bus2", "pp_index": 1, "pp_type": "bus", "type": "b", "vn_kv": 0.4, "zone": null}, "type": "Feature"}, {"geometry": {"coordinates": [1.0, 3.0], "type": "Point"}, "id": "bus-7", "properties": {"in_service": true, "name": "bus3", "pp_index": 7, "pp_type": "bus", "type": "b", "vn_kv": 0.4, "zone": null}, "type": "Feature"}, {"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "max_theta_deg": 360.0, "min_theta_deg": -360.0, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'

# test exporting specific nodes
result = geo.dump_to_geojson(_net, nodes=[1])
Expand All @@ -286,7 +286,7 @@ def test_dump_to_geojson():
# test exporting specific branches
result = geo.dump_to_geojson(_net, branches=[0])
assert isinstance(result, FeatureCollection)
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "max_i_ka": 0.328, "max_theta_deg": 360.0, "min_theta_deg": -360.0, "name": "line1", "parallel": 1, "pp_index": 0, "pp_type": "line", "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'

# test exporting props from bus and res_bus
_net.res_bus.loc[1, ["vm_pu", "va_degree", "p_mw", "q_mvar"]] = [1.0, 1.0, 1.0, 1.0]
Expand All @@ -298,7 +298,7 @@ def test_dump_to_geojson():
_net.res_line.loc[0, _net.res_line.columns] = [7.0]*len(_net.res_line.columns)
result = geo.dump_to_geojson(_net, branches=[0])
assert isinstance(result, FeatureCollection)
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "i_from_ka": 7.0, "i_ka": 7.0, "i_to_ka": 7.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "loading_percent": 7.0, "max_i_ka": 0.328, "name": "line1", "p_from_mw": 7.0, "p_to_mw": 7.0, "parallel": 1, "pl_mw": 7.0, "pp_index": 0, "pp_type": "line", "q_from_mvar": 7.0, "q_to_mvar": 7.0, "ql_mvar": 7.0, "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "va_from_degree": 7.0, "va_to_degree": 7.0, "vm_from_pu": 7.0, "vm_to_pu": 7.0, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'
assert dumps(result, sort_keys=True) == '{"features": [{"geometry": {"coordinates": [[1.0, 2.0], [3.0, 4.0]], "type": "LineString"}, "id": "line-0", "properties": {"c_nf_per_km": 720.0, "df": 1.0, "from_bus": 1, "g_us_per_km": 0.0, "i_from_ka": 7.0, "i_ka": 7.0, "i_to_ka": 7.0, "ices": 0.389985, "in_service": true, "length_km": 1.0, "loading_percent": 7.0, "max_i_ka": 0.328, "max_theta_deg": 360.0, "min_theta_deg": -360.0, "name": "line1", "p_from_mw": 7.0, "p_to_mw": 7.0, "parallel": 1, "pl_mw": 7.0, "pp_index": 0, "pp_type": "line", "q_from_mvar": 7.0, "q_to_mvar": 7.0, "ql_mvar": 7.0, "r_ohm_per_km": 0.2067, "std_type": null, "to_bus": 7, "type": null, "va_from_degree": 7.0, "va_to_degree": 7.0, "vm_from_pu": 7.0, "vm_to_pu": 7.0, "x_ohm_per_km": 0.1897522}, "type": "Feature"}], "type": "FeatureCollection"}'


def test_convert_geodata_to_geojson():
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pandapower"
version = "3.0.0" # File format version '__format_version__' is tracked in _version.py
version = "3.1.0" # File format version '__format_version__' is tracked in _version.py
authors = [
{ name = "Leon Thurner", email = "[email protected]" },
{ name = "Alexander Scheidler", email = "[email protected]" }
Expand Down
Loading