e2nIEE / pandapower
1
# -*- coding: utf-8 -*-
2

3
# Copyright (c) 2016-2021 by University of Kassel and Fraunhofer Institute for Energy Economics
4
# and Energy System Technology (IEE), Kassel. All rights reserved.
5

6

7 1
import pandas as pd
8 1
from numpy import nan, isnan, arange, dtype, isin, any as np_any, zeros, array, bool_, \
9
    all as np_all, float64
10 1
from packaging import version
11

12 1
from pandapower import __version__
13 1
from pandapower.auxiliary import pandapowerNet, get_free_id, _preserve_dtypes
14 1
from pandapower.results import reset_results
15 1
from pandapower.std_types import add_basic_std_types, load_std_type
16

17 1
try:
18 1
    import pplog as logging
19 1
except ImportError:
20 1
    import logging
21

22 1
logger = logging.getLogger(__name__)
23

24

25 1
def create_empty_network(name="", f_hz=50., sn_mva=1, add_stdtypes=True):
26
    """
27
    This function initializes the pandapower datastructure.
28

29
    OPTIONAL:
30
        **f_hz** (float, 50.) - power system frequency in hertz
31

32
        **name** (string, None) - name for the network
33

34
        **sn_mva** (float, 1e3) - reference apparent power for per unit system
35

36
        **add_stdtypes** (boolean, True) - Includes standard types to net
37

38
    OUTPUT:
39
        **net** (attrdict) - PANDAPOWER attrdict with empty tables:
40

41
    EXAMPLE:
42
        net = create_empty_network()
43

44
    """
45 1
    net = pandapowerNet({
46
        # structure data
47
        "bus": [('name', dtype(object)),
48
                ('vn_kv', 'f8'),
49
                ('type', dtype(object)),
50
                ('zone', dtype(object)),
51
                ('in_service', 'bool'), ],
52
        "load": [("name", dtype(object)),
53
                 ("bus", "u4"),
54
                 ("p_mw", "f8"),
55
                 ("q_mvar", "f8"),
56
                 ("const_z_percent", "f8"),
57
                 ("const_i_percent", "f8"),
58
                 ("sn_mva", "f8"),
59
                 ("scaling", "f8"),
60
                 ("in_service", 'bool'),
61
                 ("type", dtype(object))],
62
        "sgen": [("name", dtype(object)),
63
                 ("bus", "i8"),
64
                 ("p_mw", "f8"),
65
                 ("q_mvar", "f8"),
66
                 ("sn_mva", "f8"),
67
                 ("scaling", "f8"),
68
                 ("in_service", 'bool'),
69
                 ("type", dtype(object)),
70
                 ("current_source", "bool")],
71
        "motor": [("name", dtype(object)),
72
                  ("bus", "i8"),
73
                  ("pn_mech_mw", "f8"),
74
                  ("loading_percent", "f8"),
75
                  ("cos_phi", "f8"),
76
                  ("cos_phi_n", "f8"),
77
                  ("efficiency_percent", "f8"),
78
                  ("efficiency_n_percent", "f8"),
79
                  ("lrc_pu", "f8"),
80
                  ("vn_kv", "f8"),
81
                  ("scaling", "f8"),
82
                  ("in_service", 'bool'),
83
                  ("rx", 'f8')
84
                  ],
85
        "asymmetric_load": [("name", dtype(object)),
86
                            ("bus", "u4"),
87
                            ("p_a_mw", "f8"),
88
                            ("q_a_mvar", "f8"),
89
                            ("p_b_mw", "f8"),
90
                            ("q_b_mvar", "f8"),
91
                            ("p_c_mw", "f8"),
92
                            ("q_c_mvar", "f8"),
93
                            ("sn_mva", "f8"),
94
                            ("scaling", "f8"),
95
                            ("in_service", 'bool'),
96
                            ("type", dtype(object))],
97

98
        "asymmetric_sgen": [("name", dtype(object)),
99
                            ("bus", "i8"),
100
                            ("p_a_mw", "f8"),
101
                            ("q_a_mvar", "f8"),
102
                            ("p_b_mw", "f8"),
103
                            ("q_b_mvar", "f8"),
104
                            ("p_c_mw", "f8"),
105
                            ("q_c_mvar", "f8"),
106
                            ("sn_mva", "f8"),
107
                            ("scaling", "f8"),
108
                            ("in_service", 'bool'),
109
                            ("type", dtype(object)),
110
                            ("current_source", "bool")],
111
        "storage": [("name", dtype(object)),
112
                    ("bus", "i8"),
113
                    ("p_mw", "f8"),
114
                    ("q_mvar", "f8"),
115
                    ("sn_mva", "f8"),
116
                    ("soc_percent", "f8"),
117
                    ("min_e_mwh", "f8"),
118
                    ("max_e_mwh", "f8"),
119
                    ("scaling", "f8"),
120
                    ("in_service", 'bool'),
121
                    ("type", dtype(object))],
122
        "gen": [("name", dtype(object)),
123
                ("bus", "u4"),
124
                ("p_mw", "f8"),
125
                ("vm_pu", "f8"),
126
                ("sn_mva", "f8"),
127
                ("min_q_mvar", "f8"),
128
                ("max_q_mvar", "f8"),
129
                ("scaling", "f8"),
130
                ("slack", "bool"),
131
                ("in_service", 'bool'),
132
                ("type", dtype(object))],
133
        "switch": [("bus", "i8"),
134
                   ("element", "i8"),
135
                   ("et", dtype(object)),
136
                   ("type", dtype(object)),
137
                   ("closed", "bool"),
138
                   ("name", dtype(object)),
139
                   ("z_ohm", "f8")],
140
        "shunt": [("bus", "u4"),
141
                  ("name", dtype(object)),
142
                  ("q_mvar", "f8"),
143
                  ("p_mw", "f8"),
144
                  ("vn_kv", "f8"),
145
                  ("step", "u4"),
146
                  ("max_step", "u4"),
147
                  ("in_service", "bool")],
148
        "ext_grid": [("name", dtype(object)),
149
                     ("bus", "u4"),
150
                     ("vm_pu", "f8"),
151
                     ("va_degree", "f8"),
152
                     ("in_service", 'bool')],
153
        "line": [("name", dtype(object)),
154
                 ("std_type", dtype(object)),
155
                 ("from_bus", "u4"),
156
                 ("to_bus", "u4"),
157
                 ("length_km", "f8"),
158
                 ("r_ohm_per_km", "f8"),
159
                 ("x_ohm_per_km", "f8"),
160
                 ("c_nf_per_km", "f8"),
161
                 ("g_us_per_km", "f8"),
162
                 ("max_i_ka", "f8"),
163
                 ("df", "f8"),
164
                 ("parallel", "u4"),
165
                 ("type", dtype(object)),
166
                 ("in_service", 'bool')],
167
        "trafo": [("name", dtype(object)),
168
                  ("std_type", dtype(object)),
169
                  ("hv_bus", "u4"),
170
                  ("lv_bus", "u4"),
171
                  ("sn_mva", "f8"),
172
                  ("vn_hv_kv", "f8"),
173
                  ("vn_lv_kv", "f8"),
174
                  ("vk_percent", "f8"),
175
                  ("vkr_percent", "f8"),
176
                  ("pfe_kw", "f8"),
177
                  ("i0_percent", "f8"),
178
                  ("shift_degree", "f8"),
179
                  ("tap_side", dtype(object)),
180
                  ("tap_neutral", "i4"),
181
                  ("tap_min", "i4"),
182
                  ("tap_max", "i4"),
183
                  ("tap_step_percent", "f8"),
184
                  ("tap_step_degree", "f8"),
185
                  ("tap_pos", "i4"),
186
                  ("tap_phase_shifter", 'bool'),
187
                  ("parallel", "u4"),
188
                  ("df", "f8"),
189
                  ("in_service", 'bool')],
190
        "trafo3w": [("name", dtype(object)),
191
                    ("std_type", dtype(object)),
192
                    ("hv_bus", "u4"),
193
                    ("mv_bus", "u4"),
194
                    ("lv_bus", "u4"),
195
                    ("sn_hv_mva", "f8"),
196
                    ("sn_mv_mva", "f8"),
197
                    ("sn_lv_mva", "f8"),
198
                    ("vn_hv_kv", "f8"),
199
                    ("vn_mv_kv", "f8"),
200
                    ("vn_lv_kv", "f8"),
201
                    ("vk_hv_percent", "f8"),
202
                    ("vk_mv_percent", "f8"),
203
                    ("vk_lv_percent", "f8"),
204
                    ("vkr_hv_percent", "f8"),
205
                    ("vkr_mv_percent", "f8"),
206
                    ("vkr_lv_percent", "f8"),
207
                    ("pfe_kw", "f8"),
208
                    ("i0_percent", "f8"),
209
                    ("shift_mv_degree", "f8"),
210
                    ("shift_lv_degree", "f8"),
211
                    ("tap_side", dtype(object)),
212
                    ("tap_neutral", "i4"),
213
                    ("tap_min", "i4"),
214
                    ("tap_max", "i4"),
215
                    ("tap_step_percent", "f8"),
216
                    ("tap_step_degree", "f8"),
217
                    ("tap_pos", "i4"),
218
                    ("tap_at_star_point", 'bool'),
219
                    ("in_service", 'bool')],
220
        "impedance": [("name", dtype(object)),
221
                      ("from_bus", "u4"),
222
                      ("to_bus", "u4"),
223
                      ("rft_pu", "f8"),
224
                      ("xft_pu", "f8"),
225
                      ("rtf_pu", "f8"),
226
                      ("xtf_pu", "f8"),
227
                      ("sn_mva", "f8"),
228
                      ("in_service", 'bool')],
229
        "dcline": [("name", dtype(object)),
230
                   ("from_bus", "u4"),
231
                   ("to_bus", "u4"),
232
                   ("p_mw", "f8"),
233
                   ("loss_percent", 'f8'),
234
                   ("loss_mw", 'f8'),
235
                   ("vm_from_pu", "f8"),
236
                   ("vm_to_pu", "f8"),
237
                   ("max_p_mw", "f8"),
238
                   ("min_q_from_mvar", "f8"),
239
                   ("min_q_to_mvar", "f8"),
240
                   ("max_q_from_mvar", "f8"),
241
                   ("max_q_to_mvar", "f8"),
242
                   ("in_service", 'bool')],
243
        "ward": [("name", dtype(object)),
244
                 ("bus", "u4"),
245
                 ("ps_mw", "f8"),
246
                 ("qs_mvar", "f8"),
247
                 ("qz_mvar", "f8"),
248
                 ("pz_mw", "f8"),
249
                 ("in_service", "bool")],
250
        "xward": [("name", dtype(object)),
251
                  ("bus", "u4"),
252
                  ("ps_mw", "f8"),
253
                  ("qs_mvar", "f8"),
254
                  ("qz_mvar", "f8"),
255
                  ("pz_mw", "f8"),
256
                  ("r_ohm", "f8"),
257
                  ("x_ohm", "f8"),
258
                  ("vm_pu", "f8"),
259
                  ("in_service", "bool")],
260
        "measurement": [("name", dtype(object)),
261
                        ("measurement_type", dtype(object)),
262
                        ("element_type", dtype(object)),
263
                        ("element", "uint32"),
264
                        ("value", "float64"),
265
                        ("std_dev", "float64"),
266
                        ("side", dtype(object))],
267
        "pwl_cost": [("power_type", dtype(object)),
268
                     ("element", "u4"),
269
                     ("et", dtype(object)),
270
                     ("points", dtype(object))],
271
        "poly_cost": [("element", "u4"),
272
                      ("et", dtype(object)),
273
                      ("cp0_eur", dtype("f8")),
274
                      ("cp1_eur_per_mw", dtype("f8")),
275
                      ("cp2_eur_per_mw2", dtype("f8")),
276
                      ("cq0_eur", dtype("f8")),
277
                      ("cq1_eur_per_mvar", dtype("f8")),
278
                      ("cq2_eur_per_mvar2", dtype("f8"))
279
                      ],
280
        'controller': [
281
            ('object', dtype(object)),
282
            ('in_service', "bool"),
283
            ('order', "float64"),
284
            ('level', dtype(object)),
285
            ('initial_run', "bool"),
286
            ("recycle", dtype(object)),
287
        ],
288
        # geodata
289
        "line_geodata": [("coords", dtype(object))],
290
        "bus_geodata": [("x", "f8"), ("y", "f8"), ("coords", dtype(object))],
291

292
        # result tables
293
        "_empty_res_bus": [("vm_pu", "f8"),
294
                           ("va_degree", "f8"),
295
                           ("p_mw", "f8"),
296
                           ("q_mvar", "f8")],
297
        "_empty_res_ext_grid": [("p_mw", "f8"),
298
                                ("q_mvar", "f8")],
299
        "_empty_res_line": [("p_from_mw", "f8"),
300
                            ("q_from_mvar", "f8"),
301
                            ("p_to_mw", "f8"),
302
                            ("q_to_mvar", "f8"),
303
                            ("pl_mw", "f8"),
304
                            ("ql_mvar", "f8"),
305
                            ("i_from_ka", "f8"),
306
                            ("i_to_ka", "f8"),
307
                            ("i_ka", "f8"),
308
                            ("vm_from_pu", "f8"),
309
                            ("va_from_degree", "f8"),
310
                            ("vm_to_pu", "f8"),
311
                            ("va_to_degree", "f8"),
312
                            ("loading_percent", "f8")],
313
        "_empty_res_trafo": [("p_hv_mw", "f8"),
314
                             ("q_hv_mvar", "f8"),
315
                             ("p_lv_mw", "f8"),
316
                             ("q_lv_mvar", "f8"),
317
                             ("pl_mw", "f8"),
318
                             ("ql_mvar", "f8"),
319
                             ("i_hv_ka", "f8"),
320
                             ("i_lv_ka", "f8"),
321
                             ("vm_hv_pu", "f8"),
322
                             ("va_hv_degree", "f8"),
323
                             ("vm_lv_pu", "f8"),
324
                             ("va_lv_degree", "f8"),
325
                             ("loading_percent", "f8")],
326
        "_empty_res_load": [("p_mw", "f8"),
327
                            ("q_mvar", "f8")],
328
        "_empty_res_asymmetric_load": [("p_mw", "f8"),
329
                            ("q_mvar", "f8")],
330
        "_empty_res_asymmetric_sgen": [("p_mw", "f8"),
331
                            ("q_mvar", "f8")],
332
        "_empty_res_motor": [("p_mw", "f8"),
333
                             ("q_mvar", "f8")],
334
        "_empty_res_sgen": [("p_mw", "f8"),
335
                            ("q_mvar", "f8")],
336
        "_empty_res_shunt": [("p_mw", "f8"),
337
                             ("q_mvar", "f8"),
338
                             ("vm_pu", "f8")],
339
        "_empty_res_impedance": [("p_from_mw", "f8"),
340
                                 ("q_from_mvar", "f8"),
341
                                 ("p_to_mw", "f8"),
342
                                 ("q_to_mvar", "f8"),
343
                                 ("pl_mw", "f8"),
344
                                 ("ql_mvar", "f8"),
345
                                 ("i_from_ka", "f8"),
346
                                 ("i_to_ka", "f8")],
347
        "_empty_res_dcline": [("p_from_mw", "f8"),
348
                              ("q_from_mvar", "f8"),
349
                              ("p_to_mw", "f8"),
350
                              ("q_to_mvar", "f8"),
351
                              ("pl_mw", "f8"),
352
                              ("vm_from_pu", "f8"),
353
                              ("va_from_degree", "f8"),
354
                              ("vm_to_pu", "f8"),
355
                              ("va_to_degree", "f8")],
356
        "_empty_res_ward": [("p_mw", "f8"),
357
                            ("q_mvar", "f8"),
358
                            ("vm_pu", "f8")],
359
        "_empty_res_xward": [("p_mw", "f8"),
360
                             ("q_mvar", "f8"),
361
                             ("vm_pu", "f8"),
362
                             ("va_internal_degree", "f8"),
363
                             ("vm_internal_pu", "f8")],
364

365
        "_empty_res_trafo_3ph": [("p_a_hv_mw", "f8"),
366
                                 ("q_a_hv_mvar", "f8"),
367
                                 ("p_b_hv_mw", "f8"),
368
                                 ("q_b_hv_mvar", "f8"),
369
                                 ("p_c_hv_mw", "f8"),
370
                                 ("q_c_hv_mvar", "f8"),
371
                                 ("p_a_lv_mw", "f8"),
372
                                 ("q_a_lv_mvar", "f8"),
373
                                 ("p_b_lv_mw", "f8"),
374
                                 ("q_b_lv_mvar", "f8"),
375
                                 ("p_c_lv_mw", "f8"),
376
                                 ("q_c_lv_mvar", "f8"),
377
                                 ("p_a_l_mw", "f8"),
378
                                 ("q_a_l_mvar", "f8"),
379
                                 ("p_b_l_mw", "f8"),
380
                                 ("q_b_l_mvar", "f8"),
381
                                 ("p_c_l_mw", "f8"),
382
                                 ("q_c_l_mvar", "f8"),
383
                                 ("i_a_hv_ka", "f8"),
384
                                 ("i_a_lv_ka", "f8"),
385
                                 ("i_b_hv_ka", "f8"),
386
                                 ("i_b_lv_ka", "f8"),
387
                                 ("i_c_hv_ka", "f8"),
388
                                 ("i_c_lv_ka", "f8"),
389
                                 # ("i_n_hv_ka", "f8"),
390
                                 # ("i_n_lv_ka", "f8"),
391
                                 ("loading_a_percent", "f8"),
392
                                 ("loading_b_percent", "f8"),
393
                                 ("loading_c_percent", "f8"),
394
                                 ("loading_percent", "f8")],
395
        "_empty_res_trafo3w": [("p_hv_mw", "f8"),
396
                               ("q_hv_mvar", "f8"),
397
                               ("p_mv_mw", "f8"),
398
                               ("q_mv_mvar", "f8"),
399
                               ("p_lv_mw", "f8"),
400
                               ("q_lv_mvar", "f8"),
401
                               ("pl_mw", "f8"),
402
                               ("ql_mvar", "f8"),
403
                               ("i_hv_ka", "f8"),
404
                               ("i_mv_ka", "f8"),
405
                               ("i_lv_ka", "f8"),
406
                               ("vm_hv_pu", "f8"),
407
                               ("va_hv_degree", "f8"),
408
                               ("vm_mv_pu", "f8"),
409
                               ("va_mv_degree", "f8"),
410
                               ("vm_lv_pu", "f8"),
411
                               ("va_lv_degree", "f8"),
412
                               ("va_internal_degree", "f8"),
413
                               ("vm_internal_pu", "f8"),
414
                               ("loading_percent", "f8")],
415
        "_empty_res_bus_3ph": [("vm_a_pu", "f8"),
416
                               ("va_a_degree", "f8"),
417
                               ("vm_b_pu", "f8"),
418
                               ("va_b_degree", "f8"),
419
                               ("vm_c_pu", "f8"),
420
                               ("va_c_degree", "f8"),
421
                               ("p_a_mw", "f8"),
422
                               ("q_a_mvar", "f8"),
423
                               ("p_b_mw", "f8"),
424
                               ("q_b_mvar", "f8"),
425
                               ("p_c_mw", "f8"),
426
                               ("q_c_mvar", "f8")],
427
        "_empty_res_ext_grid_3ph": [("p_a_mw", "f8"),
428
                                    ("q_a_mvar", "f8"),
429
                                    ("p_b_mw", "f8"),
430
                                    ("q_b_mvar", "f8"),
431
                                    ("p_c_mw", "f8"),
432
                                    ("q_c_mvar", "f8")],
433
        "_empty_res_line_3ph": [("p_a_from_mw", "f8"),
434
                                ("q_a_from_mvar", "f8"),
435
                                ("p_b_from_mw", "f8"),
436
                                ("q_b_from_mvar", "f8"),
437
                                ("q_c_from_mvar", "f8"),
438
                                ("p_a_to_mw", "f8"),
439
                                ("q_a_to_mvar", "f8"),
440
                                ("p_b_to_mw", "f8"),
441
                                ("q_b_to_mvar", "f8"),
442
                                ("p_c_to_mw", "f8"),
443
                                ("q_c_to_mvar", "f8"),
444
                                ("p_a_l_mw", "f8"),
445
                                ("q_a_l_mvar", "f8"),
446
                                ("p_b_l_mw", "f8"),
447
                                ("q_b_l_mvar", "f8"),
448
                                ("p_c_l_mw", "f8"),
449
                                ("q_c_l_mvar", "f8"),
450
                                ("i_a_from_ka", "f8"),
451
                                ("i_a_to_ka", "f8"),
452
                                ("i_b_from_ka", "f8"),
453
                                ("i_b_to_ka", "f8"),
454
                                ("i_c_from_ka", "f8"),
455
                                ("i_c_to_ka", "f8"),
456
                                ("i_a_ka", "f8"),
457
                                ("i_b_ka", "f8"),
458
                                ("i_c_ka", "f8"),
459
                                ("i_n_from_ka", "f8"),
460
                                ("i_n_to_ka", "f8"),
461
                                ("i_n_ka", "f8"),
462
                                ("loading_a_percent", "f8"),
463
                                ("loading_b_percent", "f8"),
464
                                ("loading_c_percent", "f8")],
465
        "_empty_res_asymmetric_load_3ph": [("p_a_mw", "f8"),
466
                                           ("q_a_mvar", "f8"),
467
                                           ("p_b_mw", "f8"),
468
                                           ("q_b_mvar", "f8"),
469
                                           ("p_c_mw", "f8"),
470
                                           ("q_c_mvar", "f8")],
471
        "_empty_res_asymmetric_sgen_3ph": [("p_a_mw", "f8"),
472
                                           ("q_a_mvar", "f8"),
473
                                           ("p_b_mw", "f8"),
474
                                           ("q_b_mvar", "f8"),
475
                                           ("p_c_mw", "f8"),
476
                                           ("q_c_mvar", "f8")],
477
        "_empty_res_storage": [("p_mw", "f8"),
478
                               ("q_mvar", "f8")],
479
        "_empty_res_storage_3ph": [("p_a_mw", "f8"), ("p_b_mw", "f8"), ("p_c_mw", "f8"),
480
                                   ("q_a_mvar", "f8"), ("q_b_mvar", "f8"), ("q_c_mvar", "f8")],
481
        "_empty_res_gen": [("p_mw", "f8"),
482
                           ("q_mvar", "f8"),
483
                           ("va_degree", "f8"),
484
                           ("vm_pu", "f8")],
485

486
        # internal
487
        "_ppc": None,
488
        "_ppc0": None,
489
        "_ppc1": None,
490
        "_ppc2": None,
491
        "_is_elements": None,
492
        "_pd2ppc_lookups": {"bus": None,
493
                            "ext_grid": None,
494
                            "gen": None,
495
                            "branch": None},
496
        "version": __version__,
497
        "converged": False,
498
        "name": name,
499
        "f_hz": f_hz,
500
        "sn_mva": sn_mva
501
    })
502

503 1
    net._empty_res_load_3ph = net._empty_res_load
504 1
    net._empty_res_sgen_3ph = net._empty_res_sgen
505 1
    net._empty_res_storage_3ph = net._empty_res_storage
506

507 1
    for s in net:
508 1
        if isinstance(net[s], list):
509 1
            net[s] = pd.DataFrame(zeros(0, dtype=net[s]), index=pd.Int64Index([]))
510 1
    if add_stdtypes:
511 1
        add_basic_std_types(net)
512
    else:
513 1
        net.std_types = {"line": {}, "trafo": {}, "trafo3w": {}}
514 1
    for mode in ["pf", "se", "sc", "pf_3ph"]:
515 1
        reset_results(net, mode)
516 1
    net['user_pf_options'] = dict()
517 1
    return net
518

519

520 1
def create_bus(net, vn_kv, name=None, index=None, geodata=None, type="b", zone=None,
521
               in_service=True, max_vm_pu=nan, min_vm_pu=nan, coords=None, **kwargs):
522
    """
523
    Adds one bus in table net["bus"].
524

525
    Busses are the nodes of the network that all other elements connect to.
526

527
    INPUT:
528
        **net** (pandapowerNet) - The pandapower network in which the element is created
529

530
    OPTIONAL:
531
        **name** (string, default None) - the name for this bus
532

533
        **index** (int, default None) - Force a specified ID if it is available. If None, the \
534
            index one higher than the highest already existing index is selected.
535

536
        **vn_kv** (float) - The grid voltage level.
537

538
        **geodata** ((x,y)-tuple, default None) - coordinates used for plotting
539

540
        **type** (string, default "b") - Type of the bus. "n" - node,
541
        "b" - busbar, "m" - muff
542

543
        **zone** (string, None) - grid region
544

545
        **in_service** (boolean) - True for in_service or False for out of service
546

547
        **max_vm_pu** (float, NAN) - Maximum bus voltage in p.u. - necessary for OPF
548

549
        **min_vm_pu** (float, NAN) - Minimum bus voltage in p.u. - necessary for OPF
550

551
        **coords** (array, default None, shape= (,2L)) - busbar coordinates to plot the bus with \
552
            multiple points. coords is typically a list of tuples (start and endpoint of the \
553
            busbar) [(x1, y1), (x2, y2)]
554

555
    OUTPUT:
556
        **index** (int) - The unique ID of the created element
557

558
    EXAMPLE:
559
        create_bus(net, name = "bus1")
560
    """
561 1
    index = _get_index_with_check(net, "bus", index)
562

563 1
    entries = dict(zip(["name", "vn_kv", "type", "zone", "in_service"],
564
                       [name, vn_kv, type, zone, bool(in_service)]))
565

566 1
    _set_entries(net, "bus", index, True, **entries, **kwargs)
567

568 1
    if geodata is not None:
569 1
        if len(geodata) != 2:
570 0
            raise UserWarning("geodata must be given as (x, y) tuple")
571 1
        net["bus_geodata"].loc[index, ["x", "y"]] = geodata
572

573 1
    if coords is not None:
574 0
        net["bus_geodata"].loc[index, "coords"] = coords
575

576
    # column needed by OPF. 0. and 2. are the default maximum / minimum voltages
577 1
    _create_column_and_set_value(net, index, min_vm_pu, "min_vm_pu", "bus", default_val=0.)
578 1
    _create_column_and_set_value(net, index, max_vm_pu, "max_vm_pu", "bus", default_val=2.)
579

580 1
    return index
581

582

583 1
def create_buses(net, nr_buses, vn_kv, index=None, name=None, type="b", geodata=None,
584
                 zone=None, in_service=True, max_vm_pu=None, min_vm_pu=None, coords=None, **kwargs):
585
    """
586
    Adds several buses in table net["bus"] at once.
587

588
    Busses are the nodal points of the network that all other elements connect to.
589

590
    Input:
591
        **net** (pandapowerNet) - The pandapower network in which the element is created
592

593
        **nr_buses** (int) - The number of buses that is created
594

595
    OPTIONAL:
596
        **name** (string, default None) - the name for this bus
597

598
        **index** (int, default None) - Force specified IDs if available. If None, the indices \
599
            higher than the highest already existing index are selected.
600

601
        **vn_kv** (float) - The grid voltage level.
602

603
        **geodata** ((x,y)-tuple, default None) - coordinates used for plotting
604

605
        **type** (string, default "b") - Type of the bus. "n" - auxilary node,
606
        "b" - busbar, "m" - muff
607

608
        **zone** (string, None) - grid region
609

610
        **in_service** (boolean) - True for in_service or False for out of service
611

612
        **max_vm_pu** (float, NAN) - Maximum bus voltage in p.u. - necessary for OPF
613

614
        **min_vm_pu** (float, NAN) - Minimum bus voltage in p.u. - necessary for OPF
615

616
    OUTPUT:
617
        **index** (int) - The unique indices ID of the created elements
618

619
    EXAMPLE:
620
        create_bus(net, name = "bus1")
621
    """
622 1
    index = _get_multiple_index_with_check(net, "bus", index, nr_buses)
623

624 1
    entries = {"vn_kv": vn_kv, "type": type, "zone": zone, "in_service": in_service, "name": name}
625 1
    _add_series_to_entries(entries, index, "min_vm_pu", min_vm_pu)
626 1
    _add_series_to_entries(entries, index, "max_vm_pu", max_vm_pu)
627 1
    _set_multiple_entries(net, "bus", index, **entries, **kwargs)
628

629 1
    if geodata is not None:
630
        # works with a 2-tuple or a matching array
631 1
        net.bus_geodata = net.bus_geodata.append(pd.DataFrame(
632
            zeros((len(index), len(net.bus_geodata.columns)), dtype=int), index=index,
633
            columns=net.bus_geodata.columns))
634 1
        net.bus_geodata.loc[index, :] = nan
635 1
        net.bus_geodata.loc[index, ["x", "y"]] = geodata
636 1
    if coords is not None:
637 0
        net.bus_geodata = net.bus_geodata.append(pd.DataFrame(index=index,
638
                                                              columns=net.bus_geodata.columns))
639 0
        net["bus_geodata"].loc[index, "coords"] = coords
640 1
    return index
641

642

643 1
def create_load(net, bus, p_mw, q_mvar=0, const_z_percent=0, const_i_percent=0, sn_mva=nan,
644
                name=None, scaling=1., index=None, in_service=True, type='wye', max_p_mw=nan,
645
                min_p_mw=nan, max_q_mvar=nan, min_q_mvar=nan, controllable=nan):
646
    """
647
    Adds one load in table net["load"].
648

649
    All loads are modelled in the consumer system, meaning load is positive and generation is
650
    negative active power. Please pay attention to the correct signing of the reactive power as
651
    well.
652

653
    INPUT:
654
        **net** - The net within this load should be created
655

656
        **bus** (int) - The bus id to which the load is connected
657

658
    OPTIONAL:
659
        **p_mw** (float, default 0) - The active power of the load
660

661
        - postive value   -> load
662
        - negative value  -> generation
663

664
        **q_mvar** (float, default 0) - The reactive power of the load
665

666
        **const_z_percent** (float, default 0) - percentage of p_mw and q_mvar that will be \
667
            associated to constant impedance load at rated voltage
668

669
        **const_i_percent** (float, default 0) - percentage of p_mw and q_mvar that will be \
670
            associated to constant current load at rated voltage
671

672
        **sn_mva** (float, default None) - Nominal power of the load
673

674
        **name** (string, default None) - The name for this load
675

676
        **scaling** (float, default 1.) - An OPTIONAL scaling factor to be set customly
677

678
        **type** (string, 'wye') -  type variable to classify the load: wye/delta
679

680
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
681
            higher than the highest already existing index is selected.
682

683
        **in_service** (boolean) - True for in_service or False for out of service
684

685
        **max_p_mw** (float, default NaN) - Maximum active power load - necessary for controllable \
686
            loads in for OPF
687

688
        **min_p_mw** (float, default NaN) - Minimum active power load - necessary for controllable \
689
            loads in for OPF
690

691
        **max_q_mvar** (float, default NaN) - Maximum reactive power load - necessary for \
692
            controllable loads in for OPF
693

694
        **min_q_mvar** (float, default NaN) - Minimum reactive power load - necessary for \
695
            controllable loads in OPF
696

697
        **controllable** (boolean, default NaN) - States, whether a load is controllable or not. \
698
            Only respected for OPF
699
            Defaults to False if "controllable" column exists in DataFrame
700

701
    OUTPUT:
702
        **index** (int) - The unique ID of the created element
703

704
    EXAMPLE:
705
        create_load(net, bus=0, p_mw=10., q_mvar=2.)
706

707
    """
708 1
    _check_node_element(net, bus)
709

710 1
    index = _get_index_with_check(net, "load", index)
711

712 1
    entries = dict(zip(["name", "bus", "p_mw", "const_z_percent", "const_i_percent", "scaling",
713
                        "q_mvar", "sn_mva", "in_service", "type"],
714
                       [name, bus, p_mw, const_z_percent, const_i_percent, scaling, q_mvar, sn_mva,
715
                        bool(in_service), type]))
716

717 1
    _set_entries(net, "load", index, True, **entries)
718

719 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "load")
720 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "load")
721 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "load")
722 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "load")
723 1
    _create_column_and_set_value(net, index, controllable, "controllable", "load", dtyp=bool_,
724
                                 default_val=False, default_for_nan=True)
725

726 1
    return index
727

728

729 1
def create_loads(net, buses, p_mw, q_mvar=0, const_z_percent=0, const_i_percent=0, sn_mva=nan,
730
                 name=None, scaling=1., index=None, in_service=True, type=None, max_p_mw=None,
731
                 min_p_mw=None, max_q_mvar=None, min_q_mvar=None, controllable=None, **kwargs):
732
    """
733
    Adds a number of loads in table net["load"].
734

735
    All loads are modelled in the consumer system, meaning load is positive and generation is
736
    negative active power. Please pay attention to the correct signing of the reactive power as
737
    well.
738

739
    INPUT:
740
        **net** - The net within this load should be created
741

742
        **buses** (list of int) - A list of bus ids to which the loads are connected
743

744
    OPTIONAL:
745
        **p_mw** (list of floats) - The active power of the loads
746

747
        - postive value   -> load
748
        - negative value  -> generation
749

750
        **q_mvar** (list of floats, default 0) - The reactive power of the loads
751

752
        **const_z_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
753
            be associated to constant impedance loads at rated voltage
754

755
        **const_i_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
756
            be associated to constant current load at rated voltage
757

758
        **sn_mva** (list of floats, default None) - Nominal power of the loads
759

760
        **name** (list of strings, default None) - The name for this load
761

762
        **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
763

764
        **type** (string, None) -  type variable to classify the load
765

766
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
767
            is set to a range between one higher than the highest already existing index and the \
768
            length of loads that shall be created.
769

770
        **in_service** (list of boolean) - True for in_service or False for out of service
771

772
        **max_p_mw** (list of floats, default NaN) - Maximum active power load - necessary for \
773
            controllable loads in for OPF
774

775
        **min_p_mw** (list of floats, default NaN) - Minimum active power load - necessary for \
776
            controllable loads in for OPF
777

778
        **max_q_mvar** (list of floats, default NaN) - Maximum reactive power load - necessary for \
779
            controllable loads in for OPF
780

781
        **min_q_mvar** (list of floats, default NaN) - Minimum reactive power load - necessary for \
782
            controllable loads in OPF
783

784
        **controllable** (list of boolean, default NaN) - States, whether a load is controllable \
785
            or not. Only respected for OPF
786
            Defaults to False if "controllable" column exists in DataFrame
787

788
    OUTPUT:
789
        **index** (int) - The unique IDs of the created elements
790

791
    EXAMPLE:
792
        create_loads(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
793

794
    """
795 1
    _check_multiple_node_elements(net, buses)
796

797 1
    index = _get_multiple_index_with_check(net, "load", index, len(buses))
798

799 1
    entries = {"bus": buses, "p_mw": p_mw, "q_mvar": q_mvar, "sn_mva": sn_mva,
800
               "const_z_percent": const_z_percent, "const_i_percent": const_i_percent,
801
               "scaling": scaling, "in_service": in_service, "name": name, "type": type}
802

803 1
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
804 1
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
805 1
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
806 1
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
807 1
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
808
                           default_val=False)
809

810 1
    _set_multiple_entries(net, "load", index, **entries, **kwargs)
811

812 1
    return index
813

814

815 1
def create_asymmetric_load(net, bus, p_a_mw=0, p_b_mw=0, p_c_mw=0, q_a_mvar=0, q_b_mvar=0,
816
                           q_c_mvar=0, sn_mva=nan, name=None, scaling=1., index=None,
817
                           in_service=True, type="wye"):
818
    """
819
    Adds one 3 phase load in table net["asymmetric_load"].
820

821
    All loads are modelled in the consumer system, meaning load is positive and generation is
822
    negative active power. Please pay attention to the correct signing of the reactive power as
823
    well.
824

825
    INPUT:
826
        **net** - The net within this load should be created
827

828
        **bus** (int) - The bus id to which the load is connected
829

830
    OPTIONAL:
831
        **p_a_mw** (float, default 0) - The active power for Phase A load
832

833
        **p_b_mw** (float, default 0) - The active power for Phase B load
834

835
        **p_c_mw** (float, default 0) - The active power for Phase C load
836

837
        **q_a_mvar** float, default 0) - The reactive power for Phase A load
838

839
        **q_b_mvar** float, default 0) - The reactive power for Phase B load
840

841
        **q_c_mvar** (float, default 0) - The reactive power for Phase C load
842

843
        **sn_kva** (float, default: None) - Nominal power of the load
844

845
        **name** (string, default: None) - The name for this load
846

847
        **scaling** (float, default: 1.) - An OPTIONAL scaling factor to be set customly
848

849
        **type** (string,default: wye) -  type variable to classify three ph load: delta/wye
850

851
        **index** (int,default: None) - Force a specified ID if it is available. If None, the index\
852
            one higher than the highest already existing index is selected.
853

854
        **in_service** (boolean) - True for in_service or False for out of service
855

856
    OUTPUT:
857
        **index** (int) - The unique ID of the created element
858

859
    EXAMPLE:
860
        **create_asymmetric_load(net, bus=0, p_c_mw = 9., q_c_mvar = 1.8)**
861

862
    """
863 1
    _check_node_element(net, bus)
864

865 1
    index = _get_index_with_check(net, "asymmetric_load", index, name="3 phase asymmetric_load")
866

867 1
    entries = dict(zip(["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling", "q_a_mvar",
868
                        "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"],
869
                       [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling, q_a_mvar, q_b_mvar, q_c_mvar,
870
                        sn_mva, bool(in_service), type]))
871

872 1
    _set_entries(net, "asymmetric_load", index, True, **entries)
873

874 1
    return index
875

876

877
# =============================================================================
878
# def create_impedance_load(net, bus, r_A , r_B , r_C, x_A=0, x_B=0, x_C=0,
879
#                      sn_mva=nan, name=None, scaling=1.,
880
#                     index=None, in_service=True, type=None,
881
#                     ):
882
#     """
883
#     Creates a constant impedance load element ABC.
884
#
885
#     INPUT:
886
#         **net** - The net within this constant impedance load should be created
887
#
888
#         **bus** (int) - The bus id to which the load is connected
889
#
890
#         **sn_mva** (float) - rated power of the load
891
#
892
#         **r_A** (float) - Resistance in Phase A
893
#         **r_B** (float) - Resistance in Phase B
894
#         **r_C** (float) - Resistance in Phase C
895
#         **x_A** (float) - Reactance in Phase A
896
#         **x_B** (float) - Reactance in Phase B
897
#         **x_C** (float) - Reactance in Phase C
898
#
899
#
900
#         **kwargs are passed on to the create_load function
901
#
902
#     OUTPUT:
903
#         **index** (int) - The unique ID of the created load
904
#
905
#     All elements are modeled from a consumer point of view. Active power will therefore always be
906
#     positive, reactive power will be negative for inductive behaviour and positive for capacitive
907
#     behaviour.
908
#     """
909
#     if bus not in net["bus"].index.values:
910
#         raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
911
#
912
#     if index is None:
913
#         index = get_free_id(net["asymmetric_load"])
914
#     if index in net["impedance_load"].index:
915
#         raise UserWarning("A 3 phase asymmetric_load with the id %s already exists" % index)
916
#
917
#     # store dtypes
918
#     dtypes = net.impedance_load.dtypes
919
#
920
#     net.impedance_load.loc[index, ["name", "bus", "r_A","r_B","r_C", "scaling",
921
#                       "x_A","x_B","x_C","sn_mva", "in_service", "type"]] = \
922
#     [name, bus, r_A,r_B,r_C, scaling,
923
#       x_A,x_B,x_C,sn_mva, bool(in_service), type]
924
#
925
#     # and preserve dtypes
926
#     _preserve_dtypes(net.impedance_load, dtypes)
927
#
928
#     return index
929
#
930
# =============================================================================
931

932

933 1
def create_load_from_cosphi(net, bus, sn_mva, cos_phi, mode, **kwargs):
934
    """
935
    Creates a load element from rated power and power factor cos(phi).
936

937
    INPUT:
938
        **net** - The net within this static generator should be created
939

940
        **bus** (int) - The bus id to which the load is connected
941

942
        **sn_mva** (float) - rated power of the load
943

944
        **cos_phi** (float) - power factor cos_phi
945

946
        **mode** (str) - "ind" for inductive or "cap" for capacitive behaviour
947

948
        **kwargs are passed on to the create_load function
949

950
    OUTPUT:
951
        **index** (int) - The unique ID of the created load
952

953
    All elements are modeled from a consumer point of view. Active power will therefore always be
954
    positive, reactive power will be negative for inductive behaviour and positive for capacitive
955
    behaviour.
956
    """
957 1
    from pandapower.toolbox import pq_from_cosphi
958 1
    p_mw, q_mvar = pq_from_cosphi(sn_mva, cos_phi, qmode=mode, pmode="load")
959 1
    return create_load(net, bus, sn_mva=sn_mva, p_mw=p_mw, q_mvar=q_mvar, **kwargs)
960

961

962 1
def create_sgen(net, bus, p_mw, q_mvar=0, sn_mva=nan, name=None, index=None,
963
                scaling=1., type='wye', in_service=True, max_p_mw=nan, min_p_mw=nan,
964
                max_q_mvar=nan, min_q_mvar=nan, controllable=nan, k=nan, rx=nan,
965
                current_source=True):
966
    """
967
    Adds one static generator in table net["sgen"].
968

969
    Static generators are modelled as positive and constant PQ power. This element is used to model
970
    generators with a constant active and reactive power feed-in. If you want to model a voltage
971
    controlled generator, use the generator element instead.
972

973
    gen, sgen and ext_grid in the grid are modelled in the generator system!
974
    If you want to model the generation of power, you have to assign a positive active power
975
    to the generator. Please pay attention to the correct signing of the
976
    reactive power as well (positive for injection and negative for consumption).
977

978
    INPUT:
979
        **net** - The net within this static generator should be created
980

981
        **bus** (int) - The bus id to which the static generator is connected
982

983
        **p_mw** (float) - The active power of the static generator  (positive for generation!)
984

985
    OPTIONAL:
986

987
        **q_mvar** (float, 0) - The reactive power of the sgen
988

989
        **sn_mva** (float, None) - Nominal power of the sgen
990

991
        **name** (string, None) - The name for this sgen
992

993
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
994
            higher than the highest already existing index is selected.
995

996
        **scaling** (float, 1.) - An OPTIONAL scaling factor to be set customly
997

998
        **type** (string, None) -  Three phase Connection type of the static generator: wye/delta
999

1000
        **in_service** (boolean) - True for in_service or False for out of service
1001

1002
        **max_p_mw** (float, NaN) - Maximum active power injection - necessary for \
1003
            controllable sgens in OPF
1004

1005
        **min_p_mw** (float, NaN) - Minimum active power injection - necessary for \
1006
            controllable sgens in OPF
1007

1008
        **max_q_mvar** (float, NaN) - Maximum reactive power injection - necessary for \
1009
            controllable sgens in OPF
1010

1011
        **min_q_mvar** (float, NaN) - Minimum reactive power injection - necessary for \
1012
            controllable sgens in OPF
1013

1014
        **controllable** (bool, NaN) - Whether this generator is controllable by the optimal
1015
        powerflow
1016
            Defaults to False if "controllable" column exists in DataFrame
1017

1018
        **k** (float, NaN) - Ratio of nominal current to short circuit current
1019

1020
        **rx** (float, NaN) - R/X ratio for short circuit impedance. Only relevant if type is \
1021
            specified as motor so that sgen is treated as asynchronous motor
1022

1023
        **current_source** (bool, True) - Model this sgen as a current source during short-\
1024
            circuit calculations; useful in some cases, for example the simulation of full-\
1025
            size converters per IEC 60909-0:2016.
1026

1027
    OUTPUT:
1028
        **index** (int) - The unique ID of the created sgen
1029

1030
    EXAMPLE:
1031
        create_sgen(net, 1, p_mw = -120)
1032

1033
    """
1034 1
    _check_node_element(net, bus)
1035

1036 1
    index = _get_index_with_check(net, "sgen", index, name="static generator")
1037

1038 1
    entries = dict(zip(["name", "bus", "p_mw", "scaling", "q_mvar", "sn_mva", "in_service", "type",
1039
                        "current_source"], [name, bus, p_mw, scaling, q_mvar, sn_mva,
1040
                                            bool(in_service), type, current_source]))
1041

1042 1
    _set_entries(net, "sgen", index, True, **entries)
1043

1044 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "sgen")
1045 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "sgen")
1046 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "sgen")
1047 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "sgen")
1048 1
    _create_column_and_set_value(net, index, k, "k", "sgen")
1049 1
    _create_column_and_set_value(net, index, rx, "rx", "sgen")
1050 1
    _create_column_and_set_value(net, index, controllable, "controllable", "sgen", dtyp=bool_,
1051
                                 default_val=False, default_for_nan=True)
1052

1053 1
    return index
1054

1055

1056 1
def create_sgens(net, buses, p_mw, q_mvar=0, sn_mva=nan, name=None, index=None,
1057
                 scaling=1., type='wye', in_service=True, max_p_mw=None, min_p_mw=None,
1058
                 max_q_mvar=None, min_q_mvar=None, controllable=None, k=None, rx=None,
1059
                 current_source=True, **kwargs):
1060
    """
1061
    Adds a number of sgens in table net["sgen"].
1062

1063
    Static generators are modelled as positive and constant PQ power. This element is used to model
1064
    generators with a constant active and reactive power feed-in. If you want to model a voltage
1065
    controlled generator, use the generator element instead.
1066

1067
    INPUT:
1068
        **net** - The net within this load should be created
1069

1070
        **buses** (list of int) - A list of bus ids to which the loads are connected
1071

1072
    OPTIONAL:
1073

1074
        **p_mw** (list of floats) - The active power of the sgens
1075

1076
             - postive value   -> generation
1077
             - negative value  -> load
1078

1079
        **q_mvar** (list of floats, default 0) - The reactive power of the sgens
1080

1081
        **sn_mva** (list of floats, default None) - Nominal power of the sgens
1082

1083
        **name** (list of strings, default None) - The name for this sgen
1084

1085
        **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
1086

1087
        **type** (string, None) -  type variable to classify the sgen
1088

1089
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
1090
             is set to a range between one higher than the highest already existing index and the \
1091
             length of sgens that shall be created.
1092

1093
        **in_service** (list of boolean) - True for in_service or False for out of service
1094

1095
        **max_p_mw** (list of floats, default NaN) - Maximum active power sgen - necessary for \
1096
             controllable sgens in for OPF
1097

1098
        **min_p_mw** (list of floats, default NaN) - Minimum active power sgen - necessary for \
1099
             controllable sgens in for OPF
1100

1101
        **max_q_mvar** (list of floats, default NaN) - Maximum reactive power sgen - necessary for \
1102
             controllable sgens in for OPF
1103

1104
        **min_q_mvar** (list of floats, default NaN) - Minimum reactive power sgen - necessary for \
1105
             controllable sgens in OPF
1106

1107
        **controllable** (list of boolean, default NaN) - States, whether a sgen is controllable \
1108
             or not. Only respected for OPF
1109
             Defaults to False if "controllable" column exists in DataFrame
1110

1111
        **k** (list of floats, None) - Ratio of nominal current to short circuit current
1112

1113
        **rx** (list of floats, NaN) - R/X ratio for short circuit impedance. Only relevant if type\
1114
            is specified as motor so that sgen is treated as asynchronous motor
1115

1116
        **current_source** (list of bool, True) - Model this sgen as a current source during short-\
1117
            circuit calculations; useful in some cases, for example the simulation of full-\
1118
            size converters per IEC 60909-0:2016.
1119

1120
    OUTPUT:
1121
        **index** (int) - The unique IDs of the created elements
1122

1123
    EXAMPLE:
1124
        create_sgens(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
1125

1126
    """
1127 1
    _check_multiple_node_elements(net, buses)
1128

1129 1
    index = _get_multiple_index_with_check(net, "sgen", index, len(buses))
1130

1131 1
    entries = {"bus": buses, "p_mw": p_mw, "q_mvar": q_mvar, "sn_mva": sn_mva, "scaling": scaling,
1132
               "in_service": in_service, "name": name, "type": type,
1133
               'current_source': current_source}
1134

1135 1
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
1136 1
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
1137 1
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
1138 1
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
1139 1
    _add_series_to_entries(entries, index, "k", k)
1140 1
    _add_series_to_entries(entries, index, "rx", rx)
1141 1
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
1142
                           default_val=False)
1143

1144 1
    _set_multiple_entries(net, "sgen", index, **entries, **kwargs)
1145

1146 1
    return index
1147

1148

1149
# =============================================================================
1150
# Create 3ph Sgen
1151
# =============================================================================
1152

1153 1
def create_asymmetric_sgen(net, bus, p_a_mw=0, p_b_mw=0, p_c_mw=0, q_a_mvar=0, q_b_mvar=0,
1154
                           q_c_mvar=0, sn_mva=nan,
1155
                           name=None, index=None, scaling=1., type='wye', in_service=True):
1156
    """
1157

1158
    Adds one static generator in table net["asymmetric_sgen"].
1159

1160
    Static generators are modelled as negative  PQ loads. This element is used to model generators
1161
    with a constant active and reactive power feed-in. Positive active power means generation.
1162

1163
    INPUT:
1164
        **net** - The net within this static generator should be created
1165

1166
        **bus** (int) - The bus id to which the static generator is connected
1167

1168
    OPTIONAL:
1169

1170
        **p_a_mw** (float, default 0) - The active power of the static generator : Phase A
1171

1172
        **p_b_mw** (float, default 0) - The active power of the static generator : Phase B
1173

1174
        **p_c_mw** (float, default 0) - The active power of the static generator : Phase C
1175

1176
        **q_a_mvar** (float, default 0) - The reactive power of the sgen : Phase A
1177

1178
        **q_b_mvar** (float, default 0) - The reactive power of the sgen : Phase B
1179

1180
        **q_c_mvar** (float, default 0) - The reactive power of the sgen : Phase C
1181

1182
        **sn_mva** (float, default None) - Nominal power of the sgen
1183

1184
        **name** (string, default None) - The name for this sgen
1185

1186
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1187
            higher than the highest already existing index is selected.
1188

1189
        **scaling** (float, 1.) - An OPTIONAL scaling factor to be set customly
1190

1191
        **type** (string, 'wye') -  Three phase Connection type of the static generator: wye/delta
1192

1193
        **in_service** (boolean) - True for in_service or False for out of service
1194

1195
    OUTPUT:
1196
        **index** (int) - The unique ID of the created sgen
1197

1198
    EXAMPLE:
1199
        create_asymmetric_sgen(net, 1, p_b_mw=0.12)
1200

1201
    """
1202 1
    _check_node_element(net, bus)
1203

1204 1
    index = _get_index_with_check(net, "asymmetric_sgen", index,
1205
                                  name="3 phase asymmetric static generator")
1206

1207 1
    entries = dict(zip(["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling", "q_a_mvar",
1208
                        "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"],
1209
                       [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling, q_a_mvar, q_b_mvar, q_c_mvar,
1210
                        sn_mva, bool(in_service), type]))
1211

1212 1
    _set_entries(net, "asymmetric_sgen", index, True, **entries)
1213

1214 1
    return index
1215

1216

1217 1
def create_sgen_from_cosphi(net, bus, sn_mva, cos_phi, mode, **kwargs):
1218
    """
1219
    Creates an sgen element from rated power and power factor cos(phi).
1220

1221
    INPUT:
1222
        **net** - The net within this static generator should be created
1223

1224
        **bus** (int) - The bus id to which the static generator is connected
1225

1226
        **sn_mva** (float) - rated power of the generator
1227

1228
        **cos_phi** (float) - power factor cos_phi
1229

1230
        **mode** (str) - "ind" for inductive or "cap" for capacitive behaviour
1231

1232
    OUTPUT:
1233
        **index** (int) - The unique ID of the created sgen
1234

1235
    gen, sgen, and ext_grid are modelled in the generator point of view. Active power
1236
    will therefore be postive por generation, and reactive power will be negative for consumption
1237
    behaviour and positive for generation behaviour.
1238
    """
1239 1
    from pandapower.toolbox import pq_from_cosphi
1240 1
    p_mw, q_mvar = pq_from_cosphi(sn_mva, cos_phi, qmode=mode, pmode="gen")
1241 1
    return create_sgen(net, bus, sn_mva=sn_mva, p_mw=p_mw, q_mvar=q_mvar, **kwargs)
1242

1243

1244 1
def create_storage(net, bus, p_mw, max_e_mwh, q_mvar=0, sn_mva=nan, soc_percent=nan, min_e_mwh=0.0,
1245
                   name=None, index=None, scaling=1., type=None, in_service=True, max_p_mw=nan,
1246
                   min_p_mw=nan, max_q_mvar=nan, min_q_mvar=nan, controllable=nan):
1247
    """
1248
    Adds a storage to the network.
1249

1250
    In order to simulate a storage system it is possible to use sgens or loads to model the
1251
    discharging or charging state. The power of a storage can be positive or negative, so the use
1252
    of either a sgen or a load is (per definition of the elements) not correct.
1253
    To overcome this issue, a storage element can be created.
1254

1255
    As pandapower is not a time dependend simulation tool and there is no time domain parameter in
1256
    default power flow calculations, the state of charge (SOC) is not updated during any power flow
1257
    calculation.
1258
    The implementation of energy content related parameters in the storage element allows to create
1259
    customized, time dependend simulations by running several power flow calculations and updating
1260
    variables manually.
1261

1262
    INPUT:
1263
        **net** - The net within this storage should be created
1264

1265
        **bus** (int) - The bus id to which the storage is connected
1266

1267
        **p_mw** (float) - The momentary active power of the storage \
1268
            (positive for charging, negative for discharging)
1269

1270
        **max_e_mwh** (float) - The maximum energy content of the storage \
1271
            (maximum charge level)
1272

1273
    OPTIONAL:
1274
        **q_mvar** (float, default 0) - The reactive power of the storage
1275

1276
        **sn_mva** (float, default None) - Nominal power of the storage
1277

1278
        **soc_percent** (float, NaN) - The state of charge of the storage
1279

1280
        **min_e_mwh** (float, 0) - The minimum energy content of the storage \
1281
            (minimum charge level)
1282

1283
        **name** (string, default None) - The name for this storage
1284

1285
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1286
            higher than the highest already existing index is selected.
1287

1288
        **scaling** (float, 1.) - An OPTIONAL scaling factor to be set customly
1289

1290
        **type** (string, None) -  type variable to classify the storage
1291

1292
        **in_service** (boolean) - True for in_service or False for out of service
1293

1294
        **max_p_mw** (float, NaN) - Maximum active power injection - necessary for a \
1295
            controllable storage in OPF
1296

1297
        **min_p_mw** (float, NaN) - Minimum active power injection - necessary for a \
1298
            controllable storage in OPF
1299

1300
        **max_q_mvar** (float, NaN) - Maximum reactive power injection - necessary for a \
1301
            controllable storage in OPF
1302

1303
        **min_q_mvar** (float, NaN) - Minimum reactive power injection - necessary for a \
1304
            controllable storage in OPF
1305

1306
        **controllable** (bool, NaN) - Whether this storage is controllable by the optimal
1307
        powerflow
1308
            Defaults to False if "controllable" column exists in DataFrame
1309

1310
    OUTPUT:
1311
        **index** (int) - The unique ID of the created storage
1312

1313
    EXAMPLE:
1314
        create_storage(net, 1, p_mw = -30, max_e_mwh = 60, soc_percent = 1.0, min_e_mwh = 5)
1315

1316
    """
1317 1
    _check_node_element(net, bus)
1318

1319 1
    index = _get_index_with_check(net, "storage", index)
1320

1321 1
    entries = dict(zip(["name", "bus", "p_mw", "q_mvar", "sn_mva", "scaling", "soc_percent",
1322
                        "min_e_mwh", "max_e_mwh", "in_service", "type"],
1323
                       [name, bus, p_mw, q_mvar, sn_mva, scaling, soc_percent, min_e_mwh, max_e_mwh,
1324
                        bool(in_service), type]))
1325

1326 1
    _set_entries(net, "storage", index, True, **entries)
1327

1328
    # check for OPF parameters and add columns to network table
1329 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "storage")
1330 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "storage")
1331 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "storage")
1332 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "storage")
1333 1
    _create_column_and_set_value(net, index, controllable, "controllable", "storage",
1334
                                 dtyp=bool_, default_val=False, default_for_nan=True)
1335

1336 1
    return index
1337

1338

1339 1
def create_gen(net, bus, p_mw, vm_pu=1., sn_mva=nan, name=None, index=None, max_q_mvar=nan,
1340
               min_q_mvar=nan, min_p_mw=nan, max_p_mw=nan, min_vm_pu=nan, max_vm_pu=nan,
1341
               scaling=1., type=None, slack=False, controllable=nan, vn_kv=nan,
1342
               xdss_pu=nan, rdss_ohm=nan, cos_phi=nan, pg_percent=nan, power_station_trafo=None,
1343
               in_service=True):
1344
    """
1345
    Adds a generator to the network.
1346

1347
    Generators are always modelled as voltage controlled PV nodes, which is why the input parameter
1348
    is active power and a voltage set point. If you want to model a generator as PQ load with fixed
1349
    reactive power and variable voltage, please use a static generator instead.
1350

1351
    INPUT:
1352
        **net** - The net within this generator should be created
1353

1354
        **bus** (int) - The bus id to which the generator is connected
1355

1356
    OPTIONAL:
1357
        **p_mw** (float, default 0) - The active power of the generator (positive for generation!)
1358

1359
        **vm_pu** (float, default 0) - The voltage set point of the generator.
1360

1361
        **sn_mva** (float, None) - Nominal power of the generator
1362

1363
        **name** (string, None) - The name for this generator
1364

1365
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1366
            higher than the highest already existing index is selected.
1367

1368
        **scaling** (float, 1.0) - scaling factor which for the active power of the generator
1369

1370
        **type** (string, None) - type variable to classify generators
1371

1372
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this \
1373
                generator in OPF
1374
                False: p_mw and vm_pu setpoints are enforced and *limits are ignored*.
1375
                defaults to True if "controllable" column exists in DataFrame
1376
        powerflow
1377

1378
        **vn_kv** (float, NaN) - Rated voltage of the generator for short-circuit calculation
1379

1380
        **xdss_pu** (float, NaN) - Subtransient generator reactance for short-circuit calculation
1381

1382
        **rdss_ohm** (float, NaN) - Subtransient generator resistance for short-circuit calculation
1383

1384
        **cos_phi** (float, NaN) - Rated cosine phi of the generator for short-circuit calculation
1385
        
1386
        **pg_percent** (float, NaN) - Rated pg (voltage control range) of the generator for short-circuit calculation
1387
        
1388
        **power_station_trafo** (int, None) - Index of the power station transformer for short-circuit calculation
1389

1390
        **in_service** (bool, True) - True for in_service or False for out of service
1391

1392
        **max_p_mw** (float, default NaN) - Maximum active power injection - necessary for OPF
1393

1394
        **min_p_mw** (float, default NaN) - Minimum active power injection - necessary for OPF
1395

1396
        **max_q_mvar** (float, default NaN) - Maximum reactive power injection - necessary for OPF
1397

1398
        **min_q_mvar** (float, default NaN) - Minimum reactive power injection - necessary for OPF
1399

1400
        **min_vm_pu** (float, default NaN) - Minimum voltage magnitude. If not set the bus voltage \
1401
                                             limit is taken.
1402
                                           - necessary for OPF.
1403

1404
        **max_vm_pu** (float, default NaN) - Maximum voltage magnitude. If not set the bus voltage\
1405
                                              limit is taken.
1406
                                            - necessary for OPF
1407

1408
    OUTPUT:
1409
        **index** (int) - The unique ID of the created generator
1410

1411
    EXAMPLE:
1412
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1413

1414
    """
1415 1
    _check_node_element(net, bus)
1416

1417 1
    index = _get_index_with_check(net, "gen", index, name="generator")
1418

1419 1
    columns = ["name", "bus", "p_mw", "vm_pu", "sn_mva", "type", "slack", "in_service",
1420
               "scaling"]
1421 1
    variables = [name, bus, p_mw, vm_pu, sn_mva, type, slack, bool(in_service), scaling]
1422

1423 1
    _set_entries(net, "gen", index, True, **dict(zip(columns, variables)))
1424

1425
    # OPF limits
1426 1
    if not isnan(controllable):
1427 1
        if "controllable" not in net.gen.columns:
1428 1
            net.gen.loc[:, "controllable"] = pd.Series(dtype=bool, data=True)
1429 1
        net.gen.at[index, "controllable"] = bool(controllable)
1430 1
    elif "controllable" in net.gen.columns:
1431 1
        net.gen.at[index, "controllable"] = True
1432
    # P limits for OPF if controllable == True
1433 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "gen")
1434 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "gen")
1435
    # Q limits for OPF if controllable == True
1436 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "gen")
1437 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "gen")
1438
    # V limits for OPF if controllable == True
1439 1
    _create_column_and_set_value(net, index, max_vm_pu, "max_vm_pu", "gen", default_val=2.)
1440 1
    _create_column_and_set_value(net, index, min_vm_pu, "min_vm_pu", "gen", default_val=0.)
1441

1442
    # Short circuit calculation variables
1443 1
    _create_column_and_set_value(net, index, vn_kv, "vn_kv", "gen")
1444 1
    _create_column_and_set_value(net, index, cos_phi, "cos_phi", "gen") 
1445 1
    _create_column_and_set_value(net, index, xdss_pu, "xdss_pu", "gen")
1446 1
    _create_column_and_set_value(net, index, rdss_ohm, "rdss_ohm", "gen")
1447 1
    _create_column_and_set_value(net, index, pg_percent, "pg_percent", "gen")
1448 1
    _create_column_and_set_value(net, index, power_station_trafo,
1449
                                 "power_station_trafo", "gen")
1450

1451 1
    return index
1452

1453

1454 1
def create_gens(net, buses, p_mw, vm_pu=1., sn_mva=nan, name=None, index=None, max_q_mvar=None,
1455
                min_q_mvar=None, min_p_mw=None, max_p_mw=None, min_vm_pu=None, max_vm_pu=None,
1456
                scaling=1., type=None, slack=False, controllable=None, vn_kv=None,
1457
                xdss_pu=None, rdss_ohm=None, cos_phi=None, pg_percent=None, power_station_trafo=None,
1458
                in_service=True, **kwargs):
1459
    """
1460
    Adds generators to the specified buses network.
1461

1462
    Generators are always modelled as voltage controlled PV nodes, which is why the input parameter
1463
    is active power and a voltage set point. If you want to model a generator as PQ load with fixed
1464
    reactive power and variable voltage, please use a static generator instead.
1465

1466
    INPUT:
1467
        **net** - The net within this generator should be created
1468

1469
        **buses** (list of int) - The bus ids to which the generators are connected
1470

1471
    OPTIONAL:
1472
        **p_mw** (list of float, default 0) - The active power of the generator (positive for \
1473
            generation!)
1474

1475
        **vm_pu** (list of float, default 0) - The voltage set point of the generator.
1476

1477
        **sn_mva** (list of float, None) - Nominal power of the generator
1478

1479
        **name** (list of string, None) - The name for this generator
1480

1481
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
1482
            one higher than the highest already existing index is selected.
1483

1484
        **scaling** (list of float, 1.0) - scaling factor which for the active power of the\
1485
            generator
1486

1487
        **type** (list of string, None) - type variable to classify generators
1488

1489
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this \
1490
                                       generator in OPF
1491
                                       False: p_mw and vm_pu setpoints are enforced and \
1492
                                       *limits are ignored*.
1493
                                       defaults to True if "controllable" column exists in DataFrame
1494
        powerflow
1495

1496
        **vn_kv** (list of float, NaN) - Rated voltage of the generator for short-circuit \
1497
            calculation
1498

1499
        **xdss_pu** (list of float, NaN) - Subtransient generator reactance for short-circuit \
1500
            calculation
1501

1502
        **rdss_ohm** (list of float, NaN) - Subtransient generator resistance for short-circuit \
1503
            calculation
1504

1505
        **cos_phi** (list of float, NaN) - Rated cosine phi of the generator for short-circuit \
1506
            calculation
1507
            
1508
        **pg_percent** (float, NaN) - Rated pg (voltage control range) of the generator for \
1509
            short-circuit calculation
1510
        
1511
        **power_station_trafo** (int, None) - Index of the power station transformer for short-circuit calculation
1512

1513
        **in_service** (bool, True) - True for in_service or False for out of service
1514

1515
        **max_p_mw** (list of float, default NaN) - Maximum active power injection - necessary for\
1516
            OPF
1517

1518
        **min_p_mw** (list of float, default NaN) - Minimum active power injection - necessary for \
1519
            OPF
1520

1521
        **max_q_mvar** (list of float, default NaN) - Maximum reactive power injection - necessary\
1522
            for OPF
1523

1524
        **min_q_mvar** (list of float, default NaN) - Minimum reactive power injection - necessary \
1525
            for OPF
1526

1527
        **min_vm_pu** (list of float, default NaN) - Minimum voltage magnitude. If not set the \
1528
                                                     bus voltage limit is taken.
1529
                                                   - necessary for OPF.
1530

1531
        **max_vm_pu** (list of float, default NaN) - Maximum voltage magnitude. If not set the bus\
1532
                                                      voltage limit is taken.
1533
                                                    - necessary for OPF
1534

1535
    OUTPUT:
1536
        **index** (int) - The unique ID of the created generator
1537

1538
    EXAMPLE:
1539
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1540

1541
    """
1542 1
    _check_multiple_node_elements(net, buses)
1543

1544 1
    index = _get_multiple_index_with_check(net, "gen", index, len(buses))
1545

1546 1
    entries = {"bus": buses, "p_mw": p_mw, "vm_pu": vm_pu, "sn_mva": sn_mva, "scaling": scaling,
1547
               "in_service": in_service, "name": name, "type": type, "slack": slack}
1548

1549 1
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
1550 1
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
1551 1
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
1552 1
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
1553 1
    _add_series_to_entries(entries, index, "min_vm_pu", min_vm_pu)
1554 1
    _add_series_to_entries(entries, index, "max_vm_pu", max_vm_pu)
1555 1
    _add_series_to_entries(entries, index, "vn_kv", vn_kv)
1556 1
    _add_series_to_entries(entries, index, "cos_phi", cos_phi)
1557 1
    _add_series_to_entries(entries, index, "xdss_pu", xdss_pu)
1558 1
    _add_series_to_entries(entries, index, "rdss_ohm", rdss_ohm)
1559 1
    _add_series_to_entries(entries, index, "pg_percent", pg_percent)
1560 1
    _add_series_to_entries(entries, index, "power_station_trafo", power_station_trafo)
1561 1
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
1562
                           default_val=False)
1563

1564 1
    _set_multiple_entries(net, "gen", index, **entries, **kwargs)
1565

1566 1
    return index
1567

1568

1569 1
def create_motor(net, bus, pn_mech_mw, cos_phi, efficiency_percent=100., loading_percent=100.,
1570
                 name=None, lrc_pu=nan, scaling=1.0, vn_kv=nan, rx=nan, index=None, in_service=True,
1571
                 cos_phi_n=nan, efficiency_n_percent=nan):
1572
    """
1573
    Adds a motor to the network.
1574

1575

1576
    INPUT:
1577
        **net** - The net within this motor should be created
1578

1579
        **bus** (int) - The bus id to which the motor is connected
1580

1581
        **pn_mech_mw** (float) - Mechanical rated power of the motor
1582

1583
        **cos_phi** (float, nan) - cosine phi at current operating point
1584

1585
    OPTIONAL:
1586

1587
        **name** (string, None) - The name for this motor
1588

1589
        **efficiency_percent** (float, 100) - Efficiency in percent at current operating point
1590

1591
        **loading_percent** (float, 100) - The mechanical loading in percentage of the rated \
1592
            mechanical power
1593

1594
        **scaling** (float, 1.0) - scaling factor which for the active power of the motor
1595

1596
        **cos_phi_n** (float, nan) - cosine phi at rated power of the motor for short-circuit \
1597
            calculation
1598

1599
        **efficiency_n_percent** (float, 100) - Efficiency in percent at rated power for \
1600
            short-circuit calculation
1601

1602
        **lrc_pu** (float, nan) - locked rotor current in relation to the rated motor current
1603

1604
        **rx** (float, nan) - R/X ratio of the motor for short-circuit calculation.
1605

1606
        **vn_kv** (float, NaN) - Rated voltage of the motor for short-circuit calculation
1607

1608
        **in_service** (bool, True) - True for in_service or False for out of service
1609

1610
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1611
            higher than the highest already existing index is selected.
1612

1613
    OUTPUT:
1614
        **index** (int) - The unique ID of the created motor
1615

1616
    EXAMPLE:
1617
        create_motor(net, 1, pn_mech_mw = 0.120, cos_ph=0.9, vn_kv=0.6, efficiency_percent=90, \
1618
                     loading_percent=40, lrc_pu=6.0)
1619

1620
    """
1621 1
    _check_node_element(net, bus)
1622

1623 1
    index = _get_index_with_check(net, "motor", index)
1624

1625 1
    columns = ["name", "bus", "pn_mech_mw", "cos_phi", "cos_phi_n", "vn_kv", "rx",
1626
               "efficiency_n_percent", "efficiency_percent", "loading_percent",
1627
               "lrc_pu", "scaling", "in_service"]
1628 1
    variables = [name, bus, pn_mech_mw, cos_phi, cos_phi_n, vn_kv, rx, efficiency_n_percent,
1629
                 efficiency_percent, loading_percent, lrc_pu, scaling, bool(in_service)]
1630 1
    _set_entries(net, "motor", index, **dict(zip(columns, variables)))
1631

1632 1
    return index
1633

1634

1635 1
def create_ext_grid(net, bus, vm_pu=1.0, va_degree=0., name=None, in_service=True,
1636
                    s_sc_max_mva=nan, s_sc_min_mva=nan, rx_max=nan, rx_min=nan,
1637
                    max_p_mw=nan, min_p_mw=nan, max_q_mvar=nan, min_q_mvar=nan,
1638
                    index=None, r0x0_max=nan, x0x_max=nan, controllable=nan, **kwargs):
1639
    """
1640
    Creates an external grid connection.
1641

1642
    External grids represent the higher level power grid connection and are modelled as the slack
1643
    bus in the power flow calculation.
1644

1645
    INPUT:
1646
        **net** - pandapower network
1647

1648
        **bus** (int) - bus where the slack is connected
1649

1650
    OPTIONAL:
1651
        **vm_pu** (float, default 1.0) - voltage at the slack node in per unit
1652

1653
        **va_degree** (float, default 0.) - voltage angle at the slack node in degrees*
1654

1655
        **name** (string, default None) - name of of the external grid
1656

1657
        **in_service** (boolean) - True for in_service or False for out of service
1658

1659
        **s_sc_max_mva** (float, NaN) - maximal short circuit apparent power to calculate internal \
1660
            impedance of ext_grid for short circuit calculations
1661

1662
        **s_sc_min_mva** (float, NaN) - minimal short circuit apparent power to calculate internal \
1663
            impedance of ext_grid for short circuit calculations
1664

1665
        **rx_max** (float, NaN) - maximal R/X-ratio to calculate internal impedance of ext_grid \
1666
            for short circuit calculations
1667

1668
        **rx_min** (float, NaN) - minimal R/X-ratio to calculate internal impedance of ext_grid \
1669
            for short circuit calculations
1670

1671
        **max_p_mw** (float, NaN) - Maximum active power injection. Only respected for OPF
1672

1673
        **min_p_mw** (float, NaN) - Minimum active power injection. Only respected for OPF
1674

1675
        **max_q_mvar** (float, NaN) - Maximum reactive power injection. Only respected for OPF
1676

1677
        **min_q_mvar** (float, NaN) - Minimum reactive power injection. Only respected for OPF
1678

1679
        **r0x0_max** (float, NaN) - maximal R/X-ratio to calculate Zero sequence
1680
        internal impedance of ext_grid
1681

1682
        **x0x_max** (float, NaN) - maximal X0/X-ratio to calculate Zero sequence
1683
        internal impedance of ext_grid
1684

1685
        ** only considered in loadflow if calculate_voltage_angles = True
1686

1687
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for the \
1688
                                             ext_grid in OPF. The voltage limits set in the \
1689
                                             ext_grid bus are enforced.
1690
                                       False: p_mw and vm_pu setpoints are enforced and *limits are\
1691
                                              ignored*. The vm_pu setpoint is enforced and limits \
1692
                                              of the bus table are ignored.
1693
                                       defaults to False if "controllable" column exists in\
1694
                                       DataFrame
1695

1696
    EXAMPLE:
1697
        create_ext_grid(net, 1, voltage = 1.03)
1698

1699
        For three phase load flow
1700

1701
        create_ext_grid(net, 1, voltage=1.03, s_sc_max_mva=1000, rx_max=0.1, r0x0_max=0.1,\
1702
                       x0x_max=1.0)
1703
    """
1704 1
    _check_node_element(net, bus)
1705

1706 1
    index = _get_index_with_check(net, "ext_grid", index, name="external grid")
1707

1708 1
    entries = dict(zip(["bus", "name", "vm_pu", "va_degree", "in_service"],
1709
                       [bus, name, vm_pu, va_degree, bool(in_service)]))
1710 1
    _set_entries(net, "ext_grid", index, **entries, **kwargs)
1711

1712
    # OPF limits
1713 1
    _create_column_and_set_value(net, index, s_sc_max_mva, "s_sc_max_mva", "ext_grid")
1714 1
    _create_column_and_set_value(net, index, s_sc_min_mva, "s_sc_min_mva", "ext_grid")
1715 1
    _create_column_and_set_value(net, index, rx_min, "rx_min", "ext_grid")
1716 1
    _create_column_and_set_value(net, index, rx_max, "rx_max", "ext_grid")
1717 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "ext_grid")
1718 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "ext_grid")
1719 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "ext_grid")
1720 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "ext_grid")
1721 1
    _create_column_and_set_value(net, index, x0x_max, "x0x_max", "ext_grid")
1722 1
    _create_column_and_set_value(net, index, r0x0_max, "r0x0_max", "ext_grid")
1723 1
    _create_column_and_set_value(net, index, controllable, "controllable", "ext_grid",
1724
                                 dtyp=bool_, default_val=False, default_for_nan=True)
1725

1726 1
    return index
1727

1728

1729 1
def create_line(net, from_bus, to_bus, length_km, std_type, name=None, index=None, geodata=None,
1730
                df=1., parallel=1, in_service=True, max_loading_percent=nan, alpha=nan,
1731
                temperature_degree_celsius=nan):
1732
    """
1733
    Creates a line element in net["line"]
1734
    The line parameters are defined through the standard type library.
1735

1736

1737
    INPUT:
1738
        **net** - The net within this line should be created
1739

1740
        **from_bus** (int) - ID of the bus on one side which the line will be connected with
1741

1742
        **to_bus** (int) - ID of the bus on the other side which the line will be connected with
1743

1744
        **length_km** (float) - The line length in km
1745

1746
        **std_type** (string) - Name of a standard linetype :
1747

1748
                                - Pre-defined in standard_linetypes
1749

1750
                                **or**
1751

1752
                                - Customized std_type made using **create_std_type()**
1753

1754
    OPTIONAL:
1755
        **name** (string, None) - A custom name for this line
1756

1757
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1758
            higher than the highest already existing index is selected.
1759

1760
        **geodata**
1761
        (array, default None, shape= (,2L)) -
1762
        The linegeodata of the line. The first row should be the coordinates
1763
        of bus a and the last should be the coordinates of bus b. The points
1764
        in the middle represent the bending points of the line
1765

1766
        **in_service** (boolean, True) - True for in_service or False for out of service
1767

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

1771
        **parallel** (integer, 1) - number of parallel line systems
1772

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

1775
    OUTPUT:
1776
        **index** (int) - The unique ID of the created line
1777

1778
    EXAMPLE:
1779
        create_line(net, "line1", from_bus = 0, to_bus = 1, length_km=0.1,  std_type="NAYY 4x50 SE")
1780

1781
    """
1782

1783
    # check if bus exist to attach the line to
1784 1
    _check_branch_element(net, "Line", index, from_bus, to_bus)
1785

1786 1
    index = _get_index_with_check(net, "line", index)
1787

1788 1
    v = {
1789
        "name": name, "length_km": length_km, "from_bus": from_bus,
1790
        "to_bus": to_bus, "in_service": bool(in_service), "std_type": std_type,
1791
        "df": df, "parallel": parallel
1792
    }
1793

1794 1
    lineparam = load_std_type(net, std_type, "line")
1795

1796 1
    v.update({param: lineparam[param] for param in ["r_ohm_per_km", "x_ohm_per_km", "c_nf_per_km",
1797
                                                    "max_i_ka"]})
1798 1
    if "r0_ohm_per_km" in lineparam:
1799 1
        v.update({param: lineparam[param] for param in ["r0_ohm_per_km", "x0_ohm_per_km", "c0_nf_per_km"]})
1800

1801 1
    v["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
1802

1803 1
    if "type" in lineparam:
1804 1
        v["type"] = lineparam["type"]
1805

1806
    # if net.line column already has alpha, add it from std_type
1807 1
    if "alpha" in net.line.columns and "alpha" in lineparam:
1808 1
        v["alpha"] = lineparam["alpha"]
1809

1810 1
    _set_entries(net, "line", index, **v)
1811

1812 1
    if geodata is not None:
1813 0
        net["line_geodata"].loc[index, "coords"] = None
1814 0
        net["line_geodata"].at[index, "coords"] = geodata
1815

1816 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
1817 1
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
1818 1
    _create_column_and_set_value(net, index, temperature_degree_celsius,
1819
                                 "temperature_degree_celsius", "line")
1820

1821 1
    return index
1822

1823

1824 1
def create_lines(net, from_buses, to_buses, length_km, std_type, name=None, index=None,
1825
                 geodata=None, df=1., parallel=1, in_service=True, max_loading_percent=None):
1826
    """ Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
1827
        must be arrays of equal length. Other parameters may be either arrays of the same length or
1828
        single or values. In any case the line parameters are defined through a single standard
1829
        type, so all lines have the same standard type.
1830

1831

1832
        INPUT:
1833
            **net** - The net within this line should be created
1834

1835
            **from_buses** (list of int) - ID of the bus on one side which the line will be \
1836
                connected with
1837

1838
            **to_buses** (list of int) - ID of the bus on the other side which the line will be \
1839
                connected with
1840

1841
            **length_km** (list of float) - The line length in km
1842

1843
            **std_type** (string) - The linetype of the lines.
1844

1845
        OPTIONAL:
1846
            **name** (list of string, None) - A custom name for this line
1847

1848
            **index** (list of int, None) - Force a specified ID if it is available. If None, the\
1849
                index one higher than the highest already existing index is selected.
1850

1851
            **geodata**
1852
            (list of arrays, default None, shape of arrays (,2L)) -
1853
            The linegeodata of the line. The first row should be the coordinates
1854
            of bus a and the last should be the coordinates of bus b. The points
1855
            in the middle represent the bending points of the line
1856

1857
            **in_service** (list of boolean, True) - True for in_service or False for out of service
1858

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

1862
            **parallel** (list of integer, 1) - number of parallel line systems
1863

1864
            **max_loading_percent (list of float)** - maximum current loading (only needed for OPF)
1865

1866
        OUTPUT:
1867
            **index** (list of int) - The unique ID of the created line
1868

1869
        EXAMPLE:
1870
            create_line(net, "line1", from_bus=0, to_bus=1, length_km=0.1, std_type="NAYY 4x50 SE")
1871

1872
    """
1873 1
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
1874

1875 1
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
1876

1877 1
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km,
1878
               "std_type": std_type, "name": name, "df": df, "parallel": parallel,
1879
               "in_service": in_service}
1880

1881
    # add std type data
1882 1
    lineparam = load_std_type(net, std_type, "line")
1883 1
    entries["r_ohm_per_km"] = lineparam["r_ohm_per_km"]
1884 1
    entries["x_ohm_per_km"] = lineparam["x_ohm_per_km"]
1885 1
    entries["c_nf_per_km"] = lineparam["c_nf_per_km"]
1886 1
    entries["max_i_ka"] = lineparam["max_i_ka"]
1887 1
    entries["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
1888 1
    if "type" in lineparam:
1889 1
        entries["type"] = lineparam["type"]
1890

1891 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
1892

1893 1
    _set_multiple_entries(net, "line", index, **entries)
1894

1895 1
    if geodata is not None:
1896 1
        _add_multiple_branch_geodata(net, "line", geodata, index)
1897

1898 1
    return index
1899

1900

1901 1
def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km, x_ohm_per_km,
1902
                                c_nf_per_km, max_i_ka, name=None, index=None, type=None,
1903
                                geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
1904
                                max_loading_percent=nan, alpha=nan,
1905
                                temperature_degree_celsius=nan, r0_ohm_per_km=nan,
1906
                                x0_ohm_per_km=nan, c0_nf_per_km=nan, g0_us_per_km=0,
1907
                                endtemp_degree=nan, **kwargs):
1908
    """
1909
    Creates a line element in net["line"] from line parameters.
1910

1911
    INPUT:
1912
        **net** - The net within this line should be created
1913

1914
        **from_bus** (int) - ID of the bus on one side which the line will be connected with
1915

1916
        **to_bus** (int) - ID of the bus on the other side which the line will be connected with
1917

1918
        **length_km** (float) - The line length in km
1919

1920
        **r_ohm_per_km** (float) - line resistance in ohm per km
1921

1922
        **x_ohm_per_km** (float) - line reactance in ohm per km
1923

1924
        **c_nf_per_km** (float) - line capacitance in nano Farad per km
1925

1926
        **r0_ohm_per_km** (float) - zero sequence line resistance in ohm per km
1927

1928
        **x0_ohm_per_km** (float) - zero sequence line reactance in ohm per km
1929

1930
        **c0_nf_per_km** (float) - zero sequence line capacitance in nano Farad per km
1931

1932
        **max_i_ka** (float) - maximum thermal current in kilo Ampere
1933

1934
    OPTIONAL:
1935
        **name** (string, None) - A custom name for this line
1936

1937
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
1938
            higher than the highest already existing index is selected.
1939

1940
        **in_service** (boolean, True) - True for in_service or False for out of service
1941

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

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

1947
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
1948

1949
        **g0_us_per_km** (float, 0) - zero sequence dielectric conductance in micro Siemens per km
1950

1951
        **parallel** (integer, 1) - number of parallel line systems
1952

1953
        **geodata**
1954
        (array, default None, shape= (,2L)) -
1955
        The linegeodata of the line. The first row should be the coordinates
1956
        of bus a and the last should be the coordinates of bus b. The points
1957
        in the middle represent the bending points of the line
1958

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

1961
    OUTPUT:
1962
        **index** (int) - The unique ID of the created line
1963

1964
    EXAMPLE:
1965
        create_line_from_parameters(net, "line1", from_bus = 0, to_bus = 1, lenght_km=0.1,
1966
        r_ohm_per_km = .01, x_ohm_per_km = 0.05, c_nf_per_km = 10,
1967
        max_i_ka = 0.4)
1968

1969
    """
1970

1971
    # check if bus exist to attach the line to
1972 1
    _check_branch_element(net, "Line", index, from_bus, to_bus)
1973

1974 1
    index = _get_index_with_check(net, "line", index)
1975

1976 1
    v = {
1977
        "name": name, "length_km": length_km, "from_bus": from_bus,
1978
        "to_bus": to_bus, "in_service": bool(in_service), "std_type": None,
1979
        "df": df, "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
1980
        "c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "parallel": parallel, "type": type,
1981
        "g_us_per_km": g_us_per_km
1982
    }
1983

1984 1
    _set_entries(net, "line", index, **v, **kwargs)
1985

1986 1
    nan_0_values = [isnan(r0_ohm_per_km), isnan(x0_ohm_per_km), isnan(c0_nf_per_km)]
1987 1
    if not np_any(nan_0_values):
1988 1
        _create_column_and_set_value(net, index, r0_ohm_per_km, "r0_ohm_per_km", "line")
1989 1
        _create_column_and_set_value(net, index, x0_ohm_per_km, "x0_ohm_per_km", "line")
1990 1
        _create_column_and_set_value(net, index, c0_nf_per_km, "c0_nf_per_km", "line")
1991 1
        _create_column_and_set_value(net, index, g0_us_per_km, "g0_us_per_km", "line",
1992
                                     default_val=0.)
1993 1
    elif not np_all(nan_0_values):
1994 0
        logger.warning("Zero sequence values are given for only some parameters. Please specify "
1995
                       "them for all parameters, otherwise they are not set!")
1996

1997 1
    if geodata is not None:
1998 1
        net["line_geodata"].loc[index, "coords"] = None
1999 1
        net["line_geodata"].at[index, "coords"] = geodata
2000

2001 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
2002 1
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
2003 1
    _create_column_and_set_value(net, index, temperature_degree_celsius,
2004
                                 "temperature_degree_celsius", "line")
2005 1
    _create_column_and_set_value(net, index, endtemp_degree, "endtemp_degree", "line")
2006

2007 1
    return index
2008

2009

2010 1
def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per_km, x_ohm_per_km,
2011
                                 c_nf_per_km, max_i_ka, name=None, index=None, type=None,
2012
                                 geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
2013
                                 max_loading_percent=None, alpha=None,
2014
                                 temperature_degree_celsius=None, r0_ohm_per_km=None,
2015
                                 x0_ohm_per_km=None, c0_nf_per_km=None, g0_us_per_km=None,
2016
                                 **kwargs):
2017
    """
2018
    Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
2019
        must be arrays of equal length. Other parameters may be either arrays of the same length or
2020
        single or values.
2021

2022
    INPUT:
2023
        **net** - The net within this line should be created
2024

2025
        **from_bus** (list of int) - ID of the bus on one side which the line will be connected with
2026

2027
        **to_bus** (list of int) - ID of the bus on the other side which the line will be connected\
2028
            with
2029

2030
        **length_km** (list of float) - The line length in km
2031

2032
        **r_ohm_per_km** (list of float) - line resistance in ohm per km
2033

2034
        **x_ohm_per_km** (list of float) - line reactance in ohm per km
2035

2036
        **c_nf_per_km** (list of float) - line capacitance in nano Farad per km
2037

2038
        **r0_ohm_per_km** (list of float) - zero sequence line resistance in ohm per km
2039

2040
        **x0_ohm_per_km** (list of float) - zero sequence line reactance in ohm per km
2041

2042
        **c0_nf_per_km** (list of float) - zero sequence line capacitance in nano Farad per km
2043

2044
        **max_i_ka** (list of float) - maximum thermal current in kilo Ampere
2045

2046
    OPTIONAL:
2047
        **name** (string, None) - A custom name for this line
2048

2049
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
2050
            higher than the highest already existing index is selected.
2051

2052
        **in_service** (boolean, True) - True for in_service or False for out of service
2053

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

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

2059
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
2060

2061
        **g0_us_per_km** (float, 0) - zero sequence dielectric conductance in micro Siemens per km
2062

2063
        **parallel** (integer, 1) - number of parallel line systems
2064

2065
        **geodata**
2066
        (array, default None, shape= (,2L)) -
2067
        The linegeodata of the line. The first row should be the coordinates
2068
        of bus a and the last should be the coordinates of bus b. The points
2069
        in the middle represent the bending points of the line
2070

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

2073
    OUTPUT:
2074
        **index** (int) - The unique ID of the created line
2075

2076
    EXAMPLE:
2077
        create_line_from_parameters(net, "line1", from_bus = 0, to_bus = 1, lenght_km=0.1,
2078
        r_ohm_per_km = .01, x_ohm_per_km = 0.05, c_nf_per_km = 10,
2079
        max_i_ka = 0.4)
2080

2081
    """
2082 1
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
2083

2084 1
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
2085

2086 1
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km, "type": type,
2087
               "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
2088
               "c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "g_us_per_km": g_us_per_km,
2089
               "name": name, "df": df, "parallel": parallel, "in_service": in_service}
2090

2091 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2092 1
    _add_series_to_entries(entries, index, "r0_ohm_per_km", r0_ohm_per_km)
2093 1
    _add_series_to_entries(entries, index, "x0_ohm_per_km", x0_ohm_per_km)
2094 1
    _add_series_to_entries(entries, index, "c0_nf_per_km", c0_nf_per_km)
2095 1
    _add_series_to_entries(entries, index, "g0_us_per_km", g0_us_per_km)
2096 1
    _add_series_to_entries(entries, index, "temperature_degree_celsius", temperature_degree_celsius)
2097 1
    _add_series_to_entries(entries, index, "alpha", alpha)
2098

2099 1
    _set_multiple_entries(net, "line", index, **entries, **kwargs)
2100

2101 1
    if geodata is not None:
2102 1
        _add_multiple_branch_geodata(net, "line", geodata, index)
2103

2104 1
    return index
2105

2106

2107 1
def create_transformer(net, hv_bus, lv_bus, std_type, name=None, tap_pos=nan, in_service=True,
2108
                       index=None, max_loading_percent=nan, parallel=1, df=1.):
2109
    """
2110
    Creates a two-winding transformer in table net["trafo"].
2111
    The trafo parameters are defined through the standard type library.
2112

2113
    INPUT:
2114
        **net** - The net within this transformer should be created
2115

2116
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2117
            connected to
2118

2119
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2120
            connected to
2121

2122
        **std_type** -  The used standard type from the standard type library
2123

2124
    **Zero sequence parameters** (Added through std_type For Three phase load flow) :
2125

2126
        **vk0_percent** - zero sequence relative short-circuit voltage
2127

2128
        **vkr0_percent** - real part of zero sequence relative short-circuit voltage
2129

2130
        **mag0_percent** - ratio between magnetizing and short circuit impedance (zero sequence)
2131

2132
                            z_mag0 / z0
2133

2134
        **mag0_rx**  - zero sequence magnetizing r/x  ratio
2135

2136
        **si0_hv_partial** - zero sequence short circuit impedance  distribution in hv side
2137

2138
    OPTIONAL:
2139
        **name** (string, None) - A custom name for this transformer
2140

2141
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2142
            position (tap_neutral)
2143

2144
        **in_service** (boolean, True) - True for in_service or False for out of service
2145

2146
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
2147
            higher than the highest already existing index is selected.
2148

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

2151
        **parallel** (integer) - number of parallel transformers
2152

2153
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2154
            current of transformer (from 0 to 1)
2155

2156
    OUTPUT:
2157
        **index** (int) - The unique ID of the created transformer
2158

2159
    EXAMPLE:
2160
        create_transformer(net, hv_bus = 0, lv_bus = 1, name = "trafo1", std_type = \
2161
            "0.4 MVA 10/0.4 kV")
2162
    """
2163

2164
    # Check if bus exist to attach the trafo to
2165 1
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2166

2167 1
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2168

2169 1
    if df <= 0:
2170 0
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2171

2172 1
    v = {
2173
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
2174
        "in_service": bool(in_service), "std_type": std_type
2175
    }
2176 1
    ti = load_std_type(net, std_type, "trafo")
2177

2178 1
    v.update({
2179
        "sn_mva": ti["sn_mva"],
2180
        "vn_hv_kv": ti["vn_hv_kv"],
2181
        "vn_lv_kv": ti["vn_lv_kv"],
2182
        "vk_percent": ti["vk_percent"],
2183
        "vkr_percent": ti["vkr_percent"],
2184
        "pfe_kw": ti["pfe_kw"],
2185
        "i0_percent": ti["i0_percent"],
2186
        "parallel": parallel,
2187
        "df": df,
2188
        "shift_degree": ti["shift_degree"] if "shift_degree" in ti else 0,
2189
        "tap_phase_shifter": ti["tap_phase_shifter"] if "tap_phase_shifter" in ti
2190
                                                        and pd.notnull(
2191
            ti["tap_phase_shifter"]) else False
2192
    })
2193 1
    for tp in ("tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent",
2194
               "tap_step_degree"):
2195 1
        if tp in ti:
2196 1
            v[tp] = ti[tp]
2197 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2198 1
        v["tap_pos"] = v["tap_neutral"]
2199
    else:
2200 1
        v["tap_pos"] = tap_pos
2201 1
        if isinstance(tap_pos, float):
2202 1
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2203

2204 1
    _set_entries(net, "trafo", index, **v)
2205

2206 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2207

2208
    # tap_phase_shifter default False
2209 1
    net.trafo.tap_phase_shifter.fillna(False, inplace=True)
2210

2211 1
    return index
2212

2213

2214 1
def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn_lv_kv,
2215
                                       vkr_percent, vk_percent, pfe_kw, i0_percent,
2216
                                       shift_degree=0,
2217
                                       tap_side=None, tap_neutral=nan, tap_max=nan,
2218
                                       tap_min=nan, tap_step_percent=nan, tap_step_degree=nan,
2219
                                       tap_pos=nan, tap_phase_shifter=False, in_service=True,
2220
                                       name=None, vector_group=None, index=None,
2221
                                       max_loading_percent=nan, parallel=1,
2222
                                       df=1., vk0_percent=nan, vkr0_percent=nan,
2223
                                       mag0_percent=nan, mag0_rx=nan,
2224
                                       si0_hv_partial=nan,
2225
                                       pt_percent=nan, oltc=False, **kwargs):
2226
    """
2227
    Creates a two-winding transformer in table net["trafo"].
2228
    The trafo parameters are defined through the standard type library.
2229

2230
    INPUT:
2231
        **net** - The net within this transformer should be created
2232

2233
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2234
            connected to
2235

2236
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2237
            connected to
2238

2239
        **sn_mva** (float) - rated apparent power
2240

2241
        **vn_hv_kv** (float) - rated voltage on high voltage side
2242

2243
        **vn_lv_kv** (float) - rated voltage on low voltage side
2244

2245
        **vkr_percent** (float) - real part of relative short-circuit voltage
2246

2247
        **vk_percent** (float) - relative short-circuit voltage
2248

2249
        **pfe_kw** (float)  - iron losses in kW
2250

2251
        **i0_percent** (float) - open loop losses in percent of rated current
2252

2253
        **vector_group** (String) - Vector group of the transformer
2254

2255
            HV side is Uppercase letters
2256
            and LV side is lower case
2257

2258
        **vk0_percent** (float) - zero sequence relative short-circuit voltage
2259

2260
        **vkr0_percent** - real part of zero sequence relative short-circuit voltage
2261

2262
        **mag0_percent** - zero sequence magnetizing impedance/ vk0
2263

2264
        **mag0_rx**  - zero sequence magnitizing R/X ratio
2265

2266
        **si0_hv_partial** - Distribution of zero sequence leakage impedances for HV side
2267

2268

2269
    OPTIONAL:
2270

2271
        **in_service** (boolean) - True for in_service or False for out of service
2272

2273
        **parallel** (integer) - number of parallel transformers
2274

2275
        **name** (string) - A custom name for this transformer
2276

2277
        **shift_degree** (float) - Angle shift over the transformer*
2278

2279
        **tap_side** (string) - position of tap changer ("hv", "lv")
2280

2281
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2282
            position (tap_neutral)
2283

2284
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the \
2285
            ratio of the rated voltages
2286

2287
        **tap_max** (int, nan) - maximal allowed tap position
2288

2289
        **tap_min** (int, nan):  minimal allowed tap position
2290

2291
        **tap_step_percent** (float) - tap step size for voltage magnitude in percent
2292

2293
        **tap_step_degree** (float) - tap step size for voltage angle in degree*
2294

2295
        **tap_phase_shifter** (bool) - whether the transformer is an ideal phase shifter*
2296

2297
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
2298
            higher than the highest already existing index is selected.
2299

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

2302
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2303
            current of transformer (from 0 to 1)
2304

2305
        **pt_percent** (float, nan) - (short circuit only)
2306
        
2307
        **oltc** (bool, False) - (short circuit only)
2308

2309
        ** only considered in loadflow if calculate_voltage_angles = True
2310

2311
    OUTPUT:
2312
        **index** (int) - The unique ID of the created transformer
2313

2314
    EXAMPLE:
2315
        create_transformer_from_parameters(net, hv_bus=0, lv_bus=1, name="trafo1", sn_mva=40, \
2316
            vn_hv_kv=110, vn_lv_kv=10, vk_percent=10, vkr_percent=0.3, pfe_kw=30, \
2317
            i0_percent=0.1, shift_degree=30)
2318
    """
2319

2320
    # Check if bus exist to attach the trafo to
2321 1
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2322

2323 1
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2324

2325 1
    if df <= 0:
2326 0
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2327

2328 1
    if tap_pos is nan:
2329 1
        tap_pos = tap_neutral
2330
        # store dtypes
2331

2332 1
    v = {
2333
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
2334
        "in_service": bool(in_service), "std_type": None, "sn_mva": sn_mva, "vn_hv_kv": vn_hv_kv,
2335
        "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent, "vkr_percent": vkr_percent,
2336
        "pfe_kw": pfe_kw, "i0_percent": i0_percent, "tap_neutral": tap_neutral,
2337
        "tap_max": tap_max, "tap_min": tap_min, "shift_degree": shift_degree,
2338
        "tap_side": tap_side, "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
2339
        "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df,
2340
        "pt_percent": pt_percent, "oltc": oltc
2341
    }
2342

2343 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2344 1
        v["tap_pos"] = v["tap_neutral"]
2345
    else:
2346 1
        v["tap_pos"] = tap_pos
2347 1
        if type(tap_pos) == float:
2348 1
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2349

2350 1
    _set_entries(net, "trafo", index, **v, **kwargs)
2351

2352 1
    if not (isnan(vk0_percent) and isnan(vkr0_percent) and isnan(mag0_percent)
2353
            and isnan(mag0_rx) and isnan(si0_hv_partial) and vector_group is None):
2354 1
        _create_column_and_set_value(net, index, vk0_percent, "vk0_percent", "trafo")
2355 1
        _create_column_and_set_value(net, index, vkr0_percent, "vkr0_percent", "trafo")
2356 1
        _create_column_and_set_value(net, index, mag0_percent, "mag0_percent", "trafo")
2357 1
        _create_column_and_set_value(net, index, mag0_rx, "mag0_rx", "trafo")
2358 1
        _create_column_and_set_value(net, index, si0_hv_partial, "si0_hv_partial", "trafo")
2359 1
        _create_column_and_set_value(net, index, vector_group, "vector_group", "trafo", dtyp=str,
2360
                                     default_val=None)
2361 1
    _create_column_and_set_value(net, index, pt_percent, "pt_percent", "trafo")   
2362 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2363

2364 1
    return index
2365

2366

2367 1
def create_transformers_from_parameters(net, hv_buses, lv_buses, sn_mva, vn_hv_kv, vn_lv_kv,
2368
                                        vkr_percent, vk_percent, pfe_kw, i0_percent, shift_degree=0,
2369
                                        tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
2370
                                        tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2371
                                        tap_phase_shifter=False, in_service=True, name=None,
2372
                                        vector_group=None, index=None, max_loading_percent=None,
2373
                                        parallel=1, df=1., vk0_percent=None, vkr0_percent=None,
2374
                                        mag0_percent=None, mag0_rx=None, si0_hv_partial=None,
2375
                                        pt_percent=nan, oltc=False, **kwargs):
2376
    """
2377
    Creates several two-winding transformers in table net["trafo"].
2378
    The trafo parameters are defined through the standard type library.
2379

2380
    INPUT:
2381
        **net** - The net within this transformer should be created
2382

2383
        **hv_bus** (list of int) - The bus on the high-voltage side on which the transformer will \
2384
            be connected to
2385

2386
        **lv_bus** (list of int) - The bus on the low-voltage side on which the transformer will \
2387
            be connected to
2388

2389
        **sn_mva** (list of float) - rated apparent power
2390

2391
        **vn_hv_kv** (list of float) - rated voltage on high voltage side
2392

2393
        **vn_lv_kv** (list of float) - rated voltage on low voltage side
2394

2395
        **vkr_percent** (list of float) - real part of relative short-circuit voltage
2396

2397
        **vk_percent** (list of float) - relative short-circuit voltage
2398

2399
        **pfe_kw** (list of float)  - iron losses in kW
2400

2401
        **i0_percent** (list of float) - open loop losses in percent of rated current
2402

2403
        **vector_group** (list of String) - Vector group of the transformer
2404

2405
            HV side is Uppercase letters
2406
            and LV side is lower case
2407

2408
        **vk0_percent** (list of float) - zero sequence relative short-circuit voltage
2409

2410
        **vkr0_percent** - (list of float) real part of zero sequence relative short-circuit voltage
2411

2412
        **mag0_percent** - (list of float)  zero sequence magnetizing impedance/ vk0
2413

2414
        **mag0_rx**  - (list of float)  zero sequence magnitizing R/X ratio
2415

2416
        **si0_hv_partial** - (list of float)  Distribution of zero sequence leakage impedances for \
2417
            HV side
2418

2419

2420
    OPTIONAL:
2421

2422
        **in_service** (boolean) - True for in_service or False for out of service
2423

2424
        **parallel** (integer) - number of parallel transformers
2425

2426
        **name** (string) - A custom name for this transformer
2427

2428
        **shift_degree** (float) - Angle shift over the transformer*
2429

2430
        **tap_side** (string) - position of tap changer ("hv", "lv")
2431

2432
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2433
            position (tap_neutral)
2434

2435
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the ratio\
2436
            of the rated voltages
2437

2438
        **tap_max** (int, nan) - maximal allowed tap position
2439

2440
        **tap_min** (int, nan):  minimal allowed tap position
2441

2442
        **tap_step_percent** (float) - tap step size for voltage magnitude in percent
2443

2444
        **tap_step_degree** (float) - tap step size for voltage angle in degree*
2445

2446
        **tap_phase_shifter** (bool) - whether the transformer is an ideal phase shifter*
2447

2448
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
2449
            higher than the highest already existing index is selected.
2450

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

2453
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2454
            current of transformer (from 0 to 1)
2455
        
2456
        **pt_percent** (float, nan) - (short circuit only)
2457
        
2458
        **oltc** (bool, False) - (short circuit only)
2459

2460
        ** only considered in loadflow if calculate_voltage_angles = True
2461

2462
    OUTPUT:
2463
        **index** (int) - The unique ID of the created transformer
2464

2465
    EXAMPLE:
2466
        create_transformer_from_parameters(net, hv_bus=0, lv_bus=1, name="trafo1", sn_mva=40, \
2467
            vn_hv_kv=110, vn_lv_kv=10, vk_percent=10, vkr_percent=0.3, pfe_kw=30, \
2468
            i0_percent=0.1, shift_degree=30)
2469
    """
2470 1
    _check_multiple_branch_elements(net, hv_buses, lv_buses, "Transformers")
2471

2472 1
    index = _get_multiple_index_with_check(net, "trafo", index, len(hv_buses))
2473

2474 1
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2475 1
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2476 1
    entries = {"name": name, "hv_bus": hv_buses, "lv_bus": lv_buses,
2477
               "in_service": array(in_service).astype(bool_), "std_type": None, "sn_mva": sn_mva,
2478
               "vn_hv_kv": vn_hv_kv, "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent,
2479
               "vkr_percent": vkr_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2480
               "tap_neutral": tp_neutral, "tap_max": tap_max, "tap_min": tap_min,
2481
               "shift_degree": shift_degree, "tap_pos": tp_pos, "tap_side": tap_side,
2482
               "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
2483
               "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df,
2484
               "pt_percent": pt_percent, "oltc": oltc}
2485

2486 1
    _add_series_to_entries(entries, index, "vk0_percent", vk0_percent)
2487 1
    _add_series_to_entries(entries, index, "vkr0_percent", vkr0_percent)
2488 1
    _add_series_to_entries(entries, index, "mag0_percent", mag0_percent)
2489 1
    _add_series_to_entries(entries, index, "mag0_rx", mag0_rx)
2490 1
    _add_series_to_entries(entries, index, "si0_hv_partial", si0_hv_partial)
2491 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2492 1
    _add_series_to_entries(entries, index, "vector_group", vector_group, dtyp=str)
2493 1
    _add_series_to_entries(entries, index, "pt_percent", pt_percent)
2494

2495 1
    _set_multiple_entries(net, "trafo", index, **entries, **kwargs)
2496

2497 1
    return index
2498

2499

2500 1
def create_transformer3w(net, hv_bus, mv_bus, lv_bus, std_type, name=None, tap_pos=nan,
2501
                         in_service=True, index=None, max_loading_percent=nan,
2502
                         tap_at_star_point=False):
2503
    """
2504
    Creates a three-winding transformer in table net["trafo3w"].
2505
    The trafo parameters are defined through the standard type library.
2506

2507
    INPUT:
2508
        **net** - The net within this transformer should be created
2509

2510
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2511
            connected to
2512

2513
        **mv_bus** (int) - The medium voltage bus on which the transformer will be connected to
2514

2515
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2516
            connected to
2517

2518
        **std_type** -  The used standard type from the standard type library
2519

2520
    OPTIONAL:
2521
        **name** (string) - A custom name for this transformer
2522

2523
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2524
            position (tap_neutral)
2525

2526
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2527
            3W-transformer or at the bus
2528

2529
        **in_service** (boolean) - True for in_service or False for out of service
2530

2531
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
2532
            higher than the highest already existing index is selected.
2533

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

2536
        **tap_at_star_point (bool)** - whether tap changer is modelled at star point or at the bus
2537

2538
    OUTPUT:
2539
        **index** (int) - The unique ID of the created transformer
2540

2541
    EXAMPLE:
2542
        create_transformer3w(net, hv_bus = 0, mv_bus = 1, lv_bus = 2, name = "trafo1", std_type = \
2543
            "63/25/38 MVA 110/20/10 kV")
2544
    """
2545

2546
    # Check if bus exist to attach the trafo to
2547 1
    for b in [hv_bus, mv_bus, lv_bus]:
2548 1
        if b not in net["bus"].index.values:
2549 1
            raise UserWarning("Trafo tries to attach to bus %s" % b)
2550

2551 1
    v = {
2552
        "name": name, "hv_bus": hv_bus, "mv_bus": mv_bus, "lv_bus": lv_bus,
2553
        "in_service": bool(in_service), "std_type": std_type
2554
    }
2555 1
    ti = load_std_type(net, std_type, "trafo3w")
2556

2557 1
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
2558

2559 1
    v.update({
2560
        "sn_hv_mva": ti["sn_hv_mva"],
2561
        "sn_mv_mva": ti["sn_mv_mva"],
2562
        "sn_lv_mva": ti["sn_lv_mva"],
2563
        "vn_hv_kv": ti["vn_hv_kv"],
2564
        "vn_mv_kv": ti["vn_mv_kv"],
2565
        "vn_lv_kv": ti["vn_lv_kv"],
2566
        "vk_hv_percent": ti["vk_hv_percent"],
2567
        "vk_mv_percent": ti["vk_mv_percent"],
2568
        "vk_lv_percent": ti["vk_lv_percent"],
2569
        "vkr_hv_percent": ti["vkr_hv_percent"],
2570
        "vkr_mv_percent": ti["vkr_mv_percent"],
2571
        "vkr_lv_percent": ti["vkr_lv_percent"],
2572
        "pfe_kw": ti["pfe_kw"],
2573
        "i0_percent": ti["i0_percent"],
2574
        "shift_mv_degree": ti["shift_mv_degree"] if "shift_mv_degree" in ti else 0,
2575
        "shift_lv_degree": ti["shift_lv_degree"] if "shift_lv_degree" in ti else 0,
2576
        "tap_at_star_point": tap_at_star_point
2577
    })
2578 1
    for tp in (
2579
            "tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent", "tap_step_degree"):
2580 1
        if tp in ti:
2581 1
            v.update({tp: ti[tp]})
2582

2583 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2584 1
        v["tap_pos"] = v["tap_neutral"]
2585
    else:
2586 0
        v["tap_pos"] = tap_pos
2587 0
        if type(tap_pos) == float:
2588 0
            net.trafo3w.tap_pos = net.trafo3w.tap_pos.astype(float)
2589

2590 1
    dd = pd.DataFrame(v, index=[index])
2591 1
    if version.parse(pd.__version__) < version.parse("0.21"):
2592 0
        net["trafo3w"] = net["trafo3w"].append(dd).reindex_axis(net["trafo3w"].columns, axis=1)
2593 1
    elif version.parse(pd.__version__) < version.parse("0.23"):
2594 0
        net["trafo3w"] = net["trafo3w"].append(dd).reindex(net["trafo3w"].columns, axis=1)
2595
    else:
2596 1
        net["trafo3w"] = net["trafo3w"].append(dd, sort=True).reindex(net["trafo3w"].columns,
2597
                                                                      axis=1)
2598

2599 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
2600

2601 1
    return index
2602

2603

2604 1
def create_transformer3w_from_parameters(net, hv_bus, mv_bus, lv_bus, vn_hv_kv, vn_mv_kv, vn_lv_kv,
2605
                                         sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
2606
                                         vk_mv_percent, vk_lv_percent, vkr_hv_percent,
2607
                                         vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
2608
                                         shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
2609
                                         tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2610
                                         tap_neutral=nan, tap_max=nan,
2611
                                         tap_min=nan, name=None, in_service=True, index=None,
2612
                                         max_loading_percent=nan, tap_at_star_point=False,
2613
                                         vk0_hv_percent=nan, vk0_mv_percent=nan, vk0_lv_percent=nan,
2614
                                         vkr0_hv_percent=nan, vkr0_mv_percent=nan, vkr0_lv_percent=nan,
2615
                                         vector_group=None):
2616
    """
2617
    Adds a three-winding transformer in table net["trafo3w"].
2618

2619
    Input:
2620
        **net** (pandapowerNet) - The net within this transformer should be created
2621

2622
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2623
            connected to
2624

2625
        **mv_bus** (int) - The bus on the middle-voltage side on which the transformer will be \
2626
            connected to
2627

2628
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2629
            connected to
2630

2631
        **vn_hv_kv** (float) rated voltage on high voltage side
2632

2633
        **vn_mv_kv** (float) rated voltage on medium voltage side
2634

2635
        **vn_lv_kv** (float) rated voltage on low voltage side
2636

2637
        **sn_hv_mva** (float) - rated apparent power on high voltage side
2638

2639
        **sn_mv_mva** (float) - rated apparent power on medium voltage side
2640

2641
        **sn_lv_mva** (float) - rated apparent power on low voltage side
2642

2643
        **vk_hv_percent** (float) - short circuit voltage from high to medium voltage
2644

2645
        **vk_mv_percent** (float) - short circuit voltage from medium to low voltage
2646

2647
        **vk_lv_percent** (float) - short circuit voltage from high to low voltage
2648

2649
        **vkr_hv_percent** (float) - real part of short circuit voltage from high to medium voltage
2650

2651
        **vkr_mv_percent** (float) - real part of short circuit voltage from medium to low voltage
2652

2653
        **vkr_lv_percent** (float) - real part of short circuit voltage from high to low voltage
2654

2655
        **pfe_kw** (float) - iron losses in kW
2656

2657
        **i0_percent** (float) - open loop losses
2658

2659
    OPTIONAL:
2660
        **shift_mv_degree** (float, 0) - angle shift to medium voltage side*
2661

2662
        **shift_lv_degree** (float, 0) - angle shift to low voltage side*
2663

2664
        **tap_step_percent** (float) - Tap step in percent
2665

2666
        **tap_step_degree** (float) - Tap phase shift angle in degrees
2667

2668
        **tap_side** (string, None) - "hv", "mv", "lv"
2669

2670
        **tap_neutral** (int, nan) - default tap position
2671

2672
        **tap_min** (int, nan) - Minimum tap position
2673

2674
        **tap_max** (int, nan) - Maximum tap position
2675

2676
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the \
2677
            medium position (tap_neutral)
2678

2679
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2680
            3W-transformer or at the bus
2681

2682
        **name** (string, None) - Name of the 3-winding transformer
2683

2684
        **in_service** (boolean, True) - True for in_service or False for out of service
2685

2686
        ** only considered in loadflow if calculate_voltage_angles = True
2687
        **The model currently only supports one tap-changer per 3W Transformer.
2688

2689
        **max_loading_percent (float)** - maximum current loading (only needed for OPF)
2690
        
2691
        **vk0_hv_percent** (float) - zero sequence short circuit voltage from high to medium voltage
2692

2693
        **vk0_mv_percent** (float) - zero sequence short circuit voltage from medium to low voltage
2694

2695
        **vk0_lv_percent** (float) - zero sequence short circuit voltage from high to low voltage
2696

2697
        **vkr0_hv_percent** (float) - zero sequence real part of short circuit voltage from high to medium voltage
2698

2699
        **vkr0_mv_percent** (float) - zero sequence real part of short circuit voltage from medium to low voltage
2700

2701
        **vkr0_lv_percent** (float) - zero sequence real part of short circuit voltage from high to low voltage
2702
        
2703
        **vector_group** (list of String) - Vector group of the transformer3w
2704

2705
    OUTPUT:
2706
        **trafo_id** - The unique trafo_id of the created 3W transformer
2707

2708
    Example:
2709
        create_transformer3w_from_parameters(net, hv_bus=0, mv_bus=1, lv_bus=2, name="trafo1",
2710
        sn_hv_mva=40, sn_mv_mva=20, sn_lv_mva=20, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10,
2711
        vk_hv_percent=10,vk_mv_percent=11, vk_lv_percent=12, vkr_hv_percent=0.3,
2712
        vkr_mv_percent=0.31, vkr_lv_percent=0.32, pfe_kw=30, i0_percent=0.1, shift_mv_degree=30,
2713
        shift_lv_degree=30)
2714

2715
    """
2716

2717
    # Check if bus exist to attach the trafo to
2718 1
    for b in [hv_bus, mv_bus, lv_bus]:
2719 1
        if b not in net["bus"].index.values:
2720 1
            raise UserWarning("Trafo tries to attach to non-existent bus %s" % b)
2721

2722 1
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
2723

2724 1
    if tap_pos is nan:
2725 1
        tap_pos = tap_neutral
2726

2727 1
    columns = ["lv_bus", "mv_bus", "hv_bus", "vn_hv_kv", "vn_mv_kv", "vn_lv_kv", "sn_hv_mva",
2728
               "sn_mv_mva", "sn_lv_mva", "vk_hv_percent", "vk_mv_percent", "vk_lv_percent",
2729
               "vkr_hv_percent", "vkr_mv_percent", "vkr_lv_percent", "pfe_kw", "i0_percent",
2730
               "shift_mv_degree", "shift_lv_degree", "tap_side", "tap_step_percent",
2731
               "tap_step_degree", "tap_pos", "tap_neutral", "tap_max", "tap_min", "in_service",
2732
               "name", "std_type", "tap_at_star_point", "vk0_hv_percent", "vk0_mv_percent", "vk0_lv_percent",
2733
               "vkr0_hv_percent", "vkr0_mv_percent", "vkr0_lv_percent", "vector_group"]
2734 1
    values = [lv_bus, mv_bus, hv_bus, vn_hv_kv, vn_mv_kv, vn_lv_kv, sn_hv_mva, sn_mv_mva, sn_lv_mva,
2735
              vk_hv_percent, vk_mv_percent, vk_lv_percent, vkr_hv_percent, vkr_mv_percent,
2736
              vkr_lv_percent, pfe_kw, i0_percent, shift_mv_degree, shift_lv_degree, tap_side,
2737
              tap_step_percent, tap_step_degree, tap_pos, tap_neutral, tap_max, tap_min,
2738
              bool(in_service), name, None, tap_at_star_point,
2739
              vk0_hv_percent, vk0_mv_percent, vk0_lv_percent,
2740
              vkr0_hv_percent, vkr0_mv_percent, vkr0_lv_percent, vector_group]
2741

2742 1
    _set_entries(net, "trafo3w", index, **dict(zip(columns, values)))
2743

2744 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
2745

2746 1
    return index
2747

2748

2749 1
def create_transformers3w_from_parameters(net, hv_buses, mv_buses, lv_buses, vn_hv_kv, vn_mv_kv,
2750
                                          vn_lv_kv, sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
2751
                                          vk_mv_percent, vk_lv_percent, vkr_hv_percent,
2752
                                          vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
2753
                                          shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
2754
                                          tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2755
                                          tap_neutral=nan, tap_max=nan, tap_min=nan, name=None,
2756
                                          in_service=True, index=None, max_loading_percent=None,
2757
                                          tap_at_star_point=False,
2758
                                          vk0_hv_percent=nan, vk0_mv_percent=nan, vk0_lv_percent=nan,
2759
                                          vkr0_hv_percent=nan, vkr0_mv_percent=nan, vkr0_lv_percent=nan,
2760
                                          vector_group=None, **kwargs):
2761
    """
2762
    Adds a three-winding transformer in table net["trafo3w"].
2763

2764
    Input:
2765
        **net** (pandapowerNet) - The net within this transformer should be created
2766

2767
        **hv_bus** (list) - The bus on the high-voltage side on which the transformer will be \
2768
            connected to
2769

2770
        **mv_bus** (list) - The bus on the middle-voltage side on which the transformer will be \
2771
            connected to
2772

2773
        **lv_bus** (list) - The bus on the low-voltage side on which the transformer will be \
2774
            connected to
2775

2776
        **vn_hv_kv** (float or list) rated voltage on high voltage side
2777

2778
        **vn_mv_kv** (float or list) rated voltage on medium voltage side
2779

2780
        **vn_lv_kv** (float or list) rated voltage on low voltage side
2781

2782
        **sn_hv_mva** (float or list) - rated apparent power on high voltage side
2783

2784
        **sn_mv_mva** (float or list) - rated apparent power on medium voltage side
2785

2786
        **sn_lv_mva** (float or list) - rated apparent power on low voltage side
2787

2788
        **vk_hv_percent** (float or list) - short circuit voltage from high to medium voltage
2789

2790
        **vk_mv_percent** (float or list) - short circuit voltage from medium to low voltage
2791

2792
        **vk_lv_percent** (float or list) - short circuit voltage from high to low voltage
2793

2794
        **vkr_hv_percent** (float or list) - real part of short circuit voltage from high to medium\
2795
            voltage
2796

2797
        **vkr_mv_percent** (float or list) - real part of short circuit voltage from medium to low\
2798
            voltage
2799

2800
        **vkr_lv_percent** (float or list) - real part of short circuit voltage from high to low\
2801
            voltage
2802

2803
        **pfe_kw** (float or list) - iron losses in kW
2804

2805
        **i0_percent** (float or list) - open loop losses
2806

2807
    OPTIONAL:
2808
        **shift_mv_degree** (float or list, 0) - angle shift to medium voltage side*
2809

2810
        **shift_lv_degree** (float or list, 0) - angle shift to low voltage side*
2811

2812
        **tap_step_percent** (float or list) - Tap step in percent
2813

2814
        **tap_step_degree** (float or list) - Tap phase shift angle in degrees
2815

2816
        **tap_side** (string, None) - "hv", "mv", "lv"
2817

2818
        **tap_neutral** (int, nan) - default tap position
2819

2820
        **tap_min** (int, nan) - Minimum tap position
2821

2822
        **tap_max** (int, nan) - Maximum tap position
2823

2824
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the \
2825
            medium position (tap_neutral)
2826

2827
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2828
            3W-transformer or at the bus
2829

2830
        **name** (string, None) - Name of the 3-winding transformer
2831

2832
        **in_service** (boolean, True) - True for in_service or False for out of service
2833

2834
        ** only considered in loadflow if calculate_voltage_angles = True
2835
        **The model currently only supports one tap-changer per 3W Transformer.
2836

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

2839
        **vk0_hv_percent** (float) - zero sequence short circuit voltage from high to medium voltage
2840

2841
        **vk0_mv_percent** (float) - zero sequence short circuit voltage from medium to low voltage
2842

2843
        **vk0_lv_percent** (float) - zero sequence short circuit voltage from high to low voltage
2844

2845
        **vkr0_hv_percent** (float) - zero sequence real part of short circuit voltage from high to medium voltage
2846

2847
        **vkr0_mv_percent** (float) - zero sequence real part of short circuit voltage from medium to low voltage
2848

2849
        **vkr0_lv_percent** (float) - zero sequence real part of short circuit voltage from high to low voltage
2850
        
2851
        **vector_group** (list of String) - Vector group of the transformer3w
2852

2853
    OUTPUT:
2854
        **trafo_id** - List of trafo_ids of the created 3W transformers
2855

2856
    Example:
2857
        create_transformer3w_from_parameters(net, hv_bus=0, mv_bus=1, lv_bus=2, name="trafo1",
2858
        sn_hv_mva=40, sn_mv_mva=20, sn_lv_mva=20, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10,
2859
        vk_hv_percent=10,vk_mv_percent=11, vk_lv_percent=12, vkr_hv_percent=0.3,
2860
        vkr_mv_percent=0.31, vkr_lv_percent=0.32, pfe_kw=30, i0_percent=0.1, shift_mv_degree=30,
2861
        shift_lv_degree=30)
2862

2863
    """
2864 1
    index = _get_multiple_index_with_check(net, "trafo3w", index, len(hv_buses),
2865
                                           name="Three winding transformers")
2866

2867 1
    if not np_all(isin(hv_buses, net.bus.index)):
2868 1
        bus_not_exist = set(hv_buses) - set(net.bus.index)
2869 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2870 1
    if not np_all(isin(mv_buses, net.bus.index)):
2871 1
        bus_not_exist = set(mv_buses) - set(net.bus.index)
2872 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2873 1
    if not np_all(isin(lv_buses, net.bus.index)):
2874 1
        bus_not_exist = set(lv_buses) - set(net.bus.index)
2875 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2876

2877 1
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2878 1
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2879 1
    entries = {"lv_bus": lv_buses, "mv_bus": mv_buses, "hv_bus": hv_buses, "vn_hv_kv": vn_hv_kv,
2880
               "vn_mv_kv": vn_mv_kv, "vn_lv_kv": vn_lv_kv, "sn_hv_mva": sn_hv_mva,
2881
               "sn_mv_mva": sn_mv_mva, "sn_lv_mva": sn_lv_mva, "vk_hv_percent": vk_hv_percent,
2882
               "vk_mv_percent": vk_mv_percent, "vk_lv_percent": vk_lv_percent,
2883
               "vkr_hv_percent": vkr_hv_percent, "vkr_mv_percent": vkr_mv_percent,
2884
               "vkr_lv_percent": vkr_lv_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2885
               "shift_mv_degree": shift_mv_degree, "shift_lv_degree": shift_lv_degree,
2886
               "tap_side": tap_side, "tap_step_percent": tap_step_percent,
2887
               "tap_step_degree": tap_step_degree, "tap_pos": tp_pos, "tap_neutral": tp_neutral,
2888
               "tap_max": tap_max, "tap_min": tap_min,
2889
               "in_service": array(in_service).astype(bool_), "name": name,
2890
               "tap_at_star_point": array(tap_at_star_point).astype(bool_), "std_type": None,
2891
               "vk0_hv_percent":vk0_hv_percent, "vk0_mv_percent":vk0_mv_percent,
2892
               "vk0_lv_percent":vk0_lv_percent, "vkr0_hv_percent":vkr0_hv_percent,
2893
               "vkr0_mv_percent":vkr0_mv_percent, "vkr0_lv_percent":vkr0_lv_percent,
2894
               "vector_group": vector_group}
2895

2896 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2897

2898 1
    _set_multiple_entries(net, "trafo3w", index, **entries, **kwargs)
2899

2900 1
    return index
2901

2902

2903 1
def create_switch(net, bus, element, et, closed=True, type=None, name=None, index=None, z_ohm=0):
2904
    """
2905
    Adds a switch in the net["switch"] table.
2906

2907
    Switches can be either between two buses (bus-bus switch) or at the end of a line or transformer
2908
    element (bus-element switch).
2909

2910
    Two buses that are connected through a closed bus-bus switches are fused in the power flow if
2911
    the switch is closed or separated if the switch is open.
2912

2913
    An element that is connected to a bus through a bus-element switch is connected to the bus
2914
    if the switch is closed or disconnected if the switch is open.
2915

2916
    INPUT:
2917
        **net** (pandapowerNet) - The net within which this switch should be created
2918

2919
        **bus** - The bus that the switch is connected to
2920

2921
        **element** - index of the element: bus id if et == "b", line id if et == "l", trafo id if \
2922
            et == "t"
2923

2924
        **et** - (string) element type: "l" = switch between bus and line, "t" = switch between
2925
            bus and transformer, "t3" = switch between bus and transformer3w, "b" = switch between
2926
            two buses
2927

2928
    OPTIONAL:
2929
        **closed** (boolean, True) - switch position: False = open, True = closed
2930

2931
        **type** (int, None) - indicates the type of switch: "LS" = Load Switch, "CB" = \
2932
            Circuit Breaker, "LBS" = Load Break Switch or "DS" = Disconnecting Switch
2933

2934
        **z_ohm** (float, 0) - indicates the resistance of the switch, which has effect only on
2935
            bus-bus switches, if sets to 0, the buses will be fused like before, if larger than
2936
            0 a branch will be created for the switch which has also effects on the bus mapping
2937

2938
        **name** (string, default None) - The name for this switch
2939

2940
    OUTPUT:
2941
        **sid** - The unique switch_id of the created switch
2942

2943
    EXAMPLE:
2944
        create_switch(net, bus =  0, element = 1, et = 'b', type ="LS", z_ohm = 0.1)
2945

2946
        create_switch(net, bus = 0, element = 1, et = 'l')
2947

2948
    """
2949 1
    _check_node_element(net, bus)
2950 1
    if et == "l":
2951 1
        elm_tab = 'line'
2952 1
        if element not in net[elm_tab].index:
2953 0
            raise UserWarning("Unknown line index")
2954 1
        if (not net[elm_tab]["from_bus"].loc[element] == bus and
2955
                not net[elm_tab]["to_bus"].loc[element] == bus):
2956 0
            raise UserWarning("Line %s not connected to bus %s" % (element, bus))
2957 1
    elif et == "t":
2958 1
        elm_tab = 'trafo'
2959 1
        if element not in net[elm_tab].index:
2960 0
            raise UserWarning("Unknown bus index")
2961 1
        if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2962
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2963 0
            raise UserWarning("Trafo %s not connected to bus %s" % (element, bus))
2964 1
    elif et == "t3":
2965 1
        elm_tab = 'trafo3w'
2966 1
        if element not in net[elm_tab].index:
2967 0
            raise UserWarning("Unknown trafo3w index")
2968 1
        if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2969
                not net[elm_tab]["mv_bus"].loc[element] == bus and
2970
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2971 0
            raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
2972 1
    elif et == "b":
2973 1
        _check_node_element(net, element)
2974
    else:
2975 0
        raise UserWarning("Unknown element type")
2976

2977 1
    index = _get_index_with_check(net, "switch", index)
2978

2979 1
    entries = dict(zip(["bus", "element", "et", "closed", "type", "name", "z_ohm"],
2980
                       [bus, element, et, closed, type, name, z_ohm]))
2981 1
    _set_entries(net, "switch", index, **entries)
2982

2983 1
    return index
2984

2985

2986 1
def create_switches(net, buses, elements, et, closed=True, type=None, name=None, index=None,
2987
                    z_ohm=0, **kwargs):
2988
    """
2989
    Adds a switch in the net["switch"] table.
2990

2991
    Switches can be either between two buses (bus-bus switch) or at the end of a line or transformer
2992
    element (bus-element switch).
2993

2994
    Two buses that are connected through a closed bus-bus switches are fused in the power flow if
2995
    the switch is closed or separated if the switch is open.
2996

2997
    An element that is connected to a bus through a bus-element switch is connected to the bus
2998
    if the switch is closed or disconnected if the switch is open.
2999

3000
    INPUT:
3001
        **net** (pandapowerNet) - The net within which this switch should be created
3002

3003
        **buses** (list)- The bus that the switch is connected to
3004

3005
        **element** (list)- index of the element: bus id if et == "b", line id if et == "l", \
3006
            trafo id if et == "t"
3007

3008
        **et** - (list) element type: "l" = switch between bus and line, "t" = switch between
3009
            bus and transformer, "t3" = switch between bus and transformer3w, "b" = switch between
3010
            two buses
3011

3012
    OPTIONAL:
3013
        **closed** (boolean, True) - switch position: False = open, True = closed
3014

3015
        **type** (int, None) - indicates the type of switch: "LS" = Load Switch, "CB" = \
3016
            Circuit Breaker, "LBS" = Load Break Switch or "DS" = Disconnecting Switch
3017

3018
        **z_ohm** (float, 0) - indicates the resistance of the switch, which has effect only on
3019
            bus-bus switches, if sets to 0, the buses will be fused like before, if larger than
3020
            0 a branch will be created for the switch which has also effects on the bus mapping
3021

3022
        **name** (string, default None) - The name for this switch
3023

3024
    OUTPUT:
3025
        **sid** - The unique switch_id of the created switch
3026

3027
    EXAMPLE:
3028
        create_switch(net, bus =  0, element = 1, et = 'b', type ="LS", z_ohm = 0.1)
3029

3030
        create_switch(net, bus = 0, element = 1, et = 'l')
3031

3032
    """
3033 1
    index = _get_multiple_index_with_check(net, "switch", index, len(buses), name="Switches")
3034 1
    _check_multiple_node_elements(net, buses)
3035

3036 1
    for element, elm_type, bus in zip(elements, et, buses):
3037 1
        if elm_type == "l":
3038 1
            elm_tab = 'line'
3039 1
            if element not in net[elm_tab].index:
3040 1
                raise UserWarning("Line %s does not exist" % element)
3041 1
            if (not net[elm_tab]["from_bus"].loc[element] == bus and
3042
                    not net[elm_tab]["to_bus"].loc[element] == bus):
3043 1
                raise UserWarning("Line %s not connected to bus %s" % (element, bus))
3044 1
        elif elm_type == "t":
3045 1
            elm_tab = 'trafo'
3046 1
            if element not in net[elm_tab].index:
3047 1
                raise UserWarning("Trafo %s does not exist" % element)
3048 1
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
3049
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
3050 1
                raise UserWarning("Trafo %s not connected to bus %s" % (element, bus))
3051 1
        elif elm_type == "t3":
3052 1
            elm_tab = 'trafo3w'
3053 1
            if element not in net[elm_tab].index:
3054 1
                raise UserWarning("Trafo3w %s does not exist" % element)
3055 1
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
3056
                    not net[elm_tab]["mv_bus"].loc[element] == bus and
3057
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
3058 1
                raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
3059 1
        elif elm_type == "b":
3060 1
            _check_node_element(net, element)
3061
        else:
3062 0
            raise UserWarning("Unknown element type")
3063

3064 1
    entries = {"bus": buses, "element": elements, "et": et, "closed": closed, "type": type,
3065
               "name": name, "z_ohm": z_ohm}
3066

3067 1
    _set_multiple_entries(net, "switch", index, **entries, **kwargs)
3068

3069 1
    return index
3070

3071

3072 1
def create_shunt(net, bus, q_mvar, p_mw=0., vn_kv=None, step=1, max_step=1, name=None,
3073
                 in_service=True, index=None):
3074
    """
3075
    Creates a shunt element
3076

3077
    INPUT:
3078
        **net** (pandapowerNet) - The pandapower network in which the element is created
3079

3080
        **bus** - bus number of bus to whom the shunt is connected to
3081

3082
        **p_mw** - shunt active power in MW at v= 1.0 p.u.
3083

3084
        **q_mvar** - shunt susceptance in MVAr at v= 1.0 p.u.
3085

3086
    OPTIONAL:
3087
        **vn_kv** (float, None) - rated voltage of the shunt. Defaults to rated voltage of \
3088
            connected bus
3089

3090
        **step** (int, 1) - step of shunt with which power values are multiplied
3091

3092
        **max_step** (boolean, True) - True for in_service or False for out of service
3093

3094
        **name** (str, None) - element name
3095

3096
        **in_service** (boolean, True) - True for in_service or False for out of service
3097

3098
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
3099
            higher than the highest already existing index is selected.
3100

3101
    OUTPUT:
3102
        **index** (int) - The unique ID of the created shunt
3103

3104
    EXAMPLE:
3105
        create_shunt(net, 0, 20)
3106
    """
3107 1
    _check_node_element(net, bus)
3108

3109 1
    index = _get_index_with_check(net, "shunt", index)
3110

3111 1
    if vn_kv is None:
3112 1
        vn_kv = net.bus.vn_kv.at[bus]
3113

3114 1
    entries = dict(zip(["bus", "name", "p_mw", "q_mvar", "vn_kv", "step", "max_step", "in_service"],
3115
                       [bus, name, p_mw, q_mvar, vn_kv, step, max_step, in_service]))
3116 1
    _set_entries(net, "shunt", index, **entries)
3117

3118 1
    return index
3119

3120

3121 1
def create_shunt_as_capacitor(net, bus, q_mvar, loss_factor, **kwargs):
3122
    """
3123
    Creates a shunt element representing a capacitor bank.
3124

3125
    INPUT:
3126

3127
        **net** (pandapowerNet) - The pandapower network in which the element is created
3128

3129
        **bus** - bus number of bus to whom the shunt is connected to
3130

3131
        **q_mvar** (float) - reactive power of the capacitor bank at rated voltage
3132

3133
        **loss_factor** (float) - loss factor tan(delta) of the capacitor bank
3134

3135
        **kwargs are passed to the create_shunt function
3136

3137

3138
    OUTPUT:
3139
        **index** (int) - The unique ID of the created shunt
3140
    """
3141 1
    q_mvar = -abs(q_mvar)  # q is always negative for capacitor
3142 1
    p_mw = abs(q_mvar * loss_factor)  # p is always positive for active power losses
3143 1
    return create_shunt(net, bus, q_mvar=q_mvar, p_mw=p_mw, **kwargs)
3144

3145

3146 1
def create_impedance(net, from_bus, to_bus, rft_pu, xft_pu, sn_mva, rtf_pu=None, xtf_pu=None,
3147
                     name=None, in_service=True, index=None):
3148
    """
3149
    Creates an per unit impedance element
3150

3151
    INPUT:
3152
        **net** (pandapowerNet) - The pandapower network in which the element is created
3153

3154
        **from_bus** (int) - starting bus of the impedance
3155

3156
        **to_bus** (int) - ending bus of the impedance
3157

3158
        **r_pu** (float) - real part of the impedance in per unit
3159

3160
        **x_pu** (float) - imaginary part of the impedance in per unit
3161

3162
        **sn_mva** (float) - rated power of the impedance in MVA
3163

3164
    OUTPUT:
3165

3166
        impedance id
3167
    """
3168 1
    index = _get_index_with_check(net, "impedance", index)
3169

3170 1
    _check_branch_element(net, "Impedance", index, from_bus, to_bus)
3171

3172 1
    if rtf_pu is None:
3173 1
        rtf_pu = rft_pu
3174 1
    if xtf_pu is None:
3175 1
        xtf_pu = xft_pu
3176

3177 1
    columns = ["from_bus", "to_bus", "rft_pu", "xft_pu", "rtf_pu", "xtf_pu", "name", "sn_mva",
3178
               "in_service"]
3179 1
    values = [from_bus, to_bus, rft_pu, xft_pu, rtf_pu, xtf_pu, name, sn_mva, in_service]
3180 1
    _set_entries(net, "impedance", index, **dict(zip(columns, values)))
3181

3182 1
    return index
3183

3184

3185 1
def create_series_reactor_as_impedance(net, from_bus, to_bus, r_ohm, x_ohm, sn_mva,
3186
                                       name=None, in_service=True, index=None):
3187
    """
3188
    Creates a series reactor as per-unit impedance
3189
    :param net: (pandapowerNet) - The pandapower network in which the element is created
3190
    :param from_bus: (int) - starting bus of the series reactor
3191
    :param to_bus: (int) - ending bus of the series reactor
3192
    :param r_ohm: (float) - real part of the impedance in Ohm
3193
    :param x_ohm: (float) - imaginary part of the impedance in Ohm
3194
    :param sn_mva: (float) - rated power of the series reactor in MVA
3195
    :param name:
3196
    :type name:
3197
    :param in_service:
3198
    :type in_service:
3199
    :param index:
3200
    :type index:
3201
    :return: index of the created element
3202
    """
3203 1
    if net.bus.at[from_bus, 'vn_kv'] == net.bus.at[to_bus, 'vn_kv']:
3204 1
        vn_kv = net.bus.at[from_bus, 'vn_kv']
3205
    else:
3206 0
        raise UserWarning('Unable to infer rated voltage vn_kv for series reactor %s due to '
3207
                          'different rated voltages of from_bus %d (%.3f p.u.) and '
3208
                          'to_bus %d (%.3f p.u.)' % (name, from_bus, net.bus.at[from_bus, 'vn_kv'],
3209
                                                     to_bus, net.bus.at[to_bus, 'vn_kv']))
3210

3211 1
    base_z_ohm = vn_kv ** 2 / sn_mva
3212 1
    rft_pu = r_ohm / base_z_ohm
3213 1
    xft_pu = x_ohm / base_z_ohm
3214

3215 1
    index = create_impedance(net, from_bus=from_bus, to_bus=to_bus, rft_pu=rft_pu, xft_pu=xft_pu,
3216
                             sn_mva=sn_mva, name=name, in_service=in_service, index=index)
3217 1
    return index
3218

3219

3220 1
def create_ward(net, bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name=None, in_service=True, index=None):
3221
    """
3222
    Creates a ward equivalent.
3223

3224
    A ward equivalent is a combination of an impedance load and a PQ load.
3225

3226
    INPUT:
3227
        **net** (pandapowernet) - The pandapower net within the element should be created
3228

3229
        **bus** (int) -  bus of the ward equivalent
3230

3231
        **ps_mw** (float) - active power of the PQ load
3232

3233
        **qs_mvar** (float) - reactive power of the PQ load
3234

3235
        **pz_mw** (float) - active power of the impedance load in MW at 1.pu voltage
3236

3237
        **qz_mvar** (float) - reactive power of the impedance load in MVar at 1.pu voltage
3238

3239
    OUTPUT:
3240
        ward id
3241
    """
3242 1
    _check_node_element(net, bus)
3243

3244 1
    index = _get_index_with_check(net, "ward", index, "ward equivalent")
3245

3246 1
    entries = dict(zip(["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "name", "in_service"],
3247
                       [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name, in_service]))
3248 1
    _set_entries(net, "ward", index, **entries)
3249

3250 1
    return index
3251

3252

3253 1
def create_xward(net, bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, in_service=True,
3254
                 name=None, index=None):
3255
    """
3256
    Creates an extended ward equivalent.
3257

3258
    A ward equivalent is a combination of an impedance load, a PQ load and as voltage source with
3259
    an internal impedance.
3260

3261
    INPUT:
3262
        **net** - The pandapower net within the impedance should be created
3263

3264
        **bus** (int) -  bus of the ward equivalent
3265

3266
        **ps_mw** (float) - active power of the PQ load
3267

3268
        **qs_mvar** (float) - reactive power of the PQ load
3269

3270
        **pz_mw** (float) - active power of the impedance load in MW at 1.pu voltage
3271

3272
        **qz_mvar** (float) - reactive power of the impedance load in MVar at 1.pu voltage
3273

3274
        **r_ohm** (float) - internal resistance of the voltage source
3275

3276
        **x_ohm** (float) - internal reactance of the voltage source
3277

3278
        **vm_pu** (float) - voltage magnitude at the additional PV-node
3279

3280
    OUTPUT:
3281
        xward id
3282
    """
3283 1
    _check_node_element(net, bus)
3284

3285 1
    index = _get_index_with_check(net, "xward", index, "extended ward equivalent")
3286

3287 1
    columns = ["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "r_ohm", "x_ohm", "vm_pu", "name",
3288
               "in_service"]
3289 1
    values = [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, name, in_service]
3290 1
    _set_entries(net, "xward", index, **dict(zip(columns, values)))
3291

3292 1
    return index
3293

3294

3295 1
def create_dcline(net, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu,
3296
                  index=None, name=None, max_p_mw=nan, min_q_from_mvar=nan, min_q_to_mvar=nan,
3297
                  max_q_from_mvar=nan, max_q_to_mvar=nan, in_service=True):
3298
    """
3299
    Creates a dc line.
3300

3301
    INPUT:
3302
        **from_bus** (int) - ID of the bus on one side which the line will be connected with
3303

3304
        **to_bus** (int) - ID of the bus on the other side which the line will be connected with
3305

3306
        **p_mw** - (float) Active power transmitted from 'from_bus' to 'to_bus'
3307

3308
        **loss_percent** - (float) Relative transmission loss in percent of active power
3309
            transmission
3310

3311
        **loss_mw** - (float) Total transmission loss in MW
3312

3313
        **vm_from_pu** - (float) Voltage setpoint at from bus
3314

3315
        **vm_to_pu** - (float) Voltage setpoint at to bus
3316

3317
    OPTIONAL:
3318
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
3319
            higher than the highest already existing index is selected.
3320

3321
        **name** (str, None) - A custom name for this dc line
3322

3323
        **in_service** (boolean) - True for in_service or False for out of service
3324

3325
        **max_p_mw** - Maximum active power flow. Only respected for OPF
3326

3327
        **min_q_from_mvar** - Minimum reactive power at from bus. Necessary for OPF
3328

3329
        **min_q_to_mvar** - Minimum reactive power at to bus. Necessary for OPF
3330

3331
        **max_q_from_mvar** - Maximum reactive power at from bus. Necessary for OPF
3332

3333
        **max_q_to_mvar ** - Maximum reactive power at to bus. Necessary for OPF
3334

3335
    OUTPUT:
3336
        **index** (int) - The unique ID of the created element
3337

3338
    EXAMPLE:
3339
        create_dcline(net, from_bus=0, to_bus=1, p_mw=1e4, loss_percent=1.2, loss_mw=25, \
3340
            vm_from_pu=1.01, vm_to_pu=1.02)
3341
    """
3342 1
    index = _get_index_with_check(net, "dcline", index)
3343

3344 1
    _check_branch_element(net, "DCLine"