示例#1
0
def _run_dc_pf(ppci):
    t0 = time()
    baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, _, refgen = _get_pf_variables_from_ppci(
        ppci)

    ## initial state
    Va0 = bus[:, VA] * (pi / 180.)

    ## build B matrices and phase shift injections
    B, Bf, Pbusinj, Pfinj = makeBdc(bus, branch)

    ## updates Bbus matrix
    ppci['internal']['Bbus'] = B

    ## compute complex bus power injections [generation - load]
    ## adjusted for phase shifters and real shunts
    Pbus = makeSbus(baseMVA, bus, gen) - Pbusinj - bus[:, GS] / baseMVA

    ## "run" the power flow
    Va = dcpf(B, Pbus, Va0, ref, pv, pq)

    ## update data matrices with solution
    branch[:, [QF, QT]] = zeros((branch.shape[0], 2))
    branch[:, PF] = (Bf * Va + Pfinj) * baseMVA
    branch[:, PT] = -branch[:, PF]
    bus[:, VA] = Va * (180. / pi)
    ## update Pg for slack generators
    ## (note: other gens at ref bus are accounted for in Pbus)
    ##      Pg = Pinj + Pload + Gs
    ##      newPg = oldPg + newPinj - oldPinj

    ## ext_grid (refgen) buses
    refgenbus = gen[refgen, GEN_BUS].astype(int)
    ## number of ext_grids (refgen) at those buses
    ext_grids_bus = bincount(refgenbus)
    gen[refgen,
        PG] = real(gen[refgen, PG] + (B[refgenbus, :] * Va - Pbus[refgenbus]) *
                   baseMVA / ext_grids_bus[refgenbus])

    # store results from DC powerflow for AC powerflow
    et = time() - t0
    success = True
    iterations = 1
    ppci = _store_results_from_pf_in_ppci(ppci, bus, gen, branch, success,
                                          iterations, et)
    return ppci
from pandapower.pypower.idx_bus import VA, GS
from pandapower.pypower.makeBdc import makeBdc
from pandapower.pypower.makeSbus import makeSbus

pp_net._pd2ppc_lookups = {
    "bus": np.array([], dtype=int),
    "ext_grid": np.array([], dtype=int),
    "gen": np.array([], dtype=int),
    "branch": np.array([], dtype=int)
}
# convert pandapower net to ppc
ppc, ppci = _pd2ppc(pp_net)
baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, _, refgen = _get_pf_variables_from_ppci(
    ppci)
Va0 = bus[:, VA] * (np.pi / 180.)
B, Bf, Pbusinj, Pfinj = makeBdc(bus, branch)
from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_X, TAP, SHIFT, BR_STATUS

Pbus = makeSbus(baseMVA, bus, gen) - Pbusinj - bus[:, GS] / baseMVA
Pbus_pp_ro = Pbus[pp_vect_converter]
error_p = np.abs(np.real(Sdc_me) - np.real(Pbus_pp_ro))
test_ok = True

#### pandapower DC algo (yet another one)
Va = copy.deepcopy(Va0)
pvpq = np.r_[pv, pq]
pvpq_matrix = B[pvpq.T, :].tocsc()[:, pvpq]
ref_matrix = np.transpose(Pbus[pvpq] - B[pvpq.T, :].tocsc()[:, ref] * Va0[ref])
Va[pvpq] = np.real(scipy.sparse.linalg.spsolve(pvpq_matrix, ref_matrix))
####
示例#3
0
def opf_setup(ppc, ppopt):
    """Constructs an OPF model object from a PYPOWER case dict.

    Assumes that ppc is a PYPOWER case dict with internal indexing,
    all equipment in-service, etc.

    @see: L{opf}, L{ext2int}, L{opf_execute}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    @author: Richard Lincoln

    Modified by University of Kassel (Friederike Meier): Bugfix in line 110
    """
    ## options
    dc = ppopt['PF_DC']  ## 1 = DC OPF, 0 = AC OPF
    alg = ppopt['OPF_ALG']
    verbose = ppopt['VERBOSE']

    ## data dimensions
    nb = ppc['bus'].shape[0]  ## number of buses
    nl = ppc['branch'].shape[0]  ## number of branches
    ng = ppc['gen'].shape[0]  ## number of dispatchable injections
    if 'A' in ppc:
        nusr = ppc['A'].shape[0]  ## number of linear user constraints
    else:
        nusr = 0

    if 'N' in ppc:
        nw = ppc['N'].shape[0]  ## number of general cost vars, w
    else:
        nw = 0

    if dc:
        ## ignore reactive costs for DC
        ppc['gencost'], _ = pqcost(ppc['gencost'], ng)

        ## reduce A and/or N from AC dimensions to DC dimensions, if needed
        if nusr or nw:  # pragma: no cover
            acc = r_[nb + arange(nb),
                     2 * nb + ng + arange(ng)]  ## Vm and Qg columns

            if nusr and (ppc['A'].shape[1] >= 2 * nb + 2 * ng):
                ## make sure there aren't any constraints on Vm or Qg
                if ppc['A'][:, acc].nnz > 0:
                    stderr.write(
                        'opf_setup: attempting to solve DC OPF with user constraints on Vm or Qg\n'
                    )

                # FIXME: delete sparse matrix columns
                bcc = delete(arange(ppc['A'].shape[1]), acc)
                ppc['A'] = ppc['A'].tolil()[:, bcc].tocsr(
                )  ## delete Vm and Qg columns

            if nw and (ppc['N'].shape[1] >= 2 * nb + 2 * ng):
                ## make sure there aren't any costs on Vm or Qg
                if ppc['N'][:, acc].nnz > 0:
                    ii, _ = nonzero(ppc['N'][:, acc])
                    _, ii = unique(
                        ii, return_index=True
                    )  ## indices of w with potential non-zero cost terms from Vm or Qg
                    if any(ppc['Cw'][ii]) | (('H' in ppc) & (len(ppc['H']) > 0)
                                             & any(any(ppc['H'][:, ii]))):
                        stderr.write(
                            'opf_setup: attempting to solve DC OPF with user costs on Vm or Qg\n'
                        )

                # FIXME: delete sparse matrix columns
                bcc = delete(arange(ppc['N'].shape[1]), acc)
                ppc['N'] = ppc['N'].tolil()[:, bcc].tocsr(
                )  ## delete Vm and Qg columns

#    ## convert single-block piecewise-linear costs into linear polynomial cost
    pwl1 = find((ppc['gencost'][:, MODEL] == PW_LINEAR)
                & (ppc['gencost'][:, NCOST] == 2))
    # p1 = array([])
    if len(pwl1) > 0:
        x0 = ppc['gencost'][pwl1, COST]
        y0 = ppc['gencost'][pwl1, COST + 1]
        x1 = ppc['gencost'][pwl1, COST + 2]
        y1 = ppc['gencost'][pwl1, COST + 3]
        m = (y1 - y0) / (x1 - x0)
        b = y0 - m * x0
        ppc['gencost'][pwl1, MODEL] = POLYNOMIAL
        ppc['gencost'][pwl1, NCOST] = 2
        ppc['gencost'][pwl1, COST:COST + 2] = r_[
            '1', m.reshape(len(m), 1),
            b.reshape(
                len(b), 1
            )]  # changed from ppc['gencost'][pwl1, COST:COST + 2] = r_[m, b] because we need to make sure, that m and b have the same shape, resulted in a value error due to shape mismatch before

    ## create (read-only) copies of individual fields for convenience
    baseMVA, bus, gen, branch, gencost, _, lbu, ubu, ppopt, \
            _, fparm, H, Cw, z0, zl, zu, userfcn, _ = opf_args(ppc, ppopt)

    ## warn if there is more than one reference bus
    refs = find(bus[:, BUS_TYPE] == REF)
    if len(refs) > 1 and verbose > 0:
        errstr = '\nopf_setup: Warning: Multiple reference buses.\n' + \
            '           For a system with islands, a reference bus in each island\n' + \
            '           may help convergence, but in a fully connected system such\n' + \
            '           a situation is probably not reasonable.\n\n'
        stdout.write(errstr)

    ## set up initial variables and bounds
    gbus = gen[:, GEN_BUS].astype(int)
    Va = bus[:, VA] * (pi / 180.0)
    Vm = bus[:, VM].copy()
    Vm[gbus] = gen[:, VG]  ## buses with gens, init Vm from gen data
    Pg = gen[:, PG] / baseMVA
    Qg = gen[:, QG] / baseMVA
    Pmin = gen[:, PMIN] / baseMVA
    Pmax = gen[:, PMAX] / baseMVA
    Qmin = gen[:, QMIN] / baseMVA
    Qmax = gen[:, QMAX] / baseMVA

    if dc:  ## DC model
        ## more problem dimensions
        nv = 0  ## number of voltage magnitude vars
        nq = 0  ## number of Qg vars
        q1 = array([])  ## index of 1st Qg column in Ay

        ## power mismatch constraints
        B, Bf, Pbusinj, Pfinj = makeBdc(bus, branch)
        neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], arange(ng))),
                        (nb, ng))  ## Pbus w.r.t. Pg
        Amis = hstack([B, neg_Cg], 'csr')
        bmis = -(bus[:, PD] + bus[:, GS]) / baseMVA - Pbusinj

        ## branch flow constraints
        il = find((branch[:, RATE_A] != 0) & (branch[:, RATE_A] < 1e10))
        nl2 = len(il)  ## number of constrained lines
        lpf = -Inf * ones(nl2)
        upf = branch[il, RATE_A] / baseMVA - Pfinj[il]
        upt = branch[il, RATE_A] / baseMVA + Pfinj[il]

        user_vars = ['Va', 'Pg']
        ycon_vars = ['Pg', 'y']
    else:  ## AC model
        ## more problem dimensions
        nv = nb  ## number of voltage magnitude vars
        nq = ng  ## number of Qg vars
        q1 = ng  ## index of 1st Qg column in Ay

        ## dispatchable load, constant power factor constraints
        Avl, lvl, uvl, _ = makeAvl(baseMVA, gen)

        ## generator PQ capability curve constraints
        Apqh, ubpqh, Apql, ubpql, Apqdata = makeApq(baseMVA, gen)

        user_vars = ['Va', 'Vm', 'Pg', 'Qg']
        ycon_vars = ['Pg', 'Qg', 'y']

    ## voltage angle reference constraints
    Vau = Inf * ones(nb)
    Val = -Vau
    Vau[refs] = Va[refs]
    Val[refs] = Va[refs]

    ## branch voltage angle difference limits
    Aang, lang, uang, iang = makeAang(baseMVA, branch, nb, ppopt)

    ## basin constraints for piece-wise linear gen cost variables
    if alg == 545 or alg == 550:  ## SC-PDIPM or TRALM, no CCV cost vars # pragma: no cover
        ny = 0
        Ay = None
        by = array([])
    else:
        ipwl = find(gencost[:, MODEL] == PW_LINEAR)  ## piece-wise linear costs
        ny = ipwl.shape[0]  ## number of piece-wise linear cost vars
        Ay, by = makeAy(baseMVA, ng, gencost, 1, q1, 1 + ng + nq)

    if any((gencost[:, MODEL] != POLYNOMIAL)
           & (gencost[:, MODEL] != PW_LINEAR)):
        stderr.write(
            'opf_setup: some generator cost rows have invalid MODEL value\n')

    ## more problem dimensions
    nx = nb + nv + ng + nq  ## number of standard OPF control variables
    if nusr:  # pragma: no cover
        nz = ppc['A'].shape[1] - nx  ## number of user z variables
        if nz < 0:
            stderr.write(
                'opf_setup: user supplied A matrix must have at least %d columns.\n'
                % nx)
    else:
        nz = 0  ## number of user z variables
        if nw:  ## still need to check number of columns of N
            if ppc['N'].shape[1] != nx:
                stderr.write(
                    'opf_setup: user supplied N matrix must have %d columns.\n'
                    % nx)

    ## construct OPF model object
    om = opf_model(ppc)
    if len(pwl1) > 0:
        om.userdata('pwl1', pwl1)

    if dc:
        om.userdata('Bf', Bf)
        om.userdata('Pfinj', Pfinj)
        om.userdata('iang', iang)
        om.add_vars('Va', nb, Va, Val, Vau)
        om.add_vars('Pg', ng, Pg, Pmin, Pmax)
        om.add_constraints('Pmis', Amis, bmis, bmis, ['Va', 'Pg'])  ## nb
        om.add_constraints('Pf', Bf[il, :], lpf, upf, ['Va'])  ## nl
        om.add_constraints('Pt', -Bf[il, :], lpf, upt, ['Va'])  ## nl
        om.add_constraints('ang', Aang, lang, uang, ['Va'])  ## nang
    else:
        om.userdata('Apqdata', Apqdata)
        om.userdata('iang', iang)
        om.add_vars('Va', nb, Va, Val, Vau)
        om.add_vars('Vm', nb, Vm, bus[:, VMIN], bus[:, VMAX])
        om.add_vars('Pg', ng, Pg, Pmin, Pmax)
        om.add_vars('Qg', ng, Qg, Qmin, Qmax)
        om.add_constraints('Pmis', nb, 'nonlinear')
        om.add_constraints('Qmis', nb, 'nonlinear')
        om.add_constraints('Sf', nl, 'nonlinear')
        om.add_constraints('St', nl, 'nonlinear')
        om.add_constraints('PQh', Apqh, array([]), ubpqh,
                           ['Pg', 'Qg'])  ## npqh
        om.add_constraints('PQl', Apql, array([]), ubpql,
                           ['Pg', 'Qg'])  ## npql
        om.add_constraints('vl', Avl, lvl, uvl, ['Pg', 'Qg'])  ## nvl
        om.add_constraints('ang', Aang, lang, uang, ['Va'])  ## nang

    ## y vars, constraints for piece-wise linear gen costs
    if ny > 0:
        om.add_vars('y', ny)
        om.add_constraints('ycon', Ay, array([]), by, ycon_vars)  ## ncony

    ## execute userfcn callbacks for 'formulation' stage
    run_userfcn(userfcn, 'formulation', om)

    return om
示例#4
0
    def _aux_test(self, pn_net):
        with tempfile.TemporaryDirectory() as path:
            case_name = os.path.join(path, "this_case.json")
            pp.to_json(pn_net, case_name)

            real_init_file = pp.from_json(case_name)
            backend = LightSimBackend()
            with warnings.catch_warnings():
                warnings.filterwarnings("ignore")
                backend.load_grid(case_name)

        nb_sub = backend.n_sub
        pp_net = backend.init_pp_backend._grid
        # first i deactivate all slack bus in pp that are connected but not handled in ls
        pp_net.ext_grid["in_service"].loc[:] = False
        pp_net.ext_grid["in_service"].iloc[0] = True
        conv = backend.runpf()
        conv_pp = backend.init_pp_backend.runpf()

        assert conv_pp, "Error: pandapower do not converge, impossible to perform the necessary checks"
        assert conv, "Error: lightsim do not converge"

        por_pp, qor_pp, vor_pp, aor_pp = copy.deepcopy(
            backend.init_pp_backend.lines_or_info())
        pex_pp, qex_pp, vex_pp, aex_pp = copy.deepcopy(
            backend.init_pp_backend.lines_ex_info())

        # I- Check for divergence and equality of flows"
        por_ls, qor_ls, vor_ls, aor_ls = backend.lines_or_info()
        max_mis = np.max(np.abs(por_ls - por_pp))
        assert max_mis <= self.tol, f"Error: por do not match, maximum absolute error is {max_mis:.5f} MW"
        max_mis = np.max(np.abs(qor_ls - qor_pp))
        assert max_mis <= self.tol, f"Error: qor do not match, maximum absolute error is {max_mis:.5f} MVAr"
        max_mis = np.max(np.abs(vor_ls - vor_pp))
        assert max_mis <= self.tol, f"Error: vor do not match, maximum absolute error is {max_mis:.5f} kV"
        max_mis = np.max(np.abs(aor_ls - aor_pp))
        assert max_mis <= self.tol, f"Error: aor do not match, maximum absolute error is {max_mis:.5f} A"

        # "II - Check for possible solver issues"
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore")
            pp.runpp(backend.init_pp_backend._grid, v_debug=True)
        v_tmp = backend.init_pp_backend._grid.res_bus[
            "vm_pu"].values[:nb_sub] + 0j
        v_tmp *= np.exp(
            1j * np.pi / 180. *
            backend.init_pp_backend._grid.res_bus["va_degree"].values[:nb_sub])
        v_tmp = np.concatenate((v_tmp, v_tmp))
        backend._grid.ac_pf(v_tmp, 1000, 1e-5)

        Y_pp = backend.init_pp_backend._grid._ppc["internal"]["Ybus"]
        Sbus = backend.init_pp_backend._grid._ppc["internal"]["Sbus"]
        pv_ = backend.init_pp_backend._grid._ppc["internal"]["pv"]
        pq_ = backend.init_pp_backend._grid._ppc["internal"]["pq"]
        max_iter = 10
        tol_this = 1e-8
        All_Vms = backend.init_pp_backend._grid._ppc["internal"]["Vm_it"]
        AllVas = backend.init_pp_backend._grid._ppc["internal"]["Va_it"]

        for index_V in range(All_Vms.shape[1] - 1, -1, -1):
            nb_iter = All_Vms.shape[1] - 1
            # i check from easiest to hardest, so from the last iteartion of pandapower to the first iteration of pandapower
            # take the same V as pandapower
            V_init = All_Vms[:, index_V] * (np.cos(AllVas[:, index_V]) +
                                            1j * np.sin(AllVas[:, index_V]))
            # V_init *= np.exp(1j * AllVas[:, 0])
            V_init_ref = copy.deepcopy(V_init)
            solver = ClassSolver()
            solver.solve(scipy.sparse.csc_matrix(Y_pp), V_init, Sbus, pv_, pq_,
                         max_iter, tol_this)
            time_for_nr = solver.get_timers()[3]
            if TIMER_INFO:
                print(
                    f"\t Info: Time to perform {nb_iter - index_V} NR iterations for a grid with {nb_sub} "
                    f"buses: {1000. * time_for_nr:.2f}ms")
            error_va = np.abs(
                solver.get_Va() -
                np.angle(backend.init_pp_backend._grid._ppc["internal"]["V"]))
            assert np.max(error_va) <= self.tol, f"Error: VA do not match for iteration {index_V}, maximum absolute " \
                                                 f"error is {np.max(error_va):.5f} rad"

            error_vm = np.abs(
                np.abs(solver.get_Vm() - np.abs(
                    backend.init_pp_backend._grid._ppc["internal"]["V"])))
            assert np.max(error_vm) <= self.tol, f"\t Error: VM do not match for iteration {index_V}, maximum absolute " \
                                                 f"error  is {np.max(error_vm):.5f} pu"
            solver.reset()

        if TIMER_INFO:
            print("")

        # 'III - Check the data conversion'
        pp_vect_converter = backend.init_pp_backend._grid._pd2ppc_lookups[
            "bus"][:nb_sub]
        pp_net = backend.init_pp_backend._grid

        # 1) Checking Sbus conversion
        Sbus_pp = backend.init_pp_backend._grid._ppc["internal"]["Sbus"]
        Sbus_pp_right_order = Sbus_pp[pp_vect_converter]
        Sbus_me = backend._grid.get_Sbus()
        error_p = np.abs(np.real(Sbus_me) - np.real(Sbus_pp_right_order))
        assert np.max(error_p) <= self.tol, f"\t Error: P do not match for Sbus, maximum absolute error is " \
                                            f"{np.max(error_p):.5f} MW, \t Error: significative difference for bus " \
                                            f"index (lightsim): {np.where(error_p > self.tol)[0]}"

        error_q = np.abs(np.imag(Sbus_me) - np.imag(Sbus_pp_right_order))
        assert np.max(error_q) <= self.tol, f"\t Error: Q do not match for Sbus, maximum absolute error is " \
                                            f"{np.max(error_q):.5f} MVAr, \t Error: significative difference for bus " \
                                            f"index (lightsim): {np.where(error_q > self.tol)[0]}"

        # 2)  Checking Ybus conversion"
        Y_me = backend._grid.get_Ybus()
        Y_pp = backend.init_pp_backend._grid._ppc["internal"]["Ybus"]
        Y_pp_right_order = Y_pp[pp_vect_converter.reshape(nb_sub, 1),
                                pp_vect_converter.reshape(1, nb_sub)]
        error_p = np.abs(np.real(Y_me) - np.real(Y_pp_right_order))
        assert np.max(error_p) <= self.tol, f"Error: P do not match for Ybus, maximum absolute error " \
                                            f"is {np.max(error_p):.5f}"

        error_q = np.abs(np.imag(Y_me) - np.imag(Y_pp_right_order))
        assert np.max(error_q) <= self.tol, f"\t Error: Q do not match for Ybus, maximum absolute error is " \
                                            f"{np.max(error_q):.5f}"

        # "IV - Check for the initialization (dc powerflow)"
        # 1) check that the results are same for dc lightsim and dc pandapower
        Vinit = np.ones(backend.nb_bus_total,
                        dtype=np.complex_) * pp_net["_options"]["init_vm_pu"]
        backend._grid.deactivate_result_computation()
        Vdc = backend._grid.dc_pf(Vinit, max_iter, tol_this)
        backend._grid.reactivate_result_computation()
        Ydc_me = backend._grid.get_Ybus()
        Sdc_me = backend._grid.get_Sbus()
        assert np.max(np.abs(V_init_ref[pp_vect_converter] - Vdc[:nb_sub])) <= 100.*self.tol,\
            f"\t Error for the DC approximation: resulting voltages are different " \
            f"{np.max(np.abs(V_init_ref[pp_vect_converter] - Vdc[:nb_sub])):.5f}pu"

        if np.max(np.abs(V_init_ref[pp_vect_converter] -
                         Vdc[:nb_sub])) >= self.tol:
            warnings.warn(
                "\t Warning: maximum difference after DC approximation is "
                "{np.max(np.abs(V_init_ref[pp_vect_converter] - Vdc[:nb_sub])):.5f} which is higher than "
                "the tolerance (this is just a warning because we noticed this could happen even if the "
                "results match perfectly. Probably some conversion issue with complex number and "
                "radian / degree.")
        # "2) check that the Sbus vector is same for PP and lightisim in DC"
        from pandapower.pd2ppc import _pd2ppc
        from pandapower.pf.run_newton_raphson_pf import _get_pf_variables_from_ppci
        from pandapower.pypower.idx_brch import F_BUS, T_BUS, BR_X, TAP, SHIFT, BR_STATUS
        from pandapower.pypower.idx_bus import VA, GS
        from pandapower.pypower.makeBdc import makeBdc
        from pandapower.pypower.makeSbus import makeSbus

        pp_net._pd2ppc_lookups = {
            "bus": np.array([], dtype=int),
            "ext_grid": np.array([], dtype=int),
            "gen": np.array([], dtype=int),
            "branch": np.array([], dtype=int)
        }
        # convert pandapower net to ppc
        ppc, ppci = _pd2ppc(pp_net)
        baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, _, refgen = _get_pf_variables_from_ppci(
            ppci)
        Va0 = bus[:, VA] * (np.pi / 180.)
        B, Bf, Pbusinj, Pfinj = makeBdc(bus, branch)

        Pbus = makeSbus(baseMVA, bus, gen) - Pbusinj - bus[:, GS] / baseMVA
        Pbus_pp_ro = Pbus[pp_vect_converter]
        error_p = np.abs(np.real(Sdc_me) - np.real(Pbus_pp_ro))
        test_ok = True

        #### pandapower DC algo (yet another one)
        Va = copy.deepcopy(Va0)
        pvpq = np.r_[pv, pq]
        pvpq_matrix = B[pvpq.T, :].tocsc()[:, pvpq]
        ref_matrix = np.transpose(Pbus[pvpq] -
                                  B[pvpq.T, :].tocsc()[:, ref] * Va0[ref])
        Va[pvpq] = np.real(scipy.sparse.linalg.spsolve(pvpq_matrix,
                                                       ref_matrix))
        ####

        assert np.max(error_p) <= self.tol, f"\t Error: P do not match for Sbus (dc), maximum absolute error is " \
                                            f"{np.max(error_p):.5f} MW, \nError: significative difference for bus " \
                                            f"index (lightsim): {np.where(error_p > self.tol)[0]}"

        error_q = np.abs(np.imag(Sdc_me) - np.imag(Pbus_pp_ro))
        assert np.max(error_q) <= self.tol, f"\t Error: Q do not match for Sbus (dc), maximum absolute error is " \
                                            f"{np.max(error_q):.5f} MVAr, \n\t Error: significative difference for " \
                                            f"bus index (lightsim): {np.where(error_q > self.tol)[0]}"

        # "3) check that the Ybus matrix is same for PP and lightisim in DC"
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore")
            pp.rundcpp(pp_net)
        Ydc_pp = backend.init_pp_backend._grid._ppc["internal"]["Bbus"]
        Ydc_pp_right_order = Ydc_pp[pp_vect_converter.reshape(nb_sub, 1),
                                    pp_vect_converter.reshape(1, nb_sub)]
        error_p = np.abs(np.real(Ydc_me) - np.real(Ydc_pp_right_order))
        assert np.max(error_p) <= self.tol, f"Error: P do not match for Ybus (dc mode), maximum absolute error " \
                                            f"is {np.max(error_p):.5f}"
        error_q = np.abs(np.imag(Ydc_me) - np.imag(Ydc_pp_right_order))
        assert np.max(error_q) <= self.tol, f"\t Error: Q do not match for Ybus (dc mdoe), maximum absolute error " \
                                            f"is {np.max(error_q):.5f}"

        # "3) check that lightsim ac pf init with pp dc pf give same results (than pp)"
        Vinit = np.ones(backend.nb_bus_total,
                        dtype=np.complex_) * pp_net["_options"]["init_vm_pu"]
        Vinit[:nb_sub] = V_init_ref[pp_vect_converter]
        conv = backend._grid.ac_pf(Vinit, max_iter, tol_this)
        assert conv.shape[
            0] > 0, "\t Error: the lightsim diverge when initialized with pandapower Vinit_dc"
        lpor, lqor, lvor, laor = backend._grid.get_lineor_res()
        tpor, tqor, tvor, taor = backend._grid.get_trafohv_res()
        tpex, tqex, tvex, taex = backend._grid.get_trafolv_res()
        nb_trafo = tpor.shape[0]
        nb_powerline = lpor.shape[0]
        p_or_me2 = np.concatenate((lpor, tpor))
        q_or_me2 = np.concatenate((lqor, tqor))
        v_or_me2 = np.concatenate((lvor, tvor))
        a_or_me2 = 1000. * np.concatenate((laor, taor))
        test_ok = True
        # pdb.set_trace()
        max_mis = np.max(np.abs(p_or_me2 - por_pp))
        assert np.max(
            error_q
        ) <= self.tol, f"\t Error: por do not match, maximum absolute error is {max_mis:.5f} MW"
        max_mis = np.max(np.abs(q_or_me2 - qor_pp))
        assert np.max(
            error_q
        ) <= self.tol, f"\t Error: qor do not match, maximum absolute error is {max_mis:.5f} MVAr"
        max_mis = np.max(np.abs(v_or_me2 - vor_pp))
        assert np.max(
            error_q
        ) <= self.tol, f"\t Error: vor do not match, maximum absolute error is {max_mis:.5f} kV"
        max_mis = np.max(np.abs(a_or_me2 - aor_pp))
        assert np.max(
            error_q
        ) <= self.tol, f"\t Error: aor do not match, maximum absolute error is {max_mis:.5f} A"

        # "V - Check trafo proper conversion to r,x, b"
        from lightsim2grid_cpp import GridModel, PandaPowerConverter, SolverType
        from pandapower.build_branch import _calc_branch_values_from_trafo_df, get_trafo_values
        from pandapower.build_branch import _calc_nominal_ratio_from_dataframe, _calc_r_x_y_from_dataframe
        from pandapower.build_branch import _calc_tap_from_dataframe, BASE_KV, _calc_r_x_from_dataframe

        # my trafo parameters
        converter = PandaPowerConverter()
        converter.set_sn_mva(pp_net.sn_mva)
        converter.set_f_hz(pp_net.f_hz)
        tap_neutral = 1.0 * pp_net.trafo["tap_neutral"].values
        tap_neutral[~np.isfinite(tap_neutral)] = 0.
        if np.any(tap_neutral != 0.):
            raise RuntimeError(
                "lightsim converter supposes that tap_neutral is 0 for the transformers"
            )
        tap_step_pct = 1.0 * pp_net.trafo["tap_step_percent"].values
        tap_step_pct[~np.isfinite(tap_step_pct)] = 0.
        tap_pos = 1.0 * pp_net.trafo["tap_pos"].values
        tap_pos[~np.isfinite(tap_pos)] = 0.
        shift_ = 1.0 * pp_net.trafo["shift_degree"].values
        shift_[~np.isfinite(shift_)] = 0.
        is_tap_hv_side = pp_net.trafo["tap_side"].values == "hv"
        is_tap_hv_side[~np.isfinite(is_tap_hv_side)] = True
        if np.any(pp_net.trafo["tap_phase_shifter"].values):
            raise RuntimeError(
                "ideal phase shifter are not modeled. Please remove all trafo with "
                "pp_net.trafo[\"tap_phase_shifter\"] set to True.")
        tap_angles_ = 1.0 * pp_net.trafo["tap_step_degree"].values
        tap_angles_[~np.isfinite(tap_angles_)] = 0.
        tap_angles_ = np.deg2rad(tap_angles_)
        trafo_r, trafo_x, trafo_b = \
            converter.get_trafo_param(tap_step_pct,
                                      tap_pos,
                                      tap_angles_,  # in radian !
                                      is_tap_hv_side,
                                      pp_net.bus.loc[pp_net.trafo["hv_bus"]]["vn_kv"],
                                      pp_net.bus.loc[pp_net.trafo["lv_bus"]]["vn_kv"],
                                      pp_net.trafo["vk_percent"].values,
                                      pp_net.trafo["vkr_percent"].values,
                                      pp_net.trafo["sn_mva"].values,
                                      pp_net.trafo["pfe_kw"].values,
                                      pp_net.trafo["i0_percent"].values,
                                      )
        # pandapower trafo parameters
        ppc = copy.deepcopy(pp_net._ppc)
        bus_lookup = pp_net["_pd2ppc_lookups"]["bus"]
        trafo_df = pp_net["trafo"]
        lv_bus = get_trafo_values(trafo_df, "lv_bus")
        vn_lv = ppc["bus"][bus_lookup[lv_bus], BASE_KV]
        vn_trafo_hv, vn_trafo_lv, shift_pp = _calc_tap_from_dataframe(
            pp_net, trafo_df)
        ratio = _calc_nominal_ratio_from_dataframe(ppc, trafo_df, vn_trafo_hv,
                                                   vn_trafo_lv, bus_lookup)
        r_t, x_t, b_t = _calc_r_x_y_from_dataframe(pp_net, trafo_df,
                                                   vn_trafo_lv, vn_lv,
                                                   pp_net.sn_mva)

        # check where there are mismatch if any
        val_r_pp = r_t
        val_r_me = trafo_r
        all_equals_r = np.abs(val_r_pp - val_r_me) <= self.tol
        if not np.all(all_equals_r):
            test_ok = False
            print(
                f"\t Error: some trafo resistance are not equal, max error: {np.max(np.abs(val_r_pp - val_r_me)):.5f}"
            )

        val_x_pp = x_t
        val_x_me = trafo_x
        all_equals_x = np.abs(val_x_pp - val_x_me) <= self.tol
        assert np.all(all_equals_x), f"\t Error: some trafo x are not equal, max error: " \
                                     f"{np.max(np.abs(val_x_pp - val_x_me)):.5f}"

        val_ib_pp = np.imag(b_t)
        val_ib_me = np.imag(trafo_b)
        all_equals_imag_b = np.abs(val_ib_pp - val_ib_me) <= self.tol
        assert np.all(all_equals_imag_b), f"\t Error: some trafo (imag) b are not equal, max error: " \
                                          f"{np.max(np.abs(val_ib_pp - val_ib_me)):.5f}"

        val_reb_pp = np.real(b_t)
        val_reb_me = np.real(trafo_b)
        all_equals_real_b = np.abs(val_reb_pp - val_reb_me) <= self.tol
        assert np.all(all_equals_real_b), f"\t Error: some trafo (real) b are not equal, max error: " \
                                          f"{np.max(np.abs(val_reb_pp - val_reb_me)):.5f}"