function [df, dg] = grad_ccv(x, baseMVA, bus, gen, gencost, branch, Ybus, Yf, Yt, V, ref, pv, pq, mpopt)
%GRAD_CCV  Evaluates gradients of objective function & constraints for OPF.
%   [df, dg] = grad_ccv(x, baseMVA, bus, gen, gencost, branch, Ybus, Yf, Yt, V, ref, pv, pq, mpopt)

%   MATPOWER
%   $Id: grad_ccv.m,v 1.11 2006/03/08 15:16:15 ray Exp $
%   by Ray Zimmerman, PSERC Cornell
%   Copyright (c) 1996-2006 by Power System Engineering Research Center (PSERC)
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%%----- initialize -----
%% define named indices into data, branch matrices
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
    MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
    TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
    ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
[PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;

%% constant
j = sqrt(-1);

%% generator info
on = find(gen(:, GEN_STATUS) > 0);      %% which generators are on?
gbus = gen(on, GEN_BUS);                %% what buses are they at?

%% sizes of things
nb = size(bus, 1);
nl = size(branch, 1);
npv = length(pv);
npq = length(pq);
ng = length(on);                        %% number of generators that are turned on

%% check for costs for Qg
[pcost, qcost] = pqcost(gencost, size(gen, 1), on);
if isempty(qcost)       %% set number of cost variables
    ncv = ng;           %% only Cp
else
    ncv = 2 * ng;       %% Cp and Cq
end

%% set up indexing for x
j1 = 1;         j2  = npv;              %% j1:j2    - V angle of pv buses
j3 = j2 + 1;    j4  = j2 + npq;         %% j3:j4    - V angle of pq buses
j5 = j4 + 1;    j6  = j4 + nb;          %% j5:j6    - V mag of all buses
j7 = j6 + 1;    j8  = j6 + ng;          %% j7:j8    - P of generators
j9 = j8 + 1;    j10 = j8 + ng;          %% j9:j10   - Q of generators
j11 = j10 + 1;  j12 = j10 + ng;         %% j11:j12  - Cp, cost of Pg

%% grab Pg & Qg and their costs
Pg = x(j7:j8);                              %% active generation in p.u.
Qg = x(j9:j10);                             %% reactive generation in p.u.
Cp = x(j11:j12);                            %% active costs in $/hr
if ncv > ng             %% no free VArs
    j13 = j12 + 1;  j14 = j12 + ng;         %% j13:j14  - Cq, cost of Qg
    Cq = x(j13:j14);                        %% reactive costs in $/hr
end

%%----- evaluate partials of objective function -----
%% compute values of objective function partials
df = [  zeros(j10, 1);              %% partial w.r.t. Va, Vm, Pg, Qg
        ones(ncv, 1)    ];          %% partial w.r.t. Cp (and Cq)

%%----- evaluate partials of constraints -----
if nargout > 1
    %% reconstruct V
    Va = zeros(nb, 1);
    Va([ref; pv; pq]) = [angle(V(ref)); x(j1:j2); x(j3:j4)];
    Vm = x(j5:j6);
    V = Vm .* exp(j * Va);
    
    %% compute partials of injected bus powers
    [dSbus_dVm, dSbus_dVa] = dSbus_dV(Ybus, V);     %% w.r.t. V
    dSbus_dPg = sparse(gbus, 1:ng, -1, nb, ng);     %% w.r.t. Pg
    dSbus_dQg = sparse(gbus, 1:ng, -j, nb, ng);     %% w.r.t. Qg
    
    %% compute partials of line flows w.r.t. V
    [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = dSbr_dV(branch, Yf, Yt, V);

    %% line limits are w.r.t apparent power, so compute partials of apparent power
    [dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm] = ...
                        dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St);
    br = find(branch(:, BR_STATUS));
    nbr = length(br);

    %% cost constraints w.r.t everything ( d(costfcn @ Pg - Cp) , etc.)
    dQcc_dQg = zeros(0, ng);
    dQcc_dCq = [];
    nsegs = pcost(:, NCOST) - 1;        %% number of cost constraints for each gen
    nPcc = sum(nsegs);                  %% total number of cost constraints
    dPcc_dPg = sparse([], [], [], nPcc, ng, nPcc);  %% nPcc x ng
    dPcc_dCp = sparse([], [], [], nPcc, ng, nPcc);  %% nPcc x ng
    for i = 1:ng
        xx = pcost(i,       COST:2:( COST + 2*(nsegs(i))    ))';
        yy = pcost(i,   (COST+1):2:( COST + 2*(nsegs(i)) + 1))';
        i1 = 1:nsegs(i);
        i2 = 2:(nsegs(i) + 1);
        m = (yy(i2) - yy(i1)) ./ (xx(i2) - xx(i1));
        ii = sum(nsegs(1:(i-1))) + [1:nsegs(i)];
        dPcc_dPg(ii, i) = m * baseMVA;
        dPcc_dCp(ii, i) = -1 * ones(nsegs(i), 1);
    end
    nQcc = 0;
    if ncv > ng             %% no free VArs
        nsegs = qcost(:, NCOST) - 1;        %% number of cost constraints for each gen
        nQcc = sum(nsegs);                  %% total number of cost constraints
        dQcc_dQg = sparse([], [], [], nQcc, ng, nQcc);  %% nQcc x ng
        dQcc_dCq = sparse([], [], [], nQcc, ng, nQcc);  %% nQcc x ng
        for i = 1:ng
            xx = qcost(i,       COST:2:( COST + 2*(nsegs(i))    ))';
            yy = qcost(i,   (COST+1):2:( COST + 2*(nsegs(i)) + 1))';
            i1 = 1:nsegs(i);
            i2 = 2:(nsegs(i) + 1);
            m = (yy(i2) - yy(i1)) ./ (xx(i2) - xx(i1));
            ii = sum(nsegs(1:(i-1))) + [1:nsegs(i)];
            dQcc_dQg(ii, i) = m * baseMVA;
            dQcc_dCq(ii, i) = -1 * ones(nsegs(i), 1);
        end
    end
    %%     [  dcc_dV      dcc_dPg   dcc_dQg        dcc_dCp         dcc_dCq ]
    dPcc = [sparse(nPcc,j6), dPcc_dPg, sparse(nPcc,ng), dPcc_dCp, sparse(nPcc,ncv-ng)];
    dQcc = [sparse(nQcc,j8), dQcc_dQg, sparse(nQcc,ng), dQcc_dCq];

    %% compute partials of line flow constraints
    if mpopt(24) == 1   %% branch active power limits
        dFlow_dV = [
            real(dSf_dVa(br,[pv;pq])), real(dSf_dVm(br,:)); %% from bus
            real(dSt_dVa(br,[pv;pq])), real(dSt_dVm(br,:)); %% to bus
        ];
    else                %% branch apparent power limits
        dFlow_dV = [
            dAf_dVa(br,[pv;pq]), dAf_dVm(br,:);             %% from bus
            dAt_dVa(br,[pv;pq]), dAt_dVm(br,:);             %% to bus
        ];
    end
    
    %% evaluate partials of constraints
    dg = [
        %% equality constraints
        real(dSbus_dVa(:,[pv;pq])), real(dSbus_dVm), ...
            real(dSbus_dPg), real(dSbus_dQg), sparse(nb,ncv);   %% P mismatch
        imag(dSbus_dVa(:,[pv;pq])), imag(dSbus_dVm), ...
            imag(dSbus_dPg), imag(dSbus_dQg), sparse(nb,ncv);   %% Q mismatch
    
        %% inequality constraints (variable limits, voltage & generation)
        sparse(nb,j4), -speye(nb,nb), sparse(nb,2*ng+ncv);      %% Vmin for var V
        sparse(nb,j4),  speye(nb,nb), sparse(nb,2*ng+ncv);      %% Vmax for var V
        sparse(ng,j6), -speye(ng,ng), sparse(ng,ng+ncv);        %% Pmin for generators
        sparse(ng,j6),  speye(ng,ng), sparse(ng,ng+ncv);        %% Pmax for generators
        sparse(ng,j8), -speye(ng,ng), sparse(ng,ncv);           %% Qmin for generators
        sparse(ng,j8),  speye(ng,ng), sparse(ng,ncv);           %% Qmax for generators
    
        %% inequality constraints (line flow limits)
        dFlow_dV, sparse(2*nbr,2*ng+ncv);

        %% inequality constraints on generator cost
        dPcc;
        dQcc;
    ]';
    
    %% make full if using constr or non-sparse QP solver
    if opf_slvr(mpopt(11)) == 0 | ~have_fcn('sparse_qp') | mpopt(51) == 0
        dg = full(dg);
    end
end

return;
