def d2Ibr_dV2(Ybr, V, lam):
    """Computes 2nd derivatives of complex branch current w.r.t. voltage.

    Returns 4 matrices containing the partial derivatives w.r.t. voltage
    angle and magnitude of the product of a vector LAM with the 1st partial
    derivatives of the complex branch currents. Takes sparse branch admittance
    matrix C{Ybr}, voltage vector C{V} and C{nl x 1} vector of multipliers
    C{lam}. Output matrices are sparse.

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, I{"AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation"}, MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    nb = len(V)
    ib = arange(nb)
    diaginvVm = sparse((ones(nb) / abs(V), (ib, ib)))

    Haa = sparse((-(Ybr.T * lam) * V, (ib, ib)))
    Hva = -1j * Haa * diaginvVm
    Hav = Hva.copy()
    Hvv = sparse((nb, nb))

    return Haa, Hav, Hva, Hvv
Example #2
0
def dSbus_dV(Ybus, V):
    """Computes partial derivatives of power injection w.r.t. voltage.

    Returns two matrices containing partial derivatives of the complex bus
    power injections w.r.t voltage magnitude and voltage angle respectively
    (for all buses). If C{Ybus} is a sparse matrix, the return values will be
    also. The following explains the expressions used to form the matrices::

        S = diag(V) * conj(Ibus) = diag(conj(Ibus)) * V

    Partials of V & Ibus w.r.t. voltage magnitudes::
        dV/dVm = diag(V / abs(V))
        dI/dVm = Ybus * dV/dVm = Ybus * diag(V / abs(V))

    Partials of V & Ibus w.r.t. voltage angles::
        dV/dVa = j * diag(V)
        dI/dVa = Ybus * dV/dVa = Ybus * j * diag(V)

    Partials of S w.r.t. voltage magnitudes::
        dS/dVm = diag(V) * conj(dI/dVm) + diag(conj(Ibus)) * dV/dVm
               = diag(V) * conj(Ybus * diag(V / abs(V)))
                                        + conj(diag(Ibus)) * diag(V / abs(V))

    Partials of S w.r.t. voltage angles::
        dS/dVa = diag(V) * conj(dI/dVa) + diag(conj(Ibus)) * dV/dVa
               = diag(V) * conj(Ybus * j * diag(V))
                                        + conj(diag(Ibus)) * j * diag(V)
               = -j * diag(V) * conj(Ybus * diag(V))
                                        + conj(diag(Ibus)) * j * diag(V)
               = j * diag(V) * conj(diag(Ibus) - Ybus * diag(V))

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation", MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ib = range(len(V))

    if issparse(Ybus):
        Ibus = Ybus * V

        diagV = sparse((V, (ib, ib)))
        diagIbus = sparse((Ibus, (ib, ib)))
        diagVnorm = sparse((V / abs(V), (ib, ib)))
    else:
        Ibus = Ybus * asmatrix(V).T

        diagV = asmatrix(diag(V))
        diagIbus = asmatrix(diag( asarray(Ibus).flatten() ))
        diagVnorm = asmatrix(diag(V / abs(V)))

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

    return dS_dVm, dS_dVa
Example #3
0
def qp4d(h=False, pl=0, mi=50):
    """Constrained 4-d quadratic program from
    http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm
    """

    H = sparse([[1003.1,  4.3,     6.3,     5.9],
                [4.3,     2.2,     2.1,     3.9],
                [6.3,     2.1,     3.5,     4.8],
                [5.9,     3.9,     4.8,    10.0]])
    c = zeros(4)
    A = sparse([[   1,       1,       1,       1],
                [0.17,    0.11,    0.10,    0.18]])
    l = array([1, 0.10])
    u = array([1, Inf])
    xmin = zeros(4)
    x0 = array([1, 0, 0, 1], float)

    x, zl, zu, obj, status, zg = pyipopt_qp(H, c, A, l, u, x0, xmin, None,
                                           hessian=h,
                                           print_level=pl, max_iter=mi)

    assert status == 0  # success
    assert_array_almost_equal(x, array([0, 2.8, 0.2, 0]) / 3)
    assert_almost_equal(obj, 3.29 / 3)

    assert_array_almost_equal(zl, [2.24, 0, 0, 1.7667], 4)
    assert_array_almost_equal(zu, zeros(x.shape), 13)

#    assert_array_almost_equal(zg[:, 0], array([6.58, 0]) / 3, 6)
#    assert_array_almost_equal(zg[:, 1], [0, 0], 13)

    print '4-d QP - success'
def hess6(x, lam, cost_mult=1):
    mu = lam['ineqnonlin']
    Lxx = cost_mult * \
        sparse([[ 0, -1,  0],
                [-1,  0, -1],
                [ 0, -1,  0]], dtype=float) + \
        sparse([[2 * dot([1, 1], mu),  0, 0],
                [0, 2 * dot([-1, 1], mu), 0],
                [0, 0,  2 * dot([1, 1], mu)]], dtype=float)
    return Lxx
Example #5
0
def dIbr_dV(branch, Yf, Yt, V):
    """Computes partial derivatives of branch currents w.r.t. voltage.

    Returns four matrices containing partial derivatives of the complex
    branch currents at "from" and "to" ends of each branch w.r.t voltage
    magnitude and voltage angle respectively (for all buses). If C{Yf} is a
    sparse matrix, the partial derivative matrices will be as well. Optionally
    returns vectors containing the currents themselves. The following
    explains the expressions used to form the matrices::

        If = Yf * V

    Partials of V, Vf & If w.r.t. voltage angles::
        dV/dVa  = j * diag(V)
        dVf/dVa = sparse(range(nl), f, j*V(f)) = j * sparse(range(nl), f, V(f))
        dIf/dVa = Yf * dV/dVa = Yf * j * diag(V)

    Partials of V, Vf & If w.r.t. voltage magnitudes::
        dV/dVm  = diag(V / abs(V))
        dVf/dVm = sparse(range(nl), f, V(f) / abs(V(f))
        dIf/dVm = Yf * dV/dVm = Yf * diag(V / abs(V))

    Derivations for "to" bus are similar.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    i = range(len(V))

    Vnorm = V / abs(V)

    if issparse(Yf):
        diagV = sparse((V, (i, i)))
        diagVnorm = sparse((Vnorm, (i, i)))
    else:
        diagV       = asmatrix( diag(V) )
        diagVnorm   = asmatrix( diag(Vnorm) )

    dIf_dVa = Yf * 1j * diagV
    dIf_dVm = Yf * diagVnorm
    dIt_dVa = Yt * 1j * diagV
    dIt_dVm = Yt * diagVnorm

    # Compute currents.
    if issparse(Yf):
        If = Yf * V
        It = Yt * V
    else:
        If = asarray( Yf * asmatrix(V).T ).flatten()
        It = asarray( Yt * asmatrix(V).T ).flatten()

    return dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It
Example #6
0
def lp3d(h=False, pl=0, mi=50):
    """3-d LP from linprog documentation.
    """
    c = array([-5, -4, -6], float)
    A = sparse([[1, -1,  1],
                [3,  2,  4],
                [3,  2,  0]], dtype=float)
    l = None
    u = array([20, 42, 30], float)
    xmin = array([0, 0, 0], float)
    x0 = None

    x, zl, zu, obj, status, zg = pyipopt_lp(c, A, l, u, x0, xmin, None,
                                            hessian=h,
                                            print_level=pl, max_iter=mi)

    assert status == 0  # success
    assert_array_almost_equal(x, [0, 15, 3])
    assert_almost_equal(obj, -78.0, 5)

    assert_array_almost_equal(zl, [1, 0, 0], 9)
    assert_array_almost_equal(zu, zeros(x.shape), 13)

#    assert_array_almost_equal(zg[:, 0], [0, 0, 0], 13)
#    assert_array_almost_equal(zg[:, 1], [0, 1.5, 0.5], 9)

    print '3-d LP - success'
Example #7
0
def makeSbus(baseMVA, bus, gen):
    """Builds the vector of complex bus power injections.

    Returns the vector of complex bus power injections, that is, generation
    minus load. Power is expressed in per unit.

    @see: L{makeYbus}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    ## generator info
    on = find(gen[:, GEN_STATUS] > 0)      ## which generators are on?
    gbus = gen[on, GEN_BUS]                   ## what buses are they at?

    ## form net complex bus power injection vector
    nb = bus.shape[0]
    ngon = on.shape[0]
    ## connection matrix, element i, j is 1 if gen on(j) at bus i is ON
    Cg = sparse((ones(ngon), (gbus, range(ngon))), (nb, ngon))

    ## power injected by gens plus power injected by loads converted to p.u.
    Sbus = ( Cg * (gen[on, PG] + 1j * gen[on, QG]) -
             (bus[:, PD] + 1j * bus[:, QD]) ) / baseMVA

    return Sbus
Example #8
0
def makeLODF(branch, PTDF):
    """Builds the line outage distribution factor matrix.

    Returns the DC line outage distribution factor matrix for a given PTDF.
    The matrix is C{nbr x nbr}, where C{nbr} is the number of branches.

    Example::
        H = makePTDF(baseMVA, bus, branch)
        LODF = makeLODF(branch, H)

    @see: L{makePTDF}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    nl, nb = PTDF.shape
    f = branch[:, F_BUS]
    t = branch[:, T_BUS]
    Cft = sparse((r_[ones(nl), -ones(nl)],
                      (r_[f, t], r_[arange(nl), arange(nl)])), (nb, nl))

    H = PTDF * Cft
    h = diag(H, 0)
    LODF = H / (ones((nl, nl)) - ones((nl, 1)) * h.T)
    LODF = LODF - diag(diag(LODF)) - eye(nl, nl)

    return LODF
Example #9
0
def bustypes(bus, gen):
    """Builds index lists of each type of bus (C{REF}, C{PV}, C{PQ}).

    Generators with "out-of-service" status are treated as L{PQ} buses with
    zero generation (regardless of C{Pg}/C{Qg} values in gen). Expects C{bus}
    and C{gen} have been converted to use internal consecutive bus numbering.

    @param bus: bus data
    @param gen: generator data
    @return: index lists of each bus type

    @author: Ray Zimmerman (PSERC Cornell)
    """
    # get generator status
    nb = bus.shape[0]
    ng = gen.shape[0]
    # gen connection matrix, element i, j is 1 if, generator j at bus i is ON
    Cg = sparse((gen[:, GEN_STATUS] > 0,
                 (gen[:, GEN_BUS], range(ng))), (nb, ng))
    # number of generators at each bus that are ON
    bus_gen_status = (Cg * ones(ng, int)).astype(bool)

    # form index lists for slack, PV, and PQ buses
    ref = find((bus[:, BUS_TYPE] == REF) & bus_gen_status) # ref bus index
    pv  = find((bus[:, BUS_TYPE] == PV)  & bus_gen_status) # PV bus indices
    pq  = find((bus[:, BUS_TYPE] == PQ) | ~bus_gen_status) # PQ bus indices

    # pick a new reference bus if for some reason there is none (may have been
    # shut down)
    if len(ref) == 0:
        ref = pv[0]      # use the first PV bus
        pv = pv[1:]      # take it off PV list

    return ref, pv, pq
Example #10
0
def bustypes(bus, gen, Sbus):
    """
    Builds index lists of each type of bus (C{REF}, C{PV}, C{PQ}).

    Generators with "out-of-service" status are treated as L{PQ} buses with
    zero generation (regardless of C{Pg}/C{Qg} values in gen). Expects C{bus}
    and C{gen} have been converted to use internal consecutive bus numbering.

    @param bus: bus data
    @param gen: generator data
    @return: index lists of each bus type

    @author: Ray Zimmerman (PSERC Cornell)
    """
    # flag to indicate that it is impossible to solve the grid
    the_grid_is_disabled = False

    # get generator status
    nb = bus.shape[0]
    ng = gen.shape[0]
    # gen connection matrix, element i, j is 1 if, generator j at bus i is ON
    Cg = sparse((gen[:, GEN_STATUS] > 0,
                 (gen[:, GEN_BUS], range(ng))), (nb, ng))
    # number of generators at each bus that are ON
    bus_gen_status = (Cg * ones(ng, int)).astype(bool)

    # form index lists for slack, PV, and PQ buses
    ref = find((bus[:, BUS_TYPE] == REF) & bus_gen_status)  # ref bus index
    pv = find((bus[:, BUS_TYPE] == PV) & bus_gen_status)  # PV bus indices
    pq = find((bus[:, BUS_TYPE] == PQ) | ~bus_gen_status)  # PQ bus indices

    # pick a new reference bus if for some reason there is none (may have been
    # shut down)
    if len(ref) == 0:
        if len(pv) > 0:
            ref = [pv[0]]      # use the first PV bus
            pv = pv[1:]      # take it off PV list
        else:   # look for positive power injections to take the largest as the slack
            positive_power_injections = Sbus.real[where(Sbus.real > 0)[0]]
            if len(positive_power_injections) > 0:
                idx = where(Sbus.real == max(positive_power_injections))[0]
                if len(idx) == 1:
                    ref = idx
                    i = where(pq == idx[0])[0][0]
                    pq = delete(pq, i)
                else:
                    warn('It was not possible to find a slack bus')
                    the_grid_is_disabled = True
            else:
                warn('It was not possible to find a slack bus')
                the_grid_is_disabled = True

    # create the types array
    types = zeros(nb)
    types[ref] = 3
    types[pv] = 2
    types[pq] = 1

    return ref, pv, pq, types, the_grid_is_disabled
Example #11
0
def userfcn_reserves_formulation(om, *args):
    """This is the 'formulation' stage userfcn callback that defines the
    user costs and constraints for fixed reserves. It expects to find
    a 'reserves' field in the ppc stored in om, as described above.
    By the time it is passed to this callback, ppc['reserves'] should
    have two additional fields:
        - C{igr}     C{1 x ngr}, indices of generators available for reserves
        - C{rgens}   C{1 x ng}, 1 if gen avaiable for reserves, 0 otherwise
    It is also assumed that if cost or qty were C{ngr x 1}, they have been
    expanded to C{ng x 1} and that everything has been converted to
    internal indexing, i.e. all gens are on-line (by the 'ext2int'
    callback). The optional args are not currently used.
    """
    ## initialize some things
    ppc = om.get_ppc()
    r = ppc['reserves']
    igr = r['igr']                ## indices of gens available to provide reserves
    ngr = len(igr)                ## number of gens available to provide reserves
    ng  = ppc['gen'].shape[0]     ## number of on-line gens (+ disp loads)

    ## variable bounds
    Rmin = zeros(ngr)               ## bound below by 0
    Rmax = Inf * ones(ngr)          ## bound above by ...
    k = find(ppc['gen'][igr, RAMP_10])
    Rmax[k] = ppc['gen'][igr[k], RAMP_10] ## ... ramp rate and ...
    if 'qty' in r:
        k = find(r['qty'][igr] < Rmax)
        Rmax[k] = r['qty'][igr[k]]        ## ... stated max reserve qty
    Rmax = Rmax / ppc['baseMVA']

    ## constraints
    I = speye(ngr, ngr, format='csr')                     ## identity matrix
    Ar = hstack([sparse((ones(ngr), (arange(ngr), igr)), (ngr, ng)), I], 'csr')
    ur = ppc['gen'][igr, PMAX] / ppc['baseMVA']
    lreq = r['req'] / ppc['baseMVA']

    ## cost
    Cw = r['cost'][igr] * ppc['baseMVA']     ## per unit cost coefficients

    ## add them to the model
    om.add_vars('R', ngr, [], Rmin, Rmax)
    om.add_constraints('Pg_plus_R', Ar, [], ur, ['Pg', 'R'])
    om.add_constraints('Rreq', sparse( r['zones'][:, igr] ), lreq, [], ['R'])
    om.add_costs('Rcost', {'N': I, 'Cw': Cw}, ['R'])

    return om
def gh5(x):
    h = dot([[-1.0, -1.0],
             [ 1.0,  1.0]], x**2) + [1, -2]
    dh = 2 * sparse([[-x[0], x[0]],
                     [-x[1], x[1]]])
    g = array([])
    dg = None
    return h, g, dh, dg
def f5(x, return_hessian=False):
    c = -array([1.0, 1.0])
    f = dot(c, x)
    df = c
    if not return_hessian:
        return f, df
    d2f = sparse((2, 2))
    return f, df, d2f
def gh6(x):
    h = dot([[1.0, -1.0, 1.0],
             [1.0,  1.0, 1.0]], x**2) + [-2.0, -10.0]
    dh = 2 * sparse([[ x[0], x[0]],
                     [-x[1], x[1]],
                     [ x[2], x[2]]], dtype=float)
    g = array([])
    dg = None
    return h, g, dh, dg
Example #15
0
def make_sparse(a, b, w, n, m):
    s = sparse((n,m), dtype=scipy.complex128)
    for i, value in enumerate(a):
        try:
            s[int(a[i]), int(b[i])] = w[i][0]
        except: 
            s[int(a[i]), int(b[i])] = w[i]

    return s
def f6(x, return_hessian=False):
    f = -x[0] * x[1] - x[1] * x[2]
    df = -array([x[1], x[0] + x[2], x[1]])
    if not return_hessian:
        return f, df
    d2f = -sparse([[0, 1, 0],
                   [1, 0, 1],
                   [0, 1, 0]], dtype=float)
    return f, df, d2f
Example #17
0
def pre_process(n_bus, Yseries, Vset, pq, pv, vd):
    """
    Make the Helm System matrix
    @param n_bus: Number of buses of the circuit
    @param Yseries: Circuit admittance matrix of the series elements
    @param Vset: Vector of voltages of those nodes where the voltage is controlled (AKA Slack and PV buses)
    @param pq: list of PQ node indices
    @param pv: list of PV node indices
    @param vd: list of Slack node indices
    @return: 
    """
    npq = len(pq)
    npv = len(pv)
    nvd = len(vd)
    npqpv = npq + npv

    # now to have efficient arrays of coefficients, we create the array maps
    map_pqpv = zeros(n_bus, dtype=np.int)
    map_w = zeros(n_bus, dtype=np.int)
    map_pqpv[pq] = array(range(npq))
    map_pqpv[pv] = array(range(npv))
    map_w[r_[pq, pv]] = array(range(npqpv))

    # build the expanded system matrix
    Ysys = zeros((2*n_bus, 2*n_bus))

    # Yseries is a CRC sparse matrix, I pass it to coordinates to be able to vectorize the
    m = Yseries.tocoo()
    a = m.row
    b = m.col
    Ysys[2 * a, 2 * b] = m.data.real
    Ysys[2 * a, 2 * b + 1] = -m.data.imag
    Ysys[2 * a + 1, 2 * b] = m.data.imag
    Ysys[2 * a + 1, 2 * b + 1] = m.data.real

    # set pv columns
    Ysys[:, 2 * pv] = zeros((2 * n_bus, npv))
    Ysys[pv * 2 + 1, pv * 2] = ones(npv)

    # set vd elements
    Ysys[vd * 2, :] = zeros((nvd, 2 * n_bus))
    Ysys[vd * 2 + 1, :] = zeros((nvd, 2 * n_bus))
    Ysys[vd * 2, vd * 2] = ones(nvd)
    Ysys[vd * 2 + 1, vd * 2 + 1] = ones(nvd)

    # build the PV matrix
    Ysys_pv = zeros((2 * n_bus, npv))
    for a, b in product(r_[pq, pv], pv):
        kk = map_pqpv[b]
        Ysys_pv[2 * a, kk] = Yseries[a, b].real
        Ysys_pv[2 * a + 1, kk] = Yseries[a, b].imag

    # compute the voltage squared array
    Vset2 = Vset * Vset

    return sparse(Ysys), Ysys_pv, Vset2, map_pqpv, map_w, npq, npv, nvd
def hess7(x, lam, sigma=1):
    lmbda = asscalar( lam['eqnonlin'] )
    mu    = asscalar( lam['ineqnonlin'] )
    _, _, d2f = f7(x, True)

    Lxx = sigma * d2f + lmbda * 2 * speye(4, 4) - \
        mu * sparse([
            [        0.0, x[2] * x[3], x[2] * x[3], x[1] * x[2]],
            [x[2] * x[2],         0.0, x[0] * x[3], x[0] * x[2]],
            [x[1] * x[3], x[0] * x[3],         0.0, x[0] * x[1]],
            [x[1] * x[2], x[0] * x[2], x[0] * x[1],         0.0]
        ])
    return Lxx
def f3(x, return_hessian=False):
    H = sparse([
        [ 5, -2, -1],
        [-2,  4,  3],
        [-1,  3,  5]
    ], dtype=float)
    c = array([2, -35, -47], float)
    f = 0.5 * dot(x * H, x) + dot(c, x) + 5
    df = H * x + c
    if not return_hessian:
        return f, df
    d2f = H
    return f, df, d2f
def f4(x, return_hessian=False):
    H = sparse([
        [1003.1, 4.3, 6.3,  5.9],
        [   4.3, 2.2, 2.1,  3.9],
        [   6.3, 2.1, 3.5,  4.8],
        [   5.9, 3.9, 4.8, 10.0]
    ])
    c = zeros(4)
    f = 0.5 * dot(x * H, x) + dot(c, x)
    df = H * x + c
    if not return_hessian:
        return f, df
    d2f = H
    return f, df, d2f
Example #21
0
def d2AIbr_dV2(dIbr_dVa, dIbr_dVm, Ibr, Ybr, V, lam):
    """Computes 2nd derivatives of |complex current|**2 w.r.t. V.

    Returns 4 matrices containing the partial derivatives w.r.t. voltage
    angle and magnitude of the product of a vector C{lam} with the 1st partial
    derivatives of the square of the magnitude of the branch currents.
    Takes sparse first derivative matrices of complex flow, complex flow
    vector, sparse branch admittance matrix C{Ybr}, voltage vector C{V} and
    C{nl x 1} vector of multipliers C{lam}. Output matrices are sparse.

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, I{"AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation"}, MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @see: L{dIbr_dV}.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    # define
    il = range(len(lam))

    diaglam = sparse((lam, (il, il)))
    diagIbr_conj = sparse((Ibr.conj(), (il, il)))

    Iaa, Iav, Iva, Ivv = d2Ibr_dV2(Ybr, V, diagIbr_conj * lam)

    Haa = 2 * ( Iaa + dIbr_dVa.T * diaglam * dIbr_dVa.conj() ).real
    Hva = 2 * ( Iva + dIbr_dVm.T * diaglam * dIbr_dVa.conj() ).real
    Hav = 2 * ( Iav + dIbr_dVa.T * diaglam * dIbr_dVm.conj() ).real
    Hvv = 2 * ( Ivv + dIbr_dVm.T * diaglam * dIbr_dVm.conj() ).real

    return Haa, Hav, Hva, Hvv
def f7(x, return_hessian=False):
    f = x[0] * x[3] * sum(x[:3]) + x[2]
    df = array([ x[0] * x[3] + x[3] * sum(x[:3]),
                 x[0] * x[3],
                 x[0] * x[3] + 1,
                 x[0] * sum(x[:3]) ])
    if not return_hessian:
        return f, df
    d2f = sparse([
        [2 * x[3],               x[3], x[3], 2 * x[0] + x[1] + x[2]],
        [                  x[3],  0.0,  0.0,                   x[0]],
        [                  x[3],  0.0,  0.0,                   x[0]],
        [2 * x[0] + x[1] + x[2], x[0], x[0],                    0.0]
    ])
    return f, df, d2f
def f2(x, return_hessian=False):
    a = 100
    f = a * (x[1] - x[0]**2)**2 + (1 - x[0])**2
    df = array([
        4 * a * (x[0]**3 - x[0] * x[1]) + 2 * x[0] - 2,
        2 * a * (x[1] - x[0]**2)
    ])

    if not return_hessian:
        return f, df

    d2f = 4 * a * sparse([
        [3 * x[0]**2 - x[1] + 1. / (2 * a), -x[0]],
        [                           -x[0],   0.5]
    ])
    return f, df, d2f
Example #24
0
def pyipopt_lp(c, A, gl, gu, x0, xl=None, xu=None, hessian=False, **kw_args):
    """IPOPT based quadratic program solver.

    Solves linear programs of the form:

        min c'x
         x

    subject to:

            gl <= Ax <= gu
            xl <=  x <= xu
    """
    n = c.shape[0]
    H = sparse((n, n))

    return pyipopt_qp(H, c, A, gl, gu, x0, xl, xu, hessian, **kw_args)
def makeAang(baseMVA, branch, nb, ppopt):
    """Construct constraints for branch angle difference limits.

    Constructs the parameters for the following linear constraint limiting
    the voltage angle differences across branches, where C{Va} is the vector
    of bus voltage angles. C{nb} is the number of buses::

        lang <= Aang * Va <= uang

    C{iang} is the vector of indices of branches with angle difference limits.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    @author: Richard Lincoln
    """
    ## options
    ignore_ang_lim = ppopt['OPF_IGNORE_ANG_LIM']

    if ignore_ang_lim:
        Aang  = zeros((0, nb))
        lang  = array([])
        uang  = array([])
        iang  = array([])
    else:
        iang = find(((branch[:, ANGMIN] != 0) & (branch[:, ANGMIN] > -360)) |
                    ((branch[:, ANGMAX] != 0) & (branch[:, ANGMAX] <  360)))
        iangl = find(branch[iang, ANGMIN])
        iangh = find(branch[iang, ANGMAX])
        nang = len(iang)

        if nang > 0:
            ii = r_[arange(nang), arange(nang)]
            jj = r_[branch[iang, F_BUS], branch[iang, T_BUS]]
            Aang = sparse((r_[ones(nang), -ones(nang)],
                           (ii, jj)), (nang, nb))
            uang = Inf * ones(nang)
            lang = -uang
            lang[iangl] = branch[iang[iangl], ANGMIN] * pi / 180
            uang[iangh] = branch[iang[iangh], ANGMAX] * pi / 180
        else:
            Aang  = zeros((0, nb))
            lang  = array([])
            uang  = array([])

    return Aang, lang, uang, iang
Example #26
0
def userfcn_iflims_formulation(om, *args):
    """This is the 'formulation' stage userfcn callback that defines the
    user costs and constraints for interface flow limits. It expects to
    find an 'if' field in the ppc stored in om, as described above. The
    optional args are not currently used.
    """
    ## initialize some things
    ppc = om.get_ppc()
    baseMVA, bus, branch = ppc['baseMVA'], ppc['bus'], ppc['branch']
    ifmap = ppc['if']['map']
    iflims = ppc['if']['lims']

    ## form B matrices for DC model
    _, Bf, _, Pfinj = makeBdc(baseMVA, bus, branch)
    n = Bf.shape[1]                    ## dim of theta

    ## form constraints
    ifidx = unique(iflims[:, 0])   ## interface number list
    nifs = len(ifidx)              ## number of interfaces
    Aif = lil_matrix((nifs, n))
    lif = zeros(nifs)
    uif = zeros(nifs)
    for k in range(nifs):
        ## extract branch indices
        br = ifmap[ifmap[:, 0] == ifidx[k], 1]
        if len(br) == 0:
            stderr.write('userfcn_iflims_formulation: interface %d has no in-service branches\n' % k)

        d = sign(br)
        br = abs(br)
        Ak = sparse((1, n))              ## Ak = sum( d(i) * Bf(i, :) )
        bk = 0                           ## bk = sum( d(i) * Pfinj(i) )
        for i in range(len(br)):
            Ak = Ak + d[i] * Bf[br[i], :]
            bk = bk + d[i] * Pfinj[br[i]]

        Aif[k, :] = Ak
        lif[k] = iflims[k, 1] / baseMVA - bk
        uif[k] = iflims[k, 2] / baseMVA - bk

    ## add interface constraint
    om.add_constraints('iflims',  Aif, lif, uif, ['Va'])      ## nifs

    return om
Example #27
0
def userfcn_dcline_formulation(om, args):
    """This is the 'formulation' stage userfcn callback that defines the
    user constraints for the dummy generators representing DC lines.
    It expects to find a 'dcline' field in the ppc stored in om, as
    described above. By the time it is passed to this callback,
    MPC.dcline should contain only in-service lines and the from and
    two bus columns should be converted to internal indexing. The
    optional args are not currently used.

    If Pf, Pt and Ploss are the flow at the "from" end, flow at the
    "to" end and loss respectively, and L0 and L1 are the linear loss
    coefficients, the the relationships between them is given by:
        Pf - Ploss = Pt
        Ploss = L0 + L1 * Pf
    If Pgf and Pgt represent the injections of the dummy generators
    representing the DC line injections into the network, then
    Pgf = -Pf and Pgt = Pt, and we can combine all of the above to
    get the following constraint on Pgf ang Pgt:
        -Pgf - (L0 - L1 * Pgf) = Pgt
    which can be written:
        -L0 <= (1 - L1) * Pgf + Pgt <= -L0
    """
    ## define named indices into data matrices
    c = idx_dcline.c

    ## initialize some things
    ppc = om.get_ppc()
    dc = ppc['dcline']
    ndc = dc.shape[0]              ## number of in-service DC lines
    ng  = ppc['gen'].shape[0] - 2 * ndc  ## number of original gens/disp loads

    ## constraints
    #nL0 = -dc[:, c['LOSS0']] / ppc.baseMVA
    nL0 = -dc[:, c['LOSS0']] / ppc['baseMVA']
    L1  =  dc[:, c['LOSS1']]


    Adc = hstack([sparse((ndc, ng)), spdiags(1-L1, 0, ndc, ndc), speye(ndc, ndc)], format="csr")
    #Adc = c_[zeros(ndc, ng), spdiags(1-L1, 0, ndc, ndc), speye(ndc, ndc)]
    #print("Adc", Adc.todense())
    ## add them to the model
    om = om.add_constraints('dcline', Adc, nL0, nL0, ['Pg'])

    return om
Example #28
0
def d2Sbus_dV2(Ybus, V, lam):
    """Computes 2nd derivatives of power injection w.r.t. voltage.

    Returns 4 matrices containing the partial derivatives w.r.t. voltage angle
    and magnitude of the product of a vector C{lam} with the 1st partial
    derivatives of the complex bus power injections. Takes sparse bus
    admittance matrix C{Ybus}, voltage vector C{V} and C{nb x 1} vector of
    multipliers C{lam}. Output matrices are sparse.

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, I{"AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation"}, MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    nb = len(V)
    ib = arange(nb)
    Ibus = Ybus * V
    diaglam = sparse((lam, (ib, ib)))
    diagV = sparse((V, (ib, ib)))

    A = sparse((lam * V, (ib, ib)))
    B = Ybus * diagV
    C = A * conj(B)
    D = Ybus.H * diagV
    E = diagV.conj() * (D * diaglam - sparse((D * lam, (ib, ib))))
    F = C - A * sparse((conj(Ibus), (ib, ib)))
    G = sparse((ones(nb) / abs(V), (ib, ib)))

    Gaa = E + F
    Gva = 1j * G * (E - F)
    Gav = Gva.T
    Gvv = G * (C + C.T) * G

    return Gaa, Gav, Gva, Gvv
Example #29
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
Example #30
0
def t_opf_pips(quiet=False):
    """Tests for PIPS-based AC optimal power flow.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    num_tests = 101

    t_begin(num_tests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_opf')
    verbose = 0#not quiet

    t0 = 'PIPS : '
    ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8,
                   PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9)
    ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose, OPF_ALG=560)

    ## set up indices
    ib_data     = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)]
    ib_voltage  = arange(VM, VA + 1)
    ib_lam      = arange(LAM_P, LAM_Q + 1)
    ib_mu       = arange(MU_VMAX, MU_VMIN + 1)
    ig_data     = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)]
    ig_disp     = array([PG, QG, VG])
    ig_mu       = arange(MU_PMAX, MU_QMIN + 1)
    ibr_data    = arange(ANGMAX + 1)
    ibr_flow    = arange(PF, QT + 1)
    ibr_mu      = array([MU_SF, MU_ST])
    ibr_angmu   = array([MU_ANGMIN, MU_ANGMAX])

    ## get solved AC power flow case from MAT-file
    soln9_opf = loadmat(join(tdir, 'soln9_opf.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf['bus_soln']
    gen_soln = soln9_opf['gen_soln']
    branch_soln = soln9_opf['branch_soln']
    f_soln = soln9_opf['f_soln'][0]

    ## run OPF
    t = t0
    r = runopf(casefile, ppopt)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])

    ## run with automatic conversion of single-block pwl to linear costs
    t = ''.join([t0, '(single-block PWL) : '])
    ppc = loadcase(casefile)
    ppc['gencost'][2, NCOST] = 2
    r = runopf(ppc, ppopt)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])
    xr = r_[r['var']['val']['Va'], r['var']['val']['Vm'], r['var']['val']['Pg'],
            r['var']['val']['Qg'], 0, r['var']['val']['y']]
    t_is(r['x'], xr, 8, [t, 'check on raw x returned from OPF'])

    ## get solved AC power flow case from MAT-file
    soln9_opf_Plim = loadmat(join(tdir, 'soln9_opf_Plim.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf_Plim['bus_soln']
    gen_soln = soln9_opf_Plim['gen_soln']
    branch_soln = soln9_opf_Plim['branch_soln']
    f_soln = soln9_opf_Plim['f_soln'][0]

    ## run OPF with active power line limits
    t = ''.join([t0, '(P line lim) : '])
    ppopt1 = ppoption(ppopt, OPF_FLOW_LIM=1)
    r = runopf(casefile, ppopt1)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])

    ##-----  test OPF with quadratic gen costs moved to generalized costs  -----
    ppc = loadcase(casefile)
    ppc['gencost'] = array([
        [2,   1500, 0,   3,   0.11,    5,   0],
        [2,   2000, 0,   3,   0.085,   1.2, 0],
        [2,   3000, 0,   3,   0.1225,  1,   0]
    ])
    r = runopf(ppc, ppopt)
    bus_soln, gen_soln, branch_soln, f_soln, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    branch_soln = branch_soln[:, :MU_ST + 1]

    A = None
    l = array([])
    u = array([])
    nb = ppc['bus'].shape[0]      # number of buses
    ng = ppc['gen'].shape[0]      # number of gens
    thbas = 0;                thend    = thbas + nb
    vbas     = thend;     vend     = vbas + nb
    pgbas    = vend;      pgend    = pgbas + ng
#    qgbas    = pgend;     qgend    = qgbas + ng
    nxyz = 2 * nb + 2 * ng
    N = sparse((ppc['baseMVA'] * ones(ng), (arange(ng), arange(pgbas, pgend))), (ng, nxyz))
    fparm = ones((ng, 1)) * array([[1, 0, 0, 1]])
    ix = argsort(ppc['gen'][:, 0])
    H = 2 * spdiags(ppc['gencost'][ix, 4], 0, ng, ng, 'csr')
    Cw = ppc['gencost'][ix, 5]
    ppc['gencost'][:, 4:7] = 0

    ## run OPF with quadratic gen costs moved to generalized costs
    t = ''.join([t0, 'w/quadratic generalized gen cost : '])
    r = opf(ppc, A, l, u, ppopt, N, fparm, H, Cw)
    f, bus, gen, branch, success = \
            r['f'], r['bus'], r['gen'], r['branch'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])
    t_is(r['cost']['usr'], f, 12, [t, 'user cost'])

    ##-----  run OPF with extra linear user constraints & costs  -----
    ## single new z variable constrained to be greater than or equal to
    ## deviation from 1 pu voltage at bus 1, linear cost on this z
    ## get solved AC power flow case from MAT-file
    soln9_opf_extras1 = loadmat(join(tdir, 'soln9_opf_extras1.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf_extras1['bus_soln']
    gen_soln = soln9_opf_extras1['gen_soln']
    branch_soln = soln9_opf_extras1['branch_soln']
    f_soln = soln9_opf_extras1['f_soln'][0]

    row = [0, 0, 1, 1]
    col = [9, 24, 9, 24]
    A = sparse(([-1, 1, 1, 1], (row, col)), (2, 25))
    u = array([Inf, Inf])
    l = array([-1, 1])

    N = sparse(([1], ([0], [24])), (1, 25))    ## new z variable only
    fparm = array([[1, 0, 0, 1]])              ## w = r = z
    H = sparse((1, 1))                ## no quadratic term
    Cw = array([100.0])

    t = ''.join([t0, 'w/extra constraints & costs 1 : '])
    r = opf(casefile, A, l, u, ppopt, N, fparm, H, Cw)
    f, bus, gen, branch, success = \
            r['f'], r['bus'], r['gen'], r['branch'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])
    t_is(r['var']['val']['z'], 0.025419, 6, [t, 'user variable'])
    t_is(r['cost']['usr'], 2.5419, 4, [t, 'user cost'])

    ##-----  test OPF with capability curves  -----
    ppc = loadcase(join(tdir, 't_case9_opfv2'))
    ## remove angle diff limits
    ppc['branch'][0, ANGMAX] =  360
    ppc['branch'][8, ANGMIN] = -360

    ## get solved AC power flow case from MAT-file
    soln9_opf_PQcap = loadmat(join(tdir, 'soln9_opf_PQcap.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf_PQcap['bus_soln']
    gen_soln = soln9_opf_PQcap['gen_soln']
    branch_soln = soln9_opf_PQcap['branch_soln']
    f_soln = soln9_opf_PQcap['f_soln'][0]

    ## run OPF with capability curves
    t = ''.join([t0, 'w/capability curves : '])
    r = runopf(ppc, ppopt)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])

    ##-----  test OPF with angle difference limits  -----
    ppc = loadcase(join(tdir, 't_case9_opfv2'))
    ## remove capability curves
    ppc['gen'][ix_(arange(1, 3),
                   [PC1, PC2, QC1MIN, QC1MAX, QC2MIN, QC2MAX])] = zeros((2, 6))

    ## get solved AC power flow case from MAT-file
    soln9_opf_ang = loadmat(join(tdir, 'soln9_opf_ang.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf_ang['bus_soln']
    gen_soln = soln9_opf_ang['gen_soln']
    branch_soln = soln9_opf_ang['branch_soln']
    f_soln = soln9_opf_ang['f_soln'][0]

    ## run OPF with angle difference limits
    t = ''.join([t0, 'w/angle difference limits : '])
    r = runopf(ppc, ppopt)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  1, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])
    t_is(branch[:, ibr_angmu ], branch_soln[:, ibr_angmu ],  2, [t, 'branch angle mu'])

    ##-----  test OPF with ignored angle difference limits  -----
    ## get solved AC power flow case from MAT-file
    soln9_opf = loadmat(join(tdir, 'soln9_opf.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_opf['bus_soln']
    gen_soln = soln9_opf['gen_soln']
    branch_soln = soln9_opf['branch_soln']
    f_soln = soln9_opf['f_soln'][0]

    ## run OPF with ignored angle difference limits
    t = ''.join([t0, 'w/ignored angle difference limits : '])
    ppopt1 = ppoption(ppopt, OPF_IGNORE_ANG_LIM=1)
    r = runopf(ppc, ppopt1)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    ## ang limits are not in this solution data, so let's remove them
    branch[0, ANGMAX] =  360
    branch[8, ANGMIN] = -360
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
    t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
    t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
    t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
    t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
    t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])

    t_end()
Example #31
0
File: mt3d.py Project: wulich/MudPy
def run_inversion(home,
                  project_name,
                  run_name,
                  source_name,
                  model_name,
                  GF_list,
                  G_from_file,
                  G_name,
                  reg_spatial,
                  nsources,
                  solver,
                  forceMT,
                  mt,
                  weight=False,
                  Ltype=0):
    '''
    Assemble G and d, determine smoothing and run the inversion
    '''
    from mudpy import inverse as inv
    from mudpy.forward import get_mu_and_area
    from numpy import zeros, dot, array, squeeze, expand_dims, empty, tile, eye, ones, arange, load
    from numpy.linalg import lstsq
    from scipy.sparse import csr_matrix as sparse
    from scipy.optimize import nnls
    from datetime import datetime
    import gc

    t1 = datetime.now()
    #Get data vector
    d = inv.getdata(home, project_name, GF_list, decimate=None, bandpass=None)

    #Get GFs
    G = getG(home, project_name, source_name, model_name, GF_list, G_from_file,
             G_name, forceMT)

    #Get data weights
    if weight == True:
        print 'Applying data weights'
        w = inv.get_data_weights(home, project_name, GF_list, d, None)
        W = empty(G.shape)
        W = tile(w, (G.shape[1], 1)).T
        WG = empty(G.shape)
        WG = W * G
        wd = w * d.squeeze()
        wd = expand_dims(wd, axis=1)
        #Clear up extraneous variables
        W = None
        w = None
        #Define inversion quantities
        x = WG.transpose().dot(wd)
        print 'Computing G\'G'
        K = (WG.T).dot(WG)
        #And cleanup
        W = None
        WG = None
        wd = None
    else:
        #Define inversion quantities if no weightd
        x = G.transpose().dot(d)
        print 'Computing G\'G'
        K = (G.T).dot(G)

    #Cleanup
    #G=None

    #Get regularization matrices (set to 0 matrix if not needed)
    if forceMT == False:
        Ls = eye(nsources * 6)
    else:
        Ls = eye(nsources)
    print 'Nsources: ' + str(nsources)
    Ninversion = len(reg_spatial)

    #Make L's sparse
    Ls = sparse(Ls)
    #Get regularization tranposes for ABIC
    LsLs = Ls.transpose().dot(Ls)
    #inflate
    Ls = Ls.todense()
    LsLs = LsLs.todense()

    #off we go
    dt = datetime.now() - t1
    print 'Preprocessing wall time was ' + str(dt)
    print '\n--- RUNNING INVERSIONS ---\n'
    ttotal = datetime.now()
    kout = 0

    for ks in range(len(reg_spatial)):

        t1 = datetime.now()
        lambda_spatial = reg_spatial[ks]
        print 'Running inversion ' + str(kout + 1) + ' of ' + str(
            Ninversion) + ' at regularization levels: ls =' + repr(
                lambda_spatial)

        Kinv = K + (lambda_spatial**2) * LsLs

        if solver == 'lstsq':
            sol, res, rank, s = lstsq(Kinv, x)
        elif solver == 'nnls':
            sol, res = nnls(Kinv, squeeze(x.T))

        #Compute synthetics
        ds = dot(G, sol)

        #Get stats
        L2, Lmodel = inv.get_stats(Kinv, sol, x)
        VR = inv.get_VR(home, project_name, GF_list, sol, d, ds, None)

        #Get moment
        M0total, M0, Mw = get_moment(home, project_name, source_name, sol,
                                     forceMT)

        #Write log
        write_log(home, project_name, run_name, kout, lambda_spatial, L2,
                  Lmodel, VR, M0total, Mw, model_name, source_name, G_name,
                  GF_list)

        #Write output to file
        inv.write_synthetics(home, project_name, run_name, GF_list, G, sol, ds,
                             kout, None)
        write_model(home, project_name, run_name, source_name, model_name, sol,
                    kout, forceMT, mt)

        kout += 1
        dt1 = datetime.now() - t1
        dt2 = datetime.now() - ttotal
        print '... inversion wall time was ' + str(
            dt1) + ', total wall time elapsed is ' + str(dt2)
Example #32
0
def makeBdc(baseMVA, bus, branch):
    """Builds the B matrices and phase shift injections for DC power flow.

    Returns the B matrices and phase shift injection vectors needed for a
    DC power flow.
    The bus real power injections are related to bus voltage angles by::
        P = Bbus * Va + PBusinj
    The real power flows at the from end the lines are related to the bus
    voltage angles by::
        Pf = Bf * Va + Pfinj
    Does appropriate conversions to p.u.

    @see: L{dcpf}

    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    ## constants
    nb = bus.shape[0]          ## number of buses
    nl = branch.shape[0]       ## number of lines

    ## check that bus numbers are equal to indices to bus (one set of bus nums)
    if any(bus[:, BUS_I] != range(nb)):
        stderr.write('makeBdc: buses must be numbered consecutively in '
                     'bus matrix\n')

    ## for each branch, compute the elements of the branch B matrix and the phase
    ## shift "quiescent" injections, where
    ##
    ##      | Pf |   | Bff  Bft |   | Vaf |   | Pfinj |
    ##      |    | = |          | * |     | + |       |
    ##      | Pt |   | Btf  Btt |   | Vat |   | Ptinj |
    ##
    stat = branch[:, BR_STATUS]               ## ones at in-service branches
    b = stat / branch[:, BR_X]                ## series susceptance
    tap = ones(nl)                            ## default tap ratio = 1
    i = find(branch[:, TAP])               ## indices of non-zero tap ratios
    tap[i] = branch[i, TAP]                   ## assign non-zero tap ratios
    b = b / tap

    ## build connection matrix Cft = Cf - Ct for line and from - to buses
    f = branch[:, F_BUS]                           ## list of "from" buses
    t = branch[:, T_BUS]                           ## list of "to" buses
    i = r_[range(nl), range(nl)]                   ## double set of row indices
    ## connection matrix
    Cft = sparse((r_[ones(nl), -ones(nl)], (i, r_[f, t])), (nl, nb))

    ## build Bf such that Bf * Va is the vector of real branch powers injected
    ## at each branch's "from" bus
    Bf = sparse((r_[b, -b], (i, r_[f, t])))## = spdiags(b, 0, nl, nl) * Cft

    ## build Bbus
    Bbus = Cft.T * Bf

    ## build phase shift injection vectors
    Pfinj = b * (-branch[:, SHIFT] * pi / 180)  ## injected at the from bus ...
    # Ptinj = -Pfinj                            ## and extracted at the to bus
    Pbusinj = Cft.T * Pfinj                ## Pbusinj = Cf * Pfinj + Ct * Ptinj

    return Bbus, Bf, Pbusinj, Pfinj
Example #33
0
def newtonpf(Ybus, Sbus, V0, pv, pq, options, numba):
    """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

    Modified by University of Kassel (Florian Schaefer) to use numba
    """

    ## default arguments
    global dSbus_dV_calc, dSbus_dV_calc

    ## options
    tol     = options['tolerance_kva'] * 1e-3
    max_it  = options["max_iteration"]

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

    ## set up indexing for updating V
    pvpq = r_[pv, pq]
    # generate lookup pvpq -> index pvpq (used in createJ)
    pvpq_lookup = zeros(pvpq[-1]+1, dtype=int)
    pvpq_lookup[pvpq] = arange(len(pvpq))

    # if numba is available import "numba enhanced" functions
    if numba:
        from pandapower.pypower_extensions.create_J import create_J, create_J2
        from pandapower.pypower_extensions.dSbus_dV import dSbus_dV_calc
        from pandapower.pypower_extensions.dSbus_dV import dSbus_dV

        # check if pvpq is the same as pq. In this case a faster version of create_J can be used
        if len(pvpq) == len(pq):
            createJ = create_J2
        else:
            createJ = create_J
    else:
        # numba == False -> Import pypower standard
        from pypower.dSbus_dV import dSbus_dV

    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 for convergence
    converged = _check_for_convergence(F, tol)

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

        # use numba if activated
        if numba:
            #create Jacobian from fast calc of dS_dV
            dVm_x, dVa_x = dSbus_dV_calc(Ybus.data, Ybus.indptr, Ybus.indices, V, V/abs(V))

            # data in J, space preallocated is bigger than acutal Jx -> will be reduced later on
            Jx = empty(len(dVm_x) * 4, dtype=float64)
            # row pointer, dimension = pvpq.shape[0] + pq.shape[0] + 1
            Jp = zeros(pvpq.shape[0] + pq.shape[0] + 1, dtype=int64)
            # indices, same with the preallocated space (see Jx)
            Jj = empty(len(dVm_x) * 4, dtype=int64)

            # fill Jx, Jj and Jp
            createJ(dVm_x, dVa_x, Ybus.indptr, Ybus.indices, pvpq_lookup, pvpq, pq, Jx, Jj, Jp)

            # resize before generating the scipy sparse matrix
            Jx.resize(Jp[-1], refcheck=False)
            Jj.resize(Jp[-1], refcheck=False)

            # generate scipy sparse matrix
            dimJ = npv+npq+npq
            J = sparse((Jx, Jj, Jp), shape=(dimJ, dimJ))

        else:
            # create Jacobian with standard pypower implementation.
            dS_dVm, dS_dVa = dSbus_dV(Ybus, V)

            ## evaluate Jacobian
            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
        converged = _check_for_convergence(F, tol)

    return V, converged, i
Example #34
0
def optimal_power_flow(*args):
    casedata = args[0]  # Target power flow modelling
    mpc = loadcase(casedata)  # Import the power flow modelling
    ## convert to internal indexing
    mpc = ext2int(mpc)
    baseMVA, bus, gen, branch, gencost = mpc["baseMVA"], mpc["bus"], mpc[
        "gen"], mpc["branch"], mpc["gencost"]  #

    nb = shape(mpc['bus'])[0]  ## number of buses
    nl = shape(mpc['branch'])[0]  ## number of branches
    ng = shape(mpc['gen'])[0]  ## number of dispatchable injections

    ## Formualte the
    stat = branch[:, BR_STATUS]  ## ones at in-service branches
    b = stat / branch[:, BR_X]  ## series susceptance
    tap = ones(nl)  ## default tap ratio = 1
    i = find(branch[:, TAP])  ## indices of non-zero tap ratios
    tap[i] = branch[i, TAP]  ## assign non-zero tap ratios

    ## build connection matrix Cft = Cf - Ct for line and from - to buses
    f = branch[:, F_BUS]  ## list of "from" buses
    t = branch[:, T_BUS]  ## list of "to" buses
    i = r_[range(nl), range(nl)]  ## double set of row indices
    ## connection matrix
    Cft = sparse((r_[ones(nl), -ones(nl)], (i, r_[f, t])), (nl, nb))

    ## build Bf such that Bf * Va is the vector of real branch powers injected
    ## at each branch's "from" bus
    Bf = sparse((r_[b, -b], (i, r_[f, t])),
                shape=(nl, nb))  ## = spdiags(b, 0, nl, nl) * Cft

    ## build Bbus
    Bbus = Cft.T * Bf
    # The distribution factor
    Distribution_factor = sparse(Bf * inv(Bbus))

    Cg = sparse(
        (ones(ng), (gen[:, GEN_BUS], arange(ng))), (nb, ng)
    )  # Sparse index generation method is different from the way of matlab
    Cd = sparse((ones(nb), (bus[:, BUS_I], arange(nb))),
                (nb, nb))  # Sparse index load

    Pd = sum(bus[:, PD])  # Total power demand

    # Formulate the problem
    lb = gen[:, PMIN]
    ub = gen[:, PMAX]
    Aeq = sparse(ones(ng))
    beq = [Pd]

    Aineq = Distribution_factor * Cg
    Aineq = vstack([Aineq, -Aineq])

    bineq = concatenate(
        (branch[:, RATE_A] + Distribution_factor * Cd * bus[:, PD],
         branch[:, RATE_A] - Distribution_factor * Cd * bus[:, PD]))
    c = gencost[:, 5]
    Q = 2 * diag(gencost[:, 4])
    (Pg, obj) = miqp_gurobi(c=c,
                            Q=Q,
                            Aeq=Aeq,
                            beq=beq,
                            A=Aineq,
                            b=bineq,
                            xmin=lb,
                            xmax=ub)
    obj = obj + sum(gencost[:, 6])
    return Pg, obj
Example #35
0
def dSbus_dV(Ybus, V):
    """
    Computes partial derivatives of power injection w.r.t. voltage.

    Returns two matrices containing partial derivatives of the complex bus
    power injections w.r.t voltage magnitude and voltage angle respectively
    (for all buses). If C{Ybus} is a sparse matrix, the return values will be
    also. The following explains the expressions used to form the matrices::

        S = diag(V) * conj(Ibus) = diag(conj(Ibus)) * V

    Partials of V & Ibus w.r.t. voltage magnitudes::
        dV/dVm = diag(V / abs(V))
        dI/dVm = Ybus * dV/dVm = Ybus * diag(V / abs(V))

    Partials of V & Ibus w.r.t. voltage angles::
        dV/dVa = j * diag(V)
        dI/dVa = Ybus * dV/dVa = Ybus * j * diag(V)

    Partials of S w.r.t. voltage magnitudes::
        dS/dVm = diag(V) * conj(dI/dVm) + diag(conj(Ibus)) * dV/dVm
               = diag(V) * conj(Ybus * diag(V / abs(V)))
                                        + conj(diag(Ibus)) * diag(V / abs(V))

    Partials of S w.r.t. voltage angles::
        dS/dVa = diag(V) * conj(dI/dVa) + diag(conj(Ibus)) * dV/dVa
               = diag(V) * conj(Ybus * j * diag(V))
                                        + conj(diag(Ibus)) * j * diag(V)
               = -j * diag(V) * conj(Ybus * diag(V))
                                        + conj(diag(Ibus)) * j * diag(V)
               = j * diag(V) * conj(diag(Ibus) - Ybus * diag(V))

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation", MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ib = range(len(V))

    if issparse(Ybus):
        Ibus = Ybus * V

        diagV = sparse((V, (ib, ib)))
        diagIbus = sparse((Ibus, (ib, ib)))
        diagVnorm = sparse((V / abs(V), (ib, ib)))
    else:
        Ibus = Ybus * asmatrix(V).T

        diagV = asmatrix(diag(V))
        diagIbus = asmatrix(diag(asarray(Ibus).flatten()))
        diagVnorm = asmatrix(diag(V / abs(V)))

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

    return dS_dVm, dS_dVa
Example #36
0
def makeAy(baseMVA, ng, gencost, pgbas, qgbas, ybas):
    """Make the A matrix and RHS for the CCV formulation.

    Constructs the parameters for linear "basin constraints" on C{Pg}, C{Qg}
    and C{Y} used by the CCV cost formulation, expressed as::

         Ay * x <= by

    where C{x} is the vector of optimization variables. The starting index
    within the C{x} vector for the active, reactive sources and the C{y}
    variables should be provided in arguments C{pgbas}, C{qgbas}, C{ybas}.
    The number of generators is C{ng}.

    Assumptions: All generators are in-service.  Filter any generators
    that are offline from the C{gencost} matrix before calling L{makeAy}.
    Efficiency depends on C{Qg} variables being after C{Pg} variables, and
    the C{y} variables must be the last variables within the vector C{x} for
    the dimensions of the resulting C{Ay} to be conformable with C{x}.

    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    """
    ## find all pwl cost rows in gencost, either real or reactive
    iycost = find(gencost[:, MODEL] == PW_LINEAR)

    ## this is the number of extra "y" variables needed to model those costs
    ny = iycost.shape[0]

    if ny == 0:
        Ay = zeros((0, ybas + ny - 1))  ## TODO: Check size (- 1)
        by = array([])
        return Ay, by

    ## if p(i),p(i+1),c(i),c(i+1) define one of the cost segments, then
    ## the corresponding constraint on Pg (or Qg) and Y is
    ##                                             c(i+1) - c(i)
    ##  Y   >=   c(i) + m * (Pg - p(i)),      m = ---------------
    ##                                             p(i+1) - p(i)
    ##
    ## this becomes   m * Pg - Y   <=   m*p(i) - c(i)

    ## Form A matrix.  Use two different loops, one for the PG/Qg coefs,
    ## then another for the y coefs so that everything is filled in the
    ## same order as the compressed column sparse format used by matlab
    ## this should be the quickest.

    m = sum(gencost[iycost, NCOST].astype(int))  ## total number of cost points
    Ay = sparse((m - ny, ybas + ny - 1))
    by = array([])
    ## First fill the Pg or Qg coefficients (since their columns come first)
    ## and the rhs
    k = 0
    for i in iycost:
        ns = gencost[i, NCOST].astype(int)  ## # of cost points segments = ns-1
        p = gencost[i, COST:COST + 2 * ns - 1:2] / baseMVA
        c = gencost[i, COST + 1:COST + 2 * ns:2]
        m = diff(c) / diff(p)  ## slopes for Pg (or Qg)
        if any(diff(p) == 0):
            print('makeAy: bad x axis data in row ##i of gencost matrix' % i)
        b = m * p[:ns - 1] - c[:ns - 1]  ## and rhs
        by = r_[by, b]
        if i > ng:
            sidx = qgbas + (i - ng) - 1  ## this was for a q cost
        else:
            sidx = pgbas + i - 1  ## this was for a p cost

        ## FIXME: Bug in SciPy 0.7.2 prevents setting with a sequence
#        Ay[k:k + ns - 1, sidx] = m
        for ii, kk in enumerate(range(k, k + ns - 1)):
            Ay[kk, sidx] = m[ii]

        k = k + ns - 1
    ## Now fill the y columns with -1's
    k = 0
    j = 0
    for i in iycost:
        ns = gencost[i, NCOST].astype(int)
        ## FIXME: Bug in SciPy 0.7.2 prevents setting with a sequence
        #        Ay[k:k + ns - 1, ybas + j - 1] = -ones(ns - 1)
        for kk in range(k, k + ns - 1):
            Ay[kk, ybas + j - 1] = -1
        k = k + ns - 1
        j = j + 1

    return Ay.tocsr(), by
Example #37
0
def makeApq(baseMVA, gen):
    """Construct linear constraints for generator capability curves.

    Constructs the parameters for the following linear constraints
    implementing trapezoidal generator capability curves, where
    C{Pg} and C{Qg} are the real and reactive generator injections::

        Apqh * [Pg, Qg] <= ubpqh
        Apql * [Pg, Qg] <= ubpql

    C{data} constains additional information as shown below.

    Example::
        Apqh, ubpqh, Apql, ubpql, data = makeApq(baseMVA, gen)

        data['h']      [Qc1max-Qc2max, Pc2-Pc1]
        data['l']      [Qc2min-Qc1min, Pc1-Pc2]
        data['ipqh']   indices of gens with general PQ cap curves (upper)
        data['ipql']   indices of gens with general PQ cap curves (lower)

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    """
    data = {}
    ## data dimensions
    ng = gen.shape[0]  ## number of dispatchable injections

    ## which generators require additional linear constraints
    ## (in addition to simple box constraints) on (Pg,Qg) to correctly
    ## model their PQ capability curves
    ipqh = find(hasPQcap(gen, 'U'))
    ipql = find(hasPQcap(gen, 'L'))
    npqh = ipqh.shape[0]  ## number of general PQ capability curves (upper)
    npql = ipql.shape[0]  ## number of general PQ capability curves (lower)

    ## make Apqh if there is a need to add general PQ capability curves
    ## use normalized coefficient rows so multipliers have right scaling
    ## in $$/pu
    if npqh > 0:
        data["h"] = c_[gen[ipqh, QC1MAX] - gen[ipqh, QC2MAX],
                       gen[ipqh, PC2] - gen[ipqh, PC1]]
        ubpqh = data["h"][:, 0] * gen[ipqh, PC1] + \
                data["h"][:, 1] * gen[ipqh, QC1MAX]
        for i in range(npqh):
            tmp = linalg.norm(data["h"][i, :])
            data["h"][i, :] = data["h"][i, :] / tmp
            ubpqh[i] = ubpqh[i] / tmp
        Apqh = sparse((data["h"].flatten('F'),
                       (r_[arange(npqh), arange(npqh)], r_[ipqh, ipqh + ng])),
                      (npqh, 2 * ng))
        ubpqh = ubpqh / baseMVA
    else:
        data["h"] = array([])
        Apqh = zeros((0, 2 * ng))
        ubpqh = array([])

    ## similarly Apql
    if npql > 0:
        data["l"] = c_[gen[ipql, QC2MIN] - gen[ipql, QC1MIN],
                       gen[ipql, PC1] - gen[ipql, PC2]]
        ubpql = data["l"][:, 0] * gen[ipql, PC1] + \
                data["l"][:, 1] * gen[ipql, QC1MIN]
        for i in range(npql):
            tmp = linalg.norm(data["l"][i, :])
            data["l"][i, :] = data["l"][i, :] / tmp
            ubpql[i] = ubpql[i] / tmp
        Apql = sparse((data["l"].flatten('F'),
                       (r_[arange(npql), arange(npql)], r_[ipql, ipql + ng])),
                      (npql, 2 * ng))
        ubpql = ubpql / baseMVA
    else:
        data["l"] = array([])
        Apql = zeros((0, 2 * ng))
        ubpql = array([])

    data["ipql"] = ipql
    data["ipqh"] = ipqh

    return Apqh, ubpqh, Apql, ubpql, data
Example #38
0
def ips(f_fcn,
        x0=None,
        Aeq=None,
        beq=None,
        A=None,
        b=None,
        xmin=None,
        xmax=None,
        gh_fcn=None,
        hess_fcn=None,
        opt=None):
    """Primal-dual interior point method for NLP (nonlinear programming).
    Minimize a function F(X) beginning from a starting point M{x0}, subject to
    optional linear and nonlinear constraints and variable bounds::
            min f(x)
             x
    subject to::
            g(x) = 0            (nonlinear equalities)
            h(x) <= 0           (nonlinear inequalities)
            A*x == beq          (linear constraints, equality)
            A*x <= b            (linear constraints, inequality)
            xmin <= x <= xmax   (variable bounds)
    Ported by Richard Lincoln from the MATLAB Interior Point Solver (MIPS)
    (v1.9) by Ray Zimmerman.  MIPS is distributed as part of the MATPOWER
    project, developed at the Power System Engineering Research Center (PSERC) (PSERC),
    Cornell. See U{http://www.pserc.cornell.edu/matpower/} for more info.
    MIPS was ported by Ray Zimmerman from C code written by H. Wang for his
    PhD dissertation:
      - "On the Computation and Application of Multi-period
        Security-Constrained Optimal Power Flow for Real-time
        Electricity Market Operations", Cornell University, May 2007.
    See also:
      - H. Wang, C. E. Murillo-Sanchez, R. D. Zimmerman, R. J. Thomas,
        "On Computational Issues of Market-Based Optimal Power Flow",
        IEEE Transactions on Power Systems, Vol. 22, No. 3, Aug. 2007,
        pp. 1185-1193.
    All parameters are optional except C{f_fcn} and C{x0}.
    @param f_fcn: Function that evaluates the objective function, its gradients
                  and Hessian for a given value of M{x}. If there are
                  nonlinear constraints, the Hessian information is provided
                  by the 'hess_fcn' argument and is not required here.
    @type f_fcn: callable
    @param x0: Starting value of optimization vector M{x}.
    @type x0: array
    @param Aeq: Optional equality linear constraints.
    @type Aeq: csr_matrix
    @param beq: Optional equality linear constraints.
    @type beq: array
    @param A: Optional linear constraints.
    @type A: csr_matrix
    @param b: Optional linear constraints. Default values are M{Inf}.
    @type b: array
    @param xmin: Optional lower bounds on the M{x} variables, defaults are
                 M{-Inf}.
    @type xmin: array
    @param xmax: Optional upper bounds on the M{x} variables, defaults are
                 M{Inf}.
    @type xmax: array
    @param gh_fcn: Function that evaluates the optional nonlinear constraints
                   and their gradients for a given value of M{x}.
    @type gh_fcn: callable
    @param hess_fcn: Handle to function that computes the Hessian of the
                     Lagrangian for given values of M{x}, M{lambda} and M{mu},
                     where M{lambda} and M{mu} are the multipliers on the
                     equality and inequality constraints, M{g} and M{h},
                     respectively.
    @type hess_fcn: callable
    @param opt: optional options dictionary with the following keys, all of
                which are also optional (default values shown in parentheses)
                  - C{verbose} (False) - Controls level of progress output
                    displayed
                  - C{feastol} (1e-6) - termination tolerance for feasibility
                    condition
                  - C{gradtol} (1e-6) - termination tolerance for gradient
                    condition
                  - C{comptol} (1e-6) - termination tolerance for
                    complementarity condition
                  - C{costtol} (1e-6) - termination tolerance for cost
                    condition
                  - C{max_it} (150) - maximum number of iterations
                  - C{step_control} (False) - set to True to enable step-size
                    control
                  - C{max_red} (20) - maximum number of step-size reductions if
                    step-control is on
                  - C{cost_mult} (1.0) - cost multiplier used to scale the
                    objective function for improved conditioning. Note: This
                    value is also passed as the 3rd argument to the Hessian
                    evaluation function so that it can appropriately scale the
                    objective function term in the Hessian of the Lagrangian.
    @type opt: dict
    @rtype: dict
    @return: The solution dictionary has the following keys:
               - C{x} - solution vector
               - C{f} - final objective function value
               - C{converged} - exit status
                   - True = first order optimality conditions satisfied
                   - False = maximum number of iterations reached
                   - None = numerically failed
               - C{output} - output dictionary with keys:
                   - C{iterations} - number of iterations performed
                   - C{hist} - list of arrays with trajectories of the
                     following: feascond, gradcond, compcond, costcond, gamma,
                     stepsize, obj, alphap, alphad
                   - C{message} - exit message
               - C{lmbda} - dictionary containing the Langrange and Kuhn-Tucker
                 multipliers on the constraints, with keys:
                   - C{eqnonlin} - nonlinear equality constraints
                   - C{ineqnonlin} - nonlinear inequality constraints
                   - C{mu} -  linear equal constraints
                   - C{lower} - lower bound on optimization variables
                   - C{upper} - upper bound on optimization variables
    """
    if isinstance(f_fcn, dict):  ## problem dict, the input can also be dict
        p = f_fcn
        f_fcn = p['f_fcn']
        x0 = p['x0']
        if 'opt' in p: opt = p['opt']
        if 'hess_fcn' in p: hess_fcn = p['hess_fcn']
        if 'gh_fcn' in p: gh_fcn = p['gh_fcn']
        if 'xmax' in p: xmax = p['xmax']
        if 'xmin' in p: xmin = p['xmin']
        if 'Aeq' in p: Aeq = p['Aeq']
        if 'beq' in p: beq = p['beq']
        if 'A' in p: Aeq = p['A']
        if 'b' in p: beq = p['b']

    nx = x0.shape[0]  # number of variables
    neq = Aeq.shape[
        0] if Aeq is not None else 0  # number of equal linear constraints
    nineq = A.shape[
        0] if A is not None else 0  # number of inequal linear constraints

    # default argument values
    if beq is None or len(beq) == 0: beq = -Inf * ones(neq)
    if b is None or len(b) == 0: b = Inf * ones(nineq)
    if xmin is None or len(xmin) == 0: xmin = -Inf * ones(x0.shape[0])
    if xmax is None or len(xmax) == 0: xmax = Inf * ones(x0.shape[0])
    if gh_fcn is None:
        nonlinear = False
        gn = array([])
        hn = array([])
    else:
        nonlinear = True

    if opt is None: opt = {}
    # options
    if "feastol" not in opt:
        opt["feastol"] = 1e-06
    if "gradtol" not in opt:
        opt["gradtol"] = 1e-06
    if "comptol" not in opt:
        opt["comptol"] = 1e-06
    if "costtol" not in opt:
        opt["costtol"] = 1e-06
    if "max_it" not in opt:
        opt["max_it"] = 150
    if "max_red" not in opt:
        opt["max_red"] = 20
    if "step_control" not in opt:
        opt["step_control"] = False
    if "cost_mult" not in opt:
        opt["cost_mult"] = 1
    if "verbose" not in opt:
        opt["verbose"] = 2

    # initialize history
    hist = []

    # constants
    xi = 0.99995
    sigma = 0.1
    z0 = 1
    alpha_min = 1e-8
    rho_min = 0.95
    rho_max = 1.05
    mu_threshold = 1e-5

    # initialize
    i = 0  # iteration counter
    converged = False  # flag
    eflag = False  # exit flag
    # add var limits to linear constraints
    eyex = eye(nx, nx, format="csr")

    AA = vstack([-eyex, eyex], "csr") if A is None else vstack(
        [-eyex, eyex, A], "csr")
    bb = r_[-xmin, xmax, b]
    ib = find(
        bb <=
        1e10)  # Bounded constrain, does not need to take into consideration
    if len(ib):
        idxs = [(1, ib)]
        Ai = vstack([sig * AA[idx, :] for sig, idx in idxs if len(idx)], 'csr')
    else:
        Ai = None
    bi = bb[ib]

    # Parameters input for the linear constraints
    Ae = Aeq
    be = beq
    # evaluate cost f(x0) and constraints g(x0), h(x0)
    x = x0
    f, df = f_fcn(x)  # cost
    f = f * opt["cost_mult"]
    df = df * opt["cost_mult"]
    if nonlinear:
        hn, gn, dhn, dgn = gh_fcn(x)  # nonlinear constraints
        h = hn if Ai is None else r_[hn, Ai * x - bi]  # inequality constraints
        g = gn if Ae is None else r_[gn, Ae * x - be]  # equality constraints

        if (dhn is None) and (Ai is None):
            dh = None
        elif dhn is None:
            dh = Ai.T
        elif Ai is None:
            dh = dhn
        else:
            dh = hstack([dhn, Ai.T])

        if (dgn is None) and (Ae is None):
            dg = None
        elif dgn is None:
            dg = Ae.T
        elif Ae is None:
            dg = dgn
        else:
            dg = hstack([dgn, Ae.T])
    else:
        h = -bi if Ai is None else Ai * x - bi  # inequality constraints
        g = -be if Ae is None else Ae * x - be  # equality constraints
        dh = None if Ai is None else Ai.T  # 1st derivative of inequalities
        dg = None if Ae is None else Ae.T  # 1st derivative of equalities

    # some dimensions
    neq = g.shape[0]  # number of equality constraints
    niq = h.shape[0]  # number of inequality constraints
    neqnln = gn.shape[0]  # number of nonlinear equality constraints
    niqnln = hn.shape[0]  # number of nonlinear inequality constraints

    # initialize gamma, lam, mu, z, e
    gamma = 1  # barrier coefficient
    lam = zeros(neq)
    z = z0 * ones(niq)
    mu = z0 * ones(niq)
    k = find(h < -z0)
    z[k] = -h[k]
    k = find((gamma / z) > z0)
    mu[k] = gamma / z[k]
    e = ones(niq)

    # check tolerance
    f0 = f
    if opt["step_control"]:
        L = f + dot(lam, g) + dot(mu, h + z) - gamma * sum(log(z))

    Lx = df.copy()
    Lx = Lx + dg * lam if dg is not None else Lx
    Lx = Lx + dh * mu if dh is not None else Lx

    maxh = zeros(1) if len(h) == 0 else max(h)

    gnorm = norm(g, Inf) if len(g) else 0.0
    lam_norm = norm(lam, Inf) if len(lam) else 0.0
    mu_norm = norm(mu, Inf) if len(mu) else 0.0
    znorm = norm(z, Inf) if len(z) else 0.0
    feascond = \
        max([gnorm, maxh]) / (1 + max([norm(x, Inf), znorm]))
    gradcond = \
        norm(Lx, Inf) / (1 + max([lam_norm, mu_norm]))
    compcond = dot(z, mu) / (1 + norm(x, Inf))
    costcond = absolute(f - f0) / (1 + absolute(f0))

    # save history
    hist.append({
        'feascond': feascond,
        'gradcond': gradcond,
        'compcond': compcond,
        'costcond': costcond,
        'gamma': gamma,
        'stepsize': 0,
        'obj': f / opt["cost_mult"],
        'alphap': 0,
        'alphad': 0
    })

    if opt["verbose"]:
        s = '-sc' if opt["step_control"] else ''
        if opt['verbose'] > 1:
            print(" it    objective   step size   feascond     gradcond     "
                  "compcond     costcond  ")
            print("----  ------------ --------- ------------ ------------ "
                  "------------ ------------")
            print("%3d  %12.8g %10s %12g %12g %12g %12g" %
                  (i, (f / opt["cost_mult"]), "", feascond, gradcond, compcond,
                   costcond))

    if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
                    compcond < opt["comptol"] and costcond < opt["costtol"]:
        converged = True
        if opt["verbose"]:
            print("Converged!")

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

        # compute update step
        lmbda = {
            "eqnonlin": lam[range(neqnln)],
            "ineqnonlin": mu[range(niqnln)]
        }
        if nonlinear:
            if hess_fcn is None:
                print("pips: Hessian evaluation via finite differences "
                      "not yet implemented.\nPlease provide "
                      "your own hessian evaluation function.")
            Lxx = hess_fcn(x, lmbda, opt["cost_mult"])
        else:
            _, _, d2f = f_fcn(x, True)  # cost
            Lxx = d2f * opt["cost_mult"]
        rz = range(len(z))
        zinvdiag = sparse((1.0 / z, (rz, rz))) if len(z) else None
        rmu = range(len(mu))
        mudiag = sparse((mu, (rmu, rmu))) if len(mu) else None
        dh_zinv = None if dh is None else dh * zinvdiag
        M = Lxx if dh is None else Lxx + dh_zinv * mudiag * dh.T
        N = Lx if dh is None else Lx + dh_zinv * (mudiag * h + gamma * e)

        Ab = sparse(M) if dg is None else vstack(
            [hstack([M, dg]),
             hstack([dg.T, sparse((neq, neq))])])
        bb = r_[-N, -g]

        dxdlam = spsolve(Ab.tocsr(), bb)

        if any(isnan(dxdlam)):
            if opt["verbose"]:
                print('\nNumerically Failed\n')
            eflag = -1
            break

        dx = dxdlam[:nx]
        dlam = dxdlam[nx:nx + neq]
        dz = -h - z if dh is None else -h - z - dh.T * dx
        dmu = -mu if dh is None else -mu + zinvdiag * (gamma * e - mudiag * dz)

        # optional step-size control
        sc = False
        if opt["step_control"]:
            x1 = x + dx

            # evaluate cost, constraints, derivatives at x1
            f1, df1 = f_fcn(x1)  # cost
            f1 = f1 * opt["cost_mult"]
            df1 = df1 * opt["cost_mult"]
            if nonlinear:
                hn1, gn1, dhn1, dgn1 = gh_fcn(x1)  # nonlinear constraints

                h1 = hn1 if Ai is None else r_[hn1,
                                               Ai * x1 - bi]  # ieq constraints
                g1 = gn1 if Ae is None else r_[gn1,
                                               Ae * x1 - be]  # eq constraints

                # 1st der of ieq
                if (dhn1 is None) and (Ai is None):
                    dh1 = None
                elif dhn1 is None:
                    dh1 = Ai.T
                elif Ai is None:
                    dh1 = dhn1
                else:
                    dh1 = hstack([dhn1, Ai.T])

                # 1st der of eqs
                if (dgn1 is None) and (Ae is None):
                    dg1 = None
                elif dgn is None:
                    dg1 = Ae.T
                elif Ae is None:
                    dg1 = dgn1
                else:
                    dg1 = hstack([dgn1, Ae.T])
            else:
                h1 = -bi if Ai is None else Ai * x1 - bi  # inequality constraints
                g1 = -be if Ae is None else Ae * x1 - be  # equality constraints

                dh1 = dh  ## 1st derivative of inequalities
                dg1 = dg  ## 1st derivative of equalities

            # check tolerance
            Lx1 = df1
            Lx1 = Lx1 + dg1 * lam if dg1 is not None else Lx1
            Lx1 = Lx1 + dh1 * mu if dh1 is not None else Lx1

            maxh1 = zeros(1) if len(h1) == 0 else max(h1)

            g1norm = norm(g1, Inf) if len(g1) else 0.0
            lam1_norm = norm(lam, Inf) if len(lam) else 0.0
            mu1_norm = norm(mu, Inf) if len(mu) else 0.0
            z1norm = norm(z, Inf) if len(z) else 0.0

            feascond1 = max([g1norm, maxh1]) / \
                        (1 + max([norm(x1, Inf), z1norm]))
            gradcond1 = norm(Lx1, Inf) / (1 + max([lam1_norm, mu1_norm]))

            if (feascond1 > feascond) and (gradcond1 > gradcond):
                sc = True
        if sc:
            alpha = 1.0
            for j in range(opt["max_red"]):
                dx1 = alpha * dx
                x1 = x + dx1
                f1, _ = f_fcn(x1)  # cost
                f1 = f1 * opt["cost_mult"]
                if nonlinear:
                    hn1, gn1, _, _ = gh_fcn(x1)  # nonlinear constraints
                    h1 = hn1 if Ai is None else r_[
                        hn1, Ai * x1 - bi]  # inequality constraints
                    g1 = gn1 if Ae is None else r_[gn1, Ae * x1 -
                                                   be]  # equality constraints
                else:
                    h1 = -bi if Ai is None else Ai * x1 - bi  # inequality constraints
                    g1 = -be if Ae is None else Ae * x1 - be  # equality constraints

                L1 = f1 + dot(lam, g1) + dot(mu, h1 + z) - gamma * sum(log(z))

                if opt["verbose"] > 2:
                    print("   %3d            %10.5f" % (-j, norm(dx1)))

                rho = (L1 - L) / (dot(Lx, dx1) + 0.5 * dot(dx1, Lxx * dx1))

                if (rho > rho_min) and (rho < rho_max):
                    break
                else:
                    alpha = alpha / 2.0
            dx = alpha * dx
            dz = alpha * dz
            dlam = alpha * dlam
            dmu = alpha * dmu

        # do the update
        k = find(dz < 0.0)
        alphap = min([xi * min(z[k] / -dz[k]), 1]) if len(k) else 1.0
        k = find(dmu < 0.0)
        alphad = min([xi * min(mu[k] / -dmu[k]), 1]) if len(k) else 1.0
        x = x + alphap * dx
        z = z + alphap * dz
        lam = lam + alphad * dlam
        mu = mu + alphad * dmu
        if niq > 0:
            gamma = sigma * dot(z, mu) / niq

        # evaluate cost, constraints, derivatives
        f, df = f_fcn(x)  # cost
        f = f * opt["cost_mult"]
        df = df * opt["cost_mult"]
        if nonlinear:
            hn, gn, dhn, dgn = gh_fcn(x)  # nln constraints
            #            g = gn if Ai is None else r_[gn, Ai * x - bi] # ieq constraints
            #            h = hn if Ae is None else r_[hn, Ae * x - be] # eq constraints
            h = hn if Ai is None else r_[hn, Ai * x - bi]  # ieq constr
            g = gn if Ae is None else r_[gn, Ae * x - be]  # eq constr

            if (dhn is None) and (Ai is None):
                dh = None
            elif dhn is None:
                dh = Ai.T
            elif Ai is None:
                dh = dhn
            else:
                dh = hstack([dhn, Ai.T])

            if (dgn is None) and (Ae is None):
                dg = None
            elif dgn is None:
                dg = Ae.T
            elif Ae is None:
                dg = dgn
            else:
                dg = hstack([dgn, Ae.T])
        else:
            h = -bi if Ai is None else Ai * x - bi  # inequality constraints
            g = -be if Ae is None else Ae * x - be  # equality constraints
            # 1st derivatives are constant, still dh = Ai.T, dg = Ae.T

        Lx = df
        Lx = Lx + dg * lam if dg is not None else Lx
        Lx = Lx + dh * mu if dh is not None else Lx

        if len(h) == 0:
            maxh = zeros(1)
        else:
            maxh = max(h)

        gnorm = norm(g, Inf) if len(g) else 0.0
        lam_norm = norm(lam, Inf) if len(lam) else 0.0
        mu_norm = norm(mu, Inf) if len(mu) else 0.0
        znorm = norm(z, Inf) if len(z) else 0.0
        feascond = \
            max([gnorm, maxh]) / (1 + max([norm(x, Inf), znorm]))
        gradcond = \
            norm(Lx, Inf) / (1 + max([lam_norm, mu_norm]))
        compcond = dot(z, mu) / (1 + norm(x, Inf))
        costcond = float(absolute(f - f0) / (1 + absolute(f0)))

        hist.append({
            'feascond': feascond,
            'gradcond': gradcond,
            'compcond': compcond,
            'costcond': costcond,
            'gamma': gamma,
            'stepsize': norm(dx),
            'obj': f / opt["cost_mult"],
            'alphap': alphap,
            'alphad': alphad
        })

        if opt["verbose"] > 1:
            print("%3d  %12.8g %10.5g %12g %12g %12g %12g" %
                  (i, (f / opt["cost_mult"]), norm(dx), feascond, gradcond,
                   compcond, costcond))

        if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
                        compcond < opt["comptol"] and costcond < opt["costtol"]:
            converged = True
            if opt["verbose"]:
                print("Converged!")
        else:
            if any(isnan(x)) or (alphap < alpha_min) or \
                    (alphad < alpha_min) or (gamma < EPS) or (gamma > 1.0 / EPS):
                if opt["verbose"]:
                    print("Numerically failed.")
                eflag = -1
                break
            f0 = f

            if opt["step_control"]:
                L = f + dot(lam, g) + dot(mu, (h + z)) - gamma * sum(log(z))

    if opt["verbose"]:
        if not converged:
            print("Did not converge in %d iterations." % i)

    # package results
    if eflag != -1:
        eflag = converged

    if eflag == 0:
        message = 'Did not converge'
    elif eflag == 1:
        message = 'Converged'
    elif eflag == -1:
        message = 'Numerically failed'
    else:
        raise ("Type error")

    output = {"iterations": i, "hist": hist, "message": message}

    # zero out multipliers on non-binding constraints
    mu[find((h < -opt["feastol"]) & (mu < mu_threshold))] = 0.0

    # un-scale cost and prices
    f = f / opt["cost_mult"]
    lam = lam / opt["cost_mult"]
    mu = mu / opt["cost_mult"]

    # re-package multipliers into struct
    lam_lin = lam[neqnln:neq]  # lambda for equal linear constraints
    mu_lin = mu[niqnln:niq]  # mu for inequal linear constraints

    lmbda = {
        'lam': lam_lin,
        'mu': mu_lin[nx + nx:nx + nx + nineq],
        'lower': mu_lin[:nx],
        'upper': mu_lin[nx:nx + nx]
    }

    if niqnln > 0:
        lmbda['ineqnonlin'] = mu[:niqnln]
    if neqnln > 0:
        lmbda['eqnonlin'] = lam[:neqnln]

    # lmbda = {"eqnonlin": lam[:neqnln], 'ineqnonlin': mu[:niqnln],
    #             "mu_l": mu_l[nx:], "mu_u": mu_u[nx:],
    #             "lower": mu_l[:nx], "upper": mu_u[:nx]}

    solution = {
        "x": x,
        "f": f,
        "eflag": converged,
        "output": output,
        "lmbda": lmbda
    }

    return solution
Example #39
0
def t_makePTDF(quiet=False):
    """Tests for C{makePTDF}.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ntests = 24
    t_begin(ntests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_opf')
    verbose = 0  #not quiet

    ## load case
    ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0)
    r = rundcopf(casefile, ppopt)
    baseMVA, bus, gen, branch = r['baseMVA'], r['bus'], r['gen'], r['branch']
    _, bus, gen, branch = ext2int1(bus, gen, branch)
    nb = bus.shape[0]
    nbr = branch.shape[0]
    ng = gen.shape[0]

    ## compute injections and flows
    Cg = sparse((ones(ng), (gen[:, GEN_BUS], arange(ng))), (nb, ng))
    Pg = Cg * gen[:, PG]
    Pd = bus[:, PD]
    P = Pg - Pd
    ig = find(P > 0)
    il = find(P <= 0)
    F = branch[:, PF]

    ## create corresponding slack distribution matrices
    e1 = zeros((nb, 1))
    e1[0] = 1
    e4 = zeros((nb, 1))
    e4[3] = 1
    D1 = eye(nb, nb) - dot(e1, ones((1, nb)))
    D4 = eye(nb, nb) - dot(e4, ones((1, nb)))
    Deq = eye(nb, nb) - ones((nb, 1)) / nb * ones((1, nb))
    Dg = eye(nb) - matrix(Pd / sum(Pd)).T * ones(nb)
    Dd = eye(nb) - matrix(Pg / sum(Pg)).T * ones(nb)

    ## create some PTDF matrices
    H1 = makePTDF(baseMVA, bus, branch, 0)
    H4 = makePTDF(baseMVA, bus, branch, 3)
    Heq = makePTDF(baseMVA, bus, branch, ones(nb))
    Hg = makePTDF(baseMVA, bus, branch, Pd)
    Hd = makePTDF(baseMVA, bus, branch, Pg)

    ## matrices get properly transformed by slack dist matrices
    t_is(H1, dot(H1, D1), 8, 'H1  == H1 * D1')
    t_is(H4, dot(H1, D4), 8, 'H4  == H1 * D4')
    t_is(Heq, dot(H1, Deq), 8, 'Heq == H1 * Deq')
    t_is(Hg, dot(H1, Dg), 8, 'Hg  == H1 * Dg')
    t_is(Hd, dot(H1, Dd), 8, 'Hd  == H1 * Dd')
    t_is(H1, dot(Heq, D1), 8, 'H1  == Heq * D1')
    t_is(H4, dot(Heq, D4), 8, 'H4  == Heq * D4')
    t_is(Heq, dot(Heq, Deq), 8, 'Heq == Heq * Deq')
    t_is(Hg, dot(Heq, Dg), 8, 'Hg  == Heq * Dg')
    t_is(Hd, dot(Heq, Dd), 8, 'Hd  == Heq * Dd')
    t_is(H1, dot(Hg, D1), 8, 'H1  == Hg * D1')
    t_is(H4, dot(Hg, D4), 8, 'H4  == Hg * D4')
    t_is(Heq, dot(Hg, Deq), 8, 'Heq == Hg * Deq')
    t_is(Hg, dot(Hg, Dg), 8, 'Hg  == Hg * Dg')
    t_is(Hd, dot(Hg, Dd), 8, 'Hd  == Hg * Dd')

    ## PTDFs can reconstruct flows
    t_is(F, dot(H1, P), 3, 'Flow == H1  * P')
    t_is(F, dot(H4, P), 3, 'Flow == H4  * P')
    t_is(F, dot(Heq, P), 3, 'Flow == Heq * P')
    t_is(F, dot(Hg, P), 3, 'Flow == Hg  * P')
    t_is(F, dot(Hd, P), 3, 'Flow == Hd  * P')

    ## other
    t_is(F, dot(Hg, Pg), 3, 'Flow == Hg  * Pg')
    t_is(F, dot(Hd, (-Pd)), 3, 'Flow == Hd  * (-Pd)')
    t_is(zeros(nbr), dot(Hg, (-Pd)), 3, 'zeros == Hg  * (-Pd)')
    t_is(zeros(nbr), dot(Hd, Pg), 3, 'zeros == Hd  * Pg')

    t_end()
Example #40
0
def t_opf_dc_pips(quiet=False):
    """Tests for DC optimal power flow using PIPS solver.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    num_tests = 23

    t_begin(num_tests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_opf')
    verbose = 0  #not quiet

    t0 = 'DC OPF (PIPS): '
    ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0, OPF_ALG_DC=200)

    ## run DC OPF

    ## set up indices
    ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)]
    ib_voltage = arange(VM, VA + 1)
    ib_lam = arange(LAM_P, LAM_Q + 1)
    ib_mu = arange(MU_VMAX, MU_VMIN + 1)
    ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)]
    ig_disp = array([PG, QG, VG])
    ig_mu = arange(MU_PMAX, MU_QMIN + 1)
    ibr_data = arange(ANGMAX + 1)
    ibr_flow = arange(PF, QT + 1)
    ibr_mu = array([MU_SF, MU_ST])
    #ibr_angmu   = array([MU_ANGMIN, MU_ANGMAX])

    ## get solved DC power flow case from MAT-file
    soln9_dcopf = loadmat(join(tdir, 'soln9_dcopf.mat'), struct_as_record=True)
    ## defines bus_soln, gen_soln, branch_soln, f_soln
    bus_soln = soln9_dcopf['bus_soln']
    gen_soln = soln9_dcopf['gen_soln']
    branch_soln = soln9_dcopf['branch_soln']
    f_soln = soln9_dcopf['f_soln'][0]

    ## run OPF
    t = t0
    r = rundcopf(casefile, ppopt)
    bus, gen, branch, f, success = \
            r['bus'], r['gen'], r['branch'], r['f'], r['success']
    t_ok(success, [t, 'success'])
    t_is(f, f_soln, 3, [t, 'f'])
    t_is(bus[:, ib_data], bus_soln[:, ib_data], 10, [t, 'bus data'])
    t_is(bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage'])
    t_is(bus[:, ib_lam], bus_soln[:, ib_lam], 3, [t, 'bus lambda'])
    t_is(bus[:, ib_mu], bus_soln[:, ib_mu], 2, [t, 'bus mu'])
    t_is(gen[:, ig_data], gen_soln[:, ig_data], 10, [t, 'gen data'])
    t_is(gen[:, ig_disp], gen_soln[:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(gen[:, ig_mu], gen_soln[:, ig_mu], 3, [t, 'gen mu'])
    t_is(branch[:, ibr_data], branch_soln[:, ibr_data], 10, [t, 'branch data'])
    t_is(branch[:, ibr_flow], branch_soln[:, ibr_flow], 3, [t, 'branch flow'])
    t_is(branch[:, ibr_mu], branch_soln[:, ibr_mu], 2, [t, 'branch mu'])

    ##-----  run OPF with extra linear user constraints & costs  -----
    ## two new z variables
    ##      0 <= z1, P2 - P1 <= z1
    ##      0 <= z2, P2 - P3 <= z2
    ## with A and N sized for DC opf
    ppc = loadcase(casefile)
    row = [0, 0, 0, 1, 1, 1]
    col = [9, 10, 12, 10, 11, 13]
    ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 14))
    ppc['u'] = array([0, 0])
    ppc['l'] = array([-Inf, -Inf])
    ppc['zl'] = array([0, 0])

    ppc['N'] = sparse(([1, 1], ([0, 1], [12, 13])),
                      (2, 14))  ## new z variables only
    ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]])  ## w = r = z
    ppc['H'] = sparse((2, 2))  ## no quadratic term
    ppc['Cw'] = array([1000, 1])

    t = ''.join([t0, 'w/extra constraints & costs 1 : '])
    r = rundcopf(ppc, ppopt)
    t_ok(r['success'], [t, 'success'])
    t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974'])
    t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974'])
    t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars'])
    t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs'])

    ## with A and N sized for AC opf
    ppc = loadcase(casefile)
    row = [0, 0, 0, 1, 1, 1]
    col = [18, 19, 24, 19, 20, 25]
    ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 26))
    ppc['u'] = array([0, 0])
    ppc['l'] = array([-Inf, -Inf])
    ppc['zl'] = array([0, 0])

    ppc['N'] = sparse(([1, 1], ([0, 1], [24, 25])),
                      (2, 26))  ## new z variables only
    ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]])  ## w = r = z
    ppc['H'] = sparse((2, 2))  ## no quadratic term
    ppc['Cw'] = array([1000, 1])

    t = ''.join([t0, 'w/extra constraints & costs 2 : '])
    r = rundcopf(ppc, ppopt)
    t_ok(r['success'], [t, 'success'])
    t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974'])
    t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974'])
    t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars'])
    t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs'])

    t = ''.join([t0, 'infeasible : '])
    ## with A and N sized for DC opf
    ppc = loadcase(casefile)
    ppc['A'] = sparse(([1, 1], ([0, 0], [9, 10])), (1, 14))  ## Pg1 + Pg2
    ppc['u'] = array([Inf])
    ppc['l'] = array([600])
    r = rundcopf(ppc, ppopt)
    t_ok(not r['success'], [t, 'no success'])

    t_end()
Example #41
0
def dcopf_solver(om, ppopt, out_opt=None):
    """Solves a DC optimal power flow.

    Inputs are an OPF model object, a PYPOWER options dict and
    a dict containing fields (can be empty) for each of the desired
    optional output fields.

    Outputs are a C{results} dict, C{success} flag and C{raw} output dict.

    C{results} is a PYPOWER case dict (ppc) with the usual baseMVA, bus
    branch, gen, gencost fields, along with the following additional
    fields:
        - C{order}      see 'help ext2int' for details of this field
        - C{x}          final value of optimization variables (internal order)
        - C{f}          final objective function value
        - C{mu}         shadow prices on ...
            - C{var}
                - C{l}  lower bounds on variables
                - C{u}  upper bounds on variables
            - C{lin}
                - C{l}  lower bounds on linear constraints
                - C{u}  upper bounds on linear constraints
        - C{g}          (optional) constraint values
        - C{dg}         (optional) constraint 1st derivatives
        - C{df}         (optional) obj fun 1st derivatives (not yet implemented)
        - C{d2f}        (optional) obj fun 2nd derivatives (not yet implemented)

    C{success} is C{True} if solver converged successfully, C{False} otherwise.

    C{raw} is a raw output dict in form returned by MINOS
        - C{xr}     final value of optimization variables
        - C{pimul}  constraint multipliers
        - C{info}   solver specific termination code
        - C{output} solver specific output information

    @see: L{opf}, L{qps_pypower}

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    @author: Richard Lincoln
    """
    if out_opt is None:
        out_opt = {}

    ## options
    verbose = ppopt['VERBOSE']
    alg     = ppopt['OPF_ALG_DC']

    if alg == 0:
        if have_fcn('cplex'):        ## use CPLEX by default, if available
            alg = 500
        # MOSEK is currently not supported
#        elif have_fcn('mosek'):      ## if not, then MOSEK, if available
#            alg = 600
        elif have_fcn('gurobi'):     ## if not, then Gurobi, if available
            # Error in Gurobi pypower solver -> Issue with pypower 5.1.4. Gurobi won't work. Using alg 200 instead
            # Reason for failure: In qps_gurobi of pypower len(H) raises Error:
            # TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]
            # Todo: Fix Gurobi and activate 700 again. ATM: Fallback on 200
            # alg = 700
            alg = 200
            UserWarning("Gurobi not working with pypower 5.1.4")
        else:                        ## otherwise PIPS
            alg = 200

    ## 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, H, Cw = cp["N"], cp["H"], cp["Cw"]
    fparm = array(c_[cp["dd"], cp["rh"], cp["kk"], cp["mm"]])
    Bf = om.userdata('Bf')
    Pfinj = om.userdata('Pfinj')
    vv, ll, _, _ = om.get_idx()

    ## problem dimensions
    ipol = find(gencost[:, MODEL] == POLYNOMIAL) ## polynomial costs
    ipwl = find(gencost[:, MODEL] == PW_LINEAR)  ## piece-wise linear costs
    nb = bus.shape[0]              ## number of buses
    nl = branch.shape[0]           ## number of branches
    nw = N.shape[0]                ## number of general cost vars, w
    ny = om.getN('var', 'y')       ## number of piece-wise linear costs
    nxyz = om.getN('var')          ## total number of control vars of all types

    ## linear constraints & variable bounds
    A, l, u = om.linear_constraints()
    x0, xmin, xmax = om.getv()

    ## set up objective function of the form: f = 1/2 * X'*HH*X + CC'*X
    ## where X = [x;y;z]. First set up as quadratic function of w,
    ## f = 1/2 * w'*HHw*w + CCw'*w, where w = diag(M) * (N*X - Rhat). We
    ## will be building on the (optionally present) user supplied parameters.

    ## piece-wise linear costs
    any_pwl = int(ny > 0)
    if any_pwl:
        # Sum of y vars.
        Npwl = sparse((ones(ny), (zeros(ny), arange(vv["i1"]["y"], vv["iN"]["y"]))), (1, nxyz))
        Hpwl = sparse((1, 1))
        Cpwl = array([1])
        fparm_pwl = array([[1, 0, 0, 1]])
    else:
        Npwl = None#zeros((0, nxyz))
        Hpwl = None#array([])
        Cpwl = array([])
        fparm_pwl = zeros((0, 4))

    ## quadratic costs
    npol = len(ipol)
    if any(len(gencost[ipol, NCOST] > 3)) and sum(gencost[find(gencost[ipol, NCOST] > 3)][:][NCOST+1:]):
        stderr.write('DC opf cannot handle polynomial costs with higher '
                     'than quadratic order.\n')
    iqdr = find(gencost[ipol, NCOST] == 3)
    ilin = find(gencost[ipol, NCOST] == 2)
    polycf = zeros((npol, 3))         ## quadratic coeffs for Pg
    if len(iqdr) > 0:
        polycf[iqdr, :] = gencost[ipol[iqdr], COST:COST + 3]
    if npol:
        polycf[ilin, 1:3] = gencost[ipol[ilin], COST:COST + 2]
    polycf = dot(polycf, diag([ baseMVA**2, baseMVA, 1]))     ## convert to p.u.
    if npol:
        Npol = sparse((ones(npol), (arange(npol), vv["i1"]["Pg"] + ipol)),
                      (npol, nxyz))  # Pg vars
        Hpol = sparse((2 * polycf[:, 0], (arange(npol), arange(npol))),
                      (npol, npol))
    else:
        Npol = None
        Hpol = None
    Cpol = polycf[:, 1]
    fparm_pol = ones((npol, 1)) * array([[1, 0, 0, 1]])

    ## combine with user costs
    NN = vstack([n for n in [Npwl, Npol, N] if n is not None and n.shape[0] > 0], "csr")
    # FIXME: Zero dimension sparse matrices.
    if (Hpwl is not None) and any_pwl and (npol + nw):
        Hpwl = hstack([Hpwl, sparse((any_pwl, npol + nw))])
    if Hpol is not None:
        if any_pwl and npol:
            Hpol = hstack([sparse((npol, any_pwl)), Hpol])
        if npol and nw:
            Hpol = hstack([Hpol, sparse((npol, nw))])
    if (H is not None) and nw and (any_pwl + npol):
        H = hstack([sparse((nw, any_pwl + npol)), H])
    HHw = vstack([h for h in [Hpwl, Hpol, H] if h is not None and h.shape[0] > 0], "csr")
    CCw = r_[Cpwl, Cpol, Cw]
    ffparm = r_[fparm_pwl, fparm_pol, fparm]

    ## transform quadratic coefficients for w into coefficients for X
    nnw = any_pwl + npol + nw
    M = sparse((ffparm[:, 3], (range(nnw), range(nnw))))
    MR = M * ffparm[:, 1]
    HMR = HHw * MR
    MN = M * NN
    HH = MN.T * HHw * MN
    CC = MN.T * (CCw - HMR)
    C0 = 0.5 * dot(MR, HMR) + sum(polycf[:, 2])  # Constant term of cost.

    ## set up input for QP solver
    opt = {'alg': alg, 'verbose': verbose}
    if (alg == 200) or (alg == 250):
        ## try to select an interior initial point
        Varefs = bus[bus[:, BUS_TYPE] == REF, VA] * (pi / 180.0)

        lb, ub = xmin.copy(), xmax.copy()
        lb[xmin == -Inf] = -1e10   ## replace Inf with numerical proxies
        ub[xmax ==  Inf] =  1e10
        x0 = (lb + ub) / 2;
        # angles set to first reference angle
        x0[vv["i1"]["Va"]:vv["iN"]["Va"]] = Varefs[0]
        if ny > 0:
            ipwl = find(gencost[:, MODEL] == PW_LINEAR)
            # largest y-value in CCV data
            c = gencost.flatten('F')[sub2ind(gencost.shape, ipwl,
                                NCOST + 2 * gencost[ipwl, NCOST])]
            x0[vv["i1"]["y"]:vv["iN"]["y"]] = max(c) + 0.1 * abs(max(c))

        ## set up options
        feastol = ppopt['PDIPM_FEASTOL']
        gradtol = ppopt['PDIPM_GRADTOL']
        comptol = ppopt['PDIPM_COMPTOL']
        costtol = ppopt['PDIPM_COSTTOL']
        max_it  = ppopt['PDIPM_MAX_IT']
        max_red = ppopt['SCPDIPM_RED_IT']
        if feastol == 0:
            feastol = ppopt['OPF_VIOLATION']    ## = OPF_VIOLATION by default
        opt["pips_opt"] = {  'feastol': feastol,
                             'gradtol': gradtol,
                             'comptol': comptol,
                             'costtol': costtol,
                             'max_it':  max_it,
                             'max_red': max_red,
                             'cost_mult': 1  }
#    elif alg == 400:
#        opt['ipopt_opt'] = ipopt_options([], ppopt)
#    elif alg == 500:
#        opt['cplex_opt'] = cplex_options([], ppopt)
#    elif alg == 600:
#        opt['mosek_opt'] = mosek_options([], ppopt)
#    elif alg == 700:
#        ppopt['GRB_OPT'] = 0
#        ppopt['GRB_METHOD'] = "automatic"
#        ppopt['GRB_TIMELIMIT'] = Inf
#        ppopt['GRB_THREADS'] = 0
#        opt['GRB_OPT'] = gurobi_options(None, ppopt)
#    else:
#        raise ValueError("Unrecognised solver [%d]." % alg)

    ##-----  run opf  -----
    x, f, info, output, lmbda = \
            qps_pypower(HH, CC, A, l, u, xmin, xmax, x0, opt)
    success = (info == 1)

    ##-----  calculate return values  -----
    if not any(isnan(x)):
        ## update solution data
        Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
        Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]]
        f = f + C0

        ## update voltages & generator outputs
        bus[:, VA] = Va * 180 / pi
        gen[:, PG] = Pg * baseMVA

        ## compute branch flows
        branch[:, [QF, QT]] = zeros((nl, 2))
        branch[:, PF] = (Bf * Va + Pfinj) * baseMVA
        branch[:, PT] = -branch[:, PF]

    ## package up results
    mu_l = lmbda["mu_l"]
    mu_u = lmbda["mu_u"]
    muLB = lmbda["lower"]
    muUB = lmbda["upper"]

    ## update Lagrange multipliers
    il = find((branch[:, RATE_A] != 0) & (branch[:, RATE_A] < 1e10))
    bus[:, [LAM_P, LAM_Q, MU_VMIN, MU_VMAX]] = zeros((nb, 4))
    gen[:, [MU_PMIN, MU_PMAX, MU_QMIN, MU_QMAX]] = zeros((gen.shape[0], 4))
    branch[:, [MU_SF, MU_ST]] = zeros((nl, 2))
    bus[:, LAM_P]       = (mu_u[ll["i1"]["Pmis"]:ll["iN"]["Pmis"]] -
                           mu_l[ll["i1"]["Pmis"]:ll["iN"]["Pmis"]]) / baseMVA
    branch[il, MU_SF]   = mu_u[ll["i1"]["Pf"]:ll["iN"]["Pf"]] / baseMVA
    branch[il, MU_ST]   = mu_u[ll["i1"]["Pt"]:ll["iN"]["Pt"]] / baseMVA
    gen[:, MU_PMIN]     = muLB[vv["i1"]["Pg"]:vv["iN"]["Pg"]] / baseMVA
    gen[:, MU_PMAX]     = muUB[vv["i1"]["Pg"]:vv["iN"]["Pg"]] / baseMVA

    pimul = r_[
      mu_l - mu_u,
     -ones((ny)), ## dummy entry corresponding to linear cost row in A
      muLB - muUB
    ]

    mu = { 'var': {'l': muLB, 'u': muUB},
           'lin': {'l': mu_l, 'u': mu_u} }

    results = deepcopy(ppc)
    results["bus"], results["branch"], results["gen"], \
        results["om"], results["x"], results["mu"], results["f"] = \
            bus, branch, gen, om, x, mu, f

    raw = {'xr': x, 'pimul': pimul, 'info': info, 'output': output}

    return results, success, raw
Example #42
0
def gh7(x):
    g = array( [sum(x**2) - 40.0] )
    h = array( [ -prod(x) + 25.0] )
    dg = sparse( 2 * x ).T
    dh = sparse( -prod(x) / x ).T
    return h, g, dh, dg
Example #43
0
def makeAvl(baseMVA, gen):
    """Construct linear constraints for constant power factor var loads.

    Constructs parameters for the following linear constraint enforcing a
    constant power factor constraint for dispatchable loads::

         lvl <= Avl * [Pg, Qg] <= uvl

    C{ivl} is the vector of indices of generators representing variable loads.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    """
    ## data dimensions
    ng = gen.shape[0]  ## number of dispatchable injections
    Pg = gen[:, PG] / baseMVA
    Qg = gen[:, QG] / baseMVA
    Pmin = gen[:, PMIN] / baseMVA
    Qmin = gen[:, QMIN] / baseMVA
    Qmax = gen[:, QMAX] / baseMVA

    # Find out if any of these "generators" are actually dispatchable loads.
    # (see 'help isload' for details on what constitutes a dispatchable load)
    # Dispatchable loads are modeled as generators with an added constant
    # power factor constraint. The power factor is derived from the original
    # value of Pmin and either Qmin (for inductive loads) or Qmax (for
    # capacitive loads). If both Qmin and Qmax are zero, this implies a unity
    # power factor without the need for an additional constraint.

    ivl = find(isload(gen) & ((Qmin != 0) | (Qmax != 0)))
    nvl = ivl.shape[0]  ## number of dispatchable loads

    ## at least one of the Q limits must be zero (corresponding to Pmax == 0)
    if any((Qmin[ivl] != 0) & (Qmax[ivl] != 0)):
        stderr.write('makeAvl: either Qmin or Qmax must be equal to zero for '
                     'each dispatchable load.\n')

    # Initial values of PG and QG must be consistent with specified power
    # factor This is to prevent a user from unknowingly using a case file which
    # would have defined a different power factor constraint under a previous
    # version which used PG and QG to define the power factor.
    Qlim = (Qmin[ivl] == 0) * Qmax[ivl] + (Qmax[ivl] == 0) * Qmin[ivl]
    if any(abs(Qg[ivl] - Pg[ivl] * Qlim / Pmin[ivl]) > 1e-6):
        stderr.write('makeAvl: For a dispatchable load, PG and QG must be '
                     'consistent with the power factor defined by PMIN and '
                     'the Q limits.\n')

    # make Avl, lvl, uvl, for lvl <= Avl * [Pg Qg] <= uvl
    if nvl > 0:
        xx = Pmin[ivl]
        yy = Qlim
        pftheta = arctan2(yy, xx)
        pc = sin(pftheta)
        qc = -cos(pftheta)
        ii = r_[arange(nvl), arange(nvl)]
        jj = r_[ivl, ivl + ng]
        Avl = sparse((r_[pc, qc], (ii, jj)), (nvl, 2 * ng))
        lvl = zeros(nvl)
        uvl = lvl
    else:
        Avl = zeros((0, 2 * ng))
        lvl = array([])
        uvl = array([])

    return Avl, lvl, uvl, ivl
Example #44
0
def makeBdc(bus, branch):
    """Builds the B matrices and phase shift injections for DC power flow.

    Returns the B matrices and phase shift injection vectors needed for a
    DC power flow.
    The bus real power injections are related to bus voltage angles by::
        P = Bbus * Va + PBusinj
    The real power flows at the from end the lines are related to the bus
    voltage angles by::
        Pf = Bf * Va + Pfinj
    Does appropriate conversions to p.u.

    @see: L{dcpf}

    @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
    Autonoma de Manizales)
    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    ## constants
    nb = bus.shape[0]  ## number of buses
    nl = branch.shape[0]  ## number of lines

    ## check that bus numbers are equal to indices to bus (one set of bus nums)
    if any(bus[:, BUS_I] != list(range(nb))):
        logger.error('makeBdc: buses must be numbered consecutively in '
                     'bus matrix\n')

    ## for each branch, compute the elements of the branch B matrix and the phase
    ## shift "quiescent" injections, where
    ##
    ##      | Pf |   | Bff  Bft |   | Vaf |   | Pfinj |
    ##      |    | = |          | * |     | + |       |
    ##      | Pt |   | Btf  Btt |   | Vat |   | Ptinj |
    ##
    stat = branch[:, BR_STATUS]  ## ones at in-service branches
    b = stat / branch[:, BR_X]  ## series susceptance
    tap = ones(nl)  ## default tap ratio = 1
    i = find(real(branch[:, TAP]))  ## indices of non-zero tap ratios
    tap[i] = real(branch[i, TAP])  ## assign non-zero tap ratios
    b = b / tap

    ## build connection matrix Cft = Cf - Ct for line and from - to buses
    f = real(branch[:, F_BUS]).astype(int)  ## list of "from" buses
    t = real(branch[:, T_BUS]).astype(int)  ## list of "to" buses
    i = r_[range(nl), range(nl)]  ## double set of row indices
    ## connection matrix
    Cft = sparse((r_[ones(nl), -ones(nl)], (i, r_[f, t])), (nl, nb))

    ## build Bf such that Bf * Va is the vector of real branch powers injected
    ## at each branch's "from" bus
    Bf = sparse((r_[b, -b], (i, r_[f, t])))  ## = spdiags(b, 0, nl, nl) * Cft

    ## build Bbus
    Bbus = Cft.T * Bf

    ## build phase shift injection vectors
    Pfinj = b * (-branch[:, SHIFT] * pi / 180.
                 )  ## injected at the from bus ...
    # Ptinj = -Pfinj                            ## and extracted at the to bus
    Pbusinj = Cft.T * Pfinj  ## Pbusinj = Cf * Pfinj + Ct * Ptinj

    return Bbus, Bf, Pbusinj, Pfinj
Example #45
0
def LevenbergMarquardtPF(Ybus, Sbus, V0, Ibus, pv, pq, tol, max_it=50):
    """
    Solves the power flow problem by the Levenberg-Marquardt power flow algorithm.
    It is usually better than Newton-Raphson, but it takes an order of magnitude more time to converge.
    Args:
        Ybus: Admittance matrix
        Sbus: Array of nodal power injections
        V0: Array of nodal voltages (initial solution)
        Ibus: Array of nodal current injections
        pv: Array with the indices of the PV buses
        pq: Array with the indices of the PQ buses
        tol: Tolerance
        max_it: Maximum number of iterations
    Returns:
        Voltage solution, converged?, error, calculated power injections

    @Author: Santiago Peñate Vera
    """
    start = time.time()

    # initialize
    V = V0
    Va = angle(V)
    Vm = np.abs(V)
    dVa = zeros_like(Va)
    dVm = zeros_like(Vm)
    # set up indexing for updating V
    pvpq = r_[pv, pq]
    npv = len(pv)
    npq = len(pq)

    # j1:j2 - V angle of pv buses
    j1 = 0
    j2 = npv
    # j3:j4 - V angle of pq buses
    j3 = j2
    j4 = j2 + npq
    # j5:j6 - V mag of pq buses
    j5 = j4
    j6 = j4 + npq

    update_jacobian = True
    converged = False
    iter_ = 0
    nu = 2.0
    lbmda = 0
    f_prev = 1e9  # very large number
    nn = 2 * npq + npv
    ii = np.linspace(0, nn - 1, nn)
    Idn = sparse((np.ones(nn), (ii, ii)),
                 shape=(nn, nn))  # csr_matrix identity

    while not converged and iter_ < max_it:

        # evaluate Jacobian
        if update_jacobian:
            H = Jacobian(Ybus, V, Ibus, pq, pvpq)

        # evaluate the solution error F(x0)
        Scalc = V * conj(Ybus * V - Ibus)
        mis = Scalc - Sbus  # compute the mismatch
        dz = r_[mis[pv].real, mis[pq].real,
                mis[pq].imag]  # mismatch in the Jacobian order

        # system matrix
        # H1 = H^t
        H1 = H.transpose().tocsr()

        # H2 = H1·H
        H2 = H1.dot(H)

        # set first value of lmbda
        if iter_ == 0:
            lbmda = 1e-3 * H2.diagonal().max()

        # compute system matrix A = H^T·H - lambda·I
        A = H2 + lbmda * Idn

        # right hand side
        # H^t·dz
        rhs = H1.dot(dz)

        # Solve the increment
        dx = spsolve(A, rhs)

        # objective function to minimize
        f = 0.5 * dz.dot(dz)

        # decision function
        val = dx.dot(lbmda * dx + rhs)
        if val > 0.0:
            rho = (f_prev - f) / (0.5 * val)
        else:
            rho = -1.0

        # lambda update
        if rho >= 0:
            update_jacobian = True
            lbmda *= max([1.0 / 3.0, 1 - (2 * rho - 1)**3])
            nu = 2.0

            # reassign the solution vector
            if npv:
                dVa[pv] = dx[j1:j2]
            if npq:
                dVa[pq] = dx[j3:j4]
                dVm[pq] = dx[j5:j6]

            Vm -= dVm
            Va -= dVa
            # update Vm and Va again in case we wrapped around with a negative Vm
            V = Vm * exp(1j * Va)
            Vm = np.abs(V)
            Va = angle(V)
        else:
            update_jacobian = False
            lbmda *= nu
            nu *= 2.0

        # check convergence
        # normF = np.linalg.norm(dx, np.Inf)
        normF = np.linalg.norm(Sbus - V * conj(Ybus.dot(V)), np.Inf)
        converged = normF < tol
        f_prev = f

        # update iteration counter
        iter_ += 1

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

    return V, converged, normF, Scalc, iter_, elapsed
Example #46
0
def qps_mosek(H,
              c=None,
              A=None,
              l=None,
              u=None,
              xmin=None,
              xmax=None,
              x0=None,
              opt=None):
    """Quadratic Program Solver based on MOSEK.

    A wrapper function providing a PYPOWER standardized interface for using
    MOSEKOPT to solve the following QP (quadratic programming) problem::

        min 1/2 x'*H*x + c'*x
         x

    subject to::

        l <= A*x <= u       (linear constraints)
        xmin <= x <= xmax   (variable bounds)

    Inputs (all optional except C{H}, C{C}, C{A} and C{L}):
        - C{H} : matrix (possibly sparse) of quadratic cost coefficients
        - C{C} : vector of linear cost coefficients
        - C{A, l, u} : define the optional linear constraints. Default
        values for the elements of L and U are -Inf and Inf, respectively.
        - xmin, xmax : optional lower and upper bounds on the
        C{x} variables, defaults are -Inf and Inf, respectively.
        - C{x0} : optional starting value of optimization vector C{x}
        - C{opt} : optional options structure with the following fields,
        all of which are also optional (default values shown in parentheses)
            - C{verbose} (0) - controls level of progress output displayed
                - 0 = no progress output
                - 1 = some progress output
                - 2 = verbose progress output
            - C{max_it} (0) - maximum number of iterations allowed
                - 0 = use algorithm default
            - C{mosek_opt} - options struct for MOSEK, values in
            C{verbose} and C{max_it} override these options
        - C{problem} : The inputs can alternatively be supplied in a single
        C{problem} struct with fields corresponding to the input arguments
        described above: C{H, c, A, l, u, xmin, xmax, x0, opt}

    Outputs:
        - C{x} : solution vector
        - C{f} : final objective function value
        - C{exitflag} : exit flag
              - 1 = success
              - 0 = terminated at maximum number of iterations
              - -1 = primal or dual infeasible
              < 0 = the negative of the MOSEK return code
        - C{output} : output dict with the following fields:
            - C{r} - MOSEK return code
            - C{res} - MOSEK result dict
        - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
        multipliers on the constraints, with fields:
            - C{mu_l} - lower (left-hand) limit on linear constraints
            - C{mu_u} - upper (right-hand) limit on linear constraints
            - C{lower} - lower bound on optimization variables
            - C{upper} - upper bound on optimization variables

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ##----- input argument handling  -----
    ## gather inputs
    if isinstance(H, dict):  ## problem struct
        p = H
    else:  ## individual args
        p = {'H': H, 'c': c, 'A': A, 'l': l, 'u': u}
        if xmin is not None:
            p['xmin'] = xmin
        if xmax is not None:
            p['xmax'] = xmax
        if x0 is not None:
            p['x0'] = x0
        if opt is not None:
            p['opt'] = opt

    ## define nx, set default values for H and c
    if 'H' not in p or len(p['H']) or not any(any(p['H'])):
        if ('A' not in p) | len(p['A']) == 0 & \
                ('xmin' not in p) | len(p['xmin']) == 0 & \
                ('xmax' not in p) | len(p['xmax']) == 0:
            stderr.write(
                'qps_mosek: LP problem must include constraints or variable bounds\n'
            )
        else:
            if 'A' in p & len(p['A']) > 0:
                nx = shape(p['A'])[1]
            elif 'xmin' in p & len(p['xmin']) > 0:
                nx = len(p['xmin'])
            else:  # if isfield(p, 'xmax') && ~isempty(p.xmax)
                nx = len(p['xmax'])
        p['H'] = sparse((nx, nx))
        qp = 0
    else:
        nx = shape(p['H'])[0]
        qp = 1

    if 'c' not in p | len(p['c']) == 0:
        p['c'] = zeros(nx)

    if 'x0' not in p | len(p['x0']) == 0:
        p['x0'] = zeros(nx)

    ## default options
    if 'opt' not in p:
        p['opt'] = []

    if 'verbose' in p['opt']:
        verbose = p['opt']['verbose']
    else:
        verbose = 0

    if 'max_it' in p['opt']:
        max_it = p['opt']['max_it']
    else:
        max_it = 0

    if 'mosek_opt' in p['opt']:
        mosek_opt = mosek_options(p['opt']['mosek_opt'])
    else:
        mosek_opt = mosek_options()

    if max_it:
        mosek_opt['MSK_IPAR_INTPNT_MAX_ITERATIONS'] = max_it

    if qp:
        mosek_opt['MSK_IPAR_OPTIMIZER'] = 0  ## default solver only for QP

    ## set up problem struct for MOSEK
    prob = {}
    prob['c'] = p['c']
    if qp:
        prob['qosubi'], prob['qosubj'], prob['qoval'] = find(
            tril(sparse(p['H'])))

    if 'A' in p & len(p['A']) > 0:
        prob['a'] = sparse(p['A'])

    if 'l' in p & len(p['A']) > 0:
        prob['blc'] = p['l']

    if 'u' in p & len(p['A']) > 0:
        prob['buc'] = p['u']

    if 'xmin' in p & len(p['xmin']) > 0:
        prob['blx'] = p['xmin']

    if 'xmax' in p & len(p['xmax']) > 0:
        prob['bux'] = p['xmax']

    ## A is not allowed to be empty
    if 'a' not in prob | len(prob['a']) == 0:
        unconstrained = True
        prob['a'] = sparse((1, (1, 1)), (1, nx))
        prob.blc = -Inf
        prob.buc = Inf
    else:
        unconstrained = False

    ##-----  run optimization  -----
    if verbose:
        methods = [
            'default', 'interior point', '<default>', '<default>',
            'primal simplex', 'dual simplex', 'primal dual simplex',
            'automatic simplex', '<default>', '<default>', 'concurrent'
        ]
        if len(H) == 0 or not any(any(H)):
            lpqp = 'LP'
        else:
            lpqp = 'QP'

        # (this code is also in mpver.m)
        # MOSEK Version 6.0.0.93 (Build date: 2010-10-26 13:03:27)
        # MOSEK Version 6.0.0.106 (Build date: 2011-3-17 10:46:54)
#        pat = 'Version (\.*\d)+.*Build date: (\d\d\d\d-\d\d-\d\d)';
        pat = 'Version (\.*\d)+.*Build date: (\d+-\d+-\d+)'
        s, e, tE, m, t = re.compile(eval('mosekopt'), pat)
        if len(t) == 0:
            vn = '<unknown>'
        else:
            vn = t[0][0]

        print(('MOSEK Version %s -- %s %s solver\n' %
               (vn, methods[mosek_opt['MSK_IPAR_OPTIMIZER'] + 1], lpqp)))

    cmd = 'minimize echo(%d)' % verbose
    r, res = mosekopt(cmd, prob, mosek_opt)

    ##-----  repackage results  -----
    if 'sol' in res:
        if 'bas' in res['sol']:
            sol = res['sol.bas']
        else:
            sol = res['sol.itr']
        x = sol['xx']
    else:
        sol = array([])
        x = array([])

    ##-----  process return codes  -----
    if 'symbcon' in res:
        sc = res['symbcon']
    else:
        r2, res2 = mosekopt('symbcon echo(0)')
        sc = res2['symbcon']

    eflag = -r
    msg = ''
    if r == sc.MSK_RES_OK:
        if len(sol) > 0:
            #            if sol['solsta'] == sc.MSK_SOL_STA_OPTIMAL:
            if sol['solsta'] == 'OPTIMAL':
                msg = 'The solution is optimal.'
                eflag = 1
            else:
                eflag = -1
                #                if sol['prosta'] == sc['MSK_PRO_STA_PRIM_INFEAS']:
                if sol['prosta'] == 'PRIMAL_INFEASIBLE':
                    msg = 'The problem is primal infeasible.'
#                elif sol['prosta'] == sc['MSK_PRO_STA_DUAL_INFEAS']:
                elif sol['prosta'] == 'DUAL_INFEASIBLE':
                    msg = 'The problem is dual infeasible.'
                else:
                    msg = sol['solsta']

    elif r == sc['MSK_RES_TRM_MAX_ITERATIONS']:
        eflag = 0
        msg = 'The optimizer terminated at the maximum number of iterations.'
    else:
        if 'rmsg' in res and 'rcodestr' in res:
            msg = '%s : %s' % (res['rcodestr'], res['rmsg'])
        else:
            msg = 'MOSEK return code = %d' % r

    ## always alert user if license is expired
    if (verbose or r == 1001) and len(msg) < 0:
        stdout.write('%s\n' % msg)

    ##-----  repackage results  -----
    if r == 0:
        f = p['c'].T * x
        if len(p['H']) > 0:
            f = 0.5 * x.T * p['H'] * x + f
    else:
        f = array([])

    output = {}
    output['r'] = r
    output['res'] = res

    if 'sol' in res:
        lmbda = {}
        lmbda['lower'] = sol['slx']
        lmbda['upper'] = sol['sux']
        lmbda['mu_l'] = sol['slc']
        lmbda['mu_u'] = sol['suc']
        if unconstrained:
            lmbda['mu_l'] = array([])
            lmbda['mu_u'] = array([])
    else:
        lmbda = array([])

    return x, f, eflag, output, lmbda
Example #47
0
def dSbr_dV(branch, Yf, Yt, V):
    """Computes partial derivatives of power flows w.r.t. voltage.

    returns four matrices containing partial derivatives of the complex
    branch power flows at "from" and "to" ends of each branch w.r.t voltage
    magnitude and voltage angle respectively (for all buses). If C{Yf} is a
    sparse matrix, the partial derivative matrices will be as well. Optionally
    returns vectors containing the power flows themselves. The following
    explains the expressions used to form the matrices::

        If = Yf * V;
        Sf = diag(Vf) * conj(If) = diag(conj(If)) * Vf

    Partials of V, Vf & If w.r.t. voltage angles::
        dV/dVa  = j * diag(V)
        dVf/dVa = sparse(range(nl), f, j*V(f)) = j * sparse(range(nl), f, V(f))
        dIf/dVa = Yf * dV/dVa = Yf * j * diag(V)

    Partials of V, Vf & If w.r.t. voltage magnitudes::
        dV/dVm  = diag(V / abs(V))
        dVf/dVm = sparse(range(nl), f, V(f) / abs(V(f))
        dIf/dVm = Yf * dV/dVm = Yf * diag(V / abs(V))

    Partials of Sf w.r.t. voltage angles::
        dSf/dVa = diag(Vf) * conj(dIf/dVa)
                        + diag(conj(If)) * dVf/dVa
                = diag(Vf) * conj(Yf * j * diag(V))
                        + conj(diag(If)) * j * sparse(range(nl), f, V(f))
                = -j * diag(Vf) * conj(Yf * diag(V))
                        + j * conj(diag(If)) * sparse(range(nl), f, V(f))
                = j * (conj(diag(If)) * sparse(range(nl), f, V(f))
                        - diag(Vf) * conj(Yf * diag(V)))

    Partials of Sf w.r.t. voltage magnitudes::
        dSf/dVm = diag(Vf) * conj(dIf/dVm)
                        + diag(conj(If)) * dVf/dVm
                = diag(Vf) * conj(Yf * diag(V / abs(V)))
                        + conj(diag(If)) * sparse(range(nl), f, V(f)/abs(V(f)))

    Derivations for "to" bus are similar.

    For more details on the derivations behind the derivative code used
    in PYPOWER information, see:

    [TN2]  R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and
    their Derivatives using Complex Matrix Notation", MATPOWER
    Technical Note 2, February 2010.
    U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ## define
    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)
    il = arange(nl)
    ib = arange(nb)

    Vnorm = V / abs(V)

    if issparse(Yf):
        ## compute currents
        If = Yf * V
        It = Yt * V

        diagVf = sparse((V[f], (il, il)))
        diagIf = sparse((If, (il, il)))
        diagVt = sparse((V[t], (il, il)))
        diagIt = sparse((It, (il, il)))
        diagV = sparse((V, (ib, ib)))
        diagVnorm = sparse((Vnorm, (ib, ib)))

        shape = (nl, nb)
        # Partial derivative of S w.r.t voltage phase angle.
        dSf_dVa = 1j * (conj(diagIf) * sparse(
            (V[f], (il, f)), shape) - diagVf * conj(Yf * diagV))

        dSt_dVa = 1j * (conj(diagIt) * sparse(
            (V[t], (il, t)), shape) - diagVt * conj(Yt * diagV))

        # Partial derivative of S w.r.t. voltage amplitude.
        dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * \
            sparse((Vnorm[f], (il, f)), shape)

        dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * \
            sparse((Vnorm[t], (il, t)), shape)
    else:  ## dense version
        ## compute currents
        If = asarray(Yf * asmatrix(V).T).flatten()
        It = asarray(Yt * asmatrix(V).T).flatten()

        diagVf = asmatrix(diag(V[f]))
        diagIf = asmatrix(diag(If))
        diagVt = asmatrix(diag(V[t]))
        diagIt = asmatrix(diag(It))
        diagV = asmatrix(diag(V))
        diagVnorm = asmatrix(diag(Vnorm))
        temp1 = asmatrix(zeros((nl, nb), complex))
        temp2 = asmatrix(zeros((nl, nb), complex))
        temp3 = asmatrix(zeros((nl, nb), complex))
        temp4 = asmatrix(zeros((nl, nb), complex))
        for i in range(nl):
            fi, ti = f[i], t[i]
            temp1[i, fi] = V[fi].item()
            temp2[i, fi] = Vnorm[fi].item()
            temp3[i, ti] = V[ti].item()
            temp4[i, ti] = Vnorm[ti].item()

        dSf_dVa = 1j * (conj(diagIf) * temp1 - diagVf * conj(Yf * diagV))
        dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * temp2
        dSt_dVa = 1j * (conj(diagIt) * temp3 - diagVt * conj(Yt * diagV))
        dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * temp4

    # Compute power flow vectors.
    Sf = V[f] * conj(If)
    St = V[t] * conj(It)

    return dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St
def run(mpc):
    """
    Gurobi based optimal power flow modelling and solution
    :param mpc: The input case of optimal power flow
    :return: obtained solution
    """
    # Data format
    from pypower.idx_brch import F_BUS, T_BUS, BR_R, BR_X, TAP, SHIFT, BR_STATUS, RATE_A
    from pypower.idx_cost import MODEL, NCOST, PW_LINEAR, COST, POLYNOMIAL
    from pypower.idx_bus import BUS_TYPE, REF, VA, VM, PD, GS, VMAX, VMIN, BUS_I, QD
    from pypower.idx_gen import GEN_BUS, VG, PG, QG, PMAX, PMIN, QMAX, QMIN
    from pypower.ext2int import ext2int

    mpc = ext2int(mpc)
    baseMVA, bus, gen, branch, gencost = mpc["baseMVA"], mpc["bus"], mpc["gen"], mpc["branch"], mpc["gencost"]

    nb = shape(mpc['bus'])[0]  # number of buses
    nl = shape(mpc['branch'])[0]  # number of branches
    ng = shape(mpc['gen'])[0]  # number of dispatchable injections

    for i in range(nl):  # branch indexing exchange
        if branch[i, F_BUS] > branch[i, T_BUS]:
            temp = branch[i, F_BUS]
            branch[i, F_BUS] = branch[i, T_BUS]
            branch[i, T_BUS] = temp

    f = branch[:, F_BUS]  ## list of "from" buses
    t = branch[:, T_BUS]  ## list of "to" buses
    area = ancestor_children_generation(f, t, range(nb))

    # Connection matrix
    Cg = sparse((ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))
    Branch_R = branch[:, BR_R]
    Branch_X = branch[:, BR_X]

    # Obtain the boundary information

    Slmax = branch[:, RATE_A] / baseMVA

    Pij_l = -Slmax
    Qij_l = -Slmax
    Iij_l = zeros(nl)
    Vm_l = turn_to_power(bus[:, VMIN], 2)
    Pg_l = gen[:, PMIN] / baseMVA
    Qg_l = gen[:, QMIN] / baseMVA
    Pi_l = -bus[:, PD] / baseMVA + Cg * Pg_l
    Qi_l = -bus[:, QD] / baseMVA + Cg * Qg_l

    Pij_u = Slmax
    Qij_u = Slmax
    Iij_u = Slmax
    Vm_u = turn_to_power(bus[:, VMAX], 2)
    Pg_u = 2 * gen[:, PMAX] / baseMVA
    Qg_u = 2 * gen[:, QMAX] / baseMVA
    Pi_u = -bus[:, PD] / baseMVA + Cg * Pg_u
    Qi_u = -bus[:, QD] / baseMVA + Cg * Qg_u
    #
    model = Model("OPF")
    # Define the decision variables, compact set
    Pij = {}
    Qij = {}
    Iij = {}
    Vi = {}
    Pg = {}
    Qg = {}
    Pi = {}
    Qi = {}

    for i in range(nl):
        Pij[i] = model.addVar(lb=Pij_l[i], ub=Pij_u[i], vtype=GRB.CONTINUOUS, name="Pij{0}".format(i))
        Qij[i] = model.addVar(lb=Qij_l[i], ub=Qij_u[i], vtype=GRB.CONTINUOUS, name="Qij{0}".format(i))
        Iij[i] = model.addVar(lb=Iij_l[i], ub=Iij_u[i], vtype=GRB.CONTINUOUS, name="Iij{0}".format(i))

    for i in range(nb):
        Vi[i] = model.addVar(lb=Vm_l[i], ub=Vm_u[i], vtype=GRB.CONTINUOUS, name="V{0}".format(i))

    for i in range(ng):
        Pg[i] = model.addVar(lb=Pg_l[i], ub=Pg_u[i], vtype=GRB.CONTINUOUS, name="Pg{0}".format(i))
        Qg[i] = model.addVar(lb=Qg_l[i], ub=Qg_u[i], vtype=GRB.CONTINUOUS, name="Qg{0}".format(i))
    for i in range(nb):
        Pi[i] = model.addVar(lb=Pi_l[i], ub=Pi_u[i], vtype=GRB.CONTINUOUS, name="Pi{0}".format(i))
        Qi[i] = model.addVar(lb=Qi_l[i], ub=Qi_u[i], vtype=GRB.CONTINUOUS, name="Qi{0}".format(i))
    # For each area, before decomposition
    # Add system level constraints
    for i in range(nb):
        # If the bus is the root bus, only the children information is required.
        if len(area[i]["Ai"]) == 0:
            print(i)
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]

            model.addConstr(lhs=expr - Pi[i], sense=GRB.EQUAL, rhs=0)

            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            model.addConstr(lhs=expr - Qi[i], sense=GRB.EQUAL, rhs=0)

        elif len(area[i]["Cbranch"]) == 0:  # This bus is the lead node

            model.addConstr(lhs=Pij[area[i]["Abranch"][0][0]] - Iij[area[i]["Abranch"][0][0]] * Branch_R[area[i]["Abranch"][0][0]] +
                    Pi[i],sense=GRB.EQUAL, rhs=0)

            model.addConstr(lhs=Qij[area[i]["Abranch"][0][0]] - Iij[area[i]["Abranch"][0][0]] * Branch_X[area[i]["Abranch"][0][0]] +
                    Qi[i],sense=GRB.EQUAL, rhs=0)

            model.addConstr(lhs=Vi[int(area[i]["Ai"][0])] - Vi[i] - 2 * Branch_R[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] - 2 * Branch_X[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]] +
                                Iij[area[i]["Abranch"][0][0]] * (Branch_R[area[i]["Abranch"][0][0]] ** 2 + Branch_X[area[i]["Abranch"][0][0]] ** 2),sense=GRB.EQUAL, rhs=0)

            model.addConstr(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] + Qij[area[i]["Abranch"][0][0]] * Qij[
                    area[i]["Abranch"][0][0]] <= Vi[int(area[i]["Ai"][0])] *
                Iij[area[i]["Abranch"][0][0]])

        else:
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]
            model.addConstr( lhs=
                Pij[area[i]["Abranch"][0][0]] - Iij[area[i]["Abranch"][0][0]] * Branch_R[area[i]["Abranch"][0][0]] +
                    Pi[i] - expr,sense=GRB.EQUAL, rhs=0)

            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            model.addConstr(Qij[area[i]["Abranch"][0][0]] - Iij[area[i]["Abranch"][0][0]] * Branch_X[area[i]["Abranch"][0][0]] +
                    Qi[i] - expr,sense=GRB.EQUAL, rhs=0)

            model.addConstr(lhs=Vi[int(area[i]["Ai"][0])] - Vi[i] - 2 * Branch_R[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] - 2 * Branch_X[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]] +
                                Iij[area[i]["Abranch"][0][0]] * (Branch_R[area[i]["Abranch"][0][0]] ** 2 + Branch_X[area[i]["Abranch"][0][0]] ** 2),sense=GRB.EQUAL, rhs=0)
            model.addConstr(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] + Qij[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]] <= Vi[int(area[i]["Ai"][0])] *
                Iij[area[i]["Abranch"][0][0]])
    obj = 0
    for i in range(ng):
        model.addConstr(lhs=Pg[i] - Pi[int(gen[i, GEN_BUS])] ,sense=GRB.EQUAL, rhs= bus[int(gen[i, GEN_BUS]), PD] / baseMVA)
        model.addConstr(lhs= Qg[i] - Qi[int(gen[i, GEN_BUS])], sense=GRB.EQUAL, rhs= bus[int(gen[i, GEN_BUS]), QD] / baseMVA)
        obj += gencost[i, 4] * Pg[i] * Pg[i] * baseMVA * baseMVA + gencost[i, 5] * Pg[i] * baseMVA + gencost[i, 6]

    model.setObjective(obj)
    model.Params.OutputFlag = 0
    model.Params.LogToConsole = 0
    model.Params.DisplayInterval = 1
    model.optimize()

    Pij = []
    Qij = []
    Iij = []
    Vi = []
    Pg = []
    Qg = []
    Pi = []
    Qi = []

    for i in range(nl):
        Pij.append(model.getVarByName("Pij{0}".format(i)).X)
        Qij.append(model.getVarByName("Qij{0}".format(i)).X)
        Iij.append(model.getVarByName("Iij{0}".format(i)).X)

    for i in range(nb):
        Vi.append(model.getVarByName("V{0}".format(i)).X)
        Pi.append(model.getVarByName("Pi{0}".format(i)).X)
        Qi.append(model.getVarByName("Qi{0}".format(i)).X)

    for i in range(ng):
        Pg.append(model.getVarByName("Pg{0}".format(i)).X)
        Qg.append(model.getVarByName("Qg{0}".format(i)).X)

    obj = obj.getValue()


    primal_residual = []

    for i in range(nl):
        primal_residual.append(Pij[i] * Pij[i] + Qij[i] * Qij[i] - Iij[i] * Vi[int(f[i])])

    return obj, primal_residual
    def distort_image(self,
                      image,
                      fov=20,
                      out_size=256,
                      inv=0,
                      type=1,
                      series=0):
        # Arguments:
        #     image = array_like
        #               Numpy array containing an image, containing a link to an image, or is empty.
        # 	            Leaving it empty will call up a GUI to manually select a file.
        #     fov = integer
        #               Field of view coverage with distance in visual angle. When
        #               decompressing an image, it is advised that the value is set to the fov of the original image.
        #               range=[1, 100]
        #     out_size = integer
        #               Determines the size of the output image in pixels. The value is
        #               the size of the output image on one axis. Output image is always a square image. When
        #               decompressing an image, it is advised that the value is set to the size of the original image.
        #     inv = integer
        #               Set to 1 to get a decompression of a distorted input image. Set to 0 to have compression.
        #               range[0, 1]
        #     type = integer
        #               Set to 0 for photoreceptor (cones) based distortion, set to 1 for Ganglion cell based
        #               distortion
        #     series = integer
        #               Set to 1 to store the sparse transformation matrix which can be used for a series of
        #               transformations.
        # Notes:
        # Main method for image distortion. This can be used for both forward compression (normal image to Ganglion
        # compressed image, type_d = 0), or decompressing (Ganglion/Photoreceptor compressed to normal image, type_
        # d = 1) an image. Decompression is intended to be used to create a normalized visualization of a
        # Ganglion/Photocell-compressed images. These normalized representations can be used as an indication of
        # information loss. As the original image is in pixel-space, and the model assumes an input that is described in
        # visual angle eccentricity, there is a need to describe the image coverage on the visual field in degrees of
        # visual angle. Therefore, the model needs the user to input how much of the field of view is covered by the
        # image (fov) in degrees of visual angle. The range should be between 1 and 100 degrees of visual angle.
        # The method works on the radial distance of each pixel which will be remapped according to the amount of cells
        # involved in processing the image. A constant distance between the cells is assumed.For remapping, we use an
        # inverse mapping approach in which each pixel in the new image is determined by taking it from the original
        # image. This method requires a inverted integrated cell density function.

        if (self.W is None) or (series == 0):

            try:
                [
                    self.inR, self.inC, self.inD
                ] = image.shape  # Determine dimensions of the selected image (pixel space)
            except:
                #image = np.repeat(image[:, :, np.newaxis], 3, axis=2)
                [
                    self.inR, self.inC
                ] = image.shape  # Determine dimensions of the selected image (pixel space)
                self.inD = None
            self.inS = max(
                self.inR,
                self.inC)  # Determine the largest dimension of the image

            # Parameter e represents the radius of visual field coverage (visual angle).
            e = fov / 2

            # Determine the radius of the in-and output image.
            in_radius = self.inS / 2
            out_radius = out_size / 2

            # Calculate the number of Ganglion/Photo cells covering the radius of the image, given the field of view
            # coverage of the input image. We run the degrees of visual angle (eccentricity) through the integrated
            # Ganglion/Photo cell density function which gives us the total amount of cells involved with processing the
            # image along the radius given the covered visual field.
            if type == 0:
                n_cells = self.cones_i(e)
            if type == 1:
                n_cells = self.fi(e)

            # Inv determines decompression. If set to 1, it is assumed that the image is compressed already, and
            # should be normalized. If set to 0, it is assumed the image needs to be distorted.
            if inv == 0:
                # How many degrees are modeled within a pixel of the image? This can be determined by dividing the
                # visual angle of eccentricity by half the image dimension. This will be used to adjust the new radial
                # distances for each pixel (expressed in degrees) to pixel distances.
                deg_per_pix = e / in_radius
                # The n_cells variable represents the amount of cells along the radius of the covered field of view
                # (visual angle eccentricity). Therefore, the total amount of cell involved along the diameter of the
                # image will be from -n_cells to n_cells. The image pixels are expressed in number of total cells
                # involved in processing the image up to each individual pixel.
                t = np.linspace(-n_cells, n_cells, num=out_size)
            elif inv == 1:
                # When going from distorted image to normalized image, we have to take the inverse of the inverse, thus
                # the regular integrated function. The new radial distances for each pixel will thus be given in the
                # number of retinal cells. Therefore, this has to be converted to number of pixels. This is done by
                # calculating the number of cells per pixels.
                cell_per_pix = n_cells / in_radius
                # The image is expressed in visual angles.
                t = np.linspace(-e, e, num=out_size)

            x, y = np.meshgrid(t, t)
            x = np.reshape(x, out_size**2)
            y = np.reshape(y, out_size**2)

            # For every pixel, calculate its angle, and radius.
            ang = np.angle(x + y * 1j)
            rad = np.abs(x + y * 1j)

            if inv == 0:
                # Calculate a mask that covers all pixel beyond the modeled fov coverage, for better visualization
                # (optional)
                msk = (rad <= n_cells)
                # Calculate the new location of each pixel. Inverse mapping: For each pixel in the new image, calculate
                # from which pixel in the original image it gets it values.
                if type == 0:
                    new_r = self.cones_ii(rad) / deg_per_pix
                if type == 1:
                    new_r = self.fii(rad) / deg_per_pix
                # Use angle and new radial values to determine the x and y coordinates.
                x_n = np.multiply(np.cos(ang), new_r) + self.inS / 2
                y_n = np.multiply(np.sin(ang), new_r) + self.inS / 2
            elif inv == 1:
                # Calculate a mask that covers all pixel beyond the modeled fov coverage, for better visualization
                # (optional)
                msk = (rad <= fov)
                # Calculate the new location of each pixel. Inverse mapping: For each pixel in the new image, calculate
                # from which pixel in the original image it gets it values.
                if type == 0:
                    new_r = self.cones_i(rad) / cell_per_pix
                if type == 1:
                    new_r = self.fi(rad) / cell_per_pix
                # Use angle and new radial values to determine the x and y coordinates.
                x_n = np.multiply(np.cos(ang), new_r) + in_radius
                y_n = np.multiply(np.sin(ang), new_r) + in_radius

            # The method used for image conversion. A sparse matrix that maps every pixel in the old image, to each
            # pixel in the new image via inverse mapping, is used.
            # Build a spare matrix for image conversion.
            W = sparse((out_size**2, self.inS**2), dtype=np.float)
            # Sometimes division by 0 might happen. This line makes sure the user won't see a warning when this happens.
            np.seterr(divide='ignore', invalid='ignore')
            for i in range(out_size**2):
                # Pixel indices will almost always not be a perfect integer value. Therefore, the value of the new pixel
                # is value is determined by taking the average of all pixels involved. E.g. a value of 4.3 is converted
                # to the indices 4, and 5. The RGB values are weighted accordingly (0.7 for index 4, and 0.3 for index
                # 5). Additionally, boundary checking is used. Values can never be smaller than 0, or larger than the
                # maximum index of the image.
                x = np.minimum(
                    np.maximum([math.floor(y_n[i]),
                                math.ceil(y_n[i])], 0), self.inS - 1)
                y = np.minimum(
                    np.maximum([math.floor(x_n[i]),
                                math.ceil(x_n[i])], 0), self.inS - 1)
                c, idx = np.unique([x[0] * self.inS + y, x[1] * self.inS + y],
                                   return_index=True)
                dist = np.reshape(
                    np.array([np.abs(x - x_n[i]),
                              np.abs(y - y_n[i])]), 4)
                W[i, c] = dist[idx] / sum(dist[idx])
            if series == 1:
                self.W = W
                self.msk = msk
        else:
            msk = []
        # Vectorize the image
        if self.inD:
            image = np.reshape(image, (self.inS**2, self.inD))
        else:
            self.inD = 0
            image = np.reshape(image, self.inS**2)
        # Sparse matrix multiplication with the original input image to build the new image.
        if series == 1:
            W = self.W
            msk = self.msk
        if self.inD:
            output = np.reshape(
                W.dot(image), (out_size, out_size, self.inD)).astype(np.uint8)
        else:
            output = np.reshape(W.dot(image), (out_size, out_size))
        return output, msk
Example #50
0
def t_auction_pips(quiet=False):
    """Tests for code in auction.py, using PIPS solver.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    n_tests = 183

    t_begin(n_tests, quiet)

    try:
        from pypower.extras.smartmarket import runmkt
    except ImportError:
        t_skip(n_tests, 'smartmarket code not available')
        return

    ppopt = ppoption
    ppopt['OPF_VIOLATION'] = 1e-7
    ppopt['PDIPM_GRADTOL'] = 1e-6
    ppopt['PDIPM_COMPTOL'] = 1e-7
    ppopt['PDIPM_COSTTOL'] = 5e-9
    ppopt['OPF_ALG'] = 560
    ppopt['OUT_ALL_LIM'] = 1
    ppopt['OUT_BRANCH'] = 0
    ppopt['OUT_SYS_SUM'] = 0
    ppopt['OUT_ALL'] = 0
    ppopt['VERBOSE'] = 0
    q = array([
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [10, 10, 10],
        [10, 10, 10],
        [10, 10, 10],
    ])

    ##-----  one offer block marginal @ $50  -----
    p = array([[20, 50, 60], [20, 40, 70], [20, 42, 80], [20, 44, 90],
               [20, 46, 75], [20, 48, 60], [100, 70, 60], [100, 50, 20],
               [100, 60, 50]])

    t = 'one marginal offer @ $50, auction_type = 5'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1150, 100, [], [], mpopt)
    cq5 = cq.copy()
    cp5 = cp.copy()
    i2e = bus.bus_i
    e2i = sparse((max(i2e), 1))
    e2i[i2e] = range(bus.size())
    G = find(isload(gen) == False)  ## real generators
    L = find(isload(gen))  ## dispatchable loads
    Gbus = e2i[gen.gen_bus[G]]
    Lbus = e2i[gen.gen_bus[L]]
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = \
        diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(p[L :].shape)

    t_is(cq[G[0], 1:3], [23.32, 0], 2, t)
    t_is(cp[G[0], :], 50, 4, t)
    t_is(cq[L[1], 0:2], [10, 0], 2, t)
    t_is(cp[L[1], :], 54.0312, 4, t)
    t_is(cp[G, 0], bus.lam_P[Gbus], 8, [t, ' : gen prices'])
    t_is(cp[L, 0], bus.lam_P[Lbus] + Qfudge[L, 0], 8, [t, ' : load prices'])

    lao_X = p(G[0], 1) / bus.lam_P[Gbus[0], LAM_P]
    fro_X = p(G(5), 2) / bus.lam_P[Gbus[5], LAM_P]
    lab_X = p(L(2), 1) / (bus.lam_P[Lbus[2]] + Qfudge[L[2], 0])
    frb_X = p(L(1), 1) / (bus.lam_P[Lbus[1]] + Qfudge[L[1], 0])

    t_is(lao_X, 1, 4, 'lao_X')
    t_is(fro_X, 1.1324, 4, 'fro_X')
    t_is(lab_X, 1.0787, 4, 'lab_X')
    t_is(frb_X, 0.9254, 4, 'frb_X')

    t = 'one marginal offer @ $50, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1110, 100, [], [], mpopt)
    cp1 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 6, [t, ' : prices'])

    t = 'one marginal offer @ $50, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1120, 100, [], [], mpopt)
    cp2 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :] * fro_X, 8, [t, ' : gen prices'])
    t_is(cp[L[0:1], :], cp5[L[0:1], :] * fro_X, 8, [t, ' : load 1,2 prices'])
    t_is(cp[L[2], :], 60, 5,
         [t, ' : load 3 price'])  ## clipped by accepted bid

    t = 'one marginal offer @ $50, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1130, 100, [], [], mpopt)
    cp3 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5 * lab_X, 8, [t, ' : prices'])

    t = 'one marginal offer @ $50, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1140, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], p[G[0], 1], 8, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp5[G[1:6], :] * frb_X, 8, [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp5[L, :] * frb_X, 8, [t, ' : load prices'])

    t = 'one marginal offer @ $50, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp3, 8, [t, ' : prices'])
    p2 = p.copy()
    p2[L, :] = array([[100, 100, 100], [100, 0, 0], [100, 100, 0]])
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 5, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :] * fro_X, 4, [t, ' : gen prices'])
    t_is(cp[L, :], cp5[L, :] * fro_X, 4,
         [t, ' : load prices'])  ## load 3 not clipped as in FRO

    t = 'one marginal offer @ $50, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1170, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5 * (lao_X + lab_X) / 2, 8, [t, ' : prices'])
    t_is(cp, (cp1 + cp3) / 2, 8, [t, ' : prices'])

    t = 'one marginal offer @ $50, auction_type = 8'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1180, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp1[G, :], 8, [t, ' : gen prices'])
    t_is(cp[L, :], cp3[L, :], 8, [t, ' : load prices'])

    t = 'one marginal offer @ $50, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1100, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, p, 8, [t, ' : prices'])

    ##-----  one bid block marginal @ $55  -----
    p[L[1], 1] = 55
    t = 'one marginal bid @ $55, auction_type = 5'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1150, 100, [], [], mpopt)
    cq5 = cq.copy()
    cp5 = cp.copy()
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)

    t_is(cq[G[0], 1:3], [24, 0], 2, t)
    t_is(cp[G[0], :], 50.016, 3, t)
    t_is(cq[L[1], 0:2], [10, 0.63], 2, t)
    t_is(cp[L[1], :], 55, 4, t)
    t_is(cp[G, 0], bus.lam_P[Gbus], 8, [t, ' : gen prices'])
    t_is(cp[L, 0], bus.lam_P[Lbus] + Qfudge[L, 0], 8, [t, ' : load prices'])

    lao_X = p[G[0], 1] / bus.lam_P[Gbus[0]]
    fro_X = p[G[5], 2] / bus.lam_P[Gbus[5]]
    lab_X = p[L[1], 1] / (bus.lam_P[Lbus[1]] + Qfudge[L[1], 0])
    frb_X = p[L[2], 2] / (bus.lam_P[Lbus[2]] + Qfudge[L[2], 0])

    t_is(lao_X, 0.9997, 4, 'lao_X')
    t_is(fro_X, 1.1111, 4, 'fro_X')
    t_is(lab_X, 1, 4, 'lab_X')
    t_is(frb_X, 0.8960, 4, 'frb_X')

    t = 'one marginal bid @ $55, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1110, 100, [], [], mpopt)
    cp1 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5 * lao_X, 8, [t, ' : prices'])

    t = 'one marginal bid @ $55, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1120, 100, [], [], mpopt)
    cp2 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :] * fro_X, 8, [t, ' : gen prices'])
    t_is(cp[L[0], :], cp5[L[0], :] * fro_X, 8, [t, ' : load 1 price'])
    t_is(cp[L[1], :], 55, 5, [t, ' : load 2 price'])
    t_is(cp[L[2], :], 60, 5, [t, ' : load 3 price'])

    t = 'one marginal bid @ $55, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1130, 100, [], [], mpopt)
    cp3 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 7, [t, ' : prices'])

    t = 'one marginal bid @ $55, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1140, 100, [], [], mpopt)
    cp4 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 50, 5, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp5[G[1:6], :] * frb_X, 8, [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp5[L, :] * frb_X, 8, [t, ' : load prices'])

    t = 'one marginal bid @ $55, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp1, 8, [t, ' : prices'])

    p2 = p.copy()
    p2[G, :] = array([[0, 0, 100], [0, 0, 100], [0, 0, 100], [0, 0, 100],
                      [0, 0, 100], [0, 0, 100]])
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 3, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :] * frb_X, 3,
         [t, ' : gen prices'])  ## gen 1, not clipped this time
    t_is(cp[L, :], cp4[L, :], 3, [t, ' : load prices'])

    t = 'one marginal bid @ $55, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1170, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5 * (lao_X + lab_X) / 2, 8, [t, ' : prices'])
    t_is(cp, (cp1 + cp3) / 2, 8, [t, ' : prices'])

    t = 'one marginal bid @ $55, auction_type = 8'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1180, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp1[G, :], 8, [t, ' : gen prices'])
    t_is(cp[L, :], cp3[L, :], 8, [t, ' : load prices'])

    t = 'one marginal bid @ $55, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1100, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, p, 8, [t, ' : prices'])

    ##-----  one bid block marginal @ $54.50 and one offer block marginal @ $50  -----
    p[L[1], 1] = 54.5
    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 5'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1150, 100, [], [], mpopt)
    cq5 = cq.copy()
    cp5 = cp.copy()
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)

    t_is(cq[G[0], 1:3], [23.74, 0], 2, t)
    t_is(cp[G[0], :], 50, 4, t)
    t_is(cq[L[1], 0:2], [10, 0.39], 2, t)
    t_is(cp[L[1], :], 54.5, 4, t)
    t_is(cp[G, 0], bus.lam_P[Gbus], 8, [t, ' : gen prices'])
    t_is(cp[L, 0], bus.lam_P[Lbus] + Qfudge[L, 0], 8, [t, ' : load prices'])

    lao_X = p[G[0], 1] / bus.lam_P[Gbus[0]]
    fro_X = p[G[5], 2] / bus.lam_P[Gbus[5]]
    lab_X = p[L[1], 1] / (bus.lam_P[Lbus[1]] + Qfudge[L[1], 0])
    frb_X = p[L[2], 2] / (bus.lam_P[Lbus[2]] + Qfudge[L[2], 0])

    t_is(lao_X, 1, 4, 'lao_X')
    t_is(fro_X, 1.1221, 4, 'fro_X')
    t_is(lab_X, 1, 4, 'lab_X')
    t_is(frb_X, 0.8976, 4, 'frb_X')

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1110, 100, [], [], mpopt)
    cp1 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 4, [t, ' : prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1120, 100, [], [], mpopt)
    cp2 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :] * fro_X, 5, [t, ' : gen prices'])
    t_is(cp[L[0], :], cp5[L[0], :] * fro_X, 5, [t, ' : load 1 price'])
    t_is(cp[L[1], :], 54.5, 5, [t, ' : load 2 price'])
    t_is(cp[L[2], :], 60, 5, [t, ' : load 3 price'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1130, 100, [], [], mpopt)
    cp3 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 6, [t, ' : prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1140, 100, [], [], mpopt)
    cp4 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 50, 5, [t, ' : gen 1 price'])
    t_is(cp[G[1:5], :], cp5[G[1:5], :] * frb_X, 8, [t, ' : gen 2-5 prices'])
    t_is(cp[G[5], :], 48, 5, [t, ' : gen 6 price'])
    t_is(cp[L, :], cp5[L, :] * frb_X, 8, [t, ' : load prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 4, [t, ' : prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1170, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 4, [t, ' : prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 8'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1180, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 4, [t, ' : prices'])

    t = 'marginal offer @ $50, bid @ $54.50, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1100, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, p, 8, [t, ' : prices'])

    ##-----  gen 1 at Pmin, load 3 block 2 marginal @ $60  -----
    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 5'
    p[L[1], 1] = 50  ## undo previous change
    p2 = p.copy()
    p2[G[0], 1:3] = [65, 65]
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1150, 100, [], [], mpopt)
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)

    t_is(cp[G[0], :], 65, 4, [t, ' : gen 1 price'])
    t_is(cp[G[1], :], 54.2974, 4, [t, ' : gen 2 price'])
    cq5 = cq.copy()
    cp5 = cp.copy()
    cp_lam = cp5.copt()
    cp_lam[0, :] = bus.lam_P[Gbus[0]]  ## unclipped

    lao_X = p2[G[5], 1] / bus.lam_P[Gbus[5]]
    fro_X = p2[G[5], 2] / bus.lam_P[Gbus[5]]
    lab_X = p2[L[2], 1] / (bus.lam_P[Lbus[2]] + Qfudge[L[2], 0])
    frb_X = p2[L[1], 1] / (bus.lam_P[Lbus[1]] + Qfudge[L[1], 0])

    t_is(lao_X, 0.8389, 4, 'lao_X')
    t_is(fro_X, 1.0487, 4, 'fro_X')
    t_is(lab_X, 1, 4, 'lab_X')
    t_is(frb_X, 0.8569, 4, 'frb_X')

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1110, 100, [], [], mpopt)
    cp1 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 65, 8, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp_lam[G[1:6], :] * lao_X, 8, [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp_lam[L, :] * lao_X, 8, [t, ' : load prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1120, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 65, 8, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp_lam[G[1:6], :] * fro_X, 8, [t, ' : gen 2-6 prices'])
    t_is(cp[L[0:2], :], cp_lam[L[0:2], :] * fro_X, 8,
         [t, ' : load 1-2 prices'])
    t_is(cp[L[2], :], 60, 8, [t, ' : load 3 price'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1130, 100, [], [], mpopt)
    cp3 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 65, 8, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp_lam[G[1:6], :], 6, [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp_lam[L, :], 6, [t, ' : load prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1140, 100, [], [], mpopt)
    cp4 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 65, 5, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp5[G[1:6], :] * frb_X, 8, [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp5[L, :] * frb_X, 8, [t, ' : load prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp4, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1170, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G[0], :], 65, 4, [t, ' : gen 1 price'])
    t_is(cp[G[1:6], :], cp_lam[G[1:6], :] * (lao_X + lab_X) / 2, 8,
         [t, ' : gen 2-6 prices'])
    t_is(cp[L, :], cp_lam[L, :] * (lao_X + lab_X) / 2, 8,
         [t, ' : load prices'])
    t_is(cp, (cp1 + cp3) / 2, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 8'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1180, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp1[G, :], 8, [t, ' : prices'])
    t_is(cp[L, :], cp3[L, :], 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal bid @ $60, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1100, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, p2, 8, [t, ' : prices'])

    ##-----  gen 1 at Pmin, gen 6 block 3 marginal @ $60  -----
    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 5'
    p2[L, :] = array([[100, 100, 100], [100, 0, 0], [100, 100, 0]])
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1150, 100, [], [], mpopt)
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)

    t_is(cp[G[0], :], 65, 4, [t, ' : gen 1 price'])
    t_is(cp[G[1], :], 57.1612, 4, [t, ' : gen 2 price'])
    cq5 = cq.copy()
    cp5 = cp.copy()
    cp_lam = cp5.copy()
    cp_lam[0, :] = bus.lamP[Gbus[0]]  ## unclipped

    lao_X = p2[G[5], 2] / bus.lam_P[Gbus[5]]
    fro_X = p2[G[0], 2] / bus.lam_P[Gbus[0]]
    lab_X = p2[L[2], 1] / (bus.lam_P[Lbus[2]] + Qfudge[L[2], 0])
    frb_X = p2[L[1], 1] / (bus.lam_P[Lbus[1]] + Qfudge[L[1], 0])

    t_is(lao_X, 1, 4, 'lao_X')
    t_is(fro_X, 1.1425, 4, 'fro_X')
    t_is(lab_X, 1.5813, 4, 'lab_X')
    t_is(frb_X, 0, 4, 'frb_X')

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1110, 100, [], [], mpopt)
    cp1 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp5, 6, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1120, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp_lam * fro_X, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1130, 100, [], [], mpopt)
    cp3 = cp.copy()
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp_lam * lab_X, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1140, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, 0], [654042444660], 4, [t, ' : gen prices'])
    t_is(cp[L, :], cp_lam[L, :] * frb_X, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1160, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp_lam * fro_X, 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1170, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, cp_lam * (lao_X + lab_X) / 2, 8, [t, ' : prices'])
    t_is(cp, (cp_lam + cp3) / 2, 7, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 8'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1180, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp[G, :], cp5[G, :], 7, [t, ' : prices'])
    t_is(cp[L, :], cp3[L, :], 8, [t, ' : prices'])

    t = 'gen 1 @ Pmin, marginal offer @ $60, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p2, 1100, 100, [], [], mpopt)
    t_is(cq, cq5, 8, [t, ' : quantities'])
    t_is(cp, p2, 8, [t, ' : prices'])

    ##-----  gen 2 decommitted, one offer block marginal @ $60  -----
    p[G[1], :] = p[G[1], :] + 100

    t = 'price of decommited gen, auction_type = 5'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1150, 200, [], [], mpopt)
    cp5 = cp.copy()
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)
    t_is(sum(cq[1, :]), 0, 8, t)
    t_is(cp[1, 0], 59.194, 3, t)

    # Xo = p[0:6, :] / (diag(bus.lam_P[Gbus]) * ones(p[G, :].shape))
    # ao = (cq[0:6, :] != 0)
    # ro = (cq[0:6, :] == 0)
    # Xb = p[6:9, :] / (diag(bus.lam_P[Lbus] + gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(p[L, :].shape))
    # ab = (cq[6:9, :] != 0)
    # rb = (cq[6:9, :] == 0)
    # aXo = ao * Xo
    # rXo = ro * Xo
    # aXb = ab * Xb
    # rXb = rb * Xb

    lao_X = p[G[5], 2] / bus.lam_P[Gbus[5]]
    fro_X = p[G[0], 2] / bus.lam_P[Gbus[0]]
    lab_X = p[L[0], 1] / (bus.lam_P[Lbus[0]] + Qfudge[L[0], 0])
    frb_X = p[L[0], 2] / (bus.lam_P[Lbus[0]] + Qfudge[L[0], 0])

    t_is(lao_X, 1, 4, 'lao_X')
    t_is(fro_X, 1.0212, 4, 'fro_X')
    t_is(lab_X, 1.1649, 4, 'lab_X')
    t_is(frb_X, 0.9985, 4, 'frb_X')

    t = 'price of decommited gen, auction_type = 1'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1110, 200, [], [], mpopt)
    t_is(cp[1, 0], 59.194, 3, t)

    t = 'price of decommited gen, auction_type = 2'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1120, 200, [], [], mpopt)
    t_is(cp[1, 0], cp5[1, 0] * fro_X, 3, t)

    t = 'price of decommited gen, auction_type = 3'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1130, 200, [], [], mpopt)
    t_is(cp[1, 0], cp5[1, 0] * lab_X, 3, t)

    t = 'price of decommited gen, auction_type = 4'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1140, 200, [], [], mpopt)
    t_is(cp[1, 0], cp5[1, 0] * frb_X, 3, t)

    t = 'price of decommited gen, auction_type = 6'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1160, 200, [], [], mpopt)
    t_is(cp[1, 0], cp5[1, 0] * fro_X, 3, t)

    t = 'price of decommited gen, auction_type = 7'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1170, 200, [], [], mpopt)
    t_is(cp[1, 0], cp5[1, 0] * (lao_X + lab_X) / 2, 3, t)

    t = 'price of decommited gen, auction_type = 0'
    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1100, 200, [], [], mpopt)
    t_is(cp[1, 0], 120, 3, t)

    t = 'single block, marginal offer @ $50, auction_type = 5'
    q = array([[60], [36], [36], [36], [36], [36], [30], [10], [20]])

    p = array([[50], [40], [42], [44], [46], [48], [100], [100], [100]])

    MVAbase, cq, cp, bus, gen, gencost, branch, f, dispatch, success, et = \
        runmkt('t_auction_case', q, p, 1150, 100, [], [], mpopt)
    t_is(cq[G[0]], 35.32, 2, t)
    t_is(cq[G[1:6]], q[G[1:6]], 8, [t, ' : gen qtys'])
    t_is(cp[G[0]], 50, 4, t)
    t_is(cq[L], q[L], 8, [t, ' : load qtys'])
    t_is(cp[L[1], :], 54.03, 2, t)
    t_is(cp[G], bus.lam_P[Gbus], 8, [t, ' : gen prices'])
    Qfudge = zeros(p.shape)
    Qfudge[L, :] = diag(gen.Qg[L] / gen.Pg[L] * bus.lam_Q[Lbus]) * ones(
        p[L, :].shape)
    t_is(cp[L], bus.lam_P[Lbus] + Qfudge[L, 0], 8, [t, ' : load prices'])

    t_end()
Example #51
0
def pips(f_fcn,
         x0=None,
         A=None,
         l=None,
         u=None,
         xmin=None,
         xmax=None,
         gh_fcn=None,
         hess_fcn=None,
         opt=None):
    """Primal-dual interior point method for NLP (nonlinear programming).
    Minimize a function F(X) beginning from a starting point M{x0}, subject to
    optional linear and nonlinear constraints and variable bounds::

            min f(x)
             x

    subject to::

            g(x) = 0            (nonlinear equalities)
            h(x) <= 0           (nonlinear inequalities)
            l <= A*x <= u       (linear constraints)
            xmin <= x <= xmax   (variable bounds)

    Note: The calling syntax is almost identical to that of FMINCON from
    MathWorks' Optimization Toolbox. The main difference is that the linear
    constraints are specified with C{A}, C{L}, C{U} instead of C{A}, C{B},
    C{Aeq}, C{Beq}. The functions for evaluating the objective function,
    constraints and Hessian are identical.

    Example from U{http://en.wikipedia.org/wiki/Nonlinear_programming}:
        >>> from numpy import array, r_, float64, dot
        >>> from scipy.sparse import csr_matrix
        >>> def f2(x):
        ...     f = -x[0] * x[1] - x[1] * x[2]
        ...     df = -r_[x[1], x[0] + x[2], x[1]]
        ...     # actually not used since 'hess_fcn' is provided
        ...     d2f = -array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], float64)
        ...     return f, df, d2f
        >>> def gh2(x):
        ...     h = dot(array([[1, -1, 1],
        ...                    [1,  1, 1]]), x**2) + array([-2.0, -10.0])
        ...     dh = 2 * csr_matrix(array([[ x[0], x[0]],
        ...                                [-x[1], x[1]],
        ...                                [ x[2], x[2]]]))
        ...     g = array([])
        ...     dg = None
        ...     return h, g, dh, dg
        >>> def hess2(x, lam, cost_mult=1):
        ...     mu = lam["ineqnonlin"]
        ...     a = r_[dot(2 * array([1, 1]), mu), -1, 0]
        ...     b = r_[-1, dot(2 * array([-1, 1]), mu),-1]
        ...     c = r_[0, -1, dot(2 * array([1, 1]), mu)]
        ...     Lxx = csr_matrix(array([a, b, c]))
        ...     return Lxx
        >>> x0 = array([1, 1, 0], float64)
        >>> solution = pips(f2, x0, gh_fcn=gh2, hess_fcn=hess2)
        >>> round(solution["f"], 11) == -7.07106725919
        True
        >>> solution["output"]["iterations"]
        8

    Ported by Richard Lincoln from the MATLAB Interior Point Solver (MIPS)
    (v1.9) by Ray Zimmerman.  MIPS is distributed as part of the MATPOWER
    project, developed at the Power System Engineering Research Center (PSERC) (PSERC),
    Cornell. See U{http://www.pserc.cornell.edu/matpower/} for more info.
    MIPS was ported by Ray Zimmerman from C code written by H. Wang for his
    PhD dissertation:
      - "On the Computation and Application of Multi-period
        Security-Constrained Optimal Power Flow for Real-time
        Electricity Market Operations", Cornell University, May 2007.

    See also:
      - H. Wang, C. E. Murillo-Sanchez, R. D. Zimmerman, R. J. Thomas,
        "On Computational Issues of Market-Based Optimal Power Flow",
        IEEE Transactions on Power Systems, Vol. 22, No. 3, Aug. 2007,
        pp. 1185-1193.

    All parameters are optional except C{f_fcn} and C{x0}.
    @param f_fcn: Function that evaluates the objective function, its gradients
                  and Hessian for a given value of M{x}. If there are
                  nonlinear constraints, the Hessian information is provided
                  by the 'hess_fcn' argument and is not required here.
    @type f_fcn: callable
    @param x0: Starting value of optimization vector M{x}.
    @type x0: array
    @param A: Optional linear constraints.
    @type A: csr_matrix
    @param l: Optional linear constraints. Default values are M{-Inf}.
    @type l: array
    @param u: Optional linear constraints. Default values are M{Inf}.
    @type u: array
    @param xmin: Optional lower bounds on the M{x} variables, defaults are
                 M{-Inf}.
    @type xmin: array
    @param xmax: Optional upper bounds on the M{x} variables, defaults are
                 M{Inf}.
    @type xmax: array
    @param gh_fcn: Function that evaluates the optional nonlinear constraints
                   and their gradients for a given value of M{x}.
    @type gh_fcn: callable
    @param hess_fcn: Handle to function that computes the Hessian of the
                     Lagrangian for given values of M{x}, M{lambda} and M{mu},
                     where M{lambda} and M{mu} are the multipliers on the
                     equality and inequality constraints, M{g} and M{h},
                     respectively.
    @type hess_fcn: callable
    @param opt: optional options dictionary with the following keys, all of
                which are also optional (default values shown in parentheses)
                  - C{verbose} (False) - Controls level of progress output
                    displayed
                  - C{feastol} (1e-6) - termination tolerance for feasibility
                    condition
                  - C{gradtol} (1e-6) - termination tolerance for gradient
                    condition
                  - C{comptol} (1e-6) - termination tolerance for
                    complementarity condition
                  - C{costtol} (1e-6) - termination tolerance for cost
                    condition
                  - C{max_it} (150) - maximum number of iterations
                  - C{step_control} (False) - set to True to enable step-size
                    control
                  - C{max_red} (20) - maximum number of step-size reductions if
                    step-control is on
                  - C{cost_mult} (1.0) - cost multiplier used to scale the
                    objective function for improved conditioning. Note: This
                    value is also passed as the 3rd argument to the Hessian
                    evaluation function so that it can appropriately scale the
                    objective function term in the Hessian of the Lagrangian.
    @type opt: dict

    @rtype: dict
    @return: The solution dictionary has the following keys:
               - C{x} - solution vector
               - C{f} - final objective function value
               - C{converged} - exit status
                   - True = first order optimality conditions satisfied
                   - False = maximum number of iterations reached
                   - None = numerically failed
               - C{output} - output dictionary with keys:
                   - C{iterations} - number of iterations performed
                   - C{hist} - list of arrays with trajectories of the
                     following: feascond, gradcond, compcond, costcond, gamma,
                     stepsize, obj, alphap, alphad
                   - C{message} - exit message
               - C{lmbda} - dictionary containing the Langrange and Kuhn-Tucker
                 multipliers on the constraints, with keys:
                   - C{eqnonlin} - nonlinear equality constraints
                   - C{ineqnonlin} - nonlinear inequality constraints
                   - C{mu_l} - lower (left-hand) limit on linear constraints
                   - C{mu_u} - upper (right-hand) limit on linear constraints
                   - C{lower} - lower bound on optimization variables
                   - C{upper} - upper bound on optimization variables

    @see: U{http://www.pserc.cornell.edu/matpower/}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    if isinstance(f_fcn, dict):  ## problem dict
        p = f_fcn
        f_fcn = p['f_fcn']
        x0 = p['x0']
        if 'opt' in p: opt = p['opt']
        if 'hess_fcn' in p: hess_fcn = p['hess_fcn']
        if 'gh_fcn' in p: gh_fcn = p['gh_fcn']
        if 'xmax' in p: xmax = p['xmax']
        if 'xmin' in p: xmin = p['xmin']
        if 'u' in p: u = p['u']
        if 'l' in p: l = p['l']
        if 'A' in p: A = p['A']

    nx = x0.shape[0]  # number of variables
    nA = A.shape[0] if A is not None else 0  # number of original linear constr

    # default argument values
    if l is None or len(l) == 0: l = -Inf * ones(nA)
    if u is None or len(u) == 0: u = Inf * ones(nA)
    if xmin is None or len(xmin) == 0: xmin = -Inf * ones(x0.shape[0])
    if xmax is None or len(xmax) == 0: xmax = Inf * ones(x0.shape[0])
    if gh_fcn is None:
        nonlinear = False
        gn = array([])
        hn = array([])
    else:
        nonlinear = True

    if opt is None: opt = {}
    # options
    if "feastol" not in opt:
        opt["feastol"] = 1e-06
    if "gradtol" not in opt:
        opt["gradtol"] = 1e-06
    if "comptol" not in opt:
        opt["comptol"] = 1e-06
    if "costtol" not in opt:
        opt["costtol"] = 1e-06
    if "max_it" not in opt:
        opt["max_it"] = 150
    if "max_red" not in opt:
        opt["max_red"] = 20
    if "step_control" not in opt:
        opt["step_control"] = False
    if "cost_mult" not in opt:
        opt["cost_mult"] = 1
    if "verbose" not in opt:
        opt["verbose"] = 0

    # initialize history
    hist = []

    # constants
    xi = 0.99995
    sigma = 0.1
    z0 = 1
    alpha_min = 1e-8
    rho_min = 0.95
    rho_max = 1.05
    mu_threshold = 1e-5

    # initialize
    i = 0  # iteration counter
    converged = False  # flag
    eflag = False  # exit flag

    # add var limits to linear constraints
    eyex = eye(nx, nx, format="csr")
    AA = eyex if A is None else vstack([eyex, A], "csr")
    ll = r_[xmin, l]
    uu = r_[xmax, u]

    # split up linear constraints
    ieq = find(absolute(uu - ll) <= EPS)
    igt = find((uu >= 1e10) & (ll > -1e10))
    ilt = find((ll <= -1e10) & (uu < 1e10))
    ibx = find((absolute(uu - ll) > EPS) & (uu < 1e10) & (ll > -1e10))
    # zero-sized sparse matrices unsupported
    Ae = AA[ieq, :] if len(ieq) else None
    if len(ilt) or len(igt) or len(ibx):
        idxs = [(1, ilt), (-1, igt), (1, ibx), (-1, ibx)]
        Ai = vstack([sig * AA[idx, :] for sig, idx in idxs if len(idx)], 'csr')
    else:
        Ai = None
    be = uu[ieq]
    bi = r_[uu[ilt], -ll[igt], uu[ibx], -ll[ibx]]

    # evaluate cost f(x0) and constraints g(x0), h(x0)
    x = x0
    f, df = f_fcn(x)  # cost
    f = f * opt["cost_mult"]
    df = df * opt["cost_mult"]
    if nonlinear:
        hn, gn, dhn, dgn = gh_fcn(x)  # nonlinear constraints
        h = hn if Ai is None else r_[hn, Ai * x - bi]  # inequality constraints
        g = gn if Ae is None else r_[gn, Ae * x - be]  # equality constraints

        if (dhn is None) and (Ai is None):
            dh = None
        elif dhn is None:
            dh = Ai.T
        elif Ai is None:
            dh = dhn
        else:
            dh = hstack([dhn, Ai.T])

        if (dgn is None) and (Ae is None):
            dg = None
        elif dgn is None:
            dg = Ae.T
        elif Ae is None:
            dg = dgn
        else:
            dg = hstack([dgn, Ae.T])
    else:
        h = -bi if Ai is None else Ai * x - bi  # inequality constraints
        g = -be if Ae is None else Ae * x - be  # equality constraints
        dh = None if Ai is None else Ai.T  # 1st derivative of inequalities
        dg = None if Ae is None else Ae.T  # 1st derivative of equalities

    # some dimensions
    neq = g.shape[0]  # number of equality constraints
    niq = h.shape[0]  # number of inequality constraints
    neqnln = gn.shape[0]  # number of nonlinear equality constraints
    niqnln = hn.shape[0]  # number of nonlinear inequality constraints
    nlt = len(ilt)  # number of upper bounded linear inequalities
    ngt = len(igt)  # number of lower bounded linear inequalities
    nbx = len(ibx)  # number of doubly bounded linear inequalities

    # initialize gamma, lam, mu, z, e
    gamma = 1  # barrier coefficient
    lam = zeros(neq)
    z = z0 * ones(niq)
    mu = z0 * ones(niq)
    k = find(h < -z0)
    z[k] = -h[k]
    k = find((gamma / z) > z0)
    mu[k] = gamma / z[k]
    e = ones(niq)

    # check tolerance
    f0 = f
    if opt["step_control"]:
        L = f + dot(lam, g) + dot(mu, h + z) - gamma * sum(log(z))

    Lx = df.copy()
    Lx = Lx + dg * lam if dg is not None else Lx
    Lx = Lx + dh * mu if dh is not None else Lx

    maxh = zeros(1) if len(h) == 0 else max(h)

    gnorm = norm(g, Inf) if len(g) else 0.0
    lam_norm = norm(lam, Inf) if len(lam) else 0.0
    mu_norm = norm(mu, Inf) if len(mu) else 0.0
    znorm = norm(z, Inf) if len(z) else 0.0
    feascond = \
        max([gnorm, maxh]) / (1 + max([norm(x, Inf), znorm]))
    gradcond = \
        norm(Lx, Inf) / (1 + max([lam_norm, mu_norm]))
    compcond = dot(z, mu) / (1 + norm(x, Inf))
    costcond = absolute(f - f0) / (1 + absolute(f0))

    # save history
    hist.append({
        'feascond': feascond,
        'gradcond': gradcond,
        'compcond': compcond,
        'costcond': costcond,
        'gamma': gamma,
        'stepsize': 0,
        'obj': f / opt["cost_mult"],
        'alphap': 0,
        'alphad': 0
    })

    if opt["verbose"]:
        s = '-sc' if opt["step_control"] else ''
        v = pipsver('all')
        print(('Python Interior Point Solver - PIPS%s, Version %s, %s' %
               (s, v['Version'], v['Date'])))
        if opt['verbose'] > 1:
            print(" it    objective   step size   feascond     gradcond     "
                  "compcond     costcond  ")
            print("----  ------------ --------- ------------ ------------ "
                  "------------ ------------")
            print(("%3d  %12.8g %10s %12g %12g %12g %12g" %
                   (i, (f / opt["cost_mult"]), "", feascond, gradcond,
                    compcond, costcond)))

    if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
        compcond < opt["comptol"] and costcond < opt["costtol"]:
        converged = True
        if opt["verbose"]:
            print("Converged!")

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

        # compute update step
        lmbda = {
            "eqnonlin": lam[list(range(neqnln))],
            "ineqnonlin": mu[list(range(niqnln))]
        }
        if nonlinear:
            if hess_fcn is None:
                print("pips: Hessian evaluation via finite differences "
                      "not yet implemented.\nPlease provide "
                      "your own hessian evaluation function.")
            Lxx = hess_fcn(x, lmbda, opt["cost_mult"])
        else:
            _, _, d2f = f_fcn(x, True)  # cost
            Lxx = d2f * opt["cost_mult"]
        rz = list(range(len(z)))
        zinvdiag = sparse((1.0 / z, (rz, rz))) if len(z) else None
        rmu = list(range(len(mu)))
        mudiag = sparse((mu, (rmu, rmu))) if len(mu) else None
        dh_zinv = None if dh is None else dh * zinvdiag
        M = Lxx if dh is None else Lxx + dh_zinv * mudiag * dh.T
        N = Lx if dh is None else Lx + dh_zinv * (mudiag * h + gamma * e)

        Ab = sparse(M) if dg is None else vstack(
            [hstack([M, dg]),
             hstack([dg.T, sparse((neq, neq))])])
        bb = r_[-N, -g]

        dxdlam = spsolve(Ab.tocsr(), bb)

        if any(isnan(dxdlam)):
            if opt["verbose"]:
                print('\nNumerically Failed\n')
            eflag = -1
            break

        dx = dxdlam[:nx]
        dlam = dxdlam[nx:nx + neq]
        dz = -h - z if dh is None else -h - z - dh.T * dx
        dmu = -mu if dh is None else -mu + zinvdiag * (gamma * e - mudiag * dz)

        # optional step-size control
        sc = False
        if opt["step_control"]:
            x1 = x + dx

            # evaluate cost, constraints, derivatives at x1
            f1, df1 = f_fcn(x1)  # cost
            f1 = f1 * opt["cost_mult"]
            df1 = df1 * opt["cost_mult"]
            if nonlinear:
                hn1, gn1, dhn1, dgn1 = gh_fcn(x1)  # nonlinear constraints

                h1 = hn1 if Ai is None else r_[hn1,
                                               Ai * x1 - bi]  # ieq constraints
                g1 = gn1 if Ae is None else r_[gn1,
                                               Ae * x1 - be]  # eq constraints

                # 1st der of ieq
                if (dhn1 is None) and (Ai is None):
                    dh1 = None
                elif dhn1 is None:
                    dh1 = Ai.T
                elif Ai is None:
                    dh1 = dhn1
                else:
                    dh1 = hstack([dhn1, Ai.T])

                # 1st der of eqs
                if (dgn1 is None) and (Ae is None):
                    dg1 = None
                elif dgn is None:
                    dg1 = Ae.T
                elif Ae is None:
                    dg1 = dgn1
                else:
                    dg1 = hstack([dgn1, Ae.T])
            else:
                h1 = -bi if Ai is None else Ai * x1 - bi  # inequality constraints
                g1 = -be if Ae is None else Ae * x1 - be  # equality constraints

                dh1 = dh  ## 1st derivative of inequalities
                dg1 = dg  ## 1st derivative of equalities

            # check tolerance
            Lx1 = df1
            Lx1 = Lx1 + dg1 * lam if dg1 is not None else Lx1
            Lx1 = Lx1 + dh1 * mu if dh1 is not None else Lx1

            maxh1 = zeros(1) if len(h1) == 0 else max(h1)

            g1norm = norm(g1, Inf) if len(g1) else 0.0
            lam1_norm = norm(lam, Inf) if len(lam) else 0.0
            mu1_norm = norm(mu, Inf) if len(mu) else 0.0
            z1norm = norm(z, Inf) if len(z) else 0.0

            feascond1 = max([ g1norm, maxh1 ]) / \
                (1 + max([ norm(x1, Inf), z1norm ]))
            gradcond1 = norm(Lx1, Inf) / (1 + max([lam1_norm, mu1_norm]))

            if (feascond1 > feascond) and (gradcond1 > gradcond):
                sc = True
        if sc:
            alpha = 1.0
            for j in range(opt["max_red"]):
                dx1 = alpha * dx
                x1 = x + dx1
                f1, _ = f_fcn(x1)  # cost
                f1 = f1 * opt["cost_mult"]
                if nonlinear:
                    hn1, gn1, _, _ = gh_fcn(x1)  # nonlinear constraints
                    h1 = hn1 if Ai is None else r_[
                        hn1, Ai * x1 - bi]  # inequality constraints
                    g1 = gn1 if Ae is None else r_[gn1, Ae * x1 -
                                                   be]  # equality constraints
                else:
                    h1 = -bi if Ai is None else Ai * x1 - bi  # inequality constraints
                    g1 = -be if Ae is None else Ae * x1 - be  # equality constraints

                L1 = f1 + dot(lam, g1) + dot(mu, h1 + z) - gamma * sum(log(z))

                if opt["verbose"] > 2:
                    print(("   %3d            %10.5f" % (-j, norm(dx1))))

                rho = (L1 - L) / (dot(Lx, dx1) + 0.5 * dot(dx1, Lxx * dx1))

                if (rho > rho_min) and (rho < rho_max):
                    break
                else:
                    alpha = alpha / 2.0
            dx = alpha * dx
            dz = alpha * dz
            dlam = alpha * dlam
            dmu = alpha * dmu

        # do the update
        k = find(dz < 0.0)
        alphap = min([xi * min(z[k] / -dz[k]), 1]) if len(k) else 1.0
        k = find(dmu < 0.0)
        alphad = min([xi * min(mu[k] / -dmu[k]), 1]) if len(k) else 1.0
        x = x + alphap * dx
        z = z + alphap * dz
        lam = lam + alphad * dlam
        mu = mu + alphad * dmu
        if niq > 0:
            gamma = sigma * dot(z, mu) / niq

        # evaluate cost, constraints, derivatives
        f, df = f_fcn(x)  # cost
        f = f * opt["cost_mult"]
        df = df * opt["cost_mult"]
        if nonlinear:
            hn, gn, dhn, dgn = gh_fcn(x)  # nln constraints
            #            g = gn if Ai is None else r_[gn, Ai * x - bi] # ieq constraints
            #            h = hn if Ae is None else r_[hn, Ae * x - be] # eq constraints
            h = hn if Ai is None else r_[hn, Ai * x - bi]  # ieq constr
            g = gn if Ae is None else r_[gn, Ae * x - be]  # eq constr

            if (dhn is None) and (Ai is None):
                dh = None
            elif dhn is None:
                dh = Ai.T
            elif Ai is None:
                dh = dhn
            else:
                dh = hstack([dhn, Ai.T])

            if (dgn is None) and (Ae is None):
                dg = None
            elif dgn is None:
                dg = Ae.T
            elif Ae is None:
                dg = dgn
            else:
                dg = hstack([dgn, Ae.T])
        else:
            h = -bi if Ai is None else Ai * x - bi  # inequality constraints
            g = -be if Ae is None else Ae * x - be  # equality constraints
            # 1st derivatives are constant, still dh = Ai.T, dg = Ae.T

        Lx = df
        Lx = Lx + dg * lam if dg is not None else Lx
        Lx = Lx + dh * mu if dh is not None else Lx

        if len(h) == 0:
            maxh = zeros(1)
        else:
            maxh = max(h)

        gnorm = norm(g, Inf) if len(g) else 0.0
        lam_norm = norm(lam, Inf) if len(lam) else 0.0
        mu_norm = norm(mu, Inf) if len(mu) else 0.0
        znorm = norm(z, Inf) if len(z) else 0.0
        feascond = \
            max([gnorm, maxh]) / (1 + max([norm(x, Inf), znorm]))
        gradcond = \
            norm(Lx, Inf) / (1 + max([lam_norm, mu_norm]))
        compcond = dot(z, mu) / (1 + norm(x, Inf))
        costcond = float(absolute(f - f0) / (1 + absolute(f0)))

        hist.append({
            'feascond': feascond,
            'gradcond': gradcond,
            'compcond': compcond,
            'costcond': costcond,
            'gamma': gamma,
            'stepsize': norm(dx),
            'obj': f / opt["cost_mult"],
            'alphap': alphap,
            'alphad': alphad
        })

        if opt["verbose"] > 1:
            print(("%3d  %12.8g %10.5g %12g %12g %12g %12g" %
                   (i, (f / opt["cost_mult"]), norm(dx), feascond, gradcond,
                    compcond, costcond)))

        if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
            compcond < opt["comptol"] and costcond < opt["costtol"]:
            converged = True
            if opt["verbose"]:
                print("Converged!")
        else:
            if any(isnan(x)) or (alphap < alpha_min) or \
                (alphad < alpha_min) or (gamma < EPS) or (gamma > 1.0 / EPS):
                if opt["verbose"]:
                    print("Numerically failed.")
                eflag = -1
                break
            f0 = f

            if opt["step_control"]:
                L = f + dot(lam, g) + dot(mu, (h + z)) - gamma * sum(log(z))

    if opt["verbose"]:
        if not converged:
            print(("Did not converge in %d iterations." % i))

    # package results
    if eflag != -1:
        eflag = converged

    if eflag == 0:
        message = 'Did not converge'
    elif eflag == 1:
        message = 'Converged'
    elif eflag == -1:
        message = 'Numerically failed'
    else:
        raise

    output = {"iterations": i, "hist": hist, "message": message}

    # zero out multipliers on non-binding constraints
    mu[find((h < -opt["feastol"]) & (mu < mu_threshold))] = 0.0

    # un-scale cost and prices
    f = f / opt["cost_mult"]
    lam = lam / opt["cost_mult"]
    mu = mu / opt["cost_mult"]

    # re-package multipliers into struct
    lam_lin = lam[neqnln:neq]  # lambda for linear constraints
    mu_lin = mu[niqnln:niq]  # mu for linear constraints
    kl = find(lam_lin < 0.0)  # lower bound binding
    ku = find(lam_lin > 0.0)  # upper bound binding

    mu_l = zeros(nx + nA)
    mu_l[ieq[kl]] = -lam_lin[kl]
    mu_l[igt] = mu_lin[nlt:nlt + ngt]
    mu_l[ibx] = mu_lin[nlt + ngt + nbx:nlt + ngt + nbx + nbx]

    mu_u = zeros(nx + nA)
    mu_u[ieq[ku]] = lam_lin[ku]
    mu_u[ilt] = mu_lin[:nlt]
    mu_u[ibx] = mu_lin[nlt + ngt:nlt + ngt + nbx]

    lmbda = {
        'mu_l': mu_l[nx:],
        'mu_u': mu_u[nx:],
        'lower': mu_l[:nx],
        'upper': mu_u[:nx]
    }

    if niqnln > 0:
        lmbda['ineqnonlin'] = mu[:niqnln]
    if neqnln > 0:
        lmbda['eqnonlin'] = lam[:neqnln]


#    lmbda = {"eqnonlin": lam[:neqnln], 'ineqnonlin': mu[:niqnln],
#             "mu_l": mu_l[nx:], "mu_u": mu_u[nx:],
#             "lower": mu_l[:nx], "upper": mu_u[:nx]}

    solution = {
        "x": x,
        "f": f,
        "eflag": converged,
        "output": output,
        "lmbda": lmbda
    }

    return solution
Example #52
0
def run_inversion(home,
                  project_name,
                  run_name,
                  fault_name,
                  model_name,
                  GF_list,
                  G_from_file,
                  G_name,
                  epicenter,
                  rupture_speed,
                  num_windows,
                  reg_spatial,
                  reg_temporal,
                  nfaults,
                  beta,
                  decimate,
                  bandpass,
                  solver,
                  bounds,
                  weight=False,
                  Ltype=2,
                  target_moment=None,
                  data_vector=None,
                  onset_file=None):
    '''
    Assemble G and d, determine smoothing and run the inversion
    '''
    from mudpy import inverse as inv
    from mudpy.forward import get_mu_and_area
    from numpy import zeros, dot, array, squeeze, expand_dims, empty, tile, eye, ones, arange, load, size, genfromtxt
    from numpy import where, sort, r_
    from numpy.linalg import lstsq
    from scipy.sparse import csr_matrix as sparse
    from scipy.optimize import nnls
    from datetime import datetime
    import gc
    from matplotlib import path

    t1 = datetime.now()
    #Get data vector
    if data_vector == None:
        d = inv.getdata(home,
                        project_name,
                        GF_list,
                        decimate,
                        bandpass=bandpass)
    else:
        d = load(data_vector)
    #Get GFs
    G = inv.getG(home,
                 project_name,
                 fault_name,
                 model_name,
                 GF_list,
                 G_from_file,
                 G_name,
                 epicenter,
                 rupture_speed,
                 num_windows,
                 decimate,
                 bandpass,
                 onset_file=onset_file)
    print(G.shape)
    gc.collect()
    #Get data weights
    if weight == True:
        print('Applying data weights')
        w = inv.get_data_weights(home, project_name, GF_list, d, decimate)
        W = empty(G.shape)
        W = tile(w, (G.shape[1], 1)).T
        WG = empty(G.shape)
        WG = W * G
        wd = w * d.squeeze()
        wd = expand_dims(wd, axis=1)
        #Clear up extraneous variables
        W = None
        w = None
        #Define inversion quantities
        x = WG.transpose().dot(wd)
        print('Computing G\'G')
        K = (WG.T).dot(WG)
    else:
        #Define inversion quantities if no weightd
        x = G.transpose().dot(d)
        print('Computing G\'G')
        K = (G.T).dot(G)
    #Get regularization matrices (set to 0 matrix if not needed)
    static = False  #Is it jsut a static inversion?
    if size(reg_spatial) > 1:
        if Ltype == 2:  #Laplacian smoothing
            Ls = inv.getLs(home, project_name, fault_name, nfaults,
                           num_windows, bounds)
        elif Ltype == 0:  #Tikhonov smoothing
            N = nfaults[0] * nfaults[
                1] * num_windows * 2  #Get total no. of model parameters
            Ls = eye(N)
        elif Ltype == 3:  #moment regularization
            N = nfaults[0] * nfaults[
                1] * num_windows * 2  #Get total no. of model parameters
            Ls = ones((1, N))
            #Add rigidity and subfault area
            mu, area = get_mu_and_area(home, project_name, fault_name,
                                       model_name)
            istrike = arange(0, N, 2)
            Ls[0, istrike] = area * mu
            idip = arange(1, N, 2)
            Ls[0, idip] = area * mu
            #Modify inversion quantities
            x = x + Ls.T.dot(target_moment)
        else:
            print('ERROR: Unrecognized regularization type requested')
            return
        Ninversion = len(reg_spatial)
    else:
        Ls = zeros(K.shape)
        reg_spatial = array([0.])
        Ninversion = 1
    if size(reg_temporal) > 1:
        Lt = inv.getLt(home, project_name, fault_name, num_windows)
        Ninversion = len(reg_temporal) * Ninversion
    else:
        Lt = zeros(K.shape)
        reg_temporal = array([0.])
        static = True
    #Make L's sparse
    Ls = sparse(Ls)
    Lt = sparse(Lt)
    #Get regularization tranposes for ABIC
    LsLs = Ls.transpose().dot(Ls)
    LtLt = Lt.transpose().dot(Lt)
    #inflate
    Ls = Ls.todense()
    Lt = Lt.todense()
    LsLs = LsLs.todense()
    LtLt = LtLt.todense()
    #off we go
    dt = datetime.now() - t1
    print('Preprocessing wall time was ' + str(dt))
    print('\n--- RUNNING INVERSIONS ---\n')
    ttotal = datetime.now()
    kout = 0
    for kt in range(len(reg_temporal)):
        for ks in range(len(reg_spatial)):
            t1 = datetime.now()
            lambda_spatial = reg_spatial[ks]
            lambda_temporal = reg_temporal[kt]
            print('Running inversion ' + str(kout + 1) + ' of ' +
                  str(Ninversion) + ' at regularization levels: ls =' +
                  repr(lambda_spatial) + ' , lt = ' + repr(lambda_temporal))
            if static == True:  #Only statics inversion no Lt matrix
                Kinv = K + (lambda_spatial**2) * LsLs
                Lt = eye(len(K))
                LtLt = Lt.T.dot(Lt)
            else:  #Mixed inversion
                Kinv = K + (lambda_spatial**2) * LsLs + (lambda_temporal**
                                                         2) * LtLt
            if solver.lower() == 'lstsq':
                sol, res, rank, s = lstsq(Kinv, x)
            elif solver.lower() == 'nnls':
                x = squeeze(x.T)
                try:
                    sol, res = nnls(Kinv, x)
                except:
                    print('+++ WARNING: No solution found, writting zeros.')
                    sol = zeros(G.shape[1])
                x = expand_dims(x, axis=1)
                sol = expand_dims(sol, axis=1)
            else:
                print('ERROR: Unrecognized solver \'' + solver + '\'')

            #Force faults outside a polygon to be zero
            print('WARNING: Using fault polygon to force solutions to zero')
            #load faulkt
            fault = genfromtxt(home + project_name + '/data/model_info/' +
                               fault_name)
            polygon = genfromtxt(
                '/Users/dmelgarm/Oaxaca2020/etc/zero_fault.txt')
            polygon = path.Path(polygon)
            i = where(polygon.contains_points(fault[:, 1:3]) == False)[0]
            i = sort(r_[i * 2, i * 2 + 1])
            N = nfaults[0] * 2
            i = r_[i, i + N, i + 2 * N, i + 3 * N]
            sol[i] = 0

            #Compute synthetics
            ds = dot(G, sol)

            #Get stats
            L2, Lmodel = inv.get_stats(Kinv, sol, x)
            VR, L2data = inv.get_VR(home, project_name, GF_list, sol, d, ds,
                                    decimate, WG, wd)
            #VR=inv.get_VR(WG,sol,wd)
            #ABIC=inv.get_ABIC(WG,K,sol,wd,lambda_spatial,lambda_temporal,Ls,LsLs,Lt,LtLt)
            ABIC = inv.get_ABIC(G, K, sol, d, lambda_spatial, lambda_temporal,
                                Ls, LsLs, Lt, LtLt)
            #Get moment
            Mo, Mw = inv.get_moment(home, project_name, fault_name, model_name,
                                    sol)
            #If a rotational offset was applied then reverse it for output to file
            if beta != 0:
                sol = inv.rot2ds(sol, beta)
            #Write log
            inv.write_log(home, project_name, run_name, kout, rupture_speed,
                          num_windows, lambda_spatial, lambda_temporal, beta,
                          L2, Lmodel, VR, ABIC, Mo, Mw, model_name, fault_name,
                          G_name, GF_list, solver, L2data)
            #Write output to file
            inv.write_synthetics(home, project_name, run_name, GF_list, G, sol,
                                 ds, kout, decimate)
            inv.write_model(home,
                            project_name,
                            run_name,
                            fault_name,
                            model_name,
                            rupture_speed,
                            num_windows,
                            epicenter,
                            sol,
                            kout,
                            onset_file=onset_file)
            kout += 1
            dt1 = datetime.now() - t1
            dt2 = datetime.now() - ttotal
            print('... inversion wall time was ' + str(dt1) +
                  ', total wall time elapsed is ' + str(dt2))
Example #53
0
def qps_cplex(H, c, A, l, u, xmin, xmax, x0, opt):
    """Quadratic Program Solver based on CPLEX.

    A wrapper function providing a PYPOWER standardized interface for using
    C{cplexqp} or C{cplexlp} to solve the following QP (quadratic programming)
    problem::

        min 1/2 X'*H*x + c'*x
         x

    subject to::

        l <= A*x <= u       (linear constraints)
        xmin <= x <= xmax   (variable bounds)

    Inputs (all optional except C{H}, C{c}, C{A} and C{l}):
        - C{H} : matrix (possibly sparse) of quadratic cost coefficients
        - C{c} : vector of linear cost coefficients
        - C{A, l, u} : define the optional linear constraints. Default
        values for the elements of L and U are -Inf and Inf, respectively.
        - C{xmin, xmax} : optional lower and upper bounds on the
        C{x} variables, defaults are -Inf and Inf, respectively.
        - C{x0} : optional starting value of optimization vector C{x}
        - C{opt} : optional options structure with the following fields,
        all of which are also optional (default values shown in parentheses)
            - C{verbose} (0) - controls level of progress output displayed
                - 0 = no progress output
                - 1 = some progress output
                - 2 = verbose progress output
            - C{cplex_opt} - options dict for CPLEX, value in
            verbose overrides these options
        - C{problem} : The inputs can alternatively be supplied in a single
        C{problem} dict with fields corresponding to the input arguments
        described above: C{H, c, A, l, u, xmin, xmax, x0, opt}

    Outputs:
        - C{x} : solution vector
        - C{f} : final objective function value
        - C{exitflag} : CPLEXQP/CPLEXLP exit flag
        (see C{cplexqp} and C{cplexlp} documentation for details)
        - C{output} : CPLEXQP/CPLEXLP output dict
        (see C{cplexqp} and C{cplexlp} documentation for details)
        - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
        multipliers on the constraints, with fields:
            - mu_l - lower (left-hand) limit on linear constraints
            - mu_u - upper (right-hand) limit on linear constraints
            - lower - lower bound on optimization variables
            - upper - upper bound on optimization variables

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    ##----- input argument handling  -----
    ## gather inputs
    if isinstance(H, dict):  ## problem struct
        p = H
        if 'opt' in p: opt = p['opt']
        if 'x0' in p: x0 = p['x0']
        if 'xmax' in p: xmax = p['xmax']
        if 'xmin' in p: xmin = p['xmin']
        if 'u' in p: u = p['u']
        if 'l' in p: l = p['l']
        if 'A' in p: A = p['A']
        if 'c' in p: c = p['c']
        if 'H' in p: H = p['H']
    else:  ## individual args
        assert H is not None
        assert c is not None
        assert A is not None
        assert l is not None

    if opt is None:
        opt = {}
#    if x0 is None:
#        x0 = array([])
#    if xmax is None:
#        xmax = array([])
#    if xmin is None:
#        xmin = array([])

## define nx, set default values for missing optional inputs
    if len(H) == 0 or not any(any(H)):
        if len(A) == 0 and len(xmin) == 0 and len(xmax) == 0:
            stderr.write(
                'qps_cplex: LP problem must include constraints or variable bounds\n'
            )
        else:
            if len(A) > 0:
                nx = shape(A)[1]
            elif len(xmin) > 0:
                nx = len(xmin)
            else:  # if len(xmax) > 0
                nx = len(xmax)
    else:
        nx = shape(H)[0]

    if len(c) == 0:
        c = zeros(nx)

    if  len(A) > 0 and (len(l) == 0 or all(l == -Inf)) and \
                       (len(u) == 0 or all(u ==  Inf)):
        A = None  ## no limits => no linear constraints

    nA = shape(A)[0]  ## number of original linear constraints
    if len(u) == 0:  ## By default, linear inequalities are ...
        u = Inf * ones(nA)  ## ... unbounded above and ...

    if len(l) == 0:
        l = -Inf * ones(nA)  ## ... unbounded below.

    if len(xmin) == 0:  ## By default, optimization variables are ...
        xmin = -Inf * ones(nx)  ## ... unbounded below and ...

    if len(xmax) == 0:
        xmax = Inf * ones(nx)  ## ... unbounded above.

    if len(x0) == 0:
        x0 = zeros(nx)

    ## default options
    if 'verbose' in opt:
        verbose = opt['verbose']
    else:
        verbose = 0

    #if 'max_it' in opt:
    #    max_it = opt['max_it']
    #else:
    #    max_it = 0

    ## split up linear constraints
    ieq = find(abs(u - l) <= EPS)  ## equality
    igt = find(u >= 1e10 & l > -1e10)  ## greater than, unbounded above
    ilt = find(l <= -1e10 & u < 1e10)  ## less than, unbounded below
    ibx = find((abs(u - l) > EPS) & (u < 1e10) & (l > -1e10))
    Ae = A[ieq, :]
    be = u[ieq]
    Ai = r_[A[ilt, :], -A[igt, :], A[ibx, :] - A[ibx, :]]
    bi = r_[u[ilt], -l[igt], u[ibx], -l[ibx]]

    ## grab some dimensions
    nlt = len(ilt)  ## number of upper bounded linear inequalities
    ngt = len(igt)  ## number of lower bounded linear inequalities
    nbx = len(ibx)  ## number of doubly bounded linear inequalities

    ## set up options struct for CPLEX
    if 'cplex_opt' in opt:
        cplex_opt = cplex_options(opt['cplex_opt'])
    else:
        cplex_opt = cplex_options

    cplex = Cplex('null')
    vstr = cplex.getVersion
    s, e, tE, m, t = re.compile(vstr, '(\d+\.\d+)\.')
    vnum = int(t[0][0])
    vrb = max([0, verbose - 1])
    cplex_opt['barrier']['display'] = vrb
    cplex_opt['conflict']['display'] = vrb
    cplex_opt['mip']['display'] = vrb
    cplex_opt['sifting']['display'] = vrb
    cplex_opt['simplex']['display'] = vrb
    cplex_opt['tune']['display'] = vrb
    if vrb and (vnum > 12.2):
        cplex_opt['diagnostics'] = 'on'
    #if max_it:
    #    cplex_opt.    ## not sure what to set here

    if len(Ai) == 0 and len(Ae) == 0:
        unconstrained = 1
        Ae = sparse((1, nx))
        be = 0
    else:
        unconstrained = 0

    ## call the solver
    if verbose:
        methods = [
            'default', 'primal simplex', 'dual simplex', 'network simplex',
            'barrier', 'sifting', 'concurrent'
        ]

    if len(H) == 0 or not any(any(H)):
        if verbose:
            stdout.write('CPLEX Version %s -- %s LP solver\n' %
                         (vstr, methods[cplex_opt['lpmethod'] + 1]))

        x, f, eflag, output, lam = \
            cplexlp(c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)
    else:
        if verbose:
            stdout.write('CPLEX Version %s --  %s QP solver\n' %
                         (vstr, methods[cplex_opt['qpmethod'] + 1]))
        ## ensure H is numerically symmetric
        if H != H.T:
            H = (H + H.T) / 2

        x, f, eflag, output, lam = \
            cplexqp(H, c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)

    ## check for empty results (in case optimization failed)
    if len(x) == 0:
        x = NaN * zeros(nx)

    if len(f) == 0:
        f = NaN

    if len(lam) == 0:
        lam['ineqlin'] = NaN * zeros(len(bi))
        lam['eqlin'] = NaN * zeros(len(be))
        lam['lower'] = NaN * zeros(nx)
        lam['upper'] = NaN * zeros(nx)
        mu_l = NaN * zeros(nA)
        mu_u = NaN * zeros(nA)
    else:
        mu_l = zeros(nA)
        mu_u = zeros(nA)

    if unconstrained:
        lam['eqlin'] = array([])

    ## negate prices depending on version
    if vnum < 12.3:
        lam['eqlin'] = -lam['eqlin']
        lam['ineqlin'] = -lam['ineqlin']

    ## repackage lambdas
    kl = find(lam.eqlin < 0)  ## lower bound binding
    ku = find(lam.eqlin > 0)  ## upper bound binding

    mu_l[ieq[kl]] = -lam['eqlin'][kl]
    mu_l[igt] = lam['ineqlin'][nlt + arange(ngt)]
    mu_l[ibx] = lam['ineqlin'][nlt + ngt + nbx + arange(nbx)]

    mu_u[ieq[ku]] = lam['eqlin'][ku]
    mu_u[ilt] = lam['ineqlin'][:nlt]
    mu_u[ibx] = lam['ineqlin'][nlt + ngt + arange(nbx)]

    lmbda = {
        'mu_l': mu_l,
        'mu_u': mu_u,
        'lower': lam.lower,
        'upper': lam.upper
    }

    return x, f, eflag, output, lmbda
Example #54
0
def total_load(bus, gen=None, load_zone=None, which_type=None):
    """Returns vector of total load in each load zone.

    @param bus: standard C{bus} matrix with C{nb} rows, where the fixed active
    and reactive loads are specified in columns C{PD} and C{QD}

    @param gen: (optional) standard C{gen} matrix with C{ng} rows, where the
    dispatchable loads are specified by columns C{PG}, C{QG}, C{PMIN},
    C{QMIN} and C{QMAX} (in rows for which C{isload(GEN)} returns C{True}).
    If C{gen} is empty, it assumes there are no dispatchable loads.

    @param load_zone: (optional) C{nb} element vector where the value of
    each element is either zero or the index of the load zone
    to which the corresponding bus belongs. If C{load_zone(b) = k}
    then the loads at bus C{b} will added to the values of C{Pd[k]} and
    C{Qd[k]}. If C{load_zone} is empty, the default is defined as the areas
    specified in the C{bus} matrix, i.e. C{load_zone =  bus[:, BUS_AREA]}
    and load will have dimension C{= max(bus[:, BUS_AREA])}. If
    C{load_zone = 'all'}, the result is a scalar with the total system
    load.

    @param which_type: (default is 'BOTH' if C{gen} is provided, else 'FIXED')
        - 'FIXED'        : sum only fixed loads
        - 'DISPATCHABLE' : sum only dispatchable loads
        - 'BOTH'         : sum both fixed and dispatchable loads

    @see: L{scale_load}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    nb = bus.shape[0]  ## number of buses

    if gen is None:
        gen = array([])
    if load_zone is None:
        load_zone = array([], int)

    ## fill out and check which_type
    if len(gen) == 0:
        which_type = 'FIXED'

    if (which_type == None) and (len(gen) > 0):
        which_type = 'BOTH'  ## 'FIXED', 'DISPATCHABLE' or 'BOTH'

    if (which_type[0] != 'F') and (which_type[0] != 'D') and (which_type[0] !=
                                                              'B'):
        stderr.write(
            "total_load: which_type should be 'FIXED, 'DISPATCHABLE or 'BOTH'\n"
        )

    want_Q = True
    want_fixed = (which_type[0] == 'B') | (which_type[0] == 'F')
    want_disp = (which_type[0] == 'B') | (which_type[0] == 'D')

    ## initialize load_zone
    if isinstance(load_zone, str) and (load_zone == 'all'):
        load_zone = ones(nb, int)  ## make a single zone of all buses
    elif len(load_zone) == 0:
        load_zone = bus[:, BUS_AREA].astype(
            int)  ## use areas defined in bus data as zones

    nz = max(load_zone)  ## number of load zones

    ## fixed load at each bus, & initialize dispatchable
    if want_fixed:
        Pdf = bus[:, PD]  ## real power
        if want_Q:
            Qdf = bus[:, QD]  ## reactive power
    else:
        Pdf = zeros(nb)  ## real power
        if want_Q:
            Qdf = zeros(nb)  ## reactive power

    ## dispatchable load at each bus
    if want_disp:  ## need dispatchable
        ng = gen.shape[0]
        is_ld = isload(gen) & (gen[:, GEN_STATUS] > 0)
        ld = find(is_ld)

        ## create map of external bus numbers to bus indices
        i2e = bus[:, BUS_I].astype(int)
        e2i = zeros(max(i2e) + 1)
        e2i[i2e] = arange(nb)

        gbus = gen[:, GEN_BUS].astype(int)
        Cld = sparse((is_ld, (e2i[gbus], arange(ng))), (nb, ng))
        Pdd = -Cld * gen[:, PMIN]  ## real power
        if want_Q:
            Q = zeros(ng)
            Q[ld] = (gen[ld, QMIN] == 0) * gen[ld, QMAX] + \
                    (gen[ld, QMAX] == 0) * gen[ld, QMIN]
            Qdd = -Cld * Q  ## reactive power
    else:
        Pdd = zeros(nb)
        if want_Q:
            Qdd = zeros(nb)

    ## compute load sums
    Pd = zeros(nz)
    if want_Q:
        Qd = zeros(nz)

    for k in range(1, nz + 1):
        idx = find(load_zone == k)
        Pd[k - 1] = sum(Pdf[idx]) + sum(Pdd[idx])
        if want_Q:
            Qd[k - 1] = sum(Qdf[idx]) + sum(Qdd[idx])

    return Pd, Qd
Example #55
0
def t_runmarket(quiet=False):
    """Tests for code in C{runmkt}, C{smartmkt} and C{auction}.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    n_tests = 20

    t_begin(n_tests, quiet)

    try:
        from pypower.extras.smartmarket import runmarket
    except ImportError:
        t_skip(n_tests, 'smartmarket code not available')
        t_end;
        return

    ppc = loadcase('t_auction_case')

    ppopt = ppoption(OPF_ALG=560, OUT_ALL_LIM=1,
                     OUT_BRANCH=0, OUT_SYS_SUM=0)
    ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=1)
    #ppopt = ppoption(ppopt, OUT_GEN=1, OUT_BRANCH=0, OUT_SYS_SUM=0)

    offers = {'P': {}, 'Q': {}}
    bids = {'P': {}, 'Q': {}}

    offers['P']['qty'] = array([
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24],
        [12, 24, 24]
    ])
    offers['P']['prc'] = array([
        [20, 50, 60],
        [20, 40, 70],
        [20, 42, 80],
        [20, 44, 90],
        [20, 46, 75],
        [20, 48, 60]
    ])
    bids['P']['qty'] = array([
        [10, 10, 10],
        [10, 10, 10],
        [10, 10, 10]
    ])
    bids['P']['prc'] = array([
        [100, 70, 60],
#         [100, 64.3, 20],
#         [100, 30.64545, 0],
        [100, 50, 20],
        [100, 60, 50]
    ])

    offers['Q']['qty'] = [ 60, 60, 60, 60, 60, 60, 0, 0, 0 ]
    offers['Q']['prc'] = [ 0, 0, 0, 0, 0, 3, 0, 0, 0 ]
    bids.Q['qty'] = [ 15, 15, 15, 15, 15, 15, 15, 12, 7.5 ]
#     bids.Q['prc'] = [ 0, 0, 0, 0, 0, 0, 0, 83.9056, 0 ]
    bids.Q['prc'] = [ 0, 0, 0, 0, 0, 0, 0, 20, 0 ]

    t = 'marginal Q offer, marginal PQ bid, auction_type = 5'
    mkt = {'auction_type': 5,
                      't': [],
                     'u0': [],
                    'lim': []}
    r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt)
    co5 = co.copy()
    cb5 = cb.copy()

#     [ co['P']['qty'] co['P']['prc'] ]
#     [ cb['P']['qty'] cb['P']['prc'] ]
#     [ co['Q']['qty'] co['Q']['prc'] ]
#     [ cb['Q']['qty'] cb['Q']['prc'] ]

    i2e = r['bus'][:, BUS_I]
    e2i = sparse((max(i2e), 1))
    e2i[i2e] = range(r['bus'].size)
    G = find( isload(r['gen']) == 0 )   ## real generators
    L = find( isload(r['gen']) )        ## dispatchable loads
    Gbus = e2i[r['gen'][G, GEN_BUS]]
    Lbus = e2i[r['gen'][L, GEN_BUS]]

    t_is( co['P']['qty'], ones((6, 1)) * [12, 24, 0], 2, [t, ' : gen P quantities'] )
    t_is( co['P']['prc'][0, :], 50.1578, 3, [t, ' : gen 1 P prices'] )
    t_is( cb['P']['qty'], [[10, 10, 10], [10, 0.196, 0], [10, 10, 0]], 2, [t, ' : load P quantities'] )
    t_is( cb['P']['prc'][1, :], 56.9853, 4, [t, ' : load 2 P price'] )
    t_is( co['P']['prc'][:, 0], r['bus'][Gbus, LAM_P], 8, [t, ' : gen P prices'] )
    t_is( cb['P']['prc'][:, 0], r['bus'][Lbus, LAM_P], 8, [t, ' : load P prices'] )

    t_is( co['Q']['qty'], [4.2722, 11.3723, 14.1472, 22.8939, 36.7886, 12.3375, 0, 0, 0], 2, [t, ' : Q offer quantities'] )
    t_is( co['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q offer prices'] )
    t_is( cb['Q']['qty'], [0, 0, 0, 0, 0, 0, 15, 4.0785, 5], 2, [t, ' : Q bid quantities'] )
    t_is( cb['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q bid prices'] )
    t_is( co['Q']['prc'], r['bus'][[Gbus, Lbus], LAM_Q], 8, [t, ' : Q offer prices'] )
    t_is( cb['Q']['prc'], co['Q']['prc'], 8, [t, ' : Q bid prices'] )

    t = 'marginal Q offer, marginal PQ bid, auction_type = 0'
    mkt['auction_type'] = 0
    r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt)
    t_is( co['P']['qty'], co5['P']['qty'], 8, [t, ' : gen P quantities'] )
    t_is( cb['P']['qty'], cb5['P']['qty'], 8, [t, ' : load P quantities'] )
    t_is( co['P']['prc'], offers['P']['prc'], 8, [t, ' : gen P prices'] )
    t_is( cb['P']['prc'], bids['P']['prc'], 8, [t, ' : load P prices'] )

    t_is( co['Q']['qty'], co5['Q']['qty'], 8, [t, ' : gen Q quantities'] )
    t_is( cb['Q']['qty'], cb5['Q']['qty'], 8, [t, ' : load Q quantities'] )
    t_is( co['Q']['prc'], offers['Q']['prc'], 8, [t, ' : gen Q prices'] )
    t_is( cb['Q']['prc'], bids['Q']['prc'], 8, [t, ' : load Q prices'] )


    t_end
Example #56
0
def run(mpc):
    """
    Gurobi based optimal power flow modelling and solution
    :param mpc: The input case of optimal power flow
    :return: obtained solution
    """
    # Data format
    from pypower.idx_brch import F_BUS, T_BUS, BR_R, BR_X, TAP, SHIFT, BR_STATUS, RATE_A
    from pypower.idx_cost import MODEL, NCOST, PW_LINEAR, COST, POLYNOMIAL
    from pypower.idx_bus import BUS_TYPE, REF, VA, VM, PD, GS, VMAX, VMIN, BUS_I, QD
    from pypower.idx_gen import GEN_BUS, VG, PG, QG, PMAX, PMIN, QMAX, QMIN
    from pypower.ext2int import ext2int

    mpc = ext2int(mpc)
    baseMVA, bus, gen, branch, gencost = mpc["baseMVA"], mpc["bus"], mpc[
        "gen"], mpc["branch"], mpc["gencost"]

    nb = shape(mpc['bus'])[0]  # number of buses
    nl = shape(mpc['branch'])[0]  # number of branches
    ng = shape(mpc['gen'])[0]  # number of dispatchable injections
    f = branch[:, F_BUS]  ## list of "from" buses
    t = branch[:, T_BUS]  ## list of "to" buses
    i = range(nl)  ## double set of row indices
    # Connection matrix
    Cf = sparse((ones(nl), (i, f)), (nl, nb))
    Ct = sparse((ones(nl), (i, t)), (nl, nb))
    Cg = sparse((ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))
    Branch_R = branch[:, BR_R]
    Branch_X = branch[:, BR_X]
    Cf = Cf.T
    Ct = Ct.T
    # Obtain the boundary information

    Slmax = branch[:, RATE_A] / baseMVA
    Pij_l = -Slmax
    Qij_l = -Slmax
    Iij_l = zeros(nl)
    Vm_l = turn_to_power(bus[:, VMIN], 2)
    Pg_l = gen[:, PMIN] / baseMVA
    Qg_l = gen[:, QMIN] / baseMVA

    Pij_u = Slmax
    Qij_u = Slmax
    Iij_u = Slmax
    Vm_u = turn_to_power(bus[:, VMAX], 2)
    Pg_u = 2 * gen[:, PMAX] / baseMVA
    Qg_u = 2 * gen[:, QMAX] / baseMVA
    lx = concatenate([Pij_l, Qij_l, Iij_l, Vm_l, Pg_l, Qg_l])
    ux = concatenate([Pij_u, Qij_u, Iij_u, Vm_u, Pg_u, Qg_u])
    model = Model("OPF")
    # Define the decision variables
    x = {}
    nx = 3 * nl + nb + 2 * ng
    for i in range(nx):
        x[i] = model.addVar(lb=lx[i], ub=ux[i], vtype=GRB.CONTINUOUS)

    # Add system level constraints
    Aeq_p = hstack([
        Ct - Cf,
        zeros((nb, nl)), -diag(Ct * Branch_R) * Ct,
        zeros((nb, nb)), Cg,
        zeros((nb, ng))
    ])
    beq_p = bus[:, PD] / baseMVA
    # Add constraints for each sub system
    Aeq_q = hstack([
        zeros((nb, nl)), Ct - Cf, -diag(Ct * Branch_X) * Ct,
        zeros((nb, nb)),
        zeros((nb, ng)), Cg
    ])
    beq_q = bus[:, QD] / baseMVA
    Aeq_KVL = hstack([
        -2 * diags(Branch_R), -2 * diags(Branch_X),
        diags(turn_to_power(Branch_R, 2)) + diags(turn_to_power(Branch_X, 2)),
        Cf.T - Ct.T,
        zeros((nl, 2 * ng))
    ])
    beq_KVL = zeros(nl)

    Aeq = vstack([Aeq_p, Aeq_q, Aeq_KVL])
    Aeq = Aeq.todense()
    beq = concatenate([beq_p, beq_q, beq_KVL])
    neq = len(beq)

    for i in range(neq):
        expr = 0
        for j in range(nx):
            expr += x[j] * Aeq[i, j]
        model.addConstr(lhs=expr, sense=GRB.EQUAL, rhs=beq[i])

    for i in range(nl):
        model.addConstr(x[i] * x[i] + x[i + nl] * x[i + nl] <=
                        x[i + 2 * nl] * x[f[i] + 3 * nl],
                        name='"rc{0}"'.format(i))

    obj = 0
    for i in range(ng):
        obj += gencost[i, 4] * x[i + 3 * nl + nb] * x[
            i + 3 * nl + nb] * baseMVA * baseMVA + gencost[i, 5] * x[
                i + 3 * nl + nb] * baseMVA + gencost[i, 6]

    model.setObjective(obj)
    model.Params.OutputFlag = 0
    model.Params.LogToConsole = 0
    model.Params.DisplayInterval = 1
    model.optimize()

    xx = []
    for v in model.getVars():
        xx.append(v.x)

    obj = obj.getValue()

    Pij = xx[0:nl]
    Qij = xx[nl + 0:2 * nl]
    Iij = xx[2 * nl:3 * nl]
    Vi = xx[3 * nl:3 * nl + nb]
    Pg = xx[3 * nl + nb:3 * nl + nb + ng]
    Qg = xx[3 * nl + nb + ng:3 * nl + nb + 2 * ng]

    # for i in range(nl):  # branch indexing exchange
    #     if branch[i, F_BUS] > branch[i, T_BUS]:
    #         temp = branch[i, F_BUS]
    #         branch[i, F_BUS] = branch[i, T_BUS]
    #         branch[i, T_BUS] = temp

    f = branch[:, F_BUS]  ## list of "from" buses
    t = branch[:, T_BUS]  ## list of "to" buses
    # i = range(nl)  ## double set of row indices
    area = ancestor_children_generation(f, t, range(nb))
    Pi = Cg * Pg - bus[:, PD] / baseMVA
    Qi = Cg * Qg - bus[:, QD] / baseMVA

    for i in range(nb):
        # If the bus is the root bus, only the children information is required.
        if len(area[i]["Ai"]) == 0:
            print(i)
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]

            print(expr - Pi[i])

            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            print(expr - Qi[i])

        elif len(area[i]["Cbranch"]) == 0:  # This bus is the lead node
            print(i)
            print(Pij[area[i]["Abranch"][0][0]] -
                  Iij[area[i]["Abranch"][0][0]] *
                  Branch_R[area[i]["Abranch"][0][0]] + Pi[i])

            print(Qij[area[i]["Abranch"][0][0]] -
                  Iij[area[i]["Abranch"][0][0]] *
                  Branch_X[area[i]["Abranch"][0][0]] + Qi[i])

            print(Vi[int(area[i]["Ai"][0])] - Vi[i] -
                  2 * Branch_R[area[i]["Abranch"][0][0]] *
                  Pij[area[i]["Abranch"][0][0]] -
                  2 * Branch_X[area[i]["Abranch"][0][0]] *
                  Qij[area[i]["Abranch"][0][0]] +
                  Iij[area[i]["Abranch"][0][0]] *
                  (Branch_R[area[i]["Abranch"][0][0]]**2 +
                   Branch_X[area[i]["Abranch"][0][0]]**2))

            print(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] +
                Qij[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]]
                <= Vi[int(area[i]["Ai"][0])] * Iij[area[i]["Abranch"][0][0]])

        else:
            print(i)
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]
            print(Pij[area[i]["Abranch"][0][0]] -
                  Iij[area[i]["Abranch"][0][0]] *
                  Branch_R[area[i]["Abranch"][0][0]] + Pi[i] - expr)

            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            print(Qij[area[i]["Abranch"][0][0]] -
                  Iij[area[i]["Abranch"][0][0]] *
                  Branch_X[area[i]["Abranch"][0][0]] + Qi[i] - expr)

            print(Vi[int(area[i]["Ai"][0])] - Vi[i] -
                  2 * Branch_R[area[i]["Abranch"][0][0]] *
                  Pij[area[i]["Abranch"][0][0]] -
                  2 * Branch_X[area[i]["Abranch"][0][0]] *
                  Qij[area[i]["Abranch"][0][0]] +
                  Iij[area[i]["Abranch"][0][0]] *
                  (Branch_R[area[i]["Abranch"][0][0]]**2 +
                   Branch_X[area[i]["Abranch"][0][0]]**2))
            print(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] +
                Qij[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]]
                <= Vi[int(area[i]["Ai"][0])] * Iij[area[i]["Abranch"][0][0]])
    obj = 0
    for i in range(ng):
        print(Pg[i] - Pi[int(gen[i, GEN_BUS])] -
              bus[int(gen[i, GEN_BUS]), PD] / baseMVA)
        print(Qg[i] - Qi[int(gen[i, GEN_BUS])] -
              bus[int(gen[i, GEN_BUS]), QD] / baseMVA)
        print(int(gen[i, GEN_BUS]))
        obj += gencost[i, 4] * Pg[i] * Pg[i] * baseMVA * baseMVA + gencost[
            i, 5] * Pg[i] * baseMVA + gencost[i, 6]

    # Connection matrix
    Cg = sparse((ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))
    Branch_R = branch[:, BR_R]
    Branch_X = branch[:, BR_X]

    # Obtain the boundary information

    Slmax = branch[:, RATE_A] / baseMVA

    Pij_l = -Slmax
    Qij_l = -Slmax
    Iij_l = zeros(nl)
    Vm_l = turn_to_power(bus[:, VMIN], 2)
    Pg_l = gen[:, PMIN] / baseMVA
    Qg_l = gen[:, QMIN] / baseMVA
    Pi_l = -bus[:, PD] / baseMVA + Cg * Pg_l / baseMVA
    Qi_l = -bus[:, QD] / baseMVA + Cg * Qg_l / baseMVA

    Pij_u = Slmax
    Qij_u = Slmax
    Iij_u = Slmax
    Vm_u = turn_to_power(bus[:, VMAX], 2)
    Pg_u = 2 * gen[:, PMAX] / baseMVA
    Qg_u = 2 * gen[:, QMAX] / baseMVA
    Pi_u = -bus[:, PD] / baseMVA + Cg * Pg_u  # Boundary error
    Qi_u = -bus[:, QD] / baseMVA + Cg * Qg_u  # Boundary error

    model = Model("OPF")
    # Define the decision variables, compact set
    Pij = {}
    Qij = {}
    Iij = {}
    Vi = {}
    Pg = {}
    Qg = {}
    Pi = {}
    Qi = {}

    for i in range(nl):
        Pij[i] = model.addVar(lb=Pij_l[i],
                              ub=Pij_u[i],
                              vtype=GRB.CONTINUOUS,
                              name="Pij{0}".format(i))
        Qij[i] = model.addVar(lb=Qij_l[i],
                              ub=Qij_u[i],
                              vtype=GRB.CONTINUOUS,
                              name="Qij{0}".format(i))
        Iij[i] = model.addVar(lb=Iij_l[i],
                              ub=Iij_u[i],
                              vtype=GRB.CONTINUOUS,
                              name="Iij{0}".format(i))

    for i in range(nb):
        Vi[i] = model.addVar(lb=Vm_l[i],
                             ub=Vm_u[i],
                             vtype=GRB.CONTINUOUS,
                             name="V{0}".format(i))

    for i in range(ng):
        Pg[i] = model.addVar(lb=Pg_l[i],
                             ub=Pg_u[i],
                             vtype=GRB.CONTINUOUS,
                             name="Pg{0}".format(i))
        Qg[i] = model.addVar(lb=Qg_l[i],
                             ub=Qg_u[i],
                             vtype=GRB.CONTINUOUS,
                             name="Qg{0}".format(i))
    for i in range(nb):
        Pi[i] = model.addVar(lb=Pi_l[i],
                             ub=Pi_u[i],
                             vtype=GRB.CONTINUOUS,
                             name="Pi{0}".format(i))
        Qi[i] = model.addVar(lb=Qi_l[i],
                             ub=Qi_u[i],
                             vtype=GRB.CONTINUOUS,
                             name="Qi{0}".format(i))
    # For each area, before decomposition
    # Add system level constraints
    for i in range(nb):
        # If the bus is the root bus, only the children information is required.
        if len(area[i]["Ai"]) == 0:
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]

            model.addConstr(lhs=expr - Pi[i], sense=GRB.EQUAL, rhs=0)

            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            model.addConstr(lhs=expr - Qi[i], sense=GRB.EQUAL, rhs=0)

        elif len(area[i]["Cbranch"]) == 0:  # This bus is the lead node
            model.addConstr(lhs=Pij[area[i]["Abranch"][0][0]] -
                            Iij[area[i]["Abranch"][0][0]] *
                            Branch_R[area[i]["Abranch"][0][0]] + Pi[i],
                            sense=GRB.EQUAL,
                            rhs=0)
            model.addConstr(lhs=Qij[area[i]["Abranch"][0][0]] -
                            Iij[area[i]["Abranch"][0][0]] *
                            Branch_X[area[i]["Abranch"][0][0]] + Qi[i],
                            sense=GRB.EQUAL,
                            rhs=0)

            model.addConstr(lhs=Vi[int(area[i]["Ai"][0])] - Vi[i] -
                            2 * Branch_R[area[i]["Abranch"][0][0]] *
                            Pij[area[i]["Abranch"][0][0]] -
                            2 * Branch_X[area[i]["Abranch"][0][0]] *
                            Qij[area[i]["Abranch"][0][0]] +
                            Iij[area[i]["Abranch"][0][0]] *
                            (Branch_R[area[i]["Abranch"][0][0]]**2 +
                             Branch_X[area[i]["Abranch"][0][0]]**2),
                            sense=GRB.EQUAL,
                            rhs=0)

            model.addConstr(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] +
                Qij[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]]
                <= Vi[area[i]["Ai"][0]] * Iij[area[i]["Abranch"][0][0]],
                name="rc{0}".format(i))
        else:
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Pij[area[i]["Cbranch"][0][j]]
            model.addConstr(lhs=Pij[area[i]["Abranch"][0][0]] -
                            Iij[area[i]["Abranch"][0][0]] *
                            Branch_R[area[i]["Abranch"][0][0]] + Pi[i] - expr,
                            sense=GRB.EQUAL,
                            rhs=0)
            expr = 0
            for j in range(len(area[i]["Cbranch"][0])):
                expr += Qij[area[i]["Cbranch"][0][j]]

            model.addConstr(lhs=Qij[area[i]["Abranch"][0][0]] -
                            Iij[area[i]["Abranch"][0][0]] *
                            Branch_X[area[i]["Abranch"][0][0]] + Qi[i] - expr,
                            sense=GRB.EQUAL,
                            rhs=0)

            model.addConstr(lhs=Vi[int(area[i]["Ai"][0])] - Vi[i] -
                            2 * Branch_R[area[i]["Abranch"][0][0]] *
                            Pij[area[i]["Abranch"][0][0]] -
                            2 * Branch_X[area[i]["Abranch"][0][0]] *
                            Qij[area[i]["Abranch"][0][0]] +
                            Iij[area[i]["Abranch"][0][0]] *
                            (Branch_R[area[i]["Abranch"][0][0]]**2 +
                             Branch_X[area[i]["Abranch"][0][0]]**2),
                            sense=GRB.EQUAL,
                            rhs=0)

            model.addConstr(
                Pij[area[i]["Abranch"][0][0]] * Pij[area[i]["Abranch"][0][0]] +
                Qij[area[i]["Abranch"][0][0]] * Qij[area[i]["Abranch"][0][0]]
                <= Vi[area[i]["Ai"][0]] * Iij[area[i]["Abranch"][0][0]],
                name="rc{0}".format(i))
    obj = 0
    for i in range(ng):
        model.addConstr(lhs=Pg[i] - Pi[int(gen[i, GEN_BUS])],
                        sense=GRB.EQUAL,
                        rhs=bus[int(gen[i, GEN_BUS]), PD] / baseMVA)
        model.addConstr(lhs=Qg[i] - Qi[int(gen[i, GEN_BUS])],
                        sense=GRB.EQUAL,
                        rhs=bus[int(gen[i, GEN_BUS]), QD] / baseMVA)
        obj += gencost[i, 4] * Pg[i] * Pg[i] * baseMVA * baseMVA + gencost[
            i, 5] * Pg[i] * baseMVA + gencost[i, 6]

    model.setObjective(obj)
    model.Params.OutputFlag = 0
    model.Params.LogToConsole = 0
    model.Params.DisplayInterval = 1
    model.optimize()

    Pij = []
    Qij = []
    Iij = []
    Vi = []
    Pg = []
    Qg = []
    Pi = []
    Qi = []

    for i in range(nl):
        Pij.append(model.getVarByName("Pij{0}".format(i)).X)
        Qij.append(model.getVarByName("Qij{0}".format(i)).X)
        Iij.append(model.getVarByName("Iij{0}".format(i)).X)

    for i in range(nb):
        Vi.append(model.getVarByName("V{0}".format(i)).X)
        Pi.append(model.getVarByName("Pi{0}".format(i)).X)
        Qi.append(model.getVarByName("Qi{0}".format(i)).X)

    for i in range(ng):
        Pg.append(model.getVarByName("Pg{0}".format(i)).X)
        Qg.append(model.getVarByName("Qg{0}".format(i)).X)

    obj = obj.getValue()

    primal_residual = []

    for i in range(nl):
        primal_residual.append(Pij[i] * Pij[i] + Qij[i] * Qij[i] -
                               Iij[i] * Vi[int(f[i])])

    return obj, primal_residual
Example #57
0
def t_qps_pypower(quiet=False):
    """Tests of C{qps_pypower} QP solvers.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    algs = [200, 250, 400, 500, 600, 700]
    names = ['PIPS', 'sc-PIPS', 'IPOPT', 'CPLEX', 'MOSEK', 'Gurobi']
    check = [None, None, 'ipopt', 'cplex', 'mosek', 'gurobipy']

    n = 36
    t_begin(n * len(algs), quiet)

    for k in range(len(algs)):
        if check[k] is not None and not have_fcn(check[k]):
            t_skip(n, '%s not installed' % names[k])
        else:
            opt = {'verbose': 0, 'alg': algs[k]}

            if names[k] == 'PIPS' or names[k] == 'sc-PIPS':
                opt['pips_opt'] = {}
                opt['pips_opt']['comptol'] = 1e-8
            if names[k] == 'CPLEX':
#               alg = 0        ## default uses barrier method with NaN bug in lower lim multipliers
                alg = 2        ## use dual simplex
                ppopt = ppoption(CPLEX_LPMETHOD = alg, CPLEX_QPMETHOD = min([4, alg]))
                opt['cplex_opt'] = cplex_options([], ppopt)

            if names[k] == 'MOSEK':
#                alg = 5        ## use dual simplex
                ppopt = ppoption()
#                ppopt = ppoption(ppopt, MOSEK_LP_ALG = alg)
                ppopt = ppoption(ppopt, MOSEK_GAP_TOL=1e-9)
                opt['mosek_opt'] = mosek_options([], ppopt)

            t = '%s - 3-d LP : ' % names[k]
            ## example from 'doc linprog'
            c = array([-5, -4, -6], float)
            A = sparse([[1, -1,  1],
                        [3,  2,  4],
                        [3,  2,  0]], dtype=float)
            l = None
            u = array([20, 42, 30], float)
            xmin = array([0, 0, 0], float)
            x0 = None
            x, f, s, _, lam = qps_pypower(None, c, A, l, u, xmin, None, None, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, [0, 15, 3], 6, [t, 'x'])
            t_is(f, -78, 6, [t, 'f'])
            t_is(lam['mu_l'], [0, 0, 0], 13, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 1.5, 0.5], 9, [t, 'lam.mu_u'])
            t_is(lam['lower'], [1, 0, 0], 9, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - unconstrained 3-d quadratic : ' % names[k]
            ## from http://www.akiti.ca/QuadProgEx0Constr.html
            H = sparse([
                [ 5, -2, -1],
                [-2,  4,  3],
                [-1,  3,  5]
            ], dtype=float)
            c = array([2, -35, -47], float)
            x0 = array([0, 0, 0], float)
            x, f, s, _, lam = qps_pypower(H, c, opt=opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, [3, 5, 7], 8, [t, 'x'])
            t_is(f, -249, 13, [t, 'f'])
            t_ok(len(lam['mu_l']) == 0, [t, 'lam.mu_l'])
            t_ok(len(lam['mu_u']) == 0, [t, 'lam.mu_u'])
            t_is(lam['lower'], zeros(shape(x)), 13, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - constrained 2-d QP : ' % names[k]
            ## example from 'doc quadprog'
            H = sparse([[ 1, -1],
                        [-1,  2]], dtype=float)
            c = array([-2, -6], float)
            A = sparse([[ 1, 1],
                        [-1, 2],
                        [ 2, 1]], dtype=float)
            l = None
            u = array([2, 2, 3], float)
            xmin = array([0, 0])
            x0 = None
            x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([2., 4.]) / 3, 7, [t, 'x'])
            t_is(f, -74. / 9, 6, [t, 'f'])
            t_is(lam['mu_l'], [0., 0., 0.], 13, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], array([28., 4., 0.]) / 9, 7, [t, 'lam.mu_u'])
            t_is(lam['lower'], zeros(shape(x)), 8, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - constrained 4-d QP : ' % names[k]
            ## from http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm
            H = sparse([[1003.1,  4.3,     6.3,     5.9],
                        [4.3,     2.2,     2.1,     3.9],
                        [6.3,     2.1,     3.5,     4.8],
                        [5.9,     3.9,     4.8,    10.0]])
            c = zeros(4)
            A = sparse([[   1,       1,       1,       1],
                        [0.17,    0.11,    0.10,    0.18]])
            l = array([1, 0.10])
            u = array([1, Inf])
            xmin = zeros(4)
            x0 = array([1, 0, 0, 1], float)
            x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x'])
            t_is(f, 3.29 / 3, 6, [t, 'f'])
            t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u'])
            t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - (dict) constrained 4-d QP : ' % names[k]
            p = {'H': H, 'A': A, 'l': l, 'u': u, 'xmin': xmin, 'x0': x0, 'opt': opt}
            x, f, s, _, lam = qps_pypower(p)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x'])
            t_is(f, 3.29 / 3, 6, [t, 'f'])
            t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u'])
            t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - infeasible LP : ' % names[k]
            p = {'A': sparse([1, 1]), 'c': array([1, 1]), 'u': array([-1]),
                 'xmin': array([0, 0]), 'opt': opt}
            x, f, s, _, lam = qps_pypower(p)
            t_ok(s <= 0, [t, 'no success'])

    t_end()
Example #58
0
def t_opf_dc_gurobi(quiet=False):
    """Tests for DC optimal power flow using Gurobi solver.
    """
    algs = [0, 1, 2, 3, 4]
    num_tests = 23 * len(algs)

    t_begin(num_tests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_opf')
    if quiet:
        verbose = False
    else:
        verbose = False

    ppopt = ppoption('OUT_ALL', 0, 'VERBOSE', verbose);
    ppopt = ppoption(ppopt, 'OPF_ALG_DC', 700);

    ## run DC OPF
    if have_fcn('gurobipy'):
        for k in range(len(algs)):
            ppopt = ppoption(ppopt, 'GRB_METHOD', algs[k])
            methods = [
                'automatic',
                'primal simplex',
                'dual simplex',
                'barrier',
                'concurrent',
                'deterministic concurrent',
            ]
            t0 = 'DC OPF (Gurobi %s): ' % methods[k]

            ## set up indices
            ib_data     = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)]
            ib_voltage  = arange(VM, VA + 1)
            ib_lam      = arange(LAM_P, LAM_Q + 1)
            ib_mu       = arange(MU_VMAX, MU_VMIN + 1)
            ig_data     = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)]
            ig_disp     = array([PG, QG, VG])
            ig_mu       = arange(MU_PMAX, MU_QMIN + 1)
            ibr_data    = arange(ANGMAX + 1)
            ibr_flow    = arange(PF, QT + 1)
            ibr_mu      = array([MU_SF, MU_ST])
            #ibr_angmu   = array([MU_ANGMIN, MU_ANGMAX])

            ## get solved DC power flow case from MAT-file
            ## defines bus_soln, gen_soln, branch_soln, f_soln
            soln9_dcopf = loadmat(join(tdir, 'soln9_dcopf.mat'),
                    struct_as_record=True)
            bus_soln, gen_soln, branch_soln, f_soln = \
                    soln9_dcopf['bus_soln'], soln9_dcopf['gen_soln'], \
                    soln9_dcopf['branch_soln'], soln9_dcopf['f_soln']

            ## run OPF
            t = t0
            r = rundcopf(casefile, ppopt)
            bus, gen, branch, f, success = \
                    r['bus'], r['gen'], r['branch'], r['f'], r['success']
            t_ok(success, [t, 'success'])
            t_is(f, f_soln, 3, [t, 'f'])
            t_is(   bus[:, ib_data   ],    bus_soln[:, ib_data   ], 10, [t, 'bus data'])
            t_is(   bus[:, ib_voltage],    bus_soln[:, ib_voltage],  3, [t, 'bus voltage'])
            t_is(   bus[:, ib_lam    ],    bus_soln[:, ib_lam    ],  3, [t, 'bus lambda'])
            t_is(   bus[:, ib_mu     ],    bus_soln[:, ib_mu     ],  2, [t, 'bus mu'])
            t_is(   gen[:, ig_data   ],    gen_soln[:, ig_data   ], 10, [t, 'gen data'])
            t_is(   gen[:, ig_disp   ],    gen_soln[:, ig_disp   ],  3, [t, 'gen dispatch'])
            t_is(   gen[:, ig_mu     ],    gen_soln[:, ig_mu     ],  3, [t, 'gen mu'])
            t_is(branch[:, ibr_data  ], branch_soln[:, ibr_data  ], 10, [t, 'branch data'])
            t_is(branch[:, ibr_flow  ], branch_soln[:, ibr_flow  ],  3, [t, 'branch flow'])
            t_is(branch[:, ibr_mu    ], branch_soln[:, ibr_mu    ],  2, [t, 'branch mu'])

            ##-----  run OPF with extra linear user constraints & costs  -----
            ## two new z variables
            ##      0 <= z1, P2 - P1 <= z1
            ##      0 <= z2, P2 - P3 <= z2
            ## with A and N sized for DC opf
            ppc = loadcase(casefile)
            row = [0, 0, 0, 1, 1, 1]
            col = [9, 10, 12, 10, 11, 13]
            ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 14))
            ppc['u'] = array([0, 0])
            ppc['l'] = array([-Inf, -Inf])
            ppc['zl'] = array([0, 0])

            ppc['N'] = sparse(([1, 1], ([0, 1], [12, 13])), (2, 14))  ## new z variables only
            ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]])       ## w = r = z
            ppc['H'] = sparse((2, 2))                            ## no quadratic term
            ppc['Cw'] = array([1000, 1])

            t = ''.join([t0, 'w/extra constraints & costs 1 : '])
            r = rundcopf(ppc, ppopt)
            t_ok(r['success'], [t, 'success'])
            t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974'])
            t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974'])
            t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars'])
            t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs'])

            ## with A and N sized for AC opf
            ppc = loadcase(casefile)
            row = [0, 0, 0, 1, 1, 1]
            col = [18, 19, 24, 19, 20, 25]
            ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 26))
            ppc['u'] = array([0, 0])
            ppc['l'] = array([-Inf, -Inf])
            ppc['zl'] = array([0, 0])

            ppc['N'] = sparse(([1, 1], ([0, 1], [24, 25])), (2, 26))   ## new z variables only
            ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]])        ## w = r = z
            ppc['H'] = sparse((2, 2))                            ## no quadratic term
            ppc['Cw'] = array([1000, 1])

            t = ''.join([t0, 'w/extra constraints & costs 2 : '])
            r = rundcopf(ppc, ppopt)
            t_ok(r['success'], [t, 'success'])
            t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974'])
            t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974'])
            t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars'])
            t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs'])

            t = ''.join([t0, 'infeasible : '])
            ## with A and N sized for DC opf
            ppc = loadcase(casefile)
            ppc['A'] = sparse(([1, 1], ([0, 0], [9, 10])), (1, 14))   ## Pg1 + Pg2
            ppc['u'] = array([Inf])
            ppc['l'] = array([600])
            r = rundcopf(ppc, ppopt)
            t_ok(not r['success'], [t, 'no success'])
    else:
        t_skip(num_tests, 'Gurobi not available')

    t_end()
Example #59
0
def pre_process(n_bus, Yseries, Vset, pq, pv, vd):
    """
    Make the Helm System matrix
    @param n_bus: Number of buses of the circuit
    @param Yseries: Circuit admittance matrix of the series elements
    @param Vset: Vector of voltages of those nodes where the voltage is controlled (AKA Slack and PV buses)
    @param S: Vector of power injections at all the nodes
    @param pq: list of PQ node indices
    @param pv: list of PV node indices
    @param vd: list of Slack node indices
    @return: 
    """
    """
    Reduction of the circuit magnitudes.

    Args:
        n_bus: 

        Yseries: 

        slack_indices: Array of indices of the slack nodes

        Vset: 

        S: 

    Output:
        Yred: Reduced admittance matrix (Without the rows and columns belonging to slack buses)

        I: Matrix of currents (In practice only one slack bus is selected, hence it is a vector) injected by the slack buses

        Sred: Array of power injections of the buses that are not of type slack

        types_red: Array of types of the buses that are not of type slack

        non_slack_indices: Array of indices of the buses that are not of type slack
    """

    # now to have efficient arrays of coefficients
    map_idx = zeros(n_bus, dtype=np.int)
    map_w = zeros(n_bus, dtype=np.int)
    npq = 0
    npv = 0
    npqpv = 0

    for i in pq:
        map_idx[i] = npq
        map_w[i] = npqpv
        npq += 1
        npqpv += 1

    for i in pv:
        map_idx[i] = npv
        map_w[i] = npqpv
        npv += 1
        npqpv += 1

    # build the expanded system matrix
    Ysys = zeros((2 * n_bus, 2 * n_bus))

    for a, b in product(range(n_bus), range(n_bus)):
        Ysys[2 * a, 2 * b] = Yseries[a, b].real
        Ysys[2 * a, 2 * b + 1] = -Yseries[a, b].imag
        Ysys[2 * a + 1, 2 * b] = Yseries[a, b].imag
        Ysys[2 * a + 1, 2 * b + 1] = Yseries[a, b].real

    # set pv column
    for a in pv:
        b = a
        Ysys[:, 2 * b] = zeros(2 * n_bus)
        # Ysys[a*2, b*2+1] = 0
        Ysys[a * 2 + 1, b * 2] = 1

    # set vd elements
    for a in vd:
        Ysys[a * 2, :] = zeros(2 * n_bus)
        Ysys[a * 2 + 1, :] = zeros(2 * n_bus)
        Ysys[a * 2, a * 2] = 1
        Ysys[a * 2 + 1, a * 2 + 1] = 1
    # print('Ysys\n', Ysys)

    # build the PV matrix
    Ypv = zeros((2 * n_bus, npv))
    for a, b in product(r_[pq, pv], pv):
        kk = map_idx[b]
        Ypv[2 * a, kk] = Yseries[a, b].real
        Ypv[2 * a + 1, kk] = Yseries[a, b].imag
    # print('Ypv\n', Ypv)

    Vset2 = Vset * Vset

    return sparse(Ysys), Ypv, Vset2, map_idx, map_w, npq, npv
Example #60
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)
    @author: Richard Lincoln
    
    Modified by University of Kassel (Friederike Meier): Bugfix in line 173
    """
    ##----- 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) #TypeError: dIbr_dV() missing 1 required positional argument: 'V' >> branch was missing
        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