示例#1
0
def network_observability(topology, meas_idx, V):
	from pypower.api import makeYbus
	from pypower.bustypes import bustypes
	from pypower.dSbus_dV import dSbus_dV
	from pypower.dSbr_dV import dSbr_dV

	# build admittances
	Ybus,Yfrom,Yto = makeYbus(topology["baseMVA"],topology["bus"],topology["branch"])
	Ybus, Yfrom, Yto = Ybus.toarray(), Yfrom.toarray(), Yto.toarray()
	Nk = Ybus.shape[0]

	# get non-reference buses
	ref,pv,pq = bustypes(topology["bus"],topology["gen"])
	nonref = np.r_[pv,pq]
	gbus = topology["gen"][:,GEN_BUS].astype(int)

	# calculate partial derivative
	dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus,V)
	dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(topology["branch"],Yfrom,Yto,V)
	# create Jacobian matrix
	## submatrices related to line flow
	dPf_Va = np.real(dSf_dVa)[meas_idx["Pf"],:][:,nonref]
	dPf_Vm = np.real(dSf_dVm)[meas_idx["Pf"],:][:,nonref]
	dPt_Va = np.real(dSt_dVa)[meas_idx["Pt"],:][:,nonref]
	dPt_Vm = np.real(dSt_dVm)[meas_idx["Pt"],:][:,nonref]
	dQf_Va = np.imag(dSf_dVa)[meas_idx["Qf"],:][:,nonref]
	dQf_Vm = np.imag(dSf_dVm)[meas_idx["Qf"],:][:,nonref]
	dQt_Va = np.imag(dSt_dVa)[meas_idx["Qt"],:][:,nonref]
	dQt_Vm = np.imag(dSt_dVm)[meas_idx["Qt"],:][:,nonref]
	## submatrix related to generator output
	dPg_Va = np.real(dSbus_dVa)[gbus,:][meas_idx["Pg"],:][:,nonref]
	dPg_Vm = np.real(dSbus_dVm)[gbus,:][meas_idx["Pg"],:][:,nonref]
	dQg_Va = np.imag(dSbus_dVa)[gbus,:][meas_idx["Qg"],:][:,nonref]
	dQg_Vm = np.imag(dSbus_dVm)[gbus,:][meas_idx["Qg"],:][:,nonref]
	## submatrix related to bus injection
	dPk_Va = np.real(dSbus_dVa)[meas_idx["Pk"],:][:,nonref]
	dPk_Vm = np.real(dSbus_dVm)[meas_idx["Pk"],:][:,nonref]
	dQk_Va = np.imag(dSbus_dVa)[meas_idx["Qk"],:][:,nonref]
	dQk_Vm = np.imag(dSbus_dVm)[meas_idx["Qk"],:][:,nonref]
	## submatrix related to voltage angle
	dVa_Va = np.eye(Nk)[meas_idx["Va"],:][:,nonref]
	dVa_Vm = np.zeros((Nk,Nk))[meas_idx["Va"],:][:,nonref]
	## submatrix related to voltage magnitude
	dVm_Va = np.zeros((Nk,Nk))[meas_idx["Vm"],:][:,nonref]
	dVm_Vm = np.eye(Nk)[meas_idx["Vm"],:][:,nonref]

	H = np.r_[np.c_[dPf_Va, dPf_Vm],\
			  np.c_[dPt_Va, dPt_Vm],\
			  np.c_[dPg_Va, dPg_Vm],\
			  np.c_[dQf_Va, dQf_Vm],\
			  np.c_[dQt_Va, dQt_Vm],\
			  np.c_[dQg_Va, dQg_Vm],\
			  np.c_[dPk_Va, dPk_Vm],\
			  np.c_[dQk_Va, dQk_Vm],\
			  np.c_[dVa_Va, dVa_Vm],\
			  np.c_[dVm_Va, dVm_Vm]]

	return isobservable(H,pv,pq)
示例#2
0
def voltage2power(V,topology):
	"""Calculation of nodal and line power from complex nodal voltages
	Returns dictionary of corresponding powers and a dictionary with the partial derivatives

	:param V: numpy array of complex nodal voltages
	:param topology: dict in pypower casefile format
	:returns: dict of calculated power values, dict of jacobians if V is one-dimensional

	"""
	from pypower.idx_brch import F_BUS,T_BUS
	from pypower.idx_gen import GEN_BUS
	from pypower.makeYbus import makeYbus
	from pypower.idx_bus import PD,QD
	from pypower.dSbus_dV import dSbus_dV
	from pypower.dSbr_dV import dSbr_dV

	assert(str(V.dtype)[:7]=="complex")

	list_f = topology["branch"][:,F_BUS].tolist()
	list_t = topology["branch"][:,T_BUS].tolist()

	Ybus,Yfrom,Yto = makeYbus(topology["baseMVA"],topology["bus"],topology["branch"])
	Ybus, Yfrom, Yto = Ybus.toarray(), Yfrom.toarray(), Yto.toarray()

	powers = {}
	if len(V.shape)==1:
		powers["Sf"] = V[list_f]*np.conj(np.dot(Yfrom,V))
		powers["St"] = V[list_t]*np.conj(np.dot(Yto,V))
		gbus = topology["gen"][:,GEN_BUS].astype(int)
		Sgbus= V[gbus]*np.conj(np.dot(Ybus[gbus,:],V))
		powers["Sg"] = ( Sgbus*topology["baseMVA"] + topology["bus"][gbus,PD] + 1j*topology["bus"][gbus,QD] ) / topology["baseMVA"]
		powers["Sk"] = V*np.conj(np.dot(Ybus,V))
	else:
		powers = dict([(name,[]) for name in ["Sf","St","Sg","Sk"]])
		for k in range(V.shape[0]):
			powers["Sf"].append(V[k,list_f]*np.conj(np.dot(Yfrom,V[k,:])))
			powers["St"].append(V[k,list_t]*np.conj(np.dot(Yto,V[k,:])))
			gbus = topology["gen"][:,GEN_BUS].astype(int)
			Sgbus= V[k,gbus]*np.conj(np.dot(Ybus[gbus,:],V[k,:]))
			powers["Sg"].append(( Sgbus*topology["baseMVA"] + topology["bus"][gbus,PD] + 1j*topology["bus"][gbus,QD] ) / topology["baseMVA"])
			powers["Sk"].append(V[k,:]*np.conj(np.dot(Ybus,V[k,:])))
		for key in powers.keys():
			powers[key] = np.asarray(powers[key])
		# calculate partial derivative
	jacobians = dict([])
	if len(V.shape)==1:
		jacobians["dSbus_dVm"], jacobians["dSbus_dVa"] = dSbus_dV(Ybus,V)
		jacobians["dSf_dVa"], jacobians["dSf_dVm"], jacobians["dSt_dVa"], \
			jacobians["dSt_dVm"], jacobians["Sf"], jacobians["St"] = dSbr_dV(topology["branch"],Yfrom,Yto,V)

	return powers, jacobians
示例#3
0
    def grad(self, V):
        """
        Calculate Jacobi matrix given parameters vector V
        Name is such due to compatability with Conjugated Gradients Class
        """
        dS_dVm, dS_dVa = dSbus_dV(self.Y, V)
        J11 = dS_dVa[self.pvpq[:, None], self.pvpq].real
        J12 = dS_dVm[self.pvpq[:, None], self.pq].real
        J21 = dS_dVa[self.pq[:, None], self.pvpq].imag
        J22 = dS_dVm[self.pq[:, None], self.pq].imag

        J = vstack([hstack([J11, J12]), hstack([J21, J22])], format="csr")

        return J
示例#4
0
    def admmopf_consfcn(self, x=None):
        if x is None:
            x = self.pb['x0']
        nx = len(x)
        nb = self.region['nb']
        ng = self.region['ng']
        iv = self.idx['var']
        bus = self.region['bus']
        gen = self.region['gen']
        Ybus = self.region['Ybus']
        ridx = self.idx['rbus']['int']
        # idx ranges
        iVa = iv['iVa']
        iVm = iv['iVm']
        iPg = iv['iPg']
        iQg = iv['iQg']
        # grab Pg and Qg
        gen[:, PG] = x[iPg]
        gen[:, QG] = x[iQg]
        # rebuid Sbus
        Sbus = makeSbus(1, bus, gen)
        # reconstruct V
        Va, Vm = x[iVa], x[iVm]
        V = Vm * exp(1j * Va)
        # evaluate power flow equations
        mis = V * conj(Ybus * V) - Sbus
        g = r_[mis.real, mis.imag]
        row = ridx + [i + nb for i in ridx]
        g = g[row]
        # ---- evaluate constraint gradients -------
        # compute partials of injected bus powers
        dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)  # w.r.t. V
        neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))
        # construct Jacobian of equality constraints (power flow) and transpose it
        dg = lil_matrix((2 * nb, nx))
        blank = sparse((nb, ng))
        dg = vstack([ \
			#P mismatch w.r.t Va, Vm, Pg, Qg

         hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
         # Q mismatch w.r.t Va, Vm, Pg, Qg
         hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
         ], "csr")
        dg = dg[row, :]
        dg = dg.T
        h = None
        dh = None
        return h, g, dh, dg
示例#5
0
def cpf_predictor(V, lam, Ybus, Sxfr, pv, pq, step, z, Vprv, lamprv,
                  parameterization):
    # sizes
    pvpq = r_[pv, pq]
    nb = len(V)
    npv = len(pv)
    npq = len(pq)

    # compute Jacobian for the power flow equations
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)

    j11 = dSbus_dVa[array([pvpq]).T, pvpq].real
    j12 = dSbus_dVm[array([pvpq]).T, pq].real
    j21 = dSbus_dVa[array([pq]).T, pvpq].imag
    j22 = dSbus_dVm[array([pq]).T, pq].imag

    J = vstack([hstack([j11, j12]), hstack([j21, j22])], format="csr")

    dF_dlam = -r_[Sxfr[pvpq].real, Sxfr[pq].imag].reshape((-1, 1))
    dP_dV, dP_dlam = cpf_p_jac(parameterization, z, V, lam, Vprv, lamprv, pv,
                               pq)

    # linear operator for computing the tangent predictor
    J = vstack([hstack([J, dF_dlam]), hstack([dP_dV, dP_dlam])], format="csr")

    Vaprv = angle(V)
    Vmprv = abs(V)

    # compute normalized tangent predictor
    s = zeros(npv + 2 * npq + 1)
    s[-1] = 1
    z[r_[pvpq, nb + pq, 2 * nb]] = spsolve(J, s)
    z = z / linalg.norm(z)

    Va0 = Vaprv
    Vm0 = Vmprv
    lam0 = lam

    # prediction for next step
    Va0[pvpq] = Vaprv[pvpq] + step * z[pvpq]
    Vm0[pq] = Vmprv[pq] + step * z[nb + pq]
    lam0 = lam + step * z[2 * nb]
    V0 = Vm0 * exp(1j * Va0)

    return V0, lam0, z
示例#6
0
def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None):
    """Solves the power flow using a full Newton's method.

    Solves for bus voltages given the full system admittance matrix (for
    all buses), the complex bus power injection vector (for all buses),
    the initial vector of complex bus voltages, and column vectors with
    the lists of bus indices for the swing bus, PV buses, and PQ buses,
    respectively. The bus voltage vector contains the set point for
    generator (including ref bus) buses, and the reference angle of the
    swing bus, as well as an initial guess for remaining magnitudes and
    angles. C{ppopt} is a PYPOWER options vector which can be used to
    set the termination tolerance, maximum number of iterations, and
    output options (see L{ppoption} for details). Uses default options if
    this parameter is not given. Returns the final complex voltages, a
    flag which indicates whether it converged or not, and the number of
    iterations performed.

    @see: L{runpf}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    ## default arguments
    if ppopt is None:
        ppopt = ppoption()

    ## options
    tol     = ppopt['PF_TOL']
    max_it  = ppopt['PF_MAX_IT']
    verbose = ppopt['VERBOSE']

    ## initialize
    converged = 0
    i = 0
    V = V0
    Va = angle(V)
    Vm = abs(V)

    ## set up indexing for updating V
    pvpq = r_[pv, pq]
    npv = len(pv)
    npq = len(pq)
    j1 = 0;         j2 = npv           ## j1:j2 - V angle of pv buses
    j3 = j2;        j4 = j2 + npq      ## j3:j4 - V angle of pq buses
    j5 = j4;        j6 = j4 + npq      ## j5:j6 - V mag of pq buses

    ## evaluate F(x0)
    mis = V * conj(Ybus * V) - Sbus
    F = r_[  mis[pv].real,
             mis[pq].real,
             mis[pq].imag  ]

    ## check tolerance
    normF = linalg.norm(F, Inf)
    if verbose > 1:
        sys.stdout.write('\n it    max P & Q mismatch (p.u.)')
        sys.stdout.write('\n----  ---------------------------')
        sys.stdout.write('\n%3d        %10.3e' % (i, normF))
    if normF < tol:
        converged = 1
        if verbose > 1:
            sys.stdout.write('\nConverged!\n')

    ## do Newton iterations
    while (not converged and i < max_it):
        ## update iteration counter
        i = i + 1

        ## evaluate Jacobian
        dS_dVm, dS_dVa = dSbus_dV(Ybus, V)

        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([
                hstack([J11, J12]),
                hstack([J21, J22])
            ], format="csr")

        ## compute update step
        dx = -1 * spsolve(J, F)

        ## update voltage
        if npv:
            Va[pv] = Va[pv] + dx[j1:j2]
        if npq:
            Va[pq] = Va[pq] + dx[j3:j4]
            Vm[pq] = Vm[pq] + dx[j5:j6]
        V = Vm * exp(1j * Va)
        Vm = abs(V)            ## update Vm and Va again in case
        Va = angle(V)          ## we wrapped around with a negative Vm

        ## evalute F(x)
        mis = V * conj(Ybus * V) - Sbus
        F = r_[  mis[pv].real,
                 mis[pq].real,
                 mis[pq].imag  ]

        ## check for convergence
        normF = linalg.norm(F, Inf)
        if verbose > 1:
            sys.stdout.write('\n%3d        %10.3e' % (i, normF))
        if normF < tol:
            converged = 1
            if verbose:
                sys.stdout.write("\nNewton's method power flow converged in "
                                 "%d iterations.\n" % i)

    if verbose:
        if not converged:
            sys.stdout.write("\nNewton's method power did not converge in %d "
                             "iterations.\n" % i)

    return V, converged, i
示例#7
0
def t_hessian(quiet=False):
    """Numerical tests of 2nd derivative code.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(44, quiet)

    ## run powerflow to get solved case
    ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    results, _ = runpf(case30(), ppopt)
    baseMVA, bus, gen, branch = \
        results['baseMVA'], results['bus'], results['gen'], results['branch']

    ## switch to internal bus numbering and build admittance matrices
    _, bus, gen, branch = ext2int1(bus, gen, branch)
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
    Vm = bus[:, VM]
    Va = bus[:, VA] * (pi / 180)
    V = Vm * exp(1j * Va)
    f = branch[:, F_BUS]       ## list of "from" buses
    t = branch[:, T_BUS]       ## list of "to" buses
    nl = len(f)
    nb = len(V)
    Cf = sparse((ones(nl), (range(nl), f)), (nl, nb))  ## connection matrix for line & from buses
    Ct = sparse((ones(nl), (range(nl), t)), (nl, nb))  ## connection matrix for line & to buses
    pert = 1e-8

    ##-----  check d2Sbus_dV2 code  -----
    t = ' - d2Sbus_dV2 (complex power injections)'
    lam = 10 * random.rand(nb)
    num_Haa = zeros((nb, nb), complex)
    num_Hav = zeros((nb, nb), complex)
    num_Hva = zeros((nb, nb), complex)
    num_Hvv = zeros((nb, nb), complex)
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)
    Haa, Hav, Hva, Hvv = d2Sbus_dV2(Ybus, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSbus_dVm_ap, dSbus_dVa_ap = dSbus_dV(Ybus, Vap)
        num_Haa[:, i] = (dSbus_dVa_ap - dSbus_dVa).T * lam / pert
        num_Hva[:, i] = (dSbus_dVm_ap - dSbus_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSbus_dVm_mp, dSbus_dVa_mp = dSbus_dV(Ybus, Vmp)
        num_Hav[:, i] = (dSbus_dVa_mp - dSbus_dVa).T * lam / pert
        num_Hvv[:, i] = (dSbus_dVm_mp - dSbus_dVm).T * lam / pert

    t_is(Haa.todense(), num_Haa, 4, ['Haa', t])
    t_is(Hav.todense(), num_Hav, 4, ['Hav', t])
    t_is(Hva.todense(), num_Hva, 4, ['Hva', t])
    t_is(Hvv.todense(), num_Hvv, 4, ['Hvv', t])

    ##-----  check d2Sbr_dV2 code  -----
    t = ' - d2Sbr_dV2 (complex power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, _, _ = dSbr_dV(branch, Yf, Yt, V)
    Gfaa, Gfav, Gfva, Gfvv = d2Sbr_dV2(Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2Sbr_dV2(Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        num_Gfaa[:, i] = (dSf_dVa_ap - dSf_dVa).T * lam / pert
        num_Gfva[:, i] = (dSf_dVm_ap - dSf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dSt_dVa_ap - dSt_dVa).T * lam / pert
        num_Gtva[:, i] = (dSt_dVm_ap - dSt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        num_Gfav[:, i] = (dSf_dVa_mp - dSf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dSf_dVm_mp - dSf_dVm).T * lam / pert
        num_Gtav[:, i] = (dSt_dVa_mp - dSt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dSt_dVm_mp - dSt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t])

    ##-----  check d2Ibr_dV2 code  -----
    t = ' - d2Ibr_dV2 (complex currents)'
    lam = 10 * random.rand(nl)
    # lam = [1, zeros(nl-1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, _, _ = dIbr_dV(branch, Yf, Yt, V)
    Gfaa, Gfav, Gfva, Gfvv = d2Ibr_dV2(Yf, V, lam)

    Gtaa, Gtav, Gtva, Gtvv = d2Ibr_dV2(Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \
            dIbr_dV(branch, Yf, Yt, Vap)
        num_Gfaa[:, i] = (dIf_dVa_ap - dIf_dVa).T * lam / pert
        num_Gfva[:, i] = (dIf_dVm_ap - dIf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dIt_dVa_ap - dIt_dVa).T * lam / pert
        num_Gtva[:, i] = (dIt_dVm_ap - dIt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \
            dIbr_dV(branch, Yf, Yt, Vmp)
        num_Gfav[:, i] = (dIf_dVa_mp - dIf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dIf_dVm_mp - dIf_dVm).T * lam / pert
        num_Gtav[:, i] = (dIt_dVa_mp - dIt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dIt_dVm_mp - dIt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t])

    ##-----  check d2ASbr_dV2 code  -----
    t = ' - d2ASbr_dV2 (squared apparent power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St)
    Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    ##-----  check d2ASbr_dV2 code  -----
    t = ' - d2ASbr_dV2 (squared real power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
           dAbr_dV(dSf_dVa.real, dSf_dVm.real, dSt_dVa.real, dSt_dVm.real, Sf.real, St.real)
    Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real, Sf.real, Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real, St.real, Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dSf_dVa_ap.real, dSf_dVm_ap.real, dSt_dVa_ap.real, dSt_dVm_ap.real, Sf_ap.real, St_ap.real)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dSf_dVa_mp.real, dSf_dVm_mp.real, dSt_dVa_mp.real, dSt_dVm_mp.real, Sf_mp.real, St_mp.real)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    ##-----  check d2AIbr_dV2 code  -----
    t = ' - d2AIbr_dV2 (squared current magnitudes)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It)
    Gfaa, Gfav, Gfva, Gfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \
            dIbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \
            dIbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 3, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 3, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 3, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 3, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 3, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 3, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    t_end()
def opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il=None, *args):
    """Evaluates nonlinear constraints and their Jacobian for OPF.

    Constraint evaluation function for AC optimal power flow, suitable
    for use with L{pips}. Computes constraint vectors and their gradients.

    @param x: optimization vector
    @param om: OPF model object
    @param Ybus: bus admittance matrix
    @param Yf: admittance matrix for "from" end of constrained branches
    @param Yt: admittance matrix for "to" end of constrained branches
    @param ppopt: PYPOWER options vector
    @param il: (optional) vector of branch indices corresponding to
    branches with flow limits (all others are assumed to be
    unconstrained). The default is C{range(nl)} (all branches).
    C{Yf} and C{Yt} contain only the rows corresponding to C{il}.

    @return: C{h} - vector of inequality constraint values (flow limits)
    limit^2 - flow^2, where the flow can be apparent power real power or
    current, depending on value of C{OPF_FLOW_LIM} in C{ppopt} (only for
    constrained lines). C{g} - vector of equality constraint values (power
    balances). C{dh} - (optional) inequality constraint gradients, column
    j is gradient of h(j). C{dg} - (optional) equality constraint gradients.

    @see: L{opf_costfcn}, L{opf_hessfcn}

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

    ## unpack data
    ppc = om.get_ppc()
    baseMVA, bus, gen, branch = \
        ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]
    vv, _, _, _ = om.get_idx()

    ## problem dimensions
    nb = bus.shape[0]          ## number of buses
    nl = branch.shape[0]       ## number of branches
    ng = gen.shape[0]          ## number of dispatchable injections
    nxyz = len(x)              ## total number of control vars of all types

    ## set default constrained lines
    if il is None:
        il = arange(nl)         ## all lines have limits by default
    nl2 = len(il)              ## number of constrained lines

    ## grab Pg & Qg
    Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]]  ## active generation in p.u.
    Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]]  ## reactive generation in p.u.

    ## put Pg & Qg back in gen
    gen[:, PG] = Pg * baseMVA  ## active generation in MW
    gen[:, QG] = Qg * baseMVA  ## reactive generation in MVAr

    ## rebuild Sbus
    Sbus = makeSbus(baseMVA, bus, gen) ## net injected power in p.u.

    ## ----- evaluate constraints -----
    ## reconstruct V
    Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
    Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
    V = Vm * exp(1j * Va)

    ## evaluate power flow equations
    mis = V * conj(Ybus * V) - Sbus

    ##----- evaluate constraint function values -----
    ## first, the equality constraints (power flow)
    g = r_[ mis.real,            ## active power mismatch for all buses
            mis.imag ]           ## reactive power mismatch for all buses

    ## then, the inequality constraints (branch flow limits)
    if nl2 > 0:
        flow_max = (branch[il, RATE_A] / baseMVA)**2
        flow_max[flow_max == 0] = Inf
        if ppopt['OPF_FLOW_LIM'] == 2:       ## current magnitude limit, |I|
            If = Yf * V
            It = Yt * V
            h = r_[ If * conj(If) - flow_max,     ## branch I limits (from bus)
                    It * conj(It) - flow_max ].real    ## branch I limits (to bus)
        else:
            ## compute branch power flows
            ## complex power injected at "from" bus (p.u.)
            Sf = V[ branch[il, F_BUS].astype(int) ] * conj(Yf * V)
            ## complex power injected at "to" bus (p.u.)
            St = V[ branch[il, T_BUS].astype(int) ] * conj(Yt * V)
            if ppopt['OPF_FLOW_LIM'] == 1:   ## active power limit, P (Pan Wei)
                h = r_[ Sf.real**2 - flow_max,   ## branch P limits (from bus)
                        St.real**2 - flow_max ]  ## branch P limits (to bus)
            else:                ## apparent power limit, |S|
                h = r_[ Sf * conj(Sf) - flow_max, ## branch S limits (from bus)
                        St * conj(St) - flow_max ].real  ## branch S limits (to bus)
    else:
        h = zeros((0,1))

    ##----- evaluate partials of constraints -----
    ## index ranges
    iVa = arange(vv["i1"]["Va"], vv["iN"]["Va"])
    iVm = arange(vv["i1"]["Vm"], vv["iN"]["Vm"])
    iPg = arange(vv["i1"]["Pg"], vv["iN"]["Pg"])
    iQg = arange(vv["i1"]["Qg"], vv["iN"]["Qg"])
    iVaVmPgQg = r_[iVa, iVm, iPg, iQg].T

    ## compute partials of injected bus powers
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)           ## w.r.t. V
    ## Pbus w.r.t. Pg, Qbus w.r.t. Qg
    neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))

    ## construct Jacobian of equality constraints (power flow) and transpose it
    dg = lil_matrix((2 * nb, nxyz))
    blank = sparse((nb, ng))
    dg[:, iVaVmPgQg] = vstack([
            ## P mismatch w.r.t Va, Vm, Pg, Qg
            hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
            ## Q mismatch w.r.t Va, Vm, Pg, Qg
            hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
        ], "csr")
    dg = dg.T

    if nl2 > 0:
        ## compute partials of Flows w.r.t. V
        if ppopt['OPF_FLOW_LIM'] == 2:     ## current
            dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
                    dIbr_dV(branch[il, :], Yf, Yt, V)
        else:                  ## power
            dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
                    dSbr_dV(branch[il, :], Yf, Yt, V)
        if ppopt['OPF_FLOW_LIM'] == 1:     ## real part of flow (active power)
            dFf_dVa = dFf_dVa.real
            dFf_dVm = dFf_dVm.real
            dFt_dVa = dFt_dVa.real
            dFt_dVm = dFt_dVm.real
            Ff = Ff.real
            Ft = Ft.real

        ## squared magnitude of flow (of complex power or current, or real power)
        df_dVa, df_dVm, dt_dVa, dt_dVm = \
                dAbr_dV(dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft)

        ## construct Jacobian of inequality constraints (branch limits)
        ## and transpose it.
        dh = lil_matrix((2 * nl2, nxyz))
        dh[:, r_[iVa, iVm].T] = vstack([
                hstack([df_dVa, df_dVm]),    ## "from" flow limit
                hstack([dt_dVa, dt_dVm])     ## "to" flow limit
            ], "csr")
        dh = dh.T
    else:
        dh = None

    return h, g, dh, dg
示例#9
0
def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None):
    """Solves the power flow using a full Newton's method.

    Solves for bus voltages given the full system admittance matrix (for
    all buses), the complex bus power injection vector (for all buses),
    the initial vector of complex bus voltages, and column vectors with
    the lists of bus indices for the swing bus, PV buses, and PQ buses,
    respectively. The bus voltage vector contains the set point for
    generator (including ref bus) buses, and the reference angle of the
    swing bus, as well as an initial guess for remaining magnitudes and
    angles. C{ppopt} is a PYPOWER options vector which can be used to
    set the termination tolerance, maximum number of iterations, and
    output options (see L{ppoption} for details). Uses default options if
    this parameter is not given. Returns the final complex voltages, a
    flag which indicates whether it converged or not, and the number of
    iterations performed.

    @see: L{runpf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ## default arguments
    if ppopt is None:
        ppopt = ppoption()

    ## options
    tol = ppopt['PF_TOL']
    max_it = ppopt['PF_MAX_IT']
    verbose = ppopt['VERBOSE']

    ## initialize
    converged = 0
    i = 0
    V = V0
    Va = angle(V)
    Vm = abs(V)

    ## set up indexing for updating V
    pvpq = r_[pv, pq]
    npv = len(pv)
    npq = len(pq)
    j1 = 0
    j2 = npv  ## j1:j2 - V angle of pv buses
    j3 = j2
    j4 = j2 + npq  ## j3:j4 - V angle of pq buses
    j5 = j4
    j6 = j4 + npq  ## j5:j6 - V mag of pq buses

    ## evaluate F(x0)
    mis = V * conj(Ybus * V) - Sbus
    F = r_[mis[pv].real, mis[pq].real, mis[pq].imag]

    ## check tolerance
    normF = linalg.norm(F, Inf)
    if verbose > 1:
        sys.stdout.write('\n it    max P & Q mismatch (p.u.)')
        sys.stdout.write('\n----  ---------------------------')
        sys.stdout.write('\n%3d        %10.3e' % (i, normF))
    if normF < tol:
        converged = 1
        if verbose > 1:
            sys.stdout.write('\nConverged!\n')

    ## do Newton iterations
    while (not converged and i < max_it):
        ## update iteration counter
        i = i + 1

        ## evaluate Jacobian
        dS_dVm, dS_dVa = dSbus_dV(Ybus, V)

        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([hstack([J11, J12]), hstack([J21, J22])], format="csr")

        ## compute update step
        dx = -1 * spsolve(J, F)

        ## update voltage
        if npv:
            Va[pv] = Va[pv] + dx[j1:j2]
        if npq:
            Va[pq] = Va[pq] + dx[j3:j4]
            Vm[pq] = Vm[pq] + dx[j5:j6]
        V = Vm * exp(1j * Va)
        Vm = abs(V)  ## update Vm and Va again in case
        Va = angle(V)  ## we wrapped around with a negative Vm

        ## evalute F(x)
        mis = V * conj(Ybus * V) - Sbus
        F = r_[mis[pv].real, mis[pq].real, mis[pq].imag]

        ## check for convergence
        normF = linalg.norm(F, Inf)
        if verbose > 1:
            sys.stdout.write('\n%3d        %10.3e' % (i, normF))
        if normF < tol:
            converged = 1
            if verbose:
                sys.stdout.write("\nNewton's method power flow converged in "
                                 "%d iterations.\n" % i)

    if verbose:
        if not converged:
            sys.stdout.write("\nNewton's method power did not converge in %d "
                             "iterations.\n" % i)

    return V, converged, i
示例#10
0
def opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il=None, *args):
    """Evaluates nonlinear constraints and their Jacobian for OPF.

    Constraint evaluation function for AC optimal power flow, suitable
    for use with L{pips}. Computes constraint vectors and their gradients.

    @param x: optimization vector
    @param om: OPF model object
    @param Ybus: bus admittance matrix
    @param Yf: admittance matrix for "from" end of constrained branches
    @param Yt: admittance matrix for "to" end of constrained branches
    @param ppopt: PYPOWER options vector
    @param il: (optional) vector of branch indices corresponding to
    branches with flow limits (all others are assumed to be
    unconstrained). The default is C{range(nl)} (all branches).
    C{Yf} and C{Yt} contain only the rows corresponding to C{il}.

    @return: C{h} - vector of inequality constraint values (flow limits)
    limit^2 - flow^2, where the flow can be apparent power real power or
    current, depending on value of C{OPF_FLOW_LIM} in C{ppopt} (only for
    constrained lines). C{g} - vector of equality constraint values (power
    balances). C{dh} - (optional) inequality constraint gradients, column
    j is gradient of h(j). C{dg} - (optional) equality constraint gradients.

    @see: L{opf_costfcn}, L{opf_hessfcn}

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

    ## unpack data
    ppc = om.get_ppc()
    baseMVA, bus, gen, branch = \
        ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]
    vv, _, _, _ = om.get_idx()

    ## problem dimensions
    nb = bus.shape[0]  ## number of buses
    nl = branch.shape[0]  ## number of branches
    ng = gen.shape[0]  ## number of dispatchable injections
    nxyz = len(x)  ## total number of control vars of all types

    ## set default constrained lines
    if il is None:
        il = arange(nl)  ## all lines have limits by default
    nl2 = len(il)  ## number of constrained lines

    ## grab Pg & Qg
    Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]]  ## active generation in p.u.
    Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]]  ## reactive generation in p.u.

    ## put Pg & Qg back in gen
    gen[:, PG] = Pg * baseMVA  ## active generation in MW
    gen[:, QG] = Qg * baseMVA  ## reactive generation in MVAr

    ## rebuild Sbus
    Sbus = makeSbus(baseMVA, bus, gen)  ## net injected power in p.u.

    ## ----- evaluate constraints -----
    ## reconstruct V
    Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
    Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
    V = Vm * exp(1j * Va)

    ## evaluate power flow equations
    mis = V * conj(Ybus * V) - Sbus

    ##----- evaluate constraint function values -----
    ## first, the equality constraints (power flow)
    g = r_[mis.real,  ## active power mismatch for all buses
           mis.imag]  ## reactive power mismatch for all buses

    ## then, the inequality constraints (branch flow limits)
    if nl2 > 0:
        flow_max = (branch[il, RATE_A] / baseMVA)**2
        flow_max[flow_max == 0] = Inf
        if ppopt['OPF_FLOW_LIM'] == 2:  ## current magnitude limit, |I|
            If = Yf * V
            It = Yt * V
            h = r_[If * conj(If) - flow_max,  ## branch I limits (from bus)
                   It * conj(It) - flow_max].real  ## branch I limits (to bus)
        else:
            ## compute branch power flows
            ## complex power injected at "from" bus (p.u.)
            Sf = V[branch[il, F_BUS].astype(int)] * conj(Yf * V)
            ## complex power injected at "to" bus (p.u.)
            St = V[branch[il, T_BUS].astype(int)] * conj(Yt * V)
            if ppopt['OPF_FLOW_LIM'] == 1:  ## active power limit, P (Pan Wei)
                h = r_[Sf.real**2 - flow_max,  ## branch P limits (from bus)
                       St.real**2 - flow_max]  ## branch P limits (to bus)
            else:  ## apparent power limit, |S|
                h = r_[Sf * conj(Sf) - flow_max,  ## branch S limits (from bus)
                       St * conj(St) -
                       flow_max].real  ## branch S limits (to bus)
    else:
        h = zeros((0, 1))

    ##----- evaluate partials of constraints -----
    ## index ranges
    iVa = arange(vv["i1"]["Va"], vv["iN"]["Va"])
    iVm = arange(vv["i1"]["Vm"], vv["iN"]["Vm"])
    iPg = arange(vv["i1"]["Pg"], vv["iN"]["Pg"])
    iQg = arange(vv["i1"]["Qg"], vv["iN"]["Qg"])
    iVaVmPgQg = r_[iVa, iVm, iPg, iQg].T

    ## compute partials of injected bus powers
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)  ## w.r.t. V
    ## Pbus w.r.t. Pg, Qbus w.r.t. Qg
    neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], list(range(ng)))), (nb, ng))

    ## construct Jacobian of equality constraints (power flow) and transpose it
    dg = lil_matrix((2 * nb, nxyz))
    blank = sparse((nb, ng))
    dg[:, iVaVmPgQg] = vstack(
        [
            ## P mismatch w.r.t Va, Vm, Pg, Qg
            hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
            ## Q mismatch w.r.t Va, Vm, Pg, Qg
            hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
        ],
        "csr")
    dg = dg.T

    if nl2 > 0:
        ## compute partials of Flows w.r.t. V
        if ppopt['OPF_FLOW_LIM'] == 2:  ## current
            dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
                    dIbr_dV(branch[il, :], Yf, Yt, V)
        else:  ## power
            dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
                    dSbr_dV(branch[il, :], Yf, Yt, V)
        if ppopt['OPF_FLOW_LIM'] == 1:  ## real part of flow (active power)
            dFf_dVa = dFf_dVa.real
            dFf_dVm = dFf_dVm.real
            dFt_dVa = dFt_dVa.real
            dFt_dVm = dFt_dVm.real
            Ff = Ff.real
            Ft = Ft.real

        ## squared magnitude of flow (of complex power or current, or real power)
        df_dVa, df_dVm, dt_dVa, dt_dVm = \
                dAbr_dV(dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft)

        ## construct Jacobian of inequality constraints (branch limits)
        ## and transpose it.
        dh = lil_matrix((2 * nl2, nxyz))
        dh[:, r_[iVa, iVm].T] = vstack(
            [
                hstack([df_dVa, df_dVm]),  ## "from" flow limit
                hstack([dt_dVa, dt_dVm])  ## "to" flow limit
            ],
            "csr")
        dh = dh.T
    else:
        dh = None

    return h, g, dh, dg
示例#11
0
def cpf_corrector(Ybus, Sbus, V0, ref, pv, pq, lam0, Sxfr, Vprv, lamprv, z,
                  step, parameterization, ppopt):

    # default arguments
    if ppopt is None:
        ppopt = ppoption(ppopt)

    # options
    verbose = ppopt["VERBOSE"]
    tol = ppopt["PF_TOL"]
    max_it = ppopt["PF_MAX_IT"]

    # initialize
    converged = 0
    i = 0
    V = V0
    Va = angle(V)
    Vm = abs(V)
    lam = lam0

    # set up indexing for updating V
    pvpq = r_[pv, pq]
    npv = len(pv)
    npq = len(pq)
    nb = len(V)
    j1 = 0
    j2 = npv  # j1:j2 - V angle of pv buses
    j3 = j2
    j4 = j2 + npq  # j1:j2 - V angle of pv buses
    j5 = j4
    j6 = j4 + npq  # j5:j6 - V mag of pq buses
    j7 = j6
    j8 = j6 + 1  # j7:j8 - lambda

    # evaluate F(x0, lam0), including Sxfr transfer/loading

    mis = V * conj(Ybus.dot(V)) - Sbus - lam * Sxfr
    F = r_[mis[pvpq].real, mis[pq].imag]

    # evaluate P(x0, lambda0)
    P = cpf_p(parameterization, step, z, V, lam, Vprv, lamprv, pv, pq)

    # augment F(x, lambda) with P(x, lambda)
    F = r_[F, P]

    # check tolerance
    normF = linalg.norm(F, inf)
    if verbose > 1:
        print('\n it    max P & Q mismatch (p.u.)')
        print('\n----  ---------------------------')
        print('\n%3d        %10.3e' % (i, normF))
    if normF < tol:
        converged = 1
        if verbose > 1:
            print('\nConverged!\n')

    # do Newton iterations
    while not converged and i < max_it:
        # update iteration counter
        i = i + 1

        # evaluate Jacobian
        dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)

        j11 = dSbus_dVa[array([pvpq]).T, pvpq].real
        j12 = dSbus_dVm[array([pvpq]).T, pq].real
        j21 = dSbus_dVa[array([pq]).T, pvpq].imag
        j22 = dSbus_dVm[array([pq]).T, pq].imag

        J = vstack([hstack([j11, j12]), hstack([j21, j22])], format="csr")

        dF_dlam = -r_[Sxfr[pvpq].real, Sxfr[pq].imag].reshape((-1, 1))
        dP_dV, dP_dlam = cpf_p_jac(parameterization, z, V, lam, Vprv, lamprv,
                                   pv, pq)

        # augment J with real/imag -Sxfr and z^T
        J = vstack([hstack([J, dF_dlam]),
                    hstack([dP_dV, dP_dlam])],
                   format="csr")

        # compute update step
        dx = -1 * spsolve(J, F)

        # update voltage
        if npv:
            Va[pv] = Va[pv] + dx[j1:j2]
        if npq:
            Va[pq] = Va[pq] + dx[j3:j4]
            Vm[pq] = Vm[pq] + dx[j5:j6]
        V = Vm * exp(1j * Va)
        Vm = abs(V)
        Va = angle(V)

        # update lambda
        lam = lam + dx[j7:j8]

        # evalute F(x, lam)
        mis = V * conj(Ybus.dot(V)) - Sbus - lam * Sxfr
        F = r_[mis[pv].real, mis[pq].real, mis[pq].imag]

        # evaluate P(x, lambda)
        P = cpf_p(parameterization, step, z, V, lam, Vprv, lamprv, pv, pq)

        # augment F(x, lambda) with P(x, lambda)
        F = r_[F, P]

        # check for convergence
        normF = linalg.norm(F, inf)
        if verbose > 1:
            print('\n%3d        %10.3e' % (i, normF))
        if normF < tol:
            converged = 1
            if verbose:
                print('\nNewton'
                      's method corrector converged in %d iterations.\n' % i)

    if verbose:
        if not converged:
            print('\nNewton'
                  's method corrector did not converge in %d iterations.\n' %
                  i)

    return V, converged, i, lam
示例#12
0
def t_jacobian(quiet=False):
    """Numerical tests of partial derivative code.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(28, quiet)

    ## run powerflow to get solved case
    ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    ppc = loadcase(case30())

    results, _ = runpf(ppc, ppopt)
    baseMVA, bus, gen, branch = \
        results['baseMVA'], results['bus'], results['gen'], results['branch']

    ## switch to internal bus numbering and build admittance matrices
    _, bus, gen, branch = ext2int1(bus, gen, branch)
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
    Ybus_full = Ybus.todense()
    Yf_full   = Yf.todense()
    Yt_full   = Yt.todense()
    Vm = bus[:, VM]
    Va = bus[:, VA] * (pi / 180)
    V = Vm * exp(1j * Va)
    f = branch[:, F_BUS].astype(int)       ## list of "from" buses
    t = branch[:, T_BUS].astype(int)       ## list of "to" buses
    #nl = len(f)
    nb = len(V)
    pert = 1e-8

    Vm = array([Vm]).T  # column array
    Va = array([Va]).T  # column array
    Vc = array([V]).T   # column array

    ##-----  check dSbus_dV code  -----
    ## full matrices
    dSbus_dVm_full, dSbus_dVa_full = dSbus_dV(Ybus_full, V)

    ## sparse matrices
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)
    dSbus_dVm_sp = dSbus_dVm.todense()
    dSbus_dVa_sp = dSbus_dVa.todense()

    ## compute numerically to compare
    Vmp = (Vm * ones((1, nb)) + pert*eye(nb)) * (exp(1j * Va) * ones((1, nb)))
    Vap = (Vm * ones((1, nb))) * (exp(1j * (Va*ones((1, nb)) + pert*eye(nb))))
    num_dSbus_dVm = (Vmp * conj(Ybus * Vmp) - Vc * ones((1, nb)) * conj(Ybus * Vc * ones((1, nb)))) / pert
    num_dSbus_dVa = (Vap * conj(Ybus * Vap) - Vc * ones((1, nb)) * conj(Ybus * Vc * ones((1, nb)))) / pert

    t_is(dSbus_dVm_sp, num_dSbus_dVm, 5, 'dSbus_dVm (sparse)')
    t_is(dSbus_dVa_sp, num_dSbus_dVa, 5, 'dSbus_dVa (sparse)')
    t_is(dSbus_dVm_full, num_dSbus_dVm, 5, 'dSbus_dVm (full)')
    t_is(dSbus_dVa_full, num_dSbus_dVa, 5, 'dSbus_dVa (full)')

    ##-----  check dSbr_dV code  -----
    ## full matrices
    dSf_dVa_full, dSf_dVm_full, dSt_dVa_full, dSt_dVm_full, _, _ = \
            dSbr_dV(branch, Yf_full, Yt_full, V)

    ## sparse matrices
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dSf_dVa_sp = dSf_dVa.todense()
    dSf_dVm_sp = dSf_dVm.todense()
    dSt_dVa_sp = dSt_dVa.todense()
    dSt_dVm_sp = dSt_dVm.todense()

    ## compute numerically to compare
    Vmpf = Vmp[f, :]
    Vapf = Vap[f, :]
    Vmpt = Vmp[t, :]
    Vapt = Vap[t, :]
    Sf2 = (Vc[f] * ones((1, nb))) * conj(Yf * Vc * ones((1, nb)))
    St2 = (Vc[t] * ones((1, nb))) * conj(Yt * Vc * ones((1, nb)))
    Smpf = Vmpf * conj(Yf * Vmp)
    Sapf = Vapf * conj(Yf * Vap)
    Smpt = Vmpt * conj(Yt * Vmp)
    Sapt = Vapt * conj(Yt * Vap)

    num_dSf_dVm = (Smpf - Sf2) / pert
    num_dSf_dVa = (Sapf - Sf2) / pert
    num_dSt_dVm = (Smpt - St2) / pert
    num_dSt_dVa = (Sapt - St2) / pert

    t_is(dSf_dVm_sp, num_dSf_dVm, 5, 'dSf_dVm (sparse)')
    t_is(dSf_dVa_sp, num_dSf_dVa, 5, 'dSf_dVa (sparse)')
    t_is(dSt_dVm_sp, num_dSt_dVm, 5, 'dSt_dVm (sparse)')
    t_is(dSt_dVa_sp, num_dSt_dVa, 5, 'dSt_dVa (sparse)')
    t_is(dSf_dVm_full, num_dSf_dVm, 5, 'dSf_dVm (full)')
    t_is(dSf_dVa_full, num_dSf_dVa, 5, 'dSf_dVa (full)')
    t_is(dSt_dVm_full, num_dSt_dVm, 5, 'dSt_dVm (full)')
    t_is(dSt_dVa_full, num_dSt_dVa, 5, 'dSt_dVa (full)')

    ##-----  check dAbr_dV code  -----
    ## full matrices
    dAf_dVa_full, dAf_dVm_full, dAt_dVa_full, dAt_dVm_full = \
        dAbr_dV(dSf_dVa_full, dSf_dVm_full, dSt_dVa_full, dSt_dVm_full, Sf, St)
    ## sparse matrices
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St)
    dAf_dVa_sp = dAf_dVa.todense()
    dAf_dVm_sp = dAf_dVm.todense()
    dAt_dVa_sp = dAt_dVa.todense()
    dAt_dVm_sp = dAt_dVm.todense()

    ## compute numerically to compare
    num_dAf_dVm = (abs(Smpf)**2 - abs(Sf2)**2) / pert
    num_dAf_dVa = (abs(Sapf)**2 - abs(Sf2)**2) / pert
    num_dAt_dVm = (abs(Smpt)**2 - abs(St2)**2) / pert
    num_dAt_dVa = (abs(Sapt)**2 - abs(St2)**2) / pert

    t_is(dAf_dVm_sp, num_dAf_dVm, 4, 'dAf_dVm (sparse)')
    t_is(dAf_dVa_sp, num_dAf_dVa, 4, 'dAf_dVa (sparse)')
    t_is(dAt_dVm_sp, num_dAt_dVm, 4, 'dAt_dVm (sparse)')
    t_is(dAt_dVa_sp, num_dAt_dVa, 4, 'dAt_dVa (sparse)')
    t_is(dAf_dVm_full, num_dAf_dVm, 4, 'dAf_dVm (full)')
    t_is(dAf_dVa_full, num_dAf_dVa, 4, 'dAf_dVa (full)')
    t_is(dAt_dVm_full, num_dAt_dVm, 4, 'dAt_dVm (full)')
    t_is(dAt_dVa_full, num_dAt_dVa, 4, 'dAt_dVa (full)')

    ##-----  check dIbr_dV code  -----
    ## full matrices
    dIf_dVa_full, dIf_dVm_full, dIt_dVa_full, dIt_dVm_full, _, _ = \
            dIbr_dV(branch, Yf_full, Yt_full, V)

    ## sparse matrices
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, _, _ = dIbr_dV(branch, Yf, Yt, V)
    dIf_dVa_sp = dIf_dVa.todense()
    dIf_dVm_sp = dIf_dVm.todense()
    dIt_dVa_sp = dIt_dVa.todense()
    dIt_dVm_sp = dIt_dVm.todense()

    ## compute numerically to compare
    num_dIf_dVm = (Yf * Vmp - Yf * Vc * ones((1, nb))) / pert
    num_dIf_dVa = (Yf * Vap - Yf * Vc * ones((1, nb))) / pert
    num_dIt_dVm = (Yt * Vmp - Yt * Vc * ones((1, nb))) / pert
    num_dIt_dVa = (Yt * Vap - Yt * Vc * ones((1, nb))) / pert

    t_is(dIf_dVm_sp, num_dIf_dVm, 5, 'dIf_dVm (sparse)')
    t_is(dIf_dVa_sp, num_dIf_dVa, 5, 'dIf_dVa (sparse)')
    t_is(dIt_dVm_sp, num_dIt_dVm, 5, 'dIt_dVm (sparse)')
    t_is(dIt_dVa_sp, num_dIt_dVa, 5, 'dIt_dVa (sparse)')
    t_is(dIf_dVm_full, num_dIf_dVm, 5, 'dIf_dVm (full)')
    t_is(dIf_dVa_full, num_dIf_dVa, 5, 'dIf_dVa (full)')
    t_is(dIt_dVm_full, num_dIt_dVm, 5, 'dIt_dVm (full)')
    t_is(dIt_dVa_full, num_dIt_dVa, 5, 'dIt_dVa (full)')

    t_end()
示例#13
0
    def admmopf_consfcn(self, x=None):
        if x is None:
            x = self.pb['x0']
        nx = len(x)
        nb = self.region['nb']
        ng = self.region['ng']
        iv = self.idx['var']
        bus = self.region['bus']
        gen = self.region['gen']
        branch = self.region['branch']
        Ybus = self.region['Ybus']
        Yf = self.region['Yf']
        Yt = self.region['Yt']
        baseMVA = self.region['baseMVA']

        ridx = self.idx['rbus']['int']
        # idx ranges
        iVa = iv['iVa']
        iVm = iv['iVm']
        iPg = iv['iPg']
        iQg = iv['iQg']
        # grab Pg and Qg
        gen[:, PG] = x[iPg]
        gen[:, QG] = x[iQg]
        # rebuid Sbus
        Sbus = makeSbus(1, bus, gen)
        # reconstruct V
        Va, Vm = x[iVa], x[iVm]
        V = Vm * exp(1j * Va)
        # evaluate power flow equations
        mis = V * conj(Ybus * V) - Sbus
        g = r_[mis.real, mis.imag]
        row = ridx + [i + nb for i in ridx]
        g = g[row]

        il = find((branch[:, RATE_A] != 0) & (branch[:, RATE_A] < 1e10))
        nl2 = len(il)

        Ybus2, Yf2, Yt2 = makeYbus(baseMVA, bus, branch)
        Yf = Yf2[il, :]
        Yt = Yt2[il, :]

        if nl2 > 0:
            flow_max = (branch[il, RATE_A] / baseMVA)**2
            flow_max[flow_max == 0] = Inf

            ## compute branch power flows
            ## complex power injected at "from" bus (p.u.)
            Sf = V[branch[il, F_BUS].astype(int)] * conj(Yf * V)
            ## complex power injected at "to" bus (p.u.)
            St = V[branch[il, T_BUS].astype(int)] * conj(Yt * V)
            h = r_[Sf.real**2 - flow_max,  ## branch P limits (from bus)
                   St.real**2 - flow_max]  ## branch P limits (to bus)

        else:
            h = array([])

        # ---- evaluate constraint gradients -------
        # compute partials of injected bus powers
        dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)  # w.r.t. V
        neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))

        # construct Jacobian of equality constraints (power flow) and transpose it
        dg = lil_matrix((2 * nb, nx))
        blank = sparse((nb, ng))
        dg = vstack([ \
			#P mismatch w.r.t Va, Vm, Pg, Qg

         hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
         # Q mismatch w.r.t Va, Vm, Pg, Qg
         hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
         ], "csr")
        dg = dg[row, :]
        dg = dg.T

        if nl2 > 0:
            ## compute partials of Flows w.r.t. V                  ## power
            dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
                             dSbr_dV(branch[il, :], Yf, Yt, V)
            dFf_dVa = dFf_dVa.real
            dFf_dVm = dFf_dVm.real
            dFt_dVa = dFt_dVa.real
            dFt_dVm = dFt_dVm.real
            Ff = Ff.real
            Ft = Ft.real

            ## squared magnitude of flow (of complex power or current, or real power)
            df_dVa, df_dVm, dt_dVa, dt_dVm = \
                         dAbr_dV(dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft)
            ## construct Jacobian of inequality constraints (branch limits)
            ## and transpose it.
            dh = lil_matrix((2 * nl2, nx))
            dh[:, r_[iVa, iVm].T] = vstack(
                [
                    hstack([df_dVa, df_dVm]),  ## "from" flow limit
                    hstack([dt_dVa, dt_dVm])  ## "to" flow limit
                ],
                "csr")
            dh = dh.T

        else:
            dh = None

        h = array([])
        dh = None

        return h, g, dh, dg