Skip to content

Commit

Permalink
Merge pull request e2nIEE#1394 from e2nIEE/warn_voltage_depend_loads
Browse files Browse the repository at this point in the history
complete Warn voltage depend loads
  • Loading branch information
SteffenMeinecke authored Nov 16, 2021
2 parents bfa0b10 + c6b68a6 commit c4b8c31
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 108 deletions.
77 changes: 42 additions & 35 deletions pandapower/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,15 @@ def __getattr__(self, key):

def __deepcopy__(self, memo):
"""
overloads the deepcopy function of pandapower if at least one DataFrame with column "object" is in net
overloads the deepcopy function of pandapower if at least one DataFrame with column
"object" is in net
in addition, line geodata can contain mutable objects like lists, and it is also treated specially
in addition, line geodata can contain mutable objects like lists, and it is also treated
specially
reason: some of these objects contain a reference to net which breaks the default deepcopy function.
Also, the DataFrame doesn't deepcopy its elements if geodata changes in the lists, it affects both net instances
reason: some of these objects contain a reference to net which breaks the default deepcopy
function. Also, the DataFrame doesn't deepcopy its elements if geodata changes in the
lists, it affects both net instances
This fix was introduced in pandapower 2.2.1
"""
Expand Down Expand Up @@ -404,8 +407,8 @@ def _check_connectivity_opf(ppc):
ppc['bus'][demoted_slacks, BUS_TYPE] = PV
logger.warning("Multiple connected slacks in one area found. This would probably lead "
"to non-convergence of the OPF. Therefore, all but one slack (ext_grid)"
" were changed to gens. To avoid undesired behaviour, rather convert the "
"slacks to gens yourself and set slack=True for only one of them.")
" were changed to gens. To avoid undesired behaviour, rather convert the"
" slacks to gens yourself and set slack=True for only one of them.")

isolated_nodes, pus, qus, ppc = _set_isolated_nodes_out_of_service(ppc, bus_not_reachable)
return isolated_nodes, pus, qus
Expand Down Expand Up @@ -482,7 +485,8 @@ def _python_set_elements_oos(ti, tis, bis, lis): # pragma: no cover
lis[i] = True


def _python_set_isolated_buses_oos(bus_in_service, ppc_bus_isolated, bus_lookup): # pragma: no cover
def _python_set_isolated_buses_oos(bus_in_service, ppc_bus_isolated,
bus_lookup): # pragma: no cover
for k in range(len(bus_in_service)):
if ppc_bus_isolated[bus_lookup[k]]:
bus_in_service[k] = False
Expand All @@ -509,8 +513,8 @@ def _select_is_elements_numba(net, isolated_nodes=None, sequence=None):
ppc_bus_isolated[isolated_nodes] = True
set_isolated_buses_oos(bus_in_service, ppc_bus_isolated, net["_pd2ppc_lookups"]["bus"])
# mode = net["_options"]["mode"]
elements = ["load", "motor", "sgen", "asymmetric_load", "asymmetric_sgen", "gen" \
, "ward", "xward", "shunt", "ext_grid", "storage"] # ,"impedance_load"
elements = ["load", "motor", "sgen", "asymmetric_load", "asymmetric_sgen", "gen",
"ward", "xward", "shunt", "ext_grid", "storage"] # ,"impedance_load"
is_elements = dict()
for element in elements:
len_ = len(net[element].index)
Expand Down Expand Up @@ -697,7 +701,8 @@ def _set_isolated_buses_out_of_service(net, ppc):
ppc["branch"][ppc["branch"][:, 10] == 1, :2].real.astype(int).flatten())

# but also check if they may be the only connection to an ext_grid
net._isolated_buses = np.setdiff1d(disco, ppc['bus'][ppc['bus'][:, 1] == REF, :1].real.astype(int))
net._isolated_buses = np.setdiff1d(disco, ppc['bus'][ppc['bus'][:, 1] == REF,
:1].real.astype(int))
ppc["bus"][net._isolated_buses, 1] = NONE


Expand Down Expand Up @@ -733,25 +738,26 @@ def _deactive(msg):
return False


def _check_lightsim2grid_compatibility(net, lightsim2grid, voltage_dependend_loads, algorithm, enforce_q_lims):
def _check_lightsim2grid_compatibility(net, lightsim2grid, voltage_dependend_loads, algorithm,
enforce_q_lims):
if lightsim2grid:
if not lightsim2grid_available:
return _deactive("option 'lightsim2grid' is True activates but module cannot be imported. "
"I'll deactive lightsim2grid.")
return _deactive("option 'lightsim2grid' is True activates but module cannot be "
"imported. lightsim2grid gets deactivet.")
if algorithm != 'nr':
raise ValueError("option 'lightsim2grid' is True activates but algorithm is not 'nr'.")
if voltage_dependend_loads:
return _deactive("option 'lightsim2grid' is True but voltage dependend loads are in your grid."
"I'll deactive lightsim2grid.")
return _deactive("option 'lightsim2grid' is True but voltage dependend loads are in "
"your grid. lightsim2grid gets deactivet.")
if enforce_q_lims:
return _deactive("option 'lightsim2grid' is True and enforce_q_lims is True. This is not supported."
"I'll deactive lightsim2grid.")
return _deactive("option 'lightsim2grid' is True and enforce_q_lims is True. This is "
"not supported. lightsim2grid gets deactivet.")
if len(net.ext_grid) > 1:
return _deactive("option 'lightsim2grid' is True and multiple ext_grids are in the grid."
"I'll deactive lightsim2grid.")
return _deactive("option 'lightsim2grid' is True and multiple ext_grids are in the "
"grid. lightsim2grid gets deactivet.")
if np.any(net.gen.bus.isin(net.ext_grid.bus)):
return _deactive("option 'lightsim2grid' is True and gens are at slack buses."
"I'll deactive lightsim2grid.")
"lightsim2grid gets deactivet.")

return lightsim2grid

Expand Down Expand Up @@ -973,10 +979,6 @@ def _init_runpp_options(net, algorithm, calculate_voltage_angles, init,
or np.any(net["load"]["const_i_percent"].values)):
voltage_depend_loads = False

if algorithm not in ['nr', 'bfsw', 'iwamoto_nr'] and voltage_depend_loads == True:
logger.warning("voltage-dependent loads not supported for {0} power flow algorithm -> "
"loads will be considered as constant power".format(algorithm))

lightsim2grid = _check_lightsim2grid_compatibility(net, lightsim2grid, voltage_depend_loads,
algorithm, enforce_q_lims)

Expand All @@ -1001,8 +1003,8 @@ def _init_runpp_options(net, algorithm, calculate_voltage_angles, init,
"'init_va_degree'.")

init_from_results = init == "results" or \
(isinstance(init_vm_pu, str) and init_vm_pu == "results") or \
(isinstance(init_va_degree, str) and init_va_degree == "results")
(isinstance(init_vm_pu, str) and init_vm_pu == "results") or \
(isinstance(init_va_degree, str) and init_va_degree == "results")
if init_from_results and len(net.res_bus) == 0:
init = "auto"
init_vm_pu = None
Expand All @@ -1022,14 +1024,16 @@ def _init_runpp_options(net, algorithm, calculate_voltage_angles, init,
init_va_degree = init

if distributed_slack:
false_slack_weight_elms = [elm for elm in {'asymmetric_load', 'asymmetric_sgen', 'load', 'sgen', 'shunt',
'storage', 'ward'} if "slack_weight" in net[elm].columns]
false_slack_weight_elms = [elm for elm in {
'asymmetric_load', 'asymmetric_sgen', 'load', 'sgen', 'shunt',
'storage', 'ward'} if "slack_weight" in net[elm].columns]
if len(false_slack_weight_elms):
logger.warning("Currently distributed_slack is implemented for 'ext_grid', 'gen' and 'xward'" +
"only, not for '" + "', '".join(false_slack_weight_elms) + "'.")
logger.warning("Currently distributed_slack is implemented for 'ext_grid', 'gen' "
"and 'xward' only, not for '" + "', '".join(
false_slack_weight_elms) + "'.")
if algorithm != 'nr':
raise NotImplementedError('Distributed slack is only implemented for Newton Raphson algorithm.')

raise NotImplementedError(
'Distributed slack is only implemented for Newton Raphson algorithm.')

# init options
net._options = {}
Expand Down Expand Up @@ -1109,11 +1113,13 @@ def _init_runopp_options(net, calculate_voltage_angles, check_connectivity, swit
voltage_depend_loads=kwargs.get("voltage_depend_loads", False),
delta=delta, trafo3w_losses=trafo3w_losses,
consider_line_temperature=consider_line_temperature)
_add_opf_options(net, trafo_loading=trafo_loading, ac=ac, init=init, numba=numba, lightsim2grid=lightsim2grid,
_add_opf_options(net, trafo_loading=trafo_loading, ac=ac, init=init, numba=numba,
lightsim2grid=lightsim2grid,
only_v_results=only_v_results, use_umfpack=use_umfpack, permc_spec=permc_spec)


def _init_rundcopp_options(net, check_connectivity, switch_rx_ratio, delta, trafo3w_losses, **kwargs):
def _init_rundcopp_options(net, check_connectivity, switch_rx_ratio, delta, trafo3w_losses,
**kwargs):
mode = "opf"
ac = False
init = "flat"
Expand All @@ -1133,7 +1139,8 @@ def _init_rundcopp_options(net, check_connectivity, switch_rx_ratio, delta, traf
mode=mode, switch_rx_ratio=switch_rx_ratio, init_vm_pu=init,
init_va_degree=init, enforce_q_lims=enforce_q_lims, recycle=recycle,
voltage_depend_loads=False, delta=delta, trafo3w_losses=trafo3w_losses)
_add_opf_options(net, trafo_loading=trafo_loading, init=init, ac=ac, only_v_results=only_v_results,
_add_opf_options(net, trafo_loading=trafo_loading, init=init, ac=ac,
only_v_results=only_v_results,
use_umfpack=use_umfpack, permc_spec=permc_spec)


Expand Down
39 changes: 23 additions & 16 deletions pandapower/build_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import pandas as pd

from pandapower.auxiliary import _sum_by_group, phase_to_sequence
from pandapower.pypower.idx_bus import BUS_I, BASE_KV, PD, QD, GS, BS, VMAX, VMIN, BUS_TYPE, NONE, VM, VA, \
CID, CZD, bus_cols, REF
from pandapower.pypower.idx_bus import BUS_I, BASE_KV, PD, QD, GS, BS, VMAX, VMIN, BUS_TYPE, NONE, \
VM, VA, CID, CZD, bus_cols, REF

try:
from numba import jit
Expand Down Expand Up @@ -81,7 +81,8 @@ def create_bus_lookup_numba(net, bus_index, bus_is_idx, gen_is_mask, eg_is_mask)
bus_is_pv[net["gen"]["bus"].values[gen_is_mask]] = True
# create array that represents the disjoint set
ar = np.arange(max_bus_idx + 1)
ds_create(ar, switch_bus, switch_elm, switch_et_bus, switch_closed, switch_z_ohm, bus_is_pv, bus_in_service)
ds_create(ar, switch_bus, switch_elm, switch_et_bus, switch_closed, switch_z_ohm, bus_is_pv,
bus_in_service)
# finally create and fill bus lookup
bus_lookup = -np.ones(max_bus_idx + 1, dtype=int)
fill_bus_lookup(ar, bus_lookup, bus_index)
Expand Down Expand Up @@ -116,7 +117,8 @@ def create_consecutive_bus_lookup(net, bus_index):
return bus_lookup


def create_bus_lookup_numpy(net, bus_index, bus_is_idx, gen_is_mask, eg_is_mask, closed_bb_switch_mask):
def create_bus_lookup_numpy(net, bus_index, bus_is_idx, gen_is_mask, eg_is_mask,
closed_bb_switch_mask):
bus_lookup = create_consecutive_bus_lookup(net, bus_index)
net._fused_bb_switches = closed_bb_switch_mask & (net["switch"]["z_ohm"].values <= 0)
if net._fused_bb_switches.any():
Expand Down Expand Up @@ -210,8 +212,8 @@ def get_voltage_init_vector(net, init_v, mode, sequence=None):
if res_table not in net or not net[res_table].index.equals(net.bus.index):
# cannot init from results, since sorting of results is different from element table
# TO BE REVIEWED! Why there was no raise before this commit?
raise UserWarning("Init from results not possible. Index of %s do not match with bus. "
"You should sort res_bus before calling runpp." % res_table)
raise UserWarning("Init from results not possible. Index of %s do not match with "
"bus. You should sort res_bus before calling runpp." % res_table)

if res_table == "res_bus_3ph":
vm = net.res_bus_3ph[["vm_a_pu", "vm_b_pu", "vm_c_pu"]].values.T
Expand Down Expand Up @@ -375,7 +377,7 @@ def set_reference_buses(net, ppc, bus_lookup, mode):
ppc["bus"][bus_lookup[slack_buses], BUS_TYPE] = REF


def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence= None):
def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence=None):
# init values
b, p, q = np.array([], dtype=int), np.array([]), np.array([])

Expand All @@ -390,8 +392,8 @@ def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence= None):
cz = tab["const_z_percent"].values / 100.
ci = tab["const_i_percent"].values / 100.
if ((cz + ci) > 1).any():
raise ValueError("const_z_percent + const_i_percent need to be less or equal to " +
"100%!")
raise ValueError("const_z_percent + const_i_percent need to be less or equal " +
"to 100%!")

# cumulative sum of constant-current loads
b_zip = tab["bus"].values
Expand Down Expand Up @@ -428,7 +430,7 @@ def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence= None):
p_mw, q_mvar = _get_symmetric_pq_of_unsymetric_element(net, element)
sign = -1 if element.endswith("sgen") else 1
p = np.hstack([p, p_mw * sign])
q = np.hstack([q, q_mvar * sign ])
q = np.hstack([q, q_mvar * sign])
b = np.hstack([b, net[element]["bus"].values])

# sum up p & q of bus elements
Expand All @@ -446,10 +448,11 @@ def _get_symmetric_pq_of_unsymetric_element(net, element):
p_mw = np.sum(net[element][["p_a_mw", "p_b_mw", "p_c_mw"]].values, axis=1)
return p_mw*scale, q_mvar*scale


def _get_motor_pq(net):
tab = net["motor"]
active = net._is_elements["motor"]
scale = tab["loading_percent"].values/100 *tab["scaling"].values*active
scale = tab["loading_percent"].values/100 * tab["scaling"].values*active

efficiency = tab["efficiency_percent"].values
p_mech = tab["pn_mech_mw"].values
Expand All @@ -460,6 +463,7 @@ def _get_motor_pq(net):
q_mvar = np.sqrt(s_mvar**2 - p_mw**2)
return p_mw, q_mvar


def _calc_shunts_and_add_on_ppc(net, ppc):
# init values
b, p, q = np.array([], dtype=int), np.array([]), np.array([])
Expand Down Expand Up @@ -516,6 +520,7 @@ def _calc_shunts_and_add_on_ppc(net, ppc):
ppc["bus"][b, GS] = vp
ppc["bus"][b, BS] = -vq


# Short circuit relevant routines
def _add_ext_grid_sc_impedance(net, ppc):
from pandapower.shortcircuit.idx_bus import C_MAX, C_MIN
Expand All @@ -536,12 +541,12 @@ def _add_ext_grid_sc_impedance(net, ppc):
else:
c = 1.1
if not "s_sc_%s_mva" % case in eg:
raise ValueError("short circuit apparent power s_sc_%s_mva needs to be specified for "% case +
"external grid \n Try: net.ext_grid['s_sc_max_mva'] = 1000" )
raise ValueError(("short circuit apparent power s_sc_%s_mva needs to be specified for "
"external grid \n Try: net.ext_grid['s_sc_max_mva'] = 1000") % case)
s_sc = eg["s_sc_%s_mva" % case].values/ppc['baseMVA']
if not "rx_%s" % case in eg:
raise ValueError("short circuit R/X rate rx_%s needs to be specified for external grid \n Try: net.ext_grid['rx_max'] = 0.1" %
case)
raise ValueError(("short circuit R/X rate rx_%s needs to be specified for external grid \n"
" Try: net.ext_grid['rx_max'] = 0.1") % case)
rx = eg["rx_%s" % case].values

z_grid = c / s_sc
Expand All @@ -562,6 +567,7 @@ def _add_ext_grid_sc_impedance(net, ppc):
ppc["bus"][buses, BS] = bs * ppc['baseMVA']
return gs * ppc['baseMVA'], bs * ppc['baseMVA']


def _add_motor_impedances_ppc(net, ppc):
if net._options["case"] == "min":
return
Expand All @@ -570,7 +576,8 @@ def _add_motor_impedances_ppc(net, ppc):
return
for par in ["vn_kv", "lrc_pu", "efficiency_n_percent", "cos_phi_n", "rx", "pn_mech_mw"]:
if any(pd.isnull(motor[par])):
raise UserWarning("%s needs to be specified for all motors in net.motor.%s" % (par, par))
raise UserWarning("%s needs to be specified for all motors in net.motor.%s" % (
par, par))
bus_lookup = net["_pd2ppc_lookups"]["bus"]
motor_buses_ppc = bus_lookup[motor.bus.values]
vn_net = ppc["bus"][motor_buses_ppc, BASE_KV]
Expand Down
Loading

0 comments on commit c4b8c31

Please sign in to comment.