Showing 1 of 4 files from the diff.

@@ -5,7 +5,8 @@
Loading
5 5
6 6
7 7
import pandas as pd
8 -
from numpy import nan, isnan, arange, dtype, isin, any as np_any, zeros
8 +
from numpy import nan, isnan, arange, dtype, isin, any as np_any, zeros, array, bool_, \
9 +
    all as np_all, float64
9 10
from packaging import version
10 11
11 12
from pandapower import __version__
@@ -68,19 +69,19 @@
Loading
68 69
                 ("type", dtype(object)),
69 70
                 ("current_source", "bool")],
70 71
        "motor": [("name", dtype(object)),
71 -
                 ("bus", "i8"),
72 -
                 ("pn_mech_mw", "f8"),
73 -
                 ("loading_percent", "f8"),
74 -
                 ("cos_phi", "f8"),
75 -
                 ("cos_phi_n", "f8"),
76 -
                 ("efficiency_percent", "f8"),
77 -
                 ("efficiency_n_percent", "f8"),
78 -
                 ("lrc_pu", "f8"),
79 -
                 ("vn_kv", "f8"),
80 -
                 ("scaling", "f8"),
81 -
                 ("in_service", 'bool'),
82 -
                 ("rx", 'f8')
83 -
                 ],
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 +
                  ],
84 85
        "asymmetric_load": [("name", dtype(object)),
85 86
                            ("bus", "u4"),
86 87
                            ("p_a_mw", "f8"),
@@ -338,7 +339,7 @@
Loading
338 339
        "_empty_res_load": [("p_mw", "f8"),
339 340
                            ("q_mvar", "f8")],
340 341
        "_empty_res_motor": [("p_mw", "f8"),
341 -
                            ("q_mvar", "f8")],
342 +
                             ("q_mvar", "f8")],
342 343
        "_empty_res_sgen": [("p_mw", "f8"),
343 344
                            ("q_mvar", "f8")],
344 345
        "_empty_res_shunt": [("p_mw", "f8"),
@@ -371,35 +372,35 @@
Loading
371 372
                             ("vm_internal_pu", "f8")],
372 373
373 374
        "_empty_res_trafo_3ph": [("p_a_hv_mw", "f8"),
374 -
                            ("q_a_hv_mvar", "f8"),
375 -
                            ("p_b_hv_mw", "f8"),
376 -
                            ("q_b_hv_mvar", "f8"),
377 -
                            ("p_c_hv_mw", "f8"),
378 -
                            ("q_c_hv_mvar", "f8"),
379 -
                            ("p_a_lv_mw", "f8"),
380 -
                            ("q_a_lv_mvar", "f8"),
381 -
                            ("p_b_lv_mw", "f8"),
382 -
                            ("q_b_lv_mvar", "f8"),
383 -
                            ("p_c_lv_mw", "f8"),
384 -
                            ("q_c_lv_mvar", "f8"),
385 -
                            ("p_a_l_mw", "f8"),
386 -
                            ("q_a_l_mvar", "f8"),
387 -
                            ("p_b_l_mw", "f8"),
388 -
                            ("q_b_l_mvar", "f8"),
389 -
                            ("p_c_l_mw", "f8"),
390 -
                            ("q_c_l_mvar", "f8"),
391 -
                            ("i_a_hv_ka", "f8"),
392 -
                            ("i_a_lv_ka", "f8"),
393 -
                            ("i_b_hv_ka", "f8"),
394 -
                            ("i_b_lv_ka", "f8"),
395 -
                            ("i_c_hv_ka", "f8"),
396 -
                            ("i_c_lv_ka", "f8"),
397 -
#                            ("i_n_hv_ka", "f8"),
398 -
#                            ("i_n_lv_ka", "f8"),
399 -
                            ("loading_a_percent", "f8"),
400 -
                            ("loading_b_percent", "f8"),
401 -
                            ("loading_c_percent", "f8"),
402 -
                            ("loading_percent", "f8")],
375 +
                                 ("q_a_hv_mvar", "f8"),
376 +
                                 ("p_b_hv_mw", "f8"),
377 +
                                 ("q_b_hv_mvar", "f8"),
378 +
                                 ("p_c_hv_mw", "f8"),
379 +
                                 ("q_c_hv_mvar", "f8"),
380 +
                                 ("p_a_lv_mw", "f8"),
381 +
                                 ("q_a_lv_mvar", "f8"),
382 +
                                 ("p_b_lv_mw", "f8"),
383 +
                                 ("q_b_lv_mvar", "f8"),
384 +
                                 ("p_c_lv_mw", "f8"),
385 +
                                 ("q_c_lv_mvar", "f8"),
386 +
                                 ("p_a_l_mw", "f8"),
387 +
                                 ("q_a_l_mvar", "f8"),
388 +
                                 ("p_b_l_mw", "f8"),
389 +
                                 ("q_b_l_mvar", "f8"),
390 +
                                 ("p_c_l_mw", "f8"),
391 +
                                 ("q_c_l_mvar", "f8"),
392 +
                                 ("i_a_hv_ka", "f8"),
393 +
                                 ("i_a_lv_ka", "f8"),
394 +
                                 ("i_b_hv_ka", "f8"),
395 +
                                 ("i_b_lv_ka", "f8"),
396 +
                                 ("i_c_hv_ka", "f8"),
397 +
                                 ("i_c_lv_ka", "f8"),
398 +
                                 # ("i_n_hv_ka", "f8"),
399 +
                                 # ("i_n_lv_ka", "f8"),
400 +
                                 ("loading_a_percent", "f8"),
401 +
                                 ("loading_b_percent", "f8"),
402 +
                                 ("loading_c_percent", "f8"),
403 +
                                 ("loading_percent", "f8")],
403 404
        "_empty_res_trafo3w": [("p_hv_mw", "f8"),
404 405
                               ("q_hv_mvar", "f8"),
405 406
                               ("p_mv_mw", "f8"),
@@ -525,9 +526,8 @@
Loading
525 526
    return net
526 527
527 528
528 -
def create_bus(net, vn_kv, name=None, index=None, geodata=None, type="b",
529 -
               zone=None, in_service=True, max_vm_pu=nan,
530 -
               min_vm_pu=nan, coords=None, **kwargs):
529 +
def create_bus(net, vn_kv, name=None, index=None, geodata=None, type="b", zone=None,
530 +
               in_service=True, max_vm_pu=nan, min_vm_pu=nan, coords=None, **kwargs):
531 531
    """
532 532
    Adds one bus in table net["bus"].
533 533
@@ -557,8 +557,9 @@
Loading
557 557
558 558
        **min_vm_pu** (float, NAN) - Minimum bus voltage in p.u. - necessary for OPF
559 559
560 -
        **coords** (array, default None, shape= (,2L)) - busbar coordinates to plot the bus with multiple points.
561 -
            coords is typically a list of tuples (start and endpoint of the busbar) [(x1, y1), (x2, y2)]
560 +
        **coords** (array, default None, shape= (,2L)) - busbar coordinates to plot the bus with \
561 +
            multiple points. coords is typically a list of tuples (start and endpoint of the \
562 +
            busbar) [(x1, y1), (x2, y2)]
562 563
563 564
    OUTPUT:
564 565
        **index** (int) - The unique ID of the created element
@@ -566,20 +567,12 @@
Loading
566 567
    EXAMPLE:
567 568
        create_bus(net, name = "bus1")
568 569
    """
569 -
    if index is not None and index in net["bus"].index:
570 -
        raise UserWarning("A bus with index %s already exists" % index)
571 -
572 -
    if index is None:
573 -
        index = get_free_id(net["bus"])
570 +
    index = _get_index_with_check(net, "bus", index)
574 571
575 -
    # store dtypes
576 -
    dtypes = net.bus.dtypes
572 +
    entries = dict(zip(["name", "vn_kv", "type", "zone", "in_service"],
573 +
                       [name, vn_kv, type, zone, bool(in_service)]))
577 574
578 -
    net.bus.loc[index, ["name", "vn_kv", "type", "zone", "in_service"]] = \
579 -
        [name, vn_kv, type, zone, bool(in_service)]
580 -
581 -
    # and preserve dtypes
582 -
    _preserve_dtypes(net.bus, dtypes)
575 +
    _set_entries(net, "bus", index, True, **entries, **kwargs)
583 576
584 577
    if geodata is not None:
585 578
        if len(geodata) != 2:
@@ -635,26 +628,12 @@
Loading
635 628
    EXAMPLE:
636 629
        create_bus(net, name = "bus1")
637 630
    """
638 -
    if index is not None:
639 -
        for idx in index:
640 -
            if idx in net.bus.index:
641 -
                raise UserWarning("A bus with index %s already exists" % index)
642 -
    else:
643 -
        bid = get_free_id(net["bus"])
644 -
        index = arange(bid, bid + nr_buses, 1)
645 -
646 -
    # TODO: not needed when concating anyways?
647 -
    # store dtypes
648 -
    # dtypes = net.bus.dtypes
649 -
650 -
    dd = pd.DataFrame(index=index, columns=net.bus.columns)
651 -
    dd["vn_kv"] = vn_kv
652 -
    dd["type"] = type
653 -
    dd["zone"] = zone
654 -
    dd["in_service"] = in_service
655 -
    dd["name"] = name
656 -
    # and preserve dtypes
657 -
    # _preserve_dtypes(net.bus, dtypes)
631 +
    index = _get_multiple_index_with_check(net, "bus", index, nr_buses)
632 +
633 +
    entries = {"vn_kv": vn_kv, "type": type, "zone": zone, "in_service": in_service, "name": name}
634 +
    _add_series_to_entries(entries, index, "min_vm_pu", min_vm_pu)
635 +
    _add_series_to_entries(entries, index, "max_vm_pu", max_vm_pu)
636 +
    _set_multiple_entries(net, "bus", index, **entries, **kwargs)
658 637
659 638
    if geodata is not None:
660 639
        # works with a 2-tuple or a matching array
@@ -667,23 +646,12 @@
Loading
667 646
        net.bus_geodata = net.bus_geodata.append(pd.DataFrame(index=index,
668 647
                                                              columns=net.bus_geodata.columns))
669 648
        net["bus_geodata"].loc[index, "coords"] = coords
670 -
671 -
    if min_vm_pu is not None:
672 -
        dd['min_vm_pu'] = min_vm_pu
673 -
        dd['min_vm_pu'] = dd['min_vm_pu'].astype(float)
674 -
    if max_vm_pu is not None:
675 -
        dd['max_vm_pu'] = max_vm_pu
676 -
        dd['max_vm_pu'] = dd['max_vm_pu'].astype(float)
677 -
678 -
    dd = dd.assign(**kwargs)
679 -
    net["bus"] = net["bus"].append(dd)
680 649
    return index
681 650
682 651
683 652
def create_load(net, bus, p_mw, q_mvar=0, const_z_percent=0, const_i_percent=0, sn_mva=nan,
684 -
                name=None, scaling=1., index=None,
685 -
                in_service=True, type='wye', max_p_mw=nan, min_p_mw=nan,
686 -
                max_q_mvar=nan, min_q_mvar=nan, controllable=nan):
653 +
                name=None, scaling=1., index=None, in_service=True, type='wye', max_p_mw=nan,
654 +
                min_p_mw=nan, max_q_mvar=nan, min_q_mvar=nan, controllable=nan):
687 655
    """
688 656
    Adds one load in table net["load"].
689 657
@@ -746,66 +714,117 @@
Loading
746 714
        create_load(net, bus=0, p_mw=10., q_mvar=2.)
747 715
748 716
    """
749 -
    if bus not in net["bus"].index.values:
750 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
717 +
    _check_node_element(net, bus)
751 718
752 -
    if index is None:
753 -
        index = get_free_id(net["load"])
754 -
    if index in net["load"].index:
755 -
        raise UserWarning("A load with the id %s already exists" % index)
719 +
    index = _get_index_with_check(net, "load", index)
756 720
757 -
    # store dtypes
758 -
    dtypes = net.load.dtypes
721 +
    entries = dict(zip(["name", "bus", "p_mw", "const_z_percent", "const_i_percent", "scaling",
722 +
                        "q_mvar", "sn_mva", "in_service", "type"],
723 +
                       [name, bus, p_mw, const_z_percent, const_i_percent, scaling, q_mvar, sn_mva,
724 +
                        bool(in_service), type]))
759 725
760 -
    net.load.loc[index, ["name", "bus", "p_mw", "const_z_percent", "const_i_percent", "scaling",
761 -
                         "q_mvar", "sn_mva", "in_service", "type"]] = \
762 -
        [name, bus, p_mw, const_z_percent, const_i_percent, scaling, q_mvar, sn_mva,
763 -
         bool(in_service), type]
726 +
    _set_entries(net, "load", index, True, **entries)
764 727
765 -
    # and preserve dtypes
766 -
    _preserve_dtypes(net.load, dtypes)
728 +
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "load")
729 +
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "load")
730 +
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "load")
731 +
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "load")
732 +
    _create_column_and_set_value(net, index, controllable, "controllable", "load", dtyp=bool_,
733 +
                                 default_val=False, default_for_nan=True)
767 734
768 -
    if not isnan(min_p_mw):
769 -
        if "min_p_mw" not in net.load.columns:
770 -
            net.load.loc[:, "min_p_mw"] = pd.Series()
735 +
    return index
771 736
772 -
        net.load.loc[index, "min_p_mw"] = float(min_p_mw)
773 737
774 -
    if not isnan(max_p_mw):
775 -
        if "max_p_mw" not in net.load.columns:
776 -
            net.load.loc[:, "max_p_mw"] = pd.Series()
738 +
def create_loads(net, buses, p_mw, q_mvar=0, const_z_percent=0, const_i_percent=0, sn_mva=nan,
739 +
                 name=None, scaling=1., index=None, in_service=True, type=None, max_p_mw=None,
740 +
                 min_p_mw=None, max_q_mvar=None, min_q_mvar=None, controllable=None, **kwargs):
741 +
    """
742 +
    Adds a number of loads in table net["load"].
777 743
778 -
        net.load.loc[index, "max_p_mw"] = float(max_p_mw)
744 +
    All loads are modelled in the consumer system, meaning load is positive and generation is
745 +
    negative active power. Please pay attention to the correct signing of the reactive power as
746 +
    well.
779 747
780 -
    if not isnan(min_q_mvar):
781 -
        if "min_q_mvar" not in net.load.columns:
782 -
            net.load.loc[:, "min_q_mvar"] = pd.Series()
748 +
    INPUT:
749 +
        **net** - The net within this load should be created
783 750
784 -
        net.load.loc[index, "min_q_mvar"] = float(min_q_mvar)
751 +
        **buses** (list of int) - A list of bus ids to which the loads are connected
785 752
786 -
    if not isnan(max_q_mvar):
787 -
        if "max_q_mvar" not in net.load.columns:
788 -
            net.load.loc[:, "max_q_mvar"] = pd.Series()
753 +
    OPTIONAL:
754 +
        **p_mw** (list of floats) - The active power of the loads
789 755
790 -
        net.load.loc[index, "max_q_mvar"] = float(max_q_mvar)
756 +
        - postive value   -> load
757 +
        - negative value  -> generation
791 758
792 -
    if not isnan(controllable):
793 -
        if "controllable" not in net.load.columns:
794 -
            net.load["controllable"] = False
759 +
        **q_mvar** (list of floats, default 0) - The reactive power of the loads
795 760
796 -
        net.load.loc[index, "controllable"] = bool(controllable)
797 -
    else:
798 -
        if "controllable" in net.load.columns:
799 -
            net.load.loc[index, "controllable"] = False
761 +
        **const_z_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
762 +
            be associated to constant impedance loads at rated voltage
800 763
801 -
    return index
764 +
        **const_i_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
765 +
            be associated to constant current load at rated voltage
802 766
767 +
        **sn_mva** (list of floats, default None) - Nominal power of the loads
768 +
769 +
        **name** (list of strings, default None) - The name for this load
770 +
771 +
        **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
772 +
773 +
        **type** (string, None) -  type variable to classify the load
774 +
775 +
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
776 +
            is set to a range between one higher than the highest already existing index and the \
777 +
            length of loads that shall be created.
778 +
779 +
        **in_service** (list of boolean) - True for in_service or False for out of service
780 +
781 +
        **max_p_mw** (list of floats, default NaN) - Maximum active power load - necessary for \
782 +
            controllable loads in for OPF
783 +
784 +
        **min_p_mw** (list of floats, default NaN) - Minimum active power load - necessary for \
785 +
            controllable loads in for OPF
786 +
787 +
        **max_q_mvar** (list of floats, default NaN) - Maximum reactive power load - necessary for \
788 +
            controllable loads in for OPF
789 +
790 +
        **min_q_mvar** (list of floats, default NaN) - Minimum reactive power load - necessary for \
791 +
            controllable loads in OPF
792 +
793 +
        **controllable** (list of boolean, default NaN) - States, whether a load is controllable \
794 +
            or not. Only respected for OPF
795 +
            Defaults to False if "controllable" column exists in DataFrame
796 +
797 +
    OUTPUT:
798 +
        **index** (int) - The unique IDs of the created elements
799 +
800 +
    EXAMPLE:
801 +
        create_loads(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
803 802
804 -
def create_asymmetric_load(net, bus, p_a_mw=0, p_b_mw=0, p_c_mw=0, q_a_mvar=0, \
805 -
                           q_b_mvar=0, q_c_mvar=0, sn_mva=nan, name=None, scaling=1., \
806 -
                           index=None, in_service=True, type="wye"):
807 803
    """
804 +
    _check_multiple_node_elements(net, buses)
805 +
806 +
    index = _get_multiple_index_with_check(net, "load", index, len(buses))
807 +
808 +
    entries = {"bus": buses, "p_mw": p_mw, "q_mvar": q_mvar, "sn_mva": sn_mva,
809 +
               "const_z_percent": const_z_percent, "const_i_percent": const_i_percent,
810 +
               "scaling": scaling, "in_service": in_service, "name": name, "type": type}
811 +
812 +
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
813 +
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
814 +
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
815 +
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
816 +
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
817 +
                           default_val=False)
808 818
819 +
    _set_multiple_entries(net, "load", index, **entries, **kwargs)
820 +
821 +
    return index
822 +
823 +
824 +
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,
825 +
                           q_c_mvar=0, sn_mva=nan, name=None, scaling=1., index=None,
826 +
                           in_service=True, type="wye"):
827 +
    """
809 828
    Adds one 3 phase load in table net["asymmetric_load"].
810 829
811 830
    All loads are modelled in the consumer system, meaning load is positive and generation is
@@ -820,15 +839,15 @@
Loading
820 839
    OPTIONAL:
821 840
        **p_a_mw** (float, default 0) - The active power for Phase A load
822 841
823 -
		**p_b_mw** (float, default 0) - The active power for Phase B load
842 +
        **p_b_mw** (float, default 0) - The active power for Phase B load
824 843
825 -
		**p_c_mw** (float, default 0) - The active power for Phase C load
844 +
        **p_c_mw** (float, default 0) - The active power for Phase C load
826 845
827 846
        **q_a_mvar** float, default 0) - The reactive power for Phase A load
828 847
829 -
		**q_b_mvar** float, default 0) - The reactive power for Phase B load
848 +
        **q_b_mvar** float, default 0) - The reactive power for Phase B load
830 849
831 -
		**q_c_mvar** (float, default 0) - The reactive power for Phase C load
850 +
        **q_c_mvar** (float, default 0) - The reactive power for Phase C load
832 851
833 852
        **sn_kva** (float, default: None) - Nominal power of the load
834 853
@@ -838,37 +857,28 @@
Loading
838 857
839 858
        **type** (string,default: wye) -  type variable to classify three ph load: delta/wye
840 859
841 -
        **index** (int,default: None) - Force a specified ID if it is available. If None, the index one \
842 -
            higher than the highest already existing index is selected.
860 +
        **index** (int,default: None) - Force a specified ID if it is available. If None, the index\
861 +
            one higher than the highest already existing index is selected.
843 862
844 863
        **in_service** (boolean) - True for in_service or False for out of service
845 864
846 -
847 865
    OUTPUT:
848 866
        **index** (int) - The unique ID of the created element
849 867
850 868
    EXAMPLE:
851 -
		**create_asymmetric_load(net, bus=0, p_c_mw = 9., q_c_mvar = 1.8)**
869 +
        **create_asymmetric_load(net, bus=0, p_c_mw = 9., q_c_mvar = 1.8)**
852 870
853 871
    """
854 -
    if bus not in net["bus"].index.values:
855 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
872 +
    _check_node_element(net, bus)
856 873
857 -
    if index is None:
858 -
        index = get_free_id(net["asymmetric_load"])
859 -
    if index in net["asymmetric_load"].index:
860 -
        raise UserWarning("A 3 phase asymmetric_load with the id %s already exists" % index)
874 +
    index = _get_index_with_check(net, "asymmetric_load", index, name="3 phase asymmetric_load")
861 875
862 -
    # store dtypes
863 -
    dtypes = net.asymmetric_load.dtypes
876 +
    entries = dict(zip(["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling", "q_a_mvar",
877 +
                        "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"],
878 +
                       [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling, q_a_mvar, q_b_mvar, q_c_mvar,
879 +
                        sn_mva, bool(in_service), type]))
864 880
865 -
    net.asymmetric_load.loc[index, ["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling",
866 -
                                    "q_a_mvar", "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"]] = \
867 -
        [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling,
868 -
         q_a_mvar, q_b_mvar, q_c_mvar, sn_mva, bool(in_service), type]
869 -
870 -
    # and preserve dtypes
871 -
    _preserve_dtypes(net.asymmetric_load, dtypes)
881 +
    _set_entries(net, "asymmetric_load", index, True, **entries)
872 882
873 883
    return index
874 884
@@ -929,123 +939,6 @@
Loading
929 939
# =============================================================================
930 940
931 941
932 -
def create_loads(net, buses, p_mw, q_mvar=0, const_z_percent=0, const_i_percent=0, sn_mva=nan,
933 -
                 name=None, scaling=1., index=None, in_service=True, type=None, max_p_mw=None, min_p_mw=None,
934 -
                 max_q_mvar=None, min_q_mvar=None, controllable=None, **kwargs):
935 -
    """
936 -
    Adds a number of loads in table net["load"].
937 -
938 -
    All loads are modelled in the consumer system, meaning load is positive and generation is
939 -
    negative active power. Please pay attention to the correct signing of the reactive power as
940 -
    well.
941 -
942 -
    INPUT:
943 -
        **net** - The net within this load should be created
944 -
945 -
        **buses** (list of int) - A list of bus ids to which the loads are connected
946 -
947 -
    OPTIONAL:
948 -
        **p_mw** (list of floats) - The active power of the loads
949 -
950 -
        - postive value   -> load
951 -
        - negative value  -> generation
952 -
953 -
        **q_mvar** (list of floats, default 0) - The reactive power of the loads
954 -
955 -
        **const_z_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
956 -
            be associated to constant impedance loads at rated voltage
957 -
958 -
        **const_i_percent** (list of floats, default 0) - percentage of p_mw and q_mvar that will \
959 -
            be associated to constant current load at rated voltage
960 -
961 -
        **sn_mva** (list of floats, default None) - Nominal power of the loads
962 -
963 -
        **name** (list of strings, default None) - The name for this load
964 -
965 -
        **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
966 -
967 -
        **type** (string, None) -  type variable to classify the load
968 -
969 -
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
970 -
            is set to a range between one higher than the highest already existing index and the \
971 -
            length of loads that shall be created.
972 -
973 -
        **in_service** (list of boolean) - True for in_service or False for out of service
974 -
975 -
        **max_p_mw** (list of floats, default NaN) - Maximum active power load - necessary for \
976 -
            controllable loads in for OPF
977 -
978 -
        **min_p_mw** (list of floats, default NaN) - Minimum active power load - necessary for \
979 -
            controllable loads in for OPF
980 -
981 -
        **max_q_mvar** (list of floats, default NaN) - Maximum reactive power load - necessary for \
982 -
            controllable loads in for OPF
983 -
984 -
        **min_q_mvar** (list of floats, default NaN) - Minimum reactive power load - necessary for \
985 -
            controllable loads in OPF
986 -
987 -
        **controllable** (list of boolean, default NaN) - States, whether a load is controllable \
988 -
            or not. Only respected for OPF
989 -
            Defaults to False if "controllable" column exists in DataFrame
990 -
991 -
    OUTPUT:
992 -
        **index** (int) - The unique IDs of the created elements
993 -
994 -
    EXAMPLE:
995 -
        create_loads(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
996 -
997 -
    """
998 -
    if np_any(~isin(buses, net["bus"].index.values)):
999 -
        bus_not_exist = set(buses) - set(net["bus"].index.values)
1000 -
        raise UserWarning("Cannot attach to buses %s, they does not exist" % bus_not_exist)
1001 -
1002 -
    if index is None:
1003 -
        bid = get_free_id(net["load"])
1004 -
        index = arange(bid, bid + len(buses), 1)
1005 -
    elif np_any(isin(index, net["load"].index.values)):
1006 -
        raise UserWarning("Loads with the ids %s already exists"
1007 -
                          % net["load"].index.values[isin(net["load"].index.values, index)])
1008 -
1009 -
    # store dtypes
1010 -
    dtypes = net.load.dtypes
1011 -
1012 -
    dd = pd.DataFrame(index=index, columns=net.load.columns)
1013 -
    dd["bus"] = buses
1014 -
    dd["p_mw"] = p_mw
1015 -
    dd["q_mvar"] = q_mvar
1016 -
    dd["sn_mva"] = sn_mva
1017 -
    dd["const_z_percent"] = const_z_percent
1018 -
    dd["const_i_percent"] = const_i_percent
1019 -
    dd["scaling"] = scaling
1020 -
    dd["in_service"] = in_service
1021 -
    dd["name"] = name
1022 -
    dd["type"] = type
1023 -
1024 -
    if min_p_mw is not None:
1025 -
        dd["min_p_mw"] = min_p_mw
1026 -
        dd["min_p_mw"] = dd["min_p_mw"].astype(float)
1027 -
    if max_p_mw is not None:
1028 -
        dd["max_p_mw"] =max_p_mw
1029 -
        dd["max_p_mw"] = dd["max_p_mw"].astype(float)
1030 -
    if min_q_mvar is not None:
1031 -
        dd["min_q_mvar"] = min_q_mvar
1032 -
        dd["min_q_mvar"] = dd["min_q_mvar"].astype(float)
1033 -
    if max_q_mvar is not None:
1034 -
        dd["max_q_mvar"] = max_q_mvar
1035 -
        dd["max_q_mvar"] = dd["max_q_mvar"].astype(float)
1036 -
    if controllable is not None:
1037 -
        dd["controllable"] = controllable
1038 -
        dd["controllable"] = dd["controllable"].astype(bool).fillna(False)
1039 -
1040 -
1041 -
    # and preserve dtypes
1042 -
    dd = dd.assign(**kwargs)
1043 -
    net["load"] = net["load"].append(dd)
1044 -
1045 -
    _preserve_dtypes(net.load, dtypes)
1046 -
    return index
1047 -
1048 -
1049 942
def create_load_from_cosphi(net, bus, sn_mva, cos_phi, mode, **kwargs):
1050 943
    """
1051 944
    Creates a load element from rated power and power factor cos(phi).
@@ -1082,9 +975,9 @@
Loading
1082 975
    """
1083 976
    Adds one static generator in table net["sgen"].
1084 977
1085 -
    Static generators are modelled as positive and constant PQ power. This element is used to model generators
1086 -
    with a constant active and reactive power feed-in. If you want to model a voltage controlled
1087 -
    generator, use the generator element instead.
978 +
    Static generators are modelled as positive and constant PQ power. This element is used to model
979 +
    generators with a constant active and reactive power feed-in. If you want to model a voltage
980 +
    controlled generator, use the generator element instead.
1088 981
1089 982
    gen, sgen and ext_grid in the grid are modelled in the generator system!
1090 983
    If you want to model the generation of power, you have to assign a positive active power
@@ -1147,206 +1040,127 @@
Loading
1147 1040
        create_sgen(net, 1, p_mw = -120)
1148 1041
1149 1042
    """
1150 -
    if bus not in net["bus"].index.values:
1151 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1152 -
1153 -
    if index is None:
1154 -
        index = get_free_id(net["sgen"])
1155 -
1156 -
    if index in net["sgen"].index:
1157 -
        raise UserWarning("A static generator with the id %s already exists" % index)
1158 -
1159 -
    # store dtypes
1160 -
    dtypes = net.sgen.dtypes
1161 -
1162 -
    net.sgen.loc[index, ["name", "bus", "p_mw", "scaling",
1163 -
                         "q_mvar", "sn_mva", "in_service", "type",
1164 -
                         "current_source"]] = \
1165 -
        [name, bus, p_mw, scaling, q_mvar, sn_mva, bool(in_service), type, current_source]
1166 -
1167 -
    # and preserve dtypes
1168 -
    _preserve_dtypes(net.sgen, dtypes)
1169 -
1170 -
    if not isnan(min_p_mw):
1171 -
        if "min_p_mw" not in net.sgen.columns:
1172 -
            net.sgen.loc[:, "min_p_mw"] = pd.Series()
1173 -
1174 -
        net.sgen.loc[index, "min_p_mw"] = float(min_p_mw)
1175 -
1176 -
    if not isnan(max_p_mw):
1177 -
        if "max_p_mw" not in net.sgen.columns:
1178 -
            net.sgen.loc[:, "max_p_mw"] = pd.Series()
1179 -
1180 -
        net.sgen.loc[index, "max_p_mw"] = float(max_p_mw)
1181 -
1182 -
    if not isnan(min_q_mvar):
1183 -
        if "min_q_mvar" not in net.sgen.columns:
1184 -
            net.sgen.loc[:, "min_q_mvar"] = pd.Series()
1043 +
    _check_node_element(net, bus)
1185 1044
1186 -
        net.sgen.loc[index, "min_q_mvar"] = float(min_q_mvar)
1045 +
    index = _get_index_with_check(net, "sgen", index, name="static generator")
1187 1046
1188 -
    if not isnan(max_q_mvar):
1189 -
        if "max_q_mvar" not in net.sgen.columns:
1190 -
            net.sgen.loc[:, "max_q_mvar"] = pd.Series()
1047 +
    entries = dict(zip(["name", "bus", "p_mw", "scaling", "q_mvar", "sn_mva", "in_service", "type",
1048 +
                        "current_source"], [name, bus, p_mw, scaling, q_mvar, sn_mva,
1049 +
                                            bool(in_service), type, current_source]))
1191 1050
1192 -
        net.sgen.loc[index, "max_q_mvar"] = float(max_q_mvar)
1051 +
    _set_entries(net, "sgen", index, True, **entries)
1193 1052
1194 -
    if not isnan(controllable):
1195 -
        if "controllable" not in net.sgen.columns:
1196 -
            net.sgen.loc[:, "controllable"] = False
1197 -
1198 -
        net.sgen.loc[index, "controllable"] = bool(controllable)
1199 -
    else:
1200 -
        if "controllable" in net.sgen.columns:
1201 -
            net.sgen.loc[index, "controllable"] = False
1202 -
1203 -
    if not isnan(k):
1204 -
        if "k" not in net.sgen.columns:
1205 -
            net.sgen.loc[:, "k"] = pd.Series()
1206 -
1207 -
        net.sgen.loc[index, "k"] = float(k)
1208 -
1209 -
    if not isnan(rx):
1210 -
        if "rx" not in net.sgen.columns:
1211 -
            net.sgen.loc[:, "rx"] = pd.Series()
1212 -
1213 -
        net.sgen.loc[index, "rx"] = float(rx)
1053 +
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "sgen")
1054 +
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "sgen")
1055 +
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "sgen")
1056 +
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "sgen")
1057 +
    _create_column_and_set_value(net, index, k, "k", "sgen")
1058 +
    _create_column_and_set_value(net, index, rx, "rx", "sgen")
1059 +
    _create_column_and_set_value(net, index, controllable, "controllable", "sgen", dtyp=bool_,
1060 +
                                 default_val=False, default_for_nan=True)
1214 1061
1215 1062
    return index
1216 1063
1217 1064
1218 1065
def create_sgens(net, buses, p_mw, q_mvar=0, sn_mva=nan, name=None, index=None,
1219 -
                scaling=1., type='wye', in_service=True, max_p_mw=None, min_p_mw=None,
1220 -
                max_q_mvar=None, min_q_mvar=None, controllable=None, k=None, rx=None,
1221 -
                current_source=True, **kwargs):
1066 +
                 scaling=1., type='wye', in_service=True, max_p_mw=None, min_p_mw=None,
1067 +
                 max_q_mvar=None, min_q_mvar=None, controllable=None, k=None, rx=None,
1068 +
                 current_source=True, **kwargs):
1222 1069
    """
1223 -
     Adds a number of sgens in table net["sgen"].
1070 +
    Adds a number of sgens in table net["sgen"].
1224 1071
1225 -
    Static generators are modelled as positive and constant PQ power. This element is used to model generators
1226 -
    with a constant active and reactive power feed-in. If you want to model a voltage controlled
1227 -
    generator, use the generator element instead.
1072 +
    Static generators are modelled as positive and constant PQ power. This element is used to model
1073 +
    generators with a constant active and reactive power feed-in. If you want to model a voltage
1074 +
    controlled generator, use the generator element instead.
1228 1075
1229 -
     INPUT:
1230 -
         **net** - The net within this load should be created
1076 +
    INPUT:
1077 +
        **net** - The net within this load should be created
1231 1078
1232 -
         **buses** (list of int) - A list of bus ids to which the loads are connected
1079 +
        **buses** (list of int) - A list of bus ids to which the loads are connected
1233 1080
1234 -
     OPTIONAL:
1081 +
    OPTIONAL:
1235 1082
1236 -
         **p_mw** (list of floats) - The active power of the sgens
1083 +
        **p_mw** (list of floats) - The active power of the sgens
1237 1084
1238 -
			 - postive value   -> generation
1239 -
			 - negative value  -> load
1085 +
             - postive value   -> generation
1086 +
             - negative value  -> load
1240 1087
1241 -
         **q_mvar** (list of floats, default 0) - The reactive power of the sgens
1088 +
        **q_mvar** (list of floats, default 0) - The reactive power of the sgens
1242 1089
1243 -
         **sn_mva** (list of floats, default None) - Nominal power of the sgens
1090 +
        **sn_mva** (list of floats, default None) - Nominal power of the sgens
1244 1091
1245 -
         **name** (list of strings, default None) - The name for this sgen
1092 +
        **name** (list of strings, default None) - The name for this sgen
1246 1093
1247 -
         **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
1094 +
        **scaling** (list of floats, default 1.) - An OPTIONAL scaling factor to be set customly
1248 1095
1249 -
         **type** (string, None) -  type variable to classify the sgen
1096 +
        **type** (string, None) -  type variable to classify the sgen
1250 1097
1251 -
         **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
1098 +
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
1252 1099
             is set to a range between one higher than the highest already existing index and the \
1253 1100
             length of sgens that shall be created.
1254 1101
1255 -
         **in_service** (list of boolean) - True for in_service or False for out of service
1102 +
        **in_service** (list of boolean) - True for in_service or False for out of service
1256 1103
1257 -
         **max_p_mw** (list of floats, default NaN) - Maximum active power sgen - necessary for \
1104 +
        **max_p_mw** (list of floats, default NaN) - Maximum active power sgen - necessary for \
1258 1105
             controllable sgens in for OPF
1259 1106
1260 -
         **min_p_mw** (list of floats, default NaN) - Minimum active power sgen - necessary for \
1107 +
        **min_p_mw** (list of floats, default NaN) - Minimum active power sgen - necessary for \
1261 1108
             controllable sgens in for OPF
1262 1109
1263 -
         **max_q_mvar** (list of floats, default NaN) - Maximum reactive power sgen - necessary for \
1110 +
        **max_q_mvar** (list of floats, default NaN) - Maximum reactive power sgen - necessary for \
1264 1111
             controllable sgens in for OPF
1265 1112
1266 -
         **min_q_mvar** (list of floats, default NaN) - Minimum reactive power sgen - necessary for \
1113 +
        **min_q_mvar** (list of floats, default NaN) - Minimum reactive power sgen - necessary for \
1267 1114
             controllable sgens in OPF
1268 1115
1269 -
         **controllable** (list of boolean, default NaN) - States, whether a sgen is controllable \
1116 +
        **controllable** (list of boolean, default NaN) - States, whether a sgen is controllable \
1270 1117
             or not. Only respected for OPF
1271 1118
             Defaults to False if "controllable" column exists in DataFrame
1272 1119
1273 1120
        **k** (list of floats, None) - Ratio of nominal current to short circuit current
1274 1121
1275 -
        **rx** (list of floats, NaN) - R/X ratio for short circuit impedance. Only relevant if type is \
1276 -
            specified as motor so that sgen is treated as asynchronous motor
1122 +
        **rx** (list of floats, NaN) - R/X ratio for short circuit impedance. Only relevant if type\
1123 +
            is specified as motor so that sgen is treated as asynchronous motor
1277 1124
1278 1125
        **current_source** (list of bool, True) - Model this sgen as a current source during short-\
1279 1126
            circuit calculations; useful in some cases, for example the simulation of full-\
1280 1127
            size converters per IEC 60909-0:2016.
1281 1128
1282 -
     OUTPUT:
1283 -
         **index** (int) - The unique IDs of the created elements
1129 +
    OUTPUT:
1130 +
        **index** (int) - The unique IDs of the created elements
1131 +
1132 +
    EXAMPLE:
1133 +
        create_sgens(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
1134 +
1135 +
    """
1136 +
    _check_multiple_node_elements(net, buses)
1284 1137
1285 -
     EXAMPLE:
1286 -
         create_sgens(net, buses=[0, 2], p_mw=[10., 5.], q_mvar=[2., 0.])
1138 +
    index = _get_multiple_index_with_check(net, "sgen", index, len(buses))
1287 1139
1288 -
     """
1289 -
    if np_any(~isin(buses, net["bus"].index.values)):
1290 -
        bus_not_exist = set(buses) - set(net["bus"].index.values)
1291 -
        raise UserWarning("Cannot attach to buses %s, they does not exist" % bus_not_exist)
1140 +
    entries = {"bus": buses, "p_mw": p_mw, "q_mvar": q_mvar, "sn_mva": sn_mva, "scaling": scaling,
1141 +
               "in_service": in_service, "name": name, "type": type,
1142 +
               'current_source': current_source}
1292 1143
1293 -
    if index is None:
1294 -
        bid = get_free_id(net["sgen"])
1295 -
        index = arange(bid, bid + len(buses), 1)
1296 -
    elif np_any(isin(index, net["sgen"].index.values)):
1297 -
        raise UserWarning("Sgens with the ids %s already exists"
1298 -
                          % net["sgen"].index.values[isin(net["sgen"].index.values, index)])
1299 -
1300 -
    # store dtypes
1301 -
    dtypes = net.sgen.dtypes
1302 -
1303 -
    dd = pd.DataFrame(index=index, columns=net.sgen.columns)
1304 -
1305 -
    dd["bus"] = buses
1306 -
    dd["p_mw"] = p_mw
1307 -
    dd["q_mvar"] = q_mvar
1308 -
    dd["sn_mva"] = sn_mva
1309 -
    dd["scaling"] = scaling
1310 -
    dd["in_service"] = in_service
1311 -
    dd["name"] = name
1312 -
    dd["type"] = type
1313 -
    dd['current_source'] = current_source
1314 -
1315 -
    if min_p_mw is not None:
1316 -
        dd["min_p_mw"] = min_p_mw
1317 -
        dd["min_p_mw"] = dd["min_p_mw"].astype(float)
1318 -
    if max_p_mw is not None:
1319 -
        dd["max_p_mw"] =max_p_mw
1320 -
        dd["max_p_mw"] = dd["max_p_mw"].astype(float)
1321 -
    if min_q_mvar is not None:
1322 -
        dd["min_q_mvar"] = min_q_mvar
1323 -
        dd["min_q_mvar"] = dd["min_q_mvar"].astype(float)
1324 -
    if max_q_mvar is not None:
1325 -
        dd["max_q_mvar"] = max_q_mvar
1326 -
        dd["max_q_mvar"] = dd["max_q_mvar"].astype(float)
1327 -
    if controllable is not None:
1328 -
        dd["controllable"] = controllable
1329 -
        dd["controllable"] = dd["controllable"].astype(bool)
1330 -
    if k is not None:
1331 -
        dd["k"] = k
1332 -
        dd["k"] = dd["k"].astype(float)
1333 -
    if rx is not None:
1334 -
        dd["rx"] = rx
1335 -
        dd["rx"] = dd["rx"].astype(float)
1336 -
1337 -
    dd = dd.assign(**kwargs)
1338 -
    net["sgen"] = net["sgen"].append(dd)
1144 +
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
1145 +
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
1146 +
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
1147 +
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
1148 +
    _add_series_to_entries(entries, index, "k", k)
1149 +
    _add_series_to_entries(entries, index, "rx", rx)
1150 +
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
1151 +
                           default_val=False)
1339 1152
1340 -
    # and preserve dtypes
1341 -
    _preserve_dtypes(net.sgen, dtypes)
1153 +
    _set_multiple_entries(net, "sgen", index, **entries, **kwargs)
1342 1154
1343 1155
    return index
1344 1156
1157 +
1345 1158
# =============================================================================
1346 1159
# Create 3ph Sgen
1347 1160
# =============================================================================
1348 1161
1349 -
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, q_c_mvar=0, sn_mva=nan,
1162 +
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,
1163 +
                           q_c_mvar=0, sn_mva=nan,
1350 1164
                           name=None, index=None, scaling=1., type='wye', in_service=True):
1351 1165
    """
1352 1166
@@ -1394,24 +1208,17 @@
Loading
1394 1208
        create_asymmetric_sgen(net, 1, p_b_mw=0.12)
1395 1209
1396 1210
    """
1397 -
    if bus not in net["bus"].index.values:
1398 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1211 +
    _check_node_element(net, bus)
1399 1212
1400 -
    if index is None:
1401 -
        index = get_free_id(net["asymmetric_sgen"])
1402 -
1403 -
    if index in net["asymmetric_sgen"].index:
1404 -
        raise UserWarning("A static generator with the id %s already exists" % index)
1213 +
    index = _get_index_with_check(net, "asymmetric_sgen", index,
1214 +
                                  name="3 phase asymmetric static generator")
1405 1215
1406 -
    # store dtypes
1407 -
    dtypes = net.asymmetric_sgen.dtypes
1216 +
    entries = dict(zip(["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling", "q_a_mvar",
1217 +
                        "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"],
1218 +
                       [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling, q_a_mvar, q_b_mvar, q_c_mvar,
1219 +
                        sn_mva, bool(in_service), type]))
1408 1220
1409 -
    net.asymmetric_sgen.loc[index, ["name", "bus", "p_a_mw", "p_b_mw", "p_c_mw", "scaling",
1410 -
                                    "q_a_mvar", "q_b_mvar", "q_c_mvar", "sn_mva", "in_service", "type"]] = \
1411 -
        [name, bus, p_a_mw, p_b_mw, p_c_mw, scaling, q_a_mvar, q_b_mvar, q_c_mvar, sn_mva, bool(in_service), type]
1412 -
1413 -
    # and preserve dtypes
1414 -
    _preserve_dtypes(net.asymmetric_sgen, dtypes)
1221 +
    _set_entries(net, "asymmetric_sgen", index, True, **entries)
1415 1222
1416 1223
    return index
1417 1224
@@ -1435,8 +1242,8 @@
Loading
1435 1242
        **index** (int) - The unique ID of the created sgen
1436 1243
1437 1244
    gen, sgen, and ext_grid are modelled in the generator point of view. Active power
1438 -
    will therefore be postive por generation, and reactive power will be negative for consumption behaviour and
1439 -
    positive for generation behaviour.
1245 +
    will therefore be postive por generation, and reactive power will be negative for consumption
1246 +
    behaviour and positive for generation behaviour.
1440 1247
    """
1441 1248
    from pandapower.toolbox import pq_from_cosphi
1442 1249
    p_mw, q_mvar = pq_from_cosphi(sn_mva, cos_phi, qmode=mode, pmode="gen")
@@ -1516,73 +1323,28 @@
Loading
1516 1323
        create_storage(net, 1, p_mw = -30, max_e_mwh = 60, soc_percent = 1.0, min_e_mwh = 5)
1517 1324
1518 1325
    """
1519 -
    if bus not in net["bus"].index.values:
1520 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1326 +
    _check_node_element(net, bus)
1521 1327
1522 -
    if index is None:
1523 -
        index = get_free_id(net["storage"])
1328 +
    index = _get_index_with_check(net, "storage", index)
1524 1329
1525 -
    if index in net["storage"].index:
1526 -
        raise UserWarning("A storage with the id %s already exists" % index)
1330 +
    entries = dict(zip(["name", "bus", "p_mw", "q_mvar", "sn_mva", "scaling", "soc_percent",
1331 +
                        "min_e_mwh", "max_e_mwh", "in_service", "type"],
1332 +
                       [name, bus, p_mw, q_mvar, sn_mva, scaling, soc_percent, min_e_mwh, max_e_mwh,
1333 +
                        bool(in_service), type]))
1527 1334
1528 -
    # store dtypes
1529 -
    dtypes = net.storage.dtypes
1530 -
1531 -
    net.storage.loc[index, ["name", "bus", "p_mw", "q_mvar", "sn_mva", "scaling",
1532 -
                            "soc_percent", "min_e_mwh", "max_e_mwh", "in_service", "type"]] = \
1533 -
        [name, bus, p_mw, q_mvar, sn_mva, scaling,
1534 -
         soc_percent, min_e_mwh, max_e_mwh, bool(in_service), type]
1535 -
1536 -
    # and preserve dtypes
1537 -
    _preserve_dtypes(net.storage, dtypes)
1335 +
    _set_entries(net, "storage", index, True, **entries)
1538 1336
1539 1337
    # check for OPF parameters and add columns to network table
1540 -
    if not isnan(min_p_mw):
1541 -
        if "min_p_mw" not in net.storage.columns:
1542 -
            net.storage.loc[:, "min_p_mw"] = pd.Series()
1543 -
1544 -
        net.storage.loc[index, "min_p_mw"] = float(min_p_mw)
1545 -
1546 -
    if not isnan(max_p_mw):
1547 -
        if "max_p_mw" not in net.storage.columns:
1548 -
            net.storage.loc[:, "max_p_mw"] = pd.Series()
1549 -
1550 -
        net.storage.loc[index, "max_p_mw"] = float(max_p_mw)
1551 -
1552 -
    if not isnan(min_q_mvar):
1553 -
        if "min_q_mvar" not in net.storage.columns:
1554 -
            net.storage.loc[:, "min_q_mvar"] = pd.Series()
1555 -
1556 -
        net.storage.loc[index, "min_q_mvar"] = float(min_q_mvar)
1557 -
1558 -
    if not isnan(max_q_mvar):
1559 -
        if "max_q_mvar" not in net.storage.columns:
1560 -
            net.storage.loc[:, "max_q_mvar"] = pd.Series()
1561 -
1562 -
        net.storage.loc[index, "max_q_mvar"] = float(max_q_mvar)
1563 -
1564 -
    if not isnan(controllable):
1565 -
        if "controllable" not in net.storage.columns:
1566 -
            net.storage.loc[:, "controllable"] = False
1567 -
1568 -
        net.storage.loc[index, "controllable"] = bool(controllable)
1569 -
    else:
1570 -
        if "controllable" in net.storage.columns:
1571 -
            net.storage.loc[index, "controllable"] = False
1338 +
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "storage")
1339 +
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "storage")
1340 +
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "storage")
1341 +
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "storage")
1342 +
    _create_column_and_set_value(net, index, controllable, "controllable", "storage",
1343 +
                                 dtyp=bool_, default_val=False, default_for_nan=True)
1572 1344
1573 1345
    return index
1574 1346
1575 1347
1576 -
def _create_column_and_set_value(net, index, variable, column, element, default_val=nan):
1577 -
    # if variable (e.g. p_mw) is not None and column (e.g. "p_mw") doesn't exist in element (e.g. "gen") table
1578 -
    # create this column and write the value of variable to the index of this element
1579 -
    if not isnan(variable):
1580 -
        if column not in net[element].columns:
1581 -
            net[element].loc[:, column] = float(default_val)
1582 -
        net[element].at[index, column] = float(variable)
1583 -
    return net
1584 -
1585 -
1586 1348
def create_gen(net, bus, p_mw, vm_pu=1., sn_mva=nan, name=None, index=None, max_q_mvar=nan,
1587 1349
               min_q_mvar=nan, min_p_mw=nan, max_p_mw=nan, min_vm_pu=nan, max_vm_pu=nan,
1588 1350
               scaling=1., type=None, slack=False, controllable=nan, vn_kv=nan,
@@ -1615,9 +1377,10 @@
Loading
1615 1377
1616 1378
        **type** (string, None) - type variable to classify generators
1617 1379
1618 -
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this generator in OPF
1619 -
                                        False: p_mw and vm_pu setpoints are enforced and *limits are ignored*.
1620 -
                                        defaults to True if "controllable" column exists in DataFrame
1380 +
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this \
1381 +
                generator in OPF
1382 +
                False: p_mw and vm_pu setpoints are enforced and *limits are ignored*.
1383 +
                defaults to True if "controllable" column exists in DataFrame
1621 1384
        powerflow
1622 1385
1623 1386
        **vn_kv** (float, NaN) - Rated voltage of the generator for short-circuit calculation
@@ -1638,10 +1401,12 @@
Loading
1638 1401
1639 1402
        **min_q_mvar** (float, default NaN) - Minimum reactive power injection - necessary for OPF
1640 1403
1641 -
        **min_vm_pu** (float, default NaN) - Minimum voltage magnitude. If not set the bus voltage limit is taken.
1404 +
        **min_vm_pu** (float, default NaN) - Minimum voltage magnitude. If not set the bus voltage \
1405 +
                                             limit is taken.
1642 1406
                                           - necessary for OPF.
1643 1407
1644 -
        **max_vm_pur** (float, default NaN) - Maximum voltage magnitude. If not set the bus voltage limit is taken.
1408 +
        **max_vm_pur** (float, default NaN) - Maximum voltage magnitude. If not set the bus voltage\
1409 +
                                              limit is taken.
1645 1410
                                            - necessary for OPF
1646 1411
1647 1412
    OUTPUT:
@@ -1651,63 +1416,53 @@
Loading
1651 1416
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1652 1417
1653 1418
    """
1654 -
    if bus not in net["bus"].index.values:
1655 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1419 +
    _check_node_element(net, bus)
1656 1420
1657 -
    if index is None:
1658 -
        index = get_free_id(net["gen"])
1659 -
1660 -
    if index in net["gen"].index:
1661 -
        raise UserWarning("A generator with the id %s already exists" % index)
1662 -
1663 -
    # store dtypes
1664 -
    dtypes = net.gen.dtypes
1421 +
    index = _get_index_with_check(net, "gen", index, name="generator")
1665 1422
1666 1423
    columns = ["name", "bus", "p_mw", "vm_pu", "sn_mva", "type", "slack", "in_service",
1667 1424
               "scaling"]
1668 1425
    variables = [name, bus, p_mw, vm_pu, sn_mva, type, slack, bool(in_service), scaling]
1669 -
    net.gen.loc[index, columns] = variables
1670 1426
1671 -
    # and preserve dtypes
1672 -
    _preserve_dtypes(net.gen, dtypes)
1427 +
    _set_entries(net, "gen", index, True, **dict(zip(columns, variables)))
1673 1428
1674 1429
    # OPF limits
1675 1430
    if not isnan(controllable):
1676 1431
        if "controllable" not in net.gen.columns:
1677 -
            net.gen.loc[:, "controllable"] = True
1432 +
            net.gen.loc[:, "controllable"] = pd.Series(dtype=bool, data=True)
1678 1433
        net.gen.at[index, "controllable"] = bool(controllable)
1679 1434
    elif "controllable" in net.gen.columns:
1680 1435
        net.gen.at[index, "controllable"] = True
1681 1436
    # P limits for OPF if controllable == True
1682 -
    net = _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "gen")
1683 -
    net = _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "gen")
1437 +
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "gen")
1438 +
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "gen")
1684 1439
    # Q limits for OPF if controllable == True
1685 -
    net = _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "gen")
1686 -
    net = _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "gen")
1440 +
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "gen")
1441 +
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "gen")
1687 1442
    # V limits for OPF if controllable == True
1688 -
    net = _create_column_and_set_value(net, index, max_vm_pu, "max_vm_pu", "gen", default_val=2.)
1689 -
    net = _create_column_and_set_value(net, index, min_vm_pu, "min_vm_pu", "gen", default_val=0.)
1443 +
    _create_column_and_set_value(net, index, max_vm_pu, "max_vm_pu", "gen", default_val=2.)
1444 +
    _create_column_and_set_value(net, index, min_vm_pu, "min_vm_pu", "gen", default_val=0.)
1690 1445
1691 1446
    # Short circuit calculation limits
1692 -
    net = _create_column_and_set_value(net, index, vn_kv, "vn_kv", "gen")
1693 -
    net = _create_column_and_set_value(net, index, cos_phi, "cos_phi", "gen")
1447 +
    _create_column_and_set_value(net, index, vn_kv, "vn_kv", "gen")
1448 +
    _create_column_and_set_value(net, index, cos_phi, "cos_phi", "gen")
1694 1449
1695 1450
    if not isnan(xdss_pu):
1696 1451
        if "xdss_pu" not in net.gen.columns:
1697 -
            net.gen.loc[:, "xdss_pu"] = pd.Series()
1452 +
            net.gen.loc[:, "xdss_pu"] = pd.Series(dtype=float64)
1698 1453
        if "rdss_pu" not in net.gen.columns:
1699 -
            net.gen.loc[:, "rdss_pu"] = pd.Series()
1454 +
            net.gen.loc[:, "rdss_pu"] = pd.Series(dtype=float64)
1700 1455
        net.gen.at[index, "xdss_pu"] = float(xdss_pu)
1701 1456
1702 -
    net = _create_column_and_set_value(net, index, rdss_pu, "rdss_pu", "gen")
1457 +
    _create_column_and_set_value(net, index, rdss_pu, "rdss_pu", "gen")
1703 1458
1704 1459
    return index
1705 1460
1706 1461
1707 1462
def create_gens(net, buses, p_mw, vm_pu=1., sn_mva=nan, name=None, index=None, max_q_mvar=None,
1708 -
               min_q_mvar=None, min_p_mw=None, max_p_mw=None, min_vm_pu=None, max_vm_pu=None,
1709 -
               scaling=1., type=None, slack=False, controllable=None, vn_kv=None,
1710 -
               xdss_pu=None, rdss_pu=None, cos_phi=None, in_service=True, **kwargs):
1463 +
                min_q_mvar=None, min_p_mw=None, max_p_mw=None, min_vm_pu=None, max_vm_pu=None,
1464 +
                scaling=1., type=None, slack=False, controllable=None, vn_kv=None,
1465 +
                xdss_pu=None, rdss_pu=None, cos_phi=None, in_service=True, **kwargs):
1711 1466
    """
1712 1467
    Adds generators to the specified buses network.
1713 1468
@@ -1721,7 +1476,8 @@
Loading
1721 1476
        **buses** (list of int) - The bus ids to which the generators are connected
1722 1477
1723 1478
    OPTIONAL:
1724 -
        **p_mw** (list of float, default 0) - The active power of the generator (positive for generation!)
1479 +
        **p_mw** (list of float, default 0) - The active power of the generator (positive for \
1480 +
            generation!)
1725 1481
1726 1482
        **vm_pu** (list of float, default 0) - The voltage set point of the generator.
1727 1483
@@ -1729,41 +1485,54 @@
Loading
1729 1485
1730 1486
        **name** (list of string, None) - The name for this generator
1731 1487
1732 -
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index one \
1733 -
            higher than the highest already existing index is selected.
1488 +
        **index** (list of int, None) - Force a specified ID if it is available. If None, the index\
1489 +
            one higher than the highest already existing index is selected.
1734 1490
1735 -
        **scaling** (list of float, 1.0) - scaling factor which for the active power of the generator
1491 +
        **scaling** (list of float, 1.0) - scaling factor which for the active power of the\
1492 +
            generator
1736 1493
1737 1494
        **type** (list of string, None) - type variable to classify generators
1738 1495
1739 -
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this generator in OPF
1740 -
                                        False: p_mw and vm_pu setpoints are enforced and *limits are ignored*.
1741 -
                                        defaults to True if "controllable" column exists in DataFrame
1496 +
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for this \
1497 +
                                       generator in OPF
1498 +
                                       False: p_mw and vm_pu setpoints are enforced and \
1499 +
                                       *limits are ignored*.
1500 +
                                       defaults to True if "controllable" column exists in DataFrame
1742 1501
        powerflow
1743 1502
1744 -
        **vn_kv** (list of float, NaN) - Rated voltage of the generator for short-circuit calculation
1503 +
        **vn_kv** (list of float, NaN) - Rated voltage of the generator for short-circuit \
1504 +
            calculation
1745 1505
1746 -
        **xdss_pu** (list of float, NaN) - Subtransient generator reactance for short-circuit calculation
1506 +
        **xdss_pu** (list of float, NaN) - Subtransient generator reactance for short-circuit \
1507 +
            calculation
1747 1508
1748 -
        **rdss_pu** (list of float, NaN) - Subtransient generator resistance for short-circuit calculation
1509 +
        **rdss_pu** (list of float, NaN) - Subtransient generator resistance for short-circuit \
1510 +
            calculation
1749 1511
1750 -
        **cos_phi** (list of float, NaN) - Rated cosine phi of the generator for short-circuit calculation
1512 +
        **cos_phi** (list of float, NaN) - Rated cosine phi of the generator for short-circuit \
1513 +
            calculation
1751 1514
1752 1515
        **in_service** (bool, True) - True for in_service or False for out of service
1753 1516
1754 -
        **max_p_mw** (list of float, default NaN) - Maximum active power injection - necessary for OPF
1517 +
        **max_p_mw** (list of float, default NaN) - Maximum active power injection - necessary for\
1518 +
            OPF
1755 1519
1756 -
        **min_p_mw** (list of float, default NaN) - Minimum active power injection - necessary for OPF
1520 +
        **min_p_mw** (list of float, default NaN) - Minimum active power injection - necessary for \
1521 +
            OPF
1757 1522
1758 -
        **max_q_mvar** (list of float, default NaN) - Maximum reactive power injection - necessary for OPF
1523 +
        **max_q_mvar** (list of float, default NaN) - Maximum reactive power injection - necessary\
1524 +
            for OPF
1759 1525
1760 -
        **min_q_mvar** (list of float, default NaN) - Minimum reactive power injection - necessary for OPF
1526 +
        **min_q_mvar** (list of float, default NaN) - Minimum reactive power injection - necessary \
1527 +
            for OPF
1761 1528
1762 -
        **min_vm_pu** (list of float, default NaN) - Minimum voltage magnitude. If not set the bus voltage limit is taken.
1763 -
                                           - necessary for OPF.
1529 +
        **min_vm_pu** (list of float, default NaN) - Minimum voltage magnitude. If not set the \
1530 +
                                                     bus voltage limit is taken.
1531 +
                                                   - necessary for OPF.
1764 1532
1765 -
        **max_vm_pur** (list of float, default NaN) - Maximum voltage magnitude. If not set the bus voltage limit is taken.
1766 -
                                            - necessary for OPF
1533 +
        **max_vm_pur** (list of float, default NaN) - Maximum voltage magnitude. If not set the bus\
1534 +
                                                      voltage limit is taken.
1535 +
                                                    - necessary for OPF
1767 1536
1768 1537
    OUTPUT:
1769 1538
        **index** (int) - The unique ID of the created generator
@@ -1772,79 +1541,34 @@
Loading
1772 1541
        create_gen(net, 1, p_mw = 120, vm_pu = 1.02)
1773 1542
1774 1543
    """
1775 -
    if np_any(~isin(buses, net["bus"].index.values)):
1776 -
        bus_not_exist = set(buses) - set(net["bus"].index.values)
1777 -
        raise UserWarning("Cannot attach to buses %s, they does not exist" % bus_not_exist)
1544 +
    _check_multiple_node_elements(net, buses)
1778 1545
1779 -
    if index is None:
1780 -
        bid = get_free_id(net["gen"])
1781 -
        index = arange(bid, bid + len(buses), 1)
1782 -
    elif np_any(isin(index, net["gen"].index.values)):
1783 -
        raise UserWarning("gens with the ids %s already exists"
1784 -
                          % net["gen"].index.values[isin(net["gen"].index.values, index)])
1785 -
1786 -
    # store dtypes
1787 -
    dtypes = net.gen.dtypes
1788 -
1789 -
    dd = pd.DataFrame(index=index, columns=net.gen.columns)
1790 -
    dd["bus"] = buses
1791 -
    dd["p_mw"] = p_mw
1792 -
    dd["vm_pu"] = vm_pu
1793 -
    dd["sn_mva"] = sn_mva
1794 -
    dd["scaling"] = scaling
1795 -
    dd["in_service"] = in_service
1796 -
    dd["name"] = name
1797 -
    dd["type"] = type
1798 -
    dd["slack"] = slack
1799 -
1800 -
    if min_p_mw is not None:
1801 -
        dd["min_p_mw"] = min_p_mw
1802 -
        dd["min_p_mw"] = dd["min_p_mw"].astype(float)
1803 -
    if max_p_mw is not None:
1804 -
        dd["max_p_mw"] = max_p_mw
1805 -
        dd["max_p_mw"] = dd["max_p_mw"].astype(float)
1806 -
    if min_q_mvar is not None:
1807 -
        dd["min_q_mvar"] = min_q_mvar
1808 -
        dd["min_q_mvar"] = dd["min_q_mvar"].astype(float)
1809 -
    if max_q_mvar is not None:
1810 -
        dd["max_q_mvar"] = max_q_mvar
1811 -
        dd["max_q_mvar"] = dd["max_q_mvar"].astype(float)
1812 -
    if min_vm_pu is not None:
1813 -
        dd["min_vm_pu"] = min_vm_pu
1814 -
        dd["min_vm_pu"] = dd["min_vm_pu"].astype(float)
1815 -
    if max_vm_pu is not None:
1816 -
        dd["max_vm_pu"] = max_vm_pu
1817 -
        dd["max_vm_pu"] = dd["max_vm_pu"].astype(float)
1818 -
    if vn_kv is not None:
1819 -
        dd["vn_kv"] = vn_kv
1820 -
        dd["vn_kv"] = dd["vn_kv"].astype(float)
1821 -
    if cos_phi is not None:
1822 -
        dd["cos_phi"] = cos_phi
1823 -
        dd["cos_phi"] = dd["cos_phi"].astype(float)
1824 -
    if xdss_pu is not None:
1825 -
        dd["xdss_pu"] = xdss_pu
1826 -
        dd["xdss_pu"] = dd["xdss_pu"].astype(float)
1827 -
    if rdss_pu is not None:
1828 -
        dd["rdss_pu"] = rdss_pu
1829 -
        dd["rdss_pu"] = dd["rdss_pu"].astype(float)
1830 -
    if controllable is not None:
1831 -
        dd["controllable"] = controllable
1832 -
        dd["controllable"] = dd["controllable"].astype(bool).fillna(False)
1546 +
    index = _get_multiple_index_with_check(net, "gen", index, len(buses))
1833 1547
1548 +
    entries = {"bus": buses, "p_mw": p_mw, "vm_pu": vm_pu, "sn_mva": sn_mva, "scaling": scaling,
1549 +
               "in_service": in_service, "name": name, "type": type, "slack": slack}
1834 1550
1835 -
    # and preserve dtypes
1836 -
    dd = dd.assign(**kwargs)
1837 -
    net["gen"] = net["gen"].append(dd)
1551 +
    _add_series_to_entries(entries, index, "min_p_mw", min_p_mw)
1552 +
    _add_series_to_entries(entries, index, "max_p_mw", max_p_mw)
1553 +
    _add_series_to_entries(entries, index, "min_q_mvar", min_q_mvar)
1554 +
    _add_series_to_entries(entries, index, "max_q_mvar", max_q_mvar)
1555 +
    _add_series_to_entries(entries, index, "min_vm_pu", min_vm_pu)
1556 +
    _add_series_to_entries(entries, index, "max_vm_pu", max_vm_pu)
1557 +
    _add_series_to_entries(entries, index, "vn_kv", vn_kv)
1558 +
    _add_series_to_entries(entries, index, "cos_phi", cos_phi)
1559 +
    _add_series_to_entries(entries, index, "xdss_pu", xdss_pu)
1560 +
    _add_series_to_entries(entries, index, "rdss_pu", rdss_pu)
1561 +
    _add_series_to_entries(entries, index, "controllable", controllable, dtyp=bool_,
1562 +
                           default_val=False)
1838 1563
1839 -
    _preserve_dtypes(net.gen, dtypes)
1564 +
    _set_multiple_entries(net, "gen", index, **entries, **kwargs)
1840 1565
1841 1566
    return index
1842 1567
1843 -
def create_motor(net, bus, pn_mech_mw, cos_phi, efficiency_percent=100.,
1844 -
                 loading_percent=100., name=None, lrc_pu=nan, scaling=1.0,
1845 -
				 vn_kv=nan, rx=nan, index=None, in_service=True,
1846 -
				 cos_phi_n=nan,
1847 -
                 efficiency_n_percent=nan):
1568 +
1569 +
def create_motor(net, bus, pn_mech_mw, cos_phi, efficiency_percent=100., loading_percent=100.,
1570 +
                 name=None, lrc_pu=nan, scaling=1.0, vn_kv=nan, rx=nan, index=None, in_service=True,
1571 +
                 cos_phi_n=nan, efficiency_n_percent=nan):
1848 1572
    """
1849 1573
    Adds a motor to the network.
1850 1574
@@ -1860,17 +1584,20 @@
Loading
1860 1584
1861 1585
    OPTIONAL:
1862 1586
1863 -
		**name** (string, None) - The name for this motor
1587 +
        **name** (string, None) - The name for this motor
1864 1588
1865 1589
        **efficiency_percent** (float, 100) - Efficiency in percent at current operating point
1866 1590
1867 -
        **loading_percent** (float, 100) - The mechanical loading in percentage of the rated mechanical power
1591 +
        **loading_percent** (float, 100) - The mechanical loading in percentage of the rated \
1592 +
            mechanical power
1868 1593
1869 1594
        **scaling** (float, 1.0) - scaling factor which for the active power of the motor
1870 1595
1871 -
		**cos_phi_n** (float, nan) - cosine phi at rated power of the motor for short-circuit calculation
1596 +
        **cos_phi_n** (float, nan) - cosine phi at rated power of the motor for short-circuit \
1597 +
            calculation
1872 1598
1873 -
        **efficiency_n_percent** (float, 100) - Efficiency in percent at rated power for short-circuit calculation
1599 +
        **efficiency_n_percent** (float, 100) - Efficiency in percent at rated power for \
1600 +
            short-circuit calculation
1874 1601
1875 1602
        **lrc_pu** (float, nan) - locked rotor current in relation to the rated motor current
1876 1603
@@ -1887,30 +1614,20 @@
Loading
1887 1614
        **index** (int) - The unique ID of the created motor
1888 1615
1889 1616
    EXAMPLE:
1890 -
        create_motor(net, 1, pn_mech_mw = 0.120, cos_ph=0.9, vn_kv=0.6, efficiency_percent=90, loading_percent=40, lrc_pu=6.0)
1617 +
        create_motor(net, 1, pn_mech_mw = 0.120, cos_ph=0.9, vn_kv=0.6, efficiency_percent=90, \
1618 +
                     loading_percent=40, lrc_pu=6.0)
1891 1619
1892 1620
    """
1893 -
    if bus not in net["bus"].index.values:
1894 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1895 -
1896 -
    if index is None:
1897 -
        index = get_free_id(net["motor"])
1898 -
1899 -
    if index in net["motor"].index:
1900 -
        raise UserWarning("A motor with the id %s already exists" % index)
1621 +
    _check_node_element(net, bus)
1901 1622
1902 -
    # store dtypes
1903 -
    dtypes = net.motor.dtypes
1623 +
    index = _get_index_with_check(net, "motor", index)
1904 1624
1905 1625
    columns = ["name", "bus", "pn_mech_mw", "cos_phi", "cos_phi_n", "vn_kv", "rx",
1906 1626
               "efficiency_n_percent", "efficiency_percent", "loading_percent",
1907 1627
               "lrc_pu", "scaling", "in_service"]
1908 1628
    variables = [name, bus, pn_mech_mw, cos_phi, cos_phi_n, vn_kv, rx, efficiency_n_percent,
1909 1629
                 efficiency_percent, loading_percent, lrc_pu, scaling, bool(in_service)]
1910 -
    net.motor.loc[index, columns] = variables
1911 -
1912 -
    # and preserve dtypes
1913 -
    _preserve_dtypes(net.motor, dtypes)
1630 +
    _set_entries(net, "motor", index, **dict(zip(columns, variables)))
1914 1631
1915 1632
    return index
1916 1633
@@ -1967,108 +1684,51 @@
Loading
1967 1684
1968 1685
        ** only considered in loadflow if calculate_voltage_angles = True
1969 1686
1970 -
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for the ext_grid in OPF.
1971 -
                                             The voltage limits set in the ext_grid bus are enforced.
1972 -
                                       False: p_mw and vm_pu setpoints are enforced and *limits are ignored*.
1973 -
                                              The vm_pu setpoint is enforced and limits of the bus table are ignored.
1974 -
                                       defaults to False if "controllable" column exists in DataFrame
1687 +
        **controllable** (bool, NaN) - True: p_mw, q_mvar and vm_pu limits are enforced for the \
1688 +
                                             ext_grid in OPF. The voltage limits set in the \
1689 +
                                             ext_grid bus are enforced.
1690 +
                                       False: p_mw and vm_pu setpoints are enforced and *limits are\
1691 +
                                              ignored*. The vm_pu setpoint is enforced and limits \
1692 +
                                              of the bus table are ignored.
1693 +
                                       defaults to False if "controllable" column exists in\
1694 +
                                       DataFrame
1975 1695
1976 1696
    EXAMPLE:
1977 1697
        create_ext_grid(net, 1, voltage = 1.03)
1978 1698
1979 1699
        For three phase load flow
1980 1700
1981 -
        create_ext_grid(net, 1, voltage = 1.03,s_sc_max_mva= 1000, rx_max=0.1,r0x0_max=0.1,x0x_max= 1.0 )
1701 +
        create_ext_grid(net, 1, voltage=1.03, s_sc_max_mva=1000, rx_max=0.1, r0x0_max=0.1,\
1702 +
                       x0x_max=1.0)
1982 1703
    """
1983 -
    if bus not in net["bus"].index.values:
1984 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
1704 +
    _check_node_element(net, bus)
1985 1705
1986 -
    if index is not None and index in net["ext_grid"].index:
1987 -
        raise UserWarning("An external grid with with index %s already exists" % index)
1706 +
    index = _get_index_with_check(net, "ext_grid", index, name="external grid")
1988 1707
1989 -
    if index is None:
1990 -
        index = get_free_id(net["ext_grid"])
1991 -
1992 -
    # store dtypes
1993 -
    dtypes = net.ext_grid.dtypes
1708 +
    entries = dict(zip(["bus", "name", "vm_pu", "va_degree", "in_service"],
1709 +
                       [bus, name, vm_pu, va_degree, bool(in_service)]))
1710 +
    _set_entries(net, "ext_grid", index, **entries, **kwargs)
1994 1711
1995 1712
    # OPF limits
1996 -
    if not isnan(controllable):
1997 -
        if "controllable" not in net.ext_grid.columns:
1998 -
            net.ext_grid.loc[:, "controllable"] = False
1999 -
        net.ext_grid.at[index, "controllable"] = bool(controllable)
2000 -
    elif "controllable" in net.ext_grid.columns:
2001 -
        net.ext_grid.at[index, "controllable"] = False
2002 -
2003 -
2004 -
    net.ext_grid.loc[index, ["bus", "name", "vm_pu", "va_degree", "in_service"]] = \
2005 -
        [bus, name, vm_pu, va_degree, bool(in_service)]
2006 -
2007 -
    if not isnan(s_sc_max_mva):
2008 -
        if "s_sc_max_mva" not in net.ext_grid.columns:
2009 -
            net.ext_grid.loc[:, "s_sc_max_mva"] = pd.Series()
2010 -
2011 -
        net.ext_grid.at[index, "s_sc_max_mva"] = float(s_sc_max_mva)
2012 -
2013 -
    if not isnan(s_sc_min_mva):
2014 -
        if "s_sc_min_mva" not in net.ext_grid.columns:
2015 -
            net.ext_grid.loc[:, "s_sc_min_mva"] = pd.Series()
2016 -
2017 -
        net.ext_grid.at[index, "s_sc_min_mva"] = float(s_sc_min_mva)
2018 -
2019 -
    if not isnan(rx_min):
2020 -
        if "rx_min" not in net.ext_grid.columns:
2021 -
            net.ext_grid.loc[:, "rx_min"] = pd.Series()
2022 -
2023 -
        net.ext_grid.at[index, "rx_min"] = float(rx_min)
2024 -
2025 -
    if not isnan(rx_max):
2026 -
        if "rx_max" not in net.ext_grid.columns:
2027 -
            net.ext_grid.loc[:, "rx_max"] = pd.Series()
1713 +
    _create_column_and_set_value(net, index, s_sc_max_mva, "s_sc_max_mva", "ext_grid")
1714 +
    _create_column_and_set_value(net, index, s_sc_min_mva, "s_sc_min_mva", "ext_grid")
1715 +
    _create_column_and_set_value(net, index, rx_min, "rx_min", "ext_grid")
1716 +
    _create_column_and_set_value(net, index, rx_max, "rx_max", "ext_grid")
1717 +
    _create_column_and_set_value(net, index, min_p_mw, "min_p_mw", "ext_grid")
1718 +
    _create_column_and_set_value(net, index, max_p_mw, "max_p_mw", "ext_grid")
1719 +
    _create_column_and_set_value(net, index, min_q_mvar, "min_q_mvar", "ext_grid")
1720 +
    _create_column_and_set_value(net, index, max_q_mvar, "max_q_mvar", "ext_grid")
1721 +
    _create_column_and_set_value(net, index, x0x_max, "x0x_max", "ext_grid")
1722 +
    _create_column_and_set_value(net, index, r0x0_max, "r0x0_max", "ext_grid")
1723 +
    _create_column_and_set_value(net, index, controllable, "controllable", "ext_grid",
1724 +
                                 dtyp=bool_, default_val=False, default_for_nan=True)
2028 1725
2029 -
        net.ext_grid.at[index, "rx_max"] = float(rx_max)
2030 -
2031 -
    if not isnan(min_p_mw):
2032 -
        if "min_p_mw" not in net.ext_grid.columns:
2033 -
            net.ext_grid.loc[:, "min_p_mw"] = pd.Series()
2034 -
2035 -
        net.ext_grid.loc[index, "min_p_mw"] = float(min_p_mw)
2036 -
2037 -
    if not isnan(max_p_mw):
2038 -
        if "max_p_mw" not in net.ext_grid.columns:
2039 -
            net.ext_grid.loc[:, "max_p_mw"] = pd.Series()
2040 -
2041 -
        net.ext_grid.loc[index, "max_p_mw"] = float(max_p_mw)
2042 -
2043 -
    if not isnan(min_q_mvar):
2044 -
        if "min_q_mvar" not in net.ext_grid.columns:
2045 -
            net.ext_grid.loc[:, "min_q_mvar"] = pd.Series()
2046 -
2047 -
        net.ext_grid.loc[index, "min_q_mvar"] = float(min_q_mvar)
2048 -
2049 -
    if not isnan(max_q_mvar):
2050 -
        if "max_q_mvar" not in net.ext_grid.columns:
2051 -
            net.ext_grid.loc[:, "max_q_mvar"] = pd.Series()
2052 -
2053 -
        net.ext_grid.loc[index, "max_q_mvar"] = float(max_q_mvar)
2054 -
    if not isnan(x0x_max):
2055 -
        if "x0x_max" not in net.ext_grid.columns:
2056 -
            net.ext_grid.loc[:, "x0x_max"] = pd.Series()
2057 -
2058 -
        net.ext_grid.loc[index, "x0x_max"] = float(x0x_max)
2059 -
    if not isnan(r0x0_max):
2060 -
        if "r0x0_max" not in net.ext_grid.columns:
2061 -
            net.ext_grid.loc[:, "r0x0_max"] = pd.Series()
2062 -
2063 -
        net.ext_grid.loc[index, "r0x0_max"] = float(r0x0_max)
2064 -
        # and preserve dtypes
2065 -
    _preserve_dtypes(net.ext_grid, dtypes)
2066 1726
    return index
2067 1727
2068 1728
2069 1729
def create_line(net, from_bus, to_bus, length_km, std_type, name=None, index=None, geodata=None,
2070 -
                df=1., parallel=1, in_service=True, max_loading_percent=nan, alpha=None,
2071 -
                temperature_degree_celsius=None):
1730 +
                df=1., parallel=1, in_service=True, max_loading_percent=nan, alpha=nan,
1731 +
                temperature_degree_celsius=nan):
2072 1732
    """
2073 1733
    Creates a line element in net["line"]
2074 1734
    The line parameters are defined through the standard type library.
@@ -2105,7 +1765,7 @@
Loading
2105 1765
2106 1766
        **in_service** (boolean, True) - True for in_service or False for out of service
2107 1767
2108 -
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current \
1768 +
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current\
2109 1769
            of line (from 0 to 1)
2110 1770
2111 1771
        **parallel** (integer, 1) - number of parallel line systems
@@ -2121,15 +1781,9 @@
Loading
2121 1781
    """
2122 1782
2123 1783
    # check if bus exist to attach the line to
2124 -
    for b in [from_bus, to_bus]:
2125 -
        if b not in net["bus"].index.values:
2126 -
            raise UserWarning("Line %s tries to attach to non-existing bus %s" % (name, b))
2127 -
2128 -
    if index is None:
2129 -
        index = get_free_id(net["line"])
1784 +
    _check_branch_element(net, "Line", index, from_bus, to_bus)
2130 1785
2131 -
    if index in net["line"].index:
2132 -
        raise UserWarning("A line with index %s already exists" % index)
1786 +
    index = _get_index_with_check(net, "line", index)
2133 1787
2134 1788
    v = {
2135 1789
        "name": name, "length_km": length_km, "from_bus": from_bus,
@@ -2138,12 +1792,9 @@
Loading
2138 1792
    }
2139 1793
2140 1794
    lineparam = load_std_type(net, std_type, "line")
2141 -
    v.update({
2142 -
        "r_ohm_per_km": lineparam["r_ohm_per_km"],
2143 -
        "x_ohm_per_km": lineparam["x_ohm_per_km"],
2144 -
        "c_nf_per_km": lineparam["c_nf_per_km"],
2145 -
        "max_i_ka": lineparam["max_i_ka"]
2146 -
    })
1795 +
1796 +
    v.update({param: lineparam[param] for param in ["r_ohm_per_km", "x_ohm_per_km", "c_nf_per_km",
1797 +
                                                    "max_i_ka"]})
2147 1798
    v["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
2148 1799
2149 1800
    if "type" in lineparam:
@@ -2153,47 +1804,104 @@
Loading
2153 1804
    if "alpha" in net.line.columns and "alpha" in lineparam:
2154 1805
        v["alpha"] = lineparam["alpha"]
2155 1806
2156 -
    # store dtypes
2157 -
    dtypes = net.line.dtypes
1807 +
    _set_entries(net, "line", index, **v)
1808 +
1809 +
    if geodata is not None:
1810 +
        net["line_geodata"].loc[index, "coords"] = None
1811 +
        net["line_geodata"].at[index, "coords"] = geodata
1812 +
1813 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
1814 +
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
1815 +
    _create_column_and_set_value(net, index, temperature_degree_celsius,
1816 +
                                 "temperature_degree_celsius", "line")
1817 +
1818 +
    return index
1819 +
1820 +
1821 +
def create_lines(net, from_buses, to_buses, length_km, std_type, name=None, index=None,
1822 +
                 geodata=None, df=1., parallel=1, in_service=True, max_loading_percent=None):
1823 +
    """ Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
1824 +
        must be arrays of equal length. Other parameters may be either arrays of the same length or
1825 +
        single or values. In any case the line parameters are defined through a single standard
1826 +
        type, so all lines have the same standard type.
1827 +
1828 +
1829 +
        INPUT:
1830 +
            **net** - The net within this line should be created
1831 +
1832 +
            **from_buses** (list of int) - ID of the bus on one side which the line will be \
1833 +
                connected with
1834 +
1835 +
            **to_buses** (list of int) - ID of the bus on the other side which the line will be \
1836 +
                connected with
1837 +
1838 +
            **length_km** (list of float) - The line length in km
1839 +
1840 +
            **std_type** (string) - The linetype of the lines.
1841 +
1842 +
        OPTIONAL:
1843 +
            **name** (list of string, None) - A custom name for this line
1844 +
1845 +
            **index** (list of int, None) - Force a specified ID if it is available. If None, the\
1846 +
                index one higher than the highest already existing index is selected.
1847 +
1848 +
            **geodata**
1849 +
            (list of arrays, default None, shape of arrays (,2L)) -
1850 +
            The linegeodata of the line. The first row should be the coordinates
1851 +
            of bus a and the last should be the coordinates of bus b. The points
1852 +
            in the middle represent the bending points of the line
1853 +
1854 +
            **in_service** (list of boolean, True) - True for in_service or False for out of service
1855 +
1856 +
            **df** (list of float, 1) - derating factor: maximal current of line in relation to \
1857 +
                nominal current of line (from 0 to 1)
1858 +
1859 +
            **parallel** (list of integer, 1) - number of parallel line systems
1860 +
1861 +
            **max_loading_percent (list of float)** - maximum current loading (only needed for OPF)
1862 +
1863 +
        OUTPUT:
1864 +
            **index** (list of int) - The unique ID of the created line
2158 1865
2159 -
    net.line.loc[index, list(v.keys())] = list(v.values())
1866 +
        EXAMPLE:
1867 +
            create_line(net, "line1", from_bus=0, to_bus=1, length_km=0.1, std_type="NAYY 4x50 SE")
2160 1868
2161 -
    # and preserve dtypes
2162 -
    _preserve_dtypes(net.line, dtypes)
1869 +
    """
1870 +
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
2163 1871
2164 -
    if geodata is not None:
2165 -
        net["line_geodata"].loc[index, "coords"] = None
2166 -
        net["line_geodata"].at[index, "coords"] = geodata
1872 +
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
2167 1873
2168 -
    if not isnan(max_loading_percent):
2169 -
        if "max_loading_percent" not in net.line.columns:
2170 -
            net.line.loc[:, "max_loading_percent"] = pd.Series()
1874 +
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km,
1875 +
               "std_type": std_type, "name": name, "df": df, "parallel": parallel,
1876 +
               "in_service": in_service}
2171 1877
2172 -
        net.line.loc[index, "max_loading_percent"] = float(max_loading_percent)
1878 +
    # add std type data
1879 +
    lineparam = load_std_type(net, std_type, "line")
1880 +
    entries["r_ohm_per_km"] = lineparam["r_ohm_per_km"]
1881 +
    entries["x_ohm_per_km"] = lineparam["x_ohm_per_km"]
1882 +
    entries["c_nf_per_km"] = lineparam["c_nf_per_km"]
1883 +
    entries["max_i_ka"] = lineparam["max_i_ka"]
1884 +
    entries["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
1885 +
    if "type" in lineparam:
1886 +
        entries["type"] = lineparam["type"]
1887 +
1888 +
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2173 1889
2174 -
    if alpha is not None:
2175 -
        if "alpha" not in net.line.columns:
2176 -
            net.line.loc[:, "alpha"] = pd.Series()
2177 -
        net.line.loc[index, "alpha"] = alpha
1890 +
    _set_multiple_entries(net, "line", index, **entries)
2178 1891
2179 -
    if temperature_degree_celsius is not None:
2180 -
        if "temperature_degree_celsius" not in net.line.columns:
2181 -
            net.line.loc[:, "temperature_degree_celsius"] = pd.Series()
2182 -
        net.line.loc[index, "temperature_degree_celsius"] = temperature_degree_celsius
1892 +
    if geodata is not None:
1893 +
        _add_multiple_branch_geodata(net, "line", geodata, index)
2183 1894
2184 1895
    return index
2185 1896
2186 1897
2187 1898
def create_line_from_parameters(net, from_bus, to_bus, length_km, r_ohm_per_km, x_ohm_per_km,
2188 -
                                c_nf_per_km, max_i_ka,
2189 -
                                name=None, index=None, type=None,
2190 -
                                geodata=None, in_service=True, df=1.,
2191 -
                                parallel=1, g_us_per_km=0.,
2192 -
                                max_loading_percent=nan, alpha=None,
2193 -
                                temperature_degree_celsius=None,
2194 -
                                r0_ohm_per_km=nan, x0_ohm_per_km=nan,
2195 -
                                c0_nf_per_km=nan, g0_us_per_km=0,
2196 -
                                endtemp_degree=None, **kwargs):
1899 +
                                c_nf_per_km, max_i_ka, name=None, index=None, type=None,
1900 +
                                geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
1901 +
                                max_loading_percent=nan, alpha=nan,
1902 +
                                temperature_degree_celsius=nan, r0_ohm_per_km=nan,
1903 +
                                x0_ohm_per_km=nan, c0_nf_per_km=nan, g0_us_per_km=0,
1904 +
                                endtemp_degree=nan, **kwargs):
2197 1905
    """
2198 1906
    Creates a line element in net["line"] from line parameters.
2199 1907
@@ -2230,7 +1938,7 @@
Loading
2230 1938
2231 1939
        **type** (str, None) - type of line ("ol" for overhead line or "cs" for cable system)
2232 1940
2233 -
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current \
1941 +
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current\
2234 1942
            of line (from 0 to 1)
2235 1943
2236 1944
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
@@ -2258,18 +1966,10 @@
Loading
2258 1966
    """
2259 1967
2260 1968
    # check if bus exist to attach the line to
2261 -
    for b in [from_bus, to_bus]:
2262 -
        if b not in net["bus"].index.values:
2263 -
            raise UserWarning("Line %s tries to attach to non-existing bus %s"
2264 -
                              % (name, b))
1969 +
    _check_branch_element(net, "Line", index, from_bus, to_bus)
2265 1970
2266 -
    if index is None:
2267 -
        index = get_free_id(net["line"])
2268 -
    if index in net["line"].index:
2269 -
        raise UserWarning("A line with index %s already exists" % index)
1971 +
    index = _get_index_with_check(net, "line", index)
2270 1972
2271 -
    # store dtypes
2272 -
    dtypes = net.line.dtypes
2273 1973
    v = {
2274 1974
        "name": name, "length_km": length_km, "from_bus": from_bus,
2275 1975
        "to_bus": to_bus, "in_service": bool(in_service), "std_type": None,
@@ -2278,62 +1978,39 @@
Loading
2278 1978
        "g_us_per_km": g_us_per_km
2279 1979
    }
2280 1980
2281 -
    net.line.loc[index, list(v.keys())] = list(v.values())
2282 -
2283 -
    if not (isnan(r0_ohm_per_km) and isnan(x0_ohm_per_km) and isnan(c0_nf_per_km)):
2284 -
        if "r0_ohm_per_km" not in net.line.columns:
2285 -
            net.line.loc[:, "r0_ohm_per_km"] = pd.Series()
1981 +
    _set_entries(net, "line", index, **v, **kwargs)
2286 1982
2287 -
        net.line.loc[index, "r0_ohm_per_km"] = float(r0_ohm_per_km)
2288 -
        if "x0_ohm_per_km" not in net.line.columns:
2289 -
            net.line.loc[:, "x0_ohm_per_km"] = pd.Series()
2290 -
2291 -
        net.line.loc[index, "x0_ohm_per_km"] = float(x0_ohm_per_km)
2292 -
        if "c0_nf_per_km" not in net.line.columns:
2293 -
            net.line.loc[:, "c0_nf_per_km"] = pd.Series()
2294 -
2295 -
        net.line.loc[index, "c0_nf_per_km"] = float(c0_nf_per_km)
2296 -
2297 -
    # and preserve dtypes
2298 -
    _preserve_dtypes(net.line, dtypes)
1983 +
    nan_0_values = [isnan(r0_ohm_per_km), isnan(x0_ohm_per_km), isnan(c0_nf_per_km)]
1984 +
    if not np_any(nan_0_values):
1985 +
        _create_column_and_set_value(net, index, r0_ohm_per_km, "r0_ohm_per_km", "line")
1986 +
        _create_column_and_set_value(net, index, x0_ohm_per_km, "x0_ohm_per_km", "line")
1987 +
        _create_column_and_set_value(net, index, c0_nf_per_km, "c0_nf_per_km", "line")
1988 +
        _create_column_and_set_value(net, index, g0_us_per_km, "g0_us_per_km", "line",
1989 +
                                     default_val=0.)
1990 +
    elif not np_all(nan_0_values):
1991 +
        logger.warning("Zero sequence values are given for only some parameters. Please specify "
1992 +
                       "them for all parameters, otherwise they are not set!")
2299 1993
2300 1994
    if geodata is not None:
2301 1995
        net["line_geodata"].loc[index, "coords"] = None
2302 1996
        net["line_geodata"].at[index, "coords"] = geodata
2303 1997
2304 -
    if not isnan(max_loading_percent):
2305 -
        if "max_loading_percent" not in net.line.columns:
2306 -
            net.line.loc[:, "max_loading_percent"] = pd.Series()
2307 -
2308 -
        net.line.loc[index, "max_loading_percent"] = float(max_loading_percent)
2309 -
2310 -
    if alpha is not None:
2311 -
        if "alpha" not in net.line.columns:
2312 -
            net.line.loc[:, "alpha"] = pd.Series()
2313 -
        net.line.loc[index, "alpha"] = alpha
2314 -
2315 -
    if temperature_degree_celsius is not None:
2316 -
        if "temperature_degree_celsius" not in net.line.columns:
2317 -
            net.line.loc[:, "temperature_degree_celsius"] = pd.Series()
2318 -
        net.line.loc[index, "temperature_degree_celsius"] = temperature_degree_celsius
2319 -
2320 -
    if endtemp_degree is not None:
2321 -
        if "endtemp_degree" not in net.line.columns:
2322 -
            net.line.loc[:, "endtemp_degree"] = pd.Series()
2323 -
        net.line.loc[index, "endtemp_degree"] = endtemp_degree
1998 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "line")
1999 +
    _create_column_and_set_value(net, index, alpha, "alpha", "line")
2000 +
    _create_column_and_set_value(net, index, temperature_degree_celsius,
2001 +
                                 "temperature_degree_celsius", "line")
2002 +
    _create_column_and_set_value(net, index, endtemp_degree, "endtemp_degree", "line")
2324 2003
2325 2004
    return index
2326 2005
2327 2006
2328 2007
def create_lines_from_parameters(net, from_buses, to_buses, length_km, r_ohm_per_km, x_ohm_per_km,
2329 -
                                 c_nf_per_km, max_i_ka,
2330 -
                                 name=None, index=None, type=None,
2331 -
                                 geodata=None, in_service=True, df=1.,
2332 -
                                 parallel=1, g_us_per_km=0.,
2008 +
                                 c_nf_per_km, max_i_ka, name=None, index=None, type=None,
2009 +
                                 geodata=None, in_service=True, df=1., parallel=1, g_us_per_km=0.,
2333 2010
                                 max_loading_percent=None, alpha=None,
2334 -
                                 temperature_degree_celsius=None,
2335 -
                                 r0_ohm_per_km=None, x0_ohm_per_km=None,
2336 -
                                 c0_nf_per_km=None, g0_us_per_km=None, **kwargs):
2011 +
                                 temperature_degree_celsius=None, r0_ohm_per_km=None,
2012 +
                                 x0_ohm_per_km=None, c0_nf_per_km=None, g0_us_per_km=None,
2013 +
                                 **kwargs):
2337 2014
    """
2338 2015
    Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
2339 2016
        must be arrays of equal length. Other parameters may be either arrays of the same length or
@@ -2344,7 +2021,8 @@
Loading
2344 2021
2345 2022
        **from_bus** (list of int) - ID of the bus on one side which the line will be connected with
2346 2023
2347 -
        **to_bus** (list of int) - ID of the bus on the other side which the line will be connected with
2024 +
        **to_bus** (list of int) - ID of the bus on the other side which the line will be connected\
2025 +
            with
2348 2026
2349 2027
        **length_km** (list of float) - The line length in km
2350 2028
@@ -2372,7 +2050,7 @@
Loading
2372 2050
2373 2051
        **type** (str, None) - type of line ("ol" for overhead line or "cs" for cable system)
2374 2052
2375 -
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current \
2053 +
        **df** (float, 1) - derating factor: maximal current of line in relation to nominal current\
2376 2054
            of line (from 0 to 1)
2377 2055
2378 2056
        **g_us_per_km** (float, 0) - dielectric conductance in micro Siemens per km
@@ -2398,224 +2076,27 @@
Loading
2398 2076
        max_i_ka = 0.4)
2399 2077
2400 2078
    """
2401 -
    nr_lines = len(from_buses)
2402 -
    if index is not None:
2403 -
        if any(isin(index, net.line.index)):
2404 -
            index_in = set(index) & set(net.line.index)
2405 -
            raise UserWarning("Lines with indexes %s already exists" % index_in)
2406 -
    else:
2407 -
        lid = get_free_id(net["line"])
2408 -
        index = arange(lid, lid + nr_lines, 1)
2409 -
2410 -
    if not(all(isin(from_buses, net.bus.index))) > 0:
2411 -
        bus_not_exist = set(from_buses) - set(net.bus.index)
2412 -
        raise UserWarning("Lines trying to attach to non existing buses %s" % bus_not_exist)
2413 -
    if not(all(isin(to_buses, net.bus.index))) > 0:
2414 -
        bus_not_exist = set(to_buses) - set(net.bus.index)
2415 -
        raise UserWarning("Lines trying to attach to non existing buses %s" % bus_not_exist)
2416 -
2417 -
    dtypes = net.line.dtypes
2418 -
2419 -
    dd = pd.DataFrame(index=index, columns=net.line.columns)
2420 -
2421 -
    # user defined params
2422 -
    dd["from_bus"] = from_buses
2423 -
    dd["to_bus"] = to_buses
2424 -
    dd["length_km"] = length_km
2425 -
    dd["type"] = type
2426 -
    dd["r_ohm_per_km"] = r_ohm_per_km
2427 -
    dd["x_ohm_per_km"] = x_ohm_per_km
2428 -
    dd["c_nf_per_km"] = c_nf_per_km
2429 -
    dd["max_i_ka"] = max_i_ka
2430 -
    dd["g_us_per_km"] = g_us_per_km
2431 -
2432 -
    # optional params
2433 -
    dd["name"] = name
2434 -
    dd["df"] = df
2435 -
    dd["parallel"] = parallel
2436 -
    dd["in_service"] = in_service
2437 -
2438 -
    if r0_ohm_per_km is not None:
2439 -
        dd["r0_ohm_per_km"] = r0_ohm_per_km
2440 -
        dd["r0_ohm_per_km"] = dd["r0_ohm_per_km"].astype(float)
2441 -
2442 -
    if x0_ohm_per_km is not None:
2443 -
        dd["x0_ohm_per_km"] = x0_ohm_per_km
2444 -
        dd["x0_ohm_per_km"] = dd["x0_ohm_per_km"].astype(float)
2445 -
2446 -
    if c0_nf_per_km is not None:
2447 -
        dd["c0_nf_per_km"] = c0_nf_per_km
2448 -
        dd["c0_nf_per_km"] = dd["c0_nf_per_km"].astype(float)
2449 -
2450 -
    if g0_us_per_km is not None:
2451 -
        dd["g0_us_per_km"] = g0_us_per_km
2452 -
        dd["g0_us_per_km"] = dd["g0_us_per_km"].astype(float)
2453 -
2454 -
    if max_loading_percent is not None:
2455 -
        dd["max_loading_percent"] = max_loading_percent
2456 -
        dd["max_loading_percent"] = dd["max_loading_percent"].astype(float)
2457 -
2458 -
    if temperature_degree_celsius is not None:
2459 -
        dd["temperature_degree_celsius"] = temperature_degree_celsius
2460 -
        dd["temperature_degree_celsius"] = dd["temperature_degree_celsius"].astype(float)
2461 -
2462 -
    if alpha is not None:
2463 -
        dd["alpha"] = alpha
2464 -
        dd["alpha"] = dd["alpha"].astype(float)
2465 -
2466 -
    dd = dd.assign(**kwargs)
2467 -
2468 -
    # extend the lines by the frame we just created
2469 -
    if version.parse(pd.__version__) >= version.parse("0.23"):
2470 -
        net["line"] = net["line"].append(dd, sort=False)
2471 -
    else:
2472 -
        # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
2473 -
        net["line"] = net["line"].append(dd)
2474 -
2475 -
    _preserve_dtypes(net.line, dtypes)
2476 -
2477 -
    if geodata is not None:
2478 -
        dtypes = net.line_geodata.dtypes
2479 -
        df = pd.DataFrame(index=index, columns=net.line_geodata.columns)
2480 -
        # works with single or multiple lists of coordinates
2481 -
        if len(geodata[0]) == 2 and not hasattr(geodata[0][0], "__iter__"):
2482 -
            # geodata is a single list of coordinates
2483 -
            df["coords"] = [geodata] * len(index)
2484 -
        else:
2485 -
            # geodata is multiple lists of coordinates
2486 -
            df["coords"] = geodata
2487 -
2488 -
        if version.parse(pd.__version__) >= version.parse("0.23"):
2489 -
            net.line_geodata = net.line_geodata.append(df, sort=False)
2490 -
        else:
2491 -
            # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
2492 -
            net.line_geodata = net.line_geodata.append(df)
2493 -
2494 -
        _preserve_dtypes(net.line_geodata, dtypes)
2495 -
2496 -
    return index
2497 -
2498 -
2499 -
def create_lines(net, from_buses, to_buses, length_km, std_type, name=None, index=None, geodata=None,
2500 -
                 df=1., parallel=1, in_service=True, max_loading_percent=nan):
2501 -
    """ Convenience function for creating many lines at once. Parameters 'from_buses' and 'to_buses'
2502 -
        must be arrays of equal length. Other parameters may be either arrays of the same length or
2503 -
        single or values. In any case the line parameters are defined through a single standard
2504 -
        type, so all lines have the same standard type.
2505 -
2506 -
2507 -
        INPUT:
2508 -
            **net** - The net within this line should be created
2509 -
2510 -
            **from_buses** (list of int) - ID of the bus on one side which the line will be connected with
2511 -
2512 -
            **to_buses** (list of int) - ID of the bus on the other side which the line will be connected with
2513 -
2514 -
            **length_km** (list of float) - The line length in km
2515 -
2516 -
            **std_type** (string) - The linetype of the lines.
2517 -
2518 -
        OPTIONAL:
2519 -
            **name** (list of string, None) - A custom name for this line
2520 -
2521 -
            **index** (list of int, None) - Force a specified ID if it is available. If None, the index one \
2522 -
                higher than the highest already existing index is selected.
2523 -
2524 -
            **geodata**
2525 -
            (list of arrays, default None, shape of arrays (,2L)) -
2526 -
            The linegeodata of the line. The first row should be the coordinates
2527 -
            of bus a and the last should be the coordinates of bus b. The points
2528 -
            in the middle represent the bending points of the line
2529 -
2530 -
            **in_service** (list of boolean, True) - True for in_service or False for out of service
2531 -
2532 -
            **df** (list of float, 1) - derating factor: maximal current of line in relation to nominal current \
2533 -
                of line (from 0 to 1)
2534 -
2535 -
            **parallel** (list of integer, 1) - number of parallel line systems
2536 -
2537 -
            **max_loading_percent (list of float)** - maximum current loading (only needed for OPF)
2538 -
2539 -
        OUTPUT:
2540 -
            **index** (list of int) - The unique ID of the created line
2541 -
2542 -
        EXAMPLE:
2543 -
            create_line(net, "line1", from_bus = 0, to_bus = 1, length_km=0.1,  std_type="NAYY 4x50 SE")
2544 -
2545 -
    """
2546 -
2547 -
    nr_lines = len(from_buses)
2548 -
    if index is not None:
2549 -
        for idx in index:
2550 -
            if idx in net.line.index:
2551 -
                raise UserWarning("A line with index %s already exists" % index)
2552 -
    else:
2553 -
        lid = get_free_id(net["line"])
2554 -
        index = arange(lid, lid + nr_lines, 1)
2555 -
2556 -
    dtypes = net.line.dtypes
2079 +
    _check_multiple_branch_elements(net, from_buses, to_buses, "Lines")
2557 2080
2558 -
    dd = pd.DataFrame(index=index, columns=net.line.columns)
2081 +
    index = _get_multiple_index_with_check(net, "line", index, len(from_buses))
2559 2082
2560 -
    # user defined params
2561 -
    dd["from_bus"] = from_buses
2562 -
    dd["to_bus"] = to_buses
2563 -
    dd["length_km"] = length_km
2564 -
    dd["std_type"] = std_type
2083 +
    entries = {"from_bus": from_buses, "to_bus": to_buses, "length_km": length_km, "type": type,
2084 +
               "r_ohm_per_km": r_ohm_per_km, "x_ohm_per_km": x_ohm_per_km,
2085 +
               "c_nf_per_km": c_nf_per_km, "max_i_ka": max_i_ka, "g_us_per_km": g_us_per_km,
2086 +
               "name": name, "df": df, "parallel": parallel, "in_service": in_service}
2565 2087
2566 -
    # add std type data
2567 -
    lineparam = load_std_type(net, std_type, "line")
2568 -
    dd["r_ohm_per_km"] = lineparam["r_ohm_per_km"]
2569 -
    dd["x_ohm_per_km"] = lineparam["x_ohm_per_km"]
2570 -
    dd["c_nf_per_km"] = lineparam["c_nf_per_km"]
2571 -
    dd["max_i_ka"] = lineparam["max_i_ka"]
2572 -
    dd["g_us_per_km"] = lineparam["g_us_per_km"] if "g_us_per_km" in lineparam else 0.
2573 -
    if "type" in lineparam:
2574 -
        dd["type"] = lineparam["type"]
2575 -
2576 -
    # optional params
2577 -
    dd["name"] = name
2578 -
    dd["df"] = df
2579 -
    dd["parallel"] = parallel
2580 -
    dd["in_service"] = in_service
2581 -
2582 -
    # extend the lines by the frame we just created
2583 -
    if version.parse(pd.__version__) >= version.parse("0.23"):
2584 -
        net["line"] = net["line"].append(dd, sort=False)
2585 -
    else:
2586 -
        # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
2587 -
        net["line"] = net["line"].append(dd)
2088 +
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2089 +
    _add_series_to_entries(entries, index, "r0_ohm_per_km", r0_ohm_per_km)
2090 +
    _add_series_to_entries(entries, index, "x0_ohm_per_km", x0_ohm_per_km)
2091 +
    _add_series_to_entries(entries, index, "c0_nf_per_km", c0_nf_per_km)
2092 +
    _add_series_to_entries(entries, index, "g0_us_per_km", g0_us_per_km)
2093 +
    _add_series_to_entries(entries, index, "temperature_degree_celsius", temperature_degree_celsius)
2094 +
    _add_series_to_entries(entries, index, "alpha", alpha)
2588 2095
2589 -
    if hasattr(max_loading_percent, "__iter__"):
2590 -
        if "max_loading_percent" not in net.line.columns:
2591 -
            net.line["max_loading_percent"] = pd.Series(index=net.line.index)
2592 -
        net.line.loc[index, "max_loading_percent"] = [0 if isnan(ml) else float(ml) for ml in max_loading_percent]
2593 -
    else:
2594 -
        if not isnan(max_loading_percent):
2595 -
            if "max_loading_percent" not in net.line.columns:
2596 -
                net.line["max_loading_percent"] = pd.Series(index=net.line.index)
2597 -
            net.line.loc[index, "max_loading_percent"] = max_loading_percent
2598 -
2599 -
    _preserve_dtypes(net.line, dtypes)
2096 +
    _set_multiple_entries(net, "line", index, **entries, **kwargs)
2600 2097
2601 2098
    if geodata is not None:
2602 -
        dtypes = net.line_geodata.dtypes
2603 -
        df = pd.DataFrame(index=index, columns=net.line_geodata.columns)
2604 -
        # works with single or multiple lists of coordinates
2605 -
        if len(geodata[0]) == 2 and not hasattr(geodata[0][0], "__iter__"):
2606 -
            # geodata is a single list of coordinates
2607 -
            df["coords"] = [geodata] * len(index)
2608 -
        else:
2609 -
            # geodata is multiple lists of coordinates
2610 -
            df["coords"] = geodata
2611 -
2612 -
        if version.parse(pd.__version__) >= version.parse("0.23"):
2613 -
            net.line_geodata = net.line_geodata.append(df, sort=False)
2614 -
        else:
2615 -
            # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
2616 -
            net.line_geodata = net.line_geodata.append(df)
2617 -
2618 -
        _preserve_dtypes(net.line_geodata, dtypes)
2099 +
        _add_multiple_branch_geodata(net, "line", geodata, index)
2619 2100
2620 2101
    return index
2621 2102
@@ -2678,12 +2159,12 @@
Loading
2678 2159
    """
2679 2160
2680 2161
    # Check if bus exist to attach the trafo to
2681 -
    for b in [hv_bus, lv_bus]:
2682 -
        if b not in net["bus"].index.values:
2683 -
            raise UserWarning("Trafo tries to attach to bus %s" % b)
2162 +
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2163 +
2164 +
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2684 2165
2685 2166
    if df <= 0:
2686 -
        raise UserWarning("raiting factor df must be positive: df = %.3f" % df)
2167 +
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2687 2168
2688 2169
    v = {
2689 2170
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
@@ -2691,12 +2172,6 @@
Loading
2691 2172
    }
2692 2173
    ti = load_std_type(net, std_type, "trafo")
2693 2174
2694 -
    if index is None:
2695 -
        index = get_free_id(net["trafo"])
2696 -
2697 -
    if index in net["trafo"].index:
2698 -
        raise UserWarning("A transformer with index %s already exists" % index)
2699 -
2700 2175
    v.update({
2701 2176
        "sn_mva": ti["sn_mva"],
2702 2177
        "vn_hv_kv": ti["vn_hv_kv"],
@@ -2709,48 +2184,38 @@
Loading
2709 2184
        "df": df,
2710 2185
        "shift_degree": ti["shift_degree"] if "shift_degree" in ti else 0,
2711 2186
        "tap_phase_shifter": ti["tap_phase_shifter"] if "tap_phase_shifter" in ti
2712 -
                                                        and pd.notnull(ti["tap_phase_shifter"]) else False
2187 +
                                                        and pd.notnull(
2188 +
            ti["tap_phase_shifter"]) else False
2713 2189
    })
2714 -
    for tp in ("tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent", "tap_step_degree"):
2190 +
    for tp in ("tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent",
2191 +
               "tap_step_degree"):
2715 2192
        if tp in ti:
2716 -
            v.update({tp: ti[tp]})
2193 +
            v[tp] = ti[tp]
2717 2194
    if ("tap_neutral" in v) and (tap_pos is nan):
2718 2195
        v["tap_pos"] = v["tap_neutral"]
2719 2196
    else:
2720 2197
        v["tap_pos"] = tap_pos
2721 2198
        if isinstance(tap_pos, float):
2722 2199
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2723 -
    # store dtypes
2724 -
    dtypes = net.trafo.dtypes
2725 2200
2726 -
    net.trafo.loc[index, list(v.keys())] = list(v.values())
2201 +
    _set_entries(net, "trafo", index, **v)
2727 2202
2728 -
    if not isnan(max_loading_percent):
2729 -
        if "max_loading_percent" not in net.trafo.columns:
2730 -
            net.trafo.loc[:, "max_loading_percent"] = pd.Series()
2731 -
2732 -
        net.trafo.loc[index, "max_loading_percent"] = float(max_loading_percent)
2203 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2733 2204
2734 2205
    # tap_phase_shifter default False
2735 2206
    net.trafo.tap_phase_shifter.fillna(False, inplace=True)
2736 2207
2737 -
    # and preserve dtypes
2738 -
    _preserve_dtypes(net.trafo, dtypes)
2739 -
2740 2208
    return index
2741 2209
2742 2210
2743 -
def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn_lv_kv,
2744 -
                                       vkr_percent, vk_percent, pfe_kw, i0_percent,
2745 -
                                       shift_degree=0,
2746 -
                                       tap_side=None, tap_neutral=nan, tap_max=nan,
2747 -
                                       tap_min=nan, tap_step_percent=nan, tap_step_degree=nan,
2748 -
                                       tap_pos=nan, tap_phase_shifter=False, in_service=True,
2749 -
                                       name=None, vector_group=None, index=None,
2750 -
                                       max_loading_percent=nan, parallel=1,
2751 -
                                       df=1., vk0_percent=nan, vkr0_percent=nan,
2752 -
                                       mag0_percent=nan, mag0_rx=nan,
2753 -
                                       si0_hv_partial=nan, **kwargs):
2211 +
def create_transformer_from_parameters(net, hv_bus, lv_bus, sn_mva, vn_hv_kv, vn_lv_kv, vkr_percent,
2212 +
                                       vk_percent, pfe_kw, i0_percent, shift_degree=0,
2213 +
                                       tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
2214 +
                                       tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2215 +
                                       tap_phase_shifter=False, in_service=True, name=None,
2216 +
                                       vector_group=None, index=None, max_loading_percent=nan,
2217 +
                                       parallel=1, df=1., vk0_percent=nan, vkr0_percent=nan,
2218 +
                                       mag0_percent=nan, mag0_rx=nan, si0_hv_partial=nan, **kwargs):
2754 2219
    """
2755 2220
    Creates a two-winding transformer in table net["trafo"].
2756 2221
    The trafo parameters are defined through the standard type library.
@@ -2809,8 +2274,8 @@
Loading
2809 2274
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2810 2275
            position (tap_neutral)
2811 2276
2812 -
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the ration of \
2813 -
            the rated voltages
2277 +
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the \
2278 +
            ratio of the rated voltages
2814 2279
2815 2280
        **tap_max** (int, nan) - maximal allowed tap position
2816 2281
@@ -2842,23 +2307,16 @@
Loading
2842 2307
    """
2843 2308
2844 2309
    # Check if bus exist to attach the trafo to
2845 -
    for b in [hv_bus, lv_bus]:
2846 -
        if b not in net["bus"].index.values:
2847 -
            raise UserWarning("Trafo tries to attach to bus %s" % b)
2310 +
    _check_branch_element(net, "Trafo", index, hv_bus, lv_bus)
2311 +
2312 +
    index = _get_index_with_check(net, "trafo", index, name="transformer")
2848 2313
2849 2314
    if df <= 0:
2850 2315
        raise UserWarning("derating factor df must be positive: df = %.3f" % df)
2851 2316
2852 -
    if index is None:
2853 -
        index = get_free_id(net["trafo"])
2854 -
2855 -
    if index in net["trafo"].index:
2856 -
        raise UserWarning("A transformer with index %s already exists" % index)
2857 -
2858 2317
    if tap_pos is nan:
2859 2318
        tap_pos = tap_neutral
2860 2319
        # store dtypes
2861 -
    dtypes = net.trafo.dtypes
2862 2320
2863 2321
    v = {
2864 2322
        "name": name, "hv_bus": hv_bus, "lv_bus": lv_bus,
@@ -2866,7 +2324,8 @@
Loading
2866 2324
        "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent, "vkr_percent": vkr_percent,
2867 2325
        "pfe_kw": pfe_kw, "i0_percent": i0_percent, "tap_neutral": tap_neutral,
2868 2326
        "tap_max": tap_max, "tap_min": tap_min, "shift_degree": shift_degree,
2869 -
        "tap_side": tap_side, "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
2327 +
        "tap_side": tap_side, "tap_step_percent": tap_step_percent,
2328 +
        "tap_step_degree": tap_step_degree,
2870 2329
        "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df
2871 2330
    }
2872 2331
@@ -2876,68 +2335,44 @@
Loading
2876 2335
        v["tap_pos"] = tap_pos
2877 2336
        if type(tap_pos) == float:
2878 2337
            net.trafo.tap_pos = net.trafo.tap_pos.astype(float)
2879 -
    net.trafo.loc[index, list(v.keys())] = list(v.values())
2880 -
2881 -
    if not (isnan(vk0_percent) and isnan(vkr0_percent) and isnan(mag0_percent) \
2882 -
            and isnan(mag0_rx) and isnan(si0_hv_partial) and vector_group is None):
2883 -
        if "vk0_percent" not in net.trafo.columns:
2884 -
            net.trafo.loc[:, "vk0_percent"] = pd.Series()
2885 -
2886 -
        net.trafo.loc[index, "vk0_percent"] = float(vk0_percent)
2887 -
        if "vkr0_percent" not in net.trafo.columns:
2888 -
            net.trafo.loc[:, "vkr0_percent"] = pd.Series()
2889 -
2890 -
        net.trafo.loc[index, "vkr0_percent"] = float(vkr0_percent)
2891 -
        if "mag0_percent" not in net.trafo.columns:
2892 -
            net.trafo.loc[:, "mag0_percent"] = pd.Series()
2893 -
2894 -
        net.trafo.loc[index, "mag0_percent"] = float(mag0_percent)
2895 -
        if "mag0_rx" not in net.trafo.columns:
2896 -
            net.trafo.loc[:, "mag0_rx"] = pd.Series()
2897 2338
2898 -
        net.trafo.loc[index, "mag0_rx"] = float(mag0_rx)
2899 -
        if "si0_hv_partial" not in net.trafo.columns:
2900 -
            net.trafo.loc[:, "si0_hv_partial"] = pd.Series()
2339 +
    _set_entries(net, "trafo", index, **v, **kwargs)
2901 2340
2902 -
        net.trafo.loc[index, "si0_hv_partial"] = float(si0_hv_partial)
2903 -
        if "vector_group" not in net.trafo.columns:
2904 -
            net.trafo.loc[:, "vector_group"] = pd.Series()
2905 -
2906 -
        net.trafo.loc[index, "vector_group"] = str(vector_group)
2907 -
    if not isnan(max_loading_percent):
2908 -
        if "max_loading_percent" not in net.trafo.columns:
2909 -
            net.trafo.loc[:, "max_loading_percent"] = pd.Series()
2910 -
2911 -
        net.trafo.loc[index, "max_loading_percent"] = float(max_loading_percent)
2912 -
    # and preserve dtypes
2913 -
    _preserve_dtypes(net.trafo, dtypes)
2341 +
    if not (isnan(vk0_percent) and isnan(vkr0_percent) and isnan(mag0_percent)
2342 +
            and isnan(mag0_rx) and isnan(si0_hv_partial) and vector_group is None):
2343 +
        _create_column_and_set_value(net, index, vk0_percent, "vk0_percent", "trafo")
2344 +
        _create_column_and_set_value(net, index, vkr0_percent, "vkr0_percent", "trafo")
2345 +
        _create_column_and_set_value(net, index, mag0_percent, "mag0_percent", "trafo")
2346 +
        _create_column_and_set_value(net, index, mag0_rx, "mag0_rx", "trafo")
2347 +
        _create_column_and_set_value(net, index, si0_hv_partial, "si0_hv_partial", "trafo")
2348 +
        _create_column_and_set_value(net, index, vector_group, "vector_group", "trafo", dtyp=str,
2349 +
                                     default_val=None)
2350 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo")
2914 2351
2915 2352
    return index
2916 2353
2917 2354
2918 2355
def create_transformers_from_parameters(net, hv_buses, lv_buses, sn_mva, vn_hv_kv, vn_lv_kv,
2919 -
                                       vkr_percent, vk_percent, pfe_kw, i0_percent,
2920 -
                                       shift_degree=0,
2921 -
                                       tap_side=None, tap_neutral=nan, tap_max=nan,
2922 -
                                       tap_min=nan, tap_step_percent=nan, tap_step_degree=nan,
2923 -
                                       tap_pos=nan, tap_phase_shifter=False, in_service=True,
2924 -
                                       name=None, vector_group=None, index=None,
2925 -
                                       max_loading_percent=None, parallel=1,
2926 -
                                       df=1., vk0_percent=None, vkr0_percent=None,
2927 -
                                       mag0_percent=None, mag0_rx=None,
2928 -
                                       si0_hv_partial=None, **kwargs):
2929 -
    """
2930 -
    Creates a two-winding transformer in table net["trafo"].
2356 +
                                        vkr_percent, vk_percent, pfe_kw, i0_percent, shift_degree=0,
2357 +
                                        tap_side=None, tap_neutral=nan, tap_max=nan, tap_min=nan,
2358 +
                                        tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2359 +
                                        tap_phase_shifter=False, in_service=True, name=None,
2360 +
                                        vector_group=None, index=None, max_loading_percent=None,
2361 +
                                        parallel=1, df=1., vk0_percent=None, vkr0_percent=None,
2362 +
                                        mag0_percent=None, mag0_rx=None, si0_hv_partial=None,
2363 +
                                        **kwargs):
2364 +
    """
2365 +
    Creates several two-winding transformers in table net["trafo"].
2931 2366
    The trafo parameters are defined through the standard type library.
2932 2367
2933 2368
    INPUT:
2934 2369
        **net** - The net within this transformer should be created
2935 2370
2936 -
        **hv_bus** (list of int) - The bus on the high-voltage side on which the transformer will be \
2937 -
            connected to
2371 +
        **hv_bus** (list of int) - The bus on the high-voltage side on which the transformer will \
2372 +
            be connected to
2938 2373
2939 -
        **lv_bus** (list of int) - The bus on the low-voltage side on which the transformer will be \
2940 -
            connected to
2374 +
        **lv_bus** (list of int) - The bus on the low-voltage side on which the transformer will \
2375 +
            be connected to
2941 2376
2942 2377
        **sn_mva** (list of float) - rated apparent power
2943 2378
@@ -2966,7 +2401,8 @@
Loading
2966 2401
2967 2402
        **mag0_rx**  - (list of float)  zero sequence magnitizing R/X ratio
2968 2403
2969 -
        **si0_hv_partial** - (list of float)  Distribution of zero sequence leakage impedances for HV side
2404 +
        **si0_hv_partial** - (list of float)  Distribution of zero sequence leakage impedances for \
2405 +
            HV side
2970 2406
2971 2407
2972 2408
    OPTIONAL:
@@ -2984,8 +2420,8 @@
Loading
2984 2420
        **tap_pos** (int, nan) - current tap position of the transformer. Defaults to the medium \
2985 2421
            position (tap_neutral)
2986 2422
2987 -
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the ration of \
2988 -
            the rated voltages
2423 +
        **tap_neutral** (int, nan) - tap position where the transformer ratio is equal to the ratio\
2424 +
            of the rated voltages
2989 2425
2990 2426
        **tap_max** (int, nan) - maximal allowed tap position
2991 2427
@@ -3015,74 +2451,34 @@
Loading
3015 2451
            vn_hv_kv=110, vn_lv_kv=10, vk_percent=10, vkr_percent=0.3, pfe_kw=30, \
3016 2452
            i0_percent=0.1, shift_degree=30)
3017 2453
    """
2454 +
    _check_multiple_branch_elements(net, hv_buses, lv_buses, "Transformers")
3018 2455
3019 -
    nr_trafo = len(hv_buses)
3020 -
    if index is not None:
3021 -
        for idx in index:
3022 -
            if idx in net.trafo.index:
3023 -
                raise UserWarning("A trafo with index %s already exists" % idx)
3024 -
    else:
3025 -
        tid = get_free_id(net["trafo"])
3026 -
        index = arange(tid, tid + nr_trafo, 1)
3027 -
3028 -
    if not(all(isin(hv_buses, net.bus.index))) > 0:
3029 -
        bus_not_exist = set(hv_buses) - set(net.bus.index)
3030 -
        raise UserWarning("Transformer trying to attach to non existing buses %s"
3031 -
                          % list(bus_not_exist))
3032 -
    if not(all(isin(lv_buses, net.bus.index))) > 0:
3033 -
        bus_not_exist = set(lv_buses) - set(net.bus.index)
3034 -
        raise UserWarning("Transformer trying to attach to non existing buses %s"
3035 -
                          % list(bus_not_exist))
3036 -
3037 -
    new_trafos = pd.DataFrame(index=index, columns=net.trafo.columns)
2456 +
    index = _get_multiple_index_with_check(net, "trafo", index, len(hv_buses))
3038 2457
3039 -
    # store dtypes
3040 -
    dtypes = net.trafo.dtypes
2458 +
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2459 +
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2460 +
    entries = {"name": name, "hv_bus": hv_buses, "lv_bus": lv_buses,
2461 +
               "in_service": array(in_service).astype(bool_), "std_type": None, "sn_mva": sn_mva,
2462 +
               "vn_hv_kv": vn_hv_kv, "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent,
2463 +
               "vkr_percent": vkr_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2464 +
               "tap_neutral": tp_neutral, "tap_max": tap_max, "tap_min": tap_min,
2465 +
               "shift_degree": shift_degree, "tap_pos": tp_pos, "tap_side": tap_side,
2466 +
               "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
2467 +
               "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df}
3041 2468
3042 -
    parameters = {
3043 -
        "name": name, "hv_bus": hv_buses, "lv_bus": lv_buses,
3044 -
        "in_service": bool(in_service), "std_type": None, "sn_mva": sn_mva, "vn_hv_kv": vn_hv_kv,
3045 -
        "vn_lv_kv": vn_lv_kv, "vk_percent": vk_percent, "vkr_percent": vkr_percent,
3046 -
        "pfe_kw": pfe_kw, "i0_percent": i0_percent, "tap_neutral": tap_neutral,
3047 -
        "tap_max": tap_max, "tap_min": tap_min, "shift_degree": shift_degree, "tap_pos": tap_pos,
3048 -
        "tap_side": tap_side, "tap_step_percent": tap_step_percent, "tap_step_degree": tap_step_degree,
3049 -
        "tap_phase_shifter": tap_phase_shifter, "parallel": parallel, "df": df
3050 -
    }
2469 +
    _add_series_to_entries(entries, index, "vk0_percent", vk0_percent)
2470 +
    _add_series_to_entries(entries, index, "vkr0_percent", vkr0_percent)
2471 +
    _add_series_to_entries(entries, index, "mag0_percent", mag0_percent)
2472 +
    _add_series_to_entries(entries, index, "mag0_rx", mag0_rx)
2473 +
    _add_series_to_entries(entries, index, "si0_hv_partial", si0_hv_partial)
2474 +
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2475 +
    _add_series_to_entries(entries, index, "vector_group", vector_group, dtyp=str)
3051 2476
3052 -
    new_trafos = new_trafos.assign(**parameters)
3053 -
    new_trafos["tap_pos"] = new_trafos["tap_pos"].fillna(new_trafos.tap_neutral).astype(float)
3054 -
3055 -
    if vk0_percent is not None:
3056 -
        new_trafos["vk0_percent"] = vk0_percent
3057 -
        new_trafos["vk0_percent"] = new_trafos["vk0_percent"].astype(float)
3058 -
    if vkr0_percent is not None:
3059 -
        new_trafos["vkr0_percent"] = vk0_percent
3060 -
        new_trafos["vkr0_percent"] = new_trafos["vkr0_percent"].astype(float)
3061 -
    if mag0_percent is not None:
3062 -
        new_trafos["mag0_percent"] = mag0_percent
3063 -
        new_trafos["mag0_percent"] = new_trafos["mag0_percent"].astype(float)
3064 -
    if mag0_rx is not None:
3065 -
        new_trafos["mag0_rx"] = mag0_rx
3066 -
        new_trafos["mag0_rx"] = new_trafos["mag0_rx"].astype(float)
3067 -
    if si0_hv_partial is not None:
3068 -
        new_trafos["si0_hv_partial"] = si0_hv_partial
3069 -
        new_trafos["si0_hv_partial"] = new_trafos["si0_hv_partial"].astype(float)
3070 -
    if vector_group is not None:
3071 -
        new_trafos["vector_group"] = vector_group
3072 -
        new_trafos["vector_group"] = new_trafos["vector_group"].astype(str)
3073 -
    if max_loading_percent is not None:
3074 -
        new_trafos["max_loading_percent"] = max_loading_percent
3075 -
        new_trafos["max_loading_percent"] = new_trafos["max_loading_percent"].astype(float)
3076 -
3077 -
    for label, value in kwargs.items():
3078 -
        new_trafos[label] = value
3079 -
3080 -
    net["trafo"] = net["trafo"].append(new_trafos)
3081 -
    # and preserve dtypes
3082 -
    _preserve_dtypes(net.trafo, dtypes)
2477 +
    _set_multiple_entries(net, "trafo", index, **entries, **kwargs)
3083 2478
3084 2479
    return index
3085 2480
2481 +
3086 2482
def create_transformer3w(net, hv_bus, mv_bus, lv_bus, std_type, name=None, tap_pos=nan,
3087 2483
                         in_service=True, index=None, max_loading_percent=nan,
3088 2484
                         tap_at_star_point=False):
@@ -3140,11 +2536,7 @@
Loading
3140 2536
    }
3141 2537
    ti = load_std_type(net, std_type, "trafo3w")
3142 2538
3143 -
    if index is None:
3144 -
        index = get_free_id(net["trafo3w"])
3145 -
3146 -
    if index in net["trafo3w"].index:
3147 -
        raise UserWarning("A three winding transformer with index %s already exists" % index)
2539 +
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
3148 2540
3149 2541
    v.update({
3150 2542
        "sn_hv_mva": ti["sn_hv_mva"],
@@ -3165,7 +2557,8 @@
Loading
3165 2557
        "shift_lv_degree": ti["shift_lv_degree"] if "shift_lv_degree" in ti else 0,
3166 2558
        "tap_at_star_point": tap_at_star_point
3167 2559
    })
3168 -
    for tp in ("tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent", "tap_step_degree"):
2560 +
    for tp in (
2561 +
            "tap_neutral", "tap_max", "tap_min", "tap_side", "tap_step_percent", "tap_step_degree"):
3169 2562
        if tp in ti:
3170 2563
            v.update({tp: ti[tp]})
3171 2564
@@ -3182,13 +2575,10 @@
Loading
3182 2575
    elif version.parse(pd.__version__) < version.parse("0.23"):
3183 2576
        net["trafo3w"] = net["trafo3w"].append(dd).reindex(net["trafo3w"].columns, axis=1)
3184 2577
    else:
3185 -
        net["trafo3w"] = net["trafo3w"].append(dd, sort=True).reindex(net["trafo3w"].columns, axis=1)
2578 +
        net["trafo3w"] = net["trafo3w"].append(dd, sort=True).reindex(net["trafo3w"].columns,
2579 +
                                                                      axis=1)
3186 2580
3187 -
    if not isnan(max_loading_percent):
3188 -
        if "max_loading_percent" not in net.trafo3w.columns:
3189 -
            net.trafo3w.loc[:, "max_loading_percent"] = pd.Series()
3190 -
3191 -
        net.trafo3w.loc[index, "max_loading_percent"] = float(max_loading_percent)
2581 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
3192 2582
3193 2583
    return index
3194 2584
@@ -3294,53 +2684,39 @@
Loading
3294 2684
        if b not in net["bus"].index.values:
3295 2685
            raise UserWarning("Trafo tries to attach to non-existent bus %s" % b)
3296 2686
3297 -
    if index is None:
3298 -
        index = get_free_id(net["trafo3w"])
3299 -
3300 -
    if index in net["trafo3w"].index:
3301 -
        raise UserWarning("A three winding transformer with index %s already exists" % index)
2687 +
    index = _get_index_with_check(net, "trafo3w", index, "three winding transformer")
3302 2688
3303 2689
    if tap_pos is nan:
3304 2690
        tap_pos = tap_neutral
3305 2691
3306 -
    # store dtypes
3307 -
    dtypes = net.trafo3w.dtypes
3308 -
3309 -
    net.trafo3w.loc[index, ["lv_bus", "mv_bus", "hv_bus", "vn_hv_kv", "vn_mv_kv", "vn_lv_kv",
3310 -
                            "sn_hv_mva", "sn_mv_mva", "sn_lv_mva", "vk_hv_percent",
3311 -
                            "vk_mv_percent", "vk_lv_percent", "vkr_hv_percent",
3312 -
                            "vkr_mv_percent", "vkr_lv_percent", "pfe_kw", "i0_percent",
3313 -
                            "shift_mv_degree", "shift_lv_degree", "tap_side", "tap_step_percent",
3314 -
                            "tap_step_degree", "tap_pos", "tap_neutral", "tap_max", "tap_min", "in_service",
3315 -
                            "name", "std_type", "tap_at_star_point"]] = \
3316 -
        [lv_bus, mv_bus, hv_bus, vn_hv_kv, vn_mv_kv, vn_lv_kv,
3317 -
         sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent, vk_mv_percent,
3318 -
         vk_lv_percent, vkr_hv_percent, vkr_mv_percent, vkr_lv_percent,
3319 -
         pfe_kw, i0_percent, shift_mv_degree, shift_lv_degree,
3320 -
         tap_side, tap_step_percent, tap_step_degree, tap_pos, tap_neutral, tap_max,
3321 -
         tap_min, bool(in_service), name, None, tap_at_star_point]
3322 -
3323 -
    # and preserve dtypes
3324 -
    _preserve_dtypes(net.trafo3w, dtypes)
2692 +
    columns = ["lv_bus", "mv_bus", "hv_bus", "vn_hv_kv", "vn_mv_kv", "vn_lv_kv", "sn_hv_mva",
2693 +
               "sn_mv_mva", "sn_lv_mva", "vk_hv_percent", "vk_mv_percent", "vk_lv_percent",
2694 +
               "vkr_hv_percent", "vkr_mv_percent", "vkr_lv_percent", "pfe_kw", "i0_percent",
2695 +
               "shift_mv_degree", "shift_lv_degree", "tap_side", "tap_step_percent",
2696 +
               "tap_step_degree", "tap_pos", "tap_neutral", "tap_max", "tap_min", "in_service",
2697 +
               "name", "std_type", "tap_at_star_point"]
2698 +
    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,
2699 +
              vk_hv_percent, vk_mv_percent, vk_lv_percent, vkr_hv_percent, vkr_mv_percent,
2700 +
              vkr_lv_percent, pfe_kw, i0_percent, shift_mv_degree, shift_lv_degree, tap_side,
2701 +
              tap_step_percent, tap_step_degree, tap_pos, tap_neutral, tap_max, tap_min,
2702 +
              bool(in_service), name, None, tap_at_star_point]
3325 2703
3326 -
    if not isnan(max_loading_percent):
3327 -
        if "max_loading_percent" not in net.trafo3w.columns:
3328 -
            net.trafo3w.loc[:, "max_loading_percent"] = pd.Series()
2704 +
    _set_entries(net, "trafo3w", index, **dict(zip(columns, values)))
3329 2705
3330 -
        net.trafo3w.loc[index, "max_loading_percent"] = float(max_loading_percent)
2706 +
    _create_column_and_set_value(net, index, max_loading_percent, "max_loading_percent", "trafo3w")
3331 2707
3332 2708
    return index
3333 2709
3334 2710
3335 -
def create_transformers3w_from_parameters(net, hv_buses, mv_buses, lv_buses, vn_hv_kv, vn_mv_kv, vn_lv_kv,
3336 -
                                         sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
3337 -
                                         vk_mv_percent, vk_lv_percent, vkr_hv_percent,
3338 -
                                         vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
3339 -
                                         shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
3340 -
                                         tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
3341 -
                                         tap_neutral=nan, tap_max=nan,
3342 -
                                         tap_min=nan, name=None, in_service=True, index=None,
3343 -
                                         max_loading_percent=None, tap_at_star_point=False, **kwargs):
2711 +
def create_transformers3w_from_parameters(net, hv_buses, mv_buses, lv_buses, vn_hv_kv, vn_mv_kv,
2712 +
                                          vn_lv_kv, sn_hv_mva, sn_mv_mva, sn_lv_mva, vk_hv_percent,
2713 +
                                          vk_mv_percent, vk_lv_percent, vkr_hv_percent,
2714 +
                                          vkr_mv_percent, vkr_lv_percent, pfe_kw, i0_percent,
2715 +
                                          shift_mv_degree=0., shift_lv_degree=0., tap_side=None,
2716 +
                                          tap_step_percent=nan, tap_step_degree=nan, tap_pos=nan,
2717 +
                                          tap_neutral=nan, tap_max=nan, tap_min=nan, name=None,
2718 +
                                          in_service=True, index=None, max_loading_percent=None,
2719 +
                                          tap_at_star_point=False, **kwargs):
3344 2720
    """
3345 2721
    Adds a three-winding transformer in table net["trafo3w"].
3346 2722
@@ -3374,11 +2750,14 @@
Loading
3374 2750
3375 2751
        **vk_lv_percent** (float or list) - short circuit voltage from high to low voltage
3376 2752
3377 -
        **vkr_hv_percent** (float or list) - real part of short circuit voltage from high to medium voltage
2753 +
        **vkr_hv_percent** (float or list) - real part of short circuit voltage from high to medium\
2754 +
            voltage
3378 2755
3379 -
        **vkr_mv_percent** (float or list) - real part of short circuit voltage from medium to low voltage
2756 +
        **vkr_mv_percent** (float or list) - real part of short circuit voltage from medium to low\
2757 +
            voltage
3380 2758
3381 -
        **vkr_lv_percent** (float or list) - real part of short circuit voltage from high to low voltage
2759 +
        **vkr_lv_percent** (float or list) - real part of short circuit voltage from high to low\
2760 +
            voltage
3382 2761
3383 2762
        **pfe_kw** (float or list) - iron losses in kW
3384 2763
@@ -3427,58 +2806,37 @@
Loading
3427 2806
        shift_lv_degree=30)
3428 2807
3429 2808
    """
3430 -
    nr_trafo = len(hv_buses)
3431 -
    if index is not None:
3432 -
        for idx in index:
3433 -
            if idx in net.trafo3w.index:
3434 -
                raise UserWarning("A three winding transformer with index %s already exists" % idx)
3435 -
    else:
3436 -
        tid = get_free_id(net["trafo"])
3437 -
        index = arange(tid, tid + nr_trafo, 1)
2809 +
    index = _get_multiple_index_with_check(net, "trafo3w", index, len(hv_buses),
2810 +
                                           name="Three winding transformers")
3438 2811
3439 -
    if not(all(isin(hv_buses, net.bus.index))) > 0:
2812 +
    if not np_all(isin(hv_buses, net.bus.index)):
3440 2813
        bus_not_exist = set(hv_buses) - set(net.bus.index)
3441 -
        raise UserWarning("Transformer trying to attach to non existing buses %s" % bus_not_exist)
3442 -
    if not(all(isin(mv_buses, net.bus.index))) > 0:
2814 +
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2815 +
    if not np_all(isin(mv_buses, net.bus.index)):
3443 2816
        bus_not_exist = set(mv_buses) - set(net.bus.index)
3444 -
        raise UserWarning("Transformer trying to attach to non existing buses %s" % bus_not_exist)
3445 -
    if not(all(isin(lv_buses, net.bus.index))) > 0:
2817 +
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2818 +
    if not np_all(isin(lv_buses, net.bus.index)):
3446 2819
        bus_not_exist = set(lv_buses) - set(net.bus.index)
3447 -
        raise UserWarning("Transformer trying to attach to non existing buses %s" % bus_not_exist)
3448 -
3449 -
    new_trafos = pd.DataFrame(index=index, columns=net.trafo3w.columns)
3450 -
3451 -
    # store dtypes
3452 -
    dtypes = net.trafo3w.dtypes
3453 -
3454 -
    parameters = {
3455 -
        "lv_bus":lv_buses, "mv_bus":mv_buses, "hv_bus":hv_buses, "vn_hv_kv":vn_hv_kv, "vn_mv_kv":vn_mv_kv,
3456 -
        "vn_lv_kv":vn_lv_kv, "sn_hv_mva":sn_hv_mva, "sn_mv_mva":sn_mv_mva, "sn_lv_mva":sn_lv_mva,
3457 -
        "vk_hv_percent":vk_hv_percent, "vk_mv_percent":vk_mv_percent, "vk_lv_percent":vk_lv_percent,
3458 -
        "vkr_hv_percent":vkr_hv_percent, "vkr_mv_percent":vkr_mv_percent, "vkr_lv_percent":vkr_lv_percent,
3459 -
        "pfe_kw":pfe_kw, "i0_percent":i0_percent, "shift_mv_degree":shift_mv_degree, "shift_lv_degree":shift_lv_degree,
3460 -
        "tap_side":tap_side, "tap_step_percent":tap_step_percent, "tap_step_degree":tap_step_degree,
3461 -
        "tap_pos":tap_pos, "tap_neutral":tap_neutral, "tap_max":tap_max, "tap_min":tap_min, "in_service":in_service,
3462 -
        "name":name,  "tap_at_star_point":tap_at_star_point, "std_type":None
3463 -
    }
3464 -
3465 -
    new_trafos = new_trafos.assign(**parameters)
3466 -
    new_trafos["tap_pos"] = new_trafos["tap_pos"].fillna(new_trafos.tap_neutral).astype(float)
3467 -
3468 -
    if max_loading_percent is not None:
3469 -
        new_trafos['max_loading_percent'] = max_loading_percent
3470 -
        new_trafos['max_loading_percent'] = new_trafos['max_loading_percent'].astype(float)
3471 -
3472 -
    for label, value in kwargs.items():
3473 -
        new_trafos[label] = value
3474 -
3475 -
    # store dtypes
3476 -
    dtypes = net.trafo3w.dtypes
3477 -
3478 -
    net["trafo3w"] = net["trafo3w"].append(new_trafos)
3479 -
3480 -
    # and preserve dtypes
3481 -
    _preserve_dtypes(net.trafo3w, dtypes)
2820 +
        raise UserWarning("Transformers trying to attach to non existing buses %s" % bus_not_exist)
2821 +
2822 +
    tp_neutral = pd.Series(tap_neutral, index=index, dtype=float64)
2823 +
    tp_pos = pd.Series(tap_pos, index=index, dtype=float64).fillna(tp_neutral)
2824 +
    entries = {"lv_bus": lv_buses, "mv_bus": mv_buses, "hv_bus": hv_buses, "vn_hv_kv": vn_hv_kv,
2825 +
               "vn_mv_kv": vn_mv_kv, "vn_lv_kv": vn_lv_kv, "sn_hv_mva": sn_hv_mva,
2826 +
               "sn_mv_mva": sn_mv_mva, "sn_lv_mva": sn_lv_mva, "vk_hv_percent": vk_hv_percent,
2827 +
               "vk_mv_percent": vk_mv_percent, "vk_lv_percent": vk_lv_percent,
2828 +
               "vkr_hv_percent": vkr_hv_percent, "vkr_mv_percent": vkr_mv_percent,
2829 +
               "vkr_lv_percent": vkr_lv_percent, "pfe_kw": pfe_kw, "i0_percent": i0_percent,
2830 +
               "shift_mv_degree": shift_mv_degree, "shift_lv_degree": shift_lv_degree,
2831 +
               "tap_side": tap_side, "tap_step_percent": tap_step_percent,
2832 +
               "tap_step_degree": tap_step_degree, "tap_pos": tp_pos, "tap_neutral": tp_neutral,
2833 +
               "tap_max": tap_max, "tap_min": tap_min,
2834 +
               "in_service": array(in_service).astype(bool_), "name": name,
2835 +
               "tap_at_star_point": array(tap_at_star_point).astype(bool_), "std_type": None}
2836 +
2837 +
    _add_series_to_entries(entries, index, "max_loading_percent", max_loading_percent)
2838 +
2839 +
    _set_multiple_entries(net, "trafo3w", index, **entries, **kwargs)
3482 2840
3483 2841
    return index
3484 2842
@@ -3529,8 +2887,7 @@
Loading
3529 2887
        create_switch(net, bus = 0, element = 1, et = 'l')
3530 2888
3531 2889
    """
3532 -
    if bus not in net["bus"].index:
3533 -
        raise UserWarning("Unknown bus index")
2890 +
    _check_node_element(net, bus)
3534 2891
    if et == "l":
3535 2892
        elm_tab = 'line'
3536 2893
        if element not in net[elm_tab].index:
@@ -3554,29 +2911,21 @@
Loading
3554 2911
                not net[elm_tab]["lv_bus"].loc[element] == bus):
3555 2912
            raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
3556 2913
    elif et == "b":
3557 -
        if element not in net["bus"].index:
3558 -
            raise UserWarning("Unknown bus index")
2914 +
        _check_node_element(net, element)
3559 2915
    else:
3560 2916
        raise UserWarning("Unknown element type")
3561 2917
3562 -
    if index is None:
3563 -
        index = get_free_id(net["switch"])
3564 -
    if index in net["switch"].index:
3565 -
        raise UserWarning("A switch with index %s already exists" % index)
3566 -
3567 -
    # store dtypes
3568 -
    dtypes = net.switch.dtypes
2918 +
    index = _get_index_with_check(net, "switch", index)
3569 2919
3570 -
    net.switch.loc[index, ["bus", "element", "et", "closed", "type", "name", "z_ohm"]] = \
3571 -
        [bus, element, et, closed, type, name, z_ohm]
3572 -
3573 -
    # and preserve dtypes
3574 -
    _preserve_dtypes(net.switch, dtypes)
2920 +
    entries = dict(zip(["bus", "element", "et", "closed", "type", "name", "z_ohm"],
2921 +
                       [bus, element, et, closed, type, name, z_ohm]))
2922 +
    _set_entries(net, "switch", index, **entries)
3575 2923
3576 2924
    return index
3577 2925
3578 2926
3579 -
def create_switches(net, buses, elements, et, closed=True, type=None, name=None, index=None, z_ohm=0, **kwargs):
2927 +
def create_switches(net, buses, elements, et, closed=True, type=None, name=None, index=None,
2928 +
                    z_ohm=0, **kwargs):
3580 2929
    """
3581 2930
    Adds a switch in the net["switch"] table.
3582 2931
@@ -3594,8 +2943,8 @@
Loading
3594 2943
3595 2944
        **buses** (list)- The bus that the switch is connected to
3596 2945
3597 -
        **element** (list)- index of the element: bus id if et == "b", line id if et == "l", trafo id if \
3598 -
            et == "t"
2946 +
        **element** (list)- index of the element: bus id if et == "b", line id if et == "l", \
2947 +
            trafo id if et == "t"
3599 2948
3600 2949
        **et** - (list) element type: "l" = switch between bus and line, "t" = switch between
3601 2950
            bus and transformer, "t3" = switch between bus and transformer3w, "b" = switch between
@@ -3622,18 +2971,8 @@
Loading
3622 2971
        create_switch(net, bus = 0, element = 1, et = 'l')
3623 2972
3624 2973
    """
3625 -
    nr_switches = len(buses)
3626 -
    if index is not None:
3627 -
        for idx in index:
3628 -
            if idx in net.switch.index:
3629 -
                raise UserWarning("A switch with index %s already exists" % idx)
3630 -
    else:
3631 -
        swid = get_free_id(net["switch"])
3632 -
        index = arange(swid, swid + nr_switches, 1)
3633 -
3634 -
    if not(all(isin(buses, net.bus.index))) > 0:
3635 -
        bus_not_exist = set(buses) - set(net.bus.index)
3636 -
        raise UserWarning("Buses %s do not exist" % bus_not_exist)
2974 +
    index = _get_multiple_index_with_check(net, "switch", index, len(buses), name="Switches")
2975 +
    _check_multiple_node_elements(net, buses)
3637 2976
3638 2977
    for element, elm_type, bus in zip(elements, et, buses):
3639 2978
        if elm_type == "l":
@@ -3641,47 +2980,32 @@
Loading
3641 2980
            if element not in net[elm_tab].index:
3642 2981
                raise UserWarning("Line %s does not exist" % element)
3643 2982
            if (not net[elm_tab]["from_bus"].loc[element] == bus and
3644 -
                not net[elm_tab]["to_bus"].loc[element] == bus):
2983 +
                    not net[elm_tab]["to_bus"].loc[element] == bus):
3645 2984
                raise UserWarning("Line %s not connected to bus %s" % (element, bus))
3646 2985
        elif elm_type == "t":
3647 2986
            elm_tab = 'trafo'
3648 2987
            if element not in net[elm_tab].index:
3649 2988
                raise UserWarning("Trafo %s does not exist" % element)
3650 2989
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
3651 -
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2990 +
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
3652 2991
                raise UserWarning("Trafo %s not connected to bus %s" % (element, bus))
3653 2992
        elif elm_type == "t3":
3654 2993
            elm_tab = 'trafo3w'
3655 2994
            if element not in net[elm_tab].index:
3656 2995
                raise UserWarning("Trafo3w %s does not exist" % element)
3657 2996
            if (not net[elm_tab]["hv_bus"].loc[element] == bus and
3658 -
                not net[elm_tab]["mv_bus"].loc[element] == bus and
3659 -
                not net[elm_tab]["lv_bus"].loc[element] == bus):
2997 +
                    not net[elm_tab]["mv_bus"].loc[element] == bus and
2998 +
                    not net[elm_tab]["lv_bus"].loc[element] == bus):
3660 2999
                raise UserWarning("Trafo3w %s not connected to bus %s" % (element, bus))
3661 3000
        elif elm_type == "b":
3662 -
            if element not in net["bus"].index:
3663 -
                raise UserWarning("Unknown bus index %s" % element)
3001 +
            _check_node_element(net, element)
3664 3002
        else:
3665 3003
            raise UserWarning("Unknown element type")
3666 3004
3667 -
    switches_df = pd.DataFrame(index=index, columns=net.switch.columns)
3668 -
    switches_df['bus'] = buses
3669 -
    switches_df['element'] = elements
3670 -
    switches_df['et'] = et
3671 -
    switches_df['closed'] = closed
3672 -
    switches_df['type'] = type
3673 -
    switches_df['name'] = name
3674 -
    switches_df['z_ohm'] = z_ohm
3675 -
3676 -
    switches_df = switches_df.assign(**kwargs)
3005 +
    entries = {"bus": buses, "element": elements, "et": et, "closed": closed, "type": type,
3006 +
               "name": name, "z_ohm": z_ohm}
3677 3007
3678 -
    # store dtypes
3679 -
    dtypes = net.switch.dtypes
3680 -
3681 -
    net['switch'] = net['switch'].append(switches_df)
3682 -
3683 -
    # and preserve dtypes
3684 -
    _preserve_dtypes(net.switch, dtypes)
3008 +
    _set_multiple_entries(net, "switch", index, **entries, **kwargs)
3685 3009
3686 3010
    return index
3687 3011
@@ -3721,26 +3045,16 @@
Loading
3721 3045
    EXAMPLE:
3722 3046
        create_shunt(net, 0, 20)
3723 3047
    """
3724 -
    if bus not in net["bus"].index.values:
3725 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
3726 -
3727 -
    if index is None:
3728 -
        index = get_free_id(net["shunt"])
3048 +
    _check_node_element(net, bus)
3729 3049
3730 -
    if index in net["shunt"].index:
3731 -
        raise UserWarning("A shunt with index %s already exists" % index)
3050 +
    index = _get_index_with_check(net, "shunt", index)
3732 3051
3733 3052
    if vn_kv is None:
3734 3053
        vn_kv = net.bus.vn_kv.at[bus]
3735 -
    # store dtypes
3736 -
    dtypes = net.shunt.dtypes
3737 -
3738 -
    net.shunt.loc[index, ["bus", "name", "p_mw", "q_mvar", "vn_kv", "step", "max_step",
3739 -
                          "in_service"]] = [bus, name, p_mw, q_mvar, vn_kv, step, max_step,
3740 -
                                            in_service]
3741 3054
3742 -
    # and preserve dtypes
3743 -
    _preserve_dtypes(net.shunt, dtypes)
3055 +
    entries = dict(zip(["bus", "name", "p_mw", "q_mvar", "vn_kv", "step", "max_step", "in_service"],
3056 +
                       [bus, name, p_mw, q_mvar, vn_kv, step, max_step, in_service]))
3057 +
    _set_entries(net, "shunt", index, **entries)
3744 3058
3745 3059
    return index
3746 3060
@@ -3792,28 +3106,19 @@
Loading
3792 3106
3793 3107
        impedance id
3794 3108
    """
3795 -
    for b in [from_bus, to_bus]:
3796 -
        if b not in net["bus"].index.values:
3797 -
            raise UserWarning("Impedance %s tries to attach to non-existing bus %s" % (name, b))
3109 +
    index = _get_index_with_check(net, "impedance", index)
3798 3110
3799 -
    if index is None:
3800 -
        index = get_free_id(net.impedance)
3801 -
3802 -
    if index in net["impedance"].index:
3803 -
        raise UserWarning("An impedance with index %s already exists" % index)
3111 +
    _check_branch_element(net, "Impedance", index, from_bus, to_bus)
3804 3112
3805 -
        # store dtypes
3806 -
    dtypes = net.impedance.dtypes
3807 3113
    if rtf_pu is None:
3808 3114
        rtf_pu = rft_pu
3809 3115
    if xtf_pu is None:
3810 3116
        xtf_pu = xft_pu
3811 -
    net.impedance.loc[index, ["from_bus", "to_bus", "rft_pu", "xft_pu", "rtf_pu", "xtf_pu",
3812 -
                              "name", "sn_mva", "in_service"]] = \
3813 -
        [from_bus, to_bus, rft_pu, xft_pu, rtf_pu, xtf_pu, name, sn_mva, in_service]
3814 3117
3815 -
    # and preserve dtypes
3816 -
    _preserve_dtypes(net.impedance, dtypes)
3118 +
    columns = ["from_bus", "to_bus", "rft_pu", "xft_pu", "rtf_pu", "xtf_pu", "name", "sn_mva",
3119 +
               "in_service"]
3120 +
    values = [from_bus, to_bus, rft_pu, xft_pu, rtf_pu, xtf_pu, name, sn_mva, in_service]
3121 +
    _set_entries(net, "impedance", index, **dict(zip(columns, values)))
3817 3122
3818 3123
    return index
3819 3124
@@ -3828,14 +3133,14 @@
Loading
3828 3133
    :param r_ohm: (float) - real part of the impedance in Ohm
3829 3134
    :param x_ohm: (float) - imaginary part of the impedance in Ohm
3830 3135
    :param sn_mva: (float) - rated power of the series reactor in MVA
3831 -
    :param vn_kv: (float) - rated voltage of the series reactor in kV
3136 +
    :param name:
3137 +
    :type name:
3138 +
    :param in_service:
3139 +
    :type in_service:
3140 +
    :param index:
3141 +
    :type index:
3832 3142
    :return: index of the created element
3833 3143
    """
3834 -
    for b in [from_bus, to_bus]:
3835 -
        if b not in net["bus"].index.values:
3836 -
            raise UserWarning(
3837 -
                "Series reactor %s tries to attach to non-existing bus %s" % (name, b))
3838 -
3839 3144
    if net.bus.at[from_bus, 'vn_kv'] == net.bus.at[to_bus, 'vn_kv']:
3840 3145
        vn_kv = net.bus.at[from_bus, 'vn_kv']
3841 3146
    else:
@@ -3849,8 +3154,7 @@
Loading
3849 3154
    xft_pu = x_ohm / base_z_ohm
3850 3155
3851 3156
    index = create_impedance(net, from_bus=from_bus, to_bus=to_bus, rft_pu=rft_pu, xft_pu=xft_pu,
3852 -
                             sn_mva=sn_mva, name=name, in_service=in_service,
3853 -
                             index=index)
3157 +
                             sn_mva=sn_mva, name=name, in_service=in_service, index=index)
3854 3158
    return index
3855 3159
3856 3160
@@ -3876,23 +3180,13 @@
Loading
3876 3180
    OUTPUT:
3877 3181
        ward id
3878 3182
    """
3879 -
    if bus not in net["bus"].index.values:
3880 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
3881 -
3882 -
    if index is None:
3883 -
        index = get_free_id(net.ward)
3183 +
    _check_node_element(net, bus)
3884 3184
3885 -
    if index in net["ward"].index:
3886 -
        raise UserWarning("A ward equivalent with index %s already exists" % index)
3185 +
    index = _get_index_with_check(net, "ward", index, "ward equivalent")
3887 3186
3888 -
    # store dtypes
3889 -
    dtypes = net.ward.dtypes
3890 -
3891 -
    net.ward.loc[index, ["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "name", "in_service"]] = \
3892 -
        [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name, in_service]
3893 -
3894 -
    # and preserve dtypes
3895 -
    _preserve_dtypes(net.ward, dtypes)
3187 +
    entries = dict(zip(["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "name", "in_service"],
3188 +
                       [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, name, in_service]))
3189 +
    _set_entries(net, "ward", index, **entries)
3896 3190
3897 3191
    return index
3898 3192
@@ -3927,32 +3221,21 @@
Loading
3927 3221
    OUTPUT:
3928 3222
        xward id
3929 3223
    """
3930 -
    if bus not in net["bus"].index.values:
3931 -
        raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
3932 -
3933 -
    if index is None:
3934 -
        index = get_free_id(net.xward)
3935 -
3936 -
    if index in net["xward"].index:
3937 -
        raise UserWarning("An extended ward equivalent with index %s already exists" % index)
3224 +
    _check_node_element(net, bus)
3938 3225
3939 -
    # store dtypes
3940 -
    dtypes = net.xward.dtypes
3226 +
    index = _get_index_with_check(net, "xward", index, "extended ward equivalent")
3941 3227
3942 -
    net.xward.loc[index, ["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "r_ohm", "x_ohm", "vm_pu",
3943 -
                          "name", "in_service"]] = \
3944 -
        [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, name, in_service]
3945 -
3946 -
    # and preserve dtypes
3947 -
    _preserve_dtypes(net.xward, dtypes)
3228 +
    columns = ["bus", "ps_mw", "qs_mvar", "pz_mw", "qz_mvar", "r_ohm", "x_ohm", "vm_pu", "name",
3229 +
               "in_service"]
3230 +
    values = [bus, ps_mw, qs_mvar, pz_mw, qz_mvar, r_ohm, x_ohm, vm_pu, name, in_service]
3231 +
    _set_entries(net, "xward", index, **dict(zip(columns, values)))
3948 3232
3949 3233
    return index
3950 3234
3951 3235
3952 3236
def create_dcline(net, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu,
3953 -
                  index=None, name=None, max_p_mw=nan, min_q_from_mvar=nan,
3954 -
                  min_q_to_mvar=nan, max_q_from_mvar=nan, max_q_to_mvar=nan,
3955 -
                  in_service=True):
3237 +
                  index=None, name=None, max_p_mw=nan, min_q_from_mvar=nan, min_q_to_mvar=nan,
3238 +
                  max_q_from_mvar=nan, max_q_to_mvar=nan, in_service=True):
3956 3239
    """
3957 3240
    Creates a dc line.
3958 3241
@@ -3997,27 +3280,16 @@
Loading
3997 3280
        create_dcline(net, from_bus=0, to_bus=1, p_mw=1e4, loss_percent=1.2, loss_mw=25, \
3998 3281
            vm_from_pu=1.01, vm_to_pu=1.02)
3999 3282
    """
4000 -
    for bus in [from_bus, to_bus]:
4001 -
        if bus not in net["bus"].index.values:
4002 -
            raise UserWarning("Cannot attach to bus %s, bus does not exist" % bus)
4003 -
4004 -
    if index is None:
4005 -
        index = get_free_id(net["dcline"])
4006 -
4007 -
    if index in net["dcline"].index:
4008 -
        raise UserWarning("A dcline with the id %s already exists" % index)
4009 -
4010 -
    # store dtypes
4011 -
    dtypes = net.dcline.dtypes
3283 +
    index = _get_index_with_check(net, "dcline", index)
4012 3284
4013 -
    net.dcline.loc[index, ["name", "from_bus", "to_bus", "p_mw", "loss_percent", "loss_mw",
4014 -
                           "vm_from_pu", "vm_to_pu", "max_p_mw", "min_q_from_mvar",
4015 -
                           "min_q_to_mvar", "max_q_from_mvar", "max_q_to_mvar", "in_service"]] \
4016 -
        = [name, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu,
4017 -
           max_p_mw, min_q_from_mvar, min_q_to_mvar, max_q_from_mvar, max_q_to_mvar, in_service]
3285 +
    _check_branch_element(net, "DCLine", index, from_bus, to_bus)
4018 3286
4019 -
    # and preserve dtypes
4020 -
    _preserve_dtypes(net.dcline, dtypes)
3287 +
    columns = ["name", "from_bus", "to_bus", "p_mw", "loss_percent", "loss_mw", "vm_from_pu",
3288 +
               "vm_to_pu", "max_p_mw", "min_q_from_mvar", "min_q_to_mvar", "max_q_from_mvar",
3289 +
               "max_q_to_mvar", "in_service"]
3290 +
    values = [name, from_bus, to_bus, p_mw, loss_percent, loss_mw, vm_from_pu, vm_to_pu, max_p_mw,
3291 +
              min_q_from_mvar, min_q_to_mvar, max_q_from_mvar, max_q_to_mvar, in_service]
3292 +
    _set_entries(net, "dcline", index, **dict(zip(columns, values)))
4021 3293
4022 3294
    return index
4023 3295
@@ -4039,19 +3311,22 @@
Loading
4039 3311
4040 3312
        **std_dev** (float) - Standard deviation in the same unit as the measurement
4041 3313
4042 -
        **element** (int) - Index of the measured element (either bus index, line index, trafo index, trafo3w index)
3314 +
        **element** (int) - Index of the measured element (either bus index, line index,\
3315 +
            trafo index, trafo3w index)
4043 3316
4044 -
        **side** (int, string, default: None) - Only used for measured lines or transformers. Side defines at which end
4045 -
        of the branch the measurement is gathered. For lines this may be "from", "to" to denote the side with the
4046 -
        from_bus or to_bus. It can also the be index of the from_bus or to_bus. For transformers, it can be "hv", "mv"
4047 -
        or "lv" or the corresponding bus index, respectively
3317 +
        **side** (int, string, default: None) - Only used for measured lines or transformers. Side \
3318 +
            defines at which end of the branch the measurement is gathered. For lines this may be \
3319 +
            "from", "to" to denote the side with the from_bus or to_bus. It can also the be index \
3320 +
            of the from_bus or to_bus. For transformers, it can be "hv", "mv" or "lv" or the \
3321 +
            corresponding bus index, respectively
4048 3322
4049 3323
    OPTIONAL:
4050 -
        **check_existing** (bool, default: None) - Check for and replace existing measurements for this bus,
4051 -
        type and element_type. Set it to false for performance improvements which can cause unsafe
4052 -
        behaviour
3324 +
        **check_existing** (bool, default: None) - Check for and replace existing measurements for\
3325 +
            this bus, type and element_type. Set it to false for performance improvements which can\
3326 +
            cause unsafe behaviour
4053 3327
4054 -
        **index** (int, default: None) - Index of the measurement in the measurement table. Should not exist already.
3328 +
        **index** (int, default: None) - Index of the measurement in the measurement table. Should\
3329 +
            not exist already.
4055 3330
4056 3331
        **name** (str, default: None) - Name of measurement
4057 3332
@@ -4066,7 +3341,8 @@
Loading
4066 3341
        create_measurement(net, "q", "line", 2, 4.5, 0.1, "to")
4067 3342
    """
4068 3343
    if meas_type in ("p", "q") and element_type == "bus":
4069 -
        logger.warning("Attention! Signing system of P,Q measurement of buses now changed to load reference (match pandapower res_bus pq)!")   
3344 +
        logger.warning("Attention! Signing system of P,Q measurement of buses now changed to load "
3345 +
                       "reference (match pandapower res_bus pq)!")
4070 3346
4071 3347
    if meas_type not in ("v", "p", "q", "i", "va", "ia"):
4072 3348
        raise UserWarning("Invalid measurement type ({})".format(meas_type))
@@ -4080,31 +3356,18 @@
Loading
4080 3356
    if element_type not in ("bus", "line", "trafo", "trafo3w"):
4081 3357
        raise UserWarning("Invalid element type ({})".format(element_type))
4082 3358
4083 -
    if element_type == "bus" and element not in net["bus"].index.values:
4084 -
        raise UserWarning("Bus with index={} does not exist".format(element))
4085 -
4086 -
    if element is not None and element_type == "line" and element not in net["line"].index.values:
4087 -
        raise UserWarning("Line with index={} does not exist".format(element))
4088 -
4089 -
    if element is not None and element_type == "trafo" and element not in \
4090 -
            net["trafo"].index.values:
4091 -
        raise UserWarning("Trafo with index={} does not exist".format(element))
4092 -
4093 -
    if element is not None and element_type == "trafo3w" and element not in \
4094 -
            net["trafo3w"].index.values:
4095 -
        raise UserWarning("Trafo3w with index={} does not exist".format(element))
3359 +
    if element is not None and element not in net[element_type].index.values:
3360 +
        raise UserWarning("{} with index={} does not exist".format(element_type.capitalize(),
3361 +
                                                                   element))
4096 3362
4097 -
    if index is None:
4098 -
        index = get_free_id(net.measurement)
4099 -
4100 -
    if index in net["measurement"].index:
4101 -
        raise UserWarning("A measurement with index={} already exists".format(index))
3363 +
    index = _get_index_with_check(net, "measurement", index)
4102 3364
4103 3365
    if meas_type in ("i", "ia") and element_type == "bus":
4104 3366
        raise UserWarning("Line current measurements cannot be placed at buses")
4105 3367
4106 3368
    if meas_type in ("v", "va") and element_type in ("line", "trafo", "trafo3w"):
4107 -
        raise UserWarning("Voltage measurements can only be placed at buses, not at {}".format(element_type))
3369 +
        raise UserWarning(
3370 +
            "Voltage measurements can only be placed at buses, not at {}".format(element_type))
4108 3371
4109 3372
    if check_existing:
4110 3373
        if side is None:
@@ -4122,11 +3385,9 @@
Loading
4122 3385
        elif len(existing) > 1:
4123 3386
            raise UserWarning("More than one measurement of this type exists")
4124 3387
4125 -
    dtypes = net.measurement.dtypes
4126 3388
    columns = ["name", "measurement_type", "element_type", "element", "value", "std_dev", "side"]
4127 -
    net.measurement.loc[index, columns] = \
4128 -
        [name, meas_type.lower(), element_type, element, value, std_dev, side]
4129 -
    _preserve_dtypes(net.measurement, dtypes)
3389 +
    values = [name, meas_type.lower(), element_type, element, value, std_dev, side]
3390 +
    _set_entries(net, "measurement", index, **dict(zip(columns, values)))
4130 3391
    return index
4131 3392
4132 3393
@@ -4143,9 +3404,11 @@
Loading
4143 3404
    INPUT:
4144 3405
        **element** (int) - ID of the element in the respective element table
4145 3406
4146 -
        **et** (string) - element type, one of "gen", "sgen", "ext_grid", "load", "dcline", "storage"]
3407 +
        **et** (string) - element type, one of "gen", "sgen", "ext_grid", "load", "dcline",\
3408 +
            "storage"]
4147 3409
4148 -
        **points** - (list) list of lists with [[p1, p2, c1], [p2, p3, c2], ...] where c(n) defines the costs between p(n) and p(n+1)
3410 +
        **points** - (list) list of lists with [[p1, p2, c1], [p2, p3, c2], ...] where c(n) \
3411 +
            defines the costs between p(n) and p(n+1)
4149 3412
4150 3413
    OPTIONAL:
4151 3414
        **type** - (string) - Type of cost ["p", "q"] are allowed for active or reactive power
@@ -4157,26 +3420,21 @@
Loading
4157 3420
        **index** (int) - The unique ID of created cost entry
4158 3421
4159 3422
    EXAMPLE:
4160 -
        The cost function is given by the x-values p1 and p2 with the slope m between those points. The constant part
4161 -
        b of a linear function y = m*x + b can be neglected for OPF purposes. The intervals have to be continuous (the
4162 -
        starting point of an interval has to be equal to the end point of the previous interval).
3423 +
        The cost function is given by the x-values p1 and p2 with the slope m between those points.\
3424 +
        The constant part b of a linear function y = m*x + b can be neglected for OPF purposes. \
3425 +
        The intervals have to be continuous (the starting point of an interval has to be equal to \
3426 +
        the end point of the previous interval).
4163 3427
4164 3428
        To create a gen with costs of 1€/MW between 0 and 20 MW and 2€/MW between 20 and 30:
4165 3429
4166 3430
        create_pwl_cost(net, 0, "gen", [[0, 20, 1], [20, 30, 2]])
4167 3431
    """
4168 3432
4169 -
    if index is None:
4170 -
        index = get_free_id(net["pwl_cost"])
4171 -
4172 -
    if index in net["pwl_cost"].index:
4173 -
        raise UserWarning("A piecewise_linear_cost with the id %s already exists" % index)
3433 +
    index = _get_index_with_check(net, "pwl_cost", index, "piecewise_linear_cost")
4174 3434
4175 -
    dtypes = net.pwl_cost.dtypes
4176 -
    net.pwl_cost.loc[index, ["power_type", "element", "et"]] = \
4177 -
        [power_type, element, et]
4178 -
    net.pwl_cost.points.loc[index] = points
4179 -
    _preserve_dtypes(net.pwl_cost, dtypes)
3435 +
    entries = dict(zip(["power_type", "element", "et", "points"],
3436 +
                       [power_type, element, et, points]))
3437 +
    _set_entries(net, "pwl_cost", index, **entries)
4180 3438
    return index
4181 3439
4182 3440
@@ -4223,13 +3481,164 @@
Loading
4223 3481
        create_poly_cost(net, 0, "load", cp1_eur_per_mw = 0.1)
4224 3482
    """
4225 3483
4226 -
    if index is None:
4227 -
        index = get_free_id(net["poly_cost"])
3484 +
    index = _get_index_with_check(net, "poly_cost", index)
4228 3485
    columns = ["element", "et", "cp0_eur", "cp1_eur_per_mw", "cq0_eur", "cq1_eur_per_mvar",
4229 3486
               "cp2_eur_per_mw2", "cq2_eur_per_mvar2"]
4230 3487
    variables = [element, et, cp0_eur, cp1_eur_per_mw, cq0_eur, cq1_eur_per_mvar,
4231 3488
                 cp2_eur_per_mw2, cq2_eur_per_mvar2]
4232 -
    dtypes = net.poly_cost.dtypes
4233 -
    net.poly_cost.loc[index, columns] = variables
4234 -
    _preserve_dtypes(net.poly_cost, dtypes)
3489 +
    _set_entries(net, "poly_cost", index, **dict(zip(columns, variables)))
3490 +
    return index
3491 +
3492 +
3493 +
def _get_index_with_check(net, table, index, name=None):
3494 +
    if name is None:
3495 +
        name = table
3496 +
    if index is None:
3497 +
        index = get_free_id(net[table])
3498 +
    if index in net[table].index:
3499 +
        raise UserWarning("A %s with the id %s already exists" % (name, index))
3500 +
    return index
3501 +
3502 +
3503 +
def _get_multiple_index_with_check(net, table, index, number, name=None):
3504 +
    if name is None:
3505 +
        name = table.capitalize() + "s"
3506 +
    if index is None:
3507 +
        bid = get_free_id(net[table])
3508 +
        return arange(bid, bid + number, 1)
3509 +
    contained = isin(net[table].index.values, index)
3510 +
    if np_any(contained):
3511 +
        raise UserWarning("%s with indexes %s already exist."
3512 +
                          % (name, net[table].index.values[contained]))
4235 3513
    return index
3514 +
3515 +
3516 +
def _check_node_element(net, node, node_table="bus"):
3517 +
    if node not in net[node_table].index.values:
3518 +
        raise UserWarning("Cannot attach to %s %s, %s does not exist"
3519 +
                          % (node_table, node, node_table))
3520 +
3521 +
3522 +
def _check_multiple_node_elements(net, nodes, node_table="bus", name="buses"):
3523 +
    if np_any(~isin(nodes, net[node_table].index.values)):
3524 +
        node_not_exist = set(nodes) - set(net[node_table].index.values)
3525 +
        raise UserWarning("Cannot attach to %s %s, they do not exist" % (name, node_not_exist))
3526 +
3527 +
3528 +
def _check_branch_element(net, element_name, index, from_node, to_node, node_name="bus",
3529 +
                          plural="es"):
3530 +
    missing_nodes = {from_node, to_node} - set(net[node_name].index.values)
3531 +
    if missing_nodes:
3532 +
        raise UserWarning("%s %d tries to attach to non-existing %s(%s) %s"
3533 +
                          % (element_name, index, node_name, plural, missing_nodes))
3534 +
3535 +
3536 +
def _check_multiple_branch_elements(net, from_nodes, to_nodes, element_name, node_name="bus",
3537 +
                                    plural="es"):
3538 +
    all_nodes = array(list(from_nodes) + list(to_nodes))
3539 +
    if np_any(~isin(all_nodes, net[node_name].index.values)):
3540 +
        node_not_exist = set(all_nodes) - set(net[node_name].index)
3541 +
        raise UserWarning("%s trying to attach to non existing %s%s %s"
3542 +
                          % (element_name, node_name, plural, node_not_exist))
3543 +
3544 +
3545 +
def _create_column_and_set_value(net, index, variable, column, element, dtyp=float64,
3546 +
                                 default_val=nan, default_for_nan=False):
3547 +
    # if variable (e.g. p_mw) is not None and column (e.g. "p_mw") doesn't exist in element
3548 +
    # (e.g. "gen") table
3549 +
    # create this column and write the value of variable to the index of this element
3550 +
    try:
3551 +
        set_value = not isnan(variable)
3552 +
    except TypeError:
3553 +
        set_value = True
3554 +
    if set_value:
3555 +
        if column not in net[element].columns:
3556 +
            if isinstance(default_val, str) \
3557 +
                    and version.parse(pd.__version__) < version.parse("1.0"):
3558 +
                net[element].loc[:, column] = pd.Series([default_val] * len(net[element]),
3559 +
                                                        dtype=dtyp)
3560 +
            else:
3561 +
                net[element].loc[:, column] = pd.Series(default_val, dtype=dtyp)
3562 +
        net[element].at[index, column] = variable
3563 +
    elif default_for_nan and column in net[element].columns:
3564 +
        net[element].at[index, column] = default_val
3565 +
    return net
3566 +
3567 +
3568 +
def _add_series_to_entries(entries, index, column, values, dtyp=float64, default_val=nan):
3569 +
    if values is not None:
3570 +
        try:
3571 +
            fill_default = not isnan(default_val)
3572 +
        except TypeError:
3573 +
            fill_default = True
3574 +
        if isinstance(values, str) and version.parse(pd.__version__) < version.parse("1.0"):
3575 +
            s = pd.Series([values] * len(index), index=index, dtype=dtyp)
3576 +
        else:
3577 +
            s = pd.Series(values, index=index, dtype=dtyp)
3578 +
        if fill_default:
3579 +
            s = s.fillna(default_val)
3580 +
        entries[column] = s
3581 +
3582 +
3583 +
def _add_multiple_branch_geodata(net, table, geodata, index):
3584 +
    geo_table = "%s_geodata" % table
3585 +
    dtypes = net[geo_table].dtypes
3586 +
    df = pd.DataFrame(index=index, columns=net[geo_table].columns)
3587 +
    # works with single or multiple lists of coordinates
3588 +
    if len(geodata[0]) == 2 and not hasattr(geodata[0][0], "__iter__"):
3589 +
        # geodata is a single list of coordinates
3590 +
        df["coords"] = [geodata] * len(index)
3591 +
    else:
3592 +
        # geodata is multiple lists of coordinates
3593 +
        df["coords"] = geodata
3594 +
3595 +
    if version.parse(pd.__version__) >= version.parse("0.23"):
3596 +
        net[geo_table] = net[geo_table].append(df, sort=False)
3597 +
    else:
3598 +
        # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
3599 +
        net[geo_table] = net[geo_table].append(df)
3600 +
3601 +
    _preserve_dtypes(net[geo_table], dtypes)
3602 +
3603 +
3604 +
def _set_entries(net, table, index, preserve_dtypes=True, **entries):
3605 +
    dtypes = None
3606 +
    if preserve_dtypes:
3607 +
        dtypes = net[table].dtypes
3608 +
3609 +
    for col, val in entries.items():
3610 +
        net[table].at[index, col] = val
3611 +
3612 +
    # and preserve dtypes
3613 +
    if preserve_dtypes:
3614 +
        _preserve_dtypes(net[table], dtypes)
3615 +
3616 +
3617 +
def _set_multiple_entries(net, table, index, preserve_dtypes=True, **entries):
3618 +
    dtypes = None
3619 +
    if preserve_dtypes:
3620 +
        # store dtypes
3621 +
        dtypes = net[table].dtypes
3622 +
3623 +
    def check_entry(val):
3624 +
        if isinstance(val, pd.Series) and not np_all(isin(val.index, index)):
3625 +
            return val.values
3626 +
        elif isinstance(val, set) and len(val) == len(index):
3627 +
            return list(val)
3628 +
        return val
3629 +
3630 +
    entries = {k: check_entry(v) for k, v in entries.items()}
3631 +
3632 +
    dd = pd.DataFrame(index=index, columns=net[table].columns)
3633 +
    dd = dd.assign(**entries)
3634 +
3635 +
    # extend the table by the frame we just created
3636 +
    if version.parse(pd.__version__) >= version.parse("0.23"):
3637 +
        net[table] = net[table].append(dd, sort=False)
3638 +
    else:
3639 +
        # prior to pandas 0.23 there was no explicit parameter (instead it was standard behavior)
3640 +
        net[table] = net[table].append(dd)
3641 +
3642 +
    # and preserve dtypes
3643 +
    if preserve_dtypes:
3644 +
        _preserve_dtypes(net[table], dtypes)
Files Coverage
pandapower 87.67%
Project Totals (161 files) 87.67%