Beispiel #1
0
def _powerflow(net, **kwargs):
    """
    Gets called by runpp or rundcpp with different arguments.
    """

    # get infos from options
    init_results = net["_options"]["init_results"]
    ac = net["_options"]["ac"]
    recycle = net["_options"]["recycle"]
    mode = net["_options"]["mode"]
    algorithm = net["_options"]["algorithm"]
    max_iteration = net["_options"]["max_iteration"]

    net["converged"] = False
    net["OPF_converged"] = False
    _add_auxiliary_elements(net)

    if not ac or init_results:
        verify_results(net)
    else:
        reset_results(net)

    # TODO remove this when zip loads are integrated for all PF algorithms
    if algorithm not in ['nr', 'bfsw']:
        net["_options"]["voltage_depend_loads"] = False

    if recycle["ppc"] and "_ppc" in net and net[
            "_ppc"] is not None and "_pd2ppc_lookups" in net:
        # update the ppc from last cycle
        ppc, ppci = _update_ppc(net)
    else:
        # convert pandapower net to ppc
        ppc, ppci = _pd2ppc(net)

    # store variables
    net["_ppc"] = ppc

    if not "VERBOSE" in kwargs:
        kwargs["VERBOSE"] = 0

    # ----- run the powerflow -----
    result = _run_pf_algorithm(ppci, net["_options"], **kwargs)

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    result = _copy_results_ppci_to_ppc(result, ppc, mode)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        _clean_up(net, res=False)
        raise LoadflowNotConverged("Power Flow {0} did not converge after "
                                   "{1} iterations!".format(
                                       algorithm, max_iteration))
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result)
    _clean_up(net)
Beispiel #2
0
def _runpppf_dd(net, init, ac, calculate_voltage_angles, tolerance_kva,
                trafo_model, trafo_loading, enforce_q_lims, numba, recycle,
                **kwargs):
    """
    Gets called by runpp or rundcpp with different arguments.
    """

    net["converged"] = False
    if (ac and not init == "results") or not ac:
        reset_results(net)

    # select elements in service (time consuming, so we do it once)
    is_elems = _select_is_elements(net, recycle)

    if recycle["ppc"] and "_ppc" in net and net[
            "_ppc"] is not None and "_bus_lookup" in net:
        # update the ppc from last cycle
        ppc, ppci, bus_lookup = _update_ppc(net, is_elems, recycle,
                                            calculate_voltage_angles,
                                            enforce_q_lims, trafo_model)
    else:
        # convert pandapower net to ppc
        ppc, ppci, bus_lookup = _pd2ppc(net,
                                        is_elems,
                                        calculate_voltage_angles,
                                        enforce_q_lims,
                                        trafo_model,
                                        init_results=(init == "results"))

    # store variables
    net["_ppc"] = ppc
    net["_bus_lookup"] = bus_lookup
    net["_is_elems"] = is_elems

    if not "VERBOSE" in kwargs:
        kwargs["VERBOSE"] = 0

    # run the powerflow
    result = _run_fbsw(ppci,
                       ppopt=ppoption(ENFORCE_Q_LIMS=enforce_q_lims,
                                      PF_TOL=tolerance_kva * 1e-3,
                                      **kwargs))[0]

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    result = _copy_results_ppci_to_ppc(result, ppc, bus_lookup)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        raise LoadflowNotConverged("Loadflow did not converge!")
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result, is_elems, bus_lookup, trafo_loading, ac)
    _clean_up(net)
Beispiel #3
0
def _powerflow(net, **kwargs):
    """
    Gets called by runpp or rundcpp with different arguments.
    """

    # get infos from options
    init = net["_options"]["init"]
    ac = net["_options"]["ac"]
    recycle = net["_options"]["recycle"]
    mode = net["_options"]["mode"]

    net["converged"] = False
    _add_auxiliary_elements(net)

    if (ac and not init == "results") or not ac:
        reset_results(net)

    if recycle["ppc"] and "_ppc" in net and net[
            "_ppc"] is not None and "_pd2ppc_lookups" in net:
        # update the ppc from last cycle
        ppc, ppci = _update_ppc(net)
    else:
        # convert pandapower net to ppc
        ppc, ppci = _pd2ppc(net)

    # store variables
    net["_ppc"] = ppc

    if not "VERBOSE" in kwargs:
        kwargs["VERBOSE"] = 0

    # ----- run the powerflow -----
    result = _run_pf_algorithm(ppci, net["_options"], **kwargs)

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    result = _copy_results_ppci_to_ppc(result, ppc, mode)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        raise LoadflowNotConverged("Power Flow did not converge!")
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result)
    _clean_up(net)
Beispiel #4
0
def read_pm_results_to_net(net, ppc, ppci, result_pm):
    """
    reads power models results from result_pm to ppc / ppci and then to pandapower net
    """
    # read power models results from result_pm to result (== ppc with results)
    result, multinetwork = pm_results_to_ppc_results(net, ppc, ppci, result_pm)
    net._pm_result = result_pm
    success = ppc["success"]
    if success:
        if not multinetwork:
            # results are extracted from a single time step to pandapower dataframes
            _extract_results(net, result)
        _clean_up(net)
        net["OPF_converged"] = True
    else:
        _clean_up(net, res=False)
        logger.warning("OPF did not converge!")
Beispiel #5
0
def _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model,
             trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs):
    """
    Gets called by runpp or rundcpp with different arguments.
    """

    net["converged"] = False
    if (ac and not init == "results") or not ac:
        reset_results(net)

    # select elements in service (time consuming, so we do it once)
    is_elems = _select_is_elements(net)

    # convert pandapower net to ppc
    ppc, ppci, bus_lookup = _pd2ppc(net, is_elems, calculate_voltage_angles, enforce_q_lims,
                                   trafo_model, init_results=(init == "results"))
    net["_ppc"] = ppc
    if not "VERBOSE" in kwargs:
        kwargs["VERBOSE"] = 0

    # run the powerflow with or without warnings. If init='dc', AC PF will be
    # initialized with DC voltages
    if suppress_warnings:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            result = _runpf(ppci, init, ac, Numba, ppopt=ppopt.ppoption(ENFORCE_Q_LIMS=enforce_q_lims,
                                                                       PF_TOL=tolerance_kva * 1e-3, **kwargs))[0]

    else:
        result = _runpf(ppci, init, ac, Numba, ppopt=ppopt.ppoption(ENFORCE_Q_LIMS=enforce_q_lims,
                                                                   PF_TOL=tolerance_kva * 1e-3, **kwargs))[0]

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    result = _copy_results_ppci_to_ppc(result, ppc)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        raise LoadflowNotConverged("Loadflow did not converge!")
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result, is_elems, bus_lookup, trafo_loading, ac)
    _clean_up(net)
Beispiel #6
0
def _ppci_to_net(result, net):
    # reads the results from result (== ppci with results) to pandapower net

    mode = net["_options"]["mode"]
    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    ppc = net["_ppc"]
    result = _copy_results_ppci_to_ppc(result, ppc, mode)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        _clean_up(net, res=False)
        algorithm = net["_options"]["algorithm"]
        max_iteration = net["_options"]["max_iteration"]
        raise LoadflowNotConverged("Power Flow {0} did not converge after "
                                   "{1} iterations!".format(algorithm, max_iteration))
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result)
    _clean_up(net)
Beispiel #7
0
def read_pm_results_to_net(net, ppc, ppci, result_pm):
    """
    reads power models results from result_pm to ppc / ppci and then to pandapower net
    """
    # read power models results from result_pm to result (== ppc with results)
    net._pm_result_orig = result_pm
    result_pm = _deep_copy_pm_results(result_pm)
    result_pm = _convert_pm_units_to_pp_units(result_pm, net.sn_mva)
    net._pm_result = result_pm
    result, multinetwork = pm_results_to_ppc_results(net, ppc, ppci, result_pm)
    success = ppc["success"]
    if success:
        if not multinetwork:
            # results are extracted from a single time step to pandapower dataframes
            _extract_results(net, result)
        _clean_up(net)
        net["OPF_converged"] = True
    else:
        _clean_up(net, res=False)
        logger.warning("OPF did not converge!")
        raise OPFNotConverged("PowerModels.jl OPF not converged")
Beispiel #8
0
def _runpm(net):  #pragma: no cover
    net["OPF_converged"] = False
    net["converged"] = False
    _add_auxiliary_elements(net)
    reset_results(net)
    ppc, ppci = _pd2ppc(net)
    net["_ppc_opf"] = ppci
    pm = ppc_to_pm(net, ppci)
    net._pm = pm
    if net._options["pp_to_pm_callback"] is not None:
        net._options["pp_to_pm_callback"](net, ppci, pm)
    result_pm = _call_powermodels(pm, net._options["julia_file"])
    net._pm_res = result_pm
    result = pm_results_to_ppc_results(net, ppc, ppci, result_pm)
    net._pm_result = result_pm
    success = ppc["success"]
    if success:
        _extract_results(net, result)
        _clean_up(net)
        net["OPF_converged"] = True
    else:
        _clean_up(net, res=False)
        logger.warning("OPF did not converge!")
Beispiel #9
0
def _optimal_powerflow(net, verbose, suppress_warnings, **kwargs):
    ac = net["_options"]["ac"]
    init = net["_options"]["init"]

    ppopt = ppoption(VERBOSE=verbose,
                     OPF_FLOW_LIM=2,
                     PF_DC=not ac,
                     INIT=init,
                     **kwargs)
    net["OPF_converged"] = False
    net["converged"] = False
    _add_auxiliary_elements(net)
    reset_results(net, all_empty=False)

    ppc, ppci = _pd2ppc(net)

    if not ac:
        ppci["bus"][:, VM] = 1.0
    net["_ppc_opf"] = ppci
    if len(net.dcline) > 0:
        ppci = add_userfcn(ppci,
                           'formulation',
                           _add_dcline_constraints,
                           args=net)

    if init == "pf":
        ppci = _run_pf_before_opf(net, ppci)
    if suppress_warnings:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            result = opf(ppci, ppopt)
    else:
        result = opf(ppci, ppopt)


#    net["_ppc_opf"] = result

    if verbose:
        ppopt['OUT_ALL'] = 1
        printpf(baseMVA=result["baseMVA"],
                bus=result["bus"],
                gen=result["gen"],
                fd=stdout,
                branch=result["branch"],
                success=result["success"],
                et=result["et"],
                ppopt=ppopt)

    if verbose:
        ppopt['OUT_ALL'] = 1
        printpf(baseMVA=result["baseMVA"],
                bus=result["bus"],
                gen=result["gen"],
                fd=stdout,
                branch=result["branch"],
                success=result["success"],
                et=result["et"],
                ppopt=ppopt)

    if not result["success"]:
        raise OPFNotConverged("Optimal Power Flow did not converge!")

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    mode = net["_options"]["mode"]
    result = _copy_results_ppci_to_ppc(result, ppc, mode=mode)

    #    net["_ppc_opf"] = result
    net["OPF_converged"] = True
    _extract_results(net, result)
    _clean_up(net)
Beispiel #10
0
def _optimal_powerflow(net, verbose, suppress_warnings, **kwargs):
    ac = net["_options"]["ac"]
    init = net["_options"]["init"]

    if "OPF_FLOW_LIM" not in kwargs:
        kwargs["OPF_FLOW_LIM"] = 2

    if net["_options"]["voltage_depend_loads"] and not (
            allclose(net.load.const_z_percent.values, 0)
            and allclose(net.load.const_i_percent.values, 0)):
        logger.error(
            "pandapower optimal_powerflow does not support voltage depend loads."
        )

    ppopt = ppoption(VERBOSE=verbose, PF_DC=not ac, INIT=init, **kwargs)
    net["OPF_converged"] = False
    net["converged"] = False
    _add_auxiliary_elements(net)

    if not ac or net["_options"]["init_results"]:
        verify_results(net)
    else:
        init_results(net, "opf")

    ppc, ppci = _pd2ppc(net)

    if not ac:
        ppci["bus"][:, VM] = 1.0
    net["_ppc_opf"] = ppci
    if len(net.dcline) > 0:
        ppci = add_userfcn(ppci,
                           'formulation',
                           _add_dcline_constraints,
                           args=net)

    if init == "pf":
        ppci = _run_pf_before_opf(net, ppci)
    if suppress_warnings:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            result = opf(ppci, ppopt)
    else:
        result = opf(ppci, ppopt)


#    net["_ppc_opf"] = result

    if verbose:
        ppopt['OUT_ALL'] = 1
        printpf(baseMVA=result["baseMVA"],
                bus=result["bus"],
                gen=result["gen"],
                branch=result["branch"],
                f=result["f"],
                success=result["success"],
                et=result["et"],
                fd=stdout,
                ppopt=ppopt)

    if not result["success"]:
        raise OPFNotConverged("Optimal Power Flow did not converge!")

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    mode = net["_options"]["mode"]
    result = _copy_results_ppci_to_ppc(result, ppc, mode=mode)

    #    net["_ppc_opf"] = result
    net["OPF_converged"] = True
    _extract_results(net, result)
    _clean_up(net)
Beispiel #11
0
    def estimate(self,
                 v_start=None,
                 delta_start=None,
                 calculate_voltage_angles=True):
        """
        The function estimate is the main function of the module. It takes up to three input
        arguments: v_start, delta_start and calculate_voltage_angles. The first two are the initial
        state variables for the estimation process. Usually they can be initialized in a
        "flat-start" condition: All voltages being 1.0 pu and all voltage angles being 0 degrees.
        In this case, the parameters can be left at their default values (None). If the estimation
        is applied continuously, using the results from the last estimation as the starting
        condition for the current estimation can decrease the  amount of iterations needed to
        estimate the current state. The third parameter defines whether all voltage angles are
        calculated absolutely, including phase shifts from transformers. If only the relative
        differences between buses are required, this parameter can be set to False. Returned is a
        boolean value, which is true after a successful estimation and false otherwise.
        The resulting complex voltage will be written into the pandapower network. The result
        fields are found res_bus_est of the pandapower network.

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

            **v_start** (np.array, shape=(1,), optional) - Vector with initial values for all
            voltage magnitudes in p.u. (sorted by bus index)

            **delta_start** (np.array, shape=(1,), optional) - Vector with initial values for all
            voltage angles in degrees (sorted by bus index)

        OPTIONAL:
            **calculate_voltage_angles** - (bool) - Take into account absolute voltage angles and
            phase shifts in transformers Default is True.

        OUTPUT:
            **successful** (boolean) - True if the estimation process was successful

        Optional estimation variables:
            The bus power injections can be accessed with *se.s_node_powers* and the estimated
            values corresponding to the (noisy) measurement values with *se.hx*. (*hx* denotes h(x))

        EXAMPLE:
            success = estimate(np.array([1.0, 1.0, 1.0]), np.array([0.0, 0.0, 0.0]))

        """
        if self.net is None:
            raise UserWarning("Component was not initialized with a network.")

        # add initial values for V and delta
        # node voltages
        # V<delta
        if v_start is None:
            v_start = np.ones(self.net.bus.shape[0])
        if delta_start is None:
            delta_start = np.zeros(self.net.bus.shape[0])

        # initialize result tables if not existant
        _copy_power_flow_results(self.net)

        # initialize ppc
        ppc, ppci = _init_ppc(self.net, v_start, delta_start,
                              calculate_voltage_angles)
        mapping_table = self.net["_pd2ppc_lookups"]["bus"]

        # add measurements to ppci structure
        ppci = _add_measurements_to_ppc(self.net, mapping_table, ppci,
                                        self.s_ref)

        # calculate relevant vectors from ppci measurements
        z, self.pp_meas_indices, r_cov = _build_measurement_vectors(ppci)

        # number of nodes
        n_active = len(np.where(ppci["bus"][:, 1] != 4)[0])
        slack_buses = np.where(ppci["bus"][:, 1] == 3)[0]

        # Check if observability criterion is fulfilled and the state estimation is possible
        if len(z) < 2 * n_active - 1:
            self.logger.error("System is not observable (cancelling)")
            self.logger.error(
                "Measurements available: %d. Measurements required: %d" %
                (len(z), 2 * n_active - 1))
            return False

        # set the starting values for all active buses
        v_m = ppci["bus"][:, 7]
        delta = ppci["bus"][:, 8] * np.pi / 180  # convert to rad
        delta_masked = np.ma.array(delta, mask=False)
        delta_masked.mask[slack_buses] = True
        non_slack_buses = np.arange(len(delta))[~delta_masked.mask]

        # matrix calculation object
        sem = wls_matrix_ops(ppci, slack_buses, non_slack_buses, self.s_ref,
                             bus_cols, branch_cols)

        # state vector
        E = np.concatenate((delta_masked.compressed(), v_m))

        # invert covariance matrix
        r_inv = csr_matrix(np.linalg.inv(np.diagflat(r_cov)**2))

        current_error = 100.
        current_iterations = 0

        while current_error > self.tolerance and current_iterations < self.max_iterations:
            self.logger.debug(" Starting iteration %d" %
                              (1 + current_iterations))
            try:
                # create h(x) for the current iteration
                h_x = sem.create_hx(v_m, delta)

                # residual r
                r = csr_matrix(z - h_x).T

                # jacobian matrix H
                H = csr_matrix(sem.create_jacobian(v_m, delta))

                # gain matrix G_m
                # G_m = H^t * R^-1 * H
                G_m = H.T * (r_inv * H)

                # state vector difference d_E
                # d_E = G_m^-1 * (H' * R^-1 * r)
                d_E = spsolve(G_m, H.T * (r_inv * r))
                E += d_E

                # update V/delta
                delta[non_slack_buses] = E[:len(non_slack_buses)]
                v_m = np.squeeze(E[len(non_slack_buses):])

                # prepare next iteration
                current_iterations += 1
                current_error = np.max(np.abs(d_E))
                self.logger.debug("Current error: %.4f" % current_error)

            except np.linalg.linalg.LinAlgError:
                self.logger.error(
                    "A problem appeared while using the linear algebra methods."
                    "Check and change the measurement set.")
                return False

        # print output for results
        if current_error <= self.tolerance:
            successful = True
            self.logger.info(
                "WLS State Estimation successful (%d iterations)" %
                current_iterations)
        else:
            successful = False
            self.logger.info(
                "WLS State Estimation not successful (%d/%d iterations)" %
                (current_iterations, self.max_iterations))

        # store results for all elements
        # write voltage into ppc
        ppci["bus"][:, 7] = v_m
        ppci["bus"][:, 8] = delta * 180 / np.pi  # convert to degree

        # calculate bus power injections
        v_cpx = v_m * np.exp(1j * delta)
        bus_powers_conj = np.zeros(len(v_cpx), dtype=np.complex128)
        for i in range(len(v_cpx)):
            bus_powers_conj[i] = np.dot(sem.Y_bus[i, :], v_cpx) * np.conjugate(
                v_cpx[i])
        ppci["bus"][:, 2] = bus_powers_conj.real  # saved in per unit
        ppci["bus"][:, 3] = -bus_powers_conj.imag  # saved in per unit

        # calculate line results (in ppc_i)
        s_ref, bus, gen, branch = _get_pf_variables_from_ppci(ppci)[0:4]
        out = np.flatnonzero(branch[:,
                                    BR_STATUS] == 0)  # out-of-service branches
        br = np.flatnonzero(branch[:, BR_STATUS]).astype(
            int)  # in-service branches
        # complex power at "from" bus
        Sf = v_cpx[np.real(branch[br, F_BUS]).astype(int)] * np.conj(
            sem.Yf[br, :] * v_cpx) * s_ref
        # complex power injected at "to" bus
        St = v_cpx[np.real(branch[br, T_BUS]).astype(int)] * np.conj(
            sem.Yt[br, :] * v_cpx) * s_ref
        branch[np.ix_(br, [PF, QF, PT, QT])] = np.c_[Sf.real, Sf.imag, St.real,
                                                     St.imag]
        branch[np.ix_(out, [PF, QF, PT, QT])] = np.zeros((len(out), 4))
        ppci = _store_results_from_pf_in_ppci(ppci, bus, gen, branch)

        # convert to pandapower indices
        ppc = _copy_results_ppci_to_ppc(ppci, ppc, mode="se")

        # extract results from ppc
        _add_pf_options(self.net,
                        tolerance_kva=1e-5,
                        trafo_loading="current",
                        numba=True,
                        ac=True,
                        algorithm='nr',
                        max_iteration="auto")
        _extract_results(self.net, ppc)

        # restore backup of previous results
        _rename_results(self.net)

        # additionally, write bus results (these are not written in _extract_results)
        self.net.res_bus_est.p_kw = -get_values(
            ppc["bus"][:, 2], self.net.bus.index,
            mapping_table) * self.s_ref / 1e3
        self.net.res_bus_est.q_kvar = -get_values(
            ppc["bus"][:, 3], self.net.bus.index,
            mapping_table) * self.s_ref / 1e3

        # store variables required for chi^2 and r_N_max test:
        self.R_inv = r_inv.toarray()
        self.Gm = G_m.toarray()
        self.r = r.toarray()
        self.H = H.toarray()
        self.Ht = self.H.T
        self.hx = h_x
        self.V = v_m
        self.delta = delta
        return successful
Beispiel #12
0
    def ts_newtonpf(self, net):
        options = net["_options"]

        bus = self.ppci["bus"]
        branch = self.ppci["branch"]
        gen = self.ppci["gen"]
        # compute complex bus power injections [generation - load]
        # self.Cg = _get_Cg(gen_on, bus)
        # Sbus = _get_Sbus(self.baseMVA, bus, gen, self.Cg)
        Sbus = makeSbus(self.baseMVA, bus, gen)

        # run the newton power  flow
        V, success, _, _, _, _ = nr_pf.newtonpf(self.Ybus, Sbus, self.V,
                                                self.pv, self.pq, self.ppci,
                                                options)

        if not success:
            logger.warning("Loadflow not converged")
            logger.info("Lines of of service:")
            logger.info(net.line[~net.line.in_service])
            raise LoadflowNotConverged("Power Flow did not converge after")

        if self.ppci["gen"].shape[
                0] == 1 and not options["voltage_depend_loads"]:
            pfsoln = pf_solution_single_slack
        else:
            pfsoln = pfsoln_full

        bus, gen, branch = pfsoln(self.baseMVA,
                                  bus,
                                  gen,
                                  branch,
                                  self.Ybus,
                                  self.Yf,
                                  self.Yt,
                                  V,
                                  self.ref,
                                  self.ref_gens,
                                  Ibus=self.Ibus)

        self.ppci["bus"] = bus
        self.ppci["branch"] = branch
        self.ppci["gen"] = gen
        self.ppci["success"] = success
        self.ppci["et"] = None

        # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
        self.ppc = _copy_results_ppci_to_ppc(self.ppci, self.ppc,
                                             options["mode"])

        # raise if PF was not successful. If DC -> success is always 1
        if self.ppc["success"] != 1:
            _clean_up(net, res=False)
        else:
            net["_ppc"] = self.ppc
            net["converged"] = True

        self.V = V

        _extract_results(net, self.ppc)

        return net
Beispiel #13
0
def _runpppf(net, **kwargs):
    """
    Gets called by runpp or rundcpp with different arguments.
    """

    # get infos from options
    init = net["_options"]["init"]
    ac = net["_options"]["ac"]
    recycle = net["_options"]["recycle"]
    numba = net["_options"]["numba"]
    enforce_q_lims = net["_options"]["enforce_q_lims"]
    tolerance_kva = net["_options"]["tolerance_kva"]
    mode = net["_options"]["mode"]
    algorithm = net["_options"]["algorithm"]
    max_iteration = net["_options"]["max_iteration"]

    net["converged"] = False
    _add_auxiliary_elements(net)

    if (ac and not init == "results") or not ac:
        reset_results(net)

    # select elements in service (time consuming, so we do it once)
    net["_is_elems"] = _select_is_elements(net, recycle)

    if recycle["ppc"] and "_ppc" in net and net[
            "_ppc"] is not None and "_pd2ppc_lookups" in net:
        # update the ppc from last cycle
        ppc, ppci = _update_ppc(net, recycle)
    else:
        # convert pandapower net to ppc
        ppc, ppci = _pd2ppc(net)

    # store variables
    net["_ppc"] = ppc

    if not "VERBOSE" in kwargs:
        kwargs["VERBOSE"] = 0

    # run the powerflow

    # algorithms implemented within pypower
    algorithm_pypower_dict = {'nr': 1, 'fdBX': 2, 'fdXB': 3, 'gs': 4}

    if algorithm == 'fbsw':  # foreward/backward sweep power flow algorithm
        result = _run_fbsw_ppc(ppci,
                               ppopt=ppoption(ENFORCE_Q_LIMS=enforce_q_lims,
                                              PF_TOL=tolerance_kva * 1e-3,
                                              PF_MAX_IT_GS=max_iteration,
                                              **kwargs))[0]

    elif algorithm in algorithm_pypower_dict:
        ppopt = ppoption(**kwargs)
        ppopt['PF_ALG'] = algorithm_pypower_dict[algorithm]
        ppopt['ENFORCE_Q_LIMS'] = enforce_q_lims
        ppopt['PF_TOL'] = tolerance_kva
        if max_iteration is not None:
            if algorithm == 'nr':
                ppopt['PF_MAX_IT'] = max_iteration
            elif algorithm == 'gs':
                ppopt['PF_MAX_IT_GS'] = max_iteration
            else:
                ppopt['PF_MAX_IT_FD'] = max_iteration

        result = _runpf(ppci,
                        init,
                        ac,
                        numba,
                        recycle,
                        ppopt=ppoption(ENFORCE_Q_LIMS=enforce_q_lims,
                                       PF_TOL=tolerance_kva * 1e-3,
                                       **kwargs))[0]

    else:
        AlgorithmUnknown("Algorithm {0} is unknown!".format(algorithm))

    # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
    result = _copy_results_ppci_to_ppc(result, ppc, mode)

    # raise if PF was not successful. If DC -> success is always 1
    if result["success"] != 1:
        raise LoadflowNotConverged("Loadflow did not converge!")
    else:
        net["_ppc"] = result
        net["converged"] = True

    _extract_results(net, result)
    _clean_up(net)