-
Notifications
You must be signed in to change notification settings - Fork 466
/
run.py
558 lines (422 loc) · 30.2 KB
/
run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
# -*- coding: utf-8 -*-
# Copyright (c) 2016-2024 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.
import inspect
from pandapower.auxiliary import _check_bus_index_and_print_warning_if_high, \
_check_gen_index_and_print_warning_if_high, _init_runpp_options, _init_rundcopp_options, \
_init_rundcpp_options, _init_runopp_options, _internal_stored
from pandapower.opf.validate_opf_input import _check_necessary_opf_parameters
from pandapower.powerflow import _powerflow, _recycled_powerflow
from pandapower.optimal_powerflow import _optimal_powerflow
try:
import pandaplan.core.pplog as logging
except ImportError:
import logging
try:
from power_grid_model import PowerGridModel, CalculationType, CalculationMethod
from power_grid_model.errors import PowerGridError
from power_grid_model.validation import validate_input_data
from power_grid_model_io.converters import PandaPowerConverter
PGM_IMPORTED = True
except ImportError:
PGM_IMPORTED = False
logger = logging.getLogger(__name__)
def set_user_pf_options(net, overwrite=False, **kwargs):
"""
This function sets the 'user_pf_options' dict for net. These options overrule
net.__internal_options once they are added to net. These options are used in configuration of
load flow calculation.
At the same time, user-defined arguments for pandapower.runpp() always have a higher priority.
To remove user_pf_options, set overwrite=True and provide no additional arguments
:param net: pandaPower network
:param overwrite: specifies whether the user_pf_options is removed before setting new options
:param kwargs: load flow options, e. g. tolerance_mva = 1e-3
:return: None
"""
standard_parameters = ['calculate_voltage_angles', 'trafo_model', 'check_connectivity', 'mode',
'copy_constraints_to_ppc', 'switch_rx_ratio', 'enforce_q_lims',
'recycle', 'voltage_depend_loads', 'consider_line_temperature', 'delta',
'trafo3w_losses', 'init', 'init_vm_pu', 'init_va_degree', 'init_results',
'tolerance_mva', 'trafo_loading', 'numba', 'ac', 'algorithm',
'max_iteration', 'v_debug', 'run_control', 'distributed_slack', 'lightsim2grid',
'tdpf', 'tdpf_delay_s', 'tdpf_update_r_theta']
if overwrite or 'user_pf_options' not in net.keys():
net['user_pf_options'] = dict()
net.user_pf_options.update({key: val for key, val in kwargs.items()
if key in standard_parameters})
additional_kwargs = {key: val for key, val in kwargs.items()
if key not in standard_parameters}
# this part is to inform user and to make typos in parameters visible
if len(additional_kwargs) > 0:
logger.info('parameters %s are not in the list of standard options' % list(
additional_kwargs.keys()))
net.user_pf_options.update(additional_kwargs)
def runpp(net, algorithm='nr', calculate_voltage_angles=True, init="auto",
max_iteration="auto", tolerance_mva=1e-8, trafo_model="t",
trafo_loading="current", enforce_q_lims=False, check_connectivity=True,
voltage_depend_loads=True, consider_line_temperature=False,
run_control=False, distributed_slack=False, tdpf=False, tdpf_delay_s=None, **kwargs):
"""
Runs a power flow
INPUT:
**net** - The pandapower format network
OPTIONAL:
**algorithm** (str, "nr") - algorithm that is used to solve the power flow problem.
The following algorithms are available:
- "nr" Newton-Raphson (pypower implementation with numba accelerations)
- "iwamoto_nr" Newton-Raphson with Iwamoto multiplier (maybe slower than NR but more robust)
- "bfsw" backward/forward sweep (specially suited for radial and weakly-meshed networks)
- "gs" gauss-seidel (pypower implementation)
- "fdbx" fast-decoupled (pypower implementation)
- "fdxb" fast-decoupled (pypower implementation)
**calculate_voltage_angles** (str or bool, True) - consider voltage angles in loadflow calculation
If True, voltage angles of ext_grids and transformer shifts are considered in the
loadflow calculation. Considering the voltage angles is only necessary in meshed
networks that are usually found in higher voltage levels. calculate_voltage_angles
in "auto" mode defaults to:
- True, if the network voltage level is above 70 kV
- False otherwise
The network voltage level is defined as the maximum rated voltage of any bus in the network that
is connected to a line.
**init** (str, "auto") - initialization method of the loadflow
pandapower supports four methods for initializing the loadflow:
- "auto" - init defaults to "dc" if calculate_voltage_angles is True or "flat" otherwise
- "flat"- flat start with voltage of 1.0pu and angle of 0° at all PQ-buses and 0° for PV buses as initial solution, the slack bus is initialized with the values provided in net["ext_grid"]
- "dc" - initial DC loadflow before the AC loadflow. The results of the DC loadflow are used as initial solution for the AC loadflow. Note that the DC loadflow only calculates voltage angles at PQ and PV buses, voltage magnitudes are still flat started.
- "results" - voltage vector of last loadflow from net.res_bus is used as initial solution. This can be useful to accelerate convergence in iterative loadflows like time series calculations.
Considering the voltage angles might lead to non-convergence of the power flow in flat start.
That is why in "auto" mode, init defaults to "dc" if calculate_voltage_angles is True or "flat" otherwise
**max_iteration** (int, "auto") - maximum number of iterations carried out in the power flow algorithm.
In "auto" mode, the default value depends on the power flow solver:
- 10 for "nr"
- 100 for "bfsw"
- 1000 for "gs"
- 30 for "fdbx"
- 30 for "fdxb"
- 30 for "nr" with "tdpf"
**tolerance_mva** (float, 1e-8) - loadflow termination condition referring to P / Q mismatch of node power in MVA
**trafo_model** (str, "t") - transformer equivalent circuit model
pandapower provides two equivalent circuit models for the transformer:
- "t" - transformer is modeled as equivalent with the T-model.
- "pi" - transformer is modeled as equivalent PI-model. This is not recommended, since it is less exact than the T-model. It is only recommended for valdiation with other software that uses the pi-model.
**trafo_loading** (str, "current") - mode of calculation for transformer loading
Transformer loading can be calculated relative to the rated current or the rated power. In both cases the overall transformer loading is defined as the maximum loading on the two sides of the transformer.
- "current"- transformer loading is given as ratio of current flow and rated current of the transformer. This is the recommended setting, since thermal as well as magnetic effects in the transformer depend on the current.
- "power" - transformer loading is given as ratio of apparent power flow to the rated apparent power of the transformer.
**enforce_q_lims** (bool, False) - respect generator reactive power limits
If True, the reactive power limits in net.gen.max_q_mvar/min_q_mvar are respected in the
loadflow. This is done by running a second loadflow if reactive power limits are
violated at any generator, so that the runtime for the loadflow will increase if reactive
power has to be curtailed.
Note: enforce_q_lims only works if algorithm="nr"!
**check_connectivity** (bool, True) - Perform an extra connectivity test after the conversion from pandapower to PYPOWER
If True, an extra connectivity test based on SciPy Compressed Sparse Graph Routines is perfomed.
If check finds unsupplied buses, they are set out of service in the ppc
**voltage_depend_loads** (bool, True) - consideration of voltage-dependent loads. If False, net.load.const_z_percent and net.load.const_i_percent are not considered, i.e. net.load.p_mw and net.load.q_mvar are considered as constant-power loads.
**consider_line_temperature** (bool, False) - adjustment of line impedance based on provided
line temperature. If True, net.line must contain a column "temperature_degree_celsius".
The temperature dependency coefficient alpha must be provided in the net.line.alpha
column, otherwise the default value of 0.004 is used
**distributed_slack** (bool, False) - Distribute slack power
according to contribution factor weights for external grids
and generators.
**tdpf** (bool, False) - Temperature Dependent Power Flow (TDPF). If True, line temperature is calculated based on the TDPF parameters in net.line table.
**tdpf_delay_s** (float, None) - TDPF parameter, specifies the time delay in s to consider thermal inertia of conductors.
**KWARGS**:
**lightsim2grid** ((bool,str), "auto") - whether to use the package lightsim2grid for power flow backend
**numba** (bool, True) - Activation of numba JIT compiler in the newton solver
If set to True, the numba JIT compiler is used to generate matrices for the powerflow,
which leads to significant speed improvements.
**switch_rx_ratio** (float, 2) - rx_ratio of bus-bus-switches. If impedance is zero, buses connected by a closed bus-bus switch are fused to model an ideal bus. Otherwise, they are modelled as branches with resistance defined as z_ohm column in switch table and this parameter
**delta_q** - Reactive power tolerance for option "enforce_q_lims" in kvar - helps convergence in some cases.
**trafo3w_losses** - defines where open loop losses of three-winding transformers are considered. Valid options are "hv", "mv", "lv" for HV/MV/LV side or "star" for the star point.
**v_debug** (bool, False) - if True, voltage values in each newton-raphson iteration are logged in the ppc
**init_vm_pu** (string/float/array/Series, None) - Allows to define initialization specifically for voltage magnitudes. Only works with init == "auto"!
- "auto": all buses are initialized with the mean value of all voltage controlled elements in the grid
- "flat" for flat start from 1.0
- "results": voltage magnitude vector is taken from result table
- a float with which all voltage magnitudes are initialized
- an iterable with a voltage magnitude value for each bus (length and order has to match with the buses in net.bus)
- a pandas Series with a voltage magnitude value for each bus (indexes have to match the indexes in net.bus)
**init_va_degree** (string/float/array/Series, None) - Allows to define initialization specifically for voltage angles. Only works with init == "auto"!
- "auto": voltage angles are initialized from DC power flow if angles are calculated or as 0 otherwise
- "dc": voltage angles are initialized from DC power flow
- "flat" for flat start from 0
- "results": voltage angle vector is taken from result table
- a float with which all voltage angles are initialized
- an iterable with a voltage angle value for each bus (length and order has to match with the buses in net.bus)
- a pandas Series with a voltage angle value for each bus (indexes have to match the indexes in net.bus)
**recycle** (dict, none) - Reuse of internal powerflow variables for time series calculation
Contains a dict with the following parameters:
bus_pq: If True PQ values of buses are updated
trafo: If True trafo relevant variables, e.g., the Ybus matrix, is recalculated
gen: If True Sbus and the gen table in the ppc are recalculated
**neglect_open_switch_branches** (bool, False) - If True no auxiliary buses are created for branches when switches are opened at the branch. Instead branches are set out of service
**tdpf_update_r_theta** (bool, True) - TDPF parameter, whether to update R_Theta in Newton-Raphson or to assume a constant R_Theta (either from net.line.r_theta, if set, or from a calculation based on the thermal model of Ngoko et.al.)
"""
# if dict 'user_pf_options' is present in net, these options overrule the net._options
# except for parameters that are passed by user
if isinstance(kwargs.get("recycle", None), dict) and _internal_stored(net):
_recycled_powerflow(net, **kwargs)
return
if run_control and net.controller.in_service.any():
from pandapower.control import run_control
parameters = {**locals(), **kwargs}
# disable run control for inner loop to avoid infinite loop
parameters["run_control"] = False
run_control(**parameters)
else:
passed_parameters = _passed_runpp_parameters(locals())
_init_runpp_options(net, algorithm=algorithm,
calculate_voltage_angles=calculate_voltage_angles,
init=init, max_iteration=max_iteration, tolerance_mva=tolerance_mva,
trafo_model=trafo_model, trafo_loading=trafo_loading,
enforce_q_lims=enforce_q_lims, check_connectivity=check_connectivity,
voltage_depend_loads=voltage_depend_loads,
consider_line_temperature=consider_line_temperature,
tdpf=tdpf, tdpf_delay_s=tdpf_delay_s,
distributed_slack=distributed_slack,
passed_parameters=passed_parameters, **kwargs)
_check_bus_index_and_print_warning_if_high(net)
_check_gen_index_and_print_warning_if_high(net)
_powerflow(net, **kwargs)
def runpp_pgm(net, algorithm="nr", max_iterations=20, error_tolerance_vm_pu=1e-8, symmetric=True, validate_input=False):
"""
Runs powerflow using power-grid-model library
INPUT:
**net** - The pandapower format network
OPTIONAL:
**symmetric** (bool, True) -
- True: three-phase symmetric calculation, even for asymmetric loads/generations
- False: three-phase asymmetric calculation
**algorithm** (str, "nr") - Algorithms available in power-grid-model.
Check power-grid-model documentation for detailed information on the algorithms.
- "nr" - Newton Raphson algorithm
- "bfsw" - Iterative current algorithm. Similar to backward-forward sweep algorithm
- "lc" - Linear current approximation algorithm
- "lin" - Linear approximation algorithm
**error_tolerance_u_pu** (float, 1e-8) - error tolerance for voltage in p.u.
**max_iterations** (int, 20) - Maximum number of iterations for algorithms.
No effect on linear approximation algorithms.
**validate_input** (bool, False) - Validate input data to be used for power-flow in power-grid-model.
It is recommended to use pandapower.diagnostic tool prior.
"""
if not PGM_IMPORTED:
raise ImportError(
"Power Grid Model import failed. Try using `pip install pandapower[pgm]` to install the required packages."
)
# 1. Determine the Power Grid Model calculation type corresponding to the algorithm:
algorithm_map = {
"nr": CalculationMethod.newton_raphson,
"lin": CalculationMethod.linear,
"bfsw": CalculationMethod.iterative_current,
"lc": CalculationMethod.linear_current
}
if algorithm not in algorithm_map:
raise KeyError(f"Invalid algorithm '{algorithm}'")
calculation_method = algorithm_map[algorithm]
# 2. Convert the pandapower data to the power grid model format. Ignoring the 'extra info', which is a
# dictionary representation of the internal state of the PandaPowerConverter.
pgm_converter = PandaPowerConverter()
pgm_input_data, _extra_info = pgm_converter.load_input_data(net, make_extra_info=False)
# 3. If required, validate the input data
if validate_input:
validation_errors = validate_input_data(
pgm_input_data, calculation_type=CalculationType.power_flow, symmetric=symmetric
)
# If there were validation errors, convert the errors to a human readable test and log each error for
# each element in the input data.
if validation_errors:
for i, error in enumerate(validation_errors, start=1):
pp_obj = (pgm_converter.lookup_id(pgm_id) for pgm_id in error.ids)
pp_obj = (f"{obj['table']}-{obj['index']}" for obj in pp_obj)
pp_obj = ", ".join(pp_obj)
logger.error(f"{i}. Power Grid Model validation error: Check {pp_obj}")
logger.debug(f"{i}. Native Power Grid Model error: {error}")
# 4. Create a PowerGridModel and calculate the powerflow
try:
pgm = PowerGridModel(input_data=pgm_input_data)
output_data = pgm.calculate_power_flow(
symmetric=symmetric,
error_tolerance=error_tolerance_vm_pu,
max_iterations=max_iterations,
calculation_method=calculation_method
)
net["converged"] = True
# Stop execution if a power PowerGridError was raised and log the error
except PowerGridError as ex:
logger.critical(f"Internal {type(ex).__name__} occurred!")
logger.debug(str(ex))
if not validate_input:
logger.info("Use validate_input=True to validate your input data.")
net["converged"] = False
return
# 5. Convert the Power Grid Model output data back to the pandapower format and update the pandapower net
converted_output_data = pgm_converter.convert(data=output_data)
for table in converted_output_data.keys():
net[table] = converted_output_data[table]
def rundcpp(net, trafo_model="t", trafo_loading="current", recycle=None, check_connectivity=True,
switch_rx_ratio=2, trafo3w_losses="hv", **kwargs):
"""
Runs PANDAPOWER DC Flow
INPUT:
**net** - The pandapower format network
OPTIONAL:
**trafo_model** (str, "t") - transformer equivalent circuit model
pandapower provides two equivalent circuit models for the transformer:
- "t" - transformer is modeled as equivalent with the T-model. This is consistent with PowerFactory and is also more accurate than the PI-model. We recommend using this transformer model.
- "pi" - transformer is modeled as equivalent PI-model. This is consistent with Sincal, but the method is questionable since the transformer is physically T-shaped. We therefore recommend the use of the T-model.
**trafo_loading** (str, "current") - mode of calculation for transformer loading
Transformer loading can be calculated relative to the rated current or the rated power. In both cases the overall transformer loading is defined as the maximum loading on the two sides of the transformer.
- "current"- transformer loading is given as ratio of current flow and rated current of the transformer. This is the recommended setting, since thermal as well as magnetic effects in the transformer depend on the current.
- "power" - transformer loading is given as ratio of apparent power flow to the rated apparent power of the transformer.
**check_connectivity** (bool, False) - Perform an extra connectivity test after the conversion from pandapower to PYPOWER
If true, an extra connectivity test based on SciPy Compressed Sparse Graph Routines is perfomed.
If check finds unsupplied buses, they are put out of service in the PYPOWER matrix
**switch_rx_ratio** (float, 2) - rx_ratio of bus-bus-switches. If impedance is zero, buses connected by a closed bus-bus switch are fused to model an ideal bus. Otherwise, they are modelled as branches with resistance defined as z_ohm column in switch table and this parameter
**trafo3w_losses** (str, "hv") - defines where open loop losses of three-winding transformers are considered. Valid options are "hv", "mv", "lv" for HV/MV/LV side or "star" for the star point.
**kwargs** - options to use for PYPOWER.runpf
"""
_init_rundcpp_options(net, trafo_model=trafo_model, trafo_loading=trafo_loading,
recycle=recycle, check_connectivity=check_connectivity,
switch_rx_ratio=switch_rx_ratio, trafo3w_losses=trafo3w_losses, **kwargs)
if isinstance(recycle, dict) and _internal_stored(net, ac=False):
_recycled_powerflow(net, recycle=recycle, **kwargs)
return
_check_bus_index_and_print_warning_if_high(net)
_check_gen_index_and_print_warning_if_high(net)
_powerflow(net, **kwargs)
def runopp(net, verbose=False, calculate_voltage_angles=True, check_connectivity=True,
suppress_warnings=True, switch_rx_ratio=2, delta=1e-10, init="flat", numba=True,
trafo3w_losses="hv", consider_line_temperature=False, **kwargs):
"""
Runs the pandapower Optimal Power Flow.
Flexibilities, constraints and cost parameters are defined in the pandapower element tables.
Flexibilities can be defined in net.sgen / net.gen /net.load / net.storage /net.ext_grid
net.sgen.controllable if a static generator is controllable. If False,
the active and reactive power are assigned as in a normal power flow. If True, the following
flexibilities apply:
- net.gen.min_p_mw / net.gen.max_p_mw
- net.gen.min_q_mvar / net.gen.max_q_mvar
- net.sgen.min_p_mw / net.sgen.max_p_mw
- net.sgen.min_q_mvar / net.sgen.max_q_mvar
- net.dcline.max_p_mw
- net.dcline.min_q_to_mvar / net.dcline.max_q_to_mvar / net.dcline.min_q_from_mvar / net.dcline.max_q_from_mvar
- net.ext_grid.min_p_mw / net.ext_grid.max_p_mw
- net.ext_grid.min_q_mvar / net.ext_grid.max_q_mvar
- net.load.min_p_mw / net.load.max_p_mw
- net.load.min_q_mvar / net.load.max_q_mvar
- net.storage.min_p_mw / net.storage.max_p_mw
- net.storage.min_q_mvar / net.storage.max_q_mvar
Controllable loads behave just like controllable static generators. It must be stated if they are controllable.
Otherwise, they are not respected as flexibilities.
Dc lines are controllable per default
Network constraints can be defined for buses, lines and transformers the elements in the following columns:
- net.bus.min_vm_pu / net.bus.max_vm_pu
- net.line.max_loading_percent
- net.trafo.max_loading_percent
- net.trafo3w.max_loading_percent
If the external grid ist controllable, the voltage setpoint of the external grid can be optimized within the
voltage constraints by the OPF. The same applies to the voltage setpoints of the controllable generator elements.
How these costs are combined into a cost function depends on the cost_function parameter.
INPUT:
**net** - The pandapower format network
OPTIONAL:
**verbose** (bool, False) - If True, some basic information is printed
**suppress_warnings** (bool, True) - suppress warnings in pypower
If set to True, warnings are disabled during the loadflow. Because of the way data is
processed in pypower, ComplexWarnings are raised during the loadflow.
These warnings are suppressed by this option, however keep in mind all other pypower
warnings are suppressed, too.
**init** (str, "flat") - init of starting opf vector. Options are "flat", "pf" or "results"
Starting solution vector (x0) for opf calculations is determined by this flag. Options are:
"flat" (default): starting vector is (upper bound - lower bound) / 2
"pf": a power flow is executed prior to the opf and the pf solution is the starting vector. This may improve
convergence, but takes a longer runtime (which are probably neglectible for opf calculations)
"results": voltage magnitude vector is taken from result table
**delta** (float, 1e-10) - power tolerance
**trafo3w_losses** (str, "hv") - defines where open loop losses of three-winding transformers are considered. Valid options are "hv", "mv", "lv" for HV/MV/LV side or "star" for the star point.
**consider_line_temperature** (bool, False) - adjustment of line impedance based on provided\
line temperature. If True, net.line must contain a column "temperature_degree_celsius".\
The temperature dependency coefficient alpha must be provided in the net.line.alpha\
column, otherwise the default value of 0.004 is used
**kwargs** - Pypower / Matpower keyword arguments:
- OPF_VIOLATION (5e-6) constraint violation tolerance
- PDIPM_COSTTOL (1e-6) optimality tolerance
- PDIPM_GRADTOL (1e-6) gradient tolerance
- PDIPM_COMPTOL (1e-6) complementarity condition (inequality) tolerance
- PDIPM_FEASTOL (set to OPF_VIOLATION if not specified) feasibiliy (equality) tolerance
- PDIPM_MAX_IT (150) maximum number of iterations
- SCPDIPM_RED_IT(20) maximum number of step size reductions per iteration
"""
_check_necessary_opf_parameters(net, logger)
_init_runopp_options(net, calculate_voltage_angles=calculate_voltage_angles,
check_connectivity=check_connectivity,
switch_rx_ratio=switch_rx_ratio, delta=delta, init=init, numba=numba,
trafo3w_losses=trafo3w_losses,
consider_line_temperature=consider_line_temperature, **kwargs)
_check_bus_index_and_print_warning_if_high(net)
_check_gen_index_and_print_warning_if_high(net)
_optimal_powerflow(net, verbose, suppress_warnings, **kwargs)
def rundcopp(net, verbose=False, check_connectivity=True, suppress_warnings=True,
switch_rx_ratio=0.5, delta=1e-10, trafo3w_losses="hv", **kwargs):
"""
Runs the pandapower Optimal Power Flow.
Flexibilities, constraints and cost parameters are defined in the pandapower element tables.
Flexibilities for generators can be defined in net.sgen / net.gen.
net.sgen.controllable / net.gen.controllable signals if a generator is controllable. If False,
the active and reactive power are assigned as in a normal power flow. If yes, the following
flexibilities apply:
- net.sgen.min_p_mw / net.sgen.max_p_mw
- net.gen.min_p_mw / net.gen.max_p_mw
- net.load.min_p_mw / net.load.max_p_mw
Network constraints can be defined for buses, lines and transformers the elements in the following columns:
- net.line.max_loading_percent
- net.trafo.max_loading_percent
- net.trafo3w.max_loading_percent
INPUT:
**net** - The pandapower format network
OPTIONAL:
**verbose** (bool, False) - If True, some basic information is printed
**suppress_warnings** (bool, True) - suppress warnings in pypower
If set to True, warnings are disabled during the loadflow. Because of the way data is
processed in pypower, ComplexWarnings are raised during the loadflow.
These warnings are suppressed by this option, however keep in mind all other pypower
warnings are suppressed, too.
**delta** (float, 1e-10) - power tolerance
**trafo3w_losses** (str, "hv") - defines where open loop losses of three-winding transformers are considered. Valid options are "hv", "mv", "lv" for HV/MV/LV side or "star" for the star point.
"""
if (not net.sgen.empty) & ("controllable" not in net.sgen.columns):
logger.warning('Warning: Please specify sgen["controllable"]\n')
if (not net.load.empty) & ("controllable" not in net.load.columns):
logger.warning('Warning: Please specify load["controllable"]\n')
_init_rundcopp_options(net, check_connectivity=check_connectivity,
switch_rx_ratio=switch_rx_ratio, delta=delta,
trafo3w_losses=trafo3w_losses, **kwargs)
_check_bus_index_and_print_warning_if_high(net)
_check_gen_index_and_print_warning_if_high(net)
_optimal_powerflow(net, verbose, suppress_warnings, **kwargs)
def _passed_runpp_parameters(local_parameters):
"""
Internal function to distinguish arguments for pandapower.runpp() that are explicitly passed by
the user.
:param local_parameters: locals() in the runpp() function
:return: dictionary of explicitly passed parameters
"""
net = local_parameters.pop("net")
if "user_pf_options" not in net.keys() or len(net.user_pf_options) == 0:
return None
# default_parameters contains the parameters that are specified for the runpp function by default in its definition
args, varargs, keywords, defaults, *_ = inspect.getfullargspec(runpp)
default_parameters = dict(zip(args[1:], defaults))
# we want to also include the parameters that are optional (passed in "kwargs")!
# that is why we include the parameters that are also not in default_parameters
# maybe the part "if key not in default_parameters.keys()" is redundant, idk
kwargs_parameters = local_parameters.pop('kwargs', None)
passed_parameters = {
key: val for key, val in local_parameters.items()
if key not in default_parameters.keys() or val != default_parameters.get(key, None)}
# passed_parameters should have the "kwargs" parameters in the same level as other parameters
# (not nested in "kwargs: {...}") for them to be considered later on, otherwise they will be ignored
passed_parameters.update(kwargs_parameters)
return passed_parameters