2 * Copyright (C) 1996-2010 Power System Engineering Research Center
3 * Copyright (C) 2010-2011 Richard Lincoln
5 * JPOWER is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
10 * JPOWER is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with JPOWER. If not, see <http://www.gnu.org/licenses/>.
20 package edu
.cornell
.pserc
.jpower
.opf
;
22 import java
.util
.HashMap
;
25 import cern
.colt
.matrix
.AbstractMatrix
;
26 import cern
.colt
.matrix
.tdcomplex
.DComplexMatrix1D
;
27 import cern
.colt
.matrix
.tdcomplex
.DComplexMatrix2D
;
28 import cern
.colt
.matrix
.tdouble
.DoubleFactory1D
;
29 import cern
.colt
.matrix
.tdouble
.DoubleFactory2D
;
30 import cern
.colt
.matrix
.tdouble
.DoubleMatrix1D
;
31 import cern
.colt
.matrix
.tdouble
.DoubleMatrix2D
;
33 import static edu
.emory
.mathcs
.utils
.Utils
.ifunc
;
34 import static edu
.emory
.mathcs
.utils
.Utils
.dfunc
;
35 import static edu
.emory
.mathcs
.utils
.Utils
.cfunc
;
36 import static edu
.emory
.mathcs
.utils
.Utils
.intm
;
37 import static edu
.emory
.mathcs
.utils
.Utils
.irange
;
38 import static edu
.emory
.mathcs
.utils
.Utils
.nonzero
;
39 import static edu
.emory
.mathcs
.utils
.Utils
.complex
;
41 import static edu
.cornell
.pserc
.jpower
.jpc
.JPC
.PW_LINEAR
;
42 import static edu
.cornell
.pserc
.jpower
.jpc
.JPC
.REF
;
43 import static edu
.cornell
.pserc
.jpower
.pf
.Djp_makeYbus
.makeYbus
;
44 import static edu
.cornell
.pserc
.jips
.Dips_jips
.jips
;
46 import edu
.cornell
.pserc
.jips
.ConstraintEvaluator
;
47 import edu
.cornell
.pserc
.jips
.HessianEvaluator
;
48 import edu
.cornell
.pserc
.jips
.ObjectiveEvaluator
;
49 import edu
.cornell
.pserc
.jpower
.jpc
.Branch
;
50 import edu
.cornell
.pserc
.jpower
.jpc
.Bus
;
51 import edu
.cornell
.pserc
.jpower
.jpc
.Gen
;
52 import edu
.cornell
.pserc
.jpower
.jpc
.Cost
;
53 import edu
.cornell
.pserc
.jpower
.jpc
.JPC
;
54 import edu
.cornell
.pserc
.jpower
.opf
.Djp_opf_model
.Set
;
57 * Solves AC optimal power flow using JIPS.
59 * @author Ray Zimmerman
60 * @author Richard Lincoln
63 public class Djp_jipsopf_solver
{
66 * Solves AC optimal power flow using JIPS.
73 @SuppressWarnings("static-access")
74 public static Object
[] jipsopf_solver(Djp_opf_model om
,
75 Map
<String
, Double
> jpopt
, Map
<String
, AbstractMatrix
> out_opt
) {
77 int nb
, nl
, ny
, nl2
, info
, nlnN
;
78 int[] ipwl
, il
, kl
, ku
;
79 boolean verbose
, success
;
80 double feastol
, gradtol
, comptol
, costtol
, max_it
, max_red
,
81 step_control
, baseMVA
, c
, f
;
82 Map
<String
, Double
> opt
;
89 Map
<String
, Set
>[] idx
;
90 Map
<String
, Set
> vv
, ll
, nn
;
91 Map
<String
, Object
> Output
, raw
;
92 Map
<String
, DoubleMatrix1D
> Lambda
, var
, nln
, lin
;
93 Map
<String
, Map
<String
, DoubleMatrix1D
>> mu
;
96 DoubleMatrix1D l
, u
, x0
, xmin
, xmax
, lb
, ub
, Varefs
, x
,
97 Va
, Vm
, Pg
, Qg
, muSf
, muSt
, nl_mu_l
, nl_mu_u
, pimul
;
101 DComplexMatrix1D V
, Sf
, St
;
102 DComplexMatrix2D Ybus
, Yf
, Yt
;
103 DComplexMatrix2D
[] Y
;
105 ObjectiveEvaluator f_fcn
;
106 HessianEvaluator hess_fcn
;
107 ConstraintEvaluator gh_fcn
, geq_fcn
;
111 /* ----- initialization ----- */
114 verbose
= jpopt
.get("VERBOSE") == 1;
115 feastol
= jpopt
.get("PDIPM_FEASTOL");
116 gradtol
= jpopt
.get("PDIPM_GRADTOL");
117 comptol
= jpopt
.get("PDIPM_COMPTOL");
118 costtol
= jpopt
.get("PDIPM_COSTTOL");
119 max_it
= jpopt
.get("PDIPM_MAX_IT");
120 max_red
= jpopt
.get("SCPDIPM_RED_IT");
121 step_control
= jpopt
.get("OPF_ALG") == 565 ?
1:0;
123 feastol
= jpopt
.get("OPF_VIOLATION"); // = OPF_VIOLATION by default
124 opt
= new HashMap
<String
, Double
>();
125 opt
.put("feastol", feastol
);
126 opt
.put("gradtol", gradtol
);
127 opt
.put("comptol", comptol
);
128 opt
.put("costtol", costtol
);
129 opt
.put("max_it", max_it
);
130 opt
.put("max_red", max_red
);
131 opt
.put("step_control", step_control
);
132 opt
.put("cost_mult", 1e-4);
133 opt
.put("verbose", verbose ?
1.0 : 0.0);
137 baseMVA
= jpc
.baseMVA
;
141 gencost
= jpc
.gencost
;
143 vv
= idx
[0]; ll
= idx
[1]; nn
= idx
[2];
145 /* problem dimensions */
146 nb
= bus
.size(); // number of buses
147 nl
= branch
.size(); // number of branches
148 ny
= om
.getN("var", "y"); // number of piece-wise linear costs
150 /* linear constraints */
151 Alu
= om
.linear_constraints();
152 A
= (DoubleMatrix2D
) Alu
[0];
153 l
= (DoubleMatrix1D
) Alu
[1];
154 u
= (DoubleMatrix1D
) Alu
[2];
157 x0
= xx
[0]; xmin
= xx
[1]; xmax
= xx
[2];
159 /* build admittance matrices */
160 Y
= makeYbus(baseMVA
, bus
, branch
);
161 Ybus
= Y
[0]; Yf
= Y
[1]; Yt
= Y
[2];
163 /* try to select an interior initial point */
164 lb
= xmin
.copy(); ub
= xmax
.copy();
165 lb
.viewSelection( intm( xmin
.copy().assign(dfunc
.equals(Double
.NEGATIVE_INFINITY
)) ).toArray() ).assign(-1e10
); // replace Inf with numerical proxies
166 ub
.viewSelection( intm( xmax
.copy().assign(dfunc
.equals(Double
.POSITIVE_INFINITY
)) ).toArray() ).assign( 1e10
);
167 x0
= lb
.copy().assign(ub
, dfunc
.plus
).assign(dfunc
.div(2));
168 Varefs
= bus
.Va
.viewSelection( bus
.bus_type
.copy().assign(ifunc
.equals(REF
)).toArray() ).assign(dfunc
.mult(Math
.PI
)).assign(dfunc
.div(180));
169 x0
.viewSelection(irange(vv
.get("Va").i0
, vv
.get("Va").iN
)).assign(Varefs
.get(0)); // angles set to first reference angle
171 ipwl
= nonzero( gencost
.model
.copy().assign(ifunc
.equals(PW_LINEAR
)) );
172 c
= gencost
.cost
.viewSelection(ipwl
, null).getMaxLocation()[0]; // largest y-value in CCV data
173 // TODO: compute c using sub2ind
174 x0
.viewPart(vv
.get("y").i0
, vv
.get("y").N
).assign(c
+ 0.1 * Math
.abs(c
));
177 /* find branches with flow limits */
178 il
= nonzero( intm( branch
.rate_a
.copy().assign(dfunc
.equals(0)) ).assign(ifunc
.not
).assign(intm( branch
.rate_a
.assign(dfunc
.less(1e10
)) ), ifunc
.and
) );
179 nl2
= il
.length
; // number of constrained lines
181 /* ----- run opf ----- */
182 f_fcn
= new Djp_opf_costfcn(om
);
183 hess_fcn
= new Djp_opf_hessfcn(om
, Ybus
, Yf
.viewSelection(il
, null), Yt
.viewSelection(il
, null), jpopt
, il
, opt
.get("cost_mult"));
184 gh_fcn
= new Djp_opf_consfcn(om
, Ybus
, Yf
.viewSelection(il
, null), Yt
.viewSelection(il
, null), jpopt
, il
);
185 jips
= jips(f_fcn
, x0
, A
, l
, u
, xmin
, xmax
, gh_fcn
, hess_fcn
, opt
);
186 x
= (DoubleMatrix1D
) jips
[0];
187 f
= (Double
) jips
[1];
188 info
= (Integer
) jips
[2];
189 Output
= (Map
<String
, Object
>) jips
[3];
190 Lambda
= (Map
<String
, DoubleMatrix1D
>) jips
[4];
192 success
= (info
> 0);
194 /* update solution data */
195 Va
= x
.viewPart(vv
.get("Va").i0
, vv
.get("Va").N
).copy();
196 Vm
= x
.viewPart(vv
.get("Vm").i0
, vv
.get("Vm").N
).copy();
197 Pg
= x
.viewPart(vv
.get("Pg").i0
, vv
.get("Pg").N
).copy();
198 Qg
= x
.viewPart(vv
.get("Qg").i0
, vv
.get("Qg").N
).copy();
201 /* ----- calculate return values ----- */
203 /* update voltages & generator outputs */
204 bus
.Va
= Va
.assign(dfunc
.mult(180)).assign(dfunc
.div(Math
.PI
));
206 gen
.Pg
= Pg
.assign(dfunc
.mult(baseMVA
));
207 gen
.Qg
= Qg
.assign(dfunc
.mult(baseMVA
));
208 gen
.Vg
= Vm
.viewSelection(gen
.gen_bus
.toArray());
210 /* compute branch flows */
211 Sf
= Yf
.zMult(V
, null).assign(cfunc
.conj
).assign(V
.viewSelection(branch
.f_bus
.toArray()), cfunc
.mult
); // cplx pwr at "from" bus, p.u.
212 St
= Yt
.zMult(V
, null).assign(cfunc
.conj
).assign(V
.viewSelection(branch
.t_bus
.toArray()), cfunc
.mult
); // cplx pwr at "to" bus, p.u.
213 branch
.Pf
= Sf
.getRealPart().assign(dfunc
.mult(baseMVA
));
214 branch
.Qf
= Sf
.getImaginaryPart().assign(dfunc
.mult(baseMVA
));
215 branch
.Pt
= St
.getRealPart().assign(dfunc
.mult(baseMVA
));
216 branch
.Qt
= St
.getImaginaryPart().assign(dfunc
.mult(baseMVA
));
218 /* line constraint is actually on square of limit, so we must fix multipliers */
219 muSf
= DoubleFactory1D
.dense
.make(nl
);
220 muSt
= DoubleFactory1D
.dense
.make(nl
);
222 muSf
.viewSelection(il
).assign( Lambda
.get("ineqnonlin").viewPart(0, nl2
).copy().assign(branch
.rate_a
.viewSelection(il
), dfunc
.mult
).assign(dfunc
.mult(2)).assign(dfunc
.div(baseMVA
)) );
223 muSt
.viewSelection(il
).assign( Lambda
.get("ineqnonlin").viewPart(nl2
, nl2
).copy().assign(branch
.rate_a
.viewSelection(il
), dfunc
.mult
).assign(dfunc
.mult(2)).assign(dfunc
.div(baseMVA
)) );
226 /* update Lagrange multipliers */
227 bus
.mu_Vmax
= Lambda
.get("upper").viewPart(vv
.get("Vm").i0
, vv
.get("Vm").N
).copy();
228 bus
.mu_Vmin
= Lambda
.get("lower").viewPart(vv
.get("Vm").i0
, vv
.get("Vm").N
).copy();
229 gen
.mu_Pmax
= Lambda
.get("upper").viewPart(vv
.get("Pg").i0
, vv
.get("Pg").N
).copy().assign(dfunc
.div(baseMVA
));
230 gen
.mu_Pmin
= Lambda
.get("lower").viewPart(vv
.get("Pg").i0
, vv
.get("Pg").N
).copy().assign(dfunc
.div(baseMVA
));
231 gen
.mu_Qmax
= Lambda
.get("upper").viewPart(vv
.get("Qg").i0
, vv
.get("Qg").N
).copy().assign(dfunc
.div(baseMVA
));
232 gen
.mu_Qmin
= Lambda
.get("lower").viewPart(vv
.get("Qg").i0
, vv
.get("Qg").N
).copy().assign(dfunc
.div(baseMVA
));
233 bus
.lam_P
= Lambda
.get("eqnonlin").viewPart(nn
.get("Pmis").i0
, nn
.get("Pmis").N
).copy().assign(dfunc
.div(baseMVA
));
234 bus
.lam_Q
= Lambda
.get("eqnonlin").viewPart(nn
.get("Qmis").i0
, nn
.get("Qmis").N
).copy().assign(dfunc
.div(baseMVA
));
235 branch
.mu_Sf
= muSf
.copy().assign(dfunc
.div(baseMVA
));
236 branch
.mu_St
= muSt
.copy().assign(dfunc
.div(baseMVA
));
238 /* package up results */
239 nlnN
= om
.getN("nln");
241 /* extract multipliers for non-linear constraints */
242 kl
= nonzero( Lambda
.get("eqnonlin").copy().assign(dfunc
.less(0)) );
243 ku
= nonzero( Lambda
.get("eqnonlin").copy().assign(dfunc
.greater(0)) );
244 nl_mu_l
= DoubleFactory1D
.dense
.make(nlnN
);
245 nl_mu_u
= DoubleFactory1D
.dense
.make(new DoubleMatrix1D
[] {DoubleFactory1D
.dense
.make(nb
), muSf
, muSt
});
246 nl_mu_l
.viewSelection(kl
).assign( Lambda
.get("eqnonlin").viewSelection(kl
).copy().assign(dfunc
.neg
) );
247 nl_mu_u
.viewSelection(ku
).assign( Lambda
.get("eqnonlin").viewSelection(ku
) );
249 mu
= new HashMap
<String
, Map
<String
,DoubleMatrix1D
>>();
250 var
= new HashMap
<String
, DoubleMatrix1D
>();
251 var
.put("l", Lambda
.get("lower"));
252 var
.put("u", Lambda
.get("upper"));
254 nln
= new HashMap
<String
, DoubleMatrix1D
>();
255 nln
.put("l", nl_mu_l
);
256 nln
.put("u", nl_mu_u
);
258 lin
= new HashMap
<String
, DoubleMatrix1D
>();
259 lin
.put("l", Lambda
.get("mu_l"));
260 lin
.put("u", Lambda
.get("mu_u"));
263 results
= jpc
.copy();
264 results
.bus
= bus
.copy();
265 results
.branch
= branch
.copy();
266 results
.gen
= gen
.copy();
268 results
.x
= x
.copy();
272 /* optional fields */
273 if (out_opt
.containsKey("dg")) {
274 geq_fcn
= new Djp_opf_consfcn(om
, Ybus
, Yf
, Yt
, jpopt
);
276 results
.g
= DoubleFactory1D
.dense
.append(geq
[1], geq
[0]); // include this since we computed it anyway
277 DoubleMatrix2D
[] dgeq
= geq_fcn
.dgh(x
);
278 results
.dg
= DoubleFactory2D
.sparse
.appendRows(dgeq
[1].viewDice(), dgeq
[0].viewDice()); // true Jacobian organization
280 if (out_opt
.containsKey("g") && !out_opt
.containsKey("dg")) {
281 geq_fcn
= new Djp_opf_consfcn(om
, Ybus
, Yf
, Yt
, jpopt
);
283 results
.g
= DoubleFactory1D
.dense
.append(geq
[1], geq
[0]);
285 if (out_opt
.containsKey("df"))
287 if (out_opt
.containsKey("d2f"))
290 pimul
= DoubleFactory1D
.dense
.make(new DoubleMatrix1D
[] {
291 results
.mu
.get("nln").get("l").copy().assign(results
.mu
.get("nln").get("u"), dfunc
.minus
),
292 results
.mu
.get("lin").get("l").copy().assign(results
.mu
.get("lin").get("u"), dfunc
.minus
),
293 DoubleFactory1D
.dense
.make((ny
>0) ?
1:0, -1),
294 results
.mu
.get("var").get("l").copy().assign(results
.mu
.get("var").get("u"), dfunc
.minus
)
297 raw
= new HashMap
<String
, Object
>();
299 raw
.put("pimul", pimul
);
300 raw
.put("info", info
);
301 raw
.put("output", Output
);
303 return new Object
[] {results
, success
, raw
};
306 public static Object
[] jipsopf_solver(Djp_opf_model om
, Map
<String
, Double
> jpopt
) {
307 return jipsopf_solver(om
, jpopt
, new HashMap
<String
, AbstractMatrix
>());