ltbams 0.9.9__py3-none-any.whl → 1.0.0__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 (728) hide show
  1. ams/__init__.py +4 -11
  2. ams/_version.py +4 -4
  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 +83 -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/pflow1.py +156 -0
  113. ams/routines/routine.py +1033 -0
  114. ams/routines/rted.py +519 -0
  115. ams/routines/type.py +160 -0
  116. ams/routines/uc.py +376 -0
  117. ams/shared.py +34 -9
  118. ams/system.py +61 -22
  119. ams/utils/__init__.py +3 -0
  120. ams/utils/misc.py +77 -0
  121. ams/utils/paths.py +257 -0
  122. docs/Makefile +21 -0
  123. docs/build/doctrees/nbsphinx/_examples_demo_demo_AGC_20_1.png +0 -0
  124. docs/build/doctrees/nbsphinx/_examples_demo_demo_AGC_37_1.png +0 -0
  125. docs/build/doctrees/nbsphinx/_examples_demo_demo_AGC_39_1.png +0 -0
  126. docs/build/html/_images/_examples_demo_demo_AGC_20_1.png +0 -0
  127. docs/build/html/_images/_examples_demo_demo_AGC_37_1.png +0 -0
  128. docs/build/html/_images/_examples_demo_demo_AGC_39_1.png +0 -0
  129. docs/build/html/_images/xlsx.png +0 -0
  130. docs/build/html/_static/file.png +0 -0
  131. docs/build/html/_static/minus.png +0 -0
  132. docs/build/html/_static/plus.png +0 -0
  133. docs/make.bat +35 -0
  134. docs/source/_generated/_generated/ams.core.model.Model.alter.rst +6 -0
  135. docs/source/_generated/_generated/ams.core.model.Model.class_name.rst +6 -0
  136. docs/source/_generated/_generated/ams.core.model.Model.doc.rst +6 -0
  137. docs/source/_generated/_generated/ams.core.model.Model.get.rst +6 -0
  138. docs/source/_generated/_generated/ams.core.model.Model.get_idx.rst +6 -0
  139. docs/source/_generated/_generated/ams.core.model.Model.idx2uid.rst +6 -0
  140. docs/source/_generated/_generated/ams.core.model.Model.list2array.rst +6 -0
  141. docs/source/_generated/_generated/ams.core.model.Model.set.rst +6 -0
  142. docs/source/_generated/_generated/ams.core.model.Model.set_backref.rst +6 -0
  143. docs/source/_generated/_generated/ams.core.param.RParam.class_name.rst +6 -0
  144. docs/source/_generated/_generated/ams.core.param.RParam.dtype.rst +6 -0
  145. docs/source/_generated/_generated/ams.core.param.RParam.evaluate.rst +6 -0
  146. docs/source/_generated/_generated/ams.core.param.RParam.get_idx.rst +6 -0
  147. docs/source/_generated/_generated/ams.core.param.RParam.n.rst +6 -0
  148. docs/source/_generated/_generated/ams.core.param.RParam.parse.rst +6 -0
  149. docs/source/_generated/_generated/ams.core.param.RParam.shape.rst +6 -0
  150. docs/source/_generated/_generated/ams.core.param.RParam.size.rst +6 -0
  151. docs/source/_generated/_generated/ams.core.param.RParam.update.rst +6 -0
  152. docs/source/_generated/_generated/ams.core.param.RParam.v.rst +6 -0
  153. docs/source/_generated/_generated/ams.core.service.LoadScale.assign_memory.rst +6 -0
  154. docs/source/_generated/_generated/ams.core.service.LoadScale.class_name.rst +6 -0
  155. docs/source/_generated/_generated/ams.core.service.LoadScale.evaluate.rst +6 -0
  156. docs/source/_generated/_generated/ams.core.service.LoadScale.get_names.rst +6 -0
  157. docs/source/_generated/_generated/ams.core.service.LoadScale.n.rst +6 -0
  158. docs/source/_generated/_generated/ams.core.service.LoadScale.parse.rst +6 -0
  159. docs/source/_generated/_generated/ams.core.service.LoadScale.shape.rst +6 -0
  160. docs/source/_generated/_generated/ams.core.service.LoadScale.size.rst +6 -0
  161. docs/source/_generated/_generated/ams.core.service.LoadScale.update.rst +6 -0
  162. docs/source/_generated/_generated/ams.core.service.LoadScale.v.rst +6 -0
  163. docs/source/_generated/_generated/ams.core.service.MinDur.assign_memory.rst +6 -0
  164. docs/source/_generated/_generated/ams.core.service.MinDur.class_name.rst +6 -0
  165. docs/source/_generated/_generated/ams.core.service.MinDur.evaluate.rst +6 -0
  166. docs/source/_generated/_generated/ams.core.service.MinDur.get_names.rst +6 -0
  167. docs/source/_generated/_generated/ams.core.service.MinDur.n.rst +6 -0
  168. docs/source/_generated/_generated/ams.core.service.MinDur.parse.rst +6 -0
  169. docs/source/_generated/_generated/ams.core.service.MinDur.shape.rst +6 -0
  170. docs/source/_generated/_generated/ams.core.service.MinDur.size.rst +6 -0
  171. docs/source/_generated/_generated/ams.core.service.MinDur.update.rst +6 -0
  172. docs/source/_generated/_generated/ams.core.service.MinDur.v.rst +6 -0
  173. docs/source/_generated/_generated/ams.core.service.MinDur.v0.rst +6 -0
  174. docs/source/_generated/_generated/ams.core.service.MinDur.v1.rst +6 -0
  175. docs/source/_generated/_generated/ams.core.service.NumExpandDim.assign_memory.rst +6 -0
  176. docs/source/_generated/_generated/ams.core.service.NumExpandDim.class_name.rst +6 -0
  177. docs/source/_generated/_generated/ams.core.service.NumExpandDim.evaluate.rst +6 -0
  178. docs/source/_generated/_generated/ams.core.service.NumExpandDim.get_names.rst +6 -0
  179. docs/source/_generated/_generated/ams.core.service.NumExpandDim.n.rst +6 -0
  180. docs/source/_generated/_generated/ams.core.service.NumExpandDim.parse.rst +6 -0
  181. docs/source/_generated/_generated/ams.core.service.NumExpandDim.shape.rst +6 -0
  182. docs/source/_generated/_generated/ams.core.service.NumExpandDim.size.rst +6 -0
  183. docs/source/_generated/_generated/ams.core.service.NumExpandDim.update.rst +6 -0
  184. docs/source/_generated/_generated/ams.core.service.NumExpandDim.v.rst +6 -0
  185. docs/source/_generated/_generated/ams.core.service.NumExpandDim.v0.rst +6 -0
  186. docs/source/_generated/_generated/ams.core.service.NumExpandDim.v1.rst +6 -0
  187. docs/source/_generated/_generated/ams.core.service.NumHstack.assign_memory.rst +6 -0
  188. docs/source/_generated/_generated/ams.core.service.NumHstack.class_name.rst +6 -0
  189. docs/source/_generated/_generated/ams.core.service.NumHstack.evaluate.rst +6 -0
  190. docs/source/_generated/_generated/ams.core.service.NumHstack.get_names.rst +6 -0
  191. docs/source/_generated/_generated/ams.core.service.NumHstack.n.rst +6 -0
  192. docs/source/_generated/_generated/ams.core.service.NumHstack.parse.rst +6 -0
  193. docs/source/_generated/_generated/ams.core.service.NumHstack.shape.rst +6 -0
  194. docs/source/_generated/_generated/ams.core.service.NumHstack.size.rst +6 -0
  195. docs/source/_generated/_generated/ams.core.service.NumHstack.update.rst +6 -0
  196. docs/source/_generated/_generated/ams.core.service.NumHstack.v.rst +6 -0
  197. docs/source/_generated/_generated/ams.core.service.NumHstack.v0.rst +6 -0
  198. docs/source/_generated/_generated/ams.core.service.NumHstack.v1.rst +6 -0
  199. docs/source/_generated/_generated/ams.core.service.NumOp.assign_memory.rst +6 -0
  200. docs/source/_generated/_generated/ams.core.service.NumOp.class_name.rst +6 -0
  201. docs/source/_generated/_generated/ams.core.service.NumOp.evaluate.rst +6 -0
  202. docs/source/_generated/_generated/ams.core.service.NumOp.get_names.rst +6 -0
  203. docs/source/_generated/_generated/ams.core.service.NumOp.n.rst +6 -0
  204. docs/source/_generated/_generated/ams.core.service.NumOp.parse.rst +6 -0
  205. docs/source/_generated/_generated/ams.core.service.NumOp.shape.rst +6 -0
  206. docs/source/_generated/_generated/ams.core.service.NumOp.size.rst +6 -0
  207. docs/source/_generated/_generated/ams.core.service.NumOp.update.rst +6 -0
  208. docs/source/_generated/_generated/ams.core.service.NumOp.v.rst +6 -0
  209. docs/source/_generated/_generated/ams.core.service.NumOp.v0.rst +6 -0
  210. docs/source/_generated/_generated/ams.core.service.NumOp.v1.rst +6 -0
  211. docs/source/_generated/_generated/ams.core.service.NumOpDual.assign_memory.rst +6 -0
  212. docs/source/_generated/_generated/ams.core.service.NumOpDual.class_name.rst +6 -0
  213. docs/source/_generated/_generated/ams.core.service.NumOpDual.evaluate.rst +6 -0
  214. docs/source/_generated/_generated/ams.core.service.NumOpDual.get_names.rst +6 -0
  215. docs/source/_generated/_generated/ams.core.service.NumOpDual.n.rst +6 -0
  216. docs/source/_generated/_generated/ams.core.service.NumOpDual.parse.rst +6 -0
  217. docs/source/_generated/_generated/ams.core.service.NumOpDual.shape.rst +6 -0
  218. docs/source/_generated/_generated/ams.core.service.NumOpDual.size.rst +6 -0
  219. docs/source/_generated/_generated/ams.core.service.NumOpDual.update.rst +6 -0
  220. docs/source/_generated/_generated/ams.core.service.NumOpDual.v.rst +6 -0
  221. docs/source/_generated/_generated/ams.core.service.NumOpDual.v0.rst +6 -0
  222. docs/source/_generated/_generated/ams.core.service.NumOpDual.v1.rst +6 -0
  223. docs/source/_generated/_generated/ams.core.service.RBaseService.assign_memory.rst +6 -0
  224. docs/source/_generated/_generated/ams.core.service.RBaseService.class_name.rst +6 -0
  225. docs/source/_generated/_generated/ams.core.service.RBaseService.evaluate.rst +6 -0
  226. docs/source/_generated/_generated/ams.core.service.RBaseService.get_names.rst +6 -0
  227. docs/source/_generated/_generated/ams.core.service.RBaseService.n.rst +6 -0
  228. docs/source/_generated/_generated/ams.core.service.RBaseService.parse.rst +6 -0
  229. docs/source/_generated/_generated/ams.core.service.RBaseService.shape.rst +6 -0
  230. docs/source/_generated/_generated/ams.core.service.RBaseService.size.rst +6 -0
  231. docs/source/_generated/_generated/ams.core.service.RBaseService.update.rst +6 -0
  232. docs/source/_generated/_generated/ams.core.service.RBaseService.v.rst +6 -0
  233. docs/source/_generated/_generated/ams.core.service.ROperationService.assign_memory.rst +6 -0
  234. docs/source/_generated/_generated/ams.core.service.ROperationService.class_name.rst +6 -0
  235. docs/source/_generated/_generated/ams.core.service.ROperationService.evaluate.rst +6 -0
  236. docs/source/_generated/_generated/ams.core.service.ROperationService.get_names.rst +6 -0
  237. docs/source/_generated/_generated/ams.core.service.ROperationService.n.rst +6 -0
  238. docs/source/_generated/_generated/ams.core.service.ROperationService.parse.rst +6 -0
  239. docs/source/_generated/_generated/ams.core.service.ROperationService.shape.rst +6 -0
  240. docs/source/_generated/_generated/ams.core.service.ROperationService.size.rst +6 -0
  241. docs/source/_generated/_generated/ams.core.service.ROperationService.update.rst +6 -0
  242. docs/source/_generated/_generated/ams.core.service.ROperationService.v.rst +6 -0
  243. docs/source/_generated/_generated/ams.core.service.RampSub.assign_memory.rst +6 -0
  244. docs/source/_generated/_generated/ams.core.service.RampSub.class_name.rst +6 -0
  245. docs/source/_generated/_generated/ams.core.service.RampSub.evaluate.rst +6 -0
  246. docs/source/_generated/_generated/ams.core.service.RampSub.get_names.rst +6 -0
  247. docs/source/_generated/_generated/ams.core.service.RampSub.n.rst +6 -0
  248. docs/source/_generated/_generated/ams.core.service.RampSub.parse.rst +6 -0
  249. docs/source/_generated/_generated/ams.core.service.RampSub.shape.rst +6 -0
  250. docs/source/_generated/_generated/ams.core.service.RampSub.size.rst +6 -0
  251. docs/source/_generated/_generated/ams.core.service.RampSub.update.rst +6 -0
  252. docs/source/_generated/_generated/ams.core.service.RampSub.v.rst +6 -0
  253. docs/source/_generated/_generated/ams.core.service.RampSub.v0.rst +6 -0
  254. docs/source/_generated/_generated/ams.core.service.RampSub.v1.rst +6 -0
  255. docs/source/_generated/_generated/ams.core.service.ValueService.assign_memory.rst +6 -0
  256. docs/source/_generated/_generated/ams.core.service.ValueService.class_name.rst +6 -0
  257. docs/source/_generated/_generated/ams.core.service.ValueService.evaluate.rst +6 -0
  258. docs/source/_generated/_generated/ams.core.service.ValueService.get_names.rst +6 -0
  259. docs/source/_generated/_generated/ams.core.service.ValueService.n.rst +6 -0
  260. docs/source/_generated/_generated/ams.core.service.ValueService.parse.rst +6 -0
  261. docs/source/_generated/_generated/ams.core.service.ValueService.shape.rst +6 -0
  262. docs/source/_generated/_generated/ams.core.service.ValueService.size.rst +6 -0
  263. docs/source/_generated/_generated/ams.core.service.ValueService.update.rst +6 -0
  264. docs/source/_generated/_generated/ams.core.service.ValueService.v.rst +6 -0
  265. docs/source/_generated/_generated/ams.core.service.VarReduction.assign_memory.rst +6 -0
  266. docs/source/_generated/_generated/ams.core.service.VarReduction.class_name.rst +6 -0
  267. docs/source/_generated/_generated/ams.core.service.VarReduction.evaluate.rst +6 -0
  268. docs/source/_generated/_generated/ams.core.service.VarReduction.get_names.rst +6 -0
  269. docs/source/_generated/_generated/ams.core.service.VarReduction.n.rst +6 -0
  270. docs/source/_generated/_generated/ams.core.service.VarReduction.parse.rst +6 -0
  271. docs/source/_generated/_generated/ams.core.service.VarReduction.shape.rst +6 -0
  272. docs/source/_generated/_generated/ams.core.service.VarReduction.size.rst +6 -0
  273. docs/source/_generated/_generated/ams.core.service.VarReduction.update.rst +6 -0
  274. docs/source/_generated/_generated/ams.core.service.VarReduction.v.rst +6 -0
  275. docs/source/_generated/_generated/ams.core.service.VarReduction.v0.rst +6 -0
  276. docs/source/_generated/_generated/ams.core.service.VarReduction.v1.rst +6 -0
  277. docs/source/_generated/_generated/ams.core.service.VarSelect.assign_memory.rst +6 -0
  278. docs/source/_generated/_generated/ams.core.service.VarSelect.class_name.rst +6 -0
  279. docs/source/_generated/_generated/ams.core.service.VarSelect.evaluate.rst +6 -0
  280. docs/source/_generated/_generated/ams.core.service.VarSelect.get_names.rst +6 -0
  281. docs/source/_generated/_generated/ams.core.service.VarSelect.n.rst +6 -0
  282. docs/source/_generated/_generated/ams.core.service.VarSelect.parse.rst +6 -0
  283. docs/source/_generated/_generated/ams.core.service.VarSelect.shape.rst +6 -0
  284. docs/source/_generated/_generated/ams.core.service.VarSelect.size.rst +6 -0
  285. docs/source/_generated/_generated/ams.core.service.VarSelect.update.rst +6 -0
  286. docs/source/_generated/_generated/ams.core.service.VarSelect.v.rst +6 -0
  287. docs/source/_generated/_generated/ams.core.service.VarSelect.v0.rst +6 -0
  288. docs/source/_generated/_generated/ams.core.service.VarSelect.v1.rst +6 -0
  289. docs/source/_generated/_generated/ams.core.service.ZonalSum.assign_memory.rst +6 -0
  290. docs/source/_generated/_generated/ams.core.service.ZonalSum.class_name.rst +6 -0
  291. docs/source/_generated/_generated/ams.core.service.ZonalSum.evaluate.rst +6 -0
  292. docs/source/_generated/_generated/ams.core.service.ZonalSum.get_names.rst +6 -0
  293. docs/source/_generated/_generated/ams.core.service.ZonalSum.n.rst +6 -0
  294. docs/source/_generated/_generated/ams.core.service.ZonalSum.parse.rst +6 -0
  295. docs/source/_generated/_generated/ams.core.service.ZonalSum.shape.rst +6 -0
  296. docs/source/_generated/_generated/ams.core.service.ZonalSum.size.rst +6 -0
  297. docs/source/_generated/_generated/ams.core.service.ZonalSum.update.rst +6 -0
  298. docs/source/_generated/_generated/ams.core.service.ZonalSum.v.rst +6 -0
  299. docs/source/_generated/_generated/ams.core.service.ZonalSum.v0.rst +6 -0
  300. docs/source/_generated/_generated/ams.core.service.ZonalSum.v1.rst +6 -0
  301. docs/source/_generated/_generated/ams.interface.Dynamic.is_tds.rst +6 -0
  302. docs/source/_generated/_generated/ams.interface.Dynamic.link_andes.rst +6 -0
  303. docs/source/_generated/_generated/ams.interface.Dynamic.receive.rst +6 -0
  304. docs/source/_generated/_generated/ams.interface.Dynamic.send.rst +6 -0
  305. docs/source/_generated/_generated/ams.opt.constraint.Constraint.class_name.rst +6 -0
  306. docs/source/_generated/_generated/ams.opt.constraint.Constraint.e.rst +6 -0
  307. docs/source/_generated/_generated/ams.opt.constraint.Constraint.evaluate.rst +6 -0
  308. docs/source/_generated/_generated/ams.opt.constraint.Constraint.n.rst +6 -0
  309. docs/source/_generated/_generated/ams.opt.constraint.Constraint.parse.rst +6 -0
  310. docs/source/_generated/_generated/ams.opt.constraint.Constraint.shape.rst +6 -0
  311. docs/source/_generated/_generated/ams.opt.constraint.Constraint.size.rst +6 -0
  312. docs/source/_generated/_generated/ams.opt.constraint.Constraint.v.rst +6 -0
  313. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.class_name.rst +6 -0
  314. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.e.rst +6 -0
  315. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.evaluate.rst +6 -0
  316. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.get_idx.rst +6 -0
  317. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.n.rst +6 -0
  318. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.parse.rst +6 -0
  319. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.shape.rst +6 -0
  320. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.size.rst +6 -0
  321. docs/source/_generated/_generated/ams.opt.exprcalc.ExpressionCalc.v.rst +6 -0
  322. docs/source/_generated/_generated/ams.opt.expression.Expression.class_name.rst +6 -0
  323. docs/source/_generated/_generated/ams.opt.expression.Expression.e.rst +6 -0
  324. docs/source/_generated/_generated/ams.opt.expression.Expression.evaluate.rst +6 -0
  325. docs/source/_generated/_generated/ams.opt.expression.Expression.get_idx.rst +6 -0
  326. docs/source/_generated/_generated/ams.opt.expression.Expression.n.rst +6 -0
  327. docs/source/_generated/_generated/ams.opt.expression.Expression.parse.rst +6 -0
  328. docs/source/_generated/_generated/ams.opt.expression.Expression.shape.rst +6 -0
  329. docs/source/_generated/_generated/ams.opt.expression.Expression.size.rst +6 -0
  330. docs/source/_generated/_generated/ams.opt.expression.Expression.v.rst +6 -0
  331. docs/source/_generated/_generated/ams.opt.objective.Objective.class_name.rst +6 -0
  332. docs/source/_generated/_generated/ams.opt.objective.Objective.e.rst +6 -0
  333. docs/source/_generated/_generated/ams.opt.objective.Objective.evaluate.rst +6 -0
  334. docs/source/_generated/_generated/ams.opt.objective.Objective.n.rst +6 -0
  335. docs/source/_generated/_generated/ams.opt.objective.Objective.parse.rst +6 -0
  336. docs/source/_generated/_generated/ams.opt.objective.Objective.shape.rst +6 -0
  337. docs/source/_generated/_generated/ams.opt.objective.Objective.size.rst +6 -0
  338. docs/source/_generated/_generated/ams.opt.objective.Objective.v.rst +6 -0
  339. docs/source/_generated/_generated/ams.opt.omodel.OModel.class_name.rst +6 -0
  340. docs/source/_generated/_generated/ams.opt.omodel.OModel.evaluate.rst +6 -0
  341. docs/source/_generated/_generated/ams.opt.omodel.OModel.finalize.rst +6 -0
  342. docs/source/_generated/_generated/ams.opt.omodel.OModel.init.rst +6 -0
  343. docs/source/_generated/_generated/ams.opt.omodel.OModel.initialized.rst +6 -0
  344. docs/source/_generated/_generated/ams.opt.omodel.OModel.parse.rst +6 -0
  345. docs/source/_generated/_generated/ams.opt.omodel.OModel.update.rst +6 -0
  346. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.class_name.rst +6 -0
  347. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.evaluate.rst +6 -0
  348. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.finalize.rst +6 -0
  349. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.init.rst +6 -0
  350. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.initialized.rst +6 -0
  351. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.parse.rst +6 -0
  352. docs/source/_generated/_generated/ams.opt.omodel.OModelBase.update.rst +6 -0
  353. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.class_name.rst +6 -0
  354. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.evaluate.rst +6 -0
  355. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.n.rst +6 -0
  356. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.parse.rst +6 -0
  357. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.shape.rst +6 -0
  358. docs/source/_generated/_generated/ams.opt.optbase.OptzBase.size.rst +6 -0
  359. docs/source/_generated/_generated/ams.opt.param.Param.class_name.rst +6 -0
  360. docs/source/_generated/_generated/ams.opt.param.Param.evaluate.rst +6 -0
  361. docs/source/_generated/_generated/ams.opt.param.Param.n.rst +6 -0
  362. docs/source/_generated/_generated/ams.opt.param.Param.parse.rst +6 -0
  363. docs/source/_generated/_generated/ams.opt.param.Param.shape.rst +6 -0
  364. docs/source/_generated/_generated/ams.opt.param.Param.size.rst +6 -0
  365. docs/source/_generated/_generated/ams.opt.param.Param.update.rst +6 -0
  366. docs/source/_generated/_generated/ams.opt.var.Var.class_name.rst +6 -0
  367. docs/source/_generated/_generated/ams.opt.var.Var.evaluate.rst +6 -0
  368. docs/source/_generated/_generated/ams.opt.var.Var.get_idx.rst +6 -0
  369. docs/source/_generated/_generated/ams.opt.var.Var.n.rst +6 -0
  370. docs/source/_generated/_generated/ams.opt.var.Var.parse.rst +6 -0
  371. docs/source/_generated/_generated/ams.opt.var.Var.shape.rst +6 -0
  372. docs/source/_generated/_generated/ams.opt.var.Var.size.rst +6 -0
  373. docs/source/_generated/_generated/ams.opt.var.Var.v.rst +6 -0
  374. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.addConstrs.rst +6 -0
  375. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.addRParam.rst +6 -0
  376. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.addService.rst +6 -0
  377. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.addVars.rst +6 -0
  378. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.class_name.rst +6 -0
  379. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.dc2ac.rst +6 -0
  380. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.disable.rst +6 -0
  381. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.doc.rst +6 -0
  382. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.enable.rst +6 -0
  383. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.export_csv.rst +6 -0
  384. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.get.rst +6 -0
  385. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.init.rst +6 -0
  386. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.run.rst +6 -0
  387. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.set.rst +6 -0
  388. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.solve.rst +6 -0
  389. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.summary.rst +6 -0
  390. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.unpack.rst +6 -0
  391. docs/source/_generated/_generated/ams.routines.dcopf.DCOPF.update.rst +6 -0
  392. docs/source/_generated/_generated/ams.routines.pflow.PFlow.addConstrs.rst +6 -0
  393. docs/source/_generated/_generated/ams.routines.pflow.PFlow.addRParam.rst +6 -0
  394. docs/source/_generated/_generated/ams.routines.pflow.PFlow.addService.rst +6 -0
  395. docs/source/_generated/_generated/ams.routines.pflow.PFlow.addVars.rst +6 -0
  396. docs/source/_generated/_generated/ams.routines.pflow.PFlow.class_name.rst +6 -0
  397. docs/source/_generated/_generated/ams.routines.pflow.PFlow.dc2ac.rst +6 -0
  398. docs/source/_generated/_generated/ams.routines.pflow.PFlow.disable.rst +6 -0
  399. docs/source/_generated/_generated/ams.routines.pflow.PFlow.doc.rst +6 -0
  400. docs/source/_generated/_generated/ams.routines.pflow.PFlow.enable.rst +6 -0
  401. docs/source/_generated/_generated/ams.routines.pflow.PFlow.export_csv.rst +6 -0
  402. docs/source/_generated/_generated/ams.routines.pflow.PFlow.get.rst +6 -0
  403. docs/source/_generated/_generated/ams.routines.pflow.PFlow.init.rst +6 -0
  404. docs/source/_generated/_generated/ams.routines.pflow.PFlow.run.rst +6 -0
  405. docs/source/_generated/_generated/ams.routines.pflow.PFlow.set.rst +6 -0
  406. docs/source/_generated/_generated/ams.routines.pflow.PFlow.solve.rst +6 -0
  407. docs/source/_generated/_generated/ams.routines.pflow.PFlow.summary.rst +6 -0
  408. docs/source/_generated/_generated/ams.routines.pflow.PFlow.unpack.rst +6 -0
  409. docs/source/_generated/_generated/ams.routines.pflow.PFlow.update.rst +6 -0
  410. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.addConstrs.rst +6 -0
  411. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.addRParam.rst +6 -0
  412. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.addService.rst +6 -0
  413. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.addVars.rst +6 -0
  414. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.class_name.rst +6 -0
  415. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.dc2ac.rst +6 -0
  416. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.disable.rst +6 -0
  417. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.doc.rst +6 -0
  418. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.enable.rst +6 -0
  419. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.export_csv.rst +6 -0
  420. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.get.rst +6 -0
  421. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.init.rst +6 -0
  422. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.run.rst +6 -0
  423. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.set.rst +6 -0
  424. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.solve.rst +6 -0
  425. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.summary.rst +6 -0
  426. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.unpack.rst +6 -0
  427. docs/source/_generated/_generated/ams.routines.routine.RoutineBase.update.rst +6 -0
  428. docs/source/_generated/_generated/ams.system.System.add.rst +6 -0
  429. docs/source/_generated/_generated/ams.system.System.as_dict.rst +6 -0
  430. docs/source/_generated/_generated/ams.system.System.calc_pu_coeff.rst +6 -0
  431. docs/source/_generated/_generated/ams.system.System.call_models.rst +6 -0
  432. docs/source/_generated/_generated/ams.system.System.collect_config.rst +6 -0
  433. docs/source/_generated/_generated/ams.system.System.collect_ref.rst +6 -0
  434. docs/source/_generated/_generated/ams.system.System.connectivity.rst +6 -0
  435. docs/source/_generated/_generated/ams.system.System.e_clear.rst +6 -0
  436. docs/source/_generated/_generated/ams.system.System.f_update.rst +6 -0
  437. docs/source/_generated/_generated/ams.system.System.fg_to_dae.rst +6 -0
  438. docs/source/_generated/_generated/ams.system.System.find_devices.rst +6 -0
  439. docs/source/_generated/_generated/ams.system.System.find_models.rst +6 -0
  440. docs/source/_generated/_generated/ams.system.System.from_ipysheet.rst +6 -0
  441. docs/source/_generated/_generated/ams.system.System.g_islands.rst +6 -0
  442. docs/source/_generated/_generated/ams.system.System.g_update.rst +6 -0
  443. docs/source/_generated/_generated/ams.system.System.get_z.rst +6 -0
  444. docs/source/_generated/_generated/ams.system.System.import_groups.rst +6 -0
  445. docs/source/_generated/_generated/ams.system.System.import_models.rst +6 -0
  446. docs/source/_generated/_generated/ams.system.System.import_routines.rst +6 -0
  447. docs/source/_generated/_generated/ams.system.System.import_types.rst +6 -0
  448. docs/source/_generated/_generated/ams.system.System.init.rst +6 -0
  449. docs/source/_generated/_generated/ams.system.System.j_islands.rst +6 -0
  450. docs/source/_generated/_generated/ams.system.System.j_update.rst +6 -0
  451. docs/source/_generated/_generated/ams.system.System.l_update_eq.rst +6 -0
  452. docs/source/_generated/_generated/ams.system.System.l_update_var.rst +6 -0
  453. docs/source/_generated/_generated/ams.system.System.link_ext_param.rst +6 -0
  454. docs/source/_generated/_generated/ams.system.System.precompile.rst +6 -0
  455. docs/source/_generated/_generated/ams.system.System.prepare.rst +6 -0
  456. docs/source/_generated/_generated/ams.system.System.reload.rst +6 -0
  457. docs/source/_generated/_generated/ams.system.System.remove_pycapsule.rst +6 -0
  458. docs/source/_generated/_generated/ams.system.System.report.rst +6 -0
  459. docs/source/_generated/_generated/ams.system.System.reset.rst +6 -0
  460. docs/source/_generated/_generated/ams.system.System.s_update_post.rst +6 -0
  461. docs/source/_generated/_generated/ams.system.System.s_update_var.rst +6 -0
  462. docs/source/_generated/_generated/ams.system.System.save_config.rst +6 -0
  463. docs/source/_generated/_generated/ams.system.System.set_address.rst +6 -0
  464. docs/source/_generated/_generated/ams.system.System.set_config.rst +6 -0
  465. docs/source/_generated/_generated/ams.system.System.set_dae_names.rst +6 -0
  466. docs/source/_generated/_generated/ams.system.System.set_output_subidx.rst +6 -0
  467. docs/source/_generated/_generated/ams.system.System.set_var_arrays.rst +6 -0
  468. docs/source/_generated/_generated/ams.system.System.setup.rst +6 -0
  469. docs/source/_generated/_generated/ams.system.System.store_adder_setter.rst +6 -0
  470. docs/source/_generated/_generated/ams.system.System.store_existing.rst +6 -0
  471. docs/source/_generated/_generated/ams.system.System.store_no_check_init.rst +6 -0
  472. docs/source/_generated/_generated/ams.system.System.store_sparse_pattern.rst +6 -0
  473. docs/source/_generated/_generated/ams.system.System.store_switch_times.rst +6 -0
  474. docs/source/_generated/_generated/ams.system.System.summary.rst +6 -0
  475. docs/source/_generated/_generated/ams.system.System.supported_models.rst +6 -0
  476. docs/source/_generated/_generated/ams.system.System.supported_routines.rst +6 -0
  477. docs/source/_generated/_generated/ams.system.System.switch_action.rst +6 -0
  478. docs/source/_generated/_generated/ams.system.System.to_andes.rst +6 -0
  479. docs/source/_generated/_generated/ams.system.System.to_ipysheet.rst +6 -0
  480. docs/source/_generated/_generated/ams.system.System.undill.rst +6 -0
  481. docs/source/_generated/_generated/ams.system.System.vars_to_dae.rst +6 -0
  482. docs/source/_generated/_generated/ams.system.System.vars_to_models.rst +6 -0
  483. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.display_filename_prefix_last.rst +6 -0
  484. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.display_filename_prefix_middle.rst +6 -0
  485. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.display_parent_prefix_last.rst +6 -0
  486. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.display_parent_prefix_middle.rst +6 -0
  487. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.displayable.rst +6 -0
  488. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.displayname.rst +6 -0
  489. docs/source/_generated/_generated/ams.utils.paths.DisplayablePath.make_tree.rst +6 -0
  490. docs/source/_generated/ams.cli.create_parser.rst +6 -0
  491. docs/source/_generated/ams.cli.main.rst +6 -0
  492. docs/source/_generated/ams.cli.preamble.rst +6 -0
  493. docs/source/_generated/ams.cli.rst +32 -0
  494. docs/source/_generated/ams.core.model.Model.rst +56 -0
  495. docs/source/_generated/ams.core.model.rst +30 -0
  496. docs/source/_generated/ams.core.param.RParam.rst +49 -0
  497. docs/source/_generated/ams.core.param.rst +30 -0
  498. docs/source/_generated/ams.core.service.LoadScale.rst +51 -0
  499. docs/source/_generated/ams.core.service.MinDur.rst +53 -0
  500. docs/source/_generated/ams.core.service.NumExpandDim.rst +53 -0
  501. docs/source/_generated/ams.core.service.NumHstack.rst +53 -0
  502. docs/source/_generated/ams.core.service.NumOp.rst +53 -0
  503. docs/source/_generated/ams.core.service.NumOpDual.rst +53 -0
  504. docs/source/_generated/ams.core.service.RBaseService.rst +51 -0
  505. docs/source/_generated/ams.core.service.ROperationService.rst +51 -0
  506. docs/source/_generated/ams.core.service.RampSub.rst +53 -0
  507. docs/source/_generated/ams.core.service.ValueService.rst +51 -0
  508. docs/source/_generated/ams.core.service.VarReduction.rst +53 -0
  509. docs/source/_generated/ams.core.service.VarSelect.rst +53 -0
  510. docs/source/_generated/ams.core.service.ZonalSum.rst +53 -0
  511. docs/source/_generated/ams.core.service.rst +42 -0
  512. docs/source/_generated/ams.interface.Dynamic.rst +41 -0
  513. docs/source/_generated/ams.interface.build_group_table.rst +6 -0
  514. docs/source/_generated/ams.interface.make_link_table.rst +6 -0
  515. docs/source/_generated/ams.interface.parse_addfile.rst +6 -0
  516. docs/source/_generated/ams.interface.replace_dev.rst +6 -0
  517. docs/source/_generated/ams.interface.rst +43 -0
  518. docs/source/_generated/ams.interface.sync_adsys.rst +6 -0
  519. docs/source/_generated/ams.interface.to_andes.rst +6 -0
  520. docs/source/_generated/ams.interface.verify_pf.rst +6 -0
  521. docs/source/_generated/ams.io.guess.rst +6 -0
  522. docs/source/_generated/ams.io.json.rst +30 -0
  523. docs/source/_generated/ams.io.json.write.rst +6 -0
  524. docs/source/_generated/ams.io.matpower.mpc2system.rst +6 -0
  525. docs/source/_generated/ams.io.matpower.read.rst +6 -0
  526. docs/source/_generated/ams.io.matpower.rst +33 -0
  527. docs/source/_generated/ams.io.matpower.system2mpc.rst +6 -0
  528. docs/source/_generated/ams.io.matpower.testlines.rst +6 -0
  529. docs/source/_generated/ams.io.parse.rst +6 -0
  530. docs/source/_generated/ams.io.psse.rst +23 -0
  531. docs/source/_generated/ams.io.pypower.ppc2system.rst +6 -0
  532. docs/source/_generated/ams.io.pypower.py2ppc.rst +6 -0
  533. docs/source/_generated/ams.io.pypower.read.rst +6 -0
  534. docs/source/_generated/ams.io.pypower.rst +34 -0
  535. docs/source/_generated/ams.io.pypower.system2ppc.rst +6 -0
  536. docs/source/_generated/ams.io.pypower.testlines.rst +6 -0
  537. docs/source/_generated/ams.io.rst +45 -0
  538. docs/source/_generated/ams.io.xlsx.rst +30 -0
  539. docs/source/_generated/ams.io.xlsx.write.rst +6 -0
  540. docs/source/_generated/ams.main.config_logger.rst +6 -0
  541. docs/source/_generated/ams.main.demo.rst +6 -0
  542. docs/source/_generated/ams.main.doc.rst +6 -0
  543. docs/source/_generated/ams.main.edit_conf.rst +6 -0
  544. docs/source/_generated/ams.main.find_log_path.rst +6 -0
  545. docs/source/_generated/ams.main.load.rst +6 -0
  546. docs/source/_generated/ams.main.misc.rst +6 -0
  547. docs/source/_generated/ams.main.print_license.rst +6 -0
  548. docs/source/_generated/ams.main.remove_output.rst +6 -0
  549. docs/source/_generated/ams.main.rst +44 -0
  550. docs/source/_generated/ams.main.run.rst +6 -0
  551. docs/source/_generated/ams.main.run_case.rst +6 -0
  552. docs/source/_generated/ams.main.save_conf.rst +6 -0
  553. docs/source/_generated/ams.main.selftest.rst +6 -0
  554. docs/source/_generated/ams.main.set_logger_level.rst +6 -0
  555. docs/source/_generated/ams.main.versioninfo.rst +6 -0
  556. docs/source/_generated/ams.opt.constraint.Constraint.rst +43 -0
  557. docs/source/_generated/ams.opt.constraint.rst +30 -0
  558. docs/source/_generated/ams.opt.exprcalc.ExpressionCalc.rst +46 -0
  559. docs/source/_generated/ams.opt.exprcalc.rst +30 -0
  560. docs/source/_generated/ams.opt.expression.Expression.rst +46 -0
  561. docs/source/_generated/ams.opt.expression.rst +30 -0
  562. docs/source/_generated/ams.opt.objective.Objective.rst +43 -0
  563. docs/source/_generated/ams.opt.objective.rst +30 -0
  564. docs/source/_generated/ams.opt.omodel.OModel.rst +48 -0
  565. docs/source/_generated/ams.opt.omodel.OModelBase.rst +48 -0
  566. docs/source/_generated/ams.opt.omodel.rst +31 -0
  567. docs/source/_generated/ams.opt.optbase.OptzBase.rst +41 -0
  568. docs/source/_generated/ams.opt.optbase.ensure_mats_and_parsed.rst +6 -0
  569. docs/source/_generated/ams.opt.optbase.ensure_symbols.rst +6 -0
  570. docs/source/_generated/ams.opt.optbase.rst +38 -0
  571. docs/source/_generated/ams.opt.param.Param.rst +44 -0
  572. docs/source/_generated/ams.opt.param.rst +30 -0
  573. docs/source/_generated/ams.opt.rst +40 -0
  574. docs/source/_generated/ams.opt.var.Var.rst +45 -0
  575. docs/source/_generated/ams.opt.var.rst +30 -0
  576. docs/source/_generated/ams.routines.dcopf.DCOPF.rst +83 -0
  577. docs/source/_generated/ams.routines.dcopf.rst +30 -0
  578. docs/source/_generated/ams.routines.pflow.PFlow.rst +83 -0
  579. docs/source/_generated/ams.routines.pflow.rst +30 -0
  580. docs/source/_generated/ams.routines.routine.RoutineBase.rst +83 -0
  581. docs/source/_generated/ams.routines.routine.collect_data.rst +6 -0
  582. docs/source/_generated/ams.routines.routine.initialize_data_dict.rst +6 -0
  583. docs/source/_generated/ams.routines.routine.rst +38 -0
  584. docs/source/_generated/ams.system.System.rst +189 -0
  585. docs/source/_generated/ams.system.disable_method.rst +6 -0
  586. docs/source/_generated/ams.system.disable_methods.rst +6 -0
  587. docs/source/_generated/ams.system.example.rst +6 -0
  588. docs/source/_generated/ams.system.rst +39 -0
  589. docs/source/_generated/ams.utils.paths.DisplayablePath.rst +42 -0
  590. docs/source/_generated/ams.utils.paths.ams_root.rst +6 -0
  591. docs/source/_generated/ams.utils.paths.cases_root.rst +6 -0
  592. docs/source/_generated/ams.utils.paths.confirm_overwrite.rst +6 -0
  593. docs/source/_generated/ams.utils.paths.get_case.rst +6 -0
  594. docs/source/_generated/ams.utils.paths.get_config_path.rst +6 -0
  595. docs/source/_generated/ams.utils.paths.get_dot_andes_path.rst +6 -0
  596. docs/source/_generated/ams.utils.paths.get_log_dir.rst +6 -0
  597. docs/source/_generated/ams.utils.paths.get_pkl_path.rst +6 -0
  598. docs/source/_generated/ams.utils.paths.get_pycode_path.rst +6 -0
  599. docs/source/_generated/ams.utils.paths.list_cases.rst +6 -0
  600. docs/source/_generated/ams.utils.paths.rst +47 -0
  601. docs/source/_generated/ams.utils.paths.tests_root.rst +6 -0
  602. docs/source/_templates/autosummary/base.rst +5 -0
  603. docs/source/_templates/autosummary/class.rst +35 -0
  604. docs/source/_templates/autosummary/module.rst +65 -0
  605. docs/source/_templates/autosummary/module_toctree.rst +66 -0
  606. docs/source/api.rst +102 -0
  607. docs/source/conf.py +203 -0
  608. docs/source/examples/index.rst +34 -0
  609. docs/source/genmodelref.py +61 -0
  610. docs/source/genroutineref.py +47 -0
  611. docs/source/getting_started/copyright.rst +20 -0
  612. docs/source/getting_started/formats/index.rst +20 -0
  613. docs/source/getting_started/formats/matpower.rst +183 -0
  614. docs/source/getting_started/formats/psse.rst +46 -0
  615. docs/source/getting_started/formats/pypower.rst +223 -0
  616. docs/source/getting_started/formats/xlsx.png +0 -0
  617. docs/source/getting_started/formats/xlsx.rst +23 -0
  618. docs/source/getting_started/index.rst +76 -0
  619. docs/source/getting_started/install.rst +234 -0
  620. docs/source/getting_started/overview.rst +26 -0
  621. docs/source/getting_started/testcase.rst +45 -0
  622. docs/source/getting_started/verification.rst +13 -0
  623. docs/source/groupdoc/ACLine.rst +92 -0
  624. docs/source/groupdoc/ACShort.rst +51 -0
  625. docs/source/groupdoc/ACTopology.rst +66 -0
  626. docs/source/groupdoc/Collection.rst +84 -0
  627. docs/source/groupdoc/Cost.rst +135 -0
  628. docs/source/groupdoc/DG.rst +204 -0
  629. docs/source/groupdoc/Horizon.rst +97 -0
  630. docs/source/groupdoc/Information.rst +36 -0
  631. docs/source/groupdoc/RenGen.rst +63 -0
  632. docs/source/groupdoc/Reserve.rst +135 -0
  633. docs/source/groupdoc/StaticGen.rst +229 -0
  634. docs/source/groupdoc/StaticLoad.rst +53 -0
  635. docs/source/groupdoc/StaticShunt.rst +45 -0
  636. docs/source/groupdoc/Undefined.rst +63 -0
  637. docs/source/groupdoc/VSG.rst +125 -0
  638. docs/source/images/dcopf_time.png +0 -0
  639. docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  640. docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  641. docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  642. docs/source/images/sponsors/doe.png +0 -0
  643. docs/source/index.rst +108 -0
  644. docs/source/modeling/_generated/_generated/ams.opt.Constraint.class_name.rst +6 -0
  645. docs/source/modeling/_generated/_generated/ams.opt.Constraint.e.rst +6 -0
  646. docs/source/modeling/_generated/_generated/ams.opt.Constraint.evaluate.rst +6 -0
  647. docs/source/modeling/_generated/_generated/ams.opt.Constraint.n.rst +6 -0
  648. docs/source/modeling/_generated/_generated/ams.opt.Constraint.parse.rst +6 -0
  649. docs/source/modeling/_generated/_generated/ams.opt.Constraint.shape.rst +6 -0
  650. docs/source/modeling/_generated/_generated/ams.opt.Constraint.size.rst +6 -0
  651. docs/source/modeling/_generated/_generated/ams.opt.Constraint.v.rst +6 -0
  652. docs/source/modeling/_generated/_generated/ams.opt.OModel.class_name.rst +6 -0
  653. docs/source/modeling/_generated/_generated/ams.opt.OModel.evaluate.rst +6 -0
  654. docs/source/modeling/_generated/_generated/ams.opt.OModel.finalize.rst +6 -0
  655. docs/source/modeling/_generated/_generated/ams.opt.OModel.init.rst +6 -0
  656. docs/source/modeling/_generated/_generated/ams.opt.OModel.initialized.rst +6 -0
  657. docs/source/modeling/_generated/_generated/ams.opt.OModel.parse.rst +6 -0
  658. docs/source/modeling/_generated/_generated/ams.opt.OModel.update.rst +6 -0
  659. docs/source/modeling/_generated/_generated/ams.opt.Objective.class_name.rst +6 -0
  660. docs/source/modeling/_generated/_generated/ams.opt.Objective.e.rst +6 -0
  661. docs/source/modeling/_generated/_generated/ams.opt.Objective.evaluate.rst +6 -0
  662. docs/source/modeling/_generated/_generated/ams.opt.Objective.n.rst +6 -0
  663. docs/source/modeling/_generated/_generated/ams.opt.Objective.parse.rst +6 -0
  664. docs/source/modeling/_generated/_generated/ams.opt.Objective.shape.rst +6 -0
  665. docs/source/modeling/_generated/_generated/ams.opt.Objective.size.rst +6 -0
  666. docs/source/modeling/_generated/_generated/ams.opt.Objective.v.rst +6 -0
  667. docs/source/modeling/_generated/_generated/ams.opt.Var.class_name.rst +6 -0
  668. docs/source/modeling/_generated/_generated/ams.opt.Var.evaluate.rst +6 -0
  669. docs/source/modeling/_generated/_generated/ams.opt.Var.get_idx.rst +6 -0
  670. docs/source/modeling/_generated/_generated/ams.opt.Var.n.rst +6 -0
  671. docs/source/modeling/_generated/_generated/ams.opt.Var.parse.rst +6 -0
  672. docs/source/modeling/_generated/_generated/ams.opt.Var.shape.rst +6 -0
  673. docs/source/modeling/_generated/_generated/ams.opt.Var.size.rst +6 -0
  674. docs/source/modeling/_generated/_generated/ams.opt.Var.v.rst +6 -0
  675. docs/source/modeling/_generated/ams.opt.Constraint.rst +43 -0
  676. docs/source/modeling/_generated/ams.opt.OModel.rst +48 -0
  677. docs/source/modeling/_generated/ams.opt.Objective.rst +43 -0
  678. docs/source/modeling/_generated/ams.opt.Var.rst +45 -0
  679. docs/source/modeling/example.rst +159 -0
  680. docs/source/modeling/index.rst +17 -0
  681. docs/source/modeling/model.rst +210 -0
  682. docs/source/modeling/routine.rst +122 -0
  683. docs/source/modeling/system.rst +51 -0
  684. docs/source/modelref.rst +66 -0
  685. docs/source/release-notes.rst +385 -0
  686. docs/source/routineref.rst +38 -0
  687. docs/source/typedoc/ACED.rst +91 -0
  688. docs/source/typedoc/DCED.rst +1869 -0
  689. docs/source/typedoc/DCUC.rst +899 -0
  690. docs/source/typedoc/DED.rst +390 -0
  691. docs/source/typedoc/PF.rst +376 -0
  692. docs/source/typedoc/UndefinedType.rst +8 -0
  693. icebar/ips/ips.py +668 -0
  694. ltbams-1.0.0.dist-info/METADATA +231 -0
  695. ltbams-1.0.0.dist-info/RECORD +725 -0
  696. {ltbams-0.9.9.dist-info → ltbams-1.0.0.dist-info}/WHEEL +1 -1
  697. ltbams-1.0.0.dist-info/top_level.txt +5 -0
  698. tests/__init__.py +0 -0
  699. tests/test_1st_system.py +33 -0
  700. tests/test_addressing.py +40 -0
  701. tests/test_andes_mats.py +61 -0
  702. tests/test_case.py +266 -0
  703. tests/test_cli.py +34 -0
  704. tests/test_export_csv.py +89 -0
  705. tests/test_group.py +83 -0
  706. tests/test_interface.py +216 -0
  707. tests/test_io.py +32 -0
  708. tests/test_jumper.py +27 -0
  709. tests/test_known_good.py +267 -0
  710. tests/test_matp.py +437 -0
  711. tests/test_model.py +54 -0
  712. tests/test_omodel.py +119 -0
  713. tests/test_paths.py +22 -0
  714. tests/test_report.py +245 -0
  715. tests/test_repr.py +21 -0
  716. tests/test_routine.py +178 -0
  717. tests/test_rtn_dcopf.py +101 -0
  718. tests/test_rtn_dcpf.py +77 -0
  719. tests/test_rtn_ed.py +275 -0
  720. tests/test_rtn_pflow.py +219 -0
  721. tests/test_rtn_rted.py +273 -0
  722. tests/test_rtn_uc.py +248 -0
  723. tests/test_service.py +73 -0
  724. ltbams-0.9.9.dist-info/LICENSE +0 -692
  725. ltbams-0.9.9.dist-info/METADATA +0 -859
  726. ltbams-0.9.9.dist-info/RECORD +0 -14
  727. ltbams-0.9.9.dist-info/top_level.txt +0 -1
  728. {ltbams-0.9.9.dist-info → ltbams-1.0.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1946 @@
1
+ """
2
+ Module for OPF functions.
3
+ """
4
+ import logging
5
+ from copy import deepcopy
6
+
7
+ import numpy as np
8
+ from numpy import flatnonzero as find
9
+
10
+ import scipy.sparse as sp
11
+ from scipy.sparse import csr_matrix as c_sparse
12
+ from scipy.sparse import lil_matrix as l_sparse
13
+
14
+ from ams.pypower.utils import isload, get_reorder, set_reorder
15
+ from ams.pypower.idx import IDX
16
+ from ams.pypower.make import (d2Sbus_dV2, dSbus_dV, dIbr_dV,
17
+ d2AIbr_dV2, d2ASbr_dV2, dSbr_dV,
18
+ makeSbus, dAbr_dV)
19
+
20
+ from ams.shared import inf
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il=None, cost_mult=1.0):
26
+ """
27
+ Evaluates Hessian of Lagrangian for AC OPF.
28
+
29
+ Hessian evaluation function for AC optimal power flow, suitable
30
+ for use with L{pips}.
31
+
32
+ Examples::
33
+ Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt)
34
+ Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il)
35
+ Lxx = opf_hessfcn(x, lmbda, om, Ybus, Yf, Yt, ppopt, il, cost_mult)
36
+
37
+ @param x: optimization vector
38
+ @param lmbda: C{eqnonlin} - Lagrange multipliers on power balance
39
+ equations. C{ineqnonlin} - Kuhn-Tucker multipliers on constrained
40
+ branch flows.
41
+ @param om: OPF model object
42
+ @param Ybus: bus admittance matrix
43
+ @param Yf: admittance matrix for "from" end of constrained branches
44
+ @param Yt: admittance matrix for "to" end of constrained branches
45
+ @param ppopt: PYPOWER options vector
46
+ @param il: (optional) vector of branch indices corresponding to
47
+ branches with flow limits (all others are assumed to be unconstrained).
48
+ The default is C{range(nl)} (all branches). C{Yf} and C{Yt} contain
49
+ only the rows corresponding to C{il}.
50
+ @param cost_mult: (optional) Scale factor to be applied to the cost
51
+ (default = 1).
52
+
53
+ @return: Hessian of the Lagrangian.
54
+
55
+ @see: L{opf_costfcn}, L{opf_consfcn}
56
+
57
+ @author: Ray Zimmerman (PSERC Cornell)
58
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
59
+ Autonoma de Manizales)
60
+ """
61
+ # ----- initialize -----
62
+ # unpack data
63
+ ppc = om.get_ppc()
64
+ baseMVA, bus, gen, branch, gencost = \
65
+ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"], ppc["gencost"]
66
+ cp = om.get_cost_params()
67
+ N, Cw, H, dd, rh, kk, mm = \
68
+ cp["N"], cp["Cw"], cp["H"], cp["dd"], cp["rh"], cp["kk"], cp["mm"]
69
+ vv, _, _, _ = om.get_idx()
70
+
71
+ # unpack needed parameters
72
+ nb = bus.shape[0] # number of buses
73
+ nl = branch.shape[0] # number of branches
74
+ ng = gen.shape[0] # number of dispatchable injections
75
+ nxyz = len(x) # total number of control vars of all types
76
+
77
+ # set default constrained lines
78
+ if il is None:
79
+ il = np.arange(nl) # all lines have limits by default
80
+ nl2 = len(il) # number of constrained lines
81
+
82
+ # grab Pg & Qg
83
+ Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]] # active generation in p.u.
84
+ Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]] # reactive generation in p.u.
85
+
86
+ # put Pg & Qg back in gen
87
+ gen[:, IDX.gen.PG] = Pg * baseMVA # active generation in MW
88
+ gen[:, IDX.gen.QG] = Qg * baseMVA # reactive generation in MVAr
89
+
90
+ # reconstruct V
91
+ Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
92
+ Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
93
+ V = Vm * np.exp(1j * Va)
94
+ nxtra = nxyz - 2 * nb
95
+ pcost = gencost[np.arange(ng), :]
96
+ if gencost.shape[0] > ng:
97
+ qcost = gencost[np.arange(ng, 2 * ng), :]
98
+ else:
99
+ qcost = np.array([])
100
+
101
+ # ----- evaluate d2f -----
102
+ d2f_dPg2 = np.zeros(ng) # c_sparse((ng, 1)) ## w.r.t. p.u. Pg
103
+ d2f_dQg2 = np.zeros(ng) # c_sparse((ng, 1)) ## w.r.t. p.u. Qg
104
+ ipolp = find(pcost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
105
+ d2f_dPg2[ipolp] = \
106
+ baseMVA**2 * polycost(pcost[ipolp, :], Pg[ipolp] * baseMVA, 2)
107
+ if np.any(qcost): # Qg is not free
108
+ ipolq = find(qcost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
109
+ d2f_dQg2[ipolq] = \
110
+ baseMVA**2 * polycost(qcost[ipolq, :], Qg[ipolq] * baseMVA, 2)
111
+ i = np.r_[np.arange(vv["i1"]["Pg"], vv["iN"]["Pg"]),
112
+ np.arange(vv["i1"]["Qg"], vv["iN"]["Qg"])]
113
+ # d2f = c_sparse((sp.vstack([d2f_dPg2, d2f_dQg2]).toarray().flatten(),
114
+ # (i, i)), shape=(nxyz, nxyz))
115
+ d2f = c_sparse((np.r_[d2f_dPg2, d2f_dQg2], (i, i)), (nxyz, nxyz))
116
+
117
+ # generalized cost
118
+ if sp.issparse(N) and N.nnz > 0:
119
+ nw = N.shape[0]
120
+ r = N * x - rh # Nx - rhat
121
+ iLT = find(r < -kk) # below dead zone
122
+ iEQ = find((r == 0) & (kk == 0)) # dead zone doesn't exist
123
+ iGT = find(r > kk) # above dead zone
124
+ iND = np.r_[iLT, iEQ, iGT] # rows that are Not in the Dead region
125
+ iL = find(dd == 1) # rows using linear function
126
+ iQ = find(dd == 2) # rows using quadratic function
127
+ LL = c_sparse((np.ones(len(iL)), (iL, iL)), (nw, nw))
128
+ QQ = c_sparse((np.ones(len(iQ)), (iQ, iQ)), (nw, nw))
129
+ kbar = c_sparse((np.r_[np.ones(len(iLT)), np.zeros(len(iEQ)), -np.ones(len(iGT))],
130
+ (iND, iND)), (nw, nw)) * kk
131
+ rr = r + kbar # apply non-dead zone shift
132
+ M = c_sparse((mm[iND], (iND, iND)), (nw, nw)) # dead zone or scale
133
+ diagrr = c_sparse((rr, (np.arange(nw), np.arange(nw))), (nw, nw))
134
+
135
+ # linear rows multiplied by rr(i), quadratic rows by rr(i)^2
136
+ w = M * (LL + QQ * diagrr) * rr
137
+ HwC = H * w + Cw
138
+ AA = N.T * M * (LL + 2 * QQ * diagrr)
139
+
140
+ d2f = d2f + AA * H * AA.T + 2 * N.T * M * QQ * \
141
+ c_sparse((HwC, (np.arange(nw), np.arange(nw))), (nw, nw)) * N
142
+ d2f = d2f * cost_mult
143
+
144
+ # ----- evaluate Hessian of power balance constraints -----
145
+ nlam = int(len(lmbda["eqnonlin"]) / 2)
146
+ lamP = lmbda["eqnonlin"][:nlam]
147
+ lamQ = lmbda["eqnonlin"][nlam:nlam + nlam]
148
+ Gpaa, Gpav, Gpva, Gpvv = d2Sbus_dV2(Ybus, V, lamP)
149
+ Gqaa, Gqav, Gqva, Gqvv = d2Sbus_dV2(Ybus, V, lamQ)
150
+
151
+ d2G = sp.vstack([
152
+ sp.hstack([
153
+ sp.vstack([sp.hstack([Gpaa, Gpav]),
154
+ sp.hstack([Gpva, Gpvv])]).real +
155
+ sp.vstack([sp.hstack([Gqaa, Gqav]),
156
+ sp.hstack([Gqva, Gqvv])]).imag,
157
+ c_sparse((2 * nb, nxtra))]),
158
+ sp.hstack([
159
+ c_sparse((nxtra, 2 * nb)),
160
+ c_sparse((nxtra, nxtra))
161
+ ])
162
+ ], "csr")
163
+
164
+ # ----- evaluate Hessian of flow constraints -----
165
+ nmu = int(len(lmbda["ineqnonlin"]) / 2)
166
+ muF = lmbda["ineqnonlin"][:nmu]
167
+ muT = lmbda["ineqnonlin"][nmu:nmu + nmu]
168
+ if ppopt['OPF_FLOW_LIM'] == 2: # current
169
+ dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(branch, Yf, Yt, V)
170
+ Hfaa, Hfav, Hfva, Hfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, muF)
171
+ Htaa, Htav, Htva, Htvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, muT)
172
+ else:
173
+ f = branch[il, IDX.branch.F_BUS].astype(int) # list of "from" buses
174
+ t = branch[il, IDX.branch.T_BUS].astype(int) # list of "to" buses
175
+ # connection matrix for line & from buses
176
+ Cf = c_sparse((np.ones(nl2), (np.arange(nl2), f)), (nl2, nb))
177
+ # connection matrix for line & to buses
178
+ Ct = c_sparse((np.ones(nl2), (np.arange(nl2), t)), (nl2, nb))
179
+ dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = \
180
+ dSbr_dV(branch[il, :], Yf, Yt, V)
181
+ if ppopt['OPF_FLOW_LIM'] == 1: # real power
182
+ Hfaa, Hfav, Hfva, Hfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real,
183
+ Sf.real, Cf, Yf, V, muF)
184
+ Htaa, Htav, Htva, Htvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real,
185
+ St.real, Ct, Yt, V, muT)
186
+ else: # apparent power
187
+ Hfaa, Hfav, Hfva, Hfvv = \
188
+ d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, muF)
189
+ Htaa, Htav, Htva, Htvv = \
190
+ d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, muT)
191
+
192
+ d2H = sp.vstack([
193
+ sp.hstack([
194
+ sp.vstack([sp.hstack([Hfaa, Hfav]),
195
+ sp.hstack([Hfva, Hfvv])]) +
196
+ sp.vstack([sp.hstack([Htaa, Htav]),
197
+ sp.hstack([Htva, Htvv])]),
198
+ c_sparse((2 * nb, nxtra))
199
+ ]),
200
+ sp.hstack([
201
+ c_sparse((nxtra, 2 * nb)),
202
+ c_sparse((nxtra, nxtra))
203
+ ])
204
+ ], "csr")
205
+
206
+ # ----- do numerical check using (central) finite differences -----
207
+ if 0:
208
+ nx = len(x)
209
+ step = 1e-5
210
+ num_d2f = c_sparse((nx, nx))
211
+ num_d2G = c_sparse((nx, nx))
212
+ num_d2H = c_sparse((nx, nx))
213
+ for i in range(nx):
214
+ xp = x
215
+ xm = x
216
+ xp[i] = x[i] + step / 2
217
+ xm[i] = x[i] - step / 2
218
+ # evaluate cost & gradients
219
+ _, dfp = opf_costfcn(xp, om)
220
+ _, dfm = opf_costfcn(xm, om)
221
+ # evaluate constraints & gradients
222
+ _, _, dHp, dGp = opf_consfcn(xp, om, Ybus, Yf, Yt, ppopt, il)
223
+ _, _, dHm, dGm = opf_consfcn(xm, om, Ybus, Yf, Yt, ppopt, il)
224
+ num_d2f[:, i] = cost_mult * (dfp - dfm) / step
225
+ num_d2G[:, i] = (dGp - dGm) * lmbda["eqnonlin"] / step
226
+ num_d2H[:, i] = (dHp - dHm) * lmbda["ineqnonlin"] / step
227
+ d2f_err = max(max(abs(d2f - num_d2f)))
228
+ d2G_err = max(max(abs(d2G - num_d2G)))
229
+ d2H_err = max(max(abs(d2H - num_d2H)))
230
+ if d2f_err > 1e-6:
231
+ print('Max difference in d2f: %g' % d2f_err)
232
+ if d2G_err > 1e-5:
233
+ print('Max difference in d2G: %g' % d2G_err)
234
+ if d2H_err > 1e-6:
235
+ print('Max difference in d2H: %g' % d2H_err)
236
+
237
+ return d2f + d2G + d2H
238
+
239
+
240
+ def opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il=None, *args):
241
+ """
242
+ Evaluates nonlinear constraints and their Jacobian for OPF.
243
+
244
+ Constraint evaluation function for AC optimal power flow, suitable
245
+ for use with L{pips}. Computes constraint vectors and their gradients.
246
+
247
+ @param x: optimization vector
248
+ @param om: OPF model object
249
+ @param Ybus: bus admittance matrix
250
+ @param Yf: admittance matrix for "from" end of constrained branches
251
+ @param Yt: admittance matrix for "to" end of constrained branches
252
+ @param ppopt: PYPOWER options vector
253
+ @param il: (optional) vector of branch indices corresponding to
254
+ branches with flow limits (all others are assumed to be
255
+ unconstrained). The default is C{range(nl)} (all branches).
256
+ C{Yf} and C{Yt} contain only the rows corresponding to C{il}.
257
+
258
+ @return: C{h} - vector of inequality constraint values (flow limits)
259
+ limit^2 - flow^2, where the flow can be apparent power real power or
260
+ current, depending on value of C{OPF_FLOW_LIM} in C{ppopt} (only for
261
+ constrained lines). C{g} - vector of equality constraint values (power
262
+ balances). C{dh} - (optional) inequality constraint gradients, column
263
+ j is gradient of h(j). C{dg} - (optional) equality constraint gradients.
264
+
265
+ @see: L{opf_costfcn}, L{opf_hessfcn}
266
+
267
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
268
+ Autonoma de Manizales)
269
+ @author: Ray Zimmerman (PSERC Cornell)
270
+ """
271
+ # ----- initialize -----
272
+
273
+ # unpack data
274
+ ppc = om.get_ppc()
275
+ baseMVA, bus, gen, branch = \
276
+ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]
277
+ vv, _, _, _ = om.get_idx()
278
+
279
+ # problem dimensions
280
+ nb = bus.shape[0] # number of buses
281
+ nl = branch.shape[0] # number of branches
282
+ ng = gen.shape[0] # number of dispatchable injections
283
+ nxyz = len(x) # total number of control vars of all types
284
+
285
+ # set default constrained lines
286
+ if il is None:
287
+ il = np.arange(nl) # all lines have limits by default
288
+ nl2 = len(il) # number of constrained lines
289
+
290
+ # grab Pg & Qg
291
+ Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]] # active generation in p.u.
292
+ Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]] # reactive generation in p.u.
293
+
294
+ # put Pg & Qg back in gen
295
+ gen[:, IDX.gen.PG] = Pg * baseMVA # active generation in MW
296
+ gen[:, IDX.gen.QG] = Qg * baseMVA # reactive generation in MVAr
297
+
298
+ # rebuild Sbus
299
+ Sbus = makeSbus(baseMVA, bus, gen) # net injected power in p.u.
300
+
301
+ # ----- evaluate constraints -----
302
+ # reconstruct V
303
+ Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
304
+ Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
305
+ V = Vm * np.exp(1j * Va)
306
+
307
+ # evaluate power flow equations
308
+ mis = V * np.conj(Ybus * V) - Sbus
309
+
310
+ # ----- evaluate constraint function values -----
311
+ # first, the equality constraints (power flow)
312
+ g = np.r_[mis.real, # active power mismatch for all buses
313
+ mis.imag] # reactive power mismatch for all buses
314
+
315
+ # then, the inequality constraints (branch flow limits)
316
+ if nl2 > 0:
317
+ flow_max = (branch[il, IDX.branch.RATE_A] / baseMVA)**2
318
+ flow_max[flow_max == 0] = inf
319
+ if ppopt['OPF_FLOW_LIM'] == 2: # current magnitude limit, |I|
320
+ If = Yf * V
321
+ It = Yt * V
322
+ h = np.r_[If * np.conj(If) - flow_max, # branch I limits (from bus)
323
+ It * np.conj(It) - flow_max].real # branch I limits (to bus)
324
+ else:
325
+ # compute branch power flows
326
+ # complex power injected at "from" bus (p.u.)
327
+ Sf = V[branch[il, IDX.branch.F_BUS].astype(int)] * np.conj(Yf * V)
328
+ # complex power injected at "to" bus (p.u.)
329
+ St = V[branch[il, IDX.branch.F_BUS].astype(int)] * np.conj(Yt * V)
330
+ if ppopt['OPF_FLOW_LIM'] == 1: # active power limit, P (Pan Wei)
331
+ h = np.r_[Sf.real**2 - flow_max, # branch P limits (from bus)
332
+ St.real**2 - flow_max] # branch P limits (to bus)
333
+ else: # apparent power limit, |S|
334
+ h = np.r_[Sf * np.conj(Sf) - flow_max, # branch S limits (from bus)
335
+ St * np.conj(St) - flow_max].real # branch S limits (to bus)
336
+ else:
337
+ h = np.zeros((0, 1))
338
+
339
+ # ----- evaluate partials of constraints -----
340
+ # index ranges
341
+ iVa = np.arange(vv["i1"]["Va"], vv["iN"]["Va"])
342
+ iVm = np.arange(vv["i1"]["Vm"], vv["iN"]["Vm"])
343
+ iPg = np.arange(vv["i1"]["Pg"], vv["iN"]["Pg"])
344
+ iQg = np.arange(vv["i1"]["Qg"], vv["iN"]["Qg"])
345
+ iVaVmPgQg = np.r_[iVa, iVm, iPg, iQg].T
346
+
347
+ # compute partials of injected bus powers
348
+ dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V) # w.r.t. V
349
+ # Pbus w.r.t. Pg, Qbus w.r.t. Qg
350
+ neg_Cg = c_sparse((-np.ones(ng), (gen[:, IDX.gen.GEN_BUS], range(ng))), (nb, ng))
351
+
352
+ # construct Jacobian of equality constraints (power flow) and transpose it
353
+ dg = l_sparse((2 * nb, nxyz))
354
+ blank = c_sparse((nb, ng))
355
+ dg[:, iVaVmPgQg] = sp.vstack([
356
+ # P mismatch w.r.t Va, Vm, Pg, Qg
357
+ sp.hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
358
+ # Q mismatch w.r.t Va, Vm, Pg, Qg
359
+ sp.hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
360
+ ], "csr")
361
+ dg = dg.T
362
+
363
+ if nl2 > 0:
364
+ # compute partials of Flows w.r.t. V
365
+ if ppopt['OPF_FLOW_LIM'] == 2: # current
366
+ dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
367
+ dIbr_dV(branch[il, :], Yf, Yt, V)
368
+ else: # power
369
+ dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
370
+ dSbr_dV(branch[il, :], Yf, Yt, V)
371
+ if ppopt['OPF_FLOW_LIM'] == 1: # real part of flow (active power)
372
+ dFf_dVa = dFf_dVa.real
373
+ dFf_dVm = dFf_dVm.real
374
+ dFt_dVa = dFt_dVa.real
375
+ dFt_dVm = dFt_dVm.real
376
+ Ff = Ff.real
377
+ Ft = Ft.real
378
+
379
+ # squared magnitude of flow (of complex power or current, or real power)
380
+ df_dVa, df_dVm, dt_dVa, dt_dVm = \
381
+ dAbr_dV(dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft)
382
+
383
+ # construct Jacobian of inequality constraints (branch limits)
384
+ # and transpose it.
385
+ dh = l_sparse((2 * nl2, nxyz))
386
+ dh[:, np.r_[iVa, iVm].T] = sp.vstack([
387
+ sp.hstack([df_dVa, df_dVm]), # "from" flow limit
388
+ sp.hstack([dt_dVa, dt_dVm]) # "to" flow limit
389
+ ], "csr")
390
+ dh = dh.T
391
+ else:
392
+ dh = None
393
+
394
+ return h, g, dh, dg
395
+
396
+
397
+ def opf_costfcn(x, om, return_hessian=False):
398
+ """
399
+ Evaluates objective function, gradient and Hessian for OPF.
400
+
401
+ Objective function evaluation routine for AC optimal power flow,
402
+ suitable for use with L{pips}. Computes objective function value,
403
+ gradient and Hessian.
404
+
405
+ @param x: optimization vector
406
+ @param om: OPF model object
407
+
408
+ @return: C{F} - value of objective function. C{df} - (optional) gradient
409
+ of objective function (column vector). C{d2f} - (optional) Hessian of
410
+ objective function (sparse matrix).
411
+
412
+ @see: L{opf_consfcn}, L{opf_hessfcn}
413
+
414
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
415
+ Autonoma de Manizales)
416
+ @author: Ray Zimmerman (PSERC Cornell)
417
+ """
418
+ # ----- initialize -----
419
+ # unpack data
420
+ ppc = om.get_ppc()
421
+ baseMVA, gen, gencost = ppc["baseMVA"], ppc["gen"], ppc["gencost"]
422
+ cp = om.get_cost_params()
423
+ N, Cw, H, dd, rh, kk, mm = \
424
+ cp["N"], cp["Cw"], cp["H"], cp["dd"], cp["rh"], cp["kk"], cp["mm"]
425
+ vv, _, _, _ = om.get_idx()
426
+
427
+ # problem dimensions
428
+ ng = gen.shape[0] # number of dispatchable injections
429
+ ny = om.getN('var', 'y') # number of piece-wise linear costs
430
+ nxyz = len(x) # total number of control vars of all types
431
+
432
+ # grab Pg & Qg
433
+ Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]] # active generation in p.u.
434
+ Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]] # reactive generation in p.u.
435
+
436
+ # ----- evaluate objective function -----
437
+ # polynomial cost of P and Q
438
+ # use totcost only on polynomial cost in the minimization problem
439
+ # formulation, pwl cost is the sum of the y variables.
440
+ ipol = find(gencost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL) # poly MW and MVAr costs
441
+ xx = np.r_[Pg, Qg] * baseMVA
442
+ if any(ipol):
443
+ f = sum(totcost(gencost[ipol, :], xx[ipol])) # cost of poly P or Q
444
+ else:
445
+ f = 0
446
+
447
+ # piecewise linear cost of P and Q
448
+ if ny > 0:
449
+ ccost = c_sparse((np.ones(ny),
450
+ (np.zeros(ny), np.arange(vv["i1"]["y"], vv["iN"]["y"]))),
451
+ (1, nxyz)).toarray().flatten()
452
+ f = f + np.dot(ccost, x)
453
+ else:
454
+ ccost = np.zeros(nxyz)
455
+
456
+ # generalized cost term
457
+ if sp.issparse(N) and N.nnz > 0:
458
+ nw = N.shape[0]
459
+ r = N * x - rh # Nx - rhat
460
+ iLT = find(r < -kk) # below dead zone
461
+ iEQ = find((r == 0) & (kk == 0)) # dead zone doesn't exist
462
+ iGT = find(r > kk) # above dead zone
463
+ iND = np.r_[iLT, iEQ, iGT] # rows that are Not in the Dead region
464
+ iL = find(dd == 1) # rows using linear function
465
+ iQ = find(dd == 2) # rows using quadratic function
466
+ LL = c_sparse((np.ones(len(iL)), (iL, iL)), (nw, nw))
467
+ QQ = c_sparse((np.ones(len(iQ)), (iQ, iQ)), (nw, nw))
468
+ kbar = c_sparse((np.r_[np.ones(len(iLT)), np.zeros(len(iEQ)), -np.ones(len(iGT))],
469
+ (iND, iND)), (nw, nw)) * kk
470
+ rr = r + kbar # apply non-dead zone shift
471
+ M = c_sparse((mm[iND], (iND, iND)), (nw, nw)) # dead zone or scale
472
+ diagrr = c_sparse((rr, (np.arange(nw), np.arange(nw))), (nw, nw))
473
+
474
+ # linear rows multiplied by rr(i), quadratic rows by rr(i)^2
475
+ w = M * (LL + QQ * diagrr) * rr
476
+
477
+ f = f + np.dot(w * H, w) / 2 + np.dot(Cw, w)
478
+
479
+ # ----- evaluate cost gradient -----
480
+ # index ranges
481
+ iPg = range(vv["i1"]["Pg"], vv["iN"]["Pg"])
482
+ iQg = range(vv["i1"]["Qg"], vv["iN"]["Qg"])
483
+
484
+ # polynomial cost of P and Q
485
+ df_dPgQg = np.zeros(2 * ng) # w.r.t p.u. Pg and Qg
486
+ df_dPgQg[ipol] = baseMVA * polycost(gencost[ipol, :], xx[ipol], 1)
487
+ df = np.zeros(nxyz)
488
+ df[iPg] = df_dPgQg[:ng]
489
+ df[iQg] = df_dPgQg[ng:ng + ng]
490
+
491
+ # piecewise linear cost of P and Q
492
+ df = df + ccost # The linear cost row is additive wrt any nonlinear cost.
493
+
494
+ # generalized cost term
495
+ if sp.issparse(N) and N.nnz > 0:
496
+ HwC = H * w + Cw
497
+ AA = N.T * M * (LL + 2 * QQ * diagrr)
498
+ df = df + AA * HwC
499
+
500
+ # numerical check
501
+ if 0: # 1 to check, 0 to skip check
502
+ ddff = np.zeros(df.shape)
503
+ step = 1e-7
504
+ tol = 1e-3
505
+ for k in range(len(x)):
506
+ xx = x
507
+ xx[k] = xx[k] + step
508
+ ddff[k] = (opf_costfcn(xx, om) - f) / step
509
+ if max(abs(ddff - df)) > tol:
510
+ idx = find(abs(ddff - df) == max(abs(ddff - df)))
511
+ print('Mismatch in gradient')
512
+ print('idx df(num) df diff')
513
+ print('%4d%16g%16g%16g' %
514
+ (range(len(df)), ddff.T, df.T, abs(ddff - df).T))
515
+ print('MAX')
516
+ print('%4d%16g%16g%16g' %
517
+ (idx.T, ddff[idx].T, df[idx].T,
518
+ abs(ddff[idx] - df[idx]).T))
519
+
520
+ if not return_hessian:
521
+ return f, df
522
+
523
+ # ---- evaluate cost Hessian -----
524
+ pcost = gencost[range(ng), :]
525
+ if gencost.shape[0] > ng:
526
+ qcost = gencost[ng + 1:2 * ng, :]
527
+ else:
528
+ qcost = np.array([])
529
+
530
+ # polynomial generator costs
531
+ d2f_dPg2 = np.zeros(ng) # w.r.t. p.u. Pg
532
+ d2f_dQg2 = np.zeros(ng) # w.r.t. p.u. Qg
533
+ ipolp = find(pcost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
534
+ d2f_dPg2[ipolp] = \
535
+ baseMVA**2 * polycost(pcost[ipolp, :], Pg[ipolp]*baseMVA, 2)
536
+ if any(qcost): # Qg is not free
537
+ ipolq = find(qcost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
538
+ d2f_dQg2[ipolq] = \
539
+ baseMVA**2 * polycost(qcost[ipolq, :], Qg[ipolq] * baseMVA, 2)
540
+ i = np.r_[iPg, iQg].T
541
+ d2f = c_sparse((np.r_[d2f_dPg2, d2f_dQg2], (i, i)), (nxyz, nxyz))
542
+
543
+ # generalized cost
544
+ if N is not None and sp.issparse(N):
545
+ d2f = d2f + AA * H * AA.T + 2 * N.T * M * QQ * \
546
+ c_sparse((HwC, (range(nw), range(nw))), (nw, nw)) * N
547
+
548
+ return f, df, d2f
549
+
550
+
551
+ def run_userfcn(userfcn, stage, *args2):
552
+ """
553
+ Runs the userfcn callbacks for a given stage.
554
+
555
+ Example::
556
+ ppc = om.get_mpc()
557
+ om = run_userfcn(ppc['userfcn'], 'formulation', om)
558
+
559
+ @param userfcn: the 'userfcn' field of ppc, populated by L{add_userfcn}
560
+ @param stage: the name of the callback stage begin executed
561
+ (additional arguments) some stages require additional arguments.
562
+
563
+ @see: L{add_userfcn}, L{remove_userfcn}, L{toggle_reserves},
564
+ L{toggle_iflims}, L{runopf_w_res}.
565
+
566
+ @author: Ray Zimmerman (PSERC Cornell)
567
+ """
568
+ rv = args2[0]
569
+ if (len(userfcn) > 0) and (stage in userfcn):
570
+ for k in range(len(userfcn[stage])):
571
+ if 'args' in userfcn[stage][k]:
572
+ args = userfcn[stage][k]['args']
573
+ else:
574
+ args = []
575
+
576
+ if stage in ['ext2int', 'formulation', 'int2ext']:
577
+ # ppc = userfcn_*_ext2int(ppc, args)
578
+ # om = userfcn_*_formulation(om, args)
579
+ # results = userfcn_*_int2ext(results, args)
580
+ rv = userfcn[stage][k]['fcn'](rv, args)
581
+ elif stage in ['printpf', 'savecase']:
582
+ # results = userfcn_*_printpf(results, fd, ppopt, args)
583
+ # ppc = userfcn_*_savecase(mpc, fd, prefix, args)
584
+ fdprint = args2[1]
585
+ ppoptprint = args2[2]
586
+ rv = userfcn[stage][k]['fcn'](rv, fdprint, ppoptprint, args)
587
+
588
+ return rv
589
+
590
+
591
+ def add_userfcn(ppc, stage, fcn, args=None, allow_multiple=False):
592
+ """
593
+ Appends a userfcn to the list to be called for a case.
594
+
595
+ A userfcn is a callback function that can be called automatically by
596
+ PYPOWER at one of various stages in a simulation.
597
+
598
+ Currently there are 5 different callback stages defined. Each stage has
599
+ a name, and by convention, the name of a user-defined callback function
600
+ ends with the name of the stage. The following is a description of each
601
+ stage, when it is called and the input and output arguments which vary
602
+ depending on the stage. The reserves example (see L{runopf_w_res}) is used
603
+ to illustrate how these callback userfcns might be used.
604
+
605
+ 1. C{'ext2int'}
606
+
607
+ Called from L{ext2int} immediately after the case is converted from
608
+ external to internal indexing. Inputs are a PYPOWER case dict (C{ppc}),
609
+ freshly converted to internal indexing and any (optional) C{args} value
610
+ supplied via L{add_userfcn}. Output is the (presumably updated) C{ppc}.
611
+ This is typically used to reorder any input arguments that may be needed
612
+ in internal ordering by the formulation stage.
613
+
614
+ E.g. C{ppc = userfcn_reserves_ext2int(ppc, args)}
615
+
616
+ 2. C{'formulation'}
617
+
618
+ Called from L{opf} after the OPF Model (C{om}) object has been
619
+ initialized with the standard OPF formulation, but before calling the
620
+ solver. Inputs are the C{om} object and any (optional) C{args} supplied
621
+ via L{add_userfcn}. Output is the C{om} object. This is the ideal place
622
+ to add any additional vars, constraints or costs to the OPF formulation.
623
+
624
+ E.g. C{om = userfcn_reserves_formulation(om, args)}
625
+
626
+ 3. C{'int2ext'}
627
+
628
+ Called from L{int2ext} immediately before the resulting case is converted
629
+ from internal back to external indexing. Inputs are the C{results} dict
630
+ and any (optional) C{args} supplied via C{add_userfcn}. Output is the
631
+ C{results} dict. This is typically used to convert any results to
632
+ external indexing and populate any corresponding fields in the
633
+ C{results} dict.
634
+
635
+ E.g. C{results = userfcn_reserves_int2ext(results, args)}
636
+
637
+ 4. C{'printpf'}
638
+
639
+ Called from L{printpf} after the pretty-printing of the standard OPF
640
+ output. Inputs are the C{results} dict, the file descriptor to write to,
641
+ a PYPOWER options dict, and any (optional) C{args} supplied via
642
+ L{add_userfcn}. Output is the C{results} dict. This is typically used for
643
+ any additional pretty-printing of results.
644
+
645
+ E.g. C{results = userfcn_reserves_printpf(results, fd, ppopt, args)}
646
+
647
+ 5. C{'savecase'}
648
+
649
+ Called from L{savecase} when saving a case dict to a Python file after
650
+ printing all of the other data to the file. Inputs are the case dict,
651
+ the file descriptor to write to, the variable prefix (typically 'ppc')
652
+ and any (optional) C{args} supplied via L{add_userfcn}. Output is the
653
+ case dict. This is typically used to write any non-standard case dict
654
+ fields to the case file.
655
+
656
+ E.g. C{ppc = userfcn_reserves_printpf(ppc, fd, prefix, args)}
657
+
658
+ @param ppc: the case dict
659
+ @param stage: the name of the stage at which this function should be
660
+ called: ext2int, formulation, int2ext, printpf
661
+ @param fcn: the name of the userfcn
662
+ @param args: (optional) the value to be passed as an argument to the
663
+ userfcn
664
+ @param allow_multiple: (optional) if True, allows the same function to
665
+ be added more than once.
666
+
667
+ @see: L{run_userfcn}, L{remove_userfcn}, L{toggle_reserves},
668
+ L{toggle_iflims}, L{runopf_w_res}.
669
+
670
+ @author: Ray Zimmerman (PSERC Cornell)
671
+ """
672
+ if args is None:
673
+ args = []
674
+
675
+ if stage not in ['ext2int', 'formulation', 'int2ext', 'printpf', 'savecase']:
676
+ logger.debug('add_userfcn : \'%s\' is not the name of a valid callback stage\n' % stage)
677
+
678
+ n = 0
679
+ if 'userfcn' in ppc:
680
+ if stage in ppc['userfcn']:
681
+ n = len(ppc['userfcn'][stage]) # + 1
682
+ if not allow_multiple:
683
+ for k in range(n):
684
+ if ppc['userfcn'][stage][k]['fcn'] == fcn:
685
+ logger.debug('add_userfcn: the function \'%s\' has already been added\n' % fcn.__name__)
686
+ else:
687
+ ppc['userfcn'][stage] = []
688
+ else:
689
+ ppc['userfcn'] = {stage: []}
690
+
691
+ ppc['userfcn'][stage].append({'fcn': fcn})
692
+ if len(args) > 0:
693
+ ppc['userfcn'][stage][n]['args'] = args
694
+
695
+ return ppc
696
+
697
+
698
+ def remove_userfcn(ppc, stage, fcn):
699
+ """
700
+ Removes a userfcn from the list to be called for a case.
701
+
702
+ A userfcn is a callback function that can be called automatically by
703
+ PYPOWER at one of various stages in a simulation. This function removes
704
+ the last instance of the userfcn for the given C{stage} with the function
705
+ handle specified by C{fcn}.
706
+
707
+ @see: L{add_userfcn}, L{run_userfcn}, L{toggle_reserves},
708
+ L{toggle_iflims}, L{runopf_w_res}
709
+
710
+ @author: Ray Zimmerman (PSERC Cornell)
711
+ """
712
+ n = len(ppc['userfcn'][stage])
713
+
714
+ for k in range(n - 1, -1, -1):
715
+ if ppc['userfcn'][stage][k]['fcn'] == fcn:
716
+ del ppc['userfcn'][stage][k]
717
+ break
718
+
719
+ return ppc
720
+
721
+
722
+ def totcost(gencost, Pg):
723
+ """
724
+ Computes total cost for generators at given output level.
725
+
726
+ Computes total cost for generators given a matrix in gencost format and
727
+ a column vector or matrix of generation levels. The return value has the
728
+ same dimensions as PG. Each row of C{gencost} is used to evaluate the
729
+ cost at the points specified in the corresponding row of C{Pg}.
730
+
731
+ @author: Ray Zimmerman (PSERC Cornell)
732
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
733
+ Autonoma de Manizales)
734
+ """
735
+ ng, m = gencost.shape
736
+ totalcost = np.zeros(ng)
737
+
738
+ if len(gencost) > 0:
739
+ ipwl = find(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR)
740
+ ipol = find(gencost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
741
+ if len(ipwl) > 0:
742
+ p = gencost[:, IDX.cost.COST:(m-1):2]
743
+ c = gencost[:, (IDX.cost.COST+1):m:2]
744
+
745
+ for i in ipwl:
746
+ ncost = gencost[i, IDX.cost.NCOST]
747
+ for k in np.arange(ncost - 1, dtype=int):
748
+ p1, p2 = p[i, k], p[i, k+1]
749
+ c1, c2 = c[i, k], c[i, k+1]
750
+ m = (c2 - c1) / (p2 - p1)
751
+ b = c1 - m * p1
752
+ Pgen = Pg[i]
753
+ if Pgen < p2:
754
+ totalcost[i] = m * Pgen + b
755
+ break
756
+ totalcost[i] = m * Pgen + b
757
+
758
+ if len(ipol) > 0:
759
+ totalcost[ipol] = polycost(gencost[ipol, :], Pg[ipol])
760
+
761
+ return totalcost
762
+
763
+
764
+ def modcost(gencost, alpha, modtype='SCALE_F'):
765
+ """Modifies generator costs by shifting or scaling (F or X).
766
+
767
+ For each generator cost F(X) (for real or reactive power) in
768
+ C{gencost}, this function modifies the cost by scaling or shifting
769
+ the function by C{alpha}, depending on the value of C{modtype}, and
770
+ and returns the modified C{gencost}. Rows of C{gencost} can be a mix
771
+ of polynomial or piecewise linear costs.
772
+
773
+ C{modtype} takes one of the 4 possible values (let F_alpha(X) denote the
774
+ the modified function)::
775
+ SCALE_F (default) : F_alpha(X) == F(X) * ALPHA
776
+ SCALE_X : F_alpha(X * ALPHA) == F(X)
777
+ SHIFT_F : F_alpha(X) == F(X) + ALPHA
778
+ SHIFT_X : F_alpha(X + ALPHA) == F(X)
779
+
780
+ @author: Ray Zimmerman (PSERC Cornell)
781
+ """
782
+ gencost = gencost.copy()
783
+
784
+ ng, m = gencost.shape
785
+ if ng != 0:
786
+ ipwl = find(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR)
787
+ ipol = find(gencost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL)
788
+ c = gencost[ipol, IDX.cost.COST:m]
789
+
790
+ if modtype == 'SCALE_F':
791
+ gencost[ipol, IDX.cost.COST:m] = alpha * c
792
+ gencost[ipwl, IDX.cost.COST+1:m:2] = alpha * gencost[ipwl, IDX.cost.COST + 1:m:2]
793
+ elif modtype == 'SCALE_X':
794
+ for k in range(len(ipol)):
795
+ n = gencost[ipol[k], IDX.cost.NCOST].astype(int)
796
+ for i in range(n):
797
+ gencost[ipol[k], IDX.cost.COST + i] = c[k, i] / alpha**(n - i - 1)
798
+ gencost[ipwl, IDX.cost.COST:m - 1:2] = alpha * gencost[ipwl, IDX.cost.COST:m - 1:2]
799
+ elif modtype == 'SHIFT_F':
800
+ for k in range(len(ipol)):
801
+ n = gencost[ipol[k], IDX.cost.NCOST].astype(int)
802
+ gencost[ipol[k], IDX.cost.COST + n - 1] = alpha + c[k, n - 1]
803
+ gencost[ipwl, IDX.cost.COST+1:m:2] = alpha + gencost[ipwl, IDX.cost.COST + 1:m:2]
804
+ elif modtype == 'SHIFT_X':
805
+ for k in range(len(ipol)):
806
+ n = gencost[ipol[k], IDX.cost.NCOST].astype(int)
807
+ gencost[ipol[k], IDX.cost.COST:IDX.cost.COST + n] = \
808
+ polyshift(c[k, :n].T, alpha).T
809
+ gencost[ipwl, IDX.cost.COST:m - 1:2] = alpha + gencost[ipwl, IDX.cost.COST:m - 1:2]
810
+ else:
811
+ logger.debug('modcost: "%s" is not a valid modtype\n' % modtype)
812
+
813
+ return gencost
814
+
815
+
816
+ def polyshift(c, a):
817
+ """
818
+ Returns the coefficients of a horizontally shifted polynomial.
819
+
820
+ C{d = polyshift(c, a)} shifts to the right by C{a}, the polynomial whose
821
+ coefficients are given in the column vector C{c}.
822
+
823
+ Example: For any polynomial with C{n} coefficients in C{c}, and any values
824
+ for C{x} and shift C{a}, the C{f - f0} should be zero::
825
+ x = rand
826
+ a = rand
827
+ c = rand(n, 1);
828
+ f0 = polyval(c, x)
829
+ f = polyval(polyshift(c, a), x+a)
830
+ """
831
+ n = len(c)
832
+ d = np.zeros(c.shape)
833
+ A = pow(-a * np.ones(n), np.arange(n))
834
+ b = np.ones(n)
835
+ for k in range(n):
836
+ d[n - k - 1] = np.dot(b, c[n - k - 1::-1] * A[:n - k])
837
+ b = np.cumsum(b[:n - k - 1])
838
+
839
+ return d
840
+
841
+
842
+ def polycost(gencost, Pg, der=0):
843
+ """
844
+ Evaluates polynomial generator cost & derivatives.
845
+
846
+ C{f = polycost(gencost, Pg)} returns the vector of costs evaluated at C{Pg}
847
+
848
+ C{df = polycost(gencost, Pg, 1)} returns the vector of first derivatives
849
+ of costs evaluated at C{Pg}
850
+
851
+ C{d2f = polycost(gencost, Pg, 2)} returns the vector of second derivatives
852
+ of costs evaluated at C{Pg}
853
+
854
+ C{gencost} must contain only polynomial costs
855
+ C{Pg} is in MW, not p.u. (works for C{Qg} too)
856
+
857
+ @author: Ray Zimmerman (PSERC Cornell)
858
+ """
859
+ if gencost.size == 0:
860
+ # User has a purely linear piecewise problem, exit early with empty array
861
+ return []
862
+
863
+ if any(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR):
864
+ logger.debug('polycost: all costs must be polynomial\n')
865
+
866
+ ng = len(Pg)
867
+ maxN = max(gencost[:, IDX.cost.NCOST].astype(int))
868
+ minN = min(gencost[:, IDX.cost.NCOST].astype(int))
869
+
870
+ # form coefficient matrix where 1st column is constant term, 2nd linear, etc.
871
+ c = np.zeros((ng, maxN))
872
+ for n in np.arange(minN, maxN + 1):
873
+ k = find(gencost[:, IDX.cost.NCOST] == n) # cost with n coefficients
874
+ c[k, :n] = gencost[k, (IDX.cost.COST + n - 1):IDX.cost.COST - 1:-1]
875
+
876
+ # do derivatives
877
+ for d in range(1, der + 1):
878
+ if c.shape[1] >= 2:
879
+ c = c[:, 1:maxN - d + 1]
880
+ else:
881
+ c = np.zeros((ng, 1))
882
+ break
883
+
884
+ for k in range(2, maxN - d + 1):
885
+ c[:, k-1] = c[:, k-1] * k
886
+
887
+ # evaluate polynomial
888
+ if len(c) == 0:
889
+ f = np.zeros(Pg.shape)
890
+ else:
891
+ f = c[:, :1].flatten() # constant term
892
+ for k in range(1, c.shape[1]):
893
+ f = f + c[:, k] * Pg**k
894
+
895
+ return f
896
+
897
+
898
+ def pqcost(gencost, ng, on=None):
899
+ """
900
+ Splits the gencost variable into two pieces if costs are given for Qg.
901
+
902
+ Checks whether C{gencost} has cost information for reactive power
903
+ generation (rows C{ng+1} to C{2*ng}). If so, it returns the first C{ng}
904
+ rows in C{pcost} and the last C{ng} rows in C{qcost}. Otherwise, leaves
905
+ C{qcost} empty. Also does some error checking.
906
+ If C{on} is specified (list of indices of generators which are on line)
907
+ it only returns the rows corresponding to these generators.
908
+
909
+ @author: Ray Zimmerman (PSERC Cornell)
910
+ """
911
+ if on is None:
912
+ on = np.arange(ng)
913
+
914
+ if gencost.shape[0] == ng:
915
+ pcost = gencost[on, :]
916
+ qcost = np.array([])
917
+ elif gencost.shape[0] == 2 * ng:
918
+ pcost = gencost[on, :]
919
+ qcost = gencost[on + ng, :]
920
+ else:
921
+ logger.info('pqcost: gencost has wrong number of rows')
922
+
923
+ return pcost, qcost
924
+
925
+
926
+ def poly2pwl(polycost, Pmin, Pmax, npts):
927
+ """
928
+ Converts polynomial cost variable to piecewise linear.
929
+
930
+ Converts the polynomial cost variable C{polycost} into a piece-wise linear
931
+ cost by evaluating at zero and then at C{npts} evenly spaced points between
932
+ C{Pmin} and C{Pmax}. If C{Pmin <= 0} (such as for reactive power, where
933
+ C{P} really means C{Q}) it just uses C{npts} evenly spaced points between
934
+ C{Pmin} and C{Pmax}.
935
+ """
936
+ pwlcost = polycost
937
+ # size of piece being changed
938
+ m, n = polycost.shape
939
+ # change cost model
940
+ pwlcost[:, IDX.cost.MODEL] = IDX.cost.PW_LINEAR * np.ones(m)
941
+ # zero out old data
942
+ pwlcost[:, IDX.cost.COST:IDX.cost.COST + n] = np.zeros(pwlcost[:, IDX.cost.COST:IDX.cost.COST + n].shape)
943
+ # change number of data points
944
+ pwlcost[:, IDX.cost.NCOST] = npts * IDX.cost.ones(m)
945
+
946
+ for i in range(m):
947
+ if Pmin[i] == 0:
948
+ step = (Pmax[i] - Pmin[i]) / (npts - 1)
949
+ xx = range(Pmin[i], step, Pmax[i])
950
+ elif Pmin[i] > 0:
951
+ step = (Pmax[i] - Pmin[i]) / (npts - 2)
952
+ xx = r_[0, range(Pmin[i], step, Pmax[i])]
953
+ elif Pmin[i] < 0 & Pmax[i] > 0: # for when P really means Q
954
+ step = (Pmax[i] - Pmin[i]) / (npts - 1)
955
+ xx = range(Pmin[i], step, Pmax[i])
956
+ yy = totcost(polycost[i, :], xx)
957
+ pwlcost[i, IDX.cost.COST:2:(IDX.cost.COST + 2*(npts-1))] = xx
958
+ pwlcost[i, (IDX.cost.COST+1):2:(IDX.cost.COST + 2*(npts-1) + 1)] = yy
959
+
960
+ return pwlcost
961
+
962
+
963
+ def scale_load(load, bus, gen=None, load_zone=None, opt=None):
964
+ """
965
+ Scales fixed and/or dispatchable loads.
966
+
967
+ Assumes consecutive bus numbering when dealing with dispatchable loads.
968
+
969
+ @param load: Each element specifies the amount of scaling for the
970
+ corresponding load zone, either as a direct scale factor
971
+ or as a target quantity. If there are C{nz} load zones this
972
+ vector has C{nz} elements.
973
+ @param bus: Standard C{bus} matrix with C{nb} rows, where the fixed active
974
+ and reactive loads available for scaling are specified in
975
+ columns C{PD} and C{QD}
976
+ @param gen: (optional) standard C{gen} matrix with C{ng} rows, where the
977
+ dispatchable loads available for scaling are specified by
978
+ columns C{PG}, C{QG}, C{PMIN}, C{QMIN} and C{QMAX} (in rows for which
979
+ C{isload(gen)} returns C{true}). If C{gen} is empty, it assumes
980
+ there are no dispatchable loads.
981
+ @param load_zone: (optional) C{nb} element vector where the value of
982
+ each element is either zero or the index of the load zone
983
+ to which the corresponding bus belongs. If C{load_zone[b] = k}
984
+ then the loads at bus C{b} will be scaled according to the
985
+ value of C{load[k]}. If C{load_zone[b] = 0}, the loads at bus C{b}
986
+ will not be modified. If C{load_zone} is empty, the default is
987
+ determined by the dimensions of the C{load} vector. If C{load} is
988
+ a scalar, a single system-wide zone including all buses is
989
+ used, i.e. C{load_zone = ones(nb)}. If C{load} is a vector, the
990
+ default C{load_zone} is defined as the areas specified in the
991
+ C{bus} matrix, i.e. C{load_zone = bus[:, BUS_AREA]}, and C{load}
992
+ should have dimension C{= max(bus[:, BUS_AREA])}.
993
+ @param opt: (optional) dict with three possible fields, 'scale',
994
+ 'pq' and 'which' that determine the behavior as follows:
995
+ - C{scale} (default is 'FACTOR')
996
+ - 'FACTOR' : C{load} consists of direct scale factors, where
997
+ C{load[k] =} scale factor C{R[k]} for zone C{k}
998
+ - 'QUANTITY' : C{load} consists of target quantities, where
999
+ C{load[k] =} desired total active load in MW for
1000
+ zone C{k} after scaling by an appropriate C{R(k)}
1001
+ - C{pq} (default is 'PQ')
1002
+ - 'PQ' : scale both active and reactive loads
1003
+ - 'P' : scale only active loads
1004
+ - C{which} (default is 'BOTH' if GEN is provided, else 'FIXED')
1005
+ - 'FIXED' : scale only fixed loads
1006
+ - 'DISPATCHABLE' : scale only dispatchable loads
1007
+ - 'BOTH' : scale both fixed and dispatchable loads
1008
+
1009
+ @see: L{total_load}
1010
+
1011
+ @author: Ray Zimmerman (PSERC Cornell)
1012
+ """
1013
+ nb = bus.shape[0] # number of buses
1014
+
1015
+ # ----- process inputs -----
1016
+ bus = bus.copy()
1017
+ if gen is None:
1018
+ gen = np.array([])
1019
+ else:
1020
+ gen = gen.copy()
1021
+ if load_zone is None:
1022
+ load_zone = np.array([], int)
1023
+ if opt is None:
1024
+ opt = {}
1025
+
1026
+ # fill out and check opt
1027
+ if len(gen) == 0:
1028
+ opt["which"] = 'FIXED'
1029
+ if 'pq' not in opt:
1030
+ opt["pq"] = 'PQ' # 'PQ' or 'P'
1031
+ if 'which' not in opt:
1032
+ opt["which"] = 'BOTH' # 'FIXED', 'DISPATCHABLE' or 'BOTH'
1033
+ if 'scale' not in opt:
1034
+ opt["scale"] = 'FACTOR' # 'FACTOR' or 'QUANTITY'
1035
+ if (opt["pq"] != 'P') and (opt["pq"] != 'PQ'):
1036
+ logger.debug("scale_load: opt['pq'] must equal 'PQ' or 'P'\n")
1037
+ if (opt["which"][0] != 'F') and (opt["which"][0] != 'D') and (opt["which"][0] != 'B'):
1038
+ logger.debug("scale_load: opt.which should be 'FIXED, 'DISPATCHABLE or 'BOTH'\n")
1039
+ if (opt["scale"][0] != 'F') and (opt["scale"][0] != 'Q'):
1040
+ logger.debug("scale_load: opt.scale should be 'FACTOR or 'QUANTITY'\n")
1041
+ if (len(gen) == 0) and (opt["which"][0] != 'F'):
1042
+ logger.debug('scale_load: need gen matrix to scale dispatchable loads\n')
1043
+
1044
+ # create dispatchable load connection matrix
1045
+ if len(gen) > 0:
1046
+ ng = gen.shape[0]
1047
+ is_ld = isload(gen) & (gen[:, IDX.gen.GEN_STATUS] > 0)
1048
+ ld = find(is_ld)
1049
+
1050
+ # create map of external bus numbers to bus indices
1051
+ i2e = bus[:, IDX.bus.BUS_I].astype(int)
1052
+ e2i = np.zeros(max(i2e) + 1, int)
1053
+ e2i[i2e] = np.arange(nb)
1054
+
1055
+ gbus = gen[:, IDX.gen.GEN_BUS].astype(int)
1056
+ Cld = c_sparse((is_ld, (e2i[gbus], np.arange(ng))), (nb, ng))
1057
+ else:
1058
+ ng = 0
1059
+ ld = np.array([], int)
1060
+
1061
+ if len(load_zone) == 0:
1062
+ if len(load) == 1: # make a single zone of all load buses
1063
+ load_zone = np.zeros(nb, int) # initialize
1064
+ load_zone[bus[:, IDX.bus.PD] != 0 or bus[:, IDX.bus.QD] != 0] = 1 # FIXED loads
1065
+ if len(gen) > 0:
1066
+ gbus = gen[ld, IDX.gen.GEN_BUS].astype(int)
1067
+ load_zone[e2i[gbus]] = 1 # DISPATCHABLE loads
1068
+ else: # use areas defined in bus data as zones
1069
+ load_zone = bus[:, IDX.bus.BUS_AREA]
1070
+
1071
+ # check load_zone to make sure it's consistent with size of load vector
1072
+ if max(load_zone) > len(load):
1073
+ logger.debug('scale_load: load vector must have a value for each load zone specified\n')
1074
+
1075
+ # ----- compute scale factors for each zone -----
1076
+ scale = load.copy()
1077
+ Pdd = np.zeros(nb) # dispatchable P at each bus
1078
+ if opt["scale"][0] == 'Q': # 'QUANTITY'
1079
+ # find load capacity from dispatchable loads
1080
+ if len(gen) > 0:
1081
+ Pdd = -Cld * gen[:, IDX.gen.PMIN]
1082
+
1083
+ # compute scale factors
1084
+ for k in range(len(load)):
1085
+ idx = find(load_zone == k + 1)
1086
+ fixed = sum(bus[idx, IDX.bus.PD])
1087
+ dispatchable = sum(Pdd[idx])
1088
+ total = fixed + dispatchable
1089
+ if opt["which"][0] == 'B': # 'BOTH'
1090
+ if total != 0:
1091
+ scale[k] = load[k] / total
1092
+ elif load[k] == total:
1093
+ scale[k] = 1
1094
+ else:
1095
+ raise ValueError(
1096
+ 'scale_load: impossible to make zone %d load equal %g by scaling non-existent loads' %
1097
+ (k, load[k]))
1098
+ elif opt["which"][0] == 'F': # 'FIXED'
1099
+ if fixed != 0:
1100
+ scale[k] = (load[k] - dispatchable) / fixed
1101
+ elif load[k] == dispatchable:
1102
+ scale[k] = 1
1103
+ else:
1104
+ raise ValueError(
1105
+ 'scale_load: impossible to make zone %d load equal %g by scaling non-existent fixed load' %
1106
+ (k, load[k]))
1107
+ elif opt["which"][0] == 'D': # 'DISPATCHABLE'
1108
+ if dispatchable != 0:
1109
+ scale[k] = (load[k] - fixed) / dispatchable
1110
+ elif load[k] == fixed:
1111
+ scale[k] = 1
1112
+ else:
1113
+ raise ValueError(
1114
+ 'scale_load: impossible to make zone %d load equal %g by scaling non-existent dispatchable load' % (k, load[k]))
1115
+
1116
+ # ----- do the scaling -----
1117
+ # fixed loads
1118
+ if opt["which"][0] != 'D': # includes 'FIXED', not 'DISPATCHABLE' only
1119
+ for k in range(len(scale)):
1120
+ idx = find(load_zone == k + 1)
1121
+ bus[idx, IDX.bus.PD] = bus[idx, IDX.bus.PD] * scale[k]
1122
+ if opt["pq"] == 'PQ':
1123
+ bus[idx, IDX.bus.QD] = bus[idx, IDX.bus.QD] * scale[k]
1124
+
1125
+ # dispatchable loads
1126
+ if opt["which"][0] != 'F': # includes 'DISPATCHABLE', not 'FIXED' only
1127
+ for k in range(len(scale)):
1128
+ idx = find(load_zone == k + 1)
1129
+ gbus = gen[ld, IDX.gen.GEN_BUS].astype(int)
1130
+ i = find(np.in1d(e2i[gbus], idx))
1131
+ ig = ld[i]
1132
+
1133
+ gen[np.ix_(ig, [IDX.gen.PG, IDX.gen.PMIN])] = gen[np.ix_(ig, [IDX.gen.PG, IDX.gen.PMIN])] * scale[k]
1134
+ if opt["pq"] == 'PQ':
1135
+ gen[np.ix_(ig, [IDX.gen.QG, IDX.gen.QMIN, IDX.gen.QMAX])] = gen[np.ix_(
1136
+ ig, [IDX.gen.QG, IDX.gen.QMIN, IDX.gen.QMAX])] * scale[k]
1137
+
1138
+ return bus, gen
1139
+
1140
+
1141
+ def update_mupq(baseMVA, gen, mu_PQh, mu_PQl, data):
1142
+ """
1143
+ Updates values of generator limit shadow prices.
1144
+
1145
+ Updates the values of C{MU_PMIN}, C{MU_PMAX}, C{MU_QMIN}, C{MU_QMAX} based
1146
+ on any shadow prices on the sloped portions of the generator
1147
+ capability curve constraints.
1148
+
1149
+ @param mu_PQh: shadow prices on upper sloped portion of capability curves
1150
+ @param mu_PQl: shadow prices on lower sloped portion of capability curves
1151
+ @param data: "data" dict returned by L{makeApq}
1152
+
1153
+ @see: C{makeApq}.
1154
+
1155
+ @author: Ray Zimmerman (PSERC Cornell)
1156
+ @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
1157
+ Autonoma de Manizales)
1158
+ """
1159
+ # extract the constraint parameters
1160
+ ipqh, ipql, Apqhdata, Apqldata = \
1161
+ data['ipqh'], data['ipql'], data['h'], data['l']
1162
+
1163
+ # combine original limit multipliers into single value
1164
+ muP = gen[:, IDX.gen.MU_PMAX] - gen[:, IDX.gen.MU_PMIN]
1165
+ muQ = gen[:, IDX.gen.MU_QMAX] - gen[:, IDX.gen.MU_QMIN]
1166
+
1167
+ # add P and Q components of multipliers on upper sloped constraint
1168
+ muP[ipqh] = muP[ipqh] - mu_PQh * Apqhdata[:, 0] / baseMVA
1169
+ muQ[ipqh] = muQ[ipqh] - mu_PQh * Apqhdata[:, 1] / baseMVA
1170
+
1171
+ # add P and Q components of multipliers on lower sloped constraint
1172
+ muP[ipql] = muP[ipql] - mu_PQl * Apqldata[:, 0] / baseMVA
1173
+ muQ[ipql] = muQ[ipql] - mu_PQl * Apqldata[:, 1] / baseMVA
1174
+
1175
+ # split back into upper and lower multipliers based on sign
1176
+ gen[:, IDX.gen.MU_PMAX] = (muP > 0) * muP
1177
+ gen[:, IDX.gen.MU_PMIN] = (muP < 0) * -muP
1178
+ gen[:, IDX.gen.MU_QMAX] = (muQ > 0) * muQ
1179
+ gen[:, IDX.gen.MU_QMIN] = (muQ < 0) * -muQ
1180
+
1181
+ return gen
1182
+
1183
+
1184
+ def int2ext(ppc, val_or_field=None, oldval=None, ordering=None, dim=0):
1185
+ """
1186
+ Converts internal to external bus numbering.
1187
+
1188
+ C{ppc = int2ext(ppc)}
1189
+
1190
+ If the input is a single PYPOWER case dict, then it restores all
1191
+ buses, generators and branches that were removed because of being
1192
+ isolated or off-line, and reverts to the original generator ordering
1193
+ and original bus numbering. This requires that the 'order' key
1194
+ created by L{ext2int} be in place.
1195
+
1196
+ Example::
1197
+ ppc = int2ext(ppc)
1198
+
1199
+ @see: L{ext2int}, L{i2e_field}, L{i2e_data}
1200
+
1201
+ @author: Ray Zimmerman (PSERC Cornell)
1202
+ """
1203
+ ppc = deepcopy(ppc)
1204
+ if val_or_field is None: # nargin == 1
1205
+ if 'order' not in ppc:
1206
+ logger.debug('int2ext: ppc does not have the "order" field '
1207
+ 'required for conversion back to external numbering.\n')
1208
+ o = ppc["order"]
1209
+
1210
+ if o["state"] == 'i':
1211
+ # execute userfcn callbacks for 'int2ext' stage
1212
+ if 'userfcn' in ppc:
1213
+ ppc = run_userfcn(ppc["userfcn"], 'int2ext', ppc)
1214
+
1215
+ # save data matrices with internal ordering & restore originals
1216
+ o["int"] = {}
1217
+ o["int"]["bus"] = ppc["bus"].copy()
1218
+ o["int"]["branch"] = ppc["branch"].copy()
1219
+ o["int"]["gen"] = ppc["gen"].copy()
1220
+ ppc["bus"] = o["ext"]["bus"].copy()
1221
+ ppc["branch"] = o["ext"]["branch"].copy()
1222
+ ppc["gen"] = o["ext"]["gen"].copy()
1223
+ if 'gencost' in ppc:
1224
+ o["int"]["gencost"] = ppc["gencost"].copy()
1225
+ ppc["gencost"] = o["ext"]["gencost"].copy()
1226
+ if 'areas' in ppc:
1227
+ o["int"]["areas"] = ppc["areas"].copy()
1228
+ ppc["areas"] = o["ext"]["areas"].copy()
1229
+ if 'A' in ppc:
1230
+ o["int"]["A"] = ppc["A"].copy()
1231
+ ppc["A"] = o["ext"]["A"].copy()
1232
+ if 'N' in ppc:
1233
+ o["int"]["N"] = ppc["N"].copy()
1234
+ ppc["N"] = o["ext"]["N"].copy()
1235
+
1236
+ # update data (in bus, branch and gen only)
1237
+ ppc["bus"][o["bus"]["status"]["on"], :] = \
1238
+ o["int"]["bus"]
1239
+ ppc["branch"][o["branch"]["status"]["on"], :] = \
1240
+ o["int"]["branch"]
1241
+ ppc["gen"][o["gen"]["status"]["on"], :] = \
1242
+ o["int"]["gen"][o["gen"]["i2e"], :]
1243
+ if 'areas' in ppc:
1244
+ ppc["areas"][o["areas"]["status"]["on"], :] = \
1245
+ o["int"]["areas"]
1246
+
1247
+ # revert to original bus numbers
1248
+ ppc["bus"][o["bus"]["status"]["on"], IDX.bus.BUS_I] = \
1249
+ o["bus"]["i2e"][ppc["bus"][o["bus"]["status"]["on"], IDX.bus.BUS_I].astype(int)]
1250
+ ppc["branch"][o["branch"]["status"]["on"], IDX.branch.F_BUS] = \
1251
+ o["bus"]["i2e"][ppc["branch"]
1252
+ [o["branch"]["status"]["on"], IDX.branch.F_BUS].astype(int)]
1253
+ ppc["branch"][o["branch"]["status"]["on"], IDX.branch.T_BUS] = \
1254
+ o["bus"]["i2e"][ppc["branch"]
1255
+ [o["branch"]["status"]["on"], IDX.branch.T_BUS].astype(int)]
1256
+ ppc["gen"][o["gen"]["status"]["on"], IDX.gen.GEN_BUS] = \
1257
+ o["bus"]["i2e"][ppc["gen"]
1258
+ [o["gen"]["status"]["on"], IDX.gen.GEN_BUS].astype(int)]
1259
+ if 'areas' in ppc:
1260
+ ppc["areas"][o["areas"]["status"]["on"], IDX.area.PRICE_REF_BUS] = \
1261
+ o["bus"]["i2e"][ppc["areas"]
1262
+ [o["areas"]["status"]["on"], IDX.area.PRICE_REF_BUS].astype(int)]
1263
+
1264
+ if 'ext' in o:
1265
+ del o['ext']
1266
+ o["state"] = 'e'
1267
+ ppc["order"] = o
1268
+ else:
1269
+ logger.debug('int2ext: ppc claims it is already using '
1270
+ 'external numbering.\n')
1271
+ else: # convert extra data
1272
+ if isinstance(val_or_field, str) or isinstance(val_or_field, list):
1273
+ # field (key)
1274
+ logger.warning(
1275
+ 'Calls of the form MPC = INT2EXT(MPC, '
1276
+ 'FIELD_NAME'
1277
+ ', ...) have been deprecated. Please replace INT2EXT with I2E_FIELD.')
1278
+ bus, gen = val_or_field, oldval
1279
+ if ordering is not None:
1280
+ dim = ordering
1281
+ ppc = i2e_field(ppc, bus, gen, dim)
1282
+ else:
1283
+ # value
1284
+ logger.warning(
1285
+ 'Calls of the form VAL = INT2EXT(MPC, VAL, ...) have been deprecated. Please replace INT2EXT with I2E_DATA.')
1286
+ bus, gen, branch = val_or_field, oldval, ordering
1287
+ ppc = i2e_data(ppc, bus, gen, branch, dim)
1288
+
1289
+ return ppc
1290
+
1291
+
1292
+ def int2ext1(i2e, bus, gen, branch, areas):
1293
+ """
1294
+ Converts from the consecutive internal bus numbers back to the originals
1295
+ using the mapping provided by the I2E vector returned from C{ext2int}.
1296
+
1297
+ @see: L{ext2int}
1298
+ @see: U{http://www.pserc.cornell.edu/matpower/}
1299
+ """
1300
+ bus[:, IDX.bus.BUS_I] = i2e[bus[:, IDX.bus.BUS_I].astype(int)]
1301
+ gen[:, IDX.gen.GEN_BUS] = i2e[gen[:, IDX.gen.GEN_BUS].astype(int)]
1302
+ branch[:, IDX.branch.F_BUS] = i2e[branch[:, IDX.branch.F_BUS].astype(int)]
1303
+ branch[:, IDX.branch.T_BUS] = i2e[branch[:, IDX.branch.T_BUS].astype(int)]
1304
+
1305
+ if areas != None and len(areas) > 0:
1306
+ areas[:, IDX.area.PRICE_REF_BUS] = i2e[areas[:, IDX.area.PRICE_REF_BUS].astype(int)]
1307
+ return bus, gen, branch, areas
1308
+
1309
+ return bus, gen, branch
1310
+
1311
+
1312
+ def e2i_data(ppc, val, ordering, dim=0):
1313
+ """
1314
+ Converts data from external to internal indexing.
1315
+
1316
+ When given a case dict that has already been converted to
1317
+ internal indexing, this function can be used to convert other data
1318
+ structures as well by passing in 2 or 3 extra parameters in
1319
+ addition to the case dict. If the value passed in the 2nd
1320
+ argument is a column vector, it will be converted according to the
1321
+ C{ordering} specified by the 3rd argument (described below). If C{val}
1322
+ is an n-dimensional matrix, then the optional 4th argument (C{dim},
1323
+ default = 0) can be used to specify which dimension to reorder.
1324
+ The return value in this case is the value passed in, converted
1325
+ to internal indexing.
1326
+
1327
+ The 3rd argument, C{ordering}, is used to indicate whether the data
1328
+ corresponds to bus-, gen- or branch-ordered data. It can be one
1329
+ of the following three strings: 'bus', 'gen' or 'branch'. For
1330
+ data structures with multiple blocks of data, ordered by bus,
1331
+ gen or branch, they can be converted with a single call by
1332
+ specifying C{ordering} as a list of strings.
1333
+
1334
+ Any extra elements, rows, columns, etc. beyond those indicated
1335
+ in C{ordering}, are not disturbed.
1336
+
1337
+ Examples:
1338
+ A_int = e2i_data(ppc, A_ext, ['bus','bus','gen','gen'], 1)
1339
+
1340
+ Converts an A matrix for user-supplied OPF constraints from
1341
+ external to internal ordering, where the columns of the A
1342
+ matrix correspond to bus voltage angles, then voltage
1343
+ magnitudes, then generator real power injections and finally
1344
+ generator reactive power injections.
1345
+
1346
+ gencost_int = e2i_data(ppc, gencost_ext, ['gen','gen'], 0)
1347
+
1348
+ Converts a GENCOST matrix that has both real and reactive power
1349
+ costs (in rows 1--ng and ng+1--2*ng, respectively).
1350
+ """
1351
+ if 'order' not in ppc:
1352
+ logger.debug('e2i_data: ppc does not have the \'order\' field '
1353
+ 'required to convert from external to internal numbering.\n')
1354
+ return
1355
+
1356
+ o = ppc['order']
1357
+ if o['state'] != 'i':
1358
+ logger.debug('e2i_data: ppc does not have internal ordering '
1359
+ 'data available, call ext2int first\n')
1360
+ return
1361
+
1362
+ if isinstance(ordering, str): # single set
1363
+ if ordering == 'gen':
1364
+ idx = o[ordering]["status"]["on"][o[ordering]["e2i"]]
1365
+ else:
1366
+ idx = o[ordering]["status"]["on"]
1367
+ val = get_reorder(val, idx, dim)
1368
+ else: # multiple: sets
1369
+ b = 0 # base
1370
+ new_v = []
1371
+ for ordr in ordering:
1372
+ n = o["ext"][ordr].shape[0]
1373
+ v = get_reorder(val, b + np.arange(n), dim)
1374
+ new_v.append(e2i_data(ppc, v, ordr, dim))
1375
+ b = b + n
1376
+ n = val.shape[dim]
1377
+ if n > b: # the rest
1378
+ v = get_reorder(val, np.arange(b, n), dim)
1379
+ new_v.append(v)
1380
+
1381
+ if sp.issparse(new_v[0]):
1382
+ if dim == 0:
1383
+ sp.vstack(new_v, 'csr')
1384
+ elif dim == 1:
1385
+ sp.hstack(new_v, 'csr')
1386
+ else:
1387
+ raise ValueError('dim (%d) may be 0 or 1' % dim)
1388
+ else:
1389
+ val = np.concatenate(new_v, dim)
1390
+ return val
1391
+
1392
+
1393
+ def e2i_field(ppc, field, ordering, dim=0):
1394
+ """
1395
+ Converts fields of C{ppc} from external to internal indexing.
1396
+
1397
+ This function performs several different tasks, depending on the
1398
+ arguments passed.
1399
+
1400
+ When given a case dict that has already been converted to
1401
+ internal indexing, this function can be used to convert other data
1402
+ structures as well by passing in 2 or 3 extra parameters in
1403
+ addition to the case dict.
1404
+
1405
+ The 2nd argument is a string or list of strings, specifying
1406
+ a field in the case dict whose value should be converted by
1407
+ a corresponding call to L{e2i_data}. In this case, the converted value
1408
+ is stored back in the specified field, the original value is
1409
+ saved for later use and the updated case dict is returned.
1410
+ If C{field} is a list of strings, they specify nested fields.
1411
+
1412
+ The 3rd and optional 4th arguments are simply passed along to
1413
+ the call to L{e2i_data}.
1414
+
1415
+ Examples:
1416
+ ppc = e2i_field(ppc, ['reserves', 'cost'], 'gen')
1417
+
1418
+ Reorders rows of ppc['reserves']['cost'] to match internal generator
1419
+ ordering.
1420
+
1421
+ ppc = e2i_field(ppc, ['reserves', 'zones'], 'gen', 1)
1422
+
1423
+ Reorders columns of ppc['reserves']['zones'] to match internal
1424
+ generator ordering.
1425
+
1426
+ @see: L{i2e_field}, L{e2i_data}, L{ext2int}
1427
+ """
1428
+ if isinstance(field, str):
1429
+ key = '["%s"]' % field
1430
+ else:
1431
+ key = '["%s"]' % '"]["'.join(field)
1432
+
1433
+ v_ext = ppc["order"]["ext"]
1434
+ for fld in field:
1435
+ if fld not in v_ext:
1436
+ v_ext[fld] = {}
1437
+ v_ext = v_ext[fld]
1438
+
1439
+ exec('ppc["order"]["ext"]%s = ppc%s.copy()' % (key, key))
1440
+ exec('ppc%s = e2i_data(ppc, ppc%s, ordering, dim)' % (key, key))
1441
+
1442
+ return ppc
1443
+
1444
+
1445
+ def ext2int(ppc, val_or_field=None, ordering=None, dim=0):
1446
+ """
1447
+ Converts external to internal indexing.
1448
+
1449
+ This function has two forms, the old form that operates on
1450
+ and returns individual matrices and the new form that operates
1451
+ on and returns an entire PYPOWER case dict.
1452
+
1453
+ 1. C{ppc = ext2int(ppc)}
1454
+
1455
+ If the input is a single PYPOWER case dict, then all isolated
1456
+ buses, off-line generators and branches are removed along with any
1457
+ generators, branches or areas connected to isolated buses. Then the
1458
+ buses are renumbered consecutively, beginning at 0, and the
1459
+ generators are sorted by increasing bus number. Any 'ext2int'
1460
+ callback routines registered in the case are also invoked
1461
+ automatically. All of the related
1462
+ indexing information and the original data matrices are stored under
1463
+ the 'order' key of the dict to be used by C{int2ext} to perform
1464
+ the reverse conversions. If the case is already using internal
1465
+ numbering it is returned unchanged.
1466
+
1467
+ Example::
1468
+ ppc = ext2int(ppc)
1469
+
1470
+ @see: L{int2ext}, L{e2i_field}, L{e2i_data}
1471
+
1472
+ @author: Ray Zimmerman (PSERC Cornell)
1473
+ """
1474
+ ppc = deepcopy(ppc)
1475
+ if val_or_field is None: # nargin == 1
1476
+ first = 'order' not in ppc
1477
+ if first or ppc["order"]["state"] == 'e':
1478
+ # initialize order
1479
+ if first:
1480
+ o = {
1481
+ 'ext': {
1482
+ 'bus': None,
1483
+ 'branch': None,
1484
+ 'gen': None
1485
+ },
1486
+ 'bus': {'e2i': None,
1487
+ 'i2e': None,
1488
+ 'status': {}},
1489
+ 'gen': {'e2i': None,
1490
+ 'i2e': None,
1491
+ 'status': {}},
1492
+ 'branch': {'status': {}}
1493
+ }
1494
+ else:
1495
+ o = ppc["order"]
1496
+
1497
+ # sizes
1498
+ nb = ppc["bus"].shape[0]
1499
+ ng = ppc["gen"].shape[0]
1500
+ ng0 = ng
1501
+ if 'A' in ppc:
1502
+ dc = True if ppc["A"].shape[1] < (2 * nb + 2 * ng) else False
1503
+ elif 'N' in ppc:
1504
+ dc = True if ppc["N"].shape[1] < (2 * nb + 2 * ng) else False
1505
+ else:
1506
+ dc = False
1507
+
1508
+ # save data matrices with external ordering
1509
+ if 'ext' not in o:
1510
+ o['ext'] = {}
1511
+ # Note: these dictionaries contain mixed float/int data,
1512
+ # so don't cast them all astype(int) for numpy/scipy indexing
1513
+ o["ext"]["bus"] = ppc["bus"].copy()
1514
+ o["ext"]["branch"] = ppc["branch"].copy()
1515
+ o["ext"]["gen"] = ppc["gen"].copy()
1516
+ if 'areas' in ppc:
1517
+ if len(ppc["areas"]) == 0: # if areas field is empty
1518
+ del ppc['areas'] # delete it (so it's ignored)
1519
+ else: # otherwise
1520
+ o["ext"]["areas"] = ppc["areas"].copy() # save it
1521
+
1522
+ # check that all buses have a valid BUS_TYPE
1523
+ bt = ppc["bus"][:, IDX.bus.BUS_TYPE]
1524
+ err = find(~((bt == IDX.bus.PQ) | (bt == IDX.bus.PV) |
1525
+ (bt == IDX.bus.REF) | (bt == IDX.bus.NONE)))
1526
+ if len(err) > 0:
1527
+ logger.debug('ext2int: bus %d has an invalid BUS_TYPE\n' % err)
1528
+
1529
+ # determine which buses, branches, gens are connected and
1530
+ # in-service
1531
+ n2i = c_sparse((range(nb), (ppc["bus"][:, IDX.bus.BUS_I], np.zeros(nb))),
1532
+ shape=(max(ppc["bus"][:, IDX.bus.BUS_I].astype(int)) + 1, 1))
1533
+ n2i = (np.array(n2i.todense().flatten())[0, :]).astype(int) # as 1D array
1534
+ bs = (bt != IDX.bus.NONE) # bus status
1535
+ o["bus"]["status"]["on"] = find(bs) # connected
1536
+ o["bus"]["status"]["off"] = find(~bs) # isolated
1537
+ gs = ((ppc["gen"][:, IDX.gen.GEN_STATUS] > 0) & # gen status
1538
+ bs[n2i[ppc["gen"][:, IDX.gen.GEN_BUS].astype(int)]])
1539
+ o["gen"]["status"]["on"] = find(gs) # on and connected
1540
+ o["gen"]["status"]["off"] = find(~gs) # off or isolated
1541
+ brs = (ppc["branch"][:, IDX.branch.BR_STATUS].astype(int) & # branch status
1542
+ bs[n2i[ppc["branch"][:, IDX.branch.F_BUS].astype(int)]] &
1543
+ bs[n2i[ppc["branch"][:, IDX.branch.T_BUS].astype(int)]]).astype(bool)
1544
+ o["branch"]["status"]["on"] = find(brs) # on and conn
1545
+ o["branch"]["status"]["off"] = find(~brs)
1546
+ if 'areas' in ppc:
1547
+ ar = bs[n2i[ppc["areas"][:, IDX.area.PRICE_REF_BUS].astype(int)]]
1548
+ o["areas"] = {"status": {}}
1549
+ o["areas"]["status"]["on"] = find(ar)
1550
+ o["areas"]["status"]["off"] = find(~ar)
1551
+
1552
+ # delete stuff that is "out"
1553
+ if len(o["bus"]["status"]["off"]) > 0:
1554
+ # ppc["bus"][o["bus"]["status"]["off"], :] = array([])
1555
+ ppc["bus"] = ppc["bus"][o["bus"]["status"]["on"], :]
1556
+ if len(o["branch"]["status"]["off"]) > 0:
1557
+ # ppc["branch"][o["branch"]["status"]["off"], :] = array([])
1558
+ ppc["branch"] = ppc["branch"][o["branch"]["status"]["on"], :]
1559
+ if len(o["gen"]["status"]["off"]) > 0:
1560
+ # ppc["gen"][o["gen"]["status"]["off"], :] = array([])
1561
+ ppc["gen"] = ppc["gen"][o["gen"]["status"]["on"], :]
1562
+ if 'areas' in ppc and (len(o["areas"]["status"]["off"]) > 0):
1563
+ # ppc["areas"][o["areas"]["status"]["off"], :] = array([])
1564
+ ppc["areas"] = ppc["areas"][o["areas"]["status"]["on"], :]
1565
+
1566
+ # update size
1567
+ nb = ppc["bus"].shape[0]
1568
+
1569
+ # apply consecutive bus numbering
1570
+ o["bus"]["i2e"] = ppc["bus"][:, IDX.bus.BUS_I].copy()
1571
+ o["bus"]["e2i"] = np.zeros(max(o["bus"]["i2e"]).astype(int) + 1)
1572
+ o["bus"]["e2i"][o["bus"]["i2e"].astype(int)] = np.arange(nb)
1573
+ ppc["bus"][:, IDX.bus.BUS_I] = \
1574
+ o["bus"]["e2i"][ppc["bus"][:, IDX.bus.BUS_I].astype(int)].copy()
1575
+ ppc["gen"][:, IDX.gen.GEN_BUS] = \
1576
+ o["bus"]["e2i"][ppc["gen"][:, IDX.gen.GEN_BUS].astype(int)].copy()
1577
+ ppc["branch"][:, IDX.branch.F_BUS] = \
1578
+ o["bus"]["e2i"][ppc["branch"][:, IDX.branch.F_BUS].astype(int)].copy()
1579
+ ppc["branch"][:, IDX.branch.T_BUS] = \
1580
+ o["bus"]["e2i"][ppc["branch"][:, IDX.branch.T_BUS].astype(int)].copy()
1581
+ if 'areas' in ppc:
1582
+ ppc["areas"][:, IDX.area.PRICE_REF_BUS] = \
1583
+ o["bus"]["e2i"][ppc["areas"][:,
1584
+ IDX.area.PRICE_REF_BUS].astype(int)].copy()
1585
+
1586
+ # reorder gens in order of increasing bus number
1587
+ o["gen"]["e2i"] = np.argsort(ppc["gen"][:, IDX.gen.GEN_BUS])
1588
+ o["gen"]["i2e"] = np.argsort(o["gen"]["e2i"])
1589
+
1590
+ ppc["gen"] = ppc["gen"][o["gen"]["e2i"].astype(int), :]
1591
+
1592
+ if 'int' in o:
1593
+ del o['int']
1594
+ o["state"] = 'i'
1595
+ ppc["order"] = o
1596
+
1597
+ # update gencost, A and N
1598
+ if 'gencost' in ppc:
1599
+ ordering = ['gen'] # Pg cost only
1600
+ if ppc["gencost"].shape[0] == (2 * ng0):
1601
+ ordering.append('gen') # include Qg cost
1602
+ ppc = e2i_field(ppc, 'gencost', ordering)
1603
+ if 'A' in ppc or 'N' in ppc:
1604
+ if dc:
1605
+ ordering = ['bus', 'gen']
1606
+ else:
1607
+ ordering = ['bus', 'bus', 'gen', 'gen']
1608
+ if 'A' in ppc:
1609
+ ppc = e2i_field(ppc, 'A', ordering, 1)
1610
+ if 'N' in ppc:
1611
+ ppc = e2i_field(ppc, 'N', ordering, 1)
1612
+
1613
+ # execute userfcn callbacks for 'ext2int' stage
1614
+ if 'userfcn' in ppc:
1615
+ ppc = run_userfcn(ppc['userfcn'], 'ext2int', ppc)
1616
+ else: # convert extra data
1617
+ if isinstance(val_or_field, str) or isinstance(val_or_field, list):
1618
+ # field
1619
+ logger.warning('Calls of the form ppc = ext2int(ppc, '
1620
+ '\'field_name\', ...) have been deprecated. Please '
1621
+ 'replace ext2int with e2i_field.', DeprecationWarning)
1622
+ gen, branch = val_or_field, ordering
1623
+ ppc = e2i_field(ppc, gen, branch, dim)
1624
+
1625
+ else:
1626
+ # value
1627
+ logger.warning('Calls of the form val = ext2int(ppc, val, ...) have been '
1628
+ 'deprecated. Please replace ext2int with e2i_data.',
1629
+ DeprecationWarning)
1630
+ gen, branch = val_or_field, ordering
1631
+ ppc = e2i_data(ppc, gen, branch, dim)
1632
+
1633
+ return ppc
1634
+
1635
+
1636
+ def ext2int1(bus, gen, branch, areas=None):
1637
+ """
1638
+ Converts from (possibly non-consecutive) external bus numbers to
1639
+ consecutive internal bus numbers which start at 1. Changes are made
1640
+ to BUS, GEN, BRANCH and optionally AREAS matrices, which are returned
1641
+ along with a vector of indices I2E that can be passed to INT2EXT to
1642
+ perform the reverse conversion.
1643
+
1644
+ @see: L{int2ext}
1645
+ @see: U{http://www.pserc.cornell.edu/matpower/}
1646
+ """
1647
+ i2e = bus[:, IDX.bus.BUS_I].astype(int)
1648
+ e2i = np.zeros(max(i2e) + 1)
1649
+ e2i[i2e] = np.arange(bus.shape[0])
1650
+
1651
+ bus[:, IDX.bus.BUS_I] = e2i[bus[:, IDX.bus.BUS_I].astype(int)]
1652
+ gen[:, IDX.gen.GEN_BUS] = e2i[gen[:, IDX.gen.GEN_BUS].astype(int)]
1653
+ branch[:, IDX.branch.F_BUS] = e2i[branch[:, IDX.branch.F_BUS].astype(int)]
1654
+ branch[:, IDX.branch.T_BUS] = e2i[branch[:, IDX.branch.T_BUS].astype(int)]
1655
+ if areas is not None and len(areas) > 0:
1656
+ areas[:, IDX.area.PRICE_REF_BUS] = e2i[areas[:, IDX.area.PRICE_REF_BUS].astype(int)]
1657
+
1658
+ return i2e, bus, gen, branch, areas
1659
+
1660
+ return i2e, bus, gen, branch
1661
+
1662
+
1663
+ def i2e_data(ppc, val, oldval, ordering, dim=0):
1664
+ """
1665
+ Converts data from internal to external bus numbering.
1666
+
1667
+ Parameters
1668
+ ----------
1669
+ ppc : dict
1670
+ The case dict.
1671
+ val : Numpy.array
1672
+ The data to be converted.
1673
+ oldval : Numpy.array
1674
+ The data to be used for off-line gens, branches, isolated buses,
1675
+ connected gens and branches.
1676
+ ordering : str or list of str
1677
+ The ordering of the data. Can be one of the following three
1678
+ strings: 'bus', 'gen' or 'branch'. For data structures with
1679
+ multiple blocks of data, ordered by bus, gen or branch, they
1680
+ can be converted with a single call by specifying C[ordering}
1681
+ as a list of strings.
1682
+ dim : int, optional
1683
+ The dimension to reorder. Default is 0.
1684
+
1685
+ Returns
1686
+ -------
1687
+ val : Numpy.array
1688
+ The converted data.
1689
+
1690
+ Examples
1691
+ --------
1692
+ Converts an A matrix for user-supplied OPF constraints from
1693
+ internal to external ordering, where the columns of the A
1694
+ matrix correspond to bus voltage angles, then voltage
1695
+ magnitudes, then generator real power injections and finally
1696
+ generator reactive power injections.
1697
+ >>> A_ext = i2e_data(ppc, A_int, A_orig, ['bus','bus','gen','gen'], 1)
1698
+
1699
+ Converts a C{gencost} matrix that has both real and reactive power
1700
+ costs (in rows 1--ng and ng+1--2*ng, respectively).
1701
+
1702
+ >>> gencost_ext = i2e_data(ppc, gencost_int, gencost_orig, ['gen','gen'], 0)
1703
+
1704
+ For a case dict using internal indexing, this function can be
1705
+ used to convert other data structures as well by passing in 3 or 4
1706
+ extra parameters in addition to the case dict. If the value passed
1707
+ in the 2nd argument C{val} is a column vector, it will be converted
1708
+ according to the ordering specified by the 4th argument (C{ordering},
1709
+ described below). If C{val} is an n-dimensional matrix, then the
1710
+ optional 5th argument (C{dim}, default = 0) can be used to specify
1711
+ which dimension to reorder. The 3rd argument (C{oldval}) is used to
1712
+ initialize the return value before converting C{val} to external
1713
+ indexing. In particular, any data corresponding to off-line gens
1714
+ or branches or isolated buses or any connected gens or branches
1715
+ will be taken from C{oldval}, with C[val} supplying the rest of the
1716
+ returned data.
1717
+
1718
+ The C{ordering} argument is used to indicate whether the data
1719
+ corresponds to bus-, gen- or branch-ordered data. It can be one
1720
+ of the following three strings: 'bus', 'gen' or 'branch'. For
1721
+ data structures with multiple blocks of data, ordered by bus,
1722
+ gen or branch, they can be converted with a single call by
1723
+ specifying C[ordering} as a list of strings.
1724
+
1725
+ Any extra elements, rows, columns, etc. beyond those indicated
1726
+ in C{ordering}, are not disturbed.
1727
+
1728
+ @see: L{e2i_data}, L{i2e_field}, L{int2ext}.
1729
+ """
1730
+ if 'order' not in ppc:
1731
+ logger.debug('i2e_data: ppc does not have the \'order\' field '
1732
+ 'required for conversion back to external numbering.\n')
1733
+ return
1734
+
1735
+ o = ppc["order"]
1736
+ if o['state'] != 'i':
1737
+ logger.debug('i2e_data: ppc does not appear to be in internal '
1738
+ 'order\n')
1739
+ return
1740
+
1741
+ if isinstance(ordering, str): # single set
1742
+ if ordering == 'gen':
1743
+ v = get_reorder(val, o[ordering]["i2e"], dim)
1744
+ else:
1745
+ v = val
1746
+ val = set_reorder(oldval, v, o[ordering]["status"]["on"], dim)
1747
+ else: # multiple sets
1748
+ be = 0 # base, external indexing
1749
+ bi = 0 # base, internal indexing
1750
+ new_v = []
1751
+ for ordr in ordering:
1752
+ ne = o["ext"][ordr].shape[0]
1753
+ ni = ppc[ordr].shape[0]
1754
+ v = get_reorder(val, bi + np.arange(ni), dim)
1755
+ oldv = get_reorder(oldval, be + np.arange(ne), dim)
1756
+ new_v.append(int2ext(ppc, v, oldv, ordr, dim))
1757
+ be = be + ne
1758
+ bi = bi + ni
1759
+ ni = val.shape[dim]
1760
+ if ni > bi: # the rest
1761
+ v = get_reorder(val, np.arange(bi, ni), dim)
1762
+ new_v.append(v)
1763
+ val = np.concatenate(new_v, dim)
1764
+
1765
+ return val
1766
+
1767
+
1768
+ def i2e_field(ppc, field, ordering, dim=0):
1769
+ """
1770
+ Converts fields of MPC from internal to external bus numbering.
1771
+
1772
+ Parameters
1773
+ ----------
1774
+ ppc : dict
1775
+ The case dict.
1776
+ field : str or list of str
1777
+ The field to be converted. If C{field} is a list of strings,
1778
+ they specify nested fields.
1779
+ ordering : str or list of str
1780
+ The ordering of the data. Can be one of the following three
1781
+ strings: 'bus', 'gen' or 'branch'. For data structures with
1782
+ multiple blocks of data, ordered by bus, gen or branch, they
1783
+ can be converted with a single call by specifying C[ordering}
1784
+ as a list of strings.
1785
+ dim : int, optional
1786
+ The dimension to reorder. Default is 0.
1787
+
1788
+ Returns
1789
+ -------
1790
+ ppc : dict
1791
+ The updated case dict.
1792
+
1793
+ For a case dict using internal indexing, this function can be
1794
+ used to convert other data structures as well by passing in 2 or 3
1795
+ extra parameters in addition to the case dict.
1796
+
1797
+ If the 2nd argument is a string or list of strings, it
1798
+ specifies a field in the case dict whose value should be
1799
+ converted by L{i2e_data}. In this case, the corresponding
1800
+ C{oldval} is taken from where it was stored by L{ext2int} in
1801
+ ppc['order']['ext'] and the updated case dict is returned.
1802
+ If C{field} is a list of strings, they specify nested fields.
1803
+
1804
+ The 3rd and optional 4th arguments are simply passed along to
1805
+ the call to L{i2e_data}.
1806
+
1807
+ Examples:
1808
+ ppc = i2e_field(ppc, ['reserves', 'cost'], 'gen')
1809
+
1810
+ Reorders rows of ppc['reserves']['cost'] to match external generator
1811
+ ordering.
1812
+
1813
+ ppc = i2e_field(ppc, ['reserves', 'zones'], 'gen', 1)
1814
+
1815
+ Reorders columns of ppc.reserves.zones to match external
1816
+ generator ordering.
1817
+
1818
+ @see: L{e2i_field}, L{i2e_data}, L{int2ext}.
1819
+ """
1820
+ if 'int' not in ppc['order']:
1821
+ ppc['order']['int'] = {}
1822
+
1823
+ if isinstance(field, str):
1824
+ key = '["%s"]' % field
1825
+ else: # nested dicts
1826
+ key = '["%s"]' % '"]["'.join(field)
1827
+
1828
+ v_int = ppc["order"]["int"]
1829
+ for fld in field:
1830
+ if fld not in v_int:
1831
+ v_int[fld] = {}
1832
+ v_int = v_int[fld]
1833
+
1834
+ exec('ppc["order"]["int"]%s = ppc%s.copy()' % (key, key))
1835
+ exec('ppc%s = i2e_data(ppc, ppc%s, ppc["order"]["ext"]%s, ordering, dim)' %
1836
+ (key, key, key))
1837
+
1838
+ return ppc
1839
+
1840
+
1841
+ def total_load(bus, gen=None, load_zone=None, which_type=None):
1842
+ """
1843
+ Returns vector of total load in each load zone.
1844
+
1845
+ @param bus: standard C{bus} matrix with C{nb} rows, where the fixed active
1846
+ and reactive loads are specified in columns C{PD} and C{QD}
1847
+
1848
+ @param gen: (optional) standard C{gen} matrix with C{ng} rows, where the
1849
+ dispatchable loads are specified by columns C{PG}, C{QG}, C{PMIN},
1850
+ C{QMIN} and C{QMAX} (in rows for which C{isload(GEN)} returns C{True}).
1851
+ If C{gen} is empty, it assumes there are no dispatchable loads.
1852
+
1853
+ @param load_zone: (optional) C{nb} element vector where the value of
1854
+ each element is either zero or the index of the load zone
1855
+ to which the corresponding bus belongs. If C{load_zone(b) = k}
1856
+ then the loads at bus C{b} will added to the values of C{Pd[k]} and
1857
+ C{Qd[k]}. If C{load_zone} is empty, the default is defined as the areas
1858
+ specified in the C{bus} matrix, i.e. C{load_zone = bus[:, BUS_AREA]}
1859
+ and load will have dimension C{= max(bus[:, BUS_AREA])}. If
1860
+ C{load_zone = 'all'}, the result is a scalar with the total system
1861
+ load.
1862
+
1863
+ @param which_type: (default is 'BOTH' if C{gen} is provided, else 'FIXED')
1864
+ - 'FIXED' : sum only fixed loads
1865
+ - 'DISPATCHABLE' : sum only dispatchable loads
1866
+ - 'BOTH' : sum both fixed and dispatchable loads
1867
+
1868
+ @see: L{scale_load}
1869
+
1870
+ @author: Ray Zimmerman (PSERC Cornell)
1871
+ """
1872
+ nb = bus.shape[0] # number of buses
1873
+
1874
+ if gen is None:
1875
+ gen = np.array([])
1876
+ if load_zone is None:
1877
+ load_zone = np.array([], int)
1878
+
1879
+ # fill out and check which_type
1880
+ if len(gen) == 0:
1881
+ which_type = 'FIXED'
1882
+
1883
+ if (which_type == None) and (len(gen) > 0):
1884
+ which_type = 'BOTH' # 'FIXED', 'DISPATCHABLE' or 'BOTH'
1885
+
1886
+ if (which_type[0] != 'F') and (which_type[0] != 'D') and (which_type[0] != 'B'):
1887
+ logger.debug("total_load: which_type should be 'FIXED, 'DISPATCHABLE or 'BOTH'\n")
1888
+
1889
+ want_Q = True
1890
+ want_fixed = (which_type[0] == 'B') | (which_type[0] == 'F')
1891
+ want_disp = (which_type[0] == 'B') | (which_type[0] == 'D')
1892
+
1893
+ # initialize load_zone
1894
+ if isinstance(load_zone, str) and (load_zone == 'all'):
1895
+ load_zone = np.ones(nb, int) # make a single zone of all buses
1896
+ elif len(load_zone) == 0:
1897
+ load_zone = bus[:, IDX.bus.BUS_AREA].astype(int) # use areas defined in bus data as zones
1898
+
1899
+ nz = max(load_zone) # number of load zones
1900
+
1901
+ # fixed load at each bus, & initialize dispatchable
1902
+ if want_fixed:
1903
+ Pdf = bus[:, IDX.bus.PD] # real power
1904
+ if want_Q:
1905
+ Qdf = bus[:, IDX.bus.QD] # reactive power
1906
+ else:
1907
+ Pdf = np.zeros(nb) # real power
1908
+ if want_Q:
1909
+ Qdf = np.zeros(nb) # reactive power
1910
+
1911
+ # dispatchable load at each bus
1912
+ if want_disp: # need dispatchable
1913
+ ng = gen.shape[0]
1914
+ is_ld = isload(gen) & (gen[:, IDX.gen.GEN_STATUS] > 0)
1915
+ ld = find(is_ld)
1916
+
1917
+ # create map of external bus numbers to bus indices
1918
+ i2e = bus[:, IDX.bus.BUS_I].astype(int)
1919
+ e2i = zeros(max(i2e) + 1)
1920
+ e2i[i2e] = arange(nb)
1921
+
1922
+ gbus = gen[:, IDX.gen.GEN_BUS].astype(int)
1923
+ Cld = c_sparse((is_ld, (e2i[gbus], np.arange(ng))), (nb, ng))
1924
+ Pdd = -Cld * gen[:, IDX.gen.PMIN] # real power
1925
+ if want_Q:
1926
+ Q = np.zeros(ng)
1927
+ Q[ld] = (gen[ld, IDX.gen.QMIN] == 0) * gen[ld, IDX.gen.QMAX] + \
1928
+ (gen[ld, IDX.gen.QMAX] == 0) * gen[ld, IDX.gen.QMIN]
1929
+ Qdd = -Cld * Q # reactive power
1930
+ else:
1931
+ Pdd = np.zeros(nb)
1932
+ if want_Q:
1933
+ Qdd = np.zeros(nb)
1934
+
1935
+ # compute load sums
1936
+ Pd = np.zeros(nz)
1937
+ if want_Q:
1938
+ Qd = np.zeros(nz)
1939
+
1940
+ for k in range(1, nz + 1):
1941
+ idx = find(load_zone == k)
1942
+ Pd[k - 1] = sum(Pdf[idx]) + sum(Pdd[idx])
1943
+ if want_Q:
1944
+ Qd[k - 1] = sum(Qdf[idx]) + sum(Qdd[idx])
1945
+
1946
+ return Pd, Qd