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_pu=nan, cos_phi=nan, in_service=True):
1343
    """
1344
    Adds a generator to the network.
1345

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

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

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

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

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

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

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

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

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

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

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

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

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

1381
        **rdss_pu** (float, NaN) - Subtransient generator resistance for short-circuit calculation
1382

1383
        **cos_phi** (float, NaN) - Rated cosine phi of the generator for short-circuit calculation
1384

1385
        **in_service** (bool, True) - True for in_service or False for out of service
1386

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

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

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

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

1395
        **min_vm_pu** (float, default NaN) - Minimum voltage magnitude. If not set the bus voltage \
1396
                                             limit is taken.
1397
                                           - necessary for OPF.
1398

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

1403
    OUTPUT:
1404
        **index** (int) - The unique ID of the created generator
1405

1406
    EXAMPLE:
1407
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1408

1409
    """
1410 1
    _check_node_element(net, bus)
1411

1412 1
    index = _get_index_with_check(net, "gen", index, name="generator")
1413

1414 1
    columns = ["name", "bus", "p_mw", "vm_pu", "sn_mva", "type", "slack", "in_service",
1415
               "scaling"]
1416 1
    variables = [name, bus, p_mw, vm_pu, sn_mva, type, slack, bool(in_service), scaling]
1417

1418 1
    _set_entries(net, "gen", index, True, **dict(zip(columns, variables)))
1419

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

1437
    # Short circuit calculation limits
1438 1
    _create_column_and_set_value(net, index, vn_kv, "vn_kv", "gen")
1439 1
    _create_column_and_set_value(net, index, cos_phi, "cos_phi", "gen")
1440

1441 1
    if not isnan(xdss_pu):
1442 1
        if "xdss_pu" not in net.gen.columns:
1443 1
            net.gen.loc[:, "xdss_pu"] = pd.Series(dtype=float64)
1444 1
        if "rdss_pu" not in net.gen.columns:
1445 1
            net.gen.loc[:, "rdss_pu"] = pd.Series(dtype=float64)
1446 1
        net.gen.at[index, "xdss_pu"] = float(xdss_pu)
1447

1448 1
    _create_column_and_set_value(net, index, rdss_pu, "rdss_pu", "gen")
1449

1450 1
    return index
1451

1452

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

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

1464
    INPUT:
1465
        **net** - The net within this generator should be created
1466

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

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

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

1475
        **sn_mva** (list of float, None) - Nominal power of the generator
1476

1477
        **name** (list of string, None) - The name for this generator
1478

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

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

1485
        **type** (list of string, None) - type variable to classify generators
1486

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

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

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

1500
        **rdss_pu** (list of float, NaN) - Subtransient generator resistance for short-circuit \
1501
            calculation
1502

1503
        **cos_phi** (list of float, NaN) - Rated cosine phi of the generator for short-circuit \
1504
            calculation
1505

1506
        **in_service** (bool, True) - True for in_service or False for out of service
1507

1508
        **max_p_mw** (list of float, default NaN) - Maximum active power injection - necessary for\
1509
            OPF
1510

1511
        **min_p_mw** (list of float, default NaN) - Minimum active power injection - necessary for \
1512
            OPF
1513

1514
        **max_q_mvar** (list of float, default NaN) - Maximum reactive power injection - necessary\
1515
            for OPF
1516

1517
        **min_q_mvar** (list of float, default NaN) - Minimum reactive power injection - necessary \
1518
            for OPF
1519

1520
        **min_vm_pu** (list of float, default NaN) - Minimum voltage magnitude. If not set the \
1521
                                                     bus voltage limit is taken.
1522
                                                   - necessary for OPF.
1523

1524
        **max_vm_pu** (list of float, default NaN) - Maximum voltage magnitude. If not set the bus\
1525
                                                      voltage limit is taken.
1526
                                                    - necessary for OPF
1527

1528
    OUTPUT:
1529
        **index** (int) - The unique ID of the created generator
1530

1531
    EXAMPLE:
1532
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1533

1534
    """
1535 1
    _check_multiple_node_elements(net, buses)
1536

1537 1
    index = _get_multiple_index_with_check(net, "gen", index, len(buses))
1538

1539 1
    entries = {"bus": buses, "p_mw": p_mw, "vm_pu": vm_pu, "sn_mva": sn_mva, "scaling": scaling,
1540
               "in_service": in_service, "name": name, "type": type, "slack": slack}
1541

1542 1
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
1543 1
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
1544 1
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
1545 1
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
1546 1
    _add_series_to_entries(entries, index, "min_vm_pu", min_vm_pu)
1547 1
    _add_series_to_entries(entries, index, "max_vm_pu", max_vm_pu)
1548 1
    _add_series_to_entries(entries, index, "vn_kv", vn_kv)
1549 1
    _add_series_to_entries(entries, index, "cos_phi", cos_phi)
1550 1
    _add_series_to_entries(entries, index, "xdss_pu", xdss_pu)
1551 1
    _add_series_to_entries(entries, index, "rdss_pu", rdss_pu)
1552 1
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
1553
                           default_val=False)
1554

1555 1
    _set_multiple_entries(net, "gen", index, **entries, **kwargs)
1556

1557 1
    return index
1558

1559

1560 1
def create_motor(net, bus, pn_mech_mw, cos_phi, efficiency_percent=100., loading_percent=100.,
1561
                 name=None, lrc_pu=nan, scaling=1.0, vn_kv=nan, rx=nan, index=None, in_service=True,
1562
                 cos_phi_n=nan, efficiency_n_percent=nan):
1563
    """
1564
    Adds a motor to the network.
1565

1566

1567
    INPUT:
1568
        **net** - The net within this motor should be created
1569

1570
        **bus** (int) - The bus id to which the motor is connected
1571

1572
        **pn_mech_mw** (float) - Mechanical rated power of the motor
1573

1574
        **cos_phi** (float, nan) - cosine phi at current operating point
1575

1576
    OPTIONAL:
1577

1578
        **name** (string, None) - The name for this motor
1579

1580
        **efficiency_percent** (float, 100) - Efficiency in percent at current operating point
1581

1582
        **loading_percent** (float, 100) - The mechanical loading in percentage of the rated \
1583
            mechanical power
1584

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

1587
        **cos_phi_n** (float, nan) - cosine phi at rated power of the motor for short-circuit \
1588
            calculation
1589

1590
        **efficiency_n_percent** (float, 100) - Efficiency in percent at rated power for \
1591
            short-circuit calculation
1592

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

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

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

1599
        **in_service** (bool, True) - True for in_service or False for out of service
1600

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

1604
    OUTPUT:
1605
        **index** (int) - The unique ID of the created motor
1606

1607
    EXAMPLE:
1608
        create_motor(net, 1, pn_mech_mw = 0.120, cos_ph=0.9, vn_kv=0.6, efficiency_percent=90, \
1609
                     loading_percent=40, lrc_pu=6.0)
1610

1611
    """
1612 1
    _check_node_element(net, bus)
1613

1614 1
    index = _get_index_with_check(net, "motor", index)
1615

1616 1
    columns = ["name", "bus", "pn_mech_mw", "cos_phi", "cos_phi_n", "vn_kv", "rx",
1617
               "efficiency_n_percent", "efficiency_percent", "loading_percent",
1618
               "lrc_pu", "scaling", "in_service"]
1619 1
    variables = [name, bus, pn_mech_mw, cos_phi, cos_phi_n, vn_kv, rx, efficiency_n_percent,
1620
                 efficiency_percent, loading_percent, lrc_pu, scaling, bool(in_service)]
1621 1
    _set_entries(net, "motor", index, **dict(zip(columns, variables)))
1622

1623 1
    return index
1624

1625

1626 1
def create_ext_grid(net, bus, vm_pu=1.0, va_degree=0., name=None, in_service=True,
1627
                    s_sc_max_mva=nan, s_sc_min_mva=nan, rx_max=nan, rx_min=nan,
1628
                    max_p_mw=nan, min_p_mw=nan, max_q_mvar=nan, min_q_mvar=nan,
1629
                    index=None, r0x0_max=nan, x0x_max=nan, controllable=nan, **kwargs):
1630
    """
1631
    Creates an external grid connection.
1632

1633
    External grids represent the higher level power grid connection and are modelled as the slack
1634
    bus in the power flow calculation.
1635

1636
    INPUT:
1637
        **net** - pandapower network
1638

1639
        **bus** (int) - bus where the slack is connected
1640

1641
    OPTIONAL:
1642
        **vm_pu** (float, default 1.0) - voltage at the slack node in per unit
1643

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

1646
        **name** (string, default None) - name of of the external grid
1647

1648
        **in_service** (boolean) - True for in_service or False for out of service
1649

1650
        **s_sc_max_mva** (float, NaN) - maximal short circuit apparent power to calculate internal \
1651
            impedance of ext_grid for short circuit calculations
1652

1653
        **s_sc_min_mva** (float, NaN) - minimal short circuit apparent power to calculate internal \
1654
            impedance of ext_grid for short circuit calculations
1655

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

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

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

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

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

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

1670
        **r0x0_max** (float, NaN) - maximal R/X-ratio to calculate Zero sequence
1671
        internal impedance of ext_grid
1672

1673
        **x0x_max** (float, NaN) - maximal X0/X-ratio to calculate Zero sequence
1674
        internal impedance of ext_grid
1675

1676
        ** only considered in loadflow if calculate_voltage_angles = True
1677

1678
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for the \
1679
                                             ext_grid in OPF. The voltage limits set in the \
1680
                                             ext_grid bus are enforced.
1681
                                       False: p_mw and vm_pu setpoints are enforced and *limits are\
1682
                                              ignored*. The vm_pu setpoint is enforced and limits \
1683
                                              of the bus table are ignored.
1684
                                       defaults to False if "controllable" column exists in\
1685
                                       DataFrame
1686

1687
    EXAMPLE:
1688
        create_ext_grid(net, 1, voltage = 1.03)
1689

1690
        For three phase load flow
1691

1692
        create_ext_grid(net, 1, voltage=1.03, s_sc_max_mva=1000, rx_max=0.1, r0x0_max=0.1,\
1693
                       x0x_max=1.0)
1694
    """
1695 1
    _check_node_element(net, bus)
1696

1697 1
    index = _get_index_with_check(net, "ext_grid", index, name="external grid")
1698

1699 1
    entries = dict(zip(["bus", "name", "vm_pu", "va_degree", "in_service"],
1700
                       [bus, name, vm_pu, va_degree, bool(in_service)]))
1701 1
    _set_entries(net, "ext_grid", index, **entries, **kwargs)
1702

1703
    # OPF limits
1704 1
    _create_column_and_set_value(net, index, s_sc_max_mva, "s_sc_max_mva", "ext_grid")
1705 1
    _create_column_and_set_value(net, index, s_sc_min_mva, "s_sc_min_mva", "ext_grid")
1706 1
    _create_column_and_set_value(net, index, rx_min, "rx_min", "ext_grid")
1707 1
    _create_column_and_set_value(net, index, rx_max, "rx_max", "ext_grid")
1708 1
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "ext_grid")
1709 1
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "ext_grid")
1710 1
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "ext_grid")
1711 1
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "ext_grid")
1712 1
    _create_column_and_set_value(net, index, x0x_max, "x0x_max", "ext_grid")
1713 1
    _create_column_and_set_value(net, index, r0x0_max, "r0x0_max", "ext_grid")
1714 1
    _create_column_and_set_value(net, index, controllable, "controllable", "ext_grid",
1715
                                 dtyp=bool_, default_val=False, default_for_nan=True)
1716

1717 1
    return index
1718

1719

1720 1
def create_line(net, from_bus, to_bus, length_km, std_type, name=None, index=None, geodata=None,
1721
                df=1., parallel=1, in_service=True, max_loading_percent=nan, alpha=nan,
1722
                temperature_degree_celsius=nan):
1723
    """
1724
    Creates a line element in net["line"]
1725
    The line parameters are defined through the standard type library.
1726

1727

1728
    INPUT:
1729
        **net** - The net within this line should be created
1730

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

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

1735
        **length_km** (float) - The line length in km
1736

1737
        **std_type** (string) - Name of a standard linetype :
1738

1739
                                - Pre-defined in standard_linetypes
1740

1741
                                **or**
1742

1743
                                - Customized std_type made using **create_std_type()**
1744

1745
    OPTIONAL:
1746
        **name** (string, None) - A custom name for this line
1747

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

1751
        **geodata**
1752
        (array, default None, shape= (,2L)) -
1753
        The linegeodata of the line. The first row should be the coordinates
1754
        of bus a and the last should be the coordinates of bus b. The points
1755
        in the middle represent the bending points of the line
1756

1757
        **in_service** (boolean, True) - True for in_service or False for out of service
1758

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

1762
        **parallel** (integer, 1) - number of parallel line systems
1763

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

1766
    OUTPUT:
1767
        **index** (int) - The unique ID of the created line
1768

1769
    EXAMPLE:
1770
        create_line(net, "line1", from_bus = 0, to_bus = 1, length_km=0.1,  std_type="NAYY 4x50 SE")
1771

1772
    """
1773

1774
    # check if bus exist to attach the line to
1775 1
    _check_branch_element(net, "Line", index, from_bus, to_bus)
1776

1777 1
    index = _get_index_with_check(net, "line", index)
1778

1779 1
    v = {
1780
        "name": name, "length_km": length_km, "from_bus": from_bus,
1781
        "to_bus": to_bus, "in_service": bool(in_service), "std_type": std_type,
1782
        "df": df, "parallel": parallel
1783
    }
1784

1785 1
    lineparam = load_std_type(net, std_type, "line")
1786

1787 1
    v.update({param: lineparam[param] for param in ["r_ohm_per_km", "x_ohm_per_km", "c_nf_per_km",
1788
                                                    "max_i_ka"]})
1789 1
    if "r0_ohm_per_km" in lineparam:
1790 1
        v.update({param: lineparam[param] for param in ["r0_ohm_per_km", "x0_ohm_per_km", "c0_nf_per_km"]})
1791

1792 1
    v["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
1793

1794 1
    if "type" in lineparam:
1795 1
        v["type"] = lineparam["type"]
1796

1797
    # if net.line column already has alpha, add it from std_type
1798 1
    if "alpha" in net.line.columns and "alpha" in lineparam:
1799 1
        v["alpha"] = lineparam["alpha"]
1800

1801 1
    _set_entries(net, "line", index, **v)
1802

1803 1
    if geodata is not None:
1804 0
        net["line_geodata"].loc[index, "coords"] = None
1805 0
        net["line_geodata"].at[index, "coords"] = geodata
1806

1807 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
1808 1
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
1809 1
    _create_column_and_set_value(net, index, temperature_degree_celsius,
1810
                                 "temperature_degree_celsius", "line")
1811

1812 1
    return index
1813

1814

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

1822

1823
        INPUT:
1824
            **net** - The net within this line should be created
1825

1826
            **from_buses** (list of int) - ID of the bus on one side which the line will be \
1827
                connected with
1828

1829
            **to_buses** (list of int) - ID of the bus on the other side which the line will be \
1830
                connected with
1831

1832
            **length_km** (list of float) - The line length in km
1833

1834
            **std_type** (string) - The linetype of the lines.
1835

1836
        OPTIONAL:
1837
            **name** (list of string, None) - A custom name for this line
1838

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

1842
            **geodata**
1843
            (list of arrays, default None, shape of arrays (,2L)) -
1844
            The linegeodata of the line. The first row should be the coordinates
1845
            of bus a and the last should be the coordinates of bus b. The points
1846
            in the middle represent the bending points of the line
1847

1848
            **in_service** (list of boolean, True) - True for in_service or False for out of service
1849

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

1853
            **parallel** (list of integer, 1) - number of parallel line systems
1854

1855
            **max_loading_percent (list of float)** - maximum current loading (only needed for OPF)
1856

1857
        OUTPUT:
1858
            **index** (list of int) - The unique ID of the created line
1859

1860
        EXAMPLE:
1861
            create_line(net, "line1", from_bus=0, to_bus=1, length_km=0.1, std_type="NAYY 4x50 SE")
1862

1863
    """
1864 1
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
1865

1866 1
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
1867

1868 1
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km,
1869
               "std_type": std_type, "name": name, "df": df, "parallel": parallel,
1870
               "in_service": in_service}
1871

1872
    # add std type data
1873 1
    lineparam = load_std_type(net, std_type, "line")
1874 1
    entries["r_ohm_per_km"] = lineparam["r_ohm_per_km"]
1875 1
    entries["x_ohm_per_km"] = lineparam["x_ohm_per_km"]
1876 1
    entries["c_nf_per_km"] = lineparam["c_nf_per_km"]
1877 1
    entries["max_i_ka"] = lineparam["max_i_ka"]
1878 1
    entries["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
1879 1
    if "type" in lineparam:
1880 1
        entries["type"] = lineparam["type"]
1881

1882 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
1883

1884 1
    _set_multiple_entries(net, "line", index, **entries)
1885

1886 1
    if geodata is not None:
1887 1
        _add_multiple_branch_geodata(net, "line", geodata, index)
1888

1889 1
    return index
1890

1891

1892 1
def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km, x_ohm_per_km,
1893
                                c_nf_per_km, max_i_ka, name=None, index=None, type=None,
1894
                                geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
1895
                                max_loading_percent=nan, alpha=nan,
1896
                                temperature_degree_celsius=nan, r0_ohm_per_km=nan,
1897
                                x0_ohm_per_km=nan, c0_nf_per_km=nan, g0_us_per_km=0,
1898
                                endtemp_degree=nan, **kwargs):
1899
    """
1900
    Creates a line element in net["line"] from line parameters.
1901

1902
    INPUT:
1903
        **net** - The net within this line should be created
1904

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

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

1909
        **length_km** (float) - The line length in km
1910

1911
        **r_ohm_per_km** (float) - line resistance in ohm per km
1912

1913
        **x_ohm_per_km** (float) - line reactance in ohm per km
1914

1915
        **c_nf_per_km** (float) - line capacitance in nano Farad per km
1916

1917
        **r0_ohm_per_km** (float) - zero sequence line resistance in ohm per km
1918

1919
        **x0_ohm_per_km** (float) - zero sequence line reactance in ohm per km
1920

1921
        **c0_nf_per_km** (float) - zero sequence line capacitance in nano Farad per km
1922

1923
        **max_i_ka** (float) - maximum thermal current in kilo Ampere
1924

1925
    OPTIONAL:
1926
        **name** (string, None) - A custom name for this line
1927

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

1931
        **in_service** (boolean, True) - True for in_service or False for out of service
1932

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

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

1938
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
1939

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

1942
        **parallel** (integer, 1) - number of parallel line systems
1943

1944
        **geodata**
1945
        (array, default None, shape= (,2L)) -
1946
        The linegeodata of the line. The first row should be the coordinates
1947
        of bus a and the last should be the coordinates of bus b. The points
1948
        in the middle represent the bending points of the line
1949

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

1952
    OUTPUT:
1953
        **index** (int) - The unique ID of the created line
1954

1955
    EXAMPLE:
1956
        create_line_from_parameters(net, "line1", from_bus = 0, to_bus = 1, lenght_km=0.1,
1957
        r_ohm_per_km = .01, x_ohm_per_km = 0.05, c_nf_per_km = 10,
1958
        max_i_ka = 0.4)
1959

1960
    """
1961

1962
    # check if bus exist to attach the line to
1963 1
    _check_branch_element(net, "Line", index, from_bus, to_bus)
1964

1965 1
    index = _get_index_with_check(net, "line", index)
1966

1967 1
    v = {
1968
        "name": name, "length_km": length_km, "from_bus": from_bus,
1969
        "to_bus": to_bus, "in_service": bool(in_service), "std_type": None,
1970
        "df": df, "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
1971
        "c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "parallel": parallel, "type": type,
1972
        "g_us_per_km": g_us_per_km
1973
    }
1974

1975 1
    _set_entries(net, "line", index, **v, **kwargs)
1976

1977 1
    nan_0_values = [isnan(r0_ohm_per_km), isnan(x0_ohm_per_km), isnan(c0_nf_per_km)]
1978 1
    if not np_any(nan_0_values):
1979 1
        _create_column_and_set_value(net, index, r0_ohm_per_km, "r0_ohm_per_km", "line")
1980 1
        _create_column_and_set_value(net, index, x0_ohm_per_km, "x0_ohm_per_km", "line")
1981 1
        _create_column_and_set_value(net, index, c0_nf_per_km, "c0_nf_per_km", "line")
1982 1
        _create_column_and_set_value(net, index, g0_us_per_km, "g0_us_per_km", "line",
1983
                                     default_val=0.)
1984 1
    elif not np_all(nan_0_values):
1985 0
        logger.warning("Zero sequence values are given for only some parameters. Please specify "
1986
                       "them for all parameters, otherwise they are not set!")
1987

1988 1
    if geodata is not None:
1989 1
        net["line_geodata"].loc[index, "coords"] = None
1990 1
        net["line_geodata"].at[index, "coords"] = geodata
1991

1992 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
1993 1
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
1994 1
    _create_column_and_set_value(net, index, temperature_degree_celsius,
1995
                                 "temperature_degree_celsius", "line")
1996 1
    _create_column_and_set_value(net, index, endtemp_degree, "endtemp_degree", "line")
1997

1998 1
    return index
1999

2000

2001 1
def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per_km, x_ohm_per_km,
2002
                                 c_nf_per_km, max_i_ka, name=None, index=None, type=None,
2003
                                 geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
2004
                                 max_loading_percent=None, alpha=None,
2005
                                 temperature_degree_celsius=None, r0_ohm_per_km=None,
2006
                                 x0_ohm_per_km=None, c0_nf_per_km=None, g0_us_per_km=None,
2007
                                 **kwargs):
2008
    """
2009
    Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
2010
        must be arrays of equal length. Other parameters may be either arrays of the same length or
2011
        single or values.
2012

2013
    INPUT:
2014
        **net** - The net within this line should be created
2015

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

2018
        **to_bus** (list of int) - ID of the bus on the other side which the line will be connected\
2019
            with
2020

2021
        **length_km** (list of float) - The line length in km
2022

2023
        **r_ohm_per_km** (list of float) - line resistance in ohm per km
2024

2025
        **x_ohm_per_km** (list of float) - line reactance in ohm per km
2026

2027
        **c_nf_per_km** (list of float) - line capacitance in nano Farad per km
2028

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

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

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

2035
        **max_i_ka** (list of float) - maximum thermal current in kilo Ampere
2036

2037
    OPTIONAL:
2038
        **name** (string, None) - A custom name for this line
2039

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

2043
        **in_service** (boolean, True) - True for in_service or False for out of service
2044

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

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

2050
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
2051

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

2054
        **parallel** (integer, 1) - number of parallel line systems
2055

2056
        **geodata**
2057
        (array, default None, shape= (,2L)) -
2058
        The linegeodata of the line. The first row should be the coordinates
2059
        of bus a and the last should be the coordinates of bus b. The points
2060
        in the middle represent the bending points of the line
2061

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

2064
    OUTPUT:
2065
        **index** (int) - The unique ID of the created line
2066

2067
    EXAMPLE:
2068
        create_line_from_parameters(net, "line1", from_bus = 0, to_bus = 1, lenght_km=0.1,
2069
        r_ohm_per_km = .01, x_ohm_per_km = 0.05, c_nf_per_km = 10,
2070
        max_i_ka = 0.4)
2071

2072
    """
2073 1
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
2074

2075 1
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
2076

2077 1
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km, "type": type,
2078
               "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
2079
               "c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "g_us_per_km": g_us_per_km,
2080
               "name": name, "df": df, "parallel": parallel, "in_service": in_service}
2081

2082 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2083 1
    _add_series_to_entries(entries, index, "r0_ohm_per_km", r0_ohm_per_km)
2084 1
    _add_series_to_entries(entries, index, "x0_ohm_per_km", x0_ohm_per_km)
2085 1
    _add_series_to_entries(entries, index, "c0_nf_per_km", c0_nf_per_km)
2086 1
    _add_series_to_entries(entries, index, "g0_us_per_km", g0_us_per_km)
2087 1
    _add_series_to_entries(entries, index, "temperature_degree_celsius", temperature_degree_celsius)
2088 1
    _add_series_to_entries(entries, index, "alpha", alpha)
2089

2090 1
    _set_multiple_entries(net, "line", index, **entries, **kwargs)
2091

2092 1
    if geodata is not None:
2093 1
        _add_multiple_branch_geodata(net, "line", geodata, index)
2094

2095 1
    return index
2096

2097

2098 1
def create_transformer(net, hv_bus, lv_bus, std_type, name=None, tap_pos=nan, in_service=True,
2099
                       index=None, max_loading_percent=nan, parallel=1, df=1.):
2100
    """
2101
    Creates a two-winding transformer in table net["trafo"].
2102
    The trafo parameters are defined through the standard type library.
2103

2104
    INPUT:
2105
        **net** - The net within this transformer should be created
2106

2107
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2108
            connected to
2109

2110
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2111
            connected to
2112

2113
        **std_type** -  The used standard type from the standard type library
2114

2115
    **Zero sequence parameters** (Added through std_type For Three phase load flow) :
2116

2117
        **vk0_percent** - zero sequence relative short-circuit voltage
2118

2119
        **vkr0_percent** - real part of zero sequence relative short-circuit voltage
2120

2121
        **mag0_percent** - ratio between magnetizing and short circuit impedance (zero sequence)
2122

2123
                            z_mag0 / z0
2124

2125
        **mag0_rx**  - zero sequence magnetizing r/x  ratio
2126

2127
        **si0_hv_partial** - zero sequence short circuit impedance  distribution in hv side
2128

2129
    OPTIONAL:
2130
        **name** (string, None) - A custom name for this transformer
2131

2132
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2133
            position (tap_neutral)
2134

2135
        **in_service** (boolean, True) - True for in_service or False for out of service
2136

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

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

2142
        **parallel** (integer) - number of parallel transformers
2143

2144
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2145
            current of transformer (from 0 to 1)
2146

2147
    OUTPUT:
2148
        **index** (int) - The unique ID of the created transformer
2149

2150
    EXAMPLE:
2151
        create_transformer(net, hv_bus = 0, lv_bus = 1, name = "trafo1", std_type = \
2152
            "0.4 MVA 10/0.4 kV")
2153
    """
2154

2155
    # Check if bus exist to attach the trafo to
2156 1
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2157

2158 1
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2159

2160 1
    if df <= 0:
2161 0
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2162

2163 1
    v = {
2164
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
2165
        "in_service": bool(in_service), "std_type": std_type
2166
    }
2167 1
    ti = load_std_type(net, std_type, "trafo")
2168

2169 1
    v.update({
2170
        "sn_mva": ti["sn_mva"],
2171
        "vn_hv_kv": ti["vn_hv_kv"],
2172
        "vn_lv_kv": ti["vn_lv_kv"],
2173
        "vk_percent": ti["vk_percent"],
2174
        "vkr_percent": ti["vkr_percent"],
2175
        "pfe_kw": ti["pfe_kw"],
2176
        "i0_percent": ti["i0_percent"],
2177
        "parallel": parallel,
2178
        "df": df,
2179
        "shift_degree": ti["shift_degree"] if "shift_degree" in ti else 0,
2180
        "tap_phase_shifter": ti["tap_phase_shifter"] if "tap_phase_shifter" in ti
2181
                                                        and pd.notnull(
2182
            ti["tap_phase_shifter"]) else False
2183
    })
2184 1
    for tp in ("tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent",
2185
               "tap_step_degree"):
2186 1
        if tp in ti:
2187 1
            v[tp] = ti[tp]
2188 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2189 1
        v["tap_pos"] = v["tap_neutral"]
2190
    else:
2191 1
        v["tap_pos"] = tap_pos
2192 1
        if isinstance(tap_pos, float):
2193 1
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2194

2195 1
    _set_entries(net, "trafo", index, **v)
2196

2197 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2198

2199
    # tap_phase_shifter default False
2200 1
    net.trafo.tap_phase_shifter.fillna(False, inplace=True)
2201

2202 1
    return index
2203

2204

2205 1
def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn_lv_kv, vkr_percent,
2206
                                       vk_percent, pfe_kw, i0_percent, shift_degree=0,
2207
                                       tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
2208
                                       tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2209
                                       tap_phase_shifter=False, in_service=True, name=None,
2210
                                       vector_group=None, index=None, max_loading_percent=nan,
2211
                                       parallel=1, df=1., vk0_percent=nan, vkr0_percent=nan,
2212
                                       mag0_percent=nan, mag0_rx=nan, si0_hv_partial=nan, **kwargs):
2213
    """
2214
    Creates a two-winding transformer in table net["trafo"].
2215
    The trafo parameters are defined through the standard type library.
2216

2217
    INPUT:
2218
        **net** - The net within this transformer should be created
2219

2220
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2221
            connected to
2222

2223
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2224
            connected to
2225

2226
        **sn_mva** (float) - rated apparent power
2227

2228
        **vn_hv_kv** (float) - rated voltage on high voltage side
2229

2230
        **vn_lv_kv** (float) - rated voltage on low voltage side
2231

2232
        **vkr_percent** (float) - real part of relative short-circuit voltage
2233

2234
        **vk_percent** (float) - relative short-circuit voltage
2235

2236
        **pfe_kw** (float)  - iron losses in kW
2237

2238
        **i0_percent** (float) - open loop losses in percent of rated current
2239

2240
        **vector_group** (String) - Vector group of the transformer
2241

2242
            HV side is Uppercase letters
2243
            and LV side is lower case
2244

2245
        **vk0_percent** (float) - zero sequence relative short-circuit voltage
2246

2247
        **vkr0_percent** - real part of zero sequence relative short-circuit voltage
2248

2249
        **mag0_percent** - zero sequence magnetizing impedance/ vk0
2250

2251
        **mag0_rx**  - zero sequence magnitizing R/X ratio
2252

2253
        **si0_hv_partial** - Distribution of zero sequence leakage impedances for HV side
2254

2255

2256
    OPTIONAL:
2257

2258
        **in_service** (boolean) - True for in_service or False for out of service
2259

2260
        **parallel** (integer) - number of parallel transformers
2261

2262
        **name** (string) - A custom name for this transformer
2263

2264
        **shift_degree** (float) - Angle shift over the transformer*
2265

2266
        **tap_side** (string) - position of tap changer ("hv", "lv")
2267

2268
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2269
            position (tap_neutral)
2270

2271
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the \
2272
            ratio of the rated voltages
2273

2274
        **tap_max** (int, nan) - maximal allowed tap position
2275

2276
        **tap_min** (int, nan):  minimal allowed tap position
2277

2278
        **tap_step_percent** (float) - tap step size for voltage magnitude in percent
2279

2280
        **tap_step_degree** (float) - tap step size for voltage angle in degree*
2281

2282
        **tap_phase_shifter** (bool) - whether the transformer is an ideal phase shifter*
2283

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

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

2289
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2290
            current of transformer (from 0 to 1)
2291

2292
        ** only considered in loadflow if calculate_voltage_angles = True
2293

2294
    OUTPUT:
2295
        **index** (int) - The unique ID of the created transformer
2296

2297
    EXAMPLE:
2298
        create_transformer_from_parameters(net, hv_bus=0, lv_bus=1, name="trafo1", sn_mva=40, \
2299
            vn_hv_kv=110, vn_lv_kv=10, vk_percent=10, vkr_percent=0.3, pfe_kw=30, \
2300
            i0_percent=0.1, shift_degree=30)
2301
    """
2302

2303
    # Check if bus exist to attach the trafo to
2304 1
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2305

2306 1
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2307

2308 1
    if df <= 0:
2309 0
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2310

2311 1
    if tap_pos is nan:
2312 1
        tap_pos = tap_neutral
2313
        # store dtypes
2314

2315 1
    v = {
2316
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
2317
        "in_service": bool(in_service), "std_type": None, "sn_mva": sn_mva, "vn_hv_kv": vn_hv_kv,
2318
        "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent, "vkr_percent": vkr_percent,
2319
        "pfe_kw": pfe_kw, "i0_percent": i0_percent, "tap_neutral": tap_neutral,
2320
        "tap_max": tap_max, "tap_min": tap_min, "shift_degree": shift_degree,
2321
        "tap_side": tap_side, "tap_step_percent": tap_step_percent,
2322
        "tap_step_degree": tap_step_degree,
2323
        "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df
2324
    }
2325

2326 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2327 1
        v["tap_pos"] = v["tap_neutral"]
2328
    else:
2329 1
        v["tap_pos"] = tap_pos
2330 1
        if type(tap_pos) == float:
2331 1
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2332

2333 1
    _set_entries(net, "trafo", index, **v, **kwargs)
2334

2335 1
    if not (isnan(vk0_percent) and isnan(vkr0_percent) and isnan(mag0_percent)
2336
            and isnan(mag0_rx) and isnan(si0_hv_partial) and vector_group is None):
2337 1
        _create_column_and_set_value(net, index, vk0_percent, "vk0_percent", "trafo")
2338 1
        _create_column_and_set_value(net, index, vkr0_percent, "vkr0_percent", "trafo")
2339 1
        _create_column_and_set_value(net, index, mag0_percent, "mag0_percent", "trafo")
2340 1
        _create_column_and_set_value(net, index, mag0_rx, "mag0_rx", "trafo")
2341 1
        _create_column_and_set_value(net, index, si0_hv_partial, "si0_hv_partial", "trafo")
2342 1
        _create_column_and_set_value(net, index, vector_group, "vector_group", "trafo", dtyp=str,
2343
                                     default_val=None)
2344 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2345

2346 1
    return index
2347

2348

2349 1
def create_transformers_from_parameters(net, hv_buses, lv_buses, sn_mva, vn_hv_kv, vn_lv_kv,
2350
                                        vkr_percent, vk_percent, pfe_kw, i0_percent, shift_degree=0,
2351
                                        tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
2352
                                        tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2353
                                        tap_phase_shifter=False, in_service=True, name=None,
2354
                                        vector_group=None, index=None, max_loading_percent=None,
2355
                                        parallel=1, df=1., vk0_percent=None, vkr0_percent=None,
2356
                                        mag0_percent=None, mag0_rx=None, si0_hv_partial=None,
2357
                                        **kwargs):
2358
    """
2359
    Creates several two-winding transformers in table net["trafo"].
2360
    The trafo parameters are defined through the standard type library.
2361

2362
    INPUT:
2363
        **net** - The net within this transformer should be created
2364

2365
        **hv_bus** (list of int) - The bus on the high-voltage side on which the transformer will \
2366
            be connected to
2367

2368
        **lv_bus** (list of int) - The bus on the low-voltage side on which the transformer will \
2369
            be connected to
2370

2371
        **sn_mva** (list of float) - rated apparent power
2372

2373
        **vn_hv_kv** (list of float) - rated voltage on high voltage side
2374

2375
        **vn_lv_kv** (list of float) - rated voltage on low voltage side
2376

2377
        **vkr_percent** (list of float) - real part of relative short-circuit voltage
2378

2379
        **vk_percent** (list of float) - relative short-circuit voltage
2380

2381
        **pfe_kw** (list of float)  - iron losses in kW
2382

2383
        **i0_percent** (list of float) - open loop losses in percent of rated current
2384

2385
        **vector_group** (list of String) - Vector group of the transformer
2386

2387
            HV side is Uppercase letters
2388
            and LV side is lower case
2389

2390
        **vk0_percent** (list of float) - zero sequence relative short-circuit voltage
2391

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

2394
        **mag0_percent** - (list of float)  zero sequence magnetizing impedance/ vk0
2395

2396
        **mag0_rx**  - (list of float)  zero sequence magnitizing R/X ratio
2397

2398
        **si0_hv_partial** - (list of float)  Distribution of zero sequence leakage impedances for \
2399
            HV side
2400

2401

2402
    OPTIONAL:
2403

2404
        **in_service** (boolean) - True for in_service or False for out of service
2405

2406
        **parallel** (integer) - number of parallel transformers
2407

2408
        **name** (string) - A custom name for this transformer
2409

2410
        **shift_degree** (float) - Angle shift over the transformer*
2411

2412
        **tap_side** (string) - position of tap changer ("hv", "lv")
2413

2414
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2415
            position (tap_neutral)
2416

2417
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the ratio\
2418
            of the rated voltages
2419

2420
        **tap_max** (int, nan) - maximal allowed tap position
2421

2422
        **tap_min** (int, nan):  minimal allowed tap position
2423

2424
        **tap_step_percent** (float) - tap step size for voltage magnitude in percent
2425

2426
        **tap_step_degree** (float) - tap step size for voltage angle in degree*
2427

2428
        **tap_phase_shifter** (bool) - whether the transformer is an ideal phase shifter*
2429

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

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

2435
        **df** (float) - derating factor: maximal current of transformer in relation to nominal \
2436
            current of transformer (from 0 to 1)
2437

2438
        ** only considered in loadflow if calculate_voltage_angles = True
2439

2440
    OUTPUT:
2441
        **index** (int) - The unique ID of the created transformer
2442

2443
    EXAMPLE:
2444
        create_transformer_from_parameters(net, hv_bus=0, lv_bus=1, name="trafo1", sn_mva=40, \
2445
            vn_hv_kv=110, vn_lv_kv=10, vk_percent=10, vkr_percent=0.3, pfe_kw=30, \
2446
            i0_percent=0.1, shift_degree=30)
2447
    """
2448 1
    _check_multiple_branch_elements(net, hv_buses, lv_buses, "Transformers")
2449

2450 1
    index = _get_multiple_index_with_check(net, "trafo", index, len(hv_buses))
2451

2452 1
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2453 1
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2454 1
    entries = {"name": name, "hv_bus": hv_buses, "lv_bus": lv_buses,
2455
               "in_service": array(in_service).astype(bool_), "std_type": None, "sn_mva": sn_mva,
2456
               "vn_hv_kv": vn_hv_kv, "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent,
2457
               "vkr_percent": vkr_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2458
               "tap_neutral": tp_neutral, "tap_max": tap_max, "tap_min": tap_min,
2459
               "shift_degree": shift_degree, "tap_pos": tp_pos, "tap_side": tap_side,
2460
               "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
2461
               "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df}
2462

2463 1
    _add_series_to_entries(entries, index, "vk0_percent", vk0_percent)
2464 1
    _add_series_to_entries(entries, index, "vkr0_percent", vkr0_percent)
2465 1
    _add_series_to_entries(entries, index, "mag0_percent", mag0_percent)
2466 1
    _add_series_to_entries(entries, index, "mag0_rx", mag0_rx)
2467 1
    _add_series_to_entries(entries, index, "si0_hv_partial", si0_hv_partial)
2468 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2469 1
    _add_series_to_entries(entries, index, "vector_group", vector_group, dtyp=str)
2470

2471 1
    _set_multiple_entries(net, "trafo", index, **entries, **kwargs)
2472

2473 1
    return index
2474

2475

2476 1
def create_transformer3w(net, hv_bus, mv_bus, lv_bus, std_type, name=None, tap_pos=nan,
2477
                         in_service=True, index=None, max_loading_percent=nan,
2478
                         tap_at_star_point=False):
2479
    """
2480
    Creates a three-winding transformer in table net["trafo3w"].
2481
    The trafo parameters are defined through the standard type library.
2482

2483
    INPUT:
2484
        **net** - The net within this transformer should be created
2485

2486
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2487
            connected to
2488

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

2491
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2492
            connected to
2493

2494
        **std_type** -  The used standard type from the standard type library
2495

2496
    OPTIONAL:
2497
        **name** (string) - A custom name for this transformer
2498

2499
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2500
            position (tap_neutral)
2501

2502
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2503
            3W-transformer or at the bus
2504

2505
        **in_service** (boolean) - True for in_service or False for out of service
2506

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

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

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

2514
    OUTPUT:
2515
        **index** (int) - The unique ID of the created transformer
2516

2517
    EXAMPLE:
2518
        create_transformer3w(net, hv_bus = 0, mv_bus = 1, lv_bus = 2, name = "trafo1", std_type = \
2519
            "63/25/38 MVA 110/20/10 kV")
2520
    """
2521

2522
    # Check if bus exist to attach the trafo to
2523 1
    for b in [hv_bus, mv_bus, lv_bus]:
2524 1
        if b not in net["bus"].index.values:
2525 1
            raise UserWarning("Trafo tries to attach to bus %s" % b)
2526

2527 1
    v = {
2528
        "name": name, "hv_bus": hv_bus, "mv_bus": mv_bus, "lv_bus": lv_bus,
2529
        "in_service": bool(in_service), "std_type": std_type
2530
    }
2531 1
    ti = load_std_type(net, std_type, "trafo3w")
2532

2533 1
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
2534

2535 1
    v.update({
2536
        "sn_hv_mva": ti["sn_hv_mva"],
2537
        "sn_mv_mva": ti["sn_mv_mva"],
2538
        "sn_lv_mva": ti["sn_lv_mva"],
2539
        "vn_hv_kv": ti["vn_hv_kv"],
2540
        "vn_mv_kv": ti["vn_mv_kv"],
2541
        "vn_lv_kv": ti["vn_lv_kv"],
2542
        "vk_hv_percent": ti["vk_hv_percent"],
2543
        "vk_mv_percent": ti["vk_mv_percent"],
2544
        "vk_lv_percent": ti["vk_lv_percent"],
2545
        "vkr_hv_percent": ti["vkr_hv_percent"],
2546
        "vkr_mv_percent": ti["vkr_mv_percent"],
2547
        "vkr_lv_percent": ti["vkr_lv_percent"],
2548
        "pfe_kw": ti["pfe_kw"],
2549
        "i0_percent": ti["i0_percent"],
2550
        "shift_mv_degree": ti["shift_mv_degree"] if "shift_mv_degree" in ti else 0,
2551
        "shift_lv_degree": ti["shift_lv_degree"] if "shift_lv_degree" in ti else 0,
2552
        "tap_at_star_point": tap_at_star_point
2553
    })
2554 1
    for tp in (
2555
            "tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent", "tap_step_degree"):
2556 1
        if tp in ti:
2557 1
            v.update({tp: ti[tp]})
2558

2559 1
    if ("tap_neutral" in v) and (tap_pos is nan):
2560 1
        v["tap_pos"] = v["tap_neutral"]
2561
    else:
2562 0
        v["tap_pos"] = tap_pos
2563 0
        if type(tap_pos) == float:
2564 0
            net.trafo3w.tap_pos = net.trafo3w.tap_pos.astype(float)
2565

2566 1
    dd = pd.DataFrame(v, index=[index])
2567 1
    if version.parse(pd.__version__) < version.parse("0.21"):
2568 0
        net["trafo3w"] = net["trafo3w"].append(dd).reindex_axis(net["trafo3w"].columns, axis=1)
2569 1
    elif version.parse(pd.__version__) < version.parse("0.23"):
2570 0
        net["trafo3w"] = net["trafo3w"].append(dd).reindex(net["trafo3w"].columns, axis=1)
2571
    else:
2572 1
        net["trafo3w"] = net["trafo3w"].append(dd, sort=True).reindex(net["trafo3w"].columns,
2573
                                                                      axis=1)
2574

2575 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
2576

2577 1
    return index
2578

2579

2580 1
def create_transformer3w_from_parameters(net, hv_bus, mv_bus, lv_bus, vn_hv_kv, vn_mv_kv, vn_lv_kv,
2581
                                         sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
2582
                                         vk_mv_percent, vk_lv_percent, vkr_hv_percent,
2583
                                         vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
2584
                                         shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
2585
                                         tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2586
                                         tap_neutral=nan, tap_max=nan,
2587
                                         tap_min=nan, name=None, in_service=True, index=None,
2588
                                         max_loading_percent=nan, tap_at_star_point=False):
2589
    """
2590
    Adds a three-winding transformer in table net["trafo3w"].
2591

2592
    Input:
2593
        **net** (pandapowerNet) - The net within this transformer should be created
2594

2595
        **hv_bus** (int) - The bus on the high-voltage side on which the transformer will be \
2596
            connected to
2597

2598
        **mv_bus** (int) - The bus on the middle-voltage side on which the transformer will be \
2599
            connected to
2600

2601
        **lv_bus** (int) - The bus on the low-voltage side on which the transformer will be \
2602
            connected to
2603

2604
        **vn_hv_kv** (float) rated voltage on high voltage side
2605

2606
        **vn_mv_kv** (float) rated voltage on medium voltage side
2607

2608
        **vn_lv_kv** (float) rated voltage on low voltage side
2609

2610
        **sn_hv_mva** (float) - rated apparent power on high voltage side
2611

2612
        **sn_mv_mva** (float) - rated apparent power on medium voltage side
2613

2614
        **sn_lv_mva** (float) - rated apparent power on low voltage side
2615

2616
        **vk_hv_percent** (float) - short circuit voltage from high to medium voltage
2617

2618
        **vk_mv_percent** (float) - short circuit voltage from medium to low voltage
2619

2620
        **vk_lv_percent** (float) - short circuit voltage from high to low voltage
2621

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

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

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

2628
        **pfe_kw** (float) - iron losses in kW
2629

2630
        **i0_percent** (float) - open loop losses
2631

2632
    OPTIONAL:
2633
        **shift_mv_degree** (float, 0) - angle shift to medium voltage side*
2634

2635
        **shift_lv_degree** (float, 0) - angle shift to low voltage side*
2636

2637
        **tap_step_percent** (float) - Tap step in percent
2638

2639
        **tap_step_degree** (float) - Tap phase shift angle in degrees
2640

2641
        **tap_side** (string, None) - "hv", "mv", "lv"
2642

2643
        **tap_neutral** (int, nan) - default tap position
2644

2645
        **tap_min** (int, nan) - Minimum tap position
2646

2647
        **tap_max** (int, nan) - Maximum tap position
2648

2649
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the \
2650
            medium position (tap_neutral)
2651

2652
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2653
            3W-transformer or at the bus
2654

2655
        **name** (string, None) - Name of the 3-winding transformer
2656

2657
        **in_service** (boolean, True) - True for in_service or False for out of service
2658

2659
        ** only considered in loadflow if calculate_voltage_angles = True
2660
        **The model currently only supports one tap-changer per 3W Transformer.
2661

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

2664
    OUTPUT:
2665
        **trafo_id** - The unique trafo_id of the created 3W transformer
2666

2667
    Example:
2668
        create_transformer3w_from_parameters(net, hv_bus=0, mv_bus=1, lv_bus=2, name="trafo1",
2669
        sn_hv_mva=40, sn_mv_mva=20, sn_lv_mva=20, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10,
2670
        vk_hv_percent=10,vk_mv_percent=11, vk_lv_percent=12, vkr_hv_percent=0.3,
2671
        vkr_mv_percent=0.31, vkr_lv_percent=0.32, pfe_kw=30, i0_percent=0.1, shift_mv_degree=30,
2672
        shift_lv_degree=30)
2673

2674
    """
2675

2676
    # Check if bus exist to attach the trafo to
2677 1
    for b in [hv_bus, mv_bus, lv_bus]:
2678 1
        if b not in net["bus"].index.values:
2679 1
            raise UserWarning("Trafo tries to attach to non-existent bus %s" % b)
2680

2681 1
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
2682

2683 1
    if tap_pos is nan:
2684 1
        tap_pos = tap_neutral
2685

2686 1
    columns = ["lv_bus", "mv_bus", "hv_bus", "vn_hv_kv", "vn_mv_kv", "vn_lv_kv", "sn_hv_mva",
2687
               "sn_mv_mva", "sn_lv_mva", "vk_hv_percent", "vk_mv_percent", "vk_lv_percent",
2688
               "vkr_hv_percent", "vkr_mv_percent", "vkr_lv_percent", "pfe_kw", "i0_percent",
2689
               "shift_mv_degree", "shift_lv_degree", "tap_side", "tap_step_percent",
2690
               "tap_step_degree", "tap_pos", "tap_neutral", "tap_max", "tap_min", "in_service",
2691
               "name", "std_type", "tap_at_star_point"]
2692 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,
2693
              vk_hv_percent, vk_mv_percent, vk_lv_percent, vkr_hv_percent, vkr_mv_percent,
2694
              vkr_lv_percent, pfe_kw, i0_percent, shift_mv_degree, shift_lv_degree, tap_side,
2695
              tap_step_percent, tap_step_degree, tap_pos, tap_neutral, tap_max, tap_min,
2696
              bool(in_service), name, None, tap_at_star_point]
2697

2698 1
    _set_entries(net, "trafo3w", index, **dict(zip(columns, values)))
2699

2700 1
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
2701

2702 1
    return index
2703

2704

2705 1
def create_transformers3w_from_parameters(net, hv_buses, mv_buses, lv_buses, vn_hv_kv, vn_mv_kv,
2706
                                          vn_lv_kv, sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
2707
                                          vk_mv_percent, vk_lv_percent, vkr_hv_percent,
2708
                                          vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
2709
                                          shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
2710
                                          tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2711
                                          tap_neutral=nan, tap_max=nan, tap_min=nan, name=None,
2712
                                          in_service=True, index=None, max_loading_percent=None,
2713
                                          tap_at_star_point=False, **kwargs):
2714
    """
2715
    Adds a three-winding transformer in table net["trafo3w"].
2716

2717
    Input:
2718
        **net** (pandapowerNet) - The net within this transformer should be created
2719

2720
        **hv_bus** (list) - The bus on the high-voltage side on which the transformer will be \
2721
            connected to
2722

2723
        **mv_bus** (list) - The bus on the middle-voltage side on which the transformer will be \
2724
            connected to
2725

2726
        **lv_bus** (list) - The bus on the low-voltage side on which the transformer will be \
2727
            connected to
2728

2729
        **vn_hv_kv** (float or list) rated voltage on high voltage side
2730

2731
        **vn_mv_kv** (float or list) rated voltage on medium voltage side
2732

2733
        **vn_lv_kv** (float or list) rated voltage on low voltage side
2734

2735
        **sn_hv_mva** (float or list) - rated apparent power on high voltage side
2736

2737
        **sn_mv_mva** (float or list) - rated apparent power on medium voltage side
2738

2739
        **sn_lv_mva** (float or list) - rated apparent power on low voltage side
2740

2741
        **vk_hv_percent** (float or list) - short circuit voltage from high to medium voltage
2742

2743
        **vk_mv_percent** (float or list) - short circuit voltage from medium to low voltage
2744

2745
        **vk_lv_percent** (float or list) - short circuit voltage from high to low voltage
2746

2747
        **vkr_hv_percent** (float or list) - real part of short circuit voltage from high to medium\
2748
            voltage
2749

2750
        **vkr_mv_percent** (float or list) - real part of short circuit voltage from medium to low\
2751
            voltage
2752

2753
        **vkr_lv_percent** (float or list) - real part of short circuit voltage from high to low\
2754
            voltage
2755

2756
        **pfe_kw** (float or list) - iron losses in kW
2757

2758
        **i0_percent** (float or list) - open loop losses
2759

2760
    OPTIONAL:
2761
        **shift_mv_degree** (float or list, 0) - angle shift to medium voltage side*
2762

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

2765
        **tap_step_percent** (float or list) - Tap step in percent
2766

2767
        **tap_step_degree** (float or list) - Tap phase shift angle in degrees
2768

2769
        **tap_side** (string, None) - "hv", "mv", "lv"
2770

2771
        **tap_neutral** (int, nan) - default tap position
2772

2773
        **tap_min** (int, nan) - Minimum tap position
2774

2775
        **tap_max** (int, nan) - Maximum tap position
2776

2777
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the \
2778
            medium position (tap_neutral)
2779

2780
        **tap_at_star_point** (boolean) - Whether tap changer is located at the star point of the \
2781
            3W-transformer or at the bus
2782

2783
        **name** (string, None) - Name of the 3-winding transformer
2784

2785
        **in_service** (boolean, True) - True for in_service or False for out of service
2786

2787
        ** only considered in loadflow if calculate_voltage_angles = True
2788
        **The model currently only supports one tap-changer per 3W Transformer.
2789

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

2792
    OUTPUT:
2793
        **trafo_id** - List of trafo_ids of the created 3W transformers
2794

2795
    Example:
2796
        create_transformer3w_from_parameters(net, hv_bus=0, mv_bus=1, lv_bus=2, name="trafo1",
2797
        sn_hv_mva=40, sn_mv_mva=20, sn_lv_mva=20, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10,
2798
        vk_hv_percent=10,vk_mv_percent=11, vk_lv_percent=12, vkr_hv_percent=0.3,
2799
        vkr_mv_percent=0.31, vkr_lv_percent=0.32, pfe_kw=30, i0_percent=0.1, shift_mv_degree=30,
2800
        shift_lv_degree=30)
2801

2802
    """
2803 1
    index = _get_multiple_index_with_check(net, "trafo3w", index, len(hv_buses),
2804
                                           name="Three winding transformers")
2805

2806 1
    if not np_all(isin(hv_buses, net.bus.index)):
2807 1
        bus_not_exist = set(hv_buses) - set(net.bus.index)
2808 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2809 1
    if not np_all(isin(mv_buses, net.bus.index)):
2810 1
        bus_not_exist = set(mv_buses) - set(net.bus.index)
2811 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2812 1
    if not np_all(isin(lv_buses, net.bus.index)):
2813 1
        bus_not_exist = set(lv_buses) - set(net.bus.index)
2814 1
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2815

2816 1
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2817 1
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2818 1
    entries = {"lv_bus": lv_buses, "mv_bus": mv_buses, "hv_bus": hv_buses, "vn_hv_kv": vn_hv_kv,
2819
               "vn_mv_kv": vn_mv_kv, "vn_lv_kv": vn_lv_kv, "sn_hv_mva": sn_hv_mva,
2820
               "sn_mv_mva": sn_mv_mva, "sn_lv_mva": sn_lv_mva, "vk_hv_percent": vk_hv_percent,
2821
               "vk_mv_percent": vk_mv_percent, "vk_lv_percent": vk_lv_percent,
2822
               "vkr_hv_percent": vkr_hv_percent, "vkr_mv_percent": vkr_mv_percent,
2823
               "vkr_lv_percent": vkr_lv_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2824
               "shift_mv_degree": shift_mv_degree, "shift_lv_degree": shift_lv_degree,
2825
               "tap_side": tap_side, "tap_step_percent": tap_step_percent,
2826
               "tap_step_degree": tap_step_degree, "tap_pos": tp_pos, "tap_neutral": tp_neutral,
2827
               "tap_max": tap_max, "tap_min": tap_min,
2828
               "in_service": array(in_service).astype(bool_), "name": name,
2829
               "tap_at_star_point": array(tap_at_star_point).astype(bool_), "std_type": None}
2830

2831 1
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2832

2833 1
    _set_multiple_entries(net, "trafo3w", index, **entries, **kwargs)
2834

2835 1
    return index
2836

2837

2838 1
def create_switch(net, bus, element, et, closed=True, type=None, name=None, index=None, z_ohm=0):
2839
    """
2840
    Adds a switch in the net["switch"] table.
2841

2842
    Switches can be either between two buses (bus-bus switch) or at the end of a line or transformer
2843
    element (bus-element switch).
2844

2845
    Two buses that are connected through a closed bus-bus switches are fused in the power flow if
2846
    the switch is closed or separated if the switch is open.
2847

2848
    An element that is connected to a bus through a bus-element switch is connected to the bus
2849
    if the switch is closed or disconnected if the switch is open.
2850

2851
    INPUT:
2852
        **net** (pandapowerNet) - The net within which this switch should be created
2853

2854
        **bus** - The bus that the switch is connected to
2855

2856
        **element** - index of the element: bus id if et == "b", line id if et == "l", trafo id if \
2857
            et == "t"
2858

2859
        **et** - (string) element type: "l" = switch between bus and line, "t" = switch between
2860
            bus and transformer, "t3" = switch between bus and transformer3w, "b" = switch between
2861
            two buses
2862

2863
    OPTIONAL:
2864
        **closed** (boolean, True) - switch position: False = open, True = closed
2865

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

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

2873
        **name** (string, default None) - The name for this switch
2874

2875
    OUTPUT:
2876
        **sid** - The unique switch_id of the created switch
2877

2878
    EXAMPLE:
2879
        create_switch(net, bus =  0, element = 1, et = 'b', type ="LS", z_ohm = 0.1)
2880

2881
        create_switch(net, bus = 0, element = 1, et = 'l')
2882

2883
    """
2884 1
    _check_node_element(net, bus)
2885 1
    if et == "l":
2886 1
        elm_tab = 'line'
2887 1
        if element not in net[elm_tab].index:
2888 0
            raise UserWarning("Unknown line index")
2889 1
        if (not net[elm_tab]["from_bus"].loc[element] == bus and
2890
                not net[elm_tab]["to_bus"].loc[element] == bus):
2891 0
            raise UserWarning("Line %s not connected to bus %s" % (element, bus))
2892 1
    elif et == "t":
2893 1
        elm_tab = 'trafo'
2894 1
        if element not in net[elm_tab].index:
2895 0
            raise UserWarning("Unknown bus index")
2896 1
        if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2897
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2898 0
            raise UserWarning("Trafo %s not connected to bus %s" % (element, bus))
2899 1
    elif et == "t3":
2900 1
        elm_tab = 'trafo3w'
2901 1
        if element not in net[elm_tab].index:
2902 0
            raise UserWarning("Unknown trafo3w index")
2903 1
        if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2904
                not net[elm_tab]["mv_bus"].loc[element] == bus and
2905
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2906 0
            raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
2907 1
    elif et == "b":
2908 1
        _check_node_element(net, element)
2909
    else:
2910 0
        raise UserWarning("Unknown element type")
2911

2912 1
    index = _get_index_with_check(net, "switch", index)
2913

2914 1
    entries = dict(zip(["bus", "element", "et", "closed", "type", "name", "z_ohm"],
2915
                       [bus, element, et, closed, type, name, z_ohm]))
2916 1
    _set_entries(net, "switch", index, **entries)
2917

2918 1
    return index
2919

2920

2921 1
def create_switches(net, buses, elements, et, closed=True, type=None, name=None, index=None,
2922
                    z_ohm=0, **kwargs):
2923
    """
2924
    Adds a switch in the net["switch"] table.
2925

2926
    Switches can be either between two buses (bus-bus switch) or at the end of a line or transformer
2927
    element (bus-element switch).
2928

2929
    Two buses that are connected through a closed bus-bus switches are fused in the power flow if
2930
    the switch is closed or separated if the switch is open.
2931

2932
    An element that is connected to a bus through a bus-element switch is connected to the bus
2933
    if the switch is closed or disconnected if the switch is open.
2934

2935
    INPUT:
2936
        **net** (pandapowerNet) - The net within which this switch should be created
2937

2938
        **buses** (list)- The bus that the switch is connected to
2939

2940
        **element** (list)- index of the element: bus id if et == "b", line id if et == "l", \
2941
            trafo id if et == "t"
2942

2943
        **et** - (list) element type: "l" = switch between bus and line, "t" = switch between
2944
            bus and transformer, "t3" = switch between bus and transformer3w, "b" = switch between
2945
            two buses
2946

2947
    OPTIONAL:
2948
        **closed** (boolean, True) - switch position: False = open, True = closed
2949

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

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

2957
        **name** (string, default None) - The name for this switch
2958

2959
    OUTPUT:
2960
        **sid** - The unique switch_id of the created switch
2961

2962
    EXAMPLE:
2963
        create_switch(net, bus =  0, element = 1, et = 'b', type ="LS", z_ohm = 0.1)
2964

2965
        create_switch(net, bus = 0, element = 1, et = 'l')
2966

2967
    """
2968 1
    index = _get_multiple_index_with_check(net, "switch", index, len(buses), name="Switches")
2969 1
    _check_multiple_node_elements(net, buses)
2970

2971 1
    for element, elm_type, bus in zip(elements, et, buses):
2972 1
        if elm_type == "l":
2973 1
            elm_tab = 'line'
2974 1
            if element not in net[elm_tab].index:
2975 1
                raise UserWarning("Line %s does not exist" % element)
2976 1
            if (not net[elm_tab]["from_bus"].loc[element] == bus and
2977
                    not net[elm_tab]["to_bus"].loc[element] == bus):
2978 1
                raise UserWarning("Line %s not connected to bus %s" % (element, bus))
2979 1
        elif elm_type == "t":
2980 1
            elm_tab = 'trafo'
2981 1
            if element not in net[elm_tab].index:
2982 1
                raise UserWarning("Trafo %s does not exist" % element)
2983 1
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2984
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
2985 1
                raise UserWarning("Trafo %s not connected to bus %s" % (element, bus))
2986 1
        elif elm_type == "t3":
2987 1
            elm_tab = 'trafo3w'
2988 1
            if element not in net[elm_tab].index:
2989 1
                raise UserWarning("Trafo3w %s does not exist" % element)
2990 1
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
2991
                    not net[elm_tab]["mv_bus"].loc[element] == bus and
2992
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
2993 1
                raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
2994 1
        elif elm_type == "b":
2995 1
            _check_node_element(net, element)
2996
        else:
2997 0
            raise UserWarning("Unknown element type")
2998

2999 1
    entries = {"bus": buses, "element": elements, "et": et, "closed": closed, "type": type,
3000
               "name": name, "z_ohm": z_ohm}
3001

3002 1
    _set_multiple_entries(net, "switch", index, **entries, **kwargs)
3003

3004 1
    return index
3005

3006

3007 1
def create_shunt(net, bus, q_mvar, p_mw=0., vn_kv=None, step=1, max_step=1, name=None,
3008
                 in_service=True, index=None):
3009
    """
3010
    Creates a shunt element
3011

3012
    INPUT:
3013
        **net** (pandapowerNet) - The pandapower network in which the element is created
3014

3015
        **bus** - bus number of bus to whom the shunt is connected to
3016

3017
        **p_mw** - shunt active power in MW at v= 1.0 p.u.
3018

3019
        **q_mvar** - shunt susceptance in MVAr at v= 1.0 p.u.
3020

3021
    OPTIONAL:
3022
        **vn_kv** (float, None) - rated voltage of the shunt. Defaults to rated voltage of \
3023
            connected bus
3024

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

3027
        **max_step** (boolean, True) - True for in_service or False for out of service
3028

3029
        **name** (str, None) - element name
3030

3031
        **in_service** (boolean, True) - True for in_service or False for out of service
3032

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

3036
    OUTPUT:
3037
        **index** (int) - The unique ID of the created shunt
3038

3039
    EXAMPLE:
3040
        create_shunt(net, 0, 20)
3041
    """
3042 1
    _check_node_element(net, bus)
3043

3044 1
    index = _get_index_with_check(net, "shunt", index)
3045

3046 1
    if vn_kv is None:
3047 1
        vn_kv = net.bus.vn_kv.at[bus]
3048

3049 1
    entries = dict(zip(["bus", "name", "p_mw", "q_mvar", "vn_kv", "step", "max_step", "in_service"],
3050
                       [bus, name, p_mw, q_mvar, vn_kv, step, max_step, in_service]))
3051 1
    _set_entries(net, "shunt", index, **entries)
3052

3053 1
    return index
3054

3055

3056 1
def create_shunt_as_capacitor(net, bus, q_mvar, loss_factor, **kwargs):
3057
    """
3058
    Creates a shunt element representing a capacitor bank.
3059

3060
    INPUT:
3061

3062
        **net** (pandapowerNet) - The pandapower network in which the element is created
3063

3064
        **bus** - bus number of bus to whom the shunt is connected to
3065

3066
        **q_mvar** (float) - reactive power of the capacitor bank at rated voltage
3067

3068
        **loss_factor** (float) - loss factor tan(delta) of the capacitor bank
3069

3070
        **kwargs are passed to the create_shunt function
3071

3072

3073
    OUTPUT:
3074
        **index** (int) - The unique ID of the created shunt
3075
    """
3076 1
    q_mvar = -abs(q_mvar)  # q is always negative for capacitor
3077 1
    p_mw = abs(q_mvar * loss_factor)  # p is always positive for active power losses
3078 1
    return create_shunt(net, bus, q_mvar=q_mvar, p_mw=p_mw, **kwargs)
3079

3080

3081 1
def create_impedance(net, from_bus, to_bus, rft_pu, xft_pu, sn_mva, rtf_pu=None, xtf_pu=None,
3082
                     name=None, in_service=True, index=None):
3083
    """
3084
    Creates an per unit impedance element
3085

3086
    INPUT:
3087
        **net** (pandapowerNet) - The pandapower network in which the element is created
3088

3089
        **from_bus** (int) - starting bus of the impedance
3090

3091
        **to_bus** (int) - ending bus of the impedance
3092

3093
        **r_pu** (float) - real part of the impedance in per unit
3094

3095
        **x_pu** (float) - imaginary part of the impedance in per unit
3096

3097
        **sn_mva** (float) - rated power of the impedance in MVA
3098

3099
    OUTPUT:
3100

3101
        impedance id
3102
    """
3103 1
    index = _get_index_with_check(net, "impedance", index)
3104

3105 1
    _check_branch_element(net, "Impedance", index, from_bus, to_bus)
3106

3107 1
    if rtf_pu is None:
3108 1
        rtf_pu = rft_pu
3109 1
    if xtf_pu is None:
3110 1
        xtf_pu = xft_pu
3111

3112 1
    columns = ["from_bus", "to_bus", "rft_pu", "xft_pu", "rtf_pu", "xtf_pu", "name", "sn_mva",
3113
               "in_service"]
3114 1
    values = [from_bus, to_bus, rft_pu, xft_pu, rtf_pu, xtf_pu, name, sn_mva, in_service]
3115 1
    _set_entries(net, "impedance", index, **dict(zip(columns, values)))
3116

3117 1
    return index
3118

3119

3120 1
def create_series_reactor_as_impedance(net, from_bus, to_bus, r_ohm, x_ohm, sn_mva,
3121
                                       name=None, in_service=True, index=None):
3122
    """
3123
    Creates a series reactor as per-unit impedance
3124
    :param net: (pandapowerNet) - The pandapower network in which the element is created
3125
    :param from_bus: (int) - starting bus of the series reactor
3126
    :param to_bus: (int) - ending bus of the series reactor
3127
    :param r_ohm: (float) - real part of the impedance in Ohm
3128
    :param x_ohm: (float) - imaginary part of the impedance in Ohm
3129
    :param sn_mva: (float) - rated power of the series reactor in MVA
3130
    :param name:
3131
    :type name:
3132
    :param in_service:
3133
    :type in_service:
3134
    :param index:
3135
    :type index:
3136
    :return: index of the created element
3137
    """
3138 1
    if net.bus.at[from_bus, 'vn_kv'] == net.bus.at[to_bus, 'vn_kv']:
3139 1
        vn_kv = net.bus.at[from_bus, 'vn_kv']
3140
    else:
3141 0
        raise UserWarning('Unable to infer rated voltage vn_kv for series reactor %s due to '
3142
                          'different rated voltages of from_bus %d (%.3f p.u.) and '
3143
                          'to_bus %d (%.3f p.u.)' % (name, from_bus, net.bus.at[from_bus, 'vn_kv'],
3144
                                                     to_bus, net.bus.at[to_bus, 'vn_kv']))
3145

3146 1
    base_z_ohm = vn_kv ** 2 / sn_mva
3147 1
    rft_pu = r_ohm / base_z_ohm
3148 1
    xft_pu = x_ohm / base_z_ohm
3149

3150 1
    index = create_impedance(net, from_bus=from_bus, to_bus=to_bus, rft_pu=rft_pu, xft_pu=xft_pu,
3151
                             sn_mva=sn_mva, name=name, in_service=in_service, index=index)
3152 1
    return index
3153

3154

3155 1
def create_ward(net, bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name=None, in_service=True, index=None):
3156
    """
3157
    Creates a ward equivalent.
3158

3159
    A ward equivalent is a combination of an impedance load and a PQ load.
3160

3161
    INPUT:
3162
        **net** (pandapowernet) - The pandapower net within the element should be created
3163

3164
        **bus** (int) -  bus of the ward equivalent
3165

3166
        **ps_mw** (float) - active power of the PQ load
3167

3168
        **qs_mvar** (float) - reactive power of the PQ load
3169

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

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

3174
    OUTPUT:
3175
        ward id
3176
    """
3177 1
    _check_node_element(net, bus)
3178

3179 1
    index = _get_index_with_check(net, "ward", index, "ward equivalent")
3180

3181 1
    entries = dict(zip(["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "name", "in_service"],
3182
                       [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name, in_service]))
3183 1
    _set_entries(net, "ward", index, **entries)
3184

3185 1
    return index
3186

3187

3188 1
def create_xward(net, bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, in_service=True,
3189
                 name=None, index=None):
3190
    """
3191
    Creates an extended ward equivalent.
3192

3193
    A ward equivalent is a combination of an impedance load, a PQ load and as voltage source with
3194
    an internal impedance.
3195

3196
    INPUT:
3197
        **net** - The pandapower net within the impedance should be created
3198

3199
        **bus** (int) -  bus of the ward equivalent
3200

3201
        **ps_mw** (float) - active power of the PQ load
3202

3203
        **qs_mvar** (float) - reactive power of the PQ load
3204

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

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

3209
        **r_ohm** (float) - internal resistance of the voltage source
3210

3211
        **x_ohm** (float) - internal reactance of the voltage source
3212

3213
        **vm_pu** (float) - voltage magnitude at the additional PV-node
3214

3215
    OUTPUT:
3216
        xward id
3217
    """
3218 1
    _check_node_element(net, bus)
3219

3220 1
    index = _get_index_with_check(net, "xward", index, "extended ward equivalent")
3221

3222 1
    columns = ["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "r_ohm", "x_ohm", "vm_pu", "name",
3223
               "in_service"]
3224 1
    values = [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, name, in_service]
3225 1
    _set_entries(net, "xward", index, **dict(zip(columns, values)))
3226

3227 1
    return index
3228

3229

3230 1
def create_dcline(net, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu,
3231
                  index=None, name=None, max_p_mw=nan, min_q_from_mvar=nan, min_q_to_mvar=nan,
3232
                  max_q_from_mvar=nan, max_q_to_mvar=nan, in_service=True):
3233
    """
3234
    Creates a dc line.
3235

3236
    INPUT:
3237
        **from_bus** (int) - ID of the bus on one side which the line will be connected with
3238

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

3241
        **p_mw** - (float) Active power transmitted from 'from_bus' to 'to_bus'
3242

3243
        **loss_percent** - (float) Relative transmission loss in percent of active power
3244
            transmission
3245

3246
        **loss_mw** - (float) Total transmission loss in MW
3247

3248
        **vm_from_pu** - (float) Voltage setpoint at from bus
3249

3250
        **vm_to_pu** - (float) Voltage setpoint at to bus
3251

3252
    OPTIONAL:
3253
        **index** (int, None) - Force a specified ID if it is available. If None, the index one \
3254
            higher than the highest already existing index is selected.
3255

3256
        **name** (str, None) - A custom name for this dc line
3257

3258
        **in_service** (boolean) - True for in_service or False for out of service
3259

3260
        **max_p_mw** - Maximum active power flow. Only respected for OPF
3261

3262
        **min_q_from_mvar** - Minimum reactive power at from bus. Necessary for OPF
3263

3264
        **min_q_to_mvar** - Minimum reactive power at to bus. Necessary for OPF
3265

3266
        **max_q_from_mvar** - Maximum reactive power at from bus. Necessary for OPF
3267

3268
        **max_q_to_mvar ** - Maximum reactive power at to bus. Necessary for OPF
3269

3270
    OUTPUT:
3271
        **index** (int) - The unique ID of the created element
3272

3273
    EXAMPLE:
3274
        create_dcline(net, from_bus=0, to_bus=1, p_mw=1e4, loss_percent=1.2, loss_mw=25, \
3275
            vm_from_pu=1.01, vm_to_pu=1.02)
3276
    """
3277 1
    index = _get_index_with_check(net, "dcline", index)
3278

3279 1
    _check_branch_element(net, "DCLine", index, from_bus, to_bus)
3280

3281 1
    columns = ["name", "from_bus", "to_bus", "p_mw", "loss_percent", "loss_mw", "vm_from_pu",
3282
               "vm_to_pu", "max_p_mw", "min_q_from_mvar", "min_q_to_mvar", "max_q_from_mvar",
3283
               "max_q_to_mvar", "in_service"]
3284 1
    values = [name, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu, max_p_mw,
3285
              min_q_from_mvar, min_q_to_mvar, max_q_from_mvar, max_q_to_mvar, in_service]
3286 1
    _set_entries(net, "dcline", index, **dict(zip(columns, values)))
3287

3288 1
    return index
3289

3290

3291 1
def create_measurement(net, meas_type, element_type, value, std_dev, element, side=None,
3292
                       check_existing=True, index=None, name=None):
3293
    """
3294
    Creates a measurement, which is used by the estimation module. Possible types of measurements
3295
    are: v, p, q, i, va, ia
3296

3297
    INPUT:
3298
        **meas_type** (string) - Type of measurement. "v", "p", "q", "i", "va", "ia" are possible
3299

3300
        **element_type** (string) - Clarifies which element is measured. "bus", "line",
3301
        "trafo", and "trafo3w" are possible
3302

3303
        **value** (float) - Measurement value. Units are "MW" for P, "MVar" for Q, "p.u." for V,
3304
        "kA" for I. Bus power measurement is in load reference system, which is consistent to
3305
        the rest of pandapower.
3306

3307
        **std_dev** (float) - Standard deviation in the same unit as the measurement
3308

3309
        **element** (int) - Index of the measured element (either bus index, line index,\
3310
            trafo index, trafo3w index)
3311

3312
        **side** (int, string, default: None) - Only used for measured lines or transformers. Side \
3313
            defines at which end of the branch the measurement is gathered. For lines this may be \
3314
            "from", "to" to denote the side with the from_bus or to_bus. It can also the be index \
3315
            of the from_bus or to_bus. For transformers, it can be "hv", "mv" or "lv" or the \
3316
            corresponding bus index, respectively
3317

3318
    OPTIONAL:
3319
        **check_existing** (bool, default: None) - Check for and replace existing measurements for\
3320
            this bus, type and element_type. Set it to false for performance improvements which can\
3321
            cause unsafe behaviour
3322

3323
        **index** (int, default: None) - Index of the measurement in the measurement table. Should\
3324
            not exist already.
3325

3326
        **name** (str, default: None) - Name of measurement
3327

3328
    OUTPUT:
3329
        (int) Index of measurement
3330

3331
    EXAMPLES:
3332
        2 MW load measurement with 0.05 MW standard deviation on bus 0:
3333
        create_measurement(net, "p", "bus", 0, 2., 0.05.)
3334

3335
        4.5 MVar line measurement with 0.1 MVar standard deviation on the "to_bus" side of line 2
3336
        create_measurement(net, "q", "line", 2, 4.5, 0.1, "to")
3337
    """
3338 1
    if meas_type not in ("v", "p", "q", "i", "va", "ia"):
3339 0
        raise UserWarning("Invalid measurement type ({})".format(meas_type))
3340

3341 1
    if side is None and element_type in ("line", "trafo"):
3342