Пример #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 opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il=None, cost_mult=1.0):
    """Evaluates Hessian of Lagrangian for AC OPF.

    Hessian evaluation function for AC optimal power flow, suitable
    for use with L{pips}.

    Examples::
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt)
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il)
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il, cost_mult)

    @param x: optimization vector
    @param lmbda: C{eqnonlin} - Lagrange multipliers on power balance
    equations. C{ineqnonlin} - Kuhn-Tucker multipliers on constrained
    branch flows.
    @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}.
    @param cost_mult: (optional) Scale factor to be applied to the cost
    (default = 1).

    @return: Hessian of the Lagrangian.

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

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    """
    ##----- initialize -----
    ## unpack data
    ppc = om.get_ppc()
    baseMVA, bus, gen, branch, gencost = \
        ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"], ppc["gencost"]
    cp = om.get_cost_params()
    N, Cw, H, dd, rh, kk, mm = \
        cp["N"], cp["Cw"], cp["H"], cp["dd"], cp["rh"], cp["kk"], cp["mm"]
    vv, _, _, _ = om.get_idx()

    ## unpack needed parameters
    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

    ## reconstruct V
    Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
    Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
    V = Vm * exp(1j * Va)
    nxtra = nxyz - 2 * nb
    pcost = gencost[arange(ng), :]
    if gencost.shape[0] > ng:
        qcost = gencost[arange(ng, 2 * ng), :]
    else:
        qcost = array([])

    ## ----- evaluate d2f -----
    d2f_dPg2 = zeros(ng)  #sparse((ng, 1))               ## w.r.t. p.u. Pg
    d2f_dQg2 = zeros(ng)  #sparse((ng, 1))               ## w.r.t. p.u. Qg
    ipolp = find(pcost[:, MODEL] == POLYNOMIAL)
    d2f_dPg2[ipolp] = \
            baseMVA**2 * polycost(pcost[ipolp, :], Pg[ipolp] * baseMVA, 2)
    if any(qcost):  ## Qg is not free
        ipolq = find(qcost[:, MODEL] == POLYNOMIAL)
        d2f_dQg2[ipolq] = \
                baseMVA**2 * polycost(qcost[ipolq, :], Qg[ipolq] * baseMVA, 2)
    i = r_[arange(vv["i1"]["Pg"], vv["iN"]["Pg"]),
           arange(vv["i1"]["Qg"], vv["iN"]["Qg"])]
    #    d2f = sparse((vstack([d2f_dPg2, d2f_dQg2]).toarray().flatten(),
    #                  (i, i)), shape=(nxyz, nxyz))
    d2f = sparse((r_[d2f_dPg2, d2f_dQg2], (i, i)), (nxyz, nxyz))

    ## generalized cost
    if issparse(N) and N.nnz > 0:
        nw = N.shape[0]
        r = N * x - rh  ## Nx - rhat
        iLT = find(r < -kk)  ## below dead zone
        iEQ = find((r == 0) & (kk == 0))  ## dead zone doesn't exist
        iGT = find(r > kk)  ## above dead zone
        iND = r_[iLT, iEQ, iGT]  ## rows that are Not in the Dead region
        iL = find(dd == 1)  ## rows using linear function
        iQ = find(dd == 2)  ## rows using quadratic function
        LL = sparse((ones(len(iL)), (iL, iL)), (nw, nw))
        QQ = sparse((ones(len(iQ)), (iQ, iQ)), (nw, nw))
        kbar = sparse((r_[ones(len(iLT)),
                          zeros(len(iEQ)), -ones(len(iGT))], (iND, iND)),
                      (nw, nw)) * kk
        rr = r + kbar  ## apply non-dead zone shift
        M = sparse((mm[iND], (iND, iND)), (nw, nw))  ## dead zone or scale
        diagrr = sparse((rr, (arange(nw), arange(nw))), (nw, nw))

        ## linear rows multiplied by rr(i), quadratic rows by rr(i)^2
        w = M * (LL + QQ * diagrr) * rr
        HwC = H * w + Cw
        AA = N.T * M * (LL + 2 * QQ * diagrr)

        d2f = d2f + AA * H * AA.T + 2 * N.T * M * QQ * \
                sparse((HwC, (arange(nw), arange(nw))), (nw, nw)) * N
    d2f = d2f * cost_mult

    ##----- evaluate Hessian of power balance constraints -----
    nlam = len(lmbda["eqnonlin"]) / 2
    lamP = lmbda["eqnonlin"][:nlam]
    lamQ = lmbda["eqnonlin"][nlam:nlam + nlam]
    Gpaa, Gpav, Gpva, Gpvv = d2Sbus_dV2(Ybus, V, lamP)
    Gqaa, Gqav, Gqva, Gqvv = d2Sbus_dV2(Ybus, V, lamQ)

    d2G = vstack([
        hstack([
            vstack([hstack([Gpaa, Gpav]),
                    hstack([Gpva, Gpvv])]).real +
            vstack([hstack([Gqaa, Gqav]),
                    hstack([Gqva, Gqvv])]).imag,
            sparse((2 * nb, nxtra))
        ]),
        hstack([sparse(
            (nxtra, 2 * nb)), sparse((nxtra, nxtra))])
    ], "csr")

    ##----- evaluate Hessian of flow constraints -----
    nmu = len(lmbda["ineqnonlin"]) / 2
    muF = lmbda["ineqnonlin"][:nmu]
    muT = lmbda["ineqnonlin"][nmu:nmu + nmu]
    if ppopt['OPF_FLOW_LIM'] == 2:  ## current
        dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(branch, Yf, Yt, V)
        Hfaa, Hfav, Hfva, Hfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, muF)
        Htaa, Htav, Htva, Htvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, muT)
    else:
        f = branch[il, F_BUS].astype(int)  ## list of "from" buses
        t = branch[il, T_BUS].astype(int)  ## list of "to" buses
        ## connection matrix for line & from buses
        Cf = sparse((ones(nl2), (arange(nl2), f)), (nl2, nb))
        ## connection matrix for line & to buses
        Ct = sparse((ones(nl2), (arange(nl2), t)), (nl2, nb))
        dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = \
                dSbr_dV(branch[il,:], Yf, Yt, V)
        if ppopt['OPF_FLOW_LIM'] == 1:  ## real power
            Hfaa, Hfav, Hfva, Hfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real,
                                                Sf.real, Cf, Yf, V, muF)
            Htaa, Htav, Htva, Htvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real,
                                                St.real, Ct, Yt, V, muT)
        else:  ## apparent power
            Hfaa, Hfav, Hfva, Hfvv = \
                    d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, muF)
            Htaa, Htav, Htva, Htvv = \
                    d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, muT)

    d2H = vstack([
        hstack([
            vstack([hstack([Hfaa, Hfav]),
                    hstack([Hfva, Hfvv])]) +
            vstack([hstack([Htaa, Htav]),
                    hstack([Htva, Htvv])]),
            sparse((2 * nb, nxtra))
        ]),
        hstack([sparse(
            (nxtra, 2 * nb)), sparse((nxtra, nxtra))])
    ], "csr")

    ##-----  do numerical check using (central) finite differences  -----
    if 0:
        nx = len(x)
        step = 1e-5
        num_d2f = sparse((nx, nx))
        num_d2G = sparse((nx, nx))
        num_d2H = sparse((nx, nx))
        for i in range(nx):
            xp = x
            xm = x
            xp[i] = x[i] + step / 2
            xm[i] = x[i] - step / 2
            # evaluate cost & gradients
            _, dfp = opf_costfcn(xp, om)
            _, dfm = opf_costfcn(xm, om)
            # evaluate constraints & gradients
            _, _, dHp, dGp = opf_consfcn(xp, om, Ybus, Yf, Yt, ppopt, il)
            _, _, dHm, dGm = opf_consfcn(xm, om, Ybus, Yf, Yt, ppopt, il)
            num_d2f[:, i] = cost_mult * (dfp - dfm) / step
            num_d2G[:, i] = (dGp - dGm) * lmbda["eqnonlin"] / step
            num_d2H[:, i] = (dHp - dHm) * lmbda["ineqnonlin"] / step
        d2f_err = max(max(abs(d2f - num_d2f)))
        d2G_err = max(max(abs(d2G - num_d2G)))
        d2H_err = max(max(abs(d2H - num_d2H)))
        if d2f_err > 1e-6:
            print('Max difference in d2f: %g' % d2f_err)
        if d2G_err > 1e-5:
            print('Max difference in d2G: %g' % d2G_err)
        if d2H_err > 1e-6:
            print('Max difference in d2H: %g' % d2H_err)

    return d2f + d2G + d2H
Пример #4
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
Пример #6
0
def opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il=None, cost_mult=1.0):
    """Evaluates Hessian of Lagrangian for AC OPF.

    Hessian evaluation function for AC optimal power flow, suitable
    for use with L{pips}.

    Examples::
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt)
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il)
        Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il, cost_mult)

    @param x: optimization vector
    @param lmbda: C{eqnonlin} - Lagrange multipliers on power balance
    equations. C{ineqnonlin} - Kuhn-Tucker multipliers on constrained
    branch flows.
    @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}.
    @param cost_mult: (optional) Scale factor to be applied to the cost
    (default = 1).

    @return: Hessian of the Lagrangian.

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

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    """
    ##----- initialize -----
    ## unpack data
    ppc = om.get_ppc()
    baseMVA, bus, gen, branch, gencost = \
        ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"], ppc["gencost"]
    cp = om.get_cost_params()
    N, Cw, H, dd, rh, kk, mm = \
        cp["N"], cp["Cw"], cp["H"], cp["dd"], cp["rh"], cp["kk"], cp["mm"]
    vv, _, _, _ = om.get_idx()

    ## unpack needed parameters
    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

    ## reconstruct V
    Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
    Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
    V = Vm * exp(1j * Va)
    nxtra = nxyz - 2 * nb
    pcost = gencost[arange(ng), :]
    if gencost.shape[0] > ng:
        qcost = gencost[arange(ng, 2 * ng), :]
    else:
        qcost = array([])

    ## ----- evaluate d2f -----
    d2f_dPg2 = zeros(ng)#sparse((ng, 1))               ## w.r.t. p.u. Pg
    d2f_dQg2 = zeros(ng)#sparse((ng, 1))               ## w.r.t. p.u. Qg
    ipolp = find(pcost[:, MODEL] == POLYNOMIAL)
    d2f_dPg2[ipolp] = \
            baseMVA**2 * polycost(pcost[ipolp, :], Pg[ipolp] * baseMVA, 2)
    if any(qcost):          ## Qg is not free
        ipolq = find(qcost[:, MODEL] == POLYNOMIAL)
        d2f_dQg2[ipolq] = \
                baseMVA**2 * polycost(qcost[ipolq, :], Qg[ipolq] * baseMVA, 2)
    i = r_[arange(vv["i1"]["Pg"], vv["iN"]["Pg"]),
           arange(vv["i1"]["Qg"], vv["iN"]["Qg"])]
#    d2f = sparse((vstack([d2f_dPg2, d2f_dQg2]).toarray().flatten(),
#                  (i, i)), shape=(nxyz, nxyz))
    d2f = sparse((r_[d2f_dPg2, d2f_dQg2], (i, i)), (nxyz, nxyz))

    ## generalized cost
    if issparse(N) and N.nnz > 0:
        nw = N.shape[0]
        r = N * x - rh                    ## Nx - rhat
        iLT = find(r < -kk)               ## below dead zone
        iEQ = find((r == 0) & (kk == 0))  ## dead zone doesn't exist
        iGT = find(r > kk)                ## above dead zone
        iND = r_[iLT, iEQ, iGT]           ## rows that are Not in the Dead region
        iL = find(dd == 1)                ## rows using linear function
        iQ = find(dd == 2)                ## rows using quadratic function
        LL = sparse((ones(len(iL)), (iL, iL)), (nw, nw))
        QQ = sparse((ones(len(iQ)), (iQ, iQ)), (nw, nw))
        kbar = sparse((r_[ones(len(iLT)), zeros(len(iEQ)), -ones(len(iGT))],
                       (iND, iND)), (nw, nw)) * kk
        rr = r + kbar                  ## apply non-dead zone shift
        M = sparse((mm[iND], (iND, iND)), (nw, nw))  ## dead zone or scale
        diagrr = sparse((rr, (arange(nw), arange(nw))), (nw, nw))

        ## linear rows multiplied by rr(i), quadratic rows by rr(i)^2
        w = M * (LL + QQ * diagrr) * rr
        HwC = H * w + Cw
        AA = N.T * M * (LL + 2 * QQ * diagrr)

        d2f = d2f + AA * H * AA.T + 2 * N.T * M * QQ * \
                sparse((HwC, (arange(nw), arange(nw))), (nw, nw)) * N
    d2f = d2f * cost_mult

    ##----- evaluate Hessian of power balance constraints -----
    nlam = len(lmbda["eqnonlin"]) / 2
    lamP = lmbda["eqnonlin"][:nlam]
    lamQ = lmbda["eqnonlin"][nlam:nlam + nlam]
    Gpaa, Gpav, Gpva, Gpvv = d2Sbus_dV2(Ybus, V, lamP)
    Gqaa, Gqav, Gqva, Gqvv = d2Sbus_dV2(Ybus, V, lamQ)

    d2G = vstack([
            hstack([
                vstack([hstack([Gpaa, Gpav]),
                        hstack([Gpva, Gpvv])]).real +
                vstack([hstack([Gqaa, Gqav]),
                        hstack([Gqva, Gqvv])]).imag,
                sparse((2 * nb, nxtra))]),
            hstack([
                sparse((nxtra, 2 * nb)),
                sparse((nxtra, nxtra))
            ])
        ], "csr")

    ##----- evaluate Hessian of flow constraints -----
    nmu = len(lmbda["ineqnonlin"]) / 2
    muF = lmbda["ineqnonlin"][:nmu]
    muT = lmbda["ineqnonlin"][nmu:nmu + nmu]
    if ppopt['OPF_FLOW_LIM'] == 2:       ## current
        dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(Yf, Yt, V)
        Hfaa, Hfav, Hfva, Hfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, muF)
        Htaa, Htav, Htva, Htvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, muT)
    else:
        f = branch[il, F_BUS].astype(int)    ## list of "from" buses
        t = branch[il, T_BUS].astype(int)    ## list of "to" buses
        ## connection matrix for line & from buses
        Cf = sparse((ones(nl2), (arange(nl2), f)), (nl2, nb))
        ## connection matrix for line & to buses
        Ct = sparse((ones(nl2), (arange(nl2), t)), (nl2, nb))
        dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = \
                dSbr_dV(branch[il,:], Yf, Yt, V)
        if ppopt['OPF_FLOW_LIM'] == 1:     ## real power
            Hfaa, Hfav, Hfva, Hfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real,
                                                Sf.real, Cf, Yf, V, muF)
            Htaa, Htav, Htva, Htvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real,
                                                St.real, Ct, Yt, V, muT)
        else:                  ## apparent power
            Hfaa, Hfav, Hfva, Hfvv = \
                    d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, muF)
            Htaa, Htav, Htva, Htvv = \
                    d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, muT)

    d2H = vstack([
            hstack([
                vstack([hstack([Hfaa, Hfav]),
                        hstack([Hfva, Hfvv])]) +
                vstack([hstack([Htaa, Htav]),
                        hstack([Htva, Htvv])]),
                sparse((2 * nb, nxtra))
            ]),
            hstack([
                sparse((nxtra, 2 * nb)),
                sparse((nxtra, nxtra))
            ])
        ], "csr")

    ##-----  do numerical check using (central) finite differences  -----
    if 0:
        nx = len(x)
        step = 1e-5
        num_d2f = sparse((nx, nx))
        num_d2G = sparse((nx, nx))
        num_d2H = sparse((nx, nx))
        for i in range(nx):
            xp = x
            xm = x
            xp[i] = x[i] + step / 2
            xm[i] = x[i] - step / 2
            # evaluate cost & gradients
            _, dfp = opf_costfcn(xp, om)
            _, dfm = opf_costfcn(xm, om)
            # evaluate constraints & gradients
            _, _, dHp, dGp = opf_consfcn(xp, om, Ybus, Yf, Yt, ppopt, il)
            _, _, dHm, dGm = opf_consfcn(xm, om, Ybus, Yf, Yt, ppopt, il)
            num_d2f[:, i] = cost_mult * (dfp - dfm) / step
            num_d2G[:, i] = (dGp - dGm) * lmbda["eqnonlin"]   / step
            num_d2H[:, i] = (dHp - dHm) * lmbda["ineqnonlin"] / step
        d2f_err = max(max(abs(d2f - num_d2f)))
        d2G_err = max(max(abs(d2G - num_d2G)))
        d2H_err = max(max(abs(d2H - num_d2H)))
        if d2f_err > 1e-6:
            print('Max difference in d2f: %g' % d2f_err)
        if d2G_err > 1e-5:
            print('Max difference in d2G: %g' % d2G_err)
        if d2H_err > 1e-6:
            print('Max difference in d2H: %g' % d2H_err)

    return d2f + d2G + d2H
Пример #7
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
Пример #8
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()
Пример #9
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