基于半不变量法的随机潮流计算模型及方法

基于半不变量法的随机潮流计算模型及方法
参考文献:《基于半不变量法的随机潮流计算模型及方法》
摘 要: 提出了一种线性化随机潮流的计算模型,在牛顿-拉夫逊法的基础上,利用半不变量法对随机变量进行卷积运算,并运用 Gram-Charlier 级数展开式计算随机变量的分布,得到节点电压概率密度函数. 通过节点电压概率分析为运行分析提供指导,以及对 IEEE-30节点系统进行计算,验证了所提模型和方法的有效性.
关键词: 电力系统; 随机潮流; 半不变量; 概率密度函数

1 引言

电力系统潮流计算是电力系统运行分析的基础,其方法包含确定性方法和不确定性潮流计算方法两大类.确定性潮流分析方法,即给定网络拓扑结构、元件的参数、节点负荷、发电机出力等参数,求解各节点电压及支路潮流的确定值。但由于实际运行中部分参数的不确定性,使得确定性潮流分析方法受到限制.为了准确模拟参数的多样性,也采用多场景计算方法,但这是对参数多种取值的枚举,计算量大,而且很难反映系统整体情况。因此,将参数的不确定性表示方法加入到潮流方程中,构造了不确定性潮流方程,形成了多种不确定性潮流分析方法,如随机潮流、盲数潮流、模糊潮流等。本文利用了随机潮流模型,改进了确定性潮流计算的不足,解决了潮流问题中的参数不确定性问题。
随机潮流计算运用概率统计方法处理系统运行中的随机变化因素,给出了系统运行电压、支路潮流的概率分布情况,更深刻地揭示了系统运行状况、系统中存在的问题、薄弱环节等信息,为规划与运行决策提供了更完整的信息 。因此,在电网规划中进行随机潮流计算显得尤为重要.此外在随机潮流计算中,本文利用了 Matlab 软件,大大缩短了程序编写和实现的过程,加快了程序的运算速度,提高了运算精度。

2 半不变量和 Cham-charlier 级数

半不变量是随机变量的一种数字特征,它可以由不高于相应阶次的随机变量的各阶矩求得。随机变量的各阶中心矩表示为:
在这里插入图片描述
可以得到各阶半不变量 Ki与中心矩 Mi的关系式为:

在这里插入图片描述
半不变量有以下重要性质:

在这里插入图片描述
由此可体现出半不变量的相加性,即独立随机变量之和的各阶半不变量等于各随机变量的各阶半不变量之和。

在这里插入图片描述
利用半不变量求和的运算代替卷积积分运算的一个关键问题是:已知矩量或半不变量,如何求出随机变量的概率密度函数.常用的方法是把概率密度函数展开成级数,用半不变量表示级数展开式的系数,本文采用 Gram-Charlier 级数展开。
在这里插入图片描述

3 计算步骤

由以上的理论分析可知,随机潮流计算的步骤可描述如图 1 所示。
在这里插入图片描述

4 算例

本文利用 Matlab 对 IEEE33 节点系统进行潮流计算分析.IEEE-33 节点系统的电网结构如图所示。
在这里插入图片描述

5 程序运行结果

1)节点6
在这里插入图片描述

2)节点14
在这里插入图片描述
3)节点22
在这里插入图片描述
4)节点26
在这里插入图片描述

6 程序

1)主函数


%% 基于半不变量法的随机潮流计算
clear 
clc
close all

%% 半不变量法随机潮流---------------------------------------------CM-----------------------------------------------------
shuju=data_ieee30;
pv=find(shuju.bus(:,2)==2);
pq=find(shuju.bus(:,2)==1);
isb=find(shuju.bus(:,2)==3);   %平衡节点
npv=length(pv);
npq=length(pq);
nb=size(shuju.bus,1);    %节点数
mu_P_G=zeros(nb,1);     %%节点发电机有功功率
mu_P_G(shuju.gen(:,1))=shuju.gen(:,2)/100;
mu_Q_G=zeros(nb,1);     %%节点发电机无功功率
mu_Q_G(shuju.gen(:,1))=shuju.gen(:,3)/100;
mu_P_L=shuju.bus(:,3)/100;  %%节点负荷有功功率
mu_Q_L=shuju.bus(:,4)/100;  %%节点负荷无功功率
sigma_P_L=mu_P_L*0.3;
sigma_Q_L=mu_Q_L*0.3;
mu_P=mu_P_G-mu_P_L;    %%节点注入有功
mu_Q=mu_Q_G-mu_Q_L;    %%节点注入无功
%% -------计算节点注入功率的半不变量
jieshu=6;
gama_p=zeros(nb,jieshu);     %注入有功的半不变量
gama_p(:,2)=sigma_P_L.^2;    
gama_q=zeros(nb,jieshu);    %注入无功的半不变量
gama_q(:,2)=sigma_Q_L.^2;
%-平衡节点及pv节点的Q置为0?
gama_p(isb,2)=0;
gama_q(isb,2)=0;
gama_q(pv,2)=0;

gama_pq=[gama_p;gama_q];
%% --------潮流计算形成2n阶雅克比矩阵
[basemva bus gen branch success et dSbus_dVm dSbus_dVa]=runpf(shuju);

H=real(dSbus_dVa);
M=imag(dSbus_dVa);
N=real(dSbus_dVm);
L=imag(dSbus_dVm);
Jacco2=[H N
        M L];      %N=dP/dU  L=dQ/dU
%-修正平衡节点和pv节点对应的系数
Jacco=Jacco2;
Jacco(isb,:)=0;
Jacco(:,isb)=0;
Jacco(isb,isb)=1;
Jacco(isb+nb,:)=0;
Jacco(:,isb+nb)=0;
Jacco(isb+nb,isb+nb)=1;

Jacco(pv+nb,:)=0;
Jacco(:,pv+nb)=0;
Jacco=Jacco+sparse(nb+pv, nb+pv, ones(npv,1), 2*nb, 2*nb);
%% ----------计算节点电压的半不变量
s1=Jacco\eye(size(Jacco));
gama_v=zeros(2*nb,jieshu);      %电压相角、幅值
for i=1:jieshu
    gama_v(:,i)=(s1.^i)*gama_pq(:,i);
end
gama_vm=gama_v(nb+pq,:);  %pq节点电压幅值的半不变量
%-----------形成支路潮流的灵敏度矩阵
li=shuju.branch(:,1);
lj=shuju.branch(:,2);
b=size(shuju.branch,1);    %线路数
G11=zeros(b,nb);  %线路有功对角度的倒数
G12=zeros(b,nb);  %线路有功对电压的导数
G21=zeros(b,nb);  
G22=zeros(b,nb);
for i=1:b
    G11(i,li(i))=-H(li(i),lj(i));
    G11(i,lj(i))=H(li(i),lj(i));
    G12(i,li(i))=0.01*2*branch(i,14)/bus(li(i),8)-N(li(i),lj(i));  %%化为标幺值
    G12(i,lj(i))=N(li(i),lj(i));
    G21(i,li(i))=-M(li(i),lj(i));
    G21(i,lj(i))=M(li(i),lj(i));
    G22(i,li(i))=0.01*2*branch(i,15)/bus(li(i),8)-H(li(i),lj(i));  %%化为标幺值
    G22(i,lj(i))=H(li(i),lj(i));
end
G=[G11 G12;G21 G22];
t1=G*s1;
%------------计算支路潮流的半不变量
gama_xianlu=zeros(2*b,jieshu);
for i=1:jieshu
    gama_xianlu(:,i)=(t1.^i)*gama_pq(:,i);
end
gama_xianlu_p=gama_xianlu(1:b,:);
gama_xianlu_q=gama_xianlu(b+1:end,:);
%% --------------用半不变量求Gram-charlie展开系数
g_vm=zeros(size(gama_vm));
g_xianlu_p=zeros(size(gama_xianlu_p));
g_xianlu_q=zeros(size(gama_xianlu_q));
for i=1:jieshu
    g_vm(:,i)=gama_vm(:,i)./(gama_vm(:,2).^(i/2));
    g_xianlu_p(:,i)=gama_xianlu_p(:,i)./(gama_xianlu_p(:,2).^(i/2));
    g_xianlu_q(:,i)=gama_xianlu_q(:,i)./(gama_xianlu_q(:,2).^(i/2));
end
%---电压展开系数C
c_vm=zeros(size(g_vm));
c_vm(:,3)=-g_vm(:,3);
c_vm(:,4)=g_vm(:,4);
c_vm(:,5)=-g_vm(:,5);
c_vm(:,6)=g_vm(:,6)+10*g_vm(:,3).^2;
%---线路有功展开系数C
c_xianlu_p=zeros(size(g_xianlu_p));
c_xianlu_p(:,3)=-g_xianlu_p(:,3);
c_xianlu_p(:,4)=g_xianlu_p(:,4);
c_xianlu_p(:,5)=-g_xianlu_p(:,5);
c_xianlu_p(:,6)=g_xianlu_p(:,6)+10*g_xianlu_p(:,3).^2;
%---线路无功展开系数C
c_xianlu_q=zeros(size(g_xianlu_q));
c_xianlu_q(:,3)=-g_xianlu_q(:,3);
c_xianlu_q(:,4)=g_xianlu_q(:,4);
c_xianlu_q(:,5)=-g_xianlu_q(:,5);
c_xianlu_q(:,6)=g_xianlu_q(:,6)+10*g_xianlu_q(:,3).^2;
%% -pq节点电压幅值期望及方差、线路功率期望及方差
mu_vm=bus(pq,8);
sigma_vm=sqrt(gama_vm(:,2));
mu_xianlu_p=branch(:,14)/100;
sigma_xianlu_p=sqrt(gama_xianlu_p(:,2));
mu_xianlu_q=branch(:,15)/100;
sigma_xianlu_q=sqrt(gama_xianlu_q(:,2));
%pq节点电压概率密度
for i=1:npq
    x=0.98:0.0001:1.05;
    x1=(x-mu_vm(i))/sigma_vm(i);
    pdf_vm(i,:)=c2pdf(x1,c_vm(i,:),sigma_vm(i));
end
figure
plot(x,pdf_vm(2,:),'r--')


%线路1有功
px=0.2:0.0001:0.9;
px1=(px-mu_xianlu_p(1))/sigma_xianlu_p(1);        %线路1有功
pdf_xianlu1_p=c2pdf(px1,c_xianlu_p(1,:),sigma_xianlu_p(1));
figure
plot(px,pdf_xianlu1_p,'r--')
legend('半不变量法')
title('线路1有功概率密度曲线')

%------------绘制各节点的概率分布
for i=1:npq
    figure
%     ksdensity(v_mc(pq(i),:))
%     hold on
    plot(x,pdf_vm(i,:),'r--')
    legend('半不变量法')
    title(['节点',num2str(pq(i)),'概率密度曲线'])
end
% % %---------由展开系数得到各点对应的概率密度
function pdf_x=c2pdf(x,c,sigma)
pdf_x=normpdf(x).*(1+c(3)*(3*x-x.^3)/factorial(3)+c(4)*(x.^4-6*x.^2+3)/factorial(4)+...
          c(5)*(-x.^5+10*x.^3-15*x)/factorial(5)+c(6)*(x.^6-15*x.^4+45*x.^2-15)/factorial(6))/sigma;
end
%----------由展开系数得到累计分布
function cdf_x=c2cdf(x,c)
cdf_x=normcdf(x)+normpdf(x).*(c(3)*(x.^2-1)/factorial(3)+c(4)*(-x.^3+3*x)/factorial(4)+...
    c(5)*(x.^4-6*x.^2+3)/factorial(5)+c(6)*(-x.^5+10*x.^3-15*x)/factorial(6));
end

2)子函数

function Sd = makeSdzip(baseMVA, bus, mpopt)
%MAKESDZIP   Builds vectors of nominal complex bus power demands for ZIP loads.
%   SD = MAKESDZIP(BASEMVA, BUS, MPOPT) returns a struct with three fields,
%   each an nb x 1 vectors. The fields 'z', 'i' and 'p' correspond to the
%   nominal p.u. complex power (at 1 p.u. voltage magnitude) of the constant
%   impedance, constant current, and constant power portions, respectively of
%   the ZIP load model.
%
%   Example:
%       Sd = makeSdzip(baseMVA, bus, mpopt);



[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;

if nargin < 3
    mpopt = [];
end
if ~isempty(mpopt) && ~isempty(mpopt.exp.sys_wide_zip_loads.pw)
    if any(size(mpopt.exp.sys_wide_zip_loads.pw) ~= [1 3])
        error('makeSdzip: ''exp.sys_wide_zip_loads.pw'' must be a 1 x 3 vector');
    end
    if abs(sum(mpopt.exp.sys_wide_zip_loads.pw) - 1) > eps
        error('makeSdzip: elements of ''exp.sys_wide_zip_loads.pw'' must sum to 1');
    end
    pw = mpopt.exp.sys_wide_zip_loads.pw;
else
    pw = [1 0 0];
end
if ~isempty(mpopt) && ~isempty(mpopt.exp.sys_wide_zip_loads.qw)
    if any(size(mpopt.exp.sys_wide_zip_loads.qw) ~= [1 3])
        error('makeSdzip: ''exp.sys_wide_zip_loads.qw'' must be a 1 x 3 vector');
    end
    if abs(sum(mpopt.exp.sys_wide_zip_loads.qw) - 1) > eps
        error('makeSdzip: elements of ''exp.sys_wide_zip_loads.qw'' must sum to 1');
    end
    qw = mpopt.exp.sys_wide_zip_loads.qw;
else
    qw = pw;
end

Sd.z = (bus(:, PD) * pw(3)  + 1j * bus(:, QD) * qw(3)) / baseMVA;
Sd.i = (bus(:, PD) * pw(2)  + 1j * bus(:, QD) * qw(2)) / baseMVA;
Sd.p = (bus(:, PD) * pw(1)  + 1j * bus(:, QD) * qw(1)) / baseMVA;


function [Sbus, dSbus_dVm] = makeSbus(baseMVA, bus, gen, mpopt, Vm, Sg)
%MAKESBUS   Builds the vector of complex bus power injections.
%   SBUS = MAKESBUS(BASEMVA, BUS, GEN)
%   SBUS = MAKESBUS(BASEMVA, BUS, GEN, MPOPT, VM)
%   SBUS = MAKESBUS(BASEMVA, BUS, GEN, MPOPT, VM, SG)
%   returns the vector of complex bus power injections, that is, generation
%   minus load. Power is expressed in per unit. If the MPOPT and VM arguments
%   are present it evaluates any ZIP loads based on the provided voltage
%   magnitude vector. If VM is empty, it assumes nominal voltage. If SG is
%   provided, it is a complex ng x 1 vector of generator power injections in


%% define named indices into bus, gen matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[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;

%% default inputs
if nargin < 5
    Vm = [];
    if nargin < 4
        mpopt = [];
    end
end
nb = size(bus, 1);

%% get load parameters
Sd = makeSdzip(baseMVA, bus, mpopt);

if nargout == 2
    Sbus = [];
    if isempty(Vm)
        dSbus_dVm = sparse(nb, nb);
    else
        dSbus_dVm = -(spdiags(Sd.i + 2 * Vm .* Sd.z, 0, nb, nb));
    end
else
    %% compute per-bus generation in p.u.
    on = find(gen(:, GEN_STATUS) > 0);      %% which generators are on?
    gbus = gen(on, GEN_BUS);                %% what buses are they at?
    ngon = size(on, 1);
    Cg = sparse(gbus, (1:ngon)', 1, nb, ngon);  %% connection matrix
                                                %% element i, j is 1 if
                                                %% gen on(j) at bus i is ON
    if nargin > 5 && ~isempty(Sg)
        Sbusg = Cg * Sg(on);
    else
        Sbusg = Cg * (gen(on, PG) + 1j * gen(on, QG)) / baseMVA;
    end

    %% compute per-bus loads in p.u.
    if isempty(Vm)
        Vm = ones(nb, 1);
    end
    Sbusd = Sd.p + Sd.i .* Vm + Sd.z .* Vm.^2;

    %% form net complex bus power injection vector
    %% (power injected by generators + power injected by loads)
    Sbus = Sbusg - Sbusd;
end

function [MVAbase, bus, gen, branch, success, et, dSbus_dVm, dSbus_dVa] = ...
                runpf(casedata, mpopt, fname, solvedcase)
%RUNPF  Runs a power flow.
%   [RESULTS, SUCCESS] = RUNPF(CASEDATA, MPOPT, FNAME, SOLVEDCASE)
%
%   Runs a power flow (full AC Newton's method by default), optionally
%   returning a RESULTS struct and SUCCESS flag.
%
%   Inputs (all are optional):
%       CASEDATA : either a MATPOWER case struct or a string containing
%           the name of the file with the case data (default is 'case9')
%           (see also CASEFORMAT and LOADCASE)
%       MPOPT : MATPOWER options struct to override default options
%           can be used to specify the solution algorithm, output options
%           termination tolerances, and more (see also MPOPTION).
%       FNAME : name of a file to which the pretty-printed output will
%           be appended
%       SOLVEDCASE : name of file to which the solved case will be saved
%           in MATPOWER case format (M-file will be assumed unless the
%           specified name ends with '.mat')
%
%   Outputs (all are optional):
%       RESULTS : results struct, with the following fields:
%           (all fields from the input MATPOWER case, i.e. bus, branch,
%               gen, etc., but with solved voltages, power flows, etc.)
%           order - info used in external <-> internal data conversion
%           et - elapsed time in seconds
%           success - success flag, 1 = succeeded, 0 = failed
%       SUCCESS : the success flag can additionally be returned as
%           a second output argument
%
%   Calling syntax options:
%       results = runpf;
%       results = runpf(casedata);
%       results = runpf(casedata, mpopt);
%       results = runpf(casedata, mpopt, fname);
%       results = runpf(casedata, mpopt, fname, solvedcase);
%       [results, success] = runpf(...);
%
%       Alternatively, for compatibility with previous versions of MATPOWER,
%       some of the results can be returned as individual output arguments:
%
%       [baseMVA, bus, gen, branch, success, et] = runpf(...);
%
%   If the pf.enforce_q_lims option is set to true (default is false) then, if
%   any generator reactive power limit is violated after running the AC power
%   flow, the corresponding bus is converted to a PQ bus, with Qg at the
%   limit, and the case is re-run. The voltage magnitude at the bus will
%   deviate from the specified value in order to satisfy the reactive power
%   limit. If the reference bus is converted to PQ, the first remaining PV
%   bus will be used as the slack bus for the next iteration. This may
%   result in the real power output at this generator being slightly off
%   from the specified values.
%
%   Examples:
%       results = runpf('case30');
%       results = runpf('case30', mpoption('pf.enforce_q_lims', 1));
%
%   See also RUNDCPF.

%   MATPOWER
%   Copyright (c) 1996-2016 by Power System Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%   Enforcing of generator Q limits inspired by contributions
%   from Mu Lin, Lincoln University, New Zealand (1/14/05).
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%%-----  initialize  -----
%% define named indices into bus, gen, branch matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[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;
[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;

%% default arguments
if nargin < 4
    solvedcase = '';                %% don't save solved case
    if nargin < 3
        fname = '';                 %% don't print results to a file
        if nargin < 2
            mpopt = mpoption;       %% use default options
            if nargin < 1
                casedata = 'case9'; %% default data file is 'case9.m'
            end
        end
    end
end

%% options
qlim = mpopt.pf.enforce_q_lims;         %% enforce Q limits on gens?
dc = strcmp(upper(mpopt.model), 'DC');  %% use DC formulation?

%% read data
mpc = loadcase(casedata);

%% add zero columns to branch for flows if needed
if size(mpc.branch,2) < QT
  mpc.branch = [ mpc.branch zeros(size(mpc.branch, 1), QT-size(mpc.branch,2)) ];
end

%% convert to internal indexing
mpc = ext2int(mpc);
[baseMVA, bus, gen, branch] = deal(mpc.baseMVA, mpc.bus, mpc.gen, mpc.branch);

%% get bus index lists of each type of bus
[ref, pv, pq] = bustypes(bus, gen);

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

%%-----  run the power flow  -----
t0 = clock;
if mpopt.verbose > 0
    v = mpver('all');
    fprintf('\nMATPOWER Version %s, %s', v.Version, v.Date);
end
if dc                               %% DC formulation
    if mpopt.verbose > 0
      fprintf(' -- DC Power Flow\n');
    end
    %% initial state
    Va0 = bus(:, VA) * (pi/180);
    
    %% build B matrices and phase shift injections
    [B, Bf, Pbusinj, Pfinj] = makeBdc(baseMVA, bus, branch);
    
    %% compute complex bus power injections (generation - load)
    %% adjusted for phase shifters and real shunts
    Pbus = real(makeSbus(baseMVA, bus, gen)) - Pbusinj - bus(:, GS) / baseMVA;
    
    %% "run" the power flow
    [Va, success] = dcpf(B, Pbus, Va0, ref, pv, pq);
    
    %% update data matrices with solution
    branch(:, [QF, QT]) = zeros(size(branch, 1), 2);
    branch(:, PF) = (Bf * Va + Pfinj) * baseMVA;
    branch(:, PT) = -branch(:, PF);
    bus(:, VM) = ones(size(bus, 1), 1);
    bus(:, VA) = Va * (180/pi);
    %% update Pg for slack generator (1st gen at ref bus)
    %% (note: other gens at ref bus are accounted for in Pbus)
    %%      Pg = Pinj + Pload + Gs
    %%      newPg = oldPg + newPinj - oldPinj
    refgen = zeros(size(ref));
    for k = 1:length(ref)
        temp = find(gbus == ref(k));
        refgen(k) = on(temp(1));
    end
    gen(refgen, PG) = gen(refgen, PG) + (B(ref, :) * Va - Pbus(ref)) * baseMVA;
else                                %% AC formulation
    alg = upper(mpopt.pf.alg);
    if mpopt.verbose > 0
        switch alg
            case 'NR'
                solver = 'Newton';
            case 'FDXB'
                solver = 'fast-decoupled, XB';
            case 'FDBX'
                solver = 'fast-decoupled, BX';
            case 'GS'
                solver = 'Gauss-Seidel';
            otherwise
                solver = 'unknown';
        end
        fprintf(' -- AC Power Flow (%s)\n', solver);
    end
    %% initial state
    % V0    = ones(size(bus, 1), 1);            %% flat start
    V0  = bus(:, VM) .* exp(sqrt(-1) * pi/180 * bus(:, VA));
    vcb = ones(size(V0));           %% create mask of voltage-controlled buses
    vcb(pq) = 0;                    %% exclude PQ buses
    k = find(vcb(gbus));            %% in-service gens at v-c buses
    V0(gbus(k)) = gen(on(k), VG) ./ abs(V0(gbus(k))).* V0(gbus(k));
    
    if qlim
        ref0 = ref;                         %% save index and angle of
        Varef0 = bus(ref0, VA);             %%   original reference bus(es)
        limited = [];                       %% list of indices of gens @ Q lims
        fixedQg = zeros(size(gen, 1), 1);   %% Qg of gens at Q limits
    end

    %% build admittance matrices
    [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);
    
    repeat = 1;
    while (repeat)
        %% function for computing V dependent complex bus power injections
        %% (generation - load)
        Sbus = @(Vm)makeSbus(baseMVA, bus, gen, mpopt, Vm);
        
        %% run the power flow
        switch alg
            case 'NR'
                [V, success, iterations, dSbus_dVm, dSbus_dVa] = newtonpf(Ybus, Sbus, V0, ref, pv, pq, mpopt);
            case {'FDXB', 'FDBX'}
                [Bp, Bpp] = makeB(baseMVA, bus, branch, alg);
                [V, success, iterations] = fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, mpopt);
            case 'GS'
                if (~isempty(mpopt.exp.sys_wide_zip_loads.pw) && ...
                        any(mpopt.exp.sys_wide_zip_loads.pw(2:3))) || ...
                        (~isempty(mpopt.exp.sys_wide_zip_loads.qw) && ...
                        any(mpopt.exp.sys_wide_zip_loads.qw(2:3)))
                    warning('runpf: Gauss-Seidel algorithm does not support ZIP load model. Converting to constant power loads.')
                    mpopt = mpoption(mpopt, 'exp.sys_wide_zip_loads', ...
                                    struct('pw', [], 'qw', []));
                end
                [V, success, iterations] = gausspf(Ybus, Sbus([]), V0, ref, pv, pq, mpopt);
            otherwise
                error('runpf: Only Newton''s method, fast-decoupled, and Gauss-Seidel power flow algorithms currently implemented.');
        end
        
        %% update data matrices with solution
        [bus, gen, branch] = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq, mpopt);
        
        if qlim             %% enforce generator Q limits
            %% find gens with violated Q constraints
            mx = find( gen(:, GEN_STATUS) > 0 ...
                    & gen(:, QG) > gen(:, QMAX) + mpopt.opf.violation );
            mn = find( gen(:, GEN_STATUS) > 0 ...
                    & gen(:, QG) < gen(:, QMIN) - mpopt.opf.violation );
            
            if ~isempty(mx) || ~isempty(mn)  %% we have some Q limit violations
                %% first check for INFEASIBILITY (all remaining gens violating)
                infeas = union(mx', mn')';  %% transposes handle fact that
                    %% union of scalars is a row vector
                remaining = find( gen(:, GEN_STATUS) > 0 & ...
                                ( bus(gen(:, GEN_BUS), BUS_TYPE) == PV | ...
                                  bus(gen(:, GEN_BUS), BUS_TYPE) == REF ));
                if length(infeas) == length(remaining) && all(infeas == remaining)
                    if mpopt.verbose
                        fprintf('All %d remaining gens exceed their Q limits : INFEASIBLE PROBLEM\n', length(infeas));
                    end
                    success = 0;
                    break;
                end

                %% one at a time?
                if qlim == 2    %% fix largest violation, ignore the rest
                    [junk, k] = max([gen(mx, QG) - gen(mx, QMAX);
                                     gen(mn, QMIN) - gen(mn, QG)]);
                    if k > length(mx)
                        mn = mn(k-length(mx));
                        mx = [];
                    else
                        mx = mx(k);
                        mn = [];
                    end
                end

                if mpopt.verbose && ~isempty(mx)
                    fprintf('Gen %d at upper Q limit, converting to PQ bus\n', mx);
                end
                if mpopt.verbose && ~isempty(mn)
                    fprintf('Gen %d at lower Q limit, converting to PQ bus\n', mn);
                end
                
                %% save corresponding limit values
                fixedQg(mx) = gen(mx, QMAX);
                fixedQg(mn) = gen(mn, QMIN);
                mx = [mx;mn];
                
                %% convert to PQ bus
                gen(mx, QG) = fixedQg(mx);      %% set Qg to binding limit
                gen(mx, GEN_STATUS) = 0;        %% temporarily turn off gen,
                for i = 1:length(mx)            %% (one at a time, since
                    bi = gen(mx(i), GEN_BUS);   %%  they may be at same bus)
                    bus(bi, [PD,QD]) = ...      %% adjust load accordingly,
                        bus(bi, [PD,QD]) - gen(mx(i), [PG,QG]);
                end
                if length(ref) > 1 && any(bus(gen(mx, GEN_BUS), BUS_TYPE) == REF)
                    error('runpf: Sorry, MATPOWER cannot enforce Q limits for slack buses in systems with multiple slacks.');
                end
                bus(gen(mx, GEN_BUS), BUS_TYPE) = PQ;   %% & set bus type to PQ
                
                %% update bus index lists of each type of bus
                ref_temp = ref;
                [ref, pv, pq] = bustypes(bus, gen);
                %% previous line can modify lists to select new REF bus
                %% if there was none, so we should update bus with these
                %% just to keep them consistent
                if ref ~= ref_temp
                    bus(ref, BUS_TYPE) = REF;
                    bus( pv, BUS_TYPE) = PV;
                    if mpopt.verbose
                        fprintf('Bus %d is new slack bus\n', ref);
                    end
                end
                limited = [limited; mx];
            else
                repeat = 0; %% no more generator Q limits violated
            end
        else
            repeat = 0;     %% don't enforce generator Q limits, once is enough
        end
    end
    if qlim && ~isempty(limited)
        %% restore injections from limited gens (those at Q limits)
        gen(limited, QG) = fixedQg(limited);    %% restore Qg value,
        for i = 1:length(limited)               %% (one at a time, since
            bi = gen(limited(i), GEN_BUS);      %%  they may be at same bus)
            bus(bi, [PD,QD]) = ...              %% re-adjust load,
                bus(bi, [PD,QD]) + gen(limited(i), [PG,QG]);
        end
        gen(limited, GEN_STATUS) = 1;               %% and turn gen back on
        if ref ~= ref0
            %% adjust voltage angles to make original ref bus correct
            bus(:, VA) = bus(:, VA) - bus(ref0, VA) + Varef0;
        end
    end
end
mpc.et = etime(clock, t0);
mpc.success = success;

%%-----  output results  -----
%% convert back to original bus numbering & print results
[mpc.bus, mpc.gen, mpc.branch] = deal(bus, gen, branch);
results = int2ext(mpc);

%% zero out result fields of out-of-service gens & branches
if ~isempty(results.order.gen.status.off)
  results.gen(results.order.gen.status.off, [PG QG]) = 0;
end
if ~isempty(results.order.branch.status.off)
  results.branch(results.order.branch.status.off, [PF QF PT QT]) = 0;
end

if fname
    [fd, msg] = fopen(fname, 'at');
    if fd == -1
        error(msg);
    else
        if mpopt.out.all == 0
            printpf(results, fd, mpoption(mpopt, 'out.all', -1));
        else
            printpf(results, fd, mpopt);
        end
        fclose(fd);
    end
end
printpf(results, 1, mpopt);

%% save solved case
if solvedcase
    savecase(solvedcase, results);
end

if nargout == 1 || nargout == 2
    MVAbase = results;
    bus = success;
elseif nargout > 2
    [MVAbase, bus, gen, branch, et] = ...
        deal(results.baseMVA, results.bus, results.gen, results.branch, results.et);
% else  %% don't define MVAbase, so it doesn't print anything
end

function [V, converged, i, dSbus_dVm, dSbus_dVa] = newtonpf(Ybus, Sbus, V0, ref, pv, pq, mpopt)
%NEWTONPF  Solves the power flow using a full Newton's method.
%   [V, CONVERGED, I] = NEWTONPF(YBUS, SBUS, V0, REF, PV, PQ, MPOPT)
%   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. MPOPT is a MATPOWER options struct which can be used to 
%   set the termination tolerance, maximum number of iterations, and 
%   output options (see MPOPTION 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 also RUNPF.

%   MATPOWER
%   Copyright (c) 1996-2016 by Power System Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%% default arguments
if nargin < 7
    mpopt = mpoption;
end

%% options
tol     = mpopt.pf.tol;
max_it  = mpopt.pf.nr.max_it;

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

%% set up indexing for updating V
npv = length(pv);
npq = length(pq);
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 + npq;      %% j5:j6 - V mag of pq buses

%% evaluate F(x0)
mis = V .* conj(Ybus * V) - Sbus(Vm);
F = [   real(mis([pv; pq]));
        imag(mis(pq))   ];

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

%% do Newton iterations
while (~converged && i < max_it)
    %% update iteration counter
    i = i + 1;
    
    %% evaluate Jacobian
    [dSbus_dVm, dSbus_dVa] = dSbus_dV(Ybus, V);
    [dummy, neg_dSd_dVm] = Sbus(Vm);
    dSbus_dVm = dSbus_dVm - neg_dSd_dVm;
    
    j11 = real(dSbus_dVa([pv; pq], [pv; pq]));
    j12 = real(dSbus_dVm([pv; pq], pq));
    j21 = imag(dSbus_dVa(pq, [pv; pq]));
    j22 = imag(dSbus_dVm(pq, pq));
    
    J = [   j11 j12;
            j21 j22;    ];

    %% compute update step
    dx = -(J \ F);

    %% update voltage
    if npv
        Va(pv) = Va(pv) + dx(j1:j2);
    end
    if npq
        Va(pq) = Va(pq) + dx(j3:j4);
        Vm(pq) = Vm(pq) + dx(j5:j6);
    end
    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(Vm);
    F = [   real(mis(pv));
            real(mis(pq));
            imag(mis(pq))   ];

    %% check for convergence
    normF = norm(F, inf);
    if mpopt.verbose > 1
        fprintf('\n%3d        %10.3e', i, normF);
    end
    if normF < tol
        converged = 1;
        if mpopt.verbose
            fprintf('\nNewton''s method power flow converged in %d iterations.\n', i);
        end
    end
end

if mpopt.verbose
    if ~converged
        fprintf('\nNewton''s method power flow did not converge in %d iterations.\n', i);
    end
end


function mpc = data_ieee30
%CASE_IEEE30  Power flow data for IEEE 30 bus test case.
%   Please see CASEFORMAT for details on the case file format.
%   This data was converted from IEEE Common Data Format
%   (ieee30cdf.txt) on 15-Oct-2014 by cdf2matp, rev. 2393
%   See end of file for warnings generated during conversion.
%
%   Converted from IEEE CDF file from:
%       http://www.ee.washington.edu/research/pstca/
% 
%  08/20/93 UW ARCHIVE           100.0  1961 W IEEE 30 Bus Test Case

%   MATPOWER

%% MATPOWER Case Format : Version 2
mpc.version = '2';

%%-----  Power Flow Data  -----%%
%% system MVA base
mpc.baseMVA = 100;

%% bus data
%  bus_i  type  Pd  Qd  Gs  Bs  area  Vm  Va  baseKV  zone  Vmax  Vmin
mpc.bus = [
  1  3  0  0  0  0  1  1.05  0  132  1  1.06  0.94;
  2  2  21.7  12.7  0  0  1  1.045  -5.48  132  1  1.06  0.94;
  3  1  2.4  1.2  0  0  1  1.021  -7.96  132  1  1.06  0.94;
  4  1  7.6  1.6  0  0  1  1.012  -9.62  132  1  1.06  0.94;
  5  2  94.2  19  0  0  1  1.01  -14.37  132  1  1.06  0.94;
  6  1  0  0  0  0  1  1.01  -11.34  132  1  1.06  0.94;
  7  1  22.8  10.9  0  0  1  1.002  -13.12  132  1  1.06  0.94;
  8  2  30  30  0  0  1  1.01  -12.1  132  1  1.06  0.94;
  9  1  0  0  0  0  1  1.051  -14.38  1  1  1.06  0.94;
  10  1  5.8  2  0  19  1  1.045  -15.97  33  1  1.06  0.94;
  11  2  0  0  0  0  1  1.05  -14.39  11  1  1.06  0.94;
  12  1  11.2  7.5  0  0  1  1.057  -15.24  33  1  1.06  0.94;
  13  2  0  0  0  0  1  1.05  -15.24  11  1  1.06  0.94;
  14  1  6.2  1.6  0  0  1  1.042  -16.13  33  1  1.06  0.94;
  15  1  8.2  2.5  0  0  1  1.038  -16.22  33  1  1.06  0.94;
  16  1  3.5  1.8  0  0  1  1.045  -15.83  33  1  1.06  0.94;
  17  1  9  5.8  0  0  1  1.04  -16.14  33  1  1.06  0.94;
  18  1  3.2  0.9  0  0  1  1.028  -16.82  33  1  1.06  0.94;
  19  1  9.5  3.4  0  0  1  1.026  -17  33  1  1.06  0.94;
  20  1  2.2  0.7  0  0  1  1.03  -16.8  33  1  1.06  0.94;
  21  1  17.5  11.2  0  0  1  1.033  -16.42  33  1  1.06  0.94;
  22  1  0  0  0  0  1  1.033  -16.41  33  1  1.06  0.94;
  23  1  3.2  1.6  0  0  1  1.027  -16.61  33  1  1.06  0.94;
  24  1  8.7  6.7  0  4.3  1  1.021  -16.78  33  1  1.06  0.94;
  25  1  0  0  0  0  1  1.017  -16.35  33  1  1.06  0.94;
  26  1  3.5  2.3  0  0  1  1  -16.77  33  1  1.06  0.94;
  27  1  0  0  0  0  1  1.023  -15.82  33  1  1.06  0.94;
  28  1  0  0  0  0  1  1.007  -11.97  132  1  1.06  0.94;
  29  1  2.4  0.9  0  0  1  1.003  -17.06  33  1  1.06  0.94;
  30  1  10.6  1.9  0  0  1  0.992  -17.94  33  1  1.06  0.94;
];

%% generator data
%  bus  Pg  Qg  Qmax  Qmin  Vg  mBase  status  Pmax  Pmin  Pc1  Pc2  Qc1min  Qc1max  Qc2min  Qc2max  ramp_agc  ramp_10  ramp_30  ramp_q  apf
mpc.gen = [
  1  260.2  -16.1  150  -20  1.05  100  1  200  50  0  0  0  0  0  0  0  0  0  0  0;
  2  80  50  60  -20  1.045  100  1  80  20  0  0  0  0  0  0  0  0  0  0  0;
  5  50  37  62.45  -15  1.01  100  1  50  15  0  0  0  0  0  0  0  0  0  0  0;
  8  20  37.3  48.73  -15  1.01  100  1  35  10  0  0  0  0  0  0  0  0  0  0  0;
  11  20  16.2  40  -10  1.05  100  1  30  10  0  0  0  0  0  0  0  0  0  0  0;
  13  20  10.6  44.72  -15  1.05  100  1  40  12  0  0  0  0  0  0  0  0  0  0  0;
];

%% branch data
%  fbus  tbus  r  x  b  rateA  rateB  rateC  ratio  angle  status  angmin  angmax
mpc.branch = [
  1  2  0.0192  0.0575  0.0528  0  0  0  0  0  1  -360  360;
  1  3  0.0452  0.1652  0.0408  0  0  0  0  0  1  -360  360;
  2  4  0.057  0.1737  0.0368  0  0  0  0  0  1  -360  360;
  3  4  0.0132  0.0379  0.0084  0  0  0  0  0  1  -360  360;
  2  5  0.0472  0.1983  0.0418  0  0  0  0  0  1  -360  360;
  2  6  0.0581  0.1763  0.0374  0  0  0  0  0  1  -360  360;
  4  6  0.0119  0.0414  0.009  0  0  0  0  0  1  -360  360;
  5  7  0.046  0.116  0.0204  0  0  0  0  0  1  -360  360;
  6  7  0.0267  0.082  0.017  0  0  0  0  0  1  -360  360;
  6  8  0.012  0.042  0.009  0  0  0  0  0  1  -360  360;
  6  9  0  0.208  0  0  0  0  0.978  0  1  -360  360;
  6  10  0  0.556  0  0  0  0  0.969  0  1  -360  360;
  9  11  0  0.208  0  0  0  0  0  0  1  -360  360;
  9  10  0  0.11  0  0  0  0  0  0  1  -360  360;
  4  12  0  0.256  0  0  0  0  0.932  0  1  -360  360;
  12  13  0  0.14  0  0  0  0  0  0  1  -360  360;
  12  14  0.1231  0.2559  0  0  0  0  0  0  1  -360  360;
  12  15  0.0662  0.1304  0  0  0  0  0  0  1  -360  360;
  12  16  0.0945  0.1987  0  0  0  0  0  0  1  -360  360;
  14  15  0.221  0.1997  0  0  0  0  0  0  1  -360  360;
  16  17  0.0524  0.1923  0  0  0  0  0  0  1  -360  360;
  15  18  0.1073  0.2185  0  0  0  0  0  0  1  -360  360;
  18  19  0.0639  0.1292  0  0  0  0  0  0  1  -360  360;
  19  20  0.034  0.068  0  0  0  0  0  0  1  -360  360;
  10  20  0.0936  0.209  0  0  0  0  0  0  1  -360  360;
  10  17  0.0324  0.0845  0  0  0  0  0  0  1  -360  360;
  10  21  0.0348  0.0749  0  0  0  0  0  0  1  -360  360;
  10  22  0.0727  0.1499  0  0  0  0  0  0  1  -360  360;
  21  22  0.0116  0.0236  0  0  0  0  0  0  1  -360  360;
  15  23  0.1  0.202  0  0  0  0  0  0  1  -360  360;
  22  24  0.115  0.179  0  0  0  0  0  0  1  -360  360;
  23  24  0.132  0.27  0  0  0  0  0  0  1  -360  360;
  24  25  0.1885  0.3292  0  0  0  0  0  0  1  -360  360;
  25  26  0.2544  0.38  0  0  0  0  0  0  1  -360  360;
  25  27  0.1093  0.2087  0  0  0  0  0  0  1  -360  360;
  28  27  0  0.396  0  0  0  0  0.968  0  1  -360  360;
  27  29  0.2198  0.4153  0  0  0  0  0  0  1  -360  360;
  27  30  0.3202  0.6027  0  0  0  0  0  0  1  -360  360;
  29  30  0.2399  0.4533  0  0  0  0  0  0  1  -360  360;
  8  28  0.0636  0.2  0.0428  0  0  0  0  0  1  -360  360;
  6  28  0.0169  0.0599  0.013  0  0  0  0  0  1  -360  360;
];

%%-----  OPF Data  -----%%
%% generator cost data
%  1  startup  shutdown  n  x1  y1  ...  xn  yn
%  2  startup  shutdown  n  c(n-1)  ...  c0
mpc.gencost = [
  2  0  0  3  0.0384319754  20  0;
  2  0  0  3  0.25  20  0;
  2  0  0  3  0.01  40  0;
  2  0  0  3  0.01  40  0;
  2  0  0  3  0.01  40  0;
  2  0  0  3  0.01  40  0;
];

%% bus names
mpc.bus_name = {
  'Glen Lyn 132';
  'Claytor  132';
  'Kumis    132';
  'Hancock  132';
  'Fieldale 132';
  'Roanoke  132';
  'Blaine   132';
  'Reusens  132';
  'Roanoke  1.0';
  'Roanoke   33';
  'Roanoke   11';
  'Hancock   33';
  'Hancock   11';
  'Bus 14    33';
  'Bus 15    33';
  'Bus 16    33';
  'Bus 17    33';
  'Bus 18    33';
  'Bus 19    33';
  'Bus 20    33';
  'Bus 21    33';
  'Bus 22    33';
  'Bus 23    33';
  'Bus 24    33';
  'Bus 25    33';
  'Bus 26    33';
  'Cloverdle 33';
  'Cloverdle132';
  'Bus 29    33';
  'Bus 30    33';
};

% Warnings from cdf2matp conversion:
%
% ***** check the title format in the first line of the cdf file.
% ***** Qmax = Qmin at generator at bus    1 (Qmax set to Qmin + 10)
% ***** MVA limit of branch 1 - 2 not given, set to 0
% ***** MVA limit of branch 1 - 3 not given, set to 0
% ***** MVA limit of branch 2 - 4 not given, set to 0
% ***** MVA limit of branch 3 - 4 not given, set to 0
% ***** MVA limit of branch 2 - 5 not given, set to 0
% ***** MVA limit of branch 2 - 6 not given, set to 0
% ***** MVA limit of branch 4 - 6 not given, set to 0
% ***** MVA limit of branch 5 - 7 not given, set to 0
% ***** MVA limit of branch 6 - 7 not given, set to 0
% ***** MVA limit of branch 6 - 8 not given, set to 0
% ***** MVA limit of branch 6 - 9 not given, set to 0
% ***** MVA limit of branch 6 - 10 not given, set to 0
% ***** MVA limit of branch 9 - 11 not given, set to 0
% ***** MVA limit of branch 9 - 10 not given, set to 0
% ***** MVA limit of branch 4 - 12 not given, set to 0
% ***** MVA limit of branch 12 - 13 not given, set to 0
% ***** MVA limit of branch 12 - 14 not given, set to 0
% ***** MVA limit of branch 12 - 15 not given, set to 0
% ***** MVA limit of branch 12 - 16 not given, set to 0
% ***** MVA limit of branch 14 - 15 not given, set to 0
% ***** MVA limit of branch 16 - 17 not given, set to 0
% ***** MVA limit of branch 15 - 18 not given, set to 0
% ***** MVA limit of branch 18 - 19 not given, set to 0
% ***** MVA limit of branch 19 - 20 not given, set to 0
% ***** MVA limit of branch 10 - 20 not given, set to 0
% ***** MVA limit of branch 10 - 17 not given, set to 0
% ***** MVA limit of branch 10 - 21 not given, set to 0
% ***** MVA limit of branch 10 - 22 not given, set to 0
% ***** MVA limit of branch 21 - 22 not given, set to 0
% ***** MVA limit of branch 15 - 23 not given, set to 0
% ***** MVA limit of branch 22 - 24 not given, set to 0
% ***** MVA limit of branch 23 - 24 not given, set to 0
% ***** MVA limit of branch 24 - 25 not given, set to 0
% ***** MVA limit of branch 25 - 26 not given, set to 0
% ***** MVA limit of branch 25 - 27 not given, set to 0
% ***** MVA limit of branch 28 - 27 not given, set to 0
% ***** MVA limit of branch 27 - 29 not given, set to 0
% ***** MVA limit of branch 27 - 30 not given, set to 0
% ***** MVA limit of branch 29 - 30 not given, set to 0
% ***** MVA limit of branch 8 - 28 not given, set to 0
% ***** MVA limit of branch 6 - 28 not given, set to 0


function opt = mpoption(varargin)
%MPOPTION  Used to set and retrieve a MATPOWER options struct.
%
%   OPT = MPOPTION
%       Returns the default options struct.
%
%   OPT = MPOPTION(OVERRIDES)
%       Returns the default options struct, with some fields overridden
%       by values from OVERRIDES, which can be a struct or the name of
%       a function that returns a struct.
%T0 is an options struct it does nothing.
%
%   OPT = MPOPTION(OPT0, OVERRIDES)
%       Applies overrides to an existing set of options, OPT0, which
%       can be an old-style options vector or an options struct.
%
%   OPT = MPOPTION(OPT0, NAME1, VALUE1, NAME2, VALUE2, ...)
%       Same as above except it uses the old-style options vector OPT0
%       as a base instead of the old default options vector.
%
%   OPT_VECTOR = MPOPTION(OPT, [])
%       Creates and returns an old-style options vector from an
%       options struct OPT.
%
%   Note: The use of old-style MATPOWER options vectors and their
%         names and values has been deprecated and will be removed
%         in a future version of MATPOWER. Until then, all uppercase
%         option names are not permitted for new top-level options.
%
%   Examples:
%       mpopt = mpoption('pf.alg', 'FDXB', 'pf.tol', 1e-4);
%       mpopt = mpoption(mpopt, 'opf.dc.solver', 'CPLEX', 'verbose', 2);
%
%The currently defined options are as follows:
%
%   name                    default     description [options]
%----------------------    ---------   ----------------------------------
%Model options:
%   model                   'AC'        AC vs. DC power flow model
%       [ 'AC' - use nonlinear AC model & corresponding algorithms/options  ]
%       [ 'DC' - use linear DC model & corresponding algorithms/options     ]
%
%Power Flow options:
%   pf.alg                  'NR'        AC power flow algorithm
%       [ 'NR'   - Newton's method                                          ]
%       [ 'FDXB' - Fast-Decoupled (XB version)                              ]
%       [ 'FDBX' - Fast-Decoupled (BX version)                              ]
%       [ 'GS'   - Gauss-Seidel                                             ]
%   pf.tol                  1e-8        termination tolerance on per unit
%                                       P & Q mismatch
%   pf.nr.max_it            10          maximum number of iterations for
%                                       Newton's method
%   pf.fd.max_it            30          maximum number of iterations for
%                                       fast decoupled method
%   pf.gs.max_it            1000        maximum number of iterations for
%                                       Gauss-Seidel method
%   pf.enforce_q_lims       0           enforce gen reactive power limits at
%                                       expense of |V|
%       [  0 - do NOT enforce limits                                        ]
%       [  1 - enforce limits, simultaneous bus type conversion             ]
%       [  2 - enforce limits, one-at-a-time bus type conversion            ]
%
%Continuation Power Flow options:
%   cpf.parameterization    3           choice of parameterization
%       [  1 - natural                                                      ]
%       [  2 - arc length                                                   ]
%       [  3 - pseudo arc length                                            ]
%   cpf.stop_at             'NOSE'      determins stopping criterion
%       [ 'NOSE'     - stop when nose point is reached                      ]
%       [ 'FULL'     - trace full nose curve                                ]
%       [ <lam_stop> - stop upon reaching specified target lambda value     ]
%   cpf.step                0.05        continuation power flow step size
%   cpf.adapt_step          0           toggle adaptive step size feature
%       [  0 - adaptive step size disabled                                  ]
%       [  1 - adaptive step size enabled                                   ]
%   cpf.error_tol           1e-3        tolerance for adaptive step control
%   cpf.step_min            1e-4        minimum allowed step size
%   cpf.step_max            0.2         maximum allowed step size
%   cpf.plot.level          0           control plotting of noze curve
%       [  0 - do not plot nose curve                                       ]
%       [  1 - plot when completed                                          ]
%       [  2 - plot incrementally at each iteration                         ]
%       [  3 - same as 2, with 'pause' at each iteration                    ]
%   cpf.plot.bus            <empty>     index of bus whose voltage is to be
%                                       plotted
%   cpf.user_callback       <empty>     string or cell array of strings
%                                       with names of user callback functions
%                                       see 'help cpf_default_callback'
%   cpf.user_callback_args  <empty>     struct passed to user-defined
%                                       callback functions
%
%Optimal Power Flow options:
%   name                    default     description [options]
%----------------------    ---------   ----------------------------------
%   opf.ac.solver           'DEFAULT'   AC optimal power flow solver
%       [ 'DEFAULT' - choose solver based on availability in the following  ]
%       [             order: 'PDIPM', 'MIPS'                                ]
%       [ 'MIPS'    - MIPS, Matlab Interior Point Solver, primal/dual       ]
%       [             interior point method (pure Matlab)                   ]
%       [ 'FMINCON' - MATLAB Optimization Toolbox, FMINCON                  ]
%       [ 'IPOPT'   - IPOPT, requires MEX interface to IPOPT solver         ]
%       [             available from:                                       ]
%       [                 http://www.coin-or.org/projects/Ipopt.xml         ]
%       [ 'KNITRO'  - KNITRO, requires MATLAB Optimization Toolbox and      ]
%       [             KNITRO libraries available from: http://www.ziena.com/]
%       [ 'MINOPF'  - MINOPF, MINOS-based solver, requires optional         ]
%       [             MEX-based MINOPF package, available from:             ]
%       [                   http://www.pserc.cornell.edu/minopf/            ]
%       [ 'PDIPM'   - PDIPM, primal/dual interior point method, requires    ]
%       [             optional MEX-based TSPOPF package, available from:    ]
%       [                   http://www.pserc.cornell.edu/tspopf/            ]
%       [ 'SDPOPF'  - SDPOPF, solver based on semidefinite relaxation of    ]
%       [             OPF problem, requires optional packages:              ]
%       [               SDP_PF, available in extras/sdp_pf                  ]
%       [               YALMIP, available from:                             ]
%       [                   http://users.isy.liu.se/johanl/yalmip/          ]
%       [               SDP solver such as SeDuMi, available from:          ]
%       [                   http://sedumi.ie.lehigh.edu/                    ]
%       [ 'TRALM'   - TRALM, trust region based augmented Langrangian       ]
%       [             method, requires TSPOPF (see 'PDIPM')                 ]
%   opf.dc.solver           'DEFAULT'   DC optimal power flow solver
%       [ 'DEFAULT' - choose solver based on availability in the following  ]
%       [             order: 'GUROBI', 'CPLEX', 'MOSEK', 'OT',              ]
%       [             'GLPK' (linear costs only), 'BPMPD', 'MIPS'           ]
%       [ 'MIPS'    - MIPS, Matlab Interior Point Solver, primal/dual       ]
%       [             interior point method (pure Matlab)                   ]
%       [ 'BPMPD'   - BPMPD, requires optional MEX-based BPMPD_MEX package  ]
%       [             available from: http://www.pserc.cornell.edu/bpmpd/   ]
%       [ 'CLP'     - CLP, requires interface to COIN-OP LP solver          ]
%       [             available from:http://www.coin-or.org/projects/Clp.xml]
%       [ 'CPLEX'   - CPLEX, requires CPLEX solver available from:          ]
%       [             http://www.ibm.com/software/integration/ ...          ]
%       [                                 ... optimization/cplex-optimizer/ ]
%       [ 'GLPK'    - GLPK, requires interface to GLPK solver               ]
%       [             available from: http://www.gnu.org/software/glpk/     ]
%       [             (GLPK does not work with quadratic cost functions)    ]
%       [ 'GUROBI'  - GUROBI, requires Gurobi optimizer (v. 5+)             ]
%       [             available from: http://www.gurobi.com/                ]
%       [ 'IPOPT'   - IPOPT, requires MEX interface to IPOPT solver         ]
%       [             available from:                                       ]
%       [                 http://www.coin-or.org/projects/Ipopt.xml         ]
%       [ 'MOSEK'   - MOSEK, requires Matlab interface to MOSEK solver      ]
%       [             available from: http://www.mosek.com/                 ]
%       [ 'OT'      - MATLAB Optimization Toolbox, QUADPROG, LINPROG        ]
%   opf.violation           5e-6        constraint violation tolerance
%   opf.flow_lim            'S'         quantity limited by branch flow
%                                       constraints
%       [ 'S' - apparent power flow (limit in MVA)                          ]
%       [ 'P' - active power flow (limit in MW)                             ]
%       [ 'I' - current magnitude (limit in MVA at 1 p.u. voltage)          ]
%   opf.ignore_angle_lim    0           angle diff limits for branches
%       [ 0 - include angle difference limits, if specified                 ]
%       [ 1 - ignore angle difference limits even if specified              ]
%   opf.init_from_mpc       -1          specify whether to use current state
%                                       in MATPOWER case to initialize OPF
%                                       (currently supported only for Ipopt,
%                                        Knitro and MIPS solvers)
%       [  -1 - MATPOWER decides, based on solver/algorithm                 ]
%       [   0 - ignore current state when initializing OPF                  ]
%       [   1 - use current state to initialize OPF                         ]
%   opf.return_raw_der      0           for AC OPF, return constraint and
%                                       derivative info in results.raw
%                                       (in fields g, dg, df, d2f) [ 0 or 1 ]
%
%Output options:
%   name                    default     description [options]
%----------------------    ---------   ----------------------------------
%   verbose                 1           amount of progress info printed
%       [   0 - print no progress info                                      ]
%       [   1 - print a little progress info                                ]
%       [   2 - print a lot of progress info                                ]
%       [   3 - print all progress info                                     ]
%   out.all                 -1          controls pretty-printing of results
%       [  -1 - individual flags control what prints                        ]
%       [   0 - do not print anything (overrides individual flags, ignored  ]
%       [       for files specified as FNAME arg to runpf(), runopf(), etc.)]
%       [   1 - print everything (overrides individual flags)               ]
%   out.sys_sum             1           print system summary       [ 0 or 1 ]
%   out.area_sum            0           print area summaries       [ 0 or 1 ]
%   out.bus                 1           print bus detail           [ 0 or 1 ]
%   out.branch              1           print branch detail        [ 0 or 1 ]
%   out.gen                 0           print generator detail     [ 0 or 1 ]
%   out.lim.all             -1          controls constraint info output
%       [  -1 - individual flags control what constraint info prints        ]
%       [   0 - no constraint info (overrides individual flags)             ]
%       [   1 - binding constraint info (overrides individual flags)        ]
%       [   2 - all constraint info (overrides individual flags)            ]
%   out.lim.v               1           control voltage limit info
%       [   0 - do not print                                                ]
%       [   1 - print binding constraints only                              ]
%       [   2 - print all constraints                                       ]
%       [   (same options for OUT_LINE_LIM, OUT_PG_LIM, OUT_QG_LIM)         ]
%   out.lim.line            1           control line flow limit info
%   out.lim.pg              1           control gen active power limit info
%   out.lim.qg              1           control gen reactive pwr limit info
%   out.force               0           print results even if success
%                                       flag = 0                   [ 0 or 1 ]
%   out.suppress_detail     -1          suppress all output but system summary
%       [  -1 - suppress details for large systems (> 500 buses)            ]
%       [   0 - do not suppress any output specified by other flags         ]
%       [   1 - suppress all output except system summary section           ]
%       [       (overrides individual flags, but not out.all = 1)           ]
%
%Solver specific options:
%       name                    default     description [options]
%   -----------------------    ---------   ----------------------------------
%   MIPS:
%       mips.linsolver          ''          linear system solver
%           [   '' or '\'   build-in backslash \ operator (e.g. x = A \ b)  ]
%           [   'PARDISO'   PARDISO solver (if available)                   ]
%       mips.feastol            0           feasibility (equality) tolerance
%                                           (set to opf.violation by default)
%       mips.gradtol            1e-6        gradient tolerance
%       mips.comptol            1e-6        complementary condition
%                                           (inequality) tolerance
%       mips.costtol            1e-6        optimality tolerance
%       mips.max_it             150         maximum number of iterations
%       mips.step_control       0           enable step-size cntrl [ 0 or 1 ]
%       mips.sc.red_it          20          maximum number of reductions per
%                                           iteration with step control
%       mips.xi                 0.99995     constant used in alpha updates*
%       mips.sigma              0.1         centering parameter*
%       mips.z0                 1           used to initialize slack variables*
%       mips.alpha_min          1e-8        returns "Numerically Failed" if
%                                           either alpha parameter becomes
%                                           smaller than this value*
%       mips.rho_min            0.95        lower bound on rho_t*
%       mips.rho_max            1.05        upper bound on rho_t*
%       mips.mu_threshold       1e-5        KT multipliers smaller than this
%                                           value for non-binding constraints
%                                           are forced to zero
%       mips.max_stepsize       1e10        returns "Numerically Failed" if the
%                                           2-norm of the reduced Newton step
%                                           exceeds this value*
%           * See the corresponding Appendix in the manual for details.
%
%   CPLEX:
%       cplex.lpmethod          0           solution algorithm for LP problems
%           [   0 - automatic: let CPLEX choose                             ]
%           [   1 - primal simplex                                          ]
%           [   2 - dual simplex                                            ]
%           [   3 - network simplex                                         ]
%           [   4 - barrier                                                 ]
%           [   5 - sifting                                                 ]
%           [   6 - concurrent (dual, barrier, and primal)                  ]
%       cplex.qpmethod          0           solution algorithm for QP problems
%           [   0 - automatic: let CPLEX choose                             ]
%           [   1 - primal simplex optimizer                                ]
%           [   2 - dual simplex optimizer                                  ]
%           [   3 - network optimizer                                       ]
%           [   4 - barrier optimizer                                       ]
%       cplex.opts              <empty>     see CPLEX_OPTIONS for details
%       cplex.opt_fname         <empty>     see CPLEX_OPTIONS for details
%       cplex.opt               0           see CPLEX_OPTIONS for details
%
%   FMINCON:
%       fmincon.alg             4           algorithm used by fmincon() for OPF
%                                           for Opt Toolbox 4 and later
%            [  1 - active-set (not suitable for large problems)            ]
%            [  2 - interior-point, w/default 'bfgs' Hessian approx         ]
%            [  3 - interior-point, w/ 'lbfgs' Hessian approx               ]
%            [  4 - interior-point, w/exact user-supplied Hessian           ]
%            [  5 - interior-point, w/Hessian via finite differences        ]
%            [  6 - sqp (not suitable for large problems)                   ]
%       fmincon.tol_x           1e-4        termination tol on x
%       fmincon.tol_f           1e-4        termination tol on f
%       fmincon.max_it          0           maximum number of iterations
%                                                           [  0 => default ]
%
%   GUROBI:
%       gurobi.method           0           solution algorithm (Method)
%           [  -1 - automatic, let Gurobi decide                            ]
%           [   0 - primal simplex                                          ]
%           [   1 - dual simplex                                            ]
%           [   2 - barrier                                                 ]
%           [   3 - concurrent (LP only)                                    ]
%           [   4 - deterministic concurrent (LP only)                      ]
%       gurobi.timelimit        Inf         maximum time allowed (TimeLimit)
%       gurobi.threads          0           max number of threads (Threads)
%       gurobi.opts             <empty>     see GUROBI_OPTIONS for details
%       gurobi.opt_fname        <empty>     see GUROBI_OPTIONS for details
%       gurobi.opt              0           see GUROBI_OPTIONS for details
%
%   IPOPT:
%       ipopt.opts              <empty>     see IPOPT_OPTIONS for details
%       ipopt.opt_fname         <empty>     see IPOPT_OPTIONS for details
%       ipopt.opt               0           see IPOPT_OPTIONS for details
%
%   KNITRO:
%       knitro.tol_x            1e-4        termination tol on x
%       knitro.tol_f            1e-4        termination tol on f
%       knitro.opt_fname        <empty>     name of user-supplied native
%                                           KNITRO options file that overrides
%                                           all other options
%       knitro.opt              0           if knitro.opt_fname is empty and
%                                           knitro.opt is a non-zero integer N
%                                           then knitro.opt_fname is auto-
%                                           generated as:
%                                           'knitro_user_options_N.txt'
%
%   LINPROG:
%       linprog                 <empty>     LINPROG options passed to
%                                           OPTIMOPTIONS or OPTIMSET.
%                                           see LINPROG in the Optimization
%                                           Toolbox for details
%
%   MINOPF:
%       minopf.feastol          0 (1e-3)    primal feasibility tolerance
%                                           (set to opf.violation by default)
%       minopf.rowtol           0 (1e-3)    row tolerance
%       minopf.xtol             0 (1e-4)    x tolerance
%       minopf.majdamp          0 (0.5)     major damping parameter
%       minopf.mindamp          0 (2.0)     minor damping parameter
%       minopf.penalty          0 (1.0)     penalty parameter
%       minopf.major_it         0 (200)     major iterations
%       minopf.minor_it         0 (2500)    minor iterations
%       minopf.max_it           0 (2500)    iterations limit
%       minopf.verbosity        -1          amount of progress info printed
%           [  -1 - controlled by 'verbose' option                          ]
%           [   0 - print nothing                                           ]
%           [   1 - print only termination status message                   ]
%           [   2 - print termination status and screen progress            ]
%           [   3 - print screen progress, report file (usually fort.9)     ]
%       minopf.core             0 (1200*nb + 2*(nb+ng)^2) memory allocation
%       minopf.supbasic_lim     0 (2*nb + 2*ng) superbasics limit
%       minopf.mult_price       0 (30)      multiple price
%
%   MOSEK:
%       mosek.lp_alg            0           solution algorithm for LP problems
%                                               (MSK_IPAR_OPTIMIZER)
%           for MOSEK 7.x ...        (see MOSEK_SYMBCON for a "better way")
%           [   0 - automatic: let MOSEK choose                             ]
%           [   1 - interior point                                          ]
%           [   3 - primal simplex                                          ]
%           [   4 - dual simplex                                            ]
%           [   5 - primal dual simplex                                     ]
%           [   6 - automatic simplex (MOSEK chooses which simplex method)  ]
%           [   7 - network primal simplex                                  ]
%           [   10 - concurrent                                             ]
%       mosek.max_it            0 (400)     interior point max iterations
%                                               (MSK_IPAR_INTPNT_MAX_ITERATIONS)
%       mosek.gap_tol           0 (1e-8)    interior point relative gap tol
%                                               (MSK_DPAR_INTPNT_TOL_REL_GAP)
%       mosek.max_time          0 (-1)      maximum time allowed
%                                               (MSK_DPAR_OPTIMIZER_MAX_TIME)
%       mosek.num_threads       0 (1)       max number of threads
%                                               (MSK_IPAR_INTPNT_NUM_THREADS)
%       mosek.opts              <empty>     see MOSEK_OPTIONS for details
%       mosek.opt_fname         <empty>     see MOSEK_OPTIONS for details
%       mosek.opt               0           see MOSEK_OPTIONS for details
%
%   QUADPROG:
%       quadprog                <empty>     QUADPROG options passed to
%                                           OPTIMOPTIONS or OPTIMSET.
%                                           see QUADPROG in the Optimization
%                                           Toolbox for details
%
%   TSPOPF:
%       pdipm.feastol           0           feasibility (equality) tolerance
%                                           (set to opf.violation by default)
%       pdipm.gradtol           1e-6        gradient tolerance
%       pdipm.comptol           1e-6        complementary condition
%                                           (inequality) tolerance
%       pdipm.costtol           1e-6        optimality tolerance
%       pdipm.max_it            150         maximum number of iterations
%       pdipm.step_control      0           enable step-size cntrl [ 0 or 1 ]
%       pdipm.sc.red_it         20          maximum number of reductions per
%                                           iteration with step control
%       pdipm.sc.smooth_ratio   0.04        piecewise linear curve smoothing
%                                           ratio
%
%       tralm.feastol           0           feasibility tolerance
%                                           (set to opf.violation by default)
%       tralm.primaltol         5e-4        primal variable tolerance
%       tralm.dualtol           5e-4        dual variable tolerance
%       tralm.costtol           1e-5        optimality tolerance
%       tralm.major_it          40          maximum number of major iterations
%       tralm.minor_it          40          maximum number of minor iterations
%       tralm.smooth_ratio      0.04        piecewise linear curve smoothing
%                                           ratio
%
%Experimental Options:
%   exp.sys_wide_zip_loads.pw   <empty>     1 x 3 vector of active load fraction
%                                           to be modeled as constant power,
%                                           constant current and constant
%                                           impedance, respectively, where
%                                           <empty> means use [1 0 0]
%   exp.sys_wide_zip_loads.qw   <empty>     same for reactive power, where
%                                           <empty> means use same value as
%                                           for 'pw'

%   MATPOWER
%   Copyright (c) 2013-2016 by Power System Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%% some constants
N = 124;                %% number of options in old-style vector
v = mpoption_version;   %% version number of MATPOWER options struct

%% initialize flags and arg counter
have_opt0 = 0;          %% existing options struct or vector provided?
have_old_style_ov = 0;  %% override options using old-style names?
return_old_style = 0;   %% return value as old-style vector?
k = 1;
if nargin > 0
    opt0 = varargin{k};
    if (isstruct(opt0) && isfield(opt0, 'v')) || ...
        (isnumeric(opt0) && size(opt0, 1) == N && size(opt0, 2) == 1)
        have_opt0 = 1;
        k = k + 1;
    end
end

%% create base options vector to which overrides are made
if have_opt0
    if isstruct(opt0)               %% it's already a valid options struct
        if DEBUG, fprintf('OPT0 is a valid options struct\n'); end
        if opt0.v < v
            %% convert older version to current version
            opt_d = mpoption_default();
            if opt0.v == 1          %% convert version 1 to 2
                if isfield(opt_d, 'linprog')
                    opt0.lingprog = opt_d.linprog;
                end
                if isfield(opt_d, 'quadprog')
                    opt0.quadprog = opt_d.quadprog;
                end
            end
            if opt0.v <= 2          %% convert version 2 to 3
                opt0.out.suppress_detail = opt_d.out.suppress_detail;
            end
            %if opt0.v <= 3          %% convert version 3 to 4
                %% new mips options were all optional, no conversion needed
            %end
            if opt0.v <= 4          %% convert version 4 to 5
                opt0.opf.init_from_mpc = opt_d.opf.init_from_mpc;
            end
            if opt0.v <= 5          %% convert version 5 to 6
                if isfield(opt_d, 'clp')
                    opt0.clp = opt_d.clp;
                end
            end
            if opt0.v <= 6          %% convert version 6 to 7
                if isfield(opt_d, 'intlinprog')
                    opt0.intlinprog = opt_d.intlinprog;
                end
            end
            if opt0.v <= 7          %% convert version 7 to 8
                opt0.mips.linsolver = opt_d.mips.linsolver;
            end
            if opt0.v <= 8          %% convert version 8 to 9
                opt0.exp.sys_wide_zip_loads = opt_d.exp.sys_wide_zip_loads;
            end
            opt0.v = v;
        end
        opt = opt0;
    else                            %% convert from old-style options vector
        if DEBUG, fprintf('OPT0 is a old-style options vector\n'); end
        opt = mpoption_v2s(opt0);
    end
else                                %% use default options struct as base
    if DEBUG, fprintf('no OPT0, starting with default options struct\n'); end
    opt = mpoption_default();
end


%% do we have OVERRIDES or NAME/VALUE pairs
ov = [];
if nargin - k == 0          %% looking at last arg, must be OVERRIDES
    if isstruct(varargin{k})        %% OVERRIDES provided as struct
        if DEBUG, fprintf('OVERRIDES struct\n'); end
        ov = varargin{k};
    elseif ischar(varargin{k})      %% OVERRIDES provided as file/function name
        if DEBUG, fprintf('OVERRIDES file/function name\n'); end
        try
            ov = feval(varargin{k});
        catch
            error('mpoption: Unable to load MATPOWER options from ''%s''', varargin{k});
        end
        if ~isstruct(ov)
            error('mpoption: calling ''%s'' did not return a struct', varargin{k});
        end
    elseif isempty(varargin{k})
        return_old_style = 1;
    else
        error('mpoption: OVERRIDES must be a struct or the name of a function that returns a struct');
    end
elseif nargin - k > 0 && mod(nargin-k, 2)   %% even number of remaining args
    if DEBUG, fprintf('NAME/VALUE pairs override defaults\n'); end
    %% process NAME/VALUE pairs
    if (have_opt0 && isnumeric(opt0)) ...   %% modifying an old-style options vector
            || strcmp(varargin{k}, upper(varargin{k}))
            %% this code implies that top-level option fields
            %% cannot be all uppercase
        if have_opt0
            have_old_style_ov = 1;
            %% convert pairs to struct
            while k < nargin
                name = varargin{k};
                val  = varargin{k+1};
                k = k + 2;
                ov.(name) = val;
            end
        else
            opt_v = mpoption_old(varargin{:});  %% create modified vector ...
            opt = mpoption_v2s(opt_v);          %% ... then convert
        end
    else                                    %% modifying options struct
        %% convert pairs to struct
        while k < nargin
            name = varargin{k};
            val  = varargin{k+1};
            k = k + 2;
            c = regexp(name, '([^\.]*)', 'tokens');
            s = struct();
            for i = 1:length(c)
                s(i).type = '.';
                s(i).subs = c{i}{1};
            end
            ov = subsasgn(ov, s, val);
        end
    end
elseif nargin == 0 || nargin == 1
    if DEBUG, fprintf('no OVERRIDES, return default options struct or converted OPT0 vector\n'); end
else
    error('mpoption: invalid calling syntax, see ''help mpoption'' to double-check the valid options');
end

%% apply overrides
if ~isempty(ov)
    if have_old_style_ov
        opt = apply_old_mpoption_overrides(opt, ov);
    else
        persistent nsc_opt;     %% cache this to speed things up
        if ~isstruct(nsc_opt)
            vf = nested_struct_copy(mpoption_default(), mpoption_info_mips('V'));
            vf = nested_struct_copy(vf, mpoption_optional_fields());
            ex = struct(...
                'name', {...
                    'cpf.user_callback_args' ...
                }, ...
                'check', {...
                    0 ...
                }, ...
                'copy_mode', {...
                    '' ...
                } ...
            );
            %% add exceptions for optional packages
            opt_pkgs = mpoption_optional_pkgs();
            n = length(ex);
            for k = 1:length(opt_pkgs)
                fname = ['mpoption_info_' opt_pkgs{k}];
                if exist(fname, 'file') == 2
                    opt_ex = feval(fname, 'E');
                    nex = length(opt_ex);
                    if ~isempty(opt_ex)
                        for j = 1:nex
                            ex(n+j).name = opt_ex(j).name;
                        end
                        if isfield(opt_ex, 'check')
                            for j = 1:nex
                                ex(n+j).check = opt_ex(j).check;
                            end
                        end
                        if isfield(opt_ex, 'copy_mode')
                            for j = 1:nex
                                ex(n+j).copy_mode = opt_ex(j).copy_mode;
                            end
                        end
                        if isfield(opt_ex, 'valid_fields')
                            for j = 1:nex
                                ex(n+j).valid_fields = opt_ex(j).valid_fields;
                            end
                        end
                        n = n + nex;
                    end
                end
            end
            nsc_opt = struct('check', 1, 'valid_fields', vf, 'exceptions', ex);
        end
%         if have_fcn('catchme')
%             try
%                 opt = nested_struct_copy(opt, ov, nsc_opt);
%             catch me
%                 str = strrep(me.message, 'field', 'option');
%                 str = strrep(str, 'nested_struct_copy', 'mpoption');
%                 error(str);
%             end
%         else
            try
                opt = nested_struct_copy(opt, ov, nsc_opt);
            catch
                me = lasterr;
                str = strrep(me, 'field', 'option');
                str = strrep(str, 'nested_struct_copy', 'mpoption');
                error(str);
            end
%         end
    end
end
if return_old_style
    opt = mpoption_s2v(opt);
end


%%-------------------------------------------------------------------
function opt = apply_old_mpoption_overrides(opt0, ov)
%
%   OPT0 is assumed to already have all of the fields and sub-fields found
%   in the default options struct.

%% initialize output
opt = opt0;

errstr = 'mpoption: %g is not a valid value for the old-style ''%s'' option';
fields = fieldnames(ov);
for f = 1:length(fields)
    ff = fields{f};
    switch ff
        case 'PF_ALG'
            switch ov.(ff)
                case 1
                    opt.pf.alg = 'NR';      %% Newton's method
                case 2
                    opt.pf.alg = 'FDXB';    %% fast-decoupled (XB version)
                case 3
                    opt.pf.alg = 'FDBX';    %% fast-decoupled (BX version)
                case 4
                    opt.pf.alg = 'GS';      %% Gauss-Seidel
                otherwise
                    error(errstr, ov.(ff), ff);
            end
        case 'PF_TOL'
            opt.pf.tol = ov.(ff);
        case 'PF_MAX_IT'
            opt.pf.nr.max_it = ov.(ff);
        case 'PF_MAX_IT_FD'
            opt.pf.fd.max_it = ov.(ff);
        case 'PF_MAX_IT_GS'
            opt.pf.gs.max_it = ov.(ff);
        case 'ENFORCE_Q_LIMS'
            opt.pf.enforce_q_lims = ov.(ff);
        case 'PF_DC'
            switch ov.(ff)
                case 0
                    opt.model = 'AC';
                case 1
                    opt.model = 'DC';
                otherwise
                    error(errstr, ov.(ff), ff);
            end
        case 'OPF_ALG'
            switch ov.(ff)
                case 0
                    opt.opf.ac.solver = 'DEFAULT';
                case 500
                    opt.opf.ac.solver = 'MINOPF';
                case 520
                    opt.opf.ac.solver = 'FMINCON';
                case {540, 545}
                    opt.opf.ac.solver = 'PDIPM';
                    if ov.(ff) == 545
                        opt.pdipm.step_control = 1;
                    else
                        opt.pdipm.step_control = 0;
                    end
                case 550
                    opt.opf.ac.solver = 'TRALM';
                case {560, 565}
                    opt.opf.ac.solver = 'MIPS';
                    if ov.(ff) == 565
                        opt.mips.step_control = 1;
                    else
                        opt.mips.step_control = 0;
                    end
                case 580
                    opt.opf.ac.solver = 'IPOPT';
                case 600
                    opt.opf.ac.solver = 'KNITRO';
                otherwise
                    error(errstr, ov.(ff), ff);
            end
        case 'OPF_VIOLATION'
            opt.opf.violation = ov.(ff);
        case 'CONSTR_TOL_X'
            opt.fmincon.tol_x = ov.(ff);
            opt.knitro.tol_x = ov.(ff);
        case 'CONSTR_TOL_F'
            opt.fmincon.tol_f = ov.(ff);
            opt.knitro.tol_f = ov.(ff);
        case 'CONSTR_MAX_IT'
            opt.fmincon.max_it = ov.(ff);
        case 'OPF_FLOW_LIM'
            switch ov.(ff)
                case 0
                    opt.opf.flow_lim = 'S';   %% apparent power (MVA)
                case 1
                    opt.opf.flow_lim = 'P';   %% real power (MW)
                case 2
                    opt.opf.flow_lim = 'I';   %% current magnitude (MVA @ 1 p.u. voltage)
                otherwise
                    error(errstr, ov.(ff), ff);
            end
        case 'OPF_IGNORE_ANG_LIM'
            opt.opf.ignore_angle_lim = ov.(ff);
        case 'OPF_ALG_DC'
            switch ov.(ff)
                case 0
                    opt.opf.dc.solver = 'DEFAULT';
                case 100
                    opt.opf.dc.solver = 'BPMPD';
                case {200, 250}
                    opt.opf.dc.solver = 'MIPS';
                    if ov.(ff) == 250
                        opt.mips.step_control = 1;
                    else
                        opt.mips.step_control = 0;
                    end
                case 300
                    opt.opf.dc.solver = 'OT';     %% QUADPROG, LINPROG
                case 400
                    opt.opf.dc.solver = 'IPOPT';
                case 500
                    opt.opf.dc.solver = 'CPLEX';
                case 600
                    opt.opf.dc.solver = 'MOSEK';
                case 700
                    opt.opf.dc.solver = 'GUROBI';
                otherwise
                    error(errstr, ov.(ff), ff);
            end
        case 'VERBOSE'
            opt.verbose = ov.(ff);
        case 'OUT_ALL'
            opt.out.all = ov.(ff);
        case 'OUT_SYS_SUM'
            opt.out.sys_sum = ov.(ff);
        case 'OUT_AREA_SUM'
            opt.out.area_sum = ov.(ff);
        case 'OUT_BUS'
            opt.out.bus = ov.(ff);
        case 'OUT_BRANCH'
            opt.out.branch = ov.(ff);
        case 'OUT_GEN'
            opt.out.gen = ov.(ff);
        case 'OUT_ALL_LIM'
            opt.out.lim.all = ov.(ff);
        case 'OUT_V_LIM'
            opt.out.lim.v = ov.(ff);
        case 'OUT_LINE_LIM'
            opt.out.lim.line = ov.(ff);
        case 'OUT_PG_LIM'
            opt.out.lim.pg = ov.(ff);
        case 'OUT_QG_LIM'
            opt.out.lim.qg = ov.(ff);
        case 'OUT_FORCE'
            opt.out.force = ov.(ff);
        case 'RETURN_RAW_DER'
            opt.opf.return_raw_der = ov.(ff);
        case 'FMC_ALG'
            opt.fmincon.alg = ov.(ff);
        case 'KNITRO_OPT'
            opt.knitro.opt = ov.(ff);
        case 'IPOPT_OPT'
            opt.ipopt.opt = ov.(ff);
        case 'MNS_FEASTOL'
            opt.minopf.feastol = ov.(ff);
        case 'MNS_ROWTOL'
            opt.minopf.rowtol = ov.(ff);
        case 'MNS_XTOL'
            opt.minopf.xtol = ov.(ff);
        case 'MNS_MAJDAMP'
            opt.minopf.majdamp = ov.(ff);
        case 'MNS_MINDAMP'
            opt.minopf.mindamp = ov.(ff);
        case 'MNS_PENALTY_PARM'
            opt.minopf.penalty = ov.(ff);
        case 'MNS_MAJOR_IT'
            opt.minopf.major_it = ov.(ff);
        case 'MNS_MINOR_IT'
            opt.minopf.minor_it = ov.(ff);
        case 'MNS_MAX_IT'
            opt.minopf.max_it = ov.(ff);
        case 'MNS_VERBOSITY'
            opt.minopf.verbosity = ov.(ff);
        case 'MNS_CORE'
            opt.minopf.core = ov.(ff);
        case 'MNS_SUPBASIC_LIM'
            opt.minopf.supbasic_lim = ov.(ff);
        case 'MNS_MULT_PRICE'
            opt.minopf.mult_price = ov.(ff);
        case 'FORCE_PC_EQ_P0'
            opt.sopf.force_Pc_eq_P0 = ov.(ff);
        case 'PDIPM_FEASTOL'
            opt.mips.feastol = ov.(ff);
            opt.pdipm.feastol = ov.(ff);
        case 'PDIPM_GRADTOL'
            opt.mips.gradtol = ov.(ff);
            opt.pdipm.gradtol = ov.(ff);
        case 'PDIPM_COMPTOL'
            opt.mips.comptol = ov.(ff);
            opt.pdipm.comptol = ov.(ff);
        case 'PDIPM_COSTTOL'
            opt.mips.costtol = ov.(ff);
            opt.pdipm.costtol = ov.(ff);
        case 'PDIPM_MAX_IT'
            opt.mips.max_it = ov.(ff);
            opt.pdipm.max_it = ov.(ff);
        case 'SCPDIPM_RED_IT'
            opt.mips.sc.red_it = ov.(ff);
            opt.pdipm.sc.red_it = ov.(ff);
        case 'TRALM_FEASTOL'
            opt.tralm.feastol = ov.(ff);
        case 'TRALM_PRIMETOL'
            opt.tralm.primaltol = ov.(ff);
        case 'TRALM_DUALTOL'
            opt.tralm.dualtol = ov.(ff);
        case 'TRALM_COSTTOL'
            opt.tralm.costtol = ov.(ff);
        case 'TRALM_MAJOR_IT'
            opt.tralm.major_it = ov.(ff);
        case 'TRALM_MINOR_IT'
            opt.tralm.minor_it = ov.(ff);
        case 'SMOOTHING_RATIO'
            opt.pdipm.sc.smooth_ratio = ov.(ff);
            opt.tralm.smooth_ratio = ov.(ff);
        case 'CPLEX_LPMETHOD'
            opt.cplex.lpmethod = ov.(ff);
        case 'CPLEX_QPMETHOD'
            opt.cplex.qpmethod = ov.(ff);
        case 'CPLEX_OPT'
            opt.cplex.opt = ov.(ff);
        case 'MOSEK_LP_ALG'
            opt.mosek.lp_alg = ov.(ff);
        case 'MOSEK_MAX_IT'
            opt.mosek.max_it = ov.(ff);
        case 'MOSEK_GAP_TOL'
            opt.mosek.gap_tol = ov.(ff);
        case 'MOSEK_MAX_TIME'
            opt.mosek.max_time = ov.(ff);
        case 'MOSEK_NUM_THREADS'
            opt.mosek.num_threads = ov.(ff);
        case 'MOSEK_OPT'
            opt.mosek.opt = ov.(ff);
        case 'GRB_METHOD'
            opt.gurobi.method = ov.(ff);
        case 'GRB_TIMELIMIT'
            opt.gurobi.timelimit = ov.(ff);
        case 'GRB_THREADS'
            opt.gurobi.threads = ov.(ff);
        case 'GRB_OPT'
            opt.gurobi.opt = ov.(ff);
        otherwise
            error('mpoption: ''%s'' is not a valid old-style option name', ff);
    end
end
% ov


%%-------------------------------------------------------------------
function opt_s = mpoption_v2s(opt_v)
if DEBUG, fprintf('mpoption_v2s()\n'); end
opt_s = mpoption_default();
errstr = 'mpoption: %g is not a valid value for the old-style ''%s'' option';
switch opt_v(1)                                 %% PF_ALG
    case 1
        opt_s.pf.alg = 'NR';        %% Newton's method
    case 2
        opt_s.pf.alg = 'FDXB';      %% fast-decoupled (XB version)
    case 3
        opt_s.pf.alg = 'FDBX';      %% fast-decoupled (BX version)
    case 4
        opt_s.pf.alg = 'GS';        %% Gauss-Seidel
    otherwise
        error(errstr, opt_v(1), 'PF_ALG');
end
opt_s.pf.tol                = opt_v(2);         %% PF_TOL
opt_s.pf.nr.max_it          = opt_v(3);         %% PF_MAX_IT
opt_s.pf.fd.max_it          = opt_v(4);         %% PF_MAX_IT_FD
opt_s.pf.gs.max_it          = opt_v(5);         %% PF_MAX_IT_GS
opt_s.pf.enforce_q_lims     = opt_v(6);         %% ENFORCE_Q_LIMS
switch opt_v(10)                                %% PF_DC
    case 0
        opt_s.model = 'AC';
    case 1
        opt_s.model = 'DC';
    otherwise
        error(errstr, opt_v(10), 'PF_DC');
end
switch opt_v(11)                                %% OPF_ALG
    case 0
        opt_s.opf.ac.solver = 'DEFAULT';
    case 500
        opt_s.opf.ac.solver = 'MINOPF';
    case 520
        opt_s.opf.ac.solver = 'FMINCON';
    case {540, 545}
        opt_s.opf.ac.solver = 'PDIPM';
    case 550
        opt_s.opf.ac.solver = 'TRALM';
    case {560, 565}
        opt_s.opf.ac.solver = 'MIPS';
    case 580
        opt_s.opf.ac.solver = 'IPOPT';
    case 600
        opt_s.opf.ac.solver = 'KNITRO';
    otherwise
        error(errstr, opt_v(11), 'OPF_ALG');
end
opt_s.opf.violation         = opt_v(16);        %% OPF_VIOLATION

opt_s.fmincon.tol_x         = opt_v(17);        %% CONSTR_TOL_X
opt_s.fmincon.tol_f         = opt_v(18);        %% CONSTR_TOL_F
opt_s.fmincon.max_it        = opt_v(19);        %% CONSTR_MAX_IT

opt_s.knitro.tol_x          = opt_v(17);        %% CONSTR_TOL_X
opt_s.knitro.tol_f          = opt_v(18);        %% CONSTR_TOL_F

switch opt_v(24)                                %% OPF_FLOW_LIM
    case 0
        opt_s.opf.flow_lim = 'S';   %% apparent power (MVA)
    case 1
        opt_s.opf.flow_lim = 'P';   %% real power (MW)
    case 2
        opt_s.opf.flow_lim = 'I';   %% current magnitude (MVA @ 1 p.u. voltage)
    otherwise
        error(errstr, opt_v(10), 'PF_DC');
end

opt_s.opf.ignore_angle_lim  = opt_v(25);        %% OPF_IGNORE_ANG_LIM

switch opt_v(26)                                %% OPF_ALG_DC
    case 0
        opt_s.opf.dc.solver = 'DEFAULT';
    case 100
        opt_s.opf.dc.solver = 'BPMPD';
    case {200, 250}
        opt_s.opf.dc.solver = 'MIPS';
    case 300
        opt_s.opf.dc.solver = 'OT';     %% QUADPROG, LINPROG
    case 400
        opt_s.opf.dc.solver = 'IPOPT';
    case 500
        opt_s.opf.dc.solver = 'CPLEX';
    case 600
        opt_s.opf.dc.solver = 'MOSEK';
    case 700
        opt_s.opf.dc.solver = 'GUROBI';
    otherwise
        error(errstr, opt_v(26), 'OPF_ALG_DC');
end

opt_s.verbose               = opt_v(31);        %% VERBOSE
opt_s.out.all               = opt_v(32);        %% OUT_ALL
opt_s.out.sys_sum           = opt_v(33);        %% OUT_SYS_SUM
opt_s.out.area_sum          = opt_v(34);        %% OUT_AREA_SUM
opt_s.out.bus               = opt_v(35);        %% OUT_BUS
opt_s.out.branch            = opt_v(36);        %% OUT_BRANCH
opt_s.out.gen               = opt_v(37);        %% OUT_GEN
opt_s.out.lim.all           = opt_v(38);        %% OUT_ALL_LIM
opt_s.out.lim.v             = opt_v(39);        %% OUT_V_LIM
opt_s.out.lim.line          = opt_v(40);        %% OUT_LINE_LIM
opt_s.out.lim.pg            = opt_v(41);        %% OUT_PG_LIM
opt_s.out.lim.qg            = opt_v(42);        %% OUT_QG_LIM
opt_s.out.force             = opt_v(44);        %% OUT_FORCE

opt_s.opf.return_raw_der    = opt_v(52);        %% RETURN_RAW_DER

opt_s.fmincon.alg           = opt_v(55);        %% FMC_ALG
opt_s.knitro.opt            = opt_v(58);        %% KNITRO_OPT
opt_s.ipopt.opt             = opt_v(60);        %% IPOPT_OPT

opt_s.minopf.feastol        = opt_v(61);        %% MNS_FEASTOL
opt_s.minopf.rowtol         = opt_v(62);        %% MNS_ROWTOL
opt_s.minopf.xtol           = opt_v(63);        %% MNS_XTOL
opt_s.minopf.majdamp        = opt_v(64);        %% MNS_MAJDAMP
opt_s.minopf.mindamp        = opt_v(65);        %% MNS_MINDAMP
opt_s.minopf.penalty        = opt_v(66);        %% MNS_PENALTY_PARM
opt_s.minopf.major_it       = opt_v(67);        %% MNS_MAJOR_IT
opt_s.minopf.minor_it       = opt_v(68);        %% MNS_MINOR_IT
opt_s.minopf.max_it         = opt_v(69);        %% MNS_MAX_IT
opt_s.minopf.verbosity      = opt_v(70);        %% MNS_VERBOSITY
opt_s.minopf.core           = opt_v(71);        %% MNS_CORE
opt_s.minopf.supbasic_lim   = opt_v(72);        %% MNS_SUPBASIC_LIM
opt_s.minopf.mult_price     = opt_v(73);        %% MNS_MULT_PRICE

opt_s.sopf.force_Pc_eq_P0   = opt_v(80);        %% FORCE_PC_EQ_P0, for c3sopf

if (opt_v(11) == 565 && opt_v(10) == 0) || (opt_v(26) == 250 && opt_v(10) == 1)
    opt_s.mips.step_control = 1;
end
opt_s.mips.feastol          = opt_v(81);        %% PDIPM_FEASTOL
opt_s.mips.gradtol          = opt_v(82);        %% PDIPM_GRADTOL
opt_s.mips.comptol          = opt_v(83);        %% PDIPM_COMPTOL
opt_s.mips.costtol          = opt_v(84);        %% PDIPM_COSTTOL
opt_s.mips.max_it           = opt_v(85);        %% PDIPM_MAX_IT
opt_s.mips.sc.red_it        = opt_v(86);        %% SCPDIPM_RED_IT

opt_s.pdipm.feastol         = opt_v(81);        %% PDIPM_FEASTOL
opt_s.pdipm.gradtol         = opt_v(82);        %% PDIPM_GRADTOL
opt_s.pdipm.comptol         = opt_v(83);        %% PDIPM_COMPTOL
opt_s.pdipm.costtol         = opt_v(84);        %% PDIPM_COSTTOL
opt_s.pdipm.max_it          = opt_v(85);        %% PDIPM_MAX_IT
opt_s.pdipm.sc.red_it       = opt_v(86);        %% SCPDIPM_RED_IT
opt_s.pdipm.sc.smooth_ratio = opt_v(93);        %% SMOOTHING_RATIO
if opt_v(11) == 545 && opt_v(10) == 0
    opt_s.pdipm.step_control = 1;
end

opt_s.tralm.feastol         = opt_v(87);        %% TRALM_FEASTOL
opt_s.tralm.primaltol       = opt_v(88);        %% TRALM_PRIMETOL
opt_s.tralm.dualtol         = opt_v(89);        %% TRALM_DUALTOL
opt_s.tralm.costtol         = opt_v(90);        %% TRALM_COSTTOL
opt_s.tralm.major_it        = opt_v(91);        %% TRALM_MAJOR_IT
opt_s.tralm.minor_it        = opt_v(92);        %% TRALM_MINOR_IT
opt_s.tralm.smooth_ratio    = opt_v(93);        %% SMOOTHING_RATIO

opt_s.cplex.lpmethod        = opt_v(95);        %% CPLEX_LPMETHOD
opt_s.cplex.qpmethod        = opt_v(96);        %% CPLEX_QPMETHOD
opt_s.cplex.opt             = opt_v(97);        %% CPLEX_OPT

opt_s.mosek.lp_alg          = opt_v(111);       %% MOSEK_LP_ALG
opt_s.mosek.max_it          = opt_v(112);       %% MOSEK_MAX_IT
opt_s.mosek.gap_tol         = opt_v(113);       %% MOSEK_GAP_TOL
opt_s.mosek.max_time        = opt_v(114);       %% MOSEK_MAX_TIME
opt_s.mosek.num_threads     = opt_v(115);       %% MOSEK_NUM_THREADS
opt_s.mosek.opt             = opt_v(116);       %% MOSEK_OPT

opt_s.gurobi.method         = opt_v(121);       %% GRB_METHOD
opt_s.gurobi.timelimit      = opt_v(122);       %% GRB_TIMELIMIT
opt_s.gurobi.threads        = opt_v(123);       %% GRB_THREADS
opt_s.gurobi.opt            = opt_v(124);       %% GRB_OPT
function opt_v = mpoption_s2v(opt_s)
if DEBUG, fprintf('mpoption_s2v()\n'); end
%% PF_ALG
old = mpoption_old;
switch upper(opt_s.pf.alg)
    case 'NR'
        PF_ALG = 1;
    case 'FDXB'
        PF_ALG = 2;
    case 'FDBX'
        PF_ALG = 3;
    case 'GS'
        PF_ALG = 4;
end

%% PF_DC
if strcmp(upper(opt_s.model), 'DC')
    PF_DC = 1;
else
    PF_DC = 0;
end

%% OPF_ALG
switch upper(opt_s.opf.ac.solver)
    case 'DEFAULT'
        OPF_ALG = 0;
    case 'MINOPF'
        OPF_ALG = 500;
    case 'FMINCON'
        OPF_ALG = 520;
    case 'PDIPM'
        if isfield(opt_s, 'pdipm') && opt_s.pdipm.step_control
            OPF_ALG = 545;
        else
            OPF_ALG = 540;
        end
    case 'TRALM'
        OPF_ALG = 550;
    case 'MIPS'
        if opt_s.mips.step_control
            OPF_ALG = 565;
        else
            OPF_ALG = 560;
        end
    case 'IPOPT'
        OPF_ALG = 580;
    case 'KNITRO'
        OPF_ALG = 600;
end

%% FMINCON, Knitro tol_x, tol_f, max_it
if strcmp(upper(opt_s.opf.ac.solver), 'KNITRO') && isfield(opt_s, 'knitro')
    CONSTR_TOL_X = opt_s.knitro.tol_x;
    CONSTR_TOL_F = opt_s.knitro.tol_f;
elseif isfield(opt_s, 'fmincon')
    CONSTR_TOL_X  = opt_s.fmincon.tol_x;
    CONSTR_TOL_F  = opt_s.fmincon.tol_f;
else
    CONSTR_TOL_X = old(17);
    CONSTR_TOL_F = old(18);
end
if isfield(opt_s, 'fmincon')
    CONSTR_MAX_IT   = opt_s.fmincon.max_it;
    FMC_ALG         = opt_s.fmincon.alg;
else
    CONSTR_MAX_IT   = old(19);
    FMC_ALG         = old(55);
end

%% OPF_FLOW_LIM
switch upper(opt_s.opf.flow_lim)
    case 'S'
        OPF_FLOW_LIM = 0;
    case 'P'
        OPF_FLOW_LIM = 1;
    case 'I'
        OPF_FLOW_LIM = 2;
end

%% OPF_ALG_DC
switch upper(opt_s.opf.dc.solver)
    case 'DEFAULT'
        OPF_ALG_DC = 0;
    case 'BPMPD'
        OPF_ALG_DC = 100;
    case 'MIPS'
        if opt_s.mips.step_control
            OPF_ALG_DC = 250;
        else
            OPF_ALG_DC = 200;
        end
    case 'OT'
        OPF_ALG_DC = 300;
    case 'IPOPT'
        OPF_ALG_DC = 400;
    case 'CPLEX'
        OPF_ALG_DC = 500;
    case 'MOSEK'
        OPF_ALG_DC = 600;
    case 'GUROBI'
        OPF_ALG_DC = 700;
end

%% KNITRO_OPT
if isfield(opt_s, 'knitro')
    KNITRO_OPT  = opt_s.knitro.opt;
else
    KNITRO_OPT  = old(58);
end

%% IPOPT_OPT
if isfield(opt_s, 'ipopt')
    IPOPT_OPT  = opt_s.ipopt.opt;
else
    IPOPT_OPT  = old(58);
end

%% MINOPF options
if isfield(opt_s, 'minopf')
    MINOPF_OPTS = [
        opt_s.minopf.feastol;   %% 61 - MNS_FEASTOL
        opt_s.minopf.rowtol;    %% 62 - MNS_ROWTOL
        opt_s.minopf.xtol;      %% 63 - MNS_XTOL
        opt_s.minopf.majdamp;   %% 64 - MNS_MAJDAMP
        opt_s.minopf.mindamp;   %% 65 - MNS_MINDAMP
        opt_s.minopf.penalty;   %% 66 - MNS_PENALTY_PARM
        opt_s.minopf.major_it;  %% 67 - MNS_MAJOR_IT
        opt_s.minopf.minor_it;  %% 68 - MNS_MINOR_IT
        opt_s.minopf.max_it;    %% 69 - MNS_MAX_IT
        opt_s.minopf.verbosity; %% 70 - MNS_VERBOSITY
        opt_s.minopf.core;      %% 71 - MNS_CORE
        opt_s.minopf.supbasic_lim;  %% 72 - MNS_SUPBASIC_LIM
        opt_s.minopf.mult_price;%% 73 - MNS_MULT_PRICE
    ];
else
    MINOPF_OPTS = old(61:73);
end

%% FORCE_PC_EQ_P0
if isfield(opt_s, 'sopf') && isfield(opt_s.sopf, 'force_Pc_eq_P0')
    FORCE_PC_EQ_P0 = opt_s.sopf.force_Pc_eq_P0;
else
    FORCE_PC_EQ_P0 = 0;
end

%% PDIPM options
if isfield(opt_s, 'pdipm')
    PDIPM_OPTS = [
        opt_s.pdipm.feastol;    %% 81 - PDIPM_FEASTOL
        opt_s.pdipm.gradtol;    %% 82 - PDIPM_GRADTOL
        opt_s.pdipm.comptol;    %% 83 - PDIPM_COMPTOL
        opt_s.pdipm.costtol;    %% 84 - PDIPM_COSTTOL
        opt_s.pdipm.max_it;     %% 85 - PDIPM_MAX_IT
        opt_s.pdipm.sc.red_it;  %% 86 - SCPDIPM_RED_IT
    ];
else
    PDIPM_OPTS = old(81:86);
end

%% TRALM options
if isfield(opt_s, 'tralm')
    TRALM_OPTS = [
        opt_s.tralm.feastol;    %% 87 - TRALM_FEASTOL
        opt_s.tralm.primaltol;  %% 88 - TRALM_PRIMETOL
        opt_s.tralm.dualtol;    %% 89 - TRALM_DUALTOL
        opt_s.tralm.costtol;    %% 90 - TRALM_COSTTOL
        opt_s.tralm.major_it;   %% 91 - TRALM_MAJOR_IT
        opt_s.tralm.minor_it;   %% 92 - TRALM_MINOR_IT
    ];
else
    TRALM_OPTS = old(87:92);
end

%% SMOOTHING_RATIO
if strcmp(upper(opt_s.opf.ac.solver), 'TRALM') && isfield(opt_s, 'tralm')
    SMOOTHING_RATIO = opt_s.tralm.smooth_ratio;
elseif isfield(opt_s, 'pdipm')
    SMOOTHING_RATIO = opt_s.pdipm.sc.smooth_ratio;
else
    SMOOTHING_RATIO = old(93);
end

%% CPLEX options
if isfield(opt_s, 'cplex')
    CPLEX_OPTS = [
        opt_s.cplex.lpmethod;   %% 95 - CPLEX_LPMETHOD
        opt_s.cplex.qpmethod;   %% 96 - CPLEX_QPMETHOD
        opt_s.cplex.opt;        %% 97 - CPLEX_OPT
    ];
else
    CPLEX_OPTS = old(95:97);
end

%% MOSEK options
if isfield(opt_s, 'mosek')
    MOSEK_OPTS = [
        opt_s.mosek.lp_alg;     %% 111 - MOSEK_LP_ALG
        opt_s.mosek.max_it;     %% 112 - MOSEK_MAX_IT
        opt_s.mosek.gap_tol;    %% 113 - MOSEK_GAP_TOL
        opt_s.mosek.max_time;   %% 114 - MOSEK_MAX_TIME
        opt_s.mosek.num_threads;%% 115 - MOSEK_NUM_THREADS
        opt_s.mosek.opt;        %% 116 - MOSEK_OPT
    ];
else
    MOSEK_OPTS = old(111:116);
end

%% Gurobi options
if isfield(opt_s, 'gurobi')
    GUROBI_OPTS = [
        opt_s.gurobi.method;    %% 121 - GRB_METHOD
        opt_s.gurobi.timelimit; %% 122 - GRB_TIMELIMIT
        opt_s.gurobi.threads;   %% 123 - GRB_THREADS
        opt_s.gurobi.opt;       %% 124 - GRB_OPT
    ];
else
    GUROBI_OPTS = old(121:124);
end

opt_v = [
        %% power flow options
        PF_ALG;                 %% 1  - PF_ALG
        opt_s.pf.tol;           %% 2  - PF_TOL
        opt_s.pf.nr.max_it;     %% 3  - PF_MAX_IT
        opt_s.pf.fd.max_it;     %% 4  - PF_MAX_IT_FD
        opt_s.pf.gs.max_it;     %% 5  - PF_MAX_IT_GS
        opt_s.pf.enforce_q_lims;%% 6  - ENFORCE_Q_LIMS
        0;                      %% 7  - RESERVED7
        0;                      %% 8  - RESERVED8
        0;                      %% 9  - RESERVED9
        PF_DC;                  %% 10 - PF_DC
        
        %% OPF options
        OPF_ALG;                %% 11 - OPF_ALG
        0;                      %% 12 - RESERVED12 (was OPF_ALG_POLY = 100)
        0;                      %% 13 - RESERVED13 (was OPF_ALG_PWL = 200)
        0;                      %% 14 - RESERVED14 (was OPF_POLY2PWL_PTS = 10)
        0;                      %% 15 - OPF_NEQ (removed)
        opt_s.opf.violation;    %% 16 - OPF_VIOLATION
        CONSTR_TOL_X;           %% 17 - CONSTR_TOL_X
        CONSTR_TOL_F;           %% 18 - CONSTR_TOL_F
        CONSTR_MAX_IT;          %% 19 - CONSTR_MAX_IT
        old(20);                %% 20 - LPC_TOL_GRAD (removed)
        old(21);                %% 21 - LPC_TOL_X (removed)
        old(22);                %% 22 - LPC_MAX_IT (removed)
        old(23);                %% 23 - LPC_MAX_RESTART (removed)
        OPF_FLOW_LIM;           %% 24 - OPF_FLOW_LIM
        opt_s.opf.ignore_angle_lim; %% 25 - OPF_IGNORE_ANG_LIM
        OPF_ALG_DC;             %% 26 - OPF_ALG_DC
        0;                      %% 27 - RESERVED27
        0;                      %% 28 - RESERVED28
        0;                      %% 29 - RESERVED29
        0;                      %% 30 - RESERVED30
        
        %% output options
        opt_s.verbose;          %% 31 - VERBOSE
        opt_s.out.all;          %% 32 - OUT_ALL
        opt_s.out.sys_sum;      %% 33 - OUT_SYS_SUM
        opt_s.out.area_sum;     %% 34 - OUT_AREA_SUM
        opt_s.out.bus;          %% 35 - OUT_BUS
        opt_s.out.branch;       %% 36 - OUT_BRANCH
        opt_s.out.gen;          %% 37 - OUT_GEN
        opt_s.out.lim.all;      %% 38 - OUT_ALL_LIM
        opt_s.out.lim.v;        %% 39 - OUT_V_LIM
        opt_s.out.lim.line;     %% 40 - OUT_LINE_LIM
        opt_s.out.lim.pg;       %% 41 - OUT_PG_LIM
        opt_s.out.lim.qg;       %% 42 - OUT_QG_LIM
        0;                      %% 43 - RESERVED43 (was OUT_RAW)
        opt_s.out.force;        %% 44 - OUT_FORCE
        0;                      %% 45 - RESERVED45
        0;                      %% 46 - RESERVED46
        0;                      %% 47 - RESERVED47
        0;                      %% 48 - RESERVED48
        0;                      %% 49 - RESERVED49
        0;                      %% 50 - RESERVED50
        
        %% other options
        old(51);                %% 51 - SPARSE_QP (removed)
        opt_s.opf.return_raw_der;   %% 52 - RETURN_RAW_DER
        0;                      %% 53 - RESERVED53
        0;                      %% 54 - RESERVED54
        FMC_ALG;                %% 55 - FMC_ALG
        0;                      %% 56 - RESERVED56
        0;                      %% 57 - RESERVED57
        KNITRO_OPT;             %% 58 - KNITRO_OPT
        0;                      %% 59 - RESERVED59
        IPOPT_OPT;              %% 60 - IPOPT_OPT
        
        %% MINOPF options
        MINOPF_OPTS;            %% 61-73 - MNS_FEASTOL-MNS_MULT_PRICE
        0;                      %% 74 - RESERVED74
        0;                      %% 75 - RESERVED75
        0;                      %% 76 - RESERVED76
        0;                      %% 77 - RESERVED77
        0;                      %% 78 - RESERVED78
        0;                      %% 79 - RESERVED79
        FORCE_PC_EQ_P0;         %% 80 - FORCE_PC_EQ_P0, for c3sopf
        
        %% MIPS, PDIPM, SC-PDIPM, and TRALM options
        PDIPM_OPTS;             %% 81-86 - PDIPM_FEASTOL-SCPDIPM_RED_IT
        TRALM_OPTS;             %% 87-92 - TRALM_FEASTOL-TRALM_MINOR_IT
        SMOOTHING_RATIO;        %% 93 - SMOOTHING_RATIO
        0;                      %% 94 - RESERVED94
        
        %% CPLEX options
        CPLEX_OPTS;             %% 95-97 - CPLEX_LPMETHOD-CPLEX_OPT
        0;                      %% 98 - RESERVED98
        0;                      %% 99 - RESERVED99
        0;                      %% 100 - RESERVED100
        0;                      %% 101 - RESERVED101
        0;                      %% 102 - RESERVED102
        0;                      %% 103 - RESERVED103
        0;                      %% 104 - RESERVED104
        0;                      %% 105 - RESERVED105
        0;                      %% 106 - RESERVED106
        0;                      %% 107 - RESERVED107
        0;                      %% 108 - RESERVED108
        0;                      %% 109 - RESERVED109
        0;                      %% 110 - RESERVED110

        %% MOSEK options
        MOSEK_OPTS;             %% 111-116 - MOSEK_LP_ALG-MOSEK_OPT
        0;                      %% 117 - RESERVED117
        0;                      %% 118 - RESERVED118
        0;                      %% 119 - RESERVED119
        0;                      %% 120 - RESERVED120

        %% Gurobi options
        GUROBI_OPTS;            %% 121-124 - GRB_METHOD-GRB_OPT
    ];


%%-------------------------------------------------------------------
function optt = mpoption_default()
if DEBUG, fprintf('mpoption_default()\n'); end
persistent opt;             %% cache this for speed
if ~isstruct(opt)
    opt = struct(...
        'v',                    mpoption_version, ...   %% version
        'model',                'AC', ...
        'pf',                   struct(...
            'alg',                  'NR', ...
            'tol',                  1e-8, ...
            'nr',                   struct(...
                'max_it',               10  ), ...
            'fd',                   struct(...
                'max_it',               30  ), ...
            'gs',                   struct(...
                'max_it',               1000  ), ...
            'enforce_q_lims',       0   ), ...
        'cpf',                  struct(...
            'parameterization',     3, ...
            'stop_at',              'NOSE', ...     %% 'NOSE', <lam val>, 'FULL'
            'step',                 0.05, ...
            'adapt_step',           0, ...
            'error_tol',            1e-3, ...
            'step_min',             1e-4, ...
            'step_max',             0.2, ...
            'plot',                 struct(...
                'level',                0, ...
                'bus',                  []  ), ...
            'user_callback',        '', ...
            'user_callback_args',   struct()    ), ...
        'opf',                  struct(...
            'ac',                   struct(...
                'solver',               'DEFAULT'   ), ...
            'dc',                   struct(...
                'solver',               'DEFAULT'   ), ...
            'violation',            5e-6, ...
            'flow_lim',             'S', ...
            'ignore_angle_lim',     0, ...
            'init_from_mpc',        -1, ...
            'return_raw_der',       0   ), ...
        'verbose',              1, ...
        'out',                  struct(...
            'all',                  -1, ...
            'sys_sum',              1, ...
            'area_sum',             0, ...
            'bus',                  1, ...
            'branch',               1, ...
            'gen',                  0, ...
            'lim',                  struct(...
                'all',                  -1, ...
                'v',                    1, ...
                'line',                 1, ...
                'pg',                   1, ...
                'qg',                   1   ), ...
            'force',                0, ...
            'suppress_detail',      -1  ), ...
        'mips',                 struct(...  %% see mpoption_info_mips() for optional fields
            'step_control',         0, ...
            'linsolver',            '', ...
            'feastol',              0, ...
            'gradtol',              1e-6, ...
            'comptol',              1e-6, ...
            'costtol',              1e-6, ...
            'max_it',               150, ...
            'sc',                   struct(...
                'red_it',               20  )), ...
        'exp',                  struct(... %% experimental options
            'sys_wide_zip_loads',   struct(...
                'pw',                   [], ...
                'qw',                   []  )) ...
    );
    opt_pkgs = mpoption_optional_pkgs();
    for k = 1:length(opt_pkgs)
        fname = ['mpoption_info_' opt_pkgs{k}];
        if exist(fname, 'file') == 2
            opt = nested_struct_copy(opt, feval(fname, 'D'));
        end
    end
end
optt = opt;

%%-------------------------------------------------------------------
function optt = mpoption_optional_fields()
if DEBUG, fprintf('mpoption_optional_fields()\n'); end
persistent opt;         %% cache this for speed
if ~isstruct(opt)
    opt_pkgs = mpoption_optional_pkgs();
    opt = struct;
    for k = 1:length(opt_pkgs)
        fname = ['mpoption_info_' opt_pkgs{k}];
        if exist(fname, 'file') == 2
            opt = nested_struct_copy(opt, feval(fname, 'V'));
        end
    end
end
optt = opt;

%% globals
%%-------------------------------------------------------------------
function v = mpoption_version
v = 10;     %% version number of MATPOWER options struct
            %% (must be incremented every time structure is updated)
            %% v1   - first version based on struct (MATPOWER 5.0b1)
            %% v2   - added 'linprog' and 'quadprog' fields
            %% v3   - (forgot to increment v) added 'out.suppress_detail'
            %%        field
            %% v4   - (forgot to increment v) MIPS 1.1, added optional
            %%        fields to 'mips' options: xi, sigma, z0, alpha_min,
            %%        rho_min, rho_max, mu_threshold and max_stepsize
            %% v5   - (forgot to increment v) added 'opf.init_from_mpc'
            %%        field (MATPOWER 5.0)
            %% v6   - added 'clp' field
            %% v7   - added 'intlinprog' field
            %% v8   - MIPS 1.2, added 'linsolver' field to
            %%        'mips' options
            %% v9   - added 'exp' for experimental fields, specifically
            %%        'sys_wide_zip_loads.pw', 'sys_wide_zip_loads.qw'
            %% v10  - added 'most' field

%%-------------------------------------------------------------------
function db_level = DEBUG
db_level = 0;

%%-------------------------------------------------------------------
function pkgs = mpoption_optional_pkgs()
pkgs = {...
    'clp', 'cplex', 'fmincon', 'gurobi', 'glpk', 'intlinprog', 'ipopt', ...
    'knitro', 'linprog', 'minopf', 'most', 'mosek', 'quadprog', 'sdp_pf', ...
    'sopf', 'tspopf', 'yalmip' ...
};

function [bus, gen, branch] = pfsoln(baseMVA, bus0, gen0, branch0, Ybus, Yf, Yt, V, ref, pv, pq, mpopt)
%PFSOLN  Updates bus, gen, branch data structures to match power flow soln.
%   [BUS, GEN, BRANCH] = PFSOLN(BASEMVA, BUS0, GEN0, BRANCH0, ...
%                                   YBUS, YF, YT, V, REF, PV, PQ, MPOPT)

%   MATPOWER
%   Copyright (c) 1996-2016 by Power System Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%% define named indices into bus, gen, branch matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[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;

%% default options
if nargin < 12
    mpopt = mpoption();
end

%% initialize return values
bus     = bus0;
gen     = gen0;
branch  = branch0;

%%----- update bus voltages -----
bus(:, VM) = abs(V);
bus(:, VA) = angle(V) * 180 / pi;

%%----- update Qg for gens at PV/slack buses and Pg for slack bus(es) -----
%% generator info
on = find(gen(:, GEN_STATUS) > 0 & ...  %% which generators are on?
        bus(gen(:, GEN_BUS), BUS_TYPE) ~= PQ);  %% ... and not at PQ buses
off = find(gen(:, GEN_STATUS) <= 0);    %% which generators are off?
gbus = gen(on, GEN_BUS);                %% what buses are they at?

%% compute total injected bus powers
Sbus = V(gbus) .* conj(Ybus(gbus, :) * V);

%% update Qg for generators at PV/slack buses
gen(off, QG) = zeros(length(off), 1);   %% zero out off-line Qg
%% don't touch the ones at PQ buses
[Pd_gbus, Qd_gbus] = total_load(bus(gbus, :), [], 'bus', [], mpopt);
gen(on, QG) = imag(Sbus) * baseMVA + Qd_gbus;   %% inj Q + local Qd
%% ... at this point any buses with more than one generator will have
%% the total Q dispatch for the bus assigned to each generator. This
%% must be split between them. We do it first equally, then in proportion
%% to the reactive range of the generator.

if length(on) > 1
    %% build connection matrix, element i, j is 1 if gen on(i) at bus j is ON
    nb = size(bus, 1);
    ngon = size(on, 1);
    Cg = sparse((1:ngon)', gbus, ones(ngon, 1), ngon, nb);

    %% divide Qg by number of generators at the bus to distribute equally
    ngg = Cg * sum(Cg)';    %% ngon x 1, number of gens at this gen's bus
    gen(on, QG) = gen(on, QG) ./ ngg;

    %% divide proportionally
    Cmin = sparse((1:ngon)', gbus, gen(on, QMIN), ngon, nb);
    Cmax = sparse((1:ngon)', gbus, gen(on, QMAX), ngon, nb);
    Qg_tot = Cg' * gen(on, QG);     %% nb x 1 vector of total Qg at each bus
    Qg_min = sum(Cmin)';            %% nb x 1 vector of min total Qg at each bus
    Qg_max = sum(Cmax)';            %% nb x 1 vector of max total Qg at each bus
    ig = find(Cg * Qg_min == Cg * Qg_max);  %% gens at buses with Qg range = 0
    Qg_save = gen(on(ig), QG);
    gen(on, QG) = gen(on, QMIN) + ...
        (Cg * ((Qg_tot - Qg_min)./(Qg_max - Qg_min + eps))) .* ...
            (gen(on, QMAX) - gen(on, QMIN));    %%    ^ avoid div by 0
    gen(on(ig), QG) = Qg_save;
end                                             %% (terms are mult by 0 anyway)

%% update Pg for slack gen(s)
for k = 1:length(ref)
    refgen = find(gbus == ref(k));              %% which is(are) the reference gen(s)?
    Pd_refk = total_load(bus(ref(k), :), [], 'bus', [], mpopt);
    gen(on(refgen(1)), PG) = real(Sbus(refgen(1))) * baseMVA + Pd_refk; %% inj P + local Pd
    if length(refgen) > 1       %% more than one generator at this ref bus
        %% subtract off what is generated by other gens at this bus
        gen(on(refgen(1)), PG) = gen(on(refgen(1)), PG) ...
                                - sum(gen(on(refgen(2:length(refgen))), PG));
    end
end

%%----- update/compute branch power flows -----
out = find(branch(:, BR_STATUS) == 0);      %% out-of-service branches
br = find(branch(:, BR_STATUS));            %% in-service branches
Sf = V(branch(br, F_BUS)) .* conj(Yf(br, :) * V) * baseMVA; %% complex power at "from" bus
St = V(branch(br, T_BUS)) .* conj(Yt(br, :) * V) * baseMVA; %% complex power injected at "to" bus
branch(br, [PF, QF, PT, QT]) = [real(Sf) imag(Sf) real(St) imag(St)];
branch(out, [PF, QF, PT, QT]) = zeros(length(out), 4);


function [Pd, Qd] = total_load(bus, gen, load_zone, opt, mpopt)
%TOTAL_LOAD Returns vector of total load in each load zone.
%   PD = TOTAL_LOAD(MPC)
%   PD = TOTAL_LOAD(MPC, LOAD_ZONE)
%   PD = TOTAL_LOAD(MPC, LOAD_ZONE, OPT)
%   PD = TOTAL_LOAD(MPC, LOAD_ZONE, OPT, MPOPT)
%   PD = TOTAL_LOAD(BUS)
%   PD = TOTAL_LOAD(BUS, GEN)
%   PD = TOTAL_LOAD(BUS, GEN, LOAD_ZONE)
%   PD = TOTAL_LOAD(BUS, GEN, LOAD_ZONE, OPT)
%   PD = TOTAL_LOAD(BUS, GEN, LOAD_ZONE, OPT, MPOPT)
%   [PD, QD] = TOTAL_LOAD(...) returns both active and reative power
%   demand for each zone.
%
%   MPC - standard MATPOWER case struct
%
%   BUS - standard BUS matrix with nb rows, where the fixed active
%       and reactive loads are specified in columns PD and QD
%
%   GEN - (optional) standard GEN matrix with ng rows, where the
%       dispatchable loads are specified by columns PG, QG, PMIN,
%       QMIN and QMAX (in rows for which ISLOAD(GEN) returns true).
%       If GEN is empty, it assumes there are no dispatchable loads.
%
%   LOAD_ZONE - (optional) 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 LOAD_ZONE(b) = k
%       then the loads at bus b will added to the values of PD(k) and
%       QD(k). If LOAD_ZONE is empty, the default is defined as the areas
%       specified in the BUS matrix, i.e. LOAD_ZONE = BUS(:, BUS_AREA)
%       and load will have dimension = MAX(BUS(:, BUS_AREA)). LOAD_ZONE
%       can also take the following string values:
%           'all'  - use a single zone for the entire system (return scalar)
%           'area' - use LOAD_ZONE = BUS(:, BUS_AREA), same as default
%           'bus'  - use a different zone for each bus (i.e. to compute
%               final values of bus-wise loads, including voltage dependent
%               fixed loads and or dispatchable loads)
%
%   OPT - (optional) option struct, with the following fields:
%           'type'  -  string specifying types of loads to include, default
%                      is 'BOTH' if GEN is provided, otherwise 'FIXED'
%               'FIXED'        : sum only fixed loads
%               'DISPATCHABLE' : sum only dispatchable loads
%               'BOTH'         : sum both fixed and dispatchable loads
%           'nominal' -  1 : use nominal load for dispatchable loads
%                        0 : (default) use actual realized load for
%                             dispatchable loads
%
%       For backward compatibility with MATPOWER 4.x, OPT can also
%       take the form of a string, with the same options as OPT.type above.
%       In this case, again for backward compatibility, it is the "nominal"
%       load that is computed for dispatchable loads, not the actual
%       realized load. Using a string for OPT is deprecated and
%       will be removed in a future version.
%
%   MPOPT - (optional) MATPOWER options struct, which may specify
%       a voltage dependent (ZIP) load model for fixed loads
%
%   Examples:
%       Return the total active load for each area as defined in BUS_AREA.
%
%       Pd = total_load(bus);
%
%       Return total active and reactive load, fixed and dispatchable, for
%       entire system.
%
%       [Pd, Qd] = total_load(bus, gen, 'all');
%
%       Return the total of the nominal dispatchable loads at buses 10-20.
%
%       load_zone = zeros(nb, 1);
%       load_zone(10:20) = 1;
%       opt = struct('type', 'DISPATCHABLE', 'nominal', 1);
%       Pd = total_load(mpc, load_zone, opt)
%
%   See also SCALE_LOAD.

%   MATPOWER
%   Copyright (c) 2004-2016 by Power System Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%% define constants
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
%% purposely being backward compatible with older MATPOWER
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, ...
    PMAX, PMIN, MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN] = idx_gen;

%%-----  process inputs  -----
if nargin < 5
    mpopt = [];
    if nargin < 4
        opt = [];
        if nargin < 3
            load_zone = [];
            if nargin < 2
                gen = [];
            end
        end
    end
end
if isstruct(bus)    %% shift input arguments
    mpopt = opt;
    opt = load_zone;
    load_zone = gen;
    mpc = bus;
    bus = mpc.bus;
    gen = mpc.gen;
end

nb = size(bus, 1);          %% number of buses

%% default options
if ischar(opt)      %% convert old WHICH_TYPE string option to struct
    opt = struct('type', opt, 'nominal', 1);
else
    if ~isfield(opt, 'type')
        if isempty(gen)
            opt.type = 'FIXED';
        else
            opt.type = 'BOTH';
        end
    end
    if ~isfield(opt, 'nominal')
        opt.nominal = 0;
    end
end
switch upper(opt.type(1))
    case {'F', 'D', 'B'}
        %% OK
    otherwise
        error('total_load: OPT.type should be ''FIXED'', ''DISPATCHABLE'' or ''BOTH''');
end
want_Q      = (nargout > 1);
want_fixed  = (opt.type(1) == 'B' || opt.type(1) == 'F');
want_disp   = (opt.type(1) == 'B' || opt.type(1) == 'D');

%% initialize load_zone
if ischar(load_zone)
    if strcmp(lower(load_zone), 'bus')
        load_zone = (1:nb)';            %% each bus is its own zone
    elseif strcmp(lower(load_zone), 'all')
        load_zone = ones(nb, 1);        %% make a single zone of all buses
    elseif strcmp(lower(load_zone), 'area')
        load_zone = bus(:, BUS_AREA);   %% use areas defined in bus data as zones
    end
elseif isempty(load_zone)
    load_zone = bus(:, BUS_AREA);   %% use areas defined in bus data as zones
end
nz = max(load_zone);    %% number of load zones

%% fixed load at each bus, & initialize dispatchable
if want_fixed
    Sd = makeSdzip(1, bus, mpopt);
    Vm = bus(:, VM);
    Sbusd = Sd.p + Sd.i .* Vm + Sd.z .* Vm.^2;
    Pdf = real(Sbusd);      %% real power
    if want_Q
        Qdf = imag(Sbusd);  %% reactive power
    end
else
    Pdf = zeros(nb, 1);     %% real power
    if want_Q
        Qdf = zeros(nb, 1); %% reactive power
    end
end

%% dispatchable load at each bus 
if want_disp            %% need dispatchable
    ng = size(gen, 1);
    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);
    e2i = sparse(max(i2e), 1);
    e2i(i2e) = (1:nb)';

    Cld = sparse(e2i(gen(:, GEN_BUS)), (1:ng)', is_ld, nb, ng);
    if opt.nominal      %% use nominal power
        Pdd = -Cld * gen(:, PMIN);      %% real power
        if want_Q
            Q = zeros(ng, 1);
            Q(ld) = (gen(ld, QMIN) == 0) .* gen(ld, QMAX) + ...
                    (gen(ld, QMAX) == 0) .* gen(ld, QMIN);
            Qdd = -Cld * Q;             %% reactive power
        end
    else                %% use realized actual power dispatch
        Pdd = -Cld * gen(:, PG);        %% real power
        if want_Q
            Qdd = -Cld * gen(:, QG);    %% reactive power
        end
    end
else
    Pdd = zeros(nb, 1);
    if want_Q
        Qdd = zeros(nb, 1);
    end
end

%% compute load sums
if nz == nb && all(load_zone == (1:nb)');   %% individual buses
    Pd = (Pdf + Pdd) .* (bus(:, BUS_TYPE) ~= NONE);
    if want_Q
        Qd = (Qdf + Qdd) .* (bus(:, BUS_TYPE) ~= NONE);
    end
else
    Pd = zeros(nz, 1);
    if want_Q
        Qd = zeros(nz, 1);
    end
    for k = 1:nz
        idx = find( load_zone == k & bus(:, BUS_TYPE) ~= NONE);
        Pd(k) = sum(Pdf(idx)) + sum(Pdd(idx));
        if want_Q
            Qd(k) = sum(Qdf(idx)) + sum(Qdd(idx));
        end
    end
end

在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电磁MATLAB

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值