ltbams 0.9.9__py3-none-any.whl → 1.0.2a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. ams/__init__.py +4 -11
  2. ams/_version.py +3 -3
  3. ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
  4. ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
  5. ams/cases/5bus/pjm5bus_uced.json +1062 -0
  6. ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
  7. ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
  8. ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
  9. ams/cases/ieee123/ieee123.xlsx +0 -0
  10. ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
  11. ams/cases/ieee14/ieee14.json +1166 -0
  12. ams/cases/ieee14/ieee14.raw +92 -0
  13. ams/cases/ieee14/ieee14_conn.xlsx +0 -0
  14. ams/cases/ieee14/ieee14_uced.xlsx +0 -0
  15. ams/cases/ieee39/ieee39.xlsx +0 -0
  16. ams/cases/ieee39/ieee39_uced.xlsx +0 -0
  17. ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
  18. ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
  19. ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
  20. ams/cases/matpower/benchmark.json +1594 -0
  21. ams/cases/matpower/case118.m +787 -0
  22. ams/cases/matpower/case14.m +129 -0
  23. ams/cases/matpower/case300.m +1315 -0
  24. ams/cases/matpower/case39.m +205 -0
  25. ams/cases/matpower/case5.m +62 -0
  26. ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
  27. ams/cases/npcc/npcc.m +644 -0
  28. ams/cases/npcc/npcc_uced.xlsx +0 -0
  29. ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
  30. ams/cases/wecc/wecc.m +714 -0
  31. ams/cases/wecc/wecc_uced.xlsx +0 -0
  32. ams/cli.py +6 -0
  33. ams/core/__init__.py +2 -0
  34. ams/core/documenter.py +652 -0
  35. ams/core/matprocessor.py +782 -0
  36. ams/core/model.py +330 -0
  37. ams/core/param.py +322 -0
  38. ams/core/service.py +918 -0
  39. ams/core/symprocessor.py +224 -0
  40. ams/core/var.py +59 -0
  41. ams/extension/__init__.py +5 -0
  42. ams/extension/eva.py +401 -0
  43. ams/interface.py +1085 -0
  44. ams/io/__init__.py +133 -0
  45. ams/io/json.py +82 -0
  46. ams/io/matpower.py +406 -0
  47. ams/io/psse.py +6 -0
  48. ams/io/pypower.py +103 -0
  49. ams/io/xlsx.py +80 -0
  50. ams/main.py +81 -4
  51. ams/models/__init__.py +24 -0
  52. ams/models/area.py +40 -0
  53. ams/models/bus.py +52 -0
  54. ams/models/cost.py +169 -0
  55. ams/models/distributed/__init__.py +3 -0
  56. ams/models/distributed/esd1.py +71 -0
  57. ams/models/distributed/ev.py +60 -0
  58. ams/models/distributed/pvd1.py +67 -0
  59. ams/models/group.py +231 -0
  60. ams/models/info.py +26 -0
  61. ams/models/line.py +238 -0
  62. ams/models/renewable/__init__.py +5 -0
  63. ams/models/renewable/regc.py +119 -0
  64. ams/models/reserve.py +94 -0
  65. ams/models/shunt.py +14 -0
  66. ams/models/static/__init__.py +2 -0
  67. ams/models/static/gen.py +165 -0
  68. ams/models/static/pq.py +61 -0
  69. ams/models/timeslot.py +69 -0
  70. ams/models/zone.py +49 -0
  71. ams/opt/__init__.py +12 -0
  72. ams/opt/constraint.py +175 -0
  73. ams/opt/exprcalc.py +127 -0
  74. ams/opt/expression.py +188 -0
  75. ams/opt/objective.py +174 -0
  76. ams/opt/omodel.py +432 -0
  77. ams/opt/optzbase.py +192 -0
  78. ams/opt/param.py +156 -0
  79. ams/opt/var.py +233 -0
  80. ams/pypower/__init__.py +8 -0
  81. ams/pypower/_compat.py +9 -0
  82. ams/pypower/core/__init__.py +8 -0
  83. ams/pypower/core/pips.py +894 -0
  84. ams/pypower/core/ppoption.py +244 -0
  85. ams/pypower/core/ppver.py +18 -0
  86. ams/pypower/core/solver.py +2451 -0
  87. ams/pypower/eps.py +6 -0
  88. ams/pypower/idx.py +174 -0
  89. ams/pypower/io.py +604 -0
  90. ams/pypower/make/__init__.py +11 -0
  91. ams/pypower/make/matrices.py +665 -0
  92. ams/pypower/make/pdv.py +506 -0
  93. ams/pypower/routines/__init__.py +7 -0
  94. ams/pypower/routines/cpf.py +513 -0
  95. ams/pypower/routines/cpf_callbacks.py +114 -0
  96. ams/pypower/routines/opf.py +1803 -0
  97. ams/pypower/routines/opffcns.py +1946 -0
  98. ams/pypower/routines/pflow.py +852 -0
  99. ams/pypower/toggle.py +1098 -0
  100. ams/pypower/utils.py +293 -0
  101. ams/report.py +212 -50
  102. ams/routines/__init__.py +23 -0
  103. ams/routines/acopf.py +117 -0
  104. ams/routines/cpf.py +65 -0
  105. ams/routines/dcopf.py +241 -0
  106. ams/routines/dcpf.py +209 -0
  107. ams/routines/dcpf0.py +196 -0
  108. ams/routines/dopf.py +150 -0
  109. ams/routines/ed.py +312 -0
  110. ams/routines/pflow.py +255 -0
  111. ams/routines/pflow0.py +113 -0
  112. ams/routines/routine.py +1033 -0
  113. ams/routines/rted.py +519 -0
  114. ams/routines/type.py +160 -0
  115. ams/routines/uc.py +376 -0
  116. ams/shared.py +63 -9
  117. ams/system.py +61 -22
  118. ams/utils/__init__.py +3 -0
  119. ams/utils/misc.py +77 -0
  120. ams/utils/paths.py +257 -0
  121. docs/Makefile +21 -0
  122. docs/make.bat +35 -0
  123. docs/source/_templates/autosummary/base.rst +5 -0
  124. docs/source/_templates/autosummary/class.rst +35 -0
  125. docs/source/_templates/autosummary/module.rst +65 -0
  126. docs/source/_templates/autosummary/module_toctree.rst +66 -0
  127. docs/source/api.rst +102 -0
  128. docs/source/conf.py +203 -0
  129. docs/source/examples/index.rst +34 -0
  130. docs/source/genmodelref.py +61 -0
  131. docs/source/genroutineref.py +47 -0
  132. docs/source/getting_started/copyright.rst +20 -0
  133. docs/source/getting_started/formats/index.rst +20 -0
  134. docs/source/getting_started/formats/matpower.rst +183 -0
  135. docs/source/getting_started/formats/psse.rst +46 -0
  136. docs/source/getting_started/formats/pypower.rst +223 -0
  137. docs/source/getting_started/formats/xlsx.png +0 -0
  138. docs/source/getting_started/formats/xlsx.rst +23 -0
  139. docs/source/getting_started/index.rst +76 -0
  140. docs/source/getting_started/install.rst +234 -0
  141. docs/source/getting_started/overview.rst +26 -0
  142. docs/source/getting_started/testcase.rst +45 -0
  143. docs/source/getting_started/verification.rst +13 -0
  144. docs/source/images/curent.ico +0 -0
  145. docs/source/images/dcopf_time.png +0 -0
  146. docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  147. docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  148. docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  149. docs/source/images/sponsors/doe.png +0 -0
  150. docs/source/index.rst +108 -0
  151. docs/source/modeling/example.rst +159 -0
  152. docs/source/modeling/index.rst +17 -0
  153. docs/source/modeling/model.rst +210 -0
  154. docs/source/modeling/routine.rst +122 -0
  155. docs/source/modeling/system.rst +51 -0
  156. docs/source/release-notes.rst +398 -0
  157. ltbams-1.0.2a1.dist-info/METADATA +210 -0
  158. ltbams-1.0.2a1.dist-info/RECORD +188 -0
  159. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
  160. ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
  161. tests/__init__.py +0 -0
  162. tests/test_1st_system.py +33 -0
  163. tests/test_addressing.py +40 -0
  164. tests/test_andes_mats.py +61 -0
  165. tests/test_case.py +266 -0
  166. tests/test_cli.py +34 -0
  167. tests/test_export_csv.py +89 -0
  168. tests/test_group.py +83 -0
  169. tests/test_interface.py +216 -0
  170. tests/test_io.py +32 -0
  171. tests/test_jumper.py +27 -0
  172. tests/test_known_good.py +267 -0
  173. tests/test_matp.py +437 -0
  174. tests/test_model.py +54 -0
  175. tests/test_omodel.py +119 -0
  176. tests/test_paths.py +22 -0
  177. tests/test_report.py +251 -0
  178. tests/test_repr.py +21 -0
  179. tests/test_routine.py +178 -0
  180. tests/test_rtn_dcopf.py +101 -0
  181. tests/test_rtn_dcpf.py +77 -0
  182. tests/test_rtn_ed.py +279 -0
  183. tests/test_rtn_pflow.py +219 -0
  184. tests/test_rtn_rted.py +273 -0
  185. tests/test_rtn_uc.py +248 -0
  186. tests/test_service.py +73 -0
  187. ltbams-0.9.9.dist-info/LICENSE +0 -692
  188. ltbams-0.9.9.dist-info/METADATA +0 -859
  189. ltbams-0.9.9.dist-info/RECORD +0 -14
  190. ltbams-0.9.9.dist-info/top_level.txt +0 -1
  191. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,894 @@
1
+ """
2
+ Python Interior Point Solver (PIPS).
3
+ """
4
+ import logging
5
+
6
+ import numpy as np
7
+ from numpy import flatnonzero as find
8
+
9
+ import scipy.sparse as sp
10
+ from scipy.sparse import csr_matrix as c_sparse
11
+
12
+ from andes.shared import deg2rad, rad2deg
13
+
14
+ from ams.shared import inf
15
+
16
+ from ams.pypower.eps import EPS
17
+ from ams.pypower.idx import IDX
18
+ from ams.pypower.utils import sub2ind
19
+ from ams.pypower.make import makeYbus
20
+ from ams.pypower.routines.opffcns import (opf_costfcn, opf_consfcn,
21
+ opf_hessfcn,)
22
+
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ def pips(f_fcn, x0=None, A=None, l=None, u=None, xmin=None, xmax=None,
28
+ gh_fcn=None, hess_fcn=None, opt=None):
29
+ """
30
+ Primal-dual interior point method for NLP (nonlinear programming).
31
+
32
+ Minimize a function F(X) beginning from a starting point x0, subject to
33
+ optional linear and nonlinear constraints and variable bounds:
34
+
35
+ min f(x)
36
+ x
37
+
38
+ subject to:
39
+
40
+ g(x) = 0 (nonlinear equalities)
41
+ h(x) <= 0 (nonlinear inequalities)
42
+ l <= A*x <= u (linear constraints)
43
+ xmin <= x <= xmax (variable bounds)
44
+
45
+ Note: The calling syntax is almost identical to that of FMINCON from
46
+ MathWorks' Optimization Toolbox. The main difference is that the linear
47
+ constraints are specified with A, l, u instead of A, B,
48
+ Aeq, Beq. The functions for evaluating the objective function,
49
+ constraints and Hessian are identical.
50
+
51
+ Example from http://en.wikipedia.org/wiki/Nonlinear_programming:
52
+ >>> from numpy import array, r_, float64, dot
53
+ >>> from scipy.sparse import csr_matrix
54
+ >>> def f2(x):
55
+ ... f = -x[0] * x[1] - x[1] * x[2]
56
+ ... df = -r_[x[1], x[0] + x[2], x[1]]
57
+ ... # actually not used since 'hess_fcn' is provided
58
+ ... d2f = -array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], float64)
59
+ ... return f, df, d2f
60
+ >>> def gh2(x):
61
+ ... h = dot(array([[1, -1, 1],
62
+ ... [1, 1, 1]]), x**2) + array([-2.0, -10.0])
63
+ ... dh = 2 * csr_matrix(array([[ x[0], x[0]],
64
+ ... [-x[1], x[1]],
65
+ ... [ x[2], x[2]]]))
66
+ ... g = array([])
67
+ ... dg = None
68
+ ... return h, g, dh, dg
69
+ >>> def hess2(x, lam, cost_mult=1):
70
+ ... mu = lam["ineqnonlin"]
71
+ ... a = r_[dot(2 * array([1, 1]), mu), -1, 0]
72
+ ... b = r_[-1, dot(2 * array([-1, 1]), mu),-1]
73
+ ... c = r_[0, -1, dot(2 * array([1, 1]), mu)]
74
+ ... Lxx = csr_matrix(array([a, b, c]))
75
+ ... return Lxx
76
+ >>> x0 = array([1, 1, 0], float64)
77
+ >>> solution = pips(f2, x0, gh_fcn=gh2, hess_fcn=hess2)
78
+ >>> round(solution["f"], 11) == -7.07106725919
79
+ True
80
+ >>> solution["output"]["iterations"]
81
+ 8
82
+
83
+ All parameters are optional except f_fcn and x0.
84
+
85
+ Parameters:
86
+ ----------
87
+ f_fcn : callable
88
+ Function that evaluates the objective function, its gradients
89
+ and Hessian for a given value of x. If there are
90
+ nonlinear constraints, the Hessian information is provided
91
+ by the 'hess_fcn' argument and is not required here.
92
+ x0 : array, optional
93
+ Starting value of optimization vector x.
94
+ A : csr_matrix, optional
95
+ Optional linear constraints.
96
+ l : array, optional
97
+ Optional linear constraints. Default values are -Inf.
98
+ u : array, optional
99
+ Optional linear constraints. Default values are Inf.
100
+ xmin : array, optional
101
+ Optional lower bounds on the x variables, defaults are
102
+ -Inf.
103
+ xmax : array, optional
104
+ Optional upper bounds on the x variables, defaults are
105
+ Inf.
106
+ gh_fcn : callable, optional
107
+ Function that evaluates the optional nonlinear constraints
108
+ and their gradients for a given value of x.
109
+ hess_fcn : callable, optional
110
+ Handle to function that computes the Hessian of the
111
+ Lagrangian for given values of x, lambda and mu,
112
+ where lambda and mu are the multipliers on the
113
+ equality and inequality constraints, g and h,
114
+ respectively.
115
+ opt : dict, optional
116
+ Optional options dictionary with the following keys, all of
117
+ which are also optional (default values shown in parentheses)
118
+ - 'verbose' (False) - Controls level of progress output
119
+ displayed
120
+ - 'feastol' (1e-6) - termination tolerance for feasibility
121
+ condition
122
+ - 'gradtol' (1e-6) - termination tolerance for gradient
123
+ condition
124
+ - 'comptol' (1e-6) - termination tolerance for
125
+ complementarity condition
126
+ - 'costtol' (1e-6) - termination tolerance for cost
127
+ condition
128
+ - 'max_it' (150) - maximum number of iterations
129
+ - 'step_control' (False) - set to True to enable step-size
130
+ control
131
+ - 'max_red' (20) - maximum number of step-size reductions if
132
+ step-control is on
133
+ - 'cost_mult' (1.0) - cost multiplier used to scale the
134
+ objective function for improved conditioning. Note: This
135
+ value is also passed as the 3rd argument to the Hessian
136
+ evaluation function so that it can appropriately scale the
137
+ objective function term in the Hessian of the Lagrangian.
138
+
139
+ Returns:
140
+ --------
141
+ dict
142
+ The solution dictionary has the following keys:
143
+ - 'x' - solution vector
144
+ - 'f' - final objective function value
145
+ - 'converged' - exit status
146
+ - True = first order optimality conditions satisfied
147
+ - False = maximum number of iterations reached
148
+ - None = numerically failed
149
+ - 'output' - output dictionary with keys:
150
+ - 'iterations' - number of iterations performed
151
+ - 'hist' - list of arrays with trajectories of the
152
+ following: feascond, gradcond, compcond, costcond, gamma,
153
+ stepsize, obj, alphap, alphad
154
+ - 'message' - exit message
155
+ - 'lmbda' - dictionary containing the Langrange and Kuhn-Tucker
156
+ multipliers on the constraints, with keys:
157
+ - 'eqnonlin' - nonlinear equality constraints
158
+ - 'ineqnonlin' - nonlinear inequality constraints
159
+ - 'mu_l' - lower (left-hand) limit on linear constraints
160
+ - 'mu_u' - upper (right-hand) limit on linear constraints
161
+ - 'lower' - lower bound on optimization variables
162
+ - 'upper' - upper bound on optimization variables
163
+
164
+ Notes
165
+ -----
166
+ 1. Ported by Richard Lincoln from the MATLAB Interior Point Solver (MIPS)
167
+ (v1.9) by Ray Zimmerman. MIPS is distributed as part of the MATPOWER
168
+ project, developed at PSERC, Cornell.
169
+
170
+ Reference:
171
+
172
+ [1] "On the Computation and Application of Multi-period Security-Constrained
173
+ Optimal Power Flow for Real-time Electricity Market Operations",
174
+ Cornell University, May 2007.
175
+
176
+ [2] H. Wang, C. E. Murillo-Sanchez, R. D. Zimmerman, R. J. Thomas, "On Computational
177
+ Issues of Market-Based Optimal Power Flow", IEEE Transactions on Power Systems,
178
+ Vol. 22, No. 3, Aug. 2007, pp. 1185-1193.
179
+
180
+ Author
181
+ ------
182
+ Ray Zimmerman (PSERC Cornell)
183
+ """
184
+ if isinstance(f_fcn, dict): # problem dict
185
+ p = f_fcn
186
+ f_fcn = p['f_fcn']
187
+ x0 = p['x0']
188
+ if 'opt' in p:
189
+ opt = p['opt']
190
+ if 'hess_fcn' in p:
191
+ hess_fcn = p['hess_fcn']
192
+ if 'gh_fcn' in p:
193
+ gh_fcn = p['gh_fcn']
194
+ if 'xmax' in p:
195
+ xmax = p['xmax']
196
+ if 'xmin' in p:
197
+ xmin = p['xmin']
198
+ if 'u' in p:
199
+ u = p['u']
200
+ if 'l' in p:
201
+ l = p['l']
202
+ if 'A' in p:
203
+ A = p['A']
204
+
205
+ nx = x0.shape[0] # number of variables
206
+ nA = A.shape[0] if A is not None else 0 # number of original linear constr
207
+
208
+ # default argument values
209
+ if l is None or len(l) == 0:
210
+ l = -inf * np.ones(nA)
211
+ if u is None or len(u) == 0:
212
+ u = inf * np.ones(nA)
213
+ if xmin is None or len(xmin) == 0:
214
+ xmin = -inf * np.ones(x0.shape[0])
215
+ if xmax is None or len(xmax) == 0:
216
+ xmax = inf * np.ones(x0.shape[0])
217
+ if gh_fcn is None:
218
+ nonlinear = False
219
+ gn = np.array([])
220
+ hn = np.array([])
221
+ else:
222
+ nonlinear = True
223
+
224
+ if opt is None:
225
+ opt = {}
226
+ # options
227
+ if "feastol" not in opt:
228
+ opt["feastol"] = 1e-06
229
+ if "gradtol" not in opt:
230
+ opt["gradtol"] = 1e-06
231
+ if "comptol" not in opt:
232
+ opt["comptol"] = 1e-06
233
+ if "costtol" not in opt:
234
+ opt["costtol"] = 1e-06
235
+ if "max_it" not in opt:
236
+ opt["max_it"] = 150
237
+ if "max_red" not in opt:
238
+ opt["max_red"] = 20
239
+ if "step_control" not in opt:
240
+ opt["step_control"] = False
241
+ if "cost_mult" not in opt:
242
+ opt["cost_mult"] = 1
243
+ if "verbose" not in opt:
244
+ opt["verbose"] = 0
245
+
246
+ # initialize history
247
+ hist = []
248
+
249
+ # constants
250
+ xi = 0.99995
251
+ sigma = 0.1
252
+ z0 = 1
253
+ alpha_min = 1e-8
254
+ rho_min = 0.95
255
+ rho_max = 1.05
256
+ mu_threshold = 1e-5
257
+
258
+ # initialize
259
+ i = 0 # iteration counter
260
+ converged = False # flag
261
+ eflag = False # exit flag
262
+
263
+ # add var limits to linear constraints
264
+ eyex = sp.eye(nx, nx, format="csr")
265
+ AA = eyex if A is None else sp.vstack([eyex, A], "csr")
266
+ ll = np.r_[xmin, l]
267
+ uu = np.r_[xmax, u]
268
+
269
+ # split up linear constraints
270
+ ieq = find(np.abs(uu - ll) <= EPS)
271
+ igt = find((uu >= 1e10) & (ll > -1e10))
272
+ ilt = find((ll <= -1e10) & (uu < 1e10))
273
+ ibx = find((np.abs(uu - ll) > EPS) & (uu < 1e10) & (ll > -1e10))
274
+ # zero-sized sparse matrices unsupported
275
+ Ae = AA[ieq, :] if len(ieq) else None
276
+ if len(ilt) or len(igt) or len(ibx):
277
+ idxs = [(1, ilt), (-1, igt), (1, ibx), (-1, ibx)]
278
+ Ai = sp.vstack([sig * AA[idx, :] for sig, idx in idxs if len(idx)], 'csr')
279
+ else:
280
+ Ai = None
281
+ be = uu[ieq]
282
+ bi = np.r_[uu[ilt], -ll[igt], uu[ibx], -ll[ibx]]
283
+
284
+ # evaluate cost f(x0) and constraints g(x0), h(x0)
285
+ x = x0
286
+ f, df = f_fcn(x) # cost
287
+ f = f * opt["cost_mult"]
288
+ df = df * opt["cost_mult"]
289
+ if nonlinear:
290
+ hn, gn, dhn, dgn = gh_fcn(x) # nonlinear constraints
291
+ h = hn if Ai is None else np.r_[hn, Ai * x - bi] # inequality constraints
292
+ g = gn if Ae is None else np.r_[gn, Ae * x - be] # equality constraints
293
+
294
+ if (dhn is None) and (Ai is None):
295
+ dh = None
296
+ elif dhn is None:
297
+ dh = Ai.T
298
+ elif Ai is None:
299
+ dh = dhn
300
+ else:
301
+ dh = sp.hstack([dhn, Ai.T])
302
+
303
+ if (dgn is None) and (Ae is None):
304
+ dg = None
305
+ elif dgn is None:
306
+ dg = Ae.T
307
+ elif Ae is None:
308
+ dg = dgn
309
+ else:
310
+ dg = sp.hstack([dgn, Ae.T])
311
+ else:
312
+ h = -bi if Ai is None else Ai * x - bi # inequality constraints
313
+ g = -be if Ae is None else Ae * x - be # equality constraints
314
+ dh = None if Ai is None else Ai.T # 1st derivative of inequalities
315
+ dg = None if Ae is None else Ae.T # 1st derivative of equalities
316
+
317
+ # some dimensions
318
+ neq = g.shape[0] # number of equality constraints
319
+ niq = h.shape[0] # number of inequality constraints
320
+ neqnln = gn.shape[0] # number of nonlinear equality constraints
321
+ niqnln = hn.shape[0] # number of nonlinear inequality constraints
322
+ nlt = len(ilt) # number of upper bounded linear inequalities
323
+ ngt = len(igt) # number of lower bounded linear inequalities
324
+ nbx = len(ibx) # number of doubly bounded linear inequalities
325
+
326
+ # initialize gamma, lam, mu, z, e
327
+ gamma = 1 # barrier coefficient
328
+ lam = np.zeros(neq)
329
+ z = z0 * np.ones(niq)
330
+ mu = z0 * np.ones(niq)
331
+ k = find(h < -z0)
332
+ z[k] = -h[k]
333
+ k = find((gamma / z) > z0)
334
+ mu[k] = gamma / z[k]
335
+ e = np.ones(niq)
336
+
337
+ # check tolerance
338
+ f0 = f
339
+ if opt["step_control"]:
340
+ L = f + np.dot(lam, g) + np.dot(mu, h + z) - gamma * sum(np.log(z))
341
+
342
+ Lx = df.copy()
343
+ Lx = Lx + dg * lam if dg is not None else Lx
344
+ Lx = Lx + dh * mu if dh is not None else Lx
345
+
346
+ maxh = np.zeros(1) if len(h) == 0 else max(h)
347
+
348
+ gnorm = np.linalg.norm(g, inf) if len(g) else 0.0
349
+ lam_norm = np.linalg.norm(lam, inf) if len(lam) else 0.0
350
+ mu_norm = np.linalg.norm(mu, inf) if len(mu) else 0.0
351
+ znorm = np.linalg.norm(z, inf) if len(z) else 0.0
352
+ feascond = \
353
+ max([gnorm, maxh]) / (1 + max([np.linalg.norm(x, inf), znorm]))
354
+ gradcond = \
355
+ np.linalg.norm(Lx, inf) / (1 + max([lam_norm, mu_norm]))
356
+ compcond = np.dot(z, mu) / (1 + np.linalg.norm(x, inf))
357
+ costcond = np.abs(f - f0) / (1 + np.abs(f0))
358
+
359
+ # save history
360
+ hist.append({'feascond': feascond, 'gradcond': gradcond,
361
+ 'compcond': compcond, 'costcond': costcond, 'gamma': gamma,
362
+ 'stepsize': 0, 'obj': f / opt["cost_mult"], 'alphap': 0, 'alphad': 0})
363
+
364
+ s = '-sc' if opt["step_control"] else ''
365
+ headers = ' n objective step size'
366
+ headers += ' feascond gradcond'
367
+ headers += ' compcond costcond'
368
+ head_line = "=== ======== ====== "
369
+ head_line += " ======= ======="
370
+ head_line += " ======= ======="
371
+ logger.debug(headers)
372
+ logger.debug(head_line)
373
+ logger.debug("%3d %12.8g %12g %12g %12g %12g %12g" %
374
+ (i, (f / opt["cost_mult"]), 0, feascond, gradcond,
375
+ compcond, costcond))
376
+
377
+ if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
378
+ compcond < opt["comptol"] and costcond < opt["costtol"]:
379
+ converged = True
380
+
381
+ # do Newton iterations
382
+ while (not converged) and (i < opt["max_it"]):
383
+ # update iteration counter
384
+ i += 1
385
+
386
+ # compute update step
387
+ lmbda = {"eqnonlin": lam[range(neqnln)],
388
+ "ineqnonlin": mu[range(niqnln)]}
389
+ if nonlinear:
390
+ if hess_fcn is None:
391
+ logger.error("pips: Hessian evaluation via finite differences "
392
+ "not yet implemented.\nPlease provide "
393
+ "your own hessian evaluation function.")
394
+ Lxx = hess_fcn(x, lmbda, opt["cost_mult"])
395
+ else:
396
+ _, _, d2f = f_fcn(x, True) # cost
397
+ Lxx = d2f * opt["cost_mult"]
398
+ rz = range(len(z))
399
+ zinvdiag = c_sparse((1.0 / z, (rz, rz))) if len(z) else None
400
+ rmu = range(len(mu))
401
+ mudiag = c_sparse((mu, (rmu, rmu))) if len(mu) else None
402
+ dh_zinv = None if dh is None else dh * zinvdiag
403
+ M = Lxx if dh is None else Lxx + dh_zinv * mudiag * dh.T
404
+ N = Lx if dh is None else Lx + dh_zinv * (mudiag * h + gamma * e)
405
+
406
+ Ab = c_sparse(M) if dg is None else sp.vstack([
407
+ sp.hstack([M, dg]),
408
+ sp.hstack([dg.T, c_sparse((neq, neq))])
409
+ ])
410
+ bb = np.r_[-N, -g]
411
+
412
+ dxdlam = sp.linalg.spsolve(Ab.tocsr(), bb)
413
+
414
+ if np.any(np.isnan(dxdlam)):
415
+ print('\nNumerically Failed\n')
416
+ eflag = -1
417
+ break
418
+
419
+ dx = dxdlam[:nx]
420
+ dlam = dxdlam[nx:nx + neq]
421
+ dz = -h - z if dh is None else -h - z - dh.T * dx
422
+ dmu = -mu if dh is None else -mu + zinvdiag * (gamma * e - mudiag * dz)
423
+
424
+ # optional step-size control
425
+ sc = False
426
+ if opt["step_control"]:
427
+ x1 = x + dx
428
+
429
+ # evaluate cost, constraints, derivatives at x1
430
+ f1, df1 = f_fcn(x1) # cost
431
+ f1 = f1 * opt["cost_mult"]
432
+ df1 = df1 * opt["cost_mult"]
433
+ if nonlinear:
434
+ hn1, gn1, dhn1, dgn1 = gh_fcn(x1) # nonlinear constraints
435
+
436
+ h1 = hn1 if Ai is None else np.r_[hn1, Ai * x1 - bi] # ieq constraints
437
+ g1 = gn1 if Ae is None else np.r_[gn1, Ae * x1 - be] # eq constraints
438
+
439
+ # 1st der of ieq
440
+ if (dhn1 is None) and (Ai is None):
441
+ dh1 = None
442
+ elif dhn1 is None:
443
+ dh1 = Ai.T
444
+ elif Ai is None:
445
+ dh1 = dhn1
446
+ else:
447
+ dh1 = sp.hstack([dhn1, Ai.T])
448
+
449
+ # 1st der of eqs
450
+ if (dgn1 is None) and (Ae is None):
451
+ dg1 = None
452
+ elif dgn is None:
453
+ dg1 = Ae.T
454
+ elif Ae is None:
455
+ dg1 = dgn1
456
+ else:
457
+ dg1 = sp.hstack([dgn1, Ae.T])
458
+ else:
459
+ h1 = -bi if Ai is None else Ai * x1 - bi # inequality constraints
460
+ g1 = -be if Ae is None else Ae * x1 - be # equality constraints
461
+
462
+ dh1 = dh # 1st derivative of inequalities
463
+ dg1 = dg # 1st derivative of equalities
464
+
465
+ # check tolerance
466
+ Lx1 = df1
467
+ Lx1 = Lx1 + dg1 * lam if dg1 is not None else Lx1
468
+ Lx1 = Lx1 + dh1 * mu if dh1 is not None else Lx1
469
+
470
+ maxh1 = np.zeros(1) if len(h1) == 0 else max(h1)
471
+
472
+ g1norm = np.linalg.norm(g1, inf) if len(g1) else 0.0
473
+ lam1_norm = np.linalg.norm(lam, inf) if len(lam) else 0.0
474
+ mu1_norm = np.linalg.norm(mu, inf) if len(mu) else 0.0
475
+ z1norm = np.linalg.norm(z, inf) if len(z) else 0.0
476
+
477
+ feascond1 = max([g1norm, maxh1]) / \
478
+ (1 + max([np.linalg.norm(x1, inf), z1norm]))
479
+ gradcond1 = np.linalg.norm(Lx1, inf) / (1 + max([lam1_norm, mu1_norm]))
480
+
481
+ if (feascond1 > feascond) and (gradcond1 > gradcond):
482
+ sc = True
483
+ if sc:
484
+ alpha = 1.0
485
+ for j in range(opt["max_red"]):
486
+ dx1 = alpha * dx
487
+ x1 = x + dx1
488
+ f1, _ = f_fcn(x1) # cost
489
+ f1 = f1 * opt["cost_mult"]
490
+ if nonlinear:
491
+ hn1, gn1, _, _ = gh_fcn(x1) # nonlinear constraints
492
+ h1 = hn1 if Ai is None else np.r_[hn1, Ai * x1 - bi] # inequality constraints
493
+ g1 = gn1 if Ae is None else np.r_[gn1, Ae * x1 - be] # equality constraints
494
+ else:
495
+ h1 = -bi if Ai is None else Ai * x1 - bi # inequality constraints
496
+ g1 = -be if Ae is None else Ae * x1 - be # equality constraints
497
+
498
+ L1 = f1 + np.dot(lam, g1) + np.dot(mu, h1 + z) - gamma * sum(np.log(z))
499
+
500
+ logger.info(" %3d %10.5f" % (-j, np.linalg.norm(dx1)))
501
+
502
+ rho = (L1 - L) / (np.dot(Lx, dx1) + 0.5 * np.dot(dx1, Lxx * dx1))
503
+
504
+ if (rho > rho_min) and (rho < rho_max):
505
+ break
506
+ else:
507
+ alpha = alpha / 2.0
508
+ dx = alpha * dx
509
+ dz = alpha * dz
510
+ dlam = alpha * dlam
511
+ dmu = alpha * dmu
512
+
513
+ # do the update
514
+ k = find(dz < 0.0)
515
+ alphap = min([xi * min(z[k] / -dz[k]), 1]) if len(k) else 1.0
516
+ k = find(dmu < 0.0)
517
+ alphad = min([xi * min(mu[k] / -dmu[k]), 1]) if len(k) else 1.0
518
+ x = x + alphap * dx
519
+ z = z + alphap * dz
520
+ lam = lam + alphad * dlam
521
+ mu = mu + alphad * dmu
522
+ if niq > 0:
523
+ gamma = sigma * np.dot(z, mu) / niq
524
+
525
+ # evaluate cost, constraints, derivatives
526
+ f, df = f_fcn(x) # cost
527
+ f = f * opt["cost_mult"]
528
+ df = df * opt["cost_mult"]
529
+ if nonlinear:
530
+ hn, gn, dhn, dgn = gh_fcn(x) # nln constraints
531
+ h = hn if Ai is None else np.r_[hn, Ai * x - bi] # ieq constr
532
+ g = gn if Ae is None else np.r_[gn, Ae * x - be] # eq constr
533
+
534
+ if (dhn is None) and (Ai is None):
535
+ dh = None
536
+ elif dhn is None:
537
+ dh = Ai.T
538
+ elif Ai is None:
539
+ dh = dhn
540
+ else:
541
+ dh = sp.hstack([dhn, Ai.T])
542
+
543
+ if (dgn is None) and (Ae is None):
544
+ dg = None
545
+ elif dgn is None:
546
+ dg = Ae.T
547
+ elif Ae is None:
548
+ dg = dgn
549
+ else:
550
+ dg = sp.hstack([dgn, Ae.T])
551
+ else:
552
+ h = -bi if Ai is None else Ai * x - bi # inequality constraints
553
+ g = -be if Ae is None else Ae * x - be # equality constraints
554
+ # 1st derivatives are constant, still dh = Ai.T, dg = Ae.T
555
+
556
+ Lx = df
557
+ Lx = Lx + dg * lam if dg is not None else Lx
558
+ Lx = Lx + dh * mu if dh is not None else Lx
559
+
560
+ if len(h) == 0:
561
+ maxh = np.zeros(1)
562
+ else:
563
+ maxh = max(h)
564
+
565
+ gnorm = np.linalg.norm(g, inf) if len(g) else 0.0
566
+ lam_norm = np.linalg.norm(lam, inf) if len(lam) else 0.0
567
+ mu_norm = np.linalg.norm(mu, inf) if len(mu) else 0.0
568
+ znorm = np.linalg.norm(z, inf) if len(z) else 0.0
569
+ feascond = \
570
+ max([gnorm, maxh]) / (1 + max([np.linalg.norm(x, inf), znorm]))
571
+ gradcond = \
572
+ np.linalg.norm(Lx, inf) / (1 + max([lam_norm, mu_norm]))
573
+ compcond = np.dot(z, mu) / (1 + np.linalg.norm(x, inf))
574
+ costcond = float(np.abs(f - f0) / (1 + np.abs(f0)))
575
+
576
+ hist.append({'feascond': feascond, 'gradcond': gradcond,
577
+ 'compcond': compcond, 'costcond': costcond, 'gamma': gamma,
578
+ 'stepsize': np.linalg.norm(dx), 'obj': f / opt["cost_mult"],
579
+ 'alphap': alphap, 'alphad': alphad})
580
+
581
+ logger.debug("%3d %12.8g %10.5g %12g %12g %12g %12g" %
582
+ (i, (f / opt["cost_mult"]), np.linalg.norm(dx), feascond, gradcond,
583
+ compcond, costcond))
584
+
585
+ if feascond < opt["feastol"] and gradcond < opt["gradtol"] and \
586
+ compcond < opt["comptol"] and costcond < opt["costtol"]:
587
+ converged = True
588
+ else:
589
+ if np.any(np.isnan(x)) or (alphap < alpha_min) or \
590
+ (alphad < alpha_min) or (gamma < EPS) or (gamma > 1.0 / EPS):
591
+ eflag = -1
592
+ break
593
+ f0 = f
594
+
595
+ if opt["step_control"]:
596
+ L = f + np.dot(lam, g) + np.dot(mu, (h + z)) - gamma * sum(np.log(z))
597
+
598
+ if not converged:
599
+ logger.debug("Did not converge in %d iterations." % i)
600
+
601
+ # package results
602
+ if eflag != -1:
603
+ eflag = converged
604
+
605
+ if eflag == 0:
606
+ message = 'Did not converge'
607
+ elif eflag == 1:
608
+ message = 'Converged'
609
+ elif eflag == -1:
610
+ message = 'Numerically failed'
611
+ else:
612
+ raise
613
+
614
+ output = {"iterations": i, "hist": hist, "message": message}
615
+
616
+ # zero out multipliers on non-binding constraints
617
+ mu[find((h < -opt["feastol"]) & (mu < mu_threshold))] = 0.0
618
+
619
+ # un-scale cost and prices
620
+ f = f / opt["cost_mult"]
621
+ lam = lam / opt["cost_mult"]
622
+ mu = mu / opt["cost_mult"]
623
+
624
+ # re-package multipliers into struct
625
+ lam_lin = lam[neqnln:neq] # lambda for linear constraints
626
+ mu_lin = mu[niqnln:niq] # mu for linear constraints
627
+ kl = find(lam_lin < 0.0) # lower bound binding
628
+ ku = find(lam_lin > 0.0) # upper bound binding
629
+
630
+ mu_l = np.zeros(nx + nA)
631
+ mu_l[ieq[kl]] = -lam_lin[kl]
632
+ mu_l[igt] = mu_lin[nlt:nlt + ngt]
633
+ mu_l[ibx] = mu_lin[nlt + ngt + nbx:nlt + ngt + nbx + nbx]
634
+
635
+ mu_u = np.zeros(nx + nA)
636
+ mu_u[ieq[ku]] = lam_lin[ku]
637
+ mu_u[ilt] = mu_lin[:nlt]
638
+ mu_u[ibx] = mu_lin[nlt + ngt:nlt + ngt + nbx]
639
+
640
+ lmbda = {'mu_l': mu_l[nx:], 'mu_u': mu_u[nx:],
641
+ 'lower': mu_l[:nx], 'upper': mu_u[:nx]}
642
+
643
+ if niqnln > 0:
644
+ lmbda['ineqnonlin'] = mu[:niqnln]
645
+ if neqnln > 0:
646
+ lmbda['eqnonlin'] = lam[:neqnln]
647
+
648
+ # lmbda = {"eqnonlin": lam[:neqnln], 'ineqnonlin': mu[:niqnln],
649
+ # "mu_l": mu_l[nx:], "mu_u": mu_u[nx:],
650
+ # "lower": mu_l[:nx], "upper": mu_u[:nx]}
651
+
652
+ solution = {"x": x, "f": f, "eflag": converged,
653
+ "output": output, "lmbda": lmbda}
654
+
655
+ return solution
656
+
657
+
658
+ def pipsver(*args):
659
+ """
660
+ Return PIPS version information for the current installation.
661
+
662
+ Author: Ray Zimmerman (PSERC Cornell)
663
+
664
+ Returns
665
+ -------
666
+ dict
667
+ A dictionary containing PIPS version information with the following keys:
668
+ - 'Name': Name of the software (PIPS)
669
+ - 'Version': Version number (1.0)
670
+ - 'Release': Release information (empty string)
671
+ - 'Date': Date of release (07-Feb-2011)
672
+
673
+ Author
674
+ ------
675
+ Ray Zimmerman (PSERC Cornell)
676
+ """
677
+ ver = {'Name': 'PIPS',
678
+ 'Version': '1.0',
679
+ 'Release': '',
680
+ 'Date': '07-Feb-2011'}
681
+
682
+ return ver
683
+
684
+
685
+ def pipsopf_solver(om, ppopt, out_opt=None):
686
+ """
687
+ Solves AC optimal power flow using PIPS.
688
+
689
+ Inputs are an OPF model object, a PYPOWER options vector, and
690
+ a dict containing keys (can be empty) for each of the desired
691
+ optional output fields.
692
+
693
+ Outputs are a `results` dict, a `success` flag, and a `raw` output dict.
694
+
695
+ Parameters
696
+ ----------
697
+ om : object
698
+ OPF model object.
699
+ ppopt : dict
700
+ PYPOWER options vector.
701
+ out_opt : dict, optional
702
+ Dictionary containing keys for optional output fields (default is None).
703
+
704
+ Returns
705
+ -------
706
+ dict
707
+ A `results` dictionary containing various fields, including optimization
708
+ variables, objective function value, and shadow prices on constraints.
709
+ bool
710
+ A `success` flag indicating whether the solver converged successfully.
711
+ dict
712
+ A `raw` output dictionary in the form returned by MINOS, containing
713
+ information about optimization variables, constraint multipliers, solver
714
+ termination code, and solver-specific output information.
715
+
716
+ Notes
717
+ -----
718
+ The `results` dictionary contains fields such as 'order', 'x', 'f', 'mu',
719
+ where 'mu' includes shadow prices on variables and constraints.
720
+
721
+ The `success` flag is `True` if the solver converged successfully, and `False`
722
+ otherwise.
723
+
724
+ The `raw` output dictionary includes information specific to the solver.
725
+
726
+ Author
727
+ ------
728
+ Ray Zimmerman (PSERC Cornell)
729
+
730
+ Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales)
731
+ """
732
+ # ----- initialization -----
733
+ # optional output
734
+ if out_opt is None:
735
+ out_opt = {}
736
+
737
+ # options
738
+ verbose = ppopt['VERBOSE']
739
+ feastol = ppopt['PDIPM_FEASTOL']
740
+ gradtol = ppopt['PDIPM_GRADTOL']
741
+ comptol = ppopt['PDIPM_COMPTOL']
742
+ costtol = ppopt['PDIPM_COSTTOL']
743
+ max_it = ppopt['PDIPM_MAX_IT']
744
+ max_red = ppopt['SCPDIPM_RED_IT']
745
+ step_control = (ppopt['OPF_ALG'] == 565) # OPF_ALG == 565, PIPS-sc
746
+ if feastol == 0:
747
+ feastol = ppopt['OPF_VIOLATION']
748
+ opt = {'feastol': feastol,
749
+ 'gradtol': gradtol,
750
+ 'comptol': comptol,
751
+ 'costtol': costtol,
752
+ 'max_it': max_it,
753
+ 'max_red': max_red,
754
+ 'step_control': step_control,
755
+ 'cost_mult': 1e-4,
756
+ 'verbose': verbose}
757
+
758
+ # unpack data
759
+ ppc = om.get_ppc()
760
+ baseMVA, bus, gen, branch, gencost = \
761
+ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"], ppc["gencost"]
762
+ vv, _, nn, _ = om.get_idx()
763
+
764
+ # problem dimensions
765
+ nb = bus.shape[0] # number of buses
766
+ nl = branch.shape[0] # number of branches
767
+ ny = om.getN('var', 'y') # number of piece-wise linear costs
768
+
769
+ # linear constraints
770
+ A, l, u = om.linear_constraints()
771
+
772
+ # bounds on optimization vars
773
+ _, xmin, xmax = om.getv()
774
+
775
+ # build admittance matrices
776
+ Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
777
+
778
+ # try to select an interior initial point
779
+ ll, uu = xmin.copy(), xmax.copy()
780
+ ll[xmin == -inf] = -1e10 # replace Inf with numerical proxies
781
+ uu[xmax == inf] = 1e10
782
+ x0 = (ll + uu) / 2
783
+ Varefs = bus[bus[:, IDX.bus.BUS_TYPE] == IDX.bus.REF, IDX.bus.VA] * deg2rad
784
+ # angles set to first reference angle
785
+ x0[vv["i1"]["Va"]:vv["iN"]["Va"]] = Varefs[0]
786
+ if ny > 0:
787
+ ipwl = find(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR)
788
+ # PQ = np.r_[gen[:, PMAX], gen[:, QMAX]]
789
+ # c = totcost(gencost[ipwl, :], PQ[ipwl])
790
+ # largest y-value in CCV data
791
+ c = gencost.flatten('F')[sub2ind(gencost.shape, ipwl, IDX.cost.NCOST+2*gencost[ipwl, IDX.cost.NCOST])]
792
+ x0[vv["i1"]["y"]:vv["iN"]["y"]] = max(c) + 0.1 * abs(max(c))
793
+ # x0[vv["i1"]["y"]:vv["iN"]["y"]] = c + 0.1 * abs(c)
794
+
795
+ # find branches with flow limits
796
+ il = find((branch[:, IDX.branch.RATE_A] != 0) & (branch[:, IDX.branch.RATE_A] < 1e10))
797
+ nl2 = len(il) # number of constrained lines
798
+
799
+ # ----- run opf -----
800
+ def f_fcn(x, return_hessian=False): return opf_costfcn(x, om, return_hessian)
801
+ def gh_fcn(x): return opf_consfcn(x, om, Ybus, Yf[il, :], Yt[il, :], ppopt, il)
802
+
803
+ def hess_fcn(
804
+ x, lmbda, cost_mult): return opf_hessfcn(
805
+ x, lmbda, om, Ybus, Yf[il, :],
806
+ Yt[il, :],
807
+ ppopt, il, cost_mult)
808
+
809
+ solution = pips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt)
810
+ x, f, info, lmbda, output = solution["x"], solution["f"], \
811
+ solution["eflag"], solution["lmbda"], solution["output"]
812
+
813
+ success = (info > 0)
814
+
815
+ # update solution data
816
+ Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
817
+ Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
818
+ Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]]
819
+ Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]]
820
+
821
+ V = Vm * np.exp(1j * Va)
822
+
823
+ # ----- calculate return values -----
824
+ # update voltages & generator outputs
825
+ bus[:, IDX.bus.VA] = Va * rad2deg
826
+
827
+ bus[:, IDX.bus.VM] = Vm
828
+ gen[:, IDX.gen.PG] = Pg * baseMVA
829
+ gen[:, IDX.gen.QG] = Qg * baseMVA
830
+ gen[:, IDX.gen.VG] = Vm[gen[:, IDX.gen.GEN_BUS].astype(int)]
831
+
832
+ # compute branch flows
833
+ Sf = V[branch[:, IDX.branch.F_BUS].astype(int)] * np.conj(Yf * V) # cplx pwr at "from" bus, p["u"].
834
+ St = V[branch[:, IDX.branch.T_BUS].astype(int)] * np.conj(Yt * V) # cplx pwr at "to" bus, p["u"].
835
+ branch[:, IDX.branch.PF] = Sf.real * baseMVA
836
+ branch[:, IDX.branch.QF] = Sf.imag * baseMVA
837
+ branch[:, IDX.branch.PT] = St.real * baseMVA
838
+ branch[:, IDX.branch.QT] = St.imag * baseMVA
839
+
840
+ # line constraint is actually on square of limit
841
+ # so we must fix multipliers
842
+ muSf = np.zeros(nl)
843
+ muSt = np.zeros(nl)
844
+ if len(il) > 0:
845
+ muSf[il] = \
846
+ 2 * lmbda["ineqnonlin"][:nl2] * branch[il, IDX.branch.RATE_A] / baseMVA
847
+ muSt[il] = \
848
+ 2 * lmbda["ineqnonlin"][nl2:nl2+nl2] * branch[il, IDX.branch.RATE_A] / baseMVA
849
+
850
+ # update Lagrange multipliers
851
+ bus[:, IDX.bus.MU_VMAX] = lmbda["upper"][vv["i1"]["Vm"]:vv["iN"]["Vm"]]
852
+ bus[:, IDX.bus.MU_VMIN] = lmbda["lower"][vv["i1"]["Vm"]:vv["iN"]["Vm"]]
853
+ gen[:, IDX.gen.MU_PMAX] = lmbda["upper"][vv["i1"]["Pg"]:vv["iN"]["Pg"]] / baseMVA
854
+ gen[:, IDX.gen.MU_PMIN] = lmbda["lower"][vv["i1"]["Pg"]:vv["iN"]["Pg"]] / baseMVA
855
+ gen[:, IDX.gen.MU_QMAX] = lmbda["upper"][vv["i1"]["Qg"]:vv["iN"]["Qg"]] / baseMVA
856
+ gen[:, IDX.gen.MU_QMIN] = lmbda["lower"][vv["i1"]["Qg"]:vv["iN"]["Qg"]] / baseMVA
857
+
858
+ bus[:, IDX.bus.LAM_P] = \
859
+ lmbda["eqnonlin"][nn["i1"]["Pmis"]:nn["iN"]["Pmis"]] / baseMVA
860
+ bus[:, IDX.bus.LAM_Q] = \
861
+ lmbda["eqnonlin"][nn["i1"]["Qmis"]:nn["iN"]["Qmis"]] / baseMVA
862
+ branch[:, IDX.branch.MU_SF] = muSf / baseMVA
863
+ branch[:, IDX.branch.MU_ST] = muSt / baseMVA
864
+
865
+ # package up results
866
+ nlnN = om.getN('nln')
867
+
868
+ # extract multipliers for nonlinear constraints
869
+ kl = find(lmbda["eqnonlin"] < 0)
870
+ ku = find(lmbda["eqnonlin"] > 0)
871
+ nl_mu_l = np.zeros(nlnN)
872
+ nl_mu_u = np.r_[np.zeros(2*nb), muSf, muSt]
873
+ nl_mu_l[kl] = -lmbda["eqnonlin"][kl]
874
+ nl_mu_u[ku] = lmbda["eqnonlin"][ku]
875
+
876
+ mu = {
877
+ 'var': {'l': lmbda["lower"], 'u': lmbda["upper"]},
878
+ 'nln': {'l': nl_mu_l, 'u': nl_mu_u},
879
+ 'lin': {'l': lmbda["mu_l"], 'u': lmbda["mu_u"]}}
880
+
881
+ results = ppc
882
+ results["bus"], results["branch"], results["gen"], \
883
+ results["om"], results["x"], results["mu"], results["f"] = \
884
+ bus, branch, gen, om, x, mu, f
885
+
886
+ pimul = np.r_[
887
+ results["mu"]["nln"]["l"] - results["mu"]["nln"]["u"],
888
+ results["mu"]["lin"]["l"] - results["mu"]["lin"]["u"],
889
+ -np.ones(int(ny > 0)),
890
+ results["mu"]["var"]["l"] - results["mu"]["var"]["u"],
891
+ ]
892
+ raw = {'xr': x, 'pimul': pimul, 'info': info, 'output': output}
893
+
894
+ return results, success, raw