def Jacobian(Ybus, V, Ibus, pq, pvpq):
    """
    Computes the system Jacobian matrix
    Args:
        Ybus: Admittance matrix
        V: Array of nodal voltages
        Ibus: Array of nodal current injections
        pq: Array with the indices of the PQ buses
        pvpq: Array with the indices of the PV and PQ buses

    Returns:
        The system Jacobian matrix
    """
    # dS_dVm, dS_dVa = dSbus_dV(Ybus, V, Ibus)  # compute the derivatives

    I = Ybus * V - Ibus

    diagV = diags(V)
    diagI = diags(I)
    diagVnorm = diags(V / np.abs(V))

    dS_dVm = diagV * conj(Ybus * diagVnorm) + conj(diagI) * diagVnorm
    dS_dVa = 1j * diagV * conj(diagI - Ybus * diagV)

    J11 = dS_dVa[array([pvpq]).T, pvpq].real
    J12 = dS_dVm[array([pvpq]).T, pq].real
    J21 = dS_dVa[array([pq]).T, pvpq].imag
    J22 = dS_dVm[array([pq]).T, pq].imag

    J = vstack_sp([hstack_sp([J11, J12]), hstack_sp([J21, J22])], format="csr")

    return J
Example #2
0
def Jrect(G, B, V, pvpq, pqpv, pq, pv):

    e = V.real
    f = V.imag
    ediag = diags(e)
    fdiag = diags(f)

    J1 = ediag * G + fdiag * B + diags(G * e - B * f)
    J2 = fdiag * G - ediag * B + diags(G * f + B * e)
    J3 = fdiag * G - ediag * B - diags(G * f + B * e)
    J4 = -ediag * G - fdiag * B + diags(G * e - B * f)
    J5 = diags(2 * e).tocsc()
    J6 = diags(2 * f).tocsc()

    J = vstack_sp([
        hstack_sp([J1[np.ix_(pvpq, pvpq)], J2[np.ix_(pvpq, pqpv)]]),
        hstack_sp([J3[np.ix_(pq, pvpq)], J4[np.ix_(pq, pqpv)]]),
        hstack_sp([J5[np.ix_(pv, pvpq)], J6[np.ix_(pv, pqpv)]])
    ],
                  format="csc")
    return J
Example #3
0
def Jacobian_I(Ybus, V, pq, pvpq):
    """
    Computes the system Jacobian matrix
    Args:
        Ybus: Admittance matrix
        V: Array of nodal voltages
        pq: Array with the indices of the PQ buses
        pvpq: Array with the indices of the PV and PQ buses

    Returns:
        The system Jacobian matrix in current equations
    """
    dI_dVm = Ybus * diags(V / np.abs(V))
    dI_dVa = 1j * (Ybus * diags(V))

    J11 = dI_dVa[array([pvpq]).T, pvpq].real
    J12 = dI_dVm[array([pvpq]).T, pq].real
    J21 = dI_dVa[array([pq]).T, pvpq].imag
    J22 = dI_dVm[array([pq]).T, pq].imag

    J = vstack_sp([hstack_sp([J11, J12]), hstack_sp([J21, J22])], format="csr")

    return J
Example #4
0
from scipy.sparse import hstack as hstack_sp, vstack as vstack_sp

circuit = MultiCircuit()

b1 = Bus(name='B1')
b2 = Bus(name='B2')
l2 = Load(P=1, Q=1)
br1 = Branch(b1, b2, r=0.1, x=1)
circuit.add_bus(b1)
circuit.add_bus(b2)
circuit.add_load(b2, l2)
circuit.add_branch(br1)

islands = circuit.compile_snapshot().compute()

npv = len(islands[0].pv)
npq = len(islands[0].pq)
pvpq = np.r_[islands[0].pv, islands[0].pq]
J = Jacobian(Ybus=islands[0].Ybus,
             V=islands[0].Vbus,
             Ibus=islands[0].Ibus,
             pq=islands[0].pq,
             pvpq=pvpq)

ek = np.zeros((1, npv + npq + npq + 1))
ek[0, -1] = 1
K = np.zeros((npv + npq + npq, 1))
J2 = vstack_sp([hstack_sp([J, K]), ek], format="csr")

pass
Example #5
0
def ASD1(Ybus, S0, V0, I0, pv, pq, vd, tol, max_it=15, gamma=0.5):
    """
    Alternate Search Directions Power Flow

    As defined in the paper:

        Unified formulation of a family of iterative solvers for power system analysis
        by Domenico Borzacchiello et. Al.

    :param Ybus: Admittance matrix
    :param S0: Power injections
    :param V0: Initial Voltage Vector
    :param I0: Current injections @V=1.0 p.u.
    :param pv: Array of PV bus indices
    :param pq: Array of PQ bus indices
    :param vd: Array of Slack bus indices
    :param tol: Tolerance
    :param max_it: Maximum number of iterations
    :param gamma: Reactive power acceleration factor
    :return: V, converged, normF, Scalc, iterations, elapsed
    """
    start = time.time()

    # initialize
    V = V0.copy()
    Vset_pv = np.abs(V0[pv])
    Scalc = S0.copy()
    Scalc[pv] = Scalc[pv].real + 0j
    normF = 1e20
    iterations = 0
    converged = False
    n = len(V0)
    npq = len(pq)
    npv = len(pv)
    pqpv = np.r_[pq, pv]

    npqpv = len(pqpv)

    # kron
    if npv:
        Y11 = Ybus[pq, :][:, pq]
        Y12 = Ybus[pq, :][:, pv]
        Y21 = Ybus[pv, :][:, pq]
        Y22 = Ybus[pv, :][:, pv]
        Ykron = Y22 + Y21 * (spsolve(Y11, Y12))

        Yred = vstack_sp((hstack_sp((Y11, Y12)), hstack_sp((Y21, Y22))))

    else:
        Yred = Ybus[pq, :][:, pq]

    # reduced system
    Sred = S0[pqpv]
    I0_red = I0[pqpv]

    Yslack = -Ybus[np.ix_(pqpv, vd)]  # yes, it is the negative of this
    Vslack = V0[vd]

    # compute alpha
    Vabs = np.ones(npqpv)
    alpha = sp.diags(np.conj(Sred) / (Vabs * Vabs))

    # compute Y-alpha
    Y_alpha = (Yred - alpha)

    # compute beta as a vector
    B = Y_alpha.diagonal()
    beta = diags(B)
    Y_beta = Yred - beta

    # get the first voltage approximation V0, or simply V(l
    Ivd = Yslack * Vslack  # slack currents
    V_l = spsolve(Y_alpha, Ivd)  # slack voltages influence
    V_l = V0[pqpv]

    while not converged and iterations < max_it:

        iterations += 1

        # Global step
        rhs_global = np.conj(Sred) / np.conj(V_l) - alpha * V_l + I0_red + Ivd
        V_l12 = spsolve(Y_alpha, rhs_global)

        # PV correction
        if npv:
            V_pv = V_l12[npq:]
            V_pv_abs = np.abs(V_pv)
            dV_l12 = (Vset_pv - V_pv_abs) * V_pv / V_pv_abs
            dI_l12 = Ykron * dV_l12
            dQ_l12 = (V_pv *
                      np.conj(dI_l12)).imag  # correct the reactive power
            Sred[npq:] = Sred[npq:].real + 1j * (
                Sred[npq:].imag + gamma * dQ_l12)  # assign the reactive power
            V_l12[npq:] += dV_l12  # correct the voltage

        # local step
        A = (Y_beta * V_l12 - I0_red - Ivd) / B
        Sigma = -np.conj(Sred) / (A * np.conj(A) * B)
        U = (-1 - np.sqrt(1 - 4 * (Sigma.imag * Sigma.imag + Sigma.real))
             ) / 2.0 + 1j * Sigma.imag
        V_l = U * A

        # Assign the reduced solution
        V[pq] = V_l[:npq]
        V[pv] = V_l[npq:]

        # compute the calculated power injection and the error of the voltage solution
        Scalc = V * np.conj(Ybus * V - I0)
        mis = Scalc - S0  # complex power mismatch
        mismatch = np.r_[mis[pv].real, mis[pq].real,
                         mis[pq].imag]  # concatenate again
        normF = np.linalg.norm(mismatch, np.Inf)

        converged = normF < tol

        print(normF)

    end = time.time()
    elapsed = end - start

    return V, converged, normF, Scalc, iterations, elapsed