e2nIEE / pandapower

Compare 36f2f7e ... +28 ... a801a5b

Coverage Reach
pandapower/converter/powerfactory/pp_import_functions.py pandapower/converter/powerfactory/validate.py pandapower/converter/powerfactory/main_pf.py pandapower/converter/powerfactory/gui.py pandapower/converter/powerfactory/export_pfd_to_pp.py pandapower/converter/powerfactory/pf_export_functions.py pandapower/converter/powerfactory/logger_setup.py pandapower/converter/powerfactory/run_import.py pandapower/converter/powerfactory/echo_off.py pandapower/converter/powerfactory/__init__.py pandapower/converter/powermodels/to_pm.py pandapower/converter/powermodels/from_pm.py pandapower/converter/powermodels/__init__.py pandapower/converter/pypower/from_ppc.py pandapower/converter/pypower/to_ppc.py pandapower/converter/pypower/__init__.py pandapower/converter/matpower/from_mpc.py pandapower/converter/matpower/to_mpc.py pandapower/converter/matpower/__init__.py pandapower/converter/__init__.py pandapower/pypower/pips.py pandapower/pypower/newtonpf.py pandapower/pypower/opf_model.py pandapower/pypower/dcopf_solver.py pandapower/pypower/opf_setup.py pandapower/pypower/pipsopf_solver.py pandapower/pypower/opf_execute.py pandapower/pypower/opf_args.py pandapower/pypower/pfsoln.py pandapower/pypower/opf_consfcn.py pandapower/pypower/fdpf.py pandapower/pypower/opf_hessfcn.py pandapower/pypower/makePTDF.py pandapower/pypower/gausspf.py pandapower/pypower/opf_costfcn.py pandapower/pypower/dSbr_dV.py pandapower/pypower/qps_pips.py pandapower/pypower/makeApq.py pandapower/pypower/makeAy.py pandapower/pypower/makeYbus.py pandapower/pypower/makeAvl.py pandapower/pypower/makeBdc.py pandapower/pypower/makeSbus.py pandapower/pypower/totcost.py pandapower/pypower/opf.py pandapower/pypower/makeAang.py pandapower/pypower/polycost.py pandapower/pypower/idx_gen.py pandapower/pypower/qps_pypower.py pandapower/pypower/idx_bus.py pandapower/pypower/idx_brch.py pandapower/pypower/idx_bus_sc.py pandapower/pypower/dSbus_dV.py pandapower/pypower/makeB.py pandapower/pypower/d2Sbus_dV2.py pandapower/pypower/dIbr_dV.py pandapower/pypower/hasPQcap.py pandapower/pypower/d2Sbr_dV2.py pandapower/pypower/add_userfcn.py pandapower/pypower/makeLODF.py pandapower/pypower/idx_brch_tdpf.py pandapower/pypower/update_mupq.py pandapower/pypower/ppoption.py pandapower/pypower/run_userfcn.py pandapower/pypower/idx_brch_sc.py pandapower/pypower/pqcost.py pandapower/pypower/util.py pandapower/pypower/d2ASbr_dV2.py pandapower/pypower/dAbr_dV.py pandapower/pypower/d2AIbr_dV2.py pandapower/pypower/d2Ibr_dV2.py pandapower/pypower/dcpf.py pandapower/pypower/printpf.py pandapower/pypower/bustypes.py pandapower/pypower/idx_cost.py pandapower/pypower/ppver.py pandapower/pypower/pipsver.py pandapower/pypower/isload.py pandapower/pypower/idx_area.py pandapower/pypower/_compat.py pandapower/pypower/__init__.py pandapower/toolbox.py pandapower/grid_equivalents/auxiliary.py pandapower/grid_equivalents/rei_generation.py pandapower/grid_equivalents/get_equivalent.py pandapower/grid_equivalents/ward_generation.py pandapower/grid_equivalents/toolbox.py pandapower/grid_equivalents/__init__.py pandapower/pf/run_bfswpf.py pandapower/pf/runpp_3ph.py pandapower/pf/create_jacobian_tdpf.py pandapower/pf/run_newton_raphson_pf.py pandapower/pf/runpf_pypower.py pandapower/pf/create_jacobian.py pandapower/pf/pfsoln_numba.py pandapower/pf/run_dc_pf.py pandapower/pf/iwamoto_multiplier.py pandapower/pf/makeYbus_numba.py pandapower/pf/ppci_variables.py pandapower/pf/dSbus_dV_numba.py pandapower/pf/no_numba.py pandapower/pf/create_jacobian_numba.py pandapower/networks/cigre_networks.py pandapower/networks/create_examples.py pandapower/networks/power_system_test_cases.py pandapower/networks/dickert_lv_networks.py pandapower/networks/kerber_networks.py pandapower/networks/simple_pandapower_test_networks.py pandapower/networks/synthetic_voltage_control_lv_networks.py pandapower/networks/kerber_extreme_networks.py pandapower/networks/mv_oberrhein.py pandapower/networks/ieee_europen_lv_asymmetric.py pandapower/networks/__init__.py pandapower/estimation/algorithm/base.py pandapower/estimation/algorithm/estimator.py pandapower/estimation/algorithm/matrix_base.py pandapower/estimation/algorithm/lp.py pandapower/estimation/algorithm/optimization.py pandapower/estimation/ppc_conversion.py pandapower/estimation/util.py pandapower/estimation/state_estimation.py pandapower/estimation/results.py pandapower/estimation/idx_brch.py pandapower/estimation/idx_bus.py pandapower/estimation/__init__.py pandapower/create.py pandapower/shortcircuit/ppc_conversion.py pandapower/shortcircuit/currents.py pandapower/shortcircuit/results.py pandapower/shortcircuit/calc_sc.py pandapower/shortcircuit/kappa.py pandapower/shortcircuit/toolbox.py pandapower/shortcircuit/impedance.py pandapower/shortcircuit/__init__.py pandapower/control/controller/trafo/ContinuousTapControl.py pandapower/control/controller/trafo/DiscreteTapControl.py pandapower/control/controller/trafo/TapDependentImpedance.py pandapower/control/controller/trafo/VmSetTapControl.py pandapower/control/controller/trafo/USetTapControl.py pandapower/control/controller/trafo_control.py pandapower/control/controller/const_control.py pandapower/control/controller/characteristic_control.py pandapower/control/util/auxiliary.py pandapower/control/util/diagnostic.py pandapower/control/util/characteristic.py pandapower/control/util/__init__.py pandapower/control/run_control.py pandapower/control/basic_controller.py pandapower/control/__init__.py pandapower/timeseries/output_writer.py pandapower/timeseries/run_time_series.py pandapower/timeseries/ts_runpp.py pandapower/timeseries/read_batch_results.py pandapower/timeseries/data_sources/frame_data.py pandapower/timeseries/data_sources/__init__.py pandapower/timeseries/data_source.py pandapower/timeseries/__init__.py pandapower/io_utils.py pandapower/build_branch.py pandapower/auxiliary.py pandapower/results_branch.py pandapower/diagnostic.py pandapower/topology/create_graph.py pandapower/topology/graph_searches.py pandapower/topology/graph_tool_interface.py pandapower/topology/__init__.py pandapower/build_bus.py pandapower/pd2ppc_zero.py pandapower/diagnostic_reports.py pandapower/results_bus.py pandapower/convert_format.py pandapower/groups.py pandapower/build_gen.py pandapower/opf/make_objective.py pandapower/opf/validate_opf_input.py pandapower/opf/pm_storage.py pandapower/opf/run_powermodels.py pandapower/sql_io.py pandapower/results_gen.py pandapower/file_io.py pandapower/pd2ppc.py pandapower/results.py pandapower/std_types.py pandapower/powerflow.py pandapower/runpm.py pandapower/optimal_powerflow.py pandapower/run.py pandapower/__init__.py setup.py

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.

Showing 15 of 31 files from the diff.

@@ -721,8 +721,7 @@
Loading
721 721
        if not section & set(net.ext_grid.bus[net.ext_grid.in_service]).union(
722 722
                net.gen.bus[net.gen.slack & net.gen.in_service]) and any(
723 723
                net.bus.in_service.loc[list(section)]):
724 -
            section_buses = list(net.bus[net.bus.index.isin(section)
725 -
                                         & (net.bus.in_service == True)].index)
724 +
            section_buses = list(net.bus[net.bus.index.isin(section) & net.bus.in_service].index)
726 725
            section_switches = list(net.switch[net.switch.bus.isin(section_buses)].index)
727 726
            section_lines = list(get_connected_elements(net, 'line', section_buses,
728 727
                                                        respect_switches=True,
@@ -734,12 +733,9 @@
Loading
734 733
            section_trafos3w = list(get_connected_elements(net, 'trafo3w', section_buses,
735 734
                                                           respect_switches=True,
736 735
                                                           respect_in_service=True))
737 -
            section_gens = list(net.gen[net.gen.bus.isin(section)
738 -
                                        & (net.gen.in_service == True)].index)
739 -
            section_sgens = list(net.sgen[net.sgen.bus.isin(section)
740 -
                                          & (net.sgen.in_service == True)].index)
741 -
            section_loads = list(net.load[net.load.bus.isin(section)
742 -
                                          & (net.load.in_service == True)].index)
736 +
            section_gens = list(net.gen[net.gen.bus.isin(section) & net.gen.in_service].index)
737 +
            section_sgens = list(net.sgen[net.sgen.bus.isin(section) & net.sgen.in_service].index)
738 +
            section_loads = list(net.load[net.load.bus.isin(section) & net.load.in_service].index)
743 739
744 740
            if section_buses:
745 741
                section_dict['buses'] = section_buses
@@ -764,15 +760,12 @@
Loading
764 760
    open_trafo_switches = net.switch[(net.switch.et == 't') & (net.switch.closed == 0)]
765 761
    isolated_trafos = set(
766 762
        (open_trafo_switches.groupby("element").count().query("bus > 1").index))
767 -
    isolated_trafos_is = isolated_trafos.intersection((set(net.trafo[net.trafo.in_service == True]
768 -
                                                           .index)))
763 +
    isolated_trafos_is = isolated_trafos.intersection((set(net.trafo[net.trafo.in_service].index)))
769 764
    if isolated_trafos_is:
770 765
        disc_elements.append({'isolated_trafos': list(isolated_trafos_is)})
771 766
772 -
    isolated_trafos3w = set(
773 -
        (open_trafo_switches.groupby("element").count().query("bus > 2").index))
774 -
    isolated_trafos3w_is = isolated_trafos3w.intersection((
775 -
        set(net.trafo[net.trafo.in_service == True].index)))
767 +
    isolated_trafos3w = set(open_trafo_switches.groupby("element").count().query("bus > 2").index)
768 +
    isolated_trafos3w_is = isolated_trafos3w.intersection(set(net.trafo[net.trafo.in_service].index))
776 769
    if isolated_trafos3w_is:
777 770
        disc_elements.append({'isolated_trafos3w': list(isolated_trafos3w_is)})
778 771

@@ -52,19 +52,20 @@
Loading
52 52
    output_writer.init_all(net)
53 53
54 54
55 -
def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=100, fill='█'):
56 -
    """
57 -
    Call in a loop to create terminal progress bar.
58 -
    the code is mentioned in : https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console
59 -
    """
60 -
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
61 -
    filled_length = int(length * iteration // total)
62 -
    bar = fill * filled_length + '-' * (length - filled_length)
63 -
    # logger.info('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix))
64 -
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end="")
65 -
    # Print New Line on Complete
66 -
    if iteration == total:
67 -
        print("\n")
55 +
#
56 +
# def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=100, fill='█'):
57 +
#     """
58 +
#     Call in a loop to create terminal progress bar.
59 +
#     the code is mentioned in : https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console
60 +
#     """
61 +
#     percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
62 +
#     filled_length = int(length * iteration // total)
63 +
#     bar = fill * filled_length + '-' * (length - filled_length)
64 +
#     # logger.info('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix))
65 +
#     print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end="")
66 +
#     # Print New Line on Complete
67 +
#     if iteration == total:
68 +
#         print("\n")
68 69
69 70
70 71
def controller_not_converged(time_step, ts_variables):
@@ -84,6 +85,7 @@
Loading
84 85
        for ctrl, net in levelorder:
85 86
            ctrl.time_step(net, time_step)
86 87
88 +
87 89
def finalize_step(controller_order, time_step):
88 90
    for levelorder in controller_order:
89 91
        for ctrl, net in levelorder:

@@ -429,7 +429,7 @@
Loading
429 429
        all_diffs["load_q_diff_is"] = load_q_diff_is
430 430
431 431
    logger.debug('verifying ext_grid')
432 -
    eg_oos = net.ext_grid[net.ext_grid.in_service == False].index
432 +
    eg_oos = net.ext_grid[~net.ext_grid.in_service].index
433 433
    ext_grid_p_diff = net.res_ext_grid.pf_p.replace(np.nan, 0).drop(eg_oos) - net.res_ext_grid.p_mw
434 434
    ext_grid_q_diff = net.res_ext_grid.pf_q.replace(np.nan, 0).drop(
435 435
        eg_oos) - net.res_ext_grid.q_mvar

@@ -642,10 +642,9 @@
Loading
642 642
    calculate_voltage_angles = net._options["calculate_voltage_angles"]
643 643
    neglect_open_switch_branches = net._options["neglect_open_switch_branches"]
644 644
    mode = net._options["mode"]
645 -
    open_switches = (net.switch.closed.values == False)
646 645
    n_bus = ppc["bus"].shape[0]
647 646
    for et, element in [("l", "line"), ("t", "trafo"), ("t3", "trafo3w")]:
648 -
        switch_mask = open_switches & (net.switch.et.values == et)
647 +
        switch_mask = ~net.switch.closed.values & (net.switch.et.values == et)
649 648
        if not switch_mask.any():
650 649
            continue
651 650
        nr_open_switches = np.count_nonzero(switch_mask)

@@ -16,77 +16,64 @@
Loading
16 16
from pandapower.create import create_empty_network, create_buses, create_ext_grid, create_loads, \
17 17
    create_sgens, create_gens, create_lines_from_parameters, create_transformers_from_parameters, \
18 18
    create_shunts, create_ext_grid, create_pwl_costs, create_poly_costs
19 -
from pandapower.run import rundcpp, runpp, runopp
20 -
from pandapower.powerflow import LoadflowNotConverged
21 -
from pandapower.optimal_powerflow import OPFNotConverged
22 -
from pandapower.toolbox import get_element_index
19 +
from pandapower.run import runpp
23 20
24 21
try:
25 22
    import pandaplan.core.pplog as logging
26 23
except ImportError:
27 24
    import logging
28 25
logger = logging.getLogger(__name__)
29 26
30 -
try:
31 -
    from pypower import ppoption, runpf, runopf, rundcpf, rundcopf
32 -
    ppopt = ppoption.ppoption(VERBOSE=0, OUT_ALL=0)
33 -
    pypower_import = True
34 -
except ImportError:
35 -
    pypower_import = False
36 -
37 27
ppc_elms = ["bus", "branch", "gen"]
38 28
39 29
40 30
def from_ppc(ppc, f_hz=50, validate_conversion=False, **kwargs):
41 31
    """
42 32
    This function converts pypower case files to pandapower net structure.
43 33
44 -
    INPUT:
45 -
46 -
        **ppc** : The pypower case file.
47 -
48 -
    OPTIONAL:
49 -
50 -
        **f_hz** (float, 50) - The frequency of the network.
51 -
52 -
        **validate_conversion** (bool, False) - If True, validate_from_ppc is run after conversion.
53 -
            For running the validation, the ppc must already contain the pypower
54 -
            powerflow results or pypower must be installed.
55 -
56 -
        ****kwargs** keyword arguments for
34 +
    Parameters
35 +
    ----------
36 +
    ppc : dict
37 +
        The pypower case file.
38 +
    f_hz : int, optional
39 +
        The frequency of the network, by default 50
40 +
    validate_conversion : bool, optional
41 +
        If True, validate_from_ppc is run after conversion.
42 +
        For running the validation, the ppc must already contain the pypower
43 +
        powerflow results or pypower must be installed, by default False
44 +
    kwargs: dict
45 +
        keyword arguments for
57 46
58 47
            - validate_from_ppc if validate_conversion is True
59 48
60 49
            - tap_side
61 50
62 51
            - check_costs is passed as "check" to create_pwl_costs() and create_poly_costs()
63 52
64 -
    OUTPUT:
65 -
66 -
        **net** : pandapower net.
67 -
68 -
    EXAMPLE:
69 -
70 -
        import pandapower.converter as pc
71 -
72 -
        from pypower import case4gs
73 -
74 -
        ppc_net = case4gs.case4gs()
75 -
76 -
        net = pc.from_ppc(ppc_net, f_hz=60)
77 -
53 +
    Returns
54 +
    -------
55 +
    pandapower.pandapowerNet
56 +
        ppc converted to pandapower net structure
57 +
58 +
    Examples
59 +
    -------
60 +
    >>> import pandapower
61 +
    >>> from pandapower.test.converter.test_from_ppc import get_testgrids
62 +
    >>> ppc = get_testgrids('pypower_cases', 'case4gs.json')
63 +
    >>> net = pandapower.converter.from_ppc(ppc, f_hz=60)
78 64
    """
65 +
79 66
    # --- catch common failures
80 67
    if pd.Series(ppc['bus'][:, BASE_KV] <= 0).any():
81 68
        logger.info('There are false baseKV given in the pypower case file.')
82 69
83 70
    net = create_empty_network(f_hz=f_hz, sn_mva=ppc["baseMVA"])
84 -
71 +
    net._from_ppc_lookups = {}
85 72
86 73
    _from_ppc_bus(net, ppc)
87 -
    gen_lookup = _from_ppc_gen(net, ppc)
88 -
    _from_ppc_branch(net, ppc, f_hz, **kwargs)
89 -
    _from_ppc_gencost(net, ppc, gen_lookup, check=kwargs.get("check_costs", True))
74 +
    net._from_ppc_lookups["gen"] = _from_ppc_gen(net, ppc)
75 +
    net._from_ppc_lookups["branch"] = _from_ppc_branch(net, ppc, f_hz, **kwargs)
76 +
    _from_ppc_gencost(net, ppc, net._from_ppc_lookups["gen"], check=kwargs.get("check_costs", True))
90 77
91 78
    # areas are unconverted
92 79
@@ -95,9 +82,6 @@
Loading
95 82
        if not validate_from_ppc(ppc, net, **kwargs):
96 83
            logger.error("Validation failed.")
97 84
98 -
    net._options = {}
99 -
    net._options["gen_lookup"] = gen_lookup
100 -
101 85
    return net
102 86
103 87
@@ -106,10 +90,11 @@
Loading
106 90
107 91
    # create buses
108 92
    idx_buses = create_buses(
109 -
        net, ppc['bus'].shape[0], name=ppc['bus'][:, BUS_I].astype(int),
93 +
        net, ppc['bus'].shape[0], name=ppc.get("bus_name", None),
110 94
        vn_kv=ppc['bus'][:, BASE_KV], type="b", zone=ppc['bus'][:, ZONE],
111 95
        in_service=(ppc['bus'][:, BUS_TYPE] != 4).astype(bool),
112 -
        max_vm_pu=ppc['bus'][:, VMAX], min_vm_pu=ppc['bus'][:, VMIN])
96 +
        max_vm_pu=ppc['bus'][:, VMAX], min_vm_pu=ppc['bus'][:, VMIN],
97 +
        index=ppc['bus'][:, BUS_I].astype(int))
113 98
114 99
    # create loads
115 100
    is_load = (ppc['bus'][:, PD] > 0) | ((ppc['bus'][:, PD] == 0) & (ppc['bus'][:, QD] != 0))
@@ -126,7 +111,7 @@
Loading
126 111
    create_shunts(net, idx_buses[is_shunt], p_mw=ppc['bus'][is_shunt, GS],
127 112
                     q_mvar=-ppc['bus'][is_shunt, BS])
128 113
129 -
    # unused data of ppc: Vm, Va (partwise: in ext_grid), zone
114 +
    # unused data from ppc: VM, VA (partwise: in ext_grid), BUS_AREA
130 115
131 116
132 117
def _from_ppc_gen(net, ppc):
@@ -147,32 +132,36 @@
Loading
147 132
    # vg_bus_lookup = vg_bus_lookup.drop_duplicates(subset=["bus"], keep="last").set_index("bus")["vg"]
148 133
    vg_bus_lookup = vg_bus_lookup.drop_duplicates(subset=["bus"]).set_index("bus")["vg"]
149 134
135 +
    gen_name = ppc.get("gen_name", np.array([None]*n_gen))
136 +
150 137
    # create ext_grid
151 138
    idx_eg = list()
152 139
    for i in np.arange(n_gen, dtype=int)[is_ext_grid]:
153 140
        idx_eg.append(create_ext_grid(
154 -
            net, bus=bus_pos[i], vm_pu=vg_bus_lookup.at[bus_pos[i]],
141 +
            net, bus=net.bus.index[bus_pos[i]], vm_pu=vg_bus_lookup.at[bus_pos[i]],
155 142
            va_degree=ppc['bus'][bus_pos[i], VA],
156 143
            in_service=(ppc['gen'][i, GEN_STATUS] > 0).astype(bool),
157 144
            max_p_mw=ppc['gen'][i, PMAX], min_p_mw=ppc['gen'][i, PMIN],
158 -
            max_q_mvar=ppc['gen'][i, QMAX], min_q_mvar=ppc['gen'][i, QMIN]))
145 +
            max_q_mvar=ppc['gen'][i, QMAX], min_q_mvar=ppc['gen'][i, QMIN],
146 +
            name=gen_name[i]))
159 147
160 148
    # create gen
161 149
    idx_gen = create_gens(
162 -
        net, buses=bus_pos[is_gen], vm_pu=vg_bus_lookup.loc[bus_pos[is_gen]].values,
150 +
        net, buses=net.bus.index[bus_pos[is_gen]], vm_pu=vg_bus_lookup.loc[bus_pos[is_gen]].values,
163 151
        p_mw=ppc['gen'][is_gen, PG], sn_mva=ppc['gen'][is_gen, MBASE],
164 152
        in_service=(ppc['gen'][is_gen, GEN_STATUS] > 0), controllable=True,
165 153
        max_p_mw=ppc['gen'][is_gen, PMAX], min_p_mw=ppc['gen'][is_gen, PMIN],
166 -
        max_q_mvar=ppc['gen'][is_gen, QMAX], min_q_mvar=ppc['gen'][is_gen, QMIN])
154 +
        max_q_mvar=ppc['gen'][is_gen, QMAX], min_q_mvar=ppc['gen'][is_gen, QMIN],
155 +
        name=gen_name[is_gen])
167 156
168 157
    # create sgen
169 158
    idx_sgen = create_sgens(
170 -
        net, buses=bus_pos[is_sgen], p_mw=ppc['gen'][is_sgen, PG],
159 +
        net, buses=net.bus.index[bus_pos[is_sgen]], p_mw=ppc['gen'][is_sgen, PG],
171 160
        q_mvar=ppc['gen'][is_sgen, QG], sn_mva=ppc['gen'][is_sgen, MBASE], type="",
172 161
        in_service=(ppc['gen'][is_sgen, GEN_STATUS] > 0),
173 162
        max_p_mw=ppc['gen'][is_sgen, PMAX], min_p_mw=ppc['gen'][is_sgen, PMIN],
174 163
        max_q_mvar=ppc['gen'][is_sgen, QMAX], min_q_mvar=ppc['gen'][is_sgen, QMIN],
175 -
        controllable=True)
164 +
        controllable=True, name=gen_name[is_sgen])
176 165
177 166
    neg_p_gens = np.arange(n_gen, dtype=int)[(ppc['gen'][:, PG] < 0) & (is_gen | is_sgen)]
178 167
    neg_p_lim_false = np.arange(n_gen, dtype=int)[ppc['gen'][:, PMIN] > ppc['gen'][:, PMAX]]
@@ -184,19 +173,22 @@
Loading
184 173
    if len(neg_q_lim_false):
185 174
        logger.info(f'These gen have QMIN > QMAX: {neg_q_lim_false}.')
186 175
187 -
    # unused data of ppc: Vg (partwise: in ext_grid and gen), mBase, Pc1, Pc2, Qc1min, Qc1max,
176 +
    # unused data from ppc: Vg (partwise: in ext_grid and gen), mBase, Pc1, Pc2, Qc1min, Qc1max,
188 177
    # Qc2min, Qc2max, ramp_agc, ramp_10, ramp_30,ramp_q, apf
189 178
190 179
    # gen_lookup
191 -
    gen_lookup = pd.DataFrame({
192 -
        'element': np.r_[idx_eg, idx_gen, idx_sgen],
193 -
        'element_type': ["ext_grid"]*sum(is_ext_grid) + ["gen"]*sum(is_gen) + ["sgen"]*sum(is_sgen)
194 -
        })
180 +
    gen_lookup = pd.DataFrame({"element": [-1]*n_gen, "element_type": [""]*n_gen})
181 +
    for is_, idx, et in zip([is_ext_grid, is_gen, is_sgen],
182 +
                            [idx_eg, idx_gen, idx_sgen],
183 +
                            ["ext_grid", "gen", "sgen"]):
184 +
        gen_lookup["element"].loc[is_] = idx
185 +
        gen_lookup["element_type"].loc[is_] = et
195 186
    return gen_lookup
196 187
197 188
198 189
def _from_ppc_branch(net, ppc, f_hz, **kwargs):
199 190
    """ branch data -> create line, trafo """
191 +
    n_bra = ppc["branch"].shape[0]
200 192
201 193
    # --- general_parameters
202 194
    baseMVA = ppc['baseMVA']  # MVA
@@ -210,6 +202,8 @@
Loading
210 202
211 203
    is_line, to_vn_is_leq = _branch_to_which(ppc, from_vn_kv=from_vn_kv, to_vn_kv=to_vn_kv)
212 204
205 +
    bra_name = ppc.get("branch_name", ppc.get("bra_name", np.array([None]*n_bra)))
206 +
213 207
    # --- create line
214 208
    Zni = ppc['bus'][to_bus, BASE_KV]**2/baseMVA  # ohm
215 209
    max_i_ka = ppc['branch'][:, 5]/ppc['bus'][to_bus, BASE_KV]/np.sqrt(3)
@@ -218,8 +212,9 @@
Loading
218 212
        max_i_ka[i_is_zero] = MAX_VAL
219 213
        logger.debug("ppc branch rateA is zero -> Using MAX_VAL instead to calculate " +
220 214
                     "maximum branch flow")
221 -
    create_lines_from_parameters(
222 -
        net, from_buses=from_bus[is_line], to_buses=to_bus[is_line], length_km=1,
215 +
    idx_line = create_lines_from_parameters(
216 +
        net, from_buses=net.bus.index[from_bus[is_line]], to_buses=net.bus.index[to_bus[is_line]],
217 +
        length_km=1, name=bra_name[is_line],
223 218
        r_ohm_per_km=(ppc['branch'][is_line, BR_R]*Zni[is_line]).real,
224 219
        x_ohm_per_km=(ppc['branch'][is_line, BR_X]*Zni[is_line]).real,
225 220
        c_nf_per_km=(ppc['branch'][is_line, BR_B]/Zni[is_line]/omega*1e9/2).real,
@@ -273,15 +268,25 @@
Loading
273 268
        vkr_percent = rk * sn * 100 / baseMVA
274 269
        vkr_percent[~tap_side_is_hv] /= (1+ratio_1[~tap_side_is_hv])**2
275 270
276 -
        create_transformers_from_parameters(
277 -
            net, hv_buses=hv_bus, lv_buses=lv_bus, sn_mva=sn,
278 -
            vn_hv_kv=vn_hv_kv, vn_lv_kv=vn_lv_kv,
271 +
        idx_trafo = create_transformers_from_parameters(
272 +
            net, hv_buses=net.bus.index[hv_bus], lv_buses=net.bus.index[lv_bus], sn_mva=sn,
273 +
            vn_hv_kv=vn_hv_kv, vn_lv_kv=vn_lv_kv, name=bra_name[~is_line],
279 274
            vk_percent=vk_percent, vkr_percent=vkr_percent,
280 275
            max_loading_percent=100, pfe_kw=0, i0_percent=i0_percent,
281 276
            shift_degree=ppc['branch'][~is_line, SHIFT].real,
282 277
            tap_step_percent=np.abs(ratio_1)*100, tap_pos=np.sign(ratio_1),
283 278
            tap_side=tap_side, tap_neutral=0)
284 -
    # unused data of ppc: rateB, rateC
279 +
    else:
280 +
        idx_trafo = []
281 +
    # unused data from ppc: rateB, rateC
282 +
283 +
    # branch_lookup: which branches are lines, and which ones are transformers
284 +
    branch_lookup = pd.DataFrame({"element": [-1] * n_bra, "element_type": [""] * n_bra})
285 +
    branch_lookup["element"].loc[is_line] = idx_line
286 +
    branch_lookup["element_type"].loc[is_line] = "line"
287 +
    branch_lookup["element"].loc[~is_line] = idx_trafo
288 +
    branch_lookup["element_type"].loc[~is_line] = "trafo"
289 +
    return branch_lookup
285 290
286 291
287 292
def _get_bus_pos(ppc, bus_names):
@@ -368,7 +373,7 @@
Loading
368 373
def _from_ppc_gencost(net, ppc, gen_lookup, check=True):
369 374
    # --- gencost -> create polynomial_cost, piecewise_cost
370 375
371 -
    if not 'gencost' in ppc:
376 +
    if 'gencost' not in ppc:
372 377
        return
373 378
374 379
    if len(ppc['gencost'].shape) == 1:
@@ -446,328 +451,159 @@
Loading
446 451
447 452
448 453
def _validate_diff_res(diff_res, max_diff_values):
449 -
    to_iterate = set(max_diff_values.keys()) & {'gen_q_mvar', 'branch_p_mw', 'branch_q_mvar',
450 -
                                                'gen_p_mw', 'bus_va_degree', 'bus_vm_pu'}
451 -
    if not len(to_iterate):
452 -
        logger.warning("There are no keys to validate.")
453 454
    val = True
454 -
    for i in to_iterate:
455 -
        elm = i.split("_")[0]
456 -
        sought = ["p", "q"] if elm != "bus" else ["vm", "va"]
457 -
        col = int(np.array([0, 1])[[j in i for j in sought]][0]) if elm != "branch" else \
458 -
            list(np.array([[0, 2], [1, 3]])[[j in i for j in sought]][0])
459 -
        val &= bool(np.max(abs(diff_res[elm][:, col])) < max_diff_values[i])
455 +
    for et_val in ['gen_q_mvar', 'branch_p_mw', 'branch_q_mvar', 'gen_p_mw', 'bus_va_degree',
456 +
                   'bus_vm_pu']:
457 +
        if max_diff_values[et_val] is not None:
458 +
            et = et_val.split("_")[0]
459 +
            log_key = et if et != "gen" else "gen_p" if "p" in et_val else "gen_q_sum_per_bus"
460 +
            i_col = _log_dict(log_key)[0]
461 +
            val &= bool(np.max(abs(diff_res[log_key][:, i_col])) < max_diff_values[et_val])
460 462
    return val
461 463
462 464
463 -
def _gen_bus_info(ppc, idx_gen):
464 -
    bus_name = int(ppc["gen"][idx_gen, GEN_BUS])
465 -
    # assumption: there is only one bus with this bus_name:
466 -
    idx_bus = int(np.where(ppc["bus"][:, BUS_I] == bus_name)[0][0])
467 -
    current_bus_type = int(ppc["bus"][idx_bus, 1])
465 +
def _gen_q_per_bus_sum(q_array, ppc):
466 +
    return pd.DataFrame(
467 +
        np.c_[q_array, ppc["gen"][:, GEN_BUS].astype(int)],
468 +
        columns=["q_mvar", "bus"]).groupby("bus").sum()
468 469
469 -
    same_bus_gen = np.where(ppc["gen"][:, GEN_BUS] == ppc["gen"][idx_gen, GEN_BUS])[0].astype(int)
470 -
    same_bus_gen = same_bus_gen[np.where(ppc["gen"][same_bus_gen, GEN_STATUS] > 0)]
471 -
    first_same_bus = same_bus_gen[0] if len(same_bus_gen) else None
472 470
473 -
    return current_bus_type, idx_bus, first_same_bus
471 +
def _log_dict(key=None):
472 +
    log_dict = {
473 +
        "bus": [[0, 1], ["voltage magnitude", "voltage angle"], ["pu", "degree"]],
474 +
        "branch": [[[0, 2], [1, 3]], ["branch flow active power", "branch flow reactive power"],
475 +
                   ["MW", "Mvar"]],
476 +
        "gen_p": [[0], ["active power generation"], ["MW"]],
477 +
        "gen_q_sum_per_bus": [[0], ["reactive power generation sum per bus"], ["Mvar"]]}
478 +
    if key is None:
479 +
        return log_dict
480 +
    else:
481 +
        return log_dict[key]
474 482
475 483
476 -
def validate_from_ppc(ppc_net, net, pf_type="runpp", max_diff_values={
477 -
    "bus_vm_pu": 1e-6, "bus_va_degree": 1e-5, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6,
478 -
        "gen_p_mw": 1e-6, "gen_q_mvar": 1e-6}, run=True):
484 +
def validate_from_ppc(ppc, net, max_diff_values={
485 +
        "bus_vm_pu": 1e-6, "bus_va_degree": 1e-5, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6,
486 +
        "gen_p_mw": 1e-6, "gen_q_mvar": 1e-6}):
479 487
    """
480 -
    This function validates the pypower case files to pandapower net structure conversion via a \
481 -
    comparison of loadflow calculation results. (Hence the opf cost conversion is not validated.)
482 -
483 -
    INPUT:
484 -
485 -
        **ppc_net** - The pypower case file, which must already contain the pypower powerflow
486 -
            results or pypower must be importable.
487 -
488 -
        **net** - The pandapower network.
489 -
490 -
    OPTIONAL:
491 -
492 -
        **pf_type** ("runpp", string) - Type of validated power flow. Possible are ("runpp",
493 -
            "rundcpp", "runopp", "rundcopp")
494 -
495 -
        **max_diff_values** - Dict of maximal allowed difference values. The keys must be
496 -
        'vm_pu', 'va_degree', 'p_branch_mw', 'q_branch_mvar', 'p_gen_mw' and 'q_gen_mvar' and
497 -
        the values floats.
498 -
499 -
        **run** (True, bool or list of two bools) - changing the value to False avoids trying to run
500 -
            (optimal) loadflows. Giving a list of two bools addresses first pypower and second
501 -
            pandapower.
502 -
503 -
    OUTPUT:
504 -
505 -
        **conversion_success** - conversion_success is returned as False if pypower or pandapower
506 -
        cannot calculate a powerflow or if the maximum difference values (max_diff_values )
507 -
        cannot be hold.
508 -
509 -
    EXAMPLE:
510 -
511 -
        import pandapower.converter as pc
512 -
513 -
        net = cv.from_ppc(ppc_net, f_hz=50)
514 -
515 -
        conversion_success = cv.validate_from_ppc(ppc_net, net)
516 -
517 -
    NOTE:
518 -
519 -
        The user has to take care that the loadflow results already are included in the provided \
520 -
        ppc_net or pypower is importable.
488 +
    This function validates the conversion of a pypower case file (ppc) to a pandapower net.
489 +
    It compares the power flow calculation results which must be provided within the ppc and the net.
490 +
491 +
    Parameters
492 +
    ----------
493 +
    ppc : dict
494 +
        _description_
495 +
    net : pandapower.pandapowerNet
496 +
        _description_
497 +
    max_diff_values : dict, optional
498 +
        _description_, by default { "bus_vm_pu": 1e-6, "bus_va_degree": 1e-5, "branch_p_mw": 1e-6,
499 +
        "branch_q_mvar": 1e-6, "gen_p_mw": 1e-6, "gen_q_mvar": 1e-6}
500 +
501 +
    Returns
502 +
    -------
503 +
    bool
504 +
        Whether the power flow results matches.
505 +
506 +
    Examples
507 +
    ------
508 +
    >>> import pandapower
509 +
    >>> from pandapower.test.converter.test_from_ppc import get_testgrids
510 +
    >>> ppc = get_testgrids('pypower_cases', 'case4gs.json')
511 +
    >>> net = pandapower.converter.from_ppc(ppc, f_hz=50)
512 +
    >>> pandapower.runpp(net)
513 +
    >>> pf_match = pandapower.converter.validate_from_ppc(ppc, net)
521 514
    """
515 +
    if "_from_ppc_lookups" not in net.keys() or \
516 +
            ("gen" not in net._from_ppc_lookups.keys() and len(ppc["gen"]) > 0) or \
517 +
            ("branch" not in net._from_ppc_lookups.keys() and len(ppc["branch"]) > 0):
518 +
        raise ValueError(
519 +
            "net._from_ppc_lookups must contain a lookup (dict of keys 'branch' and 'gen')")
522 520
523 -
    # check in case of optimal powerflow comparison whether cost information exist
524 -
    if "opp" in pf_type:
525 -
        if not (len(net.polynomial_cost) | len(net.piecewise_linear_cost)):
526 -
            if "gencost" in ppc_net:
527 -
                if not len(ppc_net["gencost"]):
528 -
                    logger.debug('ppc and pandapower net do not include cost information.')
529 -
                    return True
530 -
                else:
531 -
                    logger.error('The pandapower net does not include cost information.')
532 -
                    return False
533 -
            else:
534 -
                logger.debug('ppc and pandapower net do not include cost information.')
535 -
                return True
536 -
537 -
    # guarantee run parameter as list, for pypower and pandapower (optimal) powerflow run
538 -
    run = [run, run] if isinstance(run, bool) else run
539 -
540 -
    # --- check pypower powerflow success, if possible
541 -
    if pypower_import and run[0]:
542 -
        try:
543 -
            if pf_type == "runpp":
544 -
                ppc_net = runpf.runpf(ppc_net, ppopt)[0]
545 -
            elif pf_type == "rundcpp":
546 -
                ppc_net = rundcpf.rundcpf(ppc_net, ppopt)[0]
547 -
            elif pf_type == "runopp":
548 -
                ppc_net = runopf.runopf(ppc_net, ppopt)
549 -
            elif pf_type == "rundcopp":
550 -
                ppc_net = rundcopf.rundcopf(ppc_net, ppopt)
551 -
            else:
552 -
                raise ValueError(f"The pf_type {pf_type} is unknown")
553 -
        except:
554 -
            logger.debug("The pypower run did not work.")
555 -
    ppc_success = True
556 -
    if 'success' in ppc_net.keys():
557 -
        if ppc_net['success'] != 1:
558 -
            ppc_success = False
559 -
            logger.error("The given ppc data indicates an unsuccessful pypower powerflow: " +
560 -
                         "'ppc_net['success'] != 1'")
561 -
    if (ppc_net['branch'].shape[1] < 17):
562 -
        ppc_success = False
563 -
        logger.error("The shape of given ppc data indicates missing pypower powerflow results.")
564 -
565 -
    # --- try to run a pandapower powerflow
566 -
    if run[1]:
567 -
        if pf_type == "runpp":
568 -
            try:
569 -
                runpp(net, init="dc", calculate_voltage_angles=True, trafo_model="pi")
570 -
            except LoadflowNotConverged:
571 -
                try:
572 -
                    runpp(net, calculate_voltage_angles=True, init="flat", trafo_model="pi")
573 -
                except LoadflowNotConverged:
574 -
                    try:
575 -
                        runpp(net, trafo_model="pi", calculate_voltage_angles=False)
576 -
                        if "bus_va_degree" in max_diff_values.keys():
577 -
                            max_diff_values["bus_va_degree"] = 1e2 if max_diff_values[
578 -
                                "bus_va_degree"] < 1e2 else max_diff_values["bus_va_degree"]
579 -
                        logger.info("voltage_angles could be calculated.")
580 -
                    except LoadflowNotConverged:
581 -
                        logger.error('The pandapower powerflow does not converge.')
582 -
        elif pf_type == "rundcpp":
583 -
            try:
584 -
                rundcpp(net, trafo_model="pi")
585 -
            except LoadflowNotConverged:
586 -
                logger.error('The pandapower dc powerflow does not converge.')
587 -
        elif pf_type == "runopp":
588 -
                try:
589 -
                    runopp(net, init="flat", calculate_voltage_angles=True)
590 -
                except OPFNotConverged:
591 -
                    try:
592 -
                        runopp(net, init="pf", calculate_voltage_angles=True)
593 -
                    except (OPFNotConverged, LoadflowNotConverged, KeyError):
594 -
                        try:
595 -
                            runopp(net, init="flat", calculate_voltage_angles=False)
596 -
                            logger.info("voltage_angles could be calculated.")
597 -
                            if "bus_va_degree" in max_diff_values.keys():
598 -
                                max_diff_values["bus_va_degree"] = 1e2 if max_diff_values[
599 -
                                    "bus_va_degree"] < 1e2 else max_diff_values["bus_va_degree"]
600 -
                        except OPFNotConverged:
601 -
                            try:
602 -
                                runopp(net, init="pf", calculate_voltage_angles=False)
603 -
                                if "bus_va_degree" in max_diff_values.keys():
604 -
                                    max_diff_values["bus_va_degree"] = 1e2 if max_diff_values[
605 -
                                        "bus_va_degree"] < 1e2 else max_diff_values["bus_va_degree"]
606 -
                                logger.info("voltage_angles could be calculated.")
607 -
                            except (OPFNotConverged, LoadflowNotConverged, KeyError):
608 -
                                logger.error('The pandapower optimal powerflow does not converge.')
609 -
        elif pf_type == "rundcopp":
610 -
            try:
611 -
                rundcopp(net)
612 -
            except LoadflowNotConverged:
613 -
                logger.error('The pandapower dc optimal powerflow does not converge.')
614 -
        else:
615 -
            raise ValueError("The pf_type %s is unknown" % pf_type)
616 -
617 -
    # --- prepare powerflow result comparison by reordering pp results as they are in ppc results
618 -
    if not ppc_success:
619 -
        return False
620 -
    if "opp" in pf_type:
621 -
        if not net.OPF_converged:
622 -
            return
623 -
    elif not net.converged:
624 -
        return False
625 -
626 -
    # --- store pypower powerflow results
521 +
    if net.res_bus.shape[0] == 0 and net.bus.shape[0] > 0:
522 +
        logger.debug("runpp() is performed by validate_from_ppc() since res_bus is empty.")
523 +
        runpp(net, calculate_voltage_angles=True, trafo_model="pi")
524 +
525 +
    # --- pypower powerflow results -> ppc_res -----------------------------------------------------
627 526
    ppc_res = dict.fromkeys(ppc_elms)
628 -
    ppc_res["branch"] = ppc_net['branch'][:, 13:17]
629 -
    ppc_res["bus"] = ppc_net['bus'][:, 7:9]
630 -
    ppc_res["gen"] = ppc_net['gen'][:, 1:3]
527 +
    ppc_res["bus"] = ppc['bus'][:, 7:9]
528 +
    ppc_res["branch"] = ppc['branch'][:, 13:17]
529 +
    ppc_res["gen"] = ppc['gen'][:, 1:3]
530 +
    ppc_res["gen_p"] = ppc_res["gen"][:, :1]
531 +
    ppc_res["gen_q_sum_per_bus"] = _gen_q_per_bus_sum(ppc_res["gen"][:, -1:], ppc)
631 532
632 -
    # --- pandapower bus result table
533 +
    # --- pandapower powerflow results -> pp_res ---------------------------------------------------
633 534
    pp_res = dict.fromkeys(ppc_elms)
634 -
    pp_res["bus"] = np.array(net.res_bus.sort_index()[['vm_pu', 'va_degree']])
635 535
636 -
    # --- pandapower gen result table
637 -
    pp_res["gen"] = np.zeros([1, 2])
638 -
    # consideration of parallel generators via storing how much generators have been considered
639 -
    # each node
640 -
    # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array
641 -
    if len(ppc_net["gen"].shape) == 1:
642 -
        ppc_net["gen"] = np.array(ppc_net["gen"], ndmin=2)
643 -
    GENS = pd.DataFrame(ppc_net['gen'][:, [0]].astype(int))
644 -
    GEN_uniq = GENS.drop_duplicates()
645 -
    already_used_gen = pd.Series(np.zeros(GEN_uniq.shape[0]).astype(int),
646 -
                                 index=[int(v) for v in GEN_uniq.values])
647 -
    change_q_compare = []
648 -
    for i, j in GENS.iterrows():
649 -
        current_bus_type, current_bus_idx, first_same_bus_in_service_gen_idx, = _gen_bus_info(
650 -
            ppc_net, i)
651 -
        if current_bus_type == 3 and i == first_same_bus_in_service_gen_idx:
652 -
            pp_res["gen"] = np.append(pp_res["gen"], np.array(net.res_ext_grid[
653 -
                    net.ext_grid.bus == current_bus_idx][['p_mw', 'q_mvar']]).reshape((1, 2)), 0)
654 -
        elif current_bus_type == 2 and i == first_same_bus_in_service_gen_idx:
655 -
            pp_res["gen"] = np.append(pp_res["gen"], np.array(net.res_gen[
656 -
                    net.gen.bus == current_bus_idx][['p_mw', 'q_mvar']]).reshape((1, 2)), 0)
536 +
    # --- bus
537 +
    pp_res["bus"] = net.res_bus.loc[ppc["bus"][:, BUS_I].astype(int), ['vm_pu', 'va_degree']].values
538 +
539 +
    # --- branch
540 +
    pp_res["branch"] = np.zeros(ppc_res["branch"].shape)
541 +
    from_to_buses = -np.ones((ppc_res["branch"].shape[0], 2), dtype=int)
542 +
    for et in net._from_ppc_lookups["branch"].element_type.unique():
543 +
        if et == "line":
544 +
            from_to_cols = ["from_bus", "to_bus"]
545 +
            res_cols = ['p_from_mw', 'q_from_mvar', 'p_to_mw', 'q_to_mvar']
546 +
        elif et == "trafo":
547 +
            from_to_cols = ["hv_bus", "lv_bus"]
548 +
            res_cols = ['p_hv_mw', 'q_hv_mvar', 'p_lv_mw', 'q_lv_mvar']
657 549
        else:
658 -
            pp_res["gen"] = np.append(pp_res["gen"], np.array(net.res_sgen[
659 -
                net.sgen.bus == current_bus_idx][['p_mw', 'q_mvar']])[
660 -
                already_used_gen.at[int(j)]].reshape((1, 2)), 0)
661 -
            already_used_gen.at[int(j)] += 1
662 -
            change_q_compare += [int(j)]
663 -
    pp_res["gen"] = pp_res["gen"][1:, :]  # delete initial zero row
664 -
665 -
    # --- pandapower branch result table
666 -
    pp_res["branch"] = np.zeros([1, 4])
667 -
    # consideration of parallel branches via storing how often branches were considered
668 -
    # each node-to-node-connection
669 -
    try:
670 -
        init1 = pd.concat([net.line.from_bus, net.line.to_bus], axis=1,
671 -
                          sort=True).drop_duplicates()
672 -
        init2 = pd.concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1,
673 -
                          sort=True).drop_duplicates()
674 -
    except TypeError:
675 -
        # legacy pandas < 0.21
676 -
        init1 = pd.concat([net.line.from_bus, net.line.to_bus], axis=1).drop_duplicates()
677 -
        init2 = pd.concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1).drop_duplicates()
678 -
    init1['hv_bus'] = np.nan
679 -
    init1['lv_bus'] = np.nan
680 -
    init2['from_bus'] = np.nan
681 -
    init2['to_bus'] = np.nan
682 -
    try:
683 -
        already_used_branches = pd.concat([init1, init2], axis=0, sort=True)
684 -
    except TypeError:
685 -
        # pandas < 0.21 legacy
686 -
        already_used_branches = pd.concat([init1, init2], axis=0)
687 -
    already_used_branches['number'] = np.zeros([already_used_branches.shape[0], 1]).astype(int)
688 -
    BRANCHES = pd.DataFrame(ppc_net['branch'][:, [0, 1, TAP, SHIFT]])
689 -
    for i in BRANCHES.index:
690 -
        from_bus = get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 0]))
691 -
        to_bus = get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 1]))
692 -
        from_vn_kv = ppc_net['bus'][from_bus, BASE_KV]
693 -
        to_vn_kv = ppc_net['bus'][to_bus, BASE_KV]
694 -
        ratio = BRANCHES[2].at[i]
695 -
        angle = BRANCHES[3].at[i]
696 -
        # from line results
697 -
        if (from_vn_kv == to_vn_kv) & ((ratio == 0) | (ratio == 1)) & (angle == 0):
698 -
            pp_res["branch"] = np.append(pp_res["branch"], np.array(net.res_line[
699 -
                (net.line.from_bus == from_bus) &
700 -
                (net.line.to_bus == to_bus)]
701 -
                [['p_from_mw', 'q_from_mvar', 'p_to_mw', 'q_to_mvar']])[
702 -
                int(already_used_branches.number.loc[
703 -
                   (already_used_branches.from_bus == from_bus) &
704 -
                   (already_used_branches.to_bus == to_bus)].values)].reshape(1, 4), 0)
705 -
            already_used_branches.number.loc[(already_used_branches.from_bus == from_bus) &
706 -
                                             (already_used_branches.to_bus == to_bus)] += 1
707 -
        # from trafo results
708 -
        else:
709 -
            if from_vn_kv >= to_vn_kv:
710 -
                pp_res["branch"] = np.append(pp_res["branch"], np.array(net.res_trafo[
711 -
                    (net.trafo.hv_bus == from_bus) &
712 -
                    (net.trafo.lv_bus == to_bus)]
713 -
                    [['p_hv_mw', 'q_hv_mvar', 'p_lv_mw', 'q_lv_mvar']])[
714 -
                    int(already_used_branches.number.loc[
715 -
                        (already_used_branches.hv_bus == from_bus) &
716 -
                        (already_used_branches.lv_bus == to_bus)].values)].reshape(1, 4), 0)
717 -
                already_used_branches.number.loc[(already_used_branches.hv_bus == from_bus) &
718 -
                                                 (already_used_branches.lv_bus == to_bus)] += 1
719 -
            else:  # switch hv-lv-connection of pypower connection buses
720 -
                pp_res["branch"] = np.append(pp_res["branch"], np.array(net.res_trafo[
721 -
                    (net.trafo.hv_bus == to_bus) &
722 -
                    (net.trafo.lv_bus == from_bus)]
723 -
                    [['p_lv_mw', 'q_lv_mvar', 'p_hv_mw', 'q_hv_mvar']])[
724 -
                    int(already_used_branches.number.loc[
725 -
                        (already_used_branches.hv_bus == to_bus) &
726 -
                        (already_used_branches.lv_bus == from_bus)].values)].reshape(1, 4), 0)
727 -
                already_used_branches.number.loc[
728 -
                    (already_used_branches.hv_bus == to_bus) &
729 -
                    (already_used_branches.lv_bus == from_bus)] += 1
730 -
    pp_res["branch"] = pp_res["branch"][1:, :]  # delete initial zero row
731 -
732 -
    # --- do the powerflow result comparison
733 -
    diff_res = dict.fromkeys(ppc_elms)
734 -
    diff_res["bus"] = ppc_res["bus"] - pp_res["bus"]
735 -
    diff_res["bus"][:, 1] -= diff_res["bus"][0, 1]  # remove va_degree offset
736 -
    diff_res["branch"] = ppc_res["branch"] - pp_res["branch"]
737 -
    diff_res["gen"] = ppc_res["gen"] - pp_res["gen"]
738 -
    # comparison of buses with several generator units only as q sum
739 -
    for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index:
740 -
        next_is = GEN_uniq.index[GEN_uniq.index > i]
741 -
        if len(next_is) > 0:
742 -
            next_i = next_is[0]
743 -
        else:
744 -
            next_i = GENS.index[-1] + 1
745 -
        if (next_i - i) > 1:
746 -
            diff_res["gen"][i:next_i, 1] = sum(diff_res["gen"][i:next_i, 1])
747 -
    # logger info
748 -
    logger.debug("Maximum voltage magnitude difference between pypower and pandapower: "
749 -
                 "%.2e pu" % np.max(abs(diff_res["bus"][:, 0])))
750 -
    logger.debug("Maximum voltage angle difference between pypower and pandapower: "
751 -
                 "%.2e degree" % np.max(abs(diff_res["bus"][:, 1])))
752 -
    logger.debug("Maximum branch flow active power difference between pypower and pandapower: "
753 -
                 "%.2e MW" % np.max(abs(diff_res["branch"][:, [0, 2]])))
754 -
    logger.debug("Maximum branch flow reactive power difference between pypower and "
755 -
                 "pandapower: %.2e MVAr" % np.max(abs(diff_res["branch"][:, [1, 3]])))
756 -
    logger.debug("Maximum active power generation difference between pypower and pandapower: "
757 -
                 "%.2e MW" % np.max(abs(diff_res["gen"][:, 0])))
758 -
    logger.debug("Maximum reactive power generation difference between pypower and pandapower: "
759 -
                 "%.2e MVAr" % np.max(abs(diff_res["gen"][:, 1])))
760 -
    if _validate_diff_res(diff_res, {"bus_vm_pu": 1e-3, "bus_va_degree": 1e-3, "branch_p_mw": 1e-6,
761 -
                                     "branch_q_mvar": 1e-6}) and \
762 -
            (np.max(abs(diff_res["gen"])) > 1e-1).any():
763 -
        logger.debug("The active/reactive power generation difference possibly results "
764 -
                     "because of a pypower error. Please validate "
765 -
                     "the results via pypower loadflow.")  # this occurs e.g. at ppc case9
766 -
    # give a return
767 -
    if isinstance(max_diff_values, dict):
768 -
        return _validate_diff_res(diff_res, max_diff_values)
769 -
    else:
770 -
        logger.debug("'max_diff_values' must be a dict.")
550 +
            raise NotImplementedError(
551 +
                f"result columns for element type {et} are not implemented.")
552 +
        is_et = net._from_ppc_lookups["branch"].element_type == et
553 +
        pp_res["branch"][is_et] += net[f"res_{et}"].loc[
554 +
            net._from_ppc_lookups["branch"].element.loc[is_et], res_cols].values
555 +
        from_to_buses[is_et] = net[et].loc[
556 +
            net._from_ppc_lookups["branch"].element.loc[is_et], from_to_cols].values
557 +
558 +
    # switch direction as in ppc
559 +
    correct_from_to = np.all(from_to_buses == ppc["branch"][:, F_BUS:T_BUS+1].astype(int), axis=1)
560 +
    switch_from_to = np.all(from_to_buses[:, ::-1] == ppc["branch"][:, F_BUS:T_BUS+1].astype(
561 +
        int), axis=1)
562 +
    if not np.all(correct_from_to | switch_from_to):
563 +
        raise ValueError("ppc branch from and to buses don't fit to pandapower from and to + "
564 +
                        "hv and lv buses.")
565 +
    if np.any(switch_from_to):
566 +
        pp_res["branch"][switch_from_to, :] = pp_res["branch"][switch_from_to, :][:, [2, 3, 0, 1]]
567 +
568 +
    # --- gen
569 +
    pp_res["gen"] = np.zeros(ppc_res["gen"].shape)
570 +
    res_cols = ['p_mw', 'q_mvar']
571 +
    for et in net._from_ppc_lookups["gen"].element_type.unique():
572 +
        is_et = net._from_ppc_lookups["gen"].element_type == et
573 +
        pp_res["gen"][is_et] += net[f"res_{et}"].loc[
574 +
            net._from_ppc_lookups["gen"].element.loc[is_et], res_cols].values
575 +
576 +
    pp_res["gen_p"] = ppc_res["gen"][:, :1]
577 +
    pp_res["gen_q_sum_per_bus"] = _gen_q_per_bus_sum(pp_res["gen"][:, -1:], ppc)
578 +
579 +
    # --- log maximal differences the powerflow result comparison
580 +
    diff_res = dict()
581 +
    comp_keys = ["bus", "branch", "gen_p", "gen_q_sum_per_bus"]
582 +
    for comp_key in comp_keys:
583 +
        diff_res[comp_key] = ppc_res[comp_key] - pp_res[comp_key]
584 +
        if isinstance(diff_res[comp_key], pd.DataFrame):
585 +
            diff_res[comp_key] = diff_res[comp_key].values
586 +
        for i_col, var_str, unit in zip(*_log_dict(comp_key)):
587 +
            diff = diff_res[comp_key][:, i_col]
588 +
            logger.debug(f"Maximum {var_str} difference between pandapower and pypower: "
589 +
                         "%.2e %s" % (np.max(abs(diff)), unit))
590 +
591 +
    # --- do the powerflow result comparison -------------------------------------------------------
592 +
    pf_match = _validate_diff_res(diff_res, max_diff_values)
593 +
594 +
    # --- case of missmatch: result comparison with different max_diff (unwanted behaviour of
595 +
    # pypower possible)
596 +
    if not pf_match:
597 +
        other_max_diff = {
598 +
            "bus_vm_pu": 1e-3, "bus_va_degree": 1e-3, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6,
599 +
            "gen_p_mw": None, "gen_q_mvar": None}
600 +
        if _validate_diff_res(diff_res, other_max_diff) and \
601 +
                (np.max(abs(pp_res["gen"] - ppc_res["gen"])) > 1e-1).any():
602 +
            logger.debug("The active/reactive power generation difference possibly results "
603 +
                        "because of a pypower error. Please validate "
604 +
                        "the results via pypower loadflow.")  # this occurs e.g. at ppc case9
605 +
606 +
    return pf_match
771 607
772 608
773 609
if __name__ == "__main__":

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.

30 Commits

Hiding 1 contexual commits
+1
-5
+6
Hiding 1 contexual commits
+2
-2
Hiding 1 contexual commits
-118
-41
-77
Hiding 2 contexual commits
+118
+41
+77
Hiding 19 contexual commits
-119
-34
-85
Files Coverage
pandapower 0.24% 76.70%
setup.py 0.00%
Project Totals (189 files) 76.65%
Loading