Skip to content

Commit

Permalink
Merge branch 'e2nIEE:develop' into grid_equivalents
Browse files Browse the repository at this point in the history
  • Loading branch information
rbolgaryn authored Apr 12, 2022
2 parents 92b59a9 + 3b4d19f commit b355c75
Show file tree
Hide file tree
Showing 11 changed files with 5,881 additions and 48 deletions.
12 changes: 6 additions & 6 deletions doc/converter/powerfactory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ In order to start converter in engine mode, use the function "from_pfd": ::
Inputs:
* app: PowerFactory Application object
* prj_name: Name (”Project”), full qualified name (”Project.IntPrj”) or full qualified path (”nUsernProject.IntPrj”) of a project.
* path_dst: Destination for the export of .p file (full file path)
* path_dst: Destination for the export of .json file (full file path)
* pv_as_slack: whether "PV" nodes are imported as "Slack" nodes
* pf_variable_p_loads: variable to use as input for p_kw, can be 'plini', 'plini_a' or 'm:P:bus1'
* pf_variable_p_gen: variable to use as input for p_kw, can be 'pgini', 'pgini_a' or 'm:P:bus1'
Expand All @@ -96,11 +96,11 @@ In order to start converter in engine mode, use the function "from_pfd": ::
Output:
* net: pandapower net
* controller: pandapower controller objects
* Saves pandapower network as .p file at path_dst
* Saves pandapower network as .json file at path_dst

The function can be used as following: ::

from pandaplan.core.converter.powerfactory.pf2pp import from_pfd
from pandapower.converter.powerfactory import from_pfd
net = from_pfd(app, prj_name="Your Project Name", path_dst="Save Path")

.. Note:: PowerFactory has to be closed to start the conversion
Expand Down Expand Up @@ -203,7 +203,7 @@ symbol that is marked by a red circle in the following figure. The icon of the t
:align: center

When a project is activated, click on the icon. A window will appear, where the user is required to provide the path
for saving the .p file. The button 'Export' activates the export, and the button 'Cancel' terminates it.
for saving the .json file. The button 'Export' activates the export, and the button 'Cancel' terminates it.
The interface window is shown below:


Expand All @@ -220,7 +220,7 @@ The User interface has additional options that can be defined using CheckBoxes:
* Export 'PV' bus as Slack: defines whether 'PV' power injections are to be defined as Slack in pandapower
* Verify conversion: defines whether the network should be verified after the conversion. If the option is set, the
pandapower network will be verified by executing a load flow calculation and comparing the results to values in
PowerFactory. This happens after the .p file has been saved to the hard drive.
PowerFactory. This happens after the .json file has been saved to the hard drive.
* Logger in debug mode: can be used in case exporter stops at error. In this case more logging messages are shown.
* Export Controller: feature is not yet implemented with the user-defined tool

Expand Down Expand Up @@ -257,7 +257,7 @@ DIgSI/info - Python Script 'pp_export' started
| [2016/11/14 18:34:54] DIgSI/info - imported 1 impedances
| [2016/11/14 18:34:54] DIgSI/info - imported 2 lines
| [2016/11/14 18:34:54] DIgSI/info - created net and controller
| [2016/11/14 18:34:54] DIgSI/info - saving file to: <C:/pp_projects/test/test.p>
| [2016/11/14 18:34:54] DIgSI/info - saving file to: <C:/pp_projects/test/test.json>
| [2016/11/14 18:34:54] DIgSI/info - exported net:
This pandapower network includes the following parameter tables:
Expand Down
68 changes: 30 additions & 38 deletions pandapower/build_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,45 +385,38 @@ def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence=None):
voltage_depend_loads = net["_options"]["voltage_depend_loads"]
mode = net["_options"]["mode"]
pq_elements = ["load", "motor", "sgen", "storage", "ward", "xward"]
bus_lookup = net["_pd2ppc_lookups"]["bus"]
for element in pq_elements:
tab = net[element]
if len(tab):
if element == "load" and voltage_depend_loads:
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%!")

# cumulative sum of constant-current loads
b_zip = tab["bus"].values
load_counter = Counter(b_zip)

bus_lookup = net["_pd2ppc_lookups"]["bus"]
b_zip = bus_lookup[b_zip]
load_counter = {bus_lookup[k]: v for k, v in load_counter.items()}
b_zip, ci_sum, cz_sum = _sum_by_group(b_zip, ci, cz)

for bus, no_loads in load_counter.items():
ci_sum[b_zip == bus] /= no_loads
cz_sum[b_zip == bus] /= no_loads

ppc["bus"][b_zip, CID] = ci_sum
ppc["bus"][b_zip, CZD] = cz_sum
active = _is_elements[element]
sign = -1 if element == "sgen" else 1
if element == "motor":
p_mw, q_mvar = _get_motor_pq(net)
p = np.hstack([p, p_mw])
q = np.hstack([q, q_mvar])
elif element.endswith("ward"):
p = np.hstack([p, tab["ps_mw"].values * active * sign])
q = np.hstack([q, tab["qs_mvar"].values * active * sign])
else:
scaling = tab["scaling"].values
p = np.hstack([p, tab["p_mw"].values * active * scaling * sign])
q = np.hstack([q, tab["q_mvar"].values * active * scaling * sign])
b = np.hstack([b, tab["bus"].values])
if not len(tab):
continue
active = _is_elements[element]
if element == "load" and voltage_depend_loads:
if ((tab["const_z_percent"] + tab["const_i_percent"]) > 100).any():
raise ValueError("const_z_percent + const_i_percent need to "
"be less or equal to 100%!")
for bus in set(tab["bus"]):
mask = (tab["bus"] == bus) & active
no_loads = sum(mask)
if not no_loads:
continue
ci_sum = sum(tab["const_i_percent"][mask] / 100.)
ppc["bus"][bus_lookup[bus], CID] = ci_sum / no_loads
cz_sum = sum(tab["const_z_percent"][mask] / 100.)
ppc["bus"][bus_lookup[bus], CZD] = cz_sum / no_loads
sign = -1 if element == "sgen" else 1
if element == "motor":
p_mw, q_mvar = _get_motor_pq(net)
p = np.hstack([p, p_mw])
q = np.hstack([q, q_mvar])
elif element.endswith("ward"):
p = np.hstack([p, tab["ps_mw"].values * active * sign])
q = np.hstack([q, tab["qs_mvar"].values * active * sign])
else:
scaling = tab["scaling"].values
p = np.hstack([p, tab["p_mw"].values * active * scaling * sign])
q = np.hstack([q, tab["q_mvar"].values * active * scaling * sign])
b = np.hstack([b, tab["bus"].values])

for element in ["asymmetric_load", "asymmetric_sgen"]:
if len(net[element]) > 0 and mode == "pf":
Expand All @@ -435,7 +428,6 @@ def _calc_pq_elements_and_add_on_ppc(net, ppc, sequence=None):

# sum up p & q of bus elements
if b.size:
bus_lookup = net["_pd2ppc_lookups"]["bus"]
b = bus_lookup[b]
b, vp, vq = _sum_by_group(b, p, q)
ppc["bus"][b, PD] = vp
Expand Down
10 changes: 6 additions & 4 deletions pandapower/converter/powerfactory/pp_import_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,8 @@ def map_sgen_type_var(pf_sgen_type):


def get_power_multiplier(item, var):
if var == "m:P:bus1" and not item.HasResults():
raise UserWarning(f"{item} does not have results - cannot get power multiplier")
exponent = item.GetAttributeUnit(var)
if exponent.startswith('k'):
multiplier = 1e-3
Expand All @@ -1189,7 +1191,7 @@ def get_power_multiplier(item, var):


def ask_load_params(item, pf_variable_p_loads, dict_net, variables):
multiplier = get_power_multiplier(item, 'plini')
multiplier = get_power_multiplier(item, pf_variable_p_loads)
params = ADict()
if pf_variable_p_loads == 'm:P:bus1' and not item.HasResults(0):
raise RuntimeError('load %s does not have results and is ignored' % item.loc_name)
Expand Down Expand Up @@ -1623,7 +1625,7 @@ def get_pf_load_results(net, item, ld, is_unbalanced):


def ask_gen_params(item, pf_variable_p_gen, *vars):
multiplier = get_power_multiplier(item, 'pgini')
multiplier = get_power_multiplier(item, pf_variable_p_gen)
params = ADict()
if pf_variable_p_gen == 'm:P:bus1' and not item.HasResults(0):
raise RuntimeError('generator %s does not have results and is ignored' % item.loc_name)
Expand Down Expand Up @@ -1889,7 +1891,7 @@ def create_sgen_sym(net, item, pv_as_slack, pf_variable_p_gen, dict_net):
is_motor = bool(item.i_mot)
global_scaling = dict_net['global_parameters']['global_motor_scaling'] if is_motor else \
dict_net['global_parameters']['global_generation_scaling']
multiplier = get_power_multiplier(item, 'pgini')
multiplier = get_power_multiplier(item, pf_variable_p_gen)

if is_reference_machine or (av_mode == 'constv' and pv_as_slack):
logger.info('synchronous machine <%s> to be imported as external grid' % name)
Expand Down Expand Up @@ -1963,7 +1965,7 @@ def create_sgen_asm(net, item, pf_variable_p_gen, dict_net):
global_scaling = dict_net['global_parameters']['global_motor_scaling'] if is_motor else \
dict_net['global_parameters']['global_generation_scaling']

multiplier = get_power_multiplier(item, 'pgini')
multiplier = get_power_multiplier(item, pf_variable_p_gen)
p_res = ga(item, 'pgini') * multiplier
q_res = ga(item, 'qgini') * multiplier
if item.HasResults(0):
Expand Down
Loading

0 comments on commit b355c75

Please sign in to comment.