ltbams 0.9.9__py3-none-any.whl → 1.0.2a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ams/__init__.py +4 -11
- ams/_version.py +3 -3
- ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
- ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced.json +1062 -0
- ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
- ams/cases/ieee123/ieee123.xlsx +0 -0
- ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
- ams/cases/ieee14/ieee14.json +1166 -0
- ams/cases/ieee14/ieee14.raw +92 -0
- ams/cases/ieee14/ieee14_conn.xlsx +0 -0
- ams/cases/ieee14/ieee14_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
- ams/cases/matpower/benchmark.json +1594 -0
- ams/cases/matpower/case118.m +787 -0
- ams/cases/matpower/case14.m +129 -0
- ams/cases/matpower/case300.m +1315 -0
- ams/cases/matpower/case39.m +205 -0
- ams/cases/matpower/case5.m +62 -0
- ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
- ams/cases/npcc/npcc.m +644 -0
- ams/cases/npcc/npcc_uced.xlsx +0 -0
- ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
- ams/cases/wecc/wecc.m +714 -0
- ams/cases/wecc/wecc_uced.xlsx +0 -0
- ams/cli.py +6 -0
- ams/core/__init__.py +2 -0
- ams/core/documenter.py +652 -0
- ams/core/matprocessor.py +782 -0
- ams/core/model.py +330 -0
- ams/core/param.py +322 -0
- ams/core/service.py +918 -0
- ams/core/symprocessor.py +224 -0
- ams/core/var.py +59 -0
- ams/extension/__init__.py +5 -0
- ams/extension/eva.py +401 -0
- ams/interface.py +1085 -0
- ams/io/__init__.py +133 -0
- ams/io/json.py +82 -0
- ams/io/matpower.py +406 -0
- ams/io/psse.py +6 -0
- ams/io/pypower.py +103 -0
- ams/io/xlsx.py +80 -0
- ams/main.py +81 -4
- ams/models/__init__.py +24 -0
- ams/models/area.py +40 -0
- ams/models/bus.py +52 -0
- ams/models/cost.py +169 -0
- ams/models/distributed/__init__.py +3 -0
- ams/models/distributed/esd1.py +71 -0
- ams/models/distributed/ev.py +60 -0
- ams/models/distributed/pvd1.py +67 -0
- ams/models/group.py +231 -0
- ams/models/info.py +26 -0
- ams/models/line.py +238 -0
- ams/models/renewable/__init__.py +5 -0
- ams/models/renewable/regc.py +119 -0
- ams/models/reserve.py +94 -0
- ams/models/shunt.py +14 -0
- ams/models/static/__init__.py +2 -0
- ams/models/static/gen.py +165 -0
- ams/models/static/pq.py +61 -0
- ams/models/timeslot.py +69 -0
- ams/models/zone.py +49 -0
- ams/opt/__init__.py +12 -0
- ams/opt/constraint.py +175 -0
- ams/opt/exprcalc.py +127 -0
- ams/opt/expression.py +188 -0
- ams/opt/objective.py +174 -0
- ams/opt/omodel.py +432 -0
- ams/opt/optzbase.py +192 -0
- ams/opt/param.py +156 -0
- ams/opt/var.py +233 -0
- ams/pypower/__init__.py +8 -0
- ams/pypower/_compat.py +9 -0
- ams/pypower/core/__init__.py +8 -0
- ams/pypower/core/pips.py +894 -0
- ams/pypower/core/ppoption.py +244 -0
- ams/pypower/core/ppver.py +18 -0
- ams/pypower/core/solver.py +2451 -0
- ams/pypower/eps.py +6 -0
- ams/pypower/idx.py +174 -0
- ams/pypower/io.py +604 -0
- ams/pypower/make/__init__.py +11 -0
- ams/pypower/make/matrices.py +665 -0
- ams/pypower/make/pdv.py +506 -0
- ams/pypower/routines/__init__.py +7 -0
- ams/pypower/routines/cpf.py +513 -0
- ams/pypower/routines/cpf_callbacks.py +114 -0
- ams/pypower/routines/opf.py +1803 -0
- ams/pypower/routines/opffcns.py +1946 -0
- ams/pypower/routines/pflow.py +852 -0
- ams/pypower/toggle.py +1098 -0
- ams/pypower/utils.py +293 -0
- ams/report.py +212 -50
- ams/routines/__init__.py +23 -0
- ams/routines/acopf.py +117 -0
- ams/routines/cpf.py +65 -0
- ams/routines/dcopf.py +241 -0
- ams/routines/dcpf.py +209 -0
- ams/routines/dcpf0.py +196 -0
- ams/routines/dopf.py +150 -0
- ams/routines/ed.py +312 -0
- ams/routines/pflow.py +255 -0
- ams/routines/pflow0.py +113 -0
- ams/routines/routine.py +1033 -0
- ams/routines/rted.py +519 -0
- ams/routines/type.py +160 -0
- ams/routines/uc.py +376 -0
- ams/shared.py +63 -9
- ams/system.py +61 -22
- ams/utils/__init__.py +3 -0
- ams/utils/misc.py +77 -0
- ams/utils/paths.py +257 -0
- docs/Makefile +21 -0
- docs/make.bat +35 -0
- docs/source/_templates/autosummary/base.rst +5 -0
- docs/source/_templates/autosummary/class.rst +35 -0
- docs/source/_templates/autosummary/module.rst +65 -0
- docs/source/_templates/autosummary/module_toctree.rst +66 -0
- docs/source/api.rst +102 -0
- docs/source/conf.py +203 -0
- docs/source/examples/index.rst +34 -0
- docs/source/genmodelref.py +61 -0
- docs/source/genroutineref.py +47 -0
- docs/source/getting_started/copyright.rst +20 -0
- docs/source/getting_started/formats/index.rst +20 -0
- docs/source/getting_started/formats/matpower.rst +183 -0
- docs/source/getting_started/formats/psse.rst +46 -0
- docs/source/getting_started/formats/pypower.rst +223 -0
- docs/source/getting_started/formats/xlsx.png +0 -0
- docs/source/getting_started/formats/xlsx.rst +23 -0
- docs/source/getting_started/index.rst +76 -0
- docs/source/getting_started/install.rst +234 -0
- docs/source/getting_started/overview.rst +26 -0
- docs/source/getting_started/testcase.rst +45 -0
- docs/source/getting_started/verification.rst +13 -0
- docs/source/images/curent.ico +0 -0
- docs/source/images/dcopf_time.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
- docs/source/images/sponsors/doe.png +0 -0
- docs/source/index.rst +108 -0
- docs/source/modeling/example.rst +159 -0
- docs/source/modeling/index.rst +17 -0
- docs/source/modeling/model.rst +210 -0
- docs/source/modeling/routine.rst +122 -0
- docs/source/modeling/system.rst +51 -0
- docs/source/release-notes.rst +398 -0
- ltbams-1.0.2a1.dist-info/METADATA +210 -0
- ltbams-1.0.2a1.dist-info/RECORD +188 -0
- {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
- ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
- tests/__init__.py +0 -0
- tests/test_1st_system.py +33 -0
- tests/test_addressing.py +40 -0
- tests/test_andes_mats.py +61 -0
- tests/test_case.py +266 -0
- tests/test_cli.py +34 -0
- tests/test_export_csv.py +89 -0
- tests/test_group.py +83 -0
- tests/test_interface.py +216 -0
- tests/test_io.py +32 -0
- tests/test_jumper.py +27 -0
- tests/test_known_good.py +267 -0
- tests/test_matp.py +437 -0
- tests/test_model.py +54 -0
- tests/test_omodel.py +119 -0
- tests/test_paths.py +22 -0
- tests/test_report.py +251 -0
- tests/test_repr.py +21 -0
- tests/test_routine.py +178 -0
- tests/test_rtn_dcopf.py +101 -0
- tests/test_rtn_dcpf.py +77 -0
- tests/test_rtn_ed.py +279 -0
- tests/test_rtn_pflow.py +219 -0
- tests/test_rtn_rted.py +273 -0
- tests/test_rtn_uc.py +248 -0
- tests/test_service.py +73 -0
- ltbams-0.9.9.dist-info/LICENSE +0 -692
- ltbams-0.9.9.dist-info/METADATA +0 -859
- ltbams-0.9.9.dist-info/RECORD +0 -14
- ltbams-0.9.9.dist-info/top_level.txt +0 -1
- {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
ams/pypower/io.py
ADDED
@@ -0,0 +1,604 @@
|
|
1
|
+
"""
|
2
|
+
Save and load PYPOWER cases.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import logging
|
6
|
+
from copy import deepcopy
|
7
|
+
|
8
|
+
from os.path import basename, splitext, exists
|
9
|
+
|
10
|
+
from numpy import array, zeros, ones, c_
|
11
|
+
|
12
|
+
from scipy.io import loadmat, savemat
|
13
|
+
|
14
|
+
|
15
|
+
from sys import stderr
|
16
|
+
|
17
|
+
from os.path import basename
|
18
|
+
|
19
|
+
from numpy import array, c_, r_, any
|
20
|
+
|
21
|
+
from ams.pypower.routines.opffcns import run_userfcn
|
22
|
+
|
23
|
+
from ams.pypower.idx import IDX
|
24
|
+
|
25
|
+
|
26
|
+
logger = logging.getLogger(__name__)
|
27
|
+
|
28
|
+
|
29
|
+
def loadcase(casefile,
|
30
|
+
return_as_obj=True, expect_gencost=True, expect_areas=True):
|
31
|
+
"""Returns the individual data matrices or an dict containing them
|
32
|
+
as values.
|
33
|
+
|
34
|
+
Here C{casefile} is either a dict containing the keys C{baseMVA}, C{bus},
|
35
|
+
C{gen}, C{branch}, C{areas}, C{gencost}, or a string containing the name
|
36
|
+
of the file. If C{casefile} contains the extension '.mat' or '.py', then
|
37
|
+
the explicit file is searched. If C{casefile} containts no extension, then
|
38
|
+
L{loadcase} looks for a '.mat' file first, then for a '.py' file. If the
|
39
|
+
file does not exist or doesn't define all matrices, the function returns
|
40
|
+
an exit code as follows:
|
41
|
+
|
42
|
+
0. all variables successfully defined
|
43
|
+
1. input argument is not a string or dict
|
44
|
+
2. specified extension-less file name does not exist
|
45
|
+
3. specified .mat file does not exist
|
46
|
+
4. specified .py file does not exist
|
47
|
+
5. specified file fails to define all matrices or contains syntax
|
48
|
+
error
|
49
|
+
|
50
|
+
If the input data is not a dict containing a 'version' key, it is
|
51
|
+
assumed to be a PYPOWER case file in version 1 format, and will be
|
52
|
+
converted to version 2 format.
|
53
|
+
|
54
|
+
@author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
|
55
|
+
Autonoma de Manizales)
|
56
|
+
@author: Ray Zimmerman (PSERC Cornell)
|
57
|
+
"""
|
58
|
+
if return_as_obj == True:
|
59
|
+
expect_gencost = False
|
60
|
+
expect_areas = False
|
61
|
+
|
62
|
+
info = 0
|
63
|
+
|
64
|
+
# read data into case object
|
65
|
+
if isinstance(casefile, str):
|
66
|
+
lasterr = ''
|
67
|
+
# check for explicit extension
|
68
|
+
if casefile.endswith(('.py', '.mat')):
|
69
|
+
rootname, extension = splitext(casefile)
|
70
|
+
fname = basename(rootname)
|
71
|
+
else:
|
72
|
+
# set extension if not specified explicitly
|
73
|
+
rootname = casefile
|
74
|
+
if exists(casefile + '.mat'):
|
75
|
+
extension = '.mat'
|
76
|
+
elif exists(casefile + '.py'):
|
77
|
+
extension = '.py'
|
78
|
+
else:
|
79
|
+
info = 2
|
80
|
+
fname = basename(rootname)
|
81
|
+
|
82
|
+
# attempt to read file
|
83
|
+
if info == 0:
|
84
|
+
if extension == '.mat': # from MAT file
|
85
|
+
try:
|
86
|
+
d = loadmat(rootname + extension, struct_as_record=True)
|
87
|
+
if 'ppc' in d or 'mpc' in d: # it's a MAT/PYPOWER dict
|
88
|
+
if 'ppc' in d:
|
89
|
+
struct = d['ppc']
|
90
|
+
else:
|
91
|
+
struct = d['mpc']
|
92
|
+
val = struct[0, 0]
|
93
|
+
|
94
|
+
s = {}
|
95
|
+
for a in val.dtype.names:
|
96
|
+
s[a] = val[a]
|
97
|
+
else: # individual data matrices
|
98
|
+
d['version'] = '1'
|
99
|
+
|
100
|
+
s = {}
|
101
|
+
for k, v in d.items():
|
102
|
+
s[k] = v
|
103
|
+
|
104
|
+
s['baseMVA'] = s['baseMVA'][0] # convert array to float
|
105
|
+
|
106
|
+
except IOError as e:
|
107
|
+
info = 3
|
108
|
+
lasterr = str(e)
|
109
|
+
elif extension == '.py': # from Python file
|
110
|
+
try:
|
111
|
+
if PY2:
|
112
|
+
execfile(rootname + extension)
|
113
|
+
else:
|
114
|
+
exec(compile(open(rootname + extension).read(),
|
115
|
+
rootname + extension, 'exec'))
|
116
|
+
|
117
|
+
try: # assume it returns an object
|
118
|
+
s = eval(fname)()
|
119
|
+
except ValueError as e:
|
120
|
+
info = 4
|
121
|
+
lasterr = str(e)
|
122
|
+
# if not try individual data matrices
|
123
|
+
if info == 0 and not isinstance(s, dict):
|
124
|
+
s = {}
|
125
|
+
s['version'] = '1'
|
126
|
+
if expect_gencost:
|
127
|
+
try:
|
128
|
+
s['baseMVA'], s['bus'], s['gen'], s['branch'], \
|
129
|
+
s['areas'], s['gencost'] = eval(fname)()
|
130
|
+
except IOError as e:
|
131
|
+
info = 4
|
132
|
+
lasterr = str(e)
|
133
|
+
else:
|
134
|
+
if return_as_obj:
|
135
|
+
try:
|
136
|
+
s['baseMVA'], s['bus'], s['gen'], \
|
137
|
+
s['branch'], s['areas'], \
|
138
|
+
s['gencost'] = eval(fname)()
|
139
|
+
except ValueError as e:
|
140
|
+
try:
|
141
|
+
s['baseMVA'], s['bus'], s['gen'], \
|
142
|
+
s['branch'] = eval(fname)()
|
143
|
+
except ValueError as e:
|
144
|
+
info = 4
|
145
|
+
lasterr = str(e)
|
146
|
+
else:
|
147
|
+
try:
|
148
|
+
s['baseMVA'], s['bus'], s['gen'], \
|
149
|
+
s['branch'] = eval(fname)()
|
150
|
+
except ValueError as e:
|
151
|
+
info = 4
|
152
|
+
lasterr = str(e)
|
153
|
+
|
154
|
+
except IOError as e:
|
155
|
+
info = 4
|
156
|
+
lasterr = str(e)
|
157
|
+
|
158
|
+
if info == 4 and exists(rootname + '.py'):
|
159
|
+
info = 5
|
160
|
+
err5 = lasterr
|
161
|
+
|
162
|
+
elif isinstance(casefile, dict):
|
163
|
+
s = deepcopy(casefile)
|
164
|
+
else:
|
165
|
+
info = 1
|
166
|
+
|
167
|
+
# check contents of dict
|
168
|
+
if info == 0:
|
169
|
+
# check for required keys
|
170
|
+
if (s['baseMVA'] is None or s['bus'] is None
|
171
|
+
or s['gen'] is None or s['branch'] is None) or \
|
172
|
+
(expect_gencost and s['gencost'] is None) or \
|
173
|
+
(expect_areas and s['areas'] is None):
|
174
|
+
info = 5 # missing some expected fields
|
175
|
+
err5 = 'missing data'
|
176
|
+
else:
|
177
|
+
# remove empty areas if not needed
|
178
|
+
if hasattr(s, 'areas') and (len(s['areas']) == 0) and (not expect_areas):
|
179
|
+
del s['areas']
|
180
|
+
|
181
|
+
# all fields present, copy to ppc
|
182
|
+
ppc = deepcopy(s)
|
183
|
+
if not hasattr(ppc, 'version'): # hmm, struct with no 'version' field
|
184
|
+
if ppc['gen'].shape[1] < 21: # version 2 has 21 or 25 cols
|
185
|
+
ppc['version'] = '1'
|
186
|
+
else:
|
187
|
+
ppc['version'] = '2'
|
188
|
+
|
189
|
+
if (ppc['version'] == '1'):
|
190
|
+
# convert from version 1 to version 2
|
191
|
+
ppc['gen'], ppc['branch'] = ppc_1to2(ppc['gen'], ppc['branch'])
|
192
|
+
ppc['version'] = '2'
|
193
|
+
|
194
|
+
if info == 0: # no errors
|
195
|
+
if return_as_obj:
|
196
|
+
return ppc
|
197
|
+
else:
|
198
|
+
result = [ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch']]
|
199
|
+
if expect_gencost:
|
200
|
+
if expect_areas:
|
201
|
+
result.extend([ppc['areas'], ppc['gencost']])
|
202
|
+
else:
|
203
|
+
result.extend([ppc['gencost']])
|
204
|
+
return result
|
205
|
+
else: # error encountered
|
206
|
+
if info == 1:
|
207
|
+
logger.debug('Input arg should be a case or a string '
|
208
|
+
'containing a filename\n')
|
209
|
+
elif info == 2:
|
210
|
+
logger.debug('Specified case not a valid file\n')
|
211
|
+
elif info == 3:
|
212
|
+
logger.debug('Specified MAT file does not exist\n')
|
213
|
+
elif info == 4:
|
214
|
+
logger.debug('Specified Python file does not exist\n')
|
215
|
+
elif info == 5:
|
216
|
+
logger.debug('Syntax error or undefined data '
|
217
|
+
'matrix(ices) in the file\n')
|
218
|
+
else:
|
219
|
+
logger.debug('Unknown error encountered loading case.\n')
|
220
|
+
|
221
|
+
return info
|
222
|
+
|
223
|
+
|
224
|
+
def ppc_1to2(gen, branch):
|
225
|
+
# ----- gen -----
|
226
|
+
# use the version 1 values for column names
|
227
|
+
if gen.shape[1] >= IDX.gen.APF:
|
228
|
+
logger.debug('ppc_1to2: gen matrix appears to already be in '
|
229
|
+
'version 2 format\n')
|
230
|
+
return gen, branch
|
231
|
+
|
232
|
+
shift = IDX.gen.MU_PMAX - IDX.gen.PMIN - 1
|
233
|
+
tmp = array([IDX.gen.MU_PMAX, IDX.gen.MU_PMIN, IDX.gen.MU_QMAX, IDX.gen.MU_QMIN]) - shift
|
234
|
+
mu_Pmax, mu_Pmin, mu_Qmax, mu_Qmin = tmp
|
235
|
+
|
236
|
+
# add extra columns to gen
|
237
|
+
tmp = zeros((gen.shape[0], shift))
|
238
|
+
if gen.shape[1] >= mu_Qmin:
|
239
|
+
gen = c_[gen[:, 0:IDX.gen.PMIN + 1], tmp, gen[:, mu_Pmax:mu_Qmin]]
|
240
|
+
else:
|
241
|
+
gen = c_[gen[:, 0:IDX.gen.PMIN + 1], tmp]
|
242
|
+
|
243
|
+
# ----- branch -----
|
244
|
+
# use the version 1 values for column names
|
245
|
+
shift = IDX.branch.PF - IDX.branch.BR_STATUS - 1
|
246
|
+
tmp = array([IDX.branch.PF, IDX.branch.QF, IDX.branch.PT,
|
247
|
+
IDX.branch.QT, IDX.branch.MU_SF, IDX.branch.MU_ST]) - shift
|
248
|
+
Pf, Qf, Pt, Qt, mu_Sf, mu_St = tmp
|
249
|
+
|
250
|
+
# add extra columns to branch
|
251
|
+
tmp = ones((branch.shape[0], 1)) * array([-360, 360])
|
252
|
+
tmp2 = zeros((branch.shape[0], 2))
|
253
|
+
if branch.shape[1] >= mu_St - 1:
|
254
|
+
branch = c_[branch[:, 0:IDX.branch.BR_STATUS + 1], tmp, branch[:, IDX.branch.PF - 1:IDX.branch.MU_ST + 1], tmp2]
|
255
|
+
elif branch.shape[1] >= IDX.branch.QT - 1:
|
256
|
+
branch = c_[branch[:, 0:IDX.branch.BR_STATUS + 1], tmp, branch[:, IDX.branch.PF - 1:IDX.branch.QT + 1]]
|
257
|
+
else:
|
258
|
+
branch = c_[branch[:, 0:IDX.branch.BR_STATUS + 1], tmp]
|
259
|
+
|
260
|
+
return gen, branch
|
261
|
+
|
262
|
+
|
263
|
+
def savecase(fname, ppc, comment=None, version='2'):
|
264
|
+
"""Saves a PYPOWER case file, given a filename and the data.
|
265
|
+
|
266
|
+
Writes a PYPOWER case file, given a filename and data dict. The C{fname}
|
267
|
+
parameter is the name of the file to be created or overwritten. Returns
|
268
|
+
the filename, with extension added if necessary. The optional C{comment}
|
269
|
+
argument is either string (single line comment) or a list of strings which
|
270
|
+
are inserted as comments. When using a PYPOWER case dict, if the
|
271
|
+
optional C{version} argument is '1' it will modify the data matrices to
|
272
|
+
version 1 format before saving.
|
273
|
+
|
274
|
+
@author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
|
275
|
+
Autonoma de Manizales)
|
276
|
+
@author: Ray Zimmerman (PSERC Cornell)
|
277
|
+
"""
|
278
|
+
ppc_ver = ppc["version"] = version
|
279
|
+
baseMVA, bus, gen, branch = \
|
280
|
+
ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]
|
281
|
+
areas = ppc["areas"] if "areas" in ppc else None
|
282
|
+
gencost = ppc["gencost"] if "gencost" in ppc else None
|
283
|
+
|
284
|
+
# modifications for version 1 format
|
285
|
+
if ppc_ver == "1":
|
286
|
+
raise NotImplementedError
|
287
|
+
|
288
|
+
# verify valid filename
|
289
|
+
l = len(fname)
|
290
|
+
rootname = ""
|
291
|
+
if l > 2:
|
292
|
+
if fname[-3:] == ".py":
|
293
|
+
rootname = fname[:-3]
|
294
|
+
extension = ".py"
|
295
|
+
elif l > 4:
|
296
|
+
if fname[-4:] == ".mat":
|
297
|
+
rootname = fname[:-4]
|
298
|
+
extension = ".mat"
|
299
|
+
|
300
|
+
if not rootname:
|
301
|
+
rootname = fname
|
302
|
+
extension = ".py"
|
303
|
+
fname = rootname + extension
|
304
|
+
|
305
|
+
indent = ' ' # four spaces
|
306
|
+
indent2 = indent + indent
|
307
|
+
|
308
|
+
# open and write the file
|
309
|
+
if extension == ".mat": # MAT-file
|
310
|
+
ppc_mat = {}
|
311
|
+
ppc_mat['version'] = ppc_ver
|
312
|
+
ppc_mat['baseMVA'] = baseMVA
|
313
|
+
ppc_keys = ['bus', 'gen', 'branch']
|
314
|
+
# Assign non-scalar values as NumPy arrays
|
315
|
+
for key in ppc_keys:
|
316
|
+
ppc_mat[key] = array(ppc[key])
|
317
|
+
if 'areas' in ppc:
|
318
|
+
ppc_mat['areas'] = array(ppc['areas'])
|
319
|
+
if 'gencost' in ppc:
|
320
|
+
ppc_mat['gencost'] = array(ppc['gencost'])
|
321
|
+
if "A" in ppc and len(ppc["A"]) > 0:
|
322
|
+
ppc_mat["A"] = array(ppc["A"])
|
323
|
+
if "l" in ppc and len(ppc["l"]) > 0:
|
324
|
+
ppc_mat["l"] = array(ppc["l"])
|
325
|
+
if "u" in ppc and len(ppc["u"]) > 0:
|
326
|
+
ppc_mat["u"] = array(ppc["u"])
|
327
|
+
if "N" in ppc and len(ppc["N"]) > 0:
|
328
|
+
ppc_mat["N"] = array(ppc["N"])
|
329
|
+
if "H" in ppc and len(ppc["H"]) > 0:
|
330
|
+
ppc_mat["H"] = array(ppc["H"])
|
331
|
+
if "fparm" in ppc and len(ppc["fparm"]) > 0:
|
332
|
+
ppc_mat["fparm"] = array(ppc["fparm"])
|
333
|
+
ppc_mat["Cw"] = array(ppc["Cw"])
|
334
|
+
if 'z0' in ppc or 'zl' in ppc or 'zu' in ppc:
|
335
|
+
if 'z0' in ppc and len(ppc['z0']) > 0:
|
336
|
+
ppc_mat['z0'] = array(ppc['z0'])
|
337
|
+
if 'zl' in ppc and len(ppc['zl']) > 0:
|
338
|
+
ppc_mat['zl'] = array(ppc['zl'])
|
339
|
+
if 'zu' in ppc and len(ppc['zu']) > 0:
|
340
|
+
ppc_mat['zu'] = array(ppc['zu'])
|
341
|
+
if 'userfcn' in ppc and len(ppc['userfcn']) > 0:
|
342
|
+
ppc_mat['userfcn'] = array(ppc['userfcn'])
|
343
|
+
elif 'userfcn' in ppc:
|
344
|
+
ppc_mat['userfcn'] = ppc['userfcn']
|
345
|
+
for key in ['x', 'f']:
|
346
|
+
if key in ppc:
|
347
|
+
ppc_mat[key] = ppc[key]
|
348
|
+
for key in ['lin', 'order', 'nln', 'var', 'raw', 'mu']:
|
349
|
+
if key in ppc:
|
350
|
+
ppc_mat[key] = array(ppc[key])
|
351
|
+
|
352
|
+
savemat(fname, ppc_mat)
|
353
|
+
else: # Python file
|
354
|
+
try:
|
355
|
+
fd = open(fname, "wb")
|
356
|
+
except Exception as detail:
|
357
|
+
logger.debug("savecase: %s.\n" % detail)
|
358
|
+
return fname
|
359
|
+
|
360
|
+
# function header, etc.
|
361
|
+
if ppc_ver == "1":
|
362
|
+
raise NotImplementedError
|
363
|
+
# if (areas != None) and (gencost != None) and (len(gencost) > 0):
|
364
|
+
# fd.write('function [baseMVA, bus, gen, branch, areas, gencost] = %s\n' % rootname)
|
365
|
+
# else:
|
366
|
+
# fd.write('function [baseMVA, bus, gen, branch] = %s\n' % rootname)
|
367
|
+
# prefix = ''
|
368
|
+
else:
|
369
|
+
fd.write('def %s():\n' % basename(rootname))
|
370
|
+
prefix = 'ppc'
|
371
|
+
if comment:
|
372
|
+
if isinstance(comment, str):
|
373
|
+
fd.write('#%s\n' % comment)
|
374
|
+
elif isinstance(comment, list):
|
375
|
+
for c in comment:
|
376
|
+
fd.write('#%s\n' % c)
|
377
|
+
fd.write('\n%s## PYPOWER Case Format : Version %s\n' % (indent, ppc_ver))
|
378
|
+
if ppc_ver != "1":
|
379
|
+
fd.write("%sppc = {'version': '%s'}\n" % (indent, ppc_ver))
|
380
|
+
fd.write('\n%s##----- Power Flow Data -----##\n' % indent)
|
381
|
+
fd.write('%s## system MVA base\n' % indent)
|
382
|
+
fd.write("%s%s['baseMVA'] = %.9g\n" % (indent, prefix, baseMVA))
|
383
|
+
|
384
|
+
# bus data
|
385
|
+
ncols = bus.shape[1]
|
386
|
+
fd.write('\n%s## bus data\n' % indent)
|
387
|
+
fd.write('%s# bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin' % indent)
|
388
|
+
if ncols >= IDX.bus.MU_VMIN + 1: # opf SOLVED, save with lambda's & mu's
|
389
|
+
fd.write('lam_P lam_Q mu_Vmax mu_Vmin')
|
390
|
+
fd.write("\n%s%s['bus'] = array([\n" % (indent, prefix))
|
391
|
+
if ncols < IDX.bus.MU_VMIN + 1: # opf NOT SOLVED, save without lambda's & mu's
|
392
|
+
for i in range(bus.shape[0]):
|
393
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' %
|
394
|
+
((indent2,) + tuple(bus[i, :IDX.bus.VMIN + 1])))
|
395
|
+
else: # opf SOLVED, save with lambda's & mu's
|
396
|
+
for i in range(bus.shape[0]):
|
397
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % (
|
398
|
+
(indent2,) + tuple(bus[i, :IDX.bus.MU_VMIN + 1])))
|
399
|
+
fd.write('%s])\n' % indent)
|
400
|
+
|
401
|
+
# generator data
|
402
|
+
ncols = gen.shape[1]
|
403
|
+
fd.write('\n%s## generator data\n' % indent)
|
404
|
+
fd.write('%s# bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin' % indent)
|
405
|
+
if ppc_ver != "1":
|
406
|
+
fd.write(' Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf')
|
407
|
+
if ncols >= IDX.gen.MU_QMIN + 1: # opf SOLVED, save with mu's
|
408
|
+
fd.write(' mu_Pmax mu_Pmin mu_Qmax mu_Qmin')
|
409
|
+
fd.write("\n%s%s['gen'] = array([\n" % (indent, prefix))
|
410
|
+
if ncols < IDX.gen.MU_QMIN + 1: # opf NOT SOLVED, save without mu's
|
411
|
+
if ppc_ver == "1":
|
412
|
+
for i in range(gen.shape[0]):
|
413
|
+
fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' %
|
414
|
+
((indent2,) + tuple(gen[i, :IDX.gen.PMIN + 1])))
|
415
|
+
else:
|
416
|
+
for i in range(gen.shape[0]):
|
417
|
+
fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g],\n' % (
|
418
|
+
(indent2,) + tuple(gen[i, :IDX.gen.APF + 1])))
|
419
|
+
else:
|
420
|
+
if ppc_ver == "1":
|
421
|
+
for i in range(gen.shape[0]):
|
422
|
+
fd.write(
|
423
|
+
'%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' %
|
424
|
+
((indent2,) + tuple(gen[i, : IDX.gen.MU_QMIN + 1])))
|
425
|
+
else:
|
426
|
+
for i in range(gen.shape[0]):
|
427
|
+
fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % (
|
428
|
+
(indent2,) + tuple(gen[i, :IDX.gen.MU_QMIN + 1])))
|
429
|
+
fd.write('%s])\n' % indent)
|
430
|
+
|
431
|
+
# branch data
|
432
|
+
ncols = branch.shape[1]
|
433
|
+
fd.write('\n%s## branch data\n' % indent)
|
434
|
+
fd.write('%s# fbus tbus r x b rateA rateB rateC ratio angle status' % indent)
|
435
|
+
if ppc_ver != "1":
|
436
|
+
fd.write(' angmin angmax')
|
437
|
+
if ncols >= IDX.branch.QT + 1: # power flow SOLVED, save with line flows
|
438
|
+
fd.write(' Pf Qf Pt Qt')
|
439
|
+
if ncols >= IDX.branch.MU_ST + 1: # opf SOLVED, save with mu's
|
440
|
+
fd.write(' mu_Sf mu_St')
|
441
|
+
if ppc_ver != "1":
|
442
|
+
fd.write(' mu_angmin mu_angmax')
|
443
|
+
fd.write('\n%s%s[\'branch\'] = array([\n' % (indent, prefix))
|
444
|
+
if ncols < IDX.branch.QT + 1: # power flow NOT SOLVED, save without line flows or mu's
|
445
|
+
if ppc_ver == "1":
|
446
|
+
for i in range(branch.shape[0]):
|
447
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d],\n' %
|
448
|
+
((indent2,) + tuple(branch[i, :IDX.branch.BR_STATUS + 1])))
|
449
|
+
else:
|
450
|
+
for i in range(branch.shape[0]):
|
451
|
+
fd.write(
|
452
|
+
'%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' %
|
453
|
+
((indent2,) + tuple(branch[i, : IDX.branch.ANGMAX + 1])))
|
454
|
+
elif ncols < IDX.branch.MU_ST + 1: # power flow SOLVED, save with line flows but without mu's
|
455
|
+
if ppc_ver == "1":
|
456
|
+
for i in range(branch.shape[0]):
|
457
|
+
fd.write(
|
458
|
+
'%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f],\n' %
|
459
|
+
((indent2,) + tuple(branch[i, : IDX.branch.QT + 1])))
|
460
|
+
else:
|
461
|
+
for i in range(branch.shape[0]):
|
462
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % (
|
463
|
+
(indent2,) + tuple(branch[i, :IDX.branch.QT + 1])))
|
464
|
+
else: # opf SOLVED, save with lineflows & mu's
|
465
|
+
if ppc_ver == "1":
|
466
|
+
for i in range(branch.shape[0]):
|
467
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % (
|
468
|
+
(indent2,) + tuple(branch[i, :IDX.branch.MU_ST + 1])))
|
469
|
+
else:
|
470
|
+
for i in range(branch.shape[0]):
|
471
|
+
fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % (
|
472
|
+
(indent2,) + tuple(branch[i, :IDX.branch.MU_ANGMAX + 1])))
|
473
|
+
fd.write('%s])\n' % indent)
|
474
|
+
|
475
|
+
# OPF data
|
476
|
+
if (areas is not None) and (len(areas) > 0) or (gencost is not None) and (len(gencost) > 0):
|
477
|
+
fd.write('\n%s##----- OPF Data -----##' % indent)
|
478
|
+
if (areas is not None) and (len(areas) > 0):
|
479
|
+
# area data
|
480
|
+
fd.write('\n%s## area data\n' % indent)
|
481
|
+
fd.write('%s# area refbus\n' % indent)
|
482
|
+
fd.write("%s%s['areas'] = array([\n" % (indent, prefix))
|
483
|
+
if len(areas) > 0:
|
484
|
+
for i in range(areas.shape[0]):
|
485
|
+
fd.write('%s[%d, %d],\n' % ((indent2,) + tuple(areas[i, :IDX.area.PRICE_REF_BUS + 1])))
|
486
|
+
fd.write('%s])\n' % indent)
|
487
|
+
if gencost is not None and len(gencost) > 0:
|
488
|
+
# generator cost data
|
489
|
+
fd.write('\n%s## generator cost data\n' % indent)
|
490
|
+
fd.write('%s# 1 startup shutdown n x1 y1 ... xn yn\n' % indent)
|
491
|
+
fd.write('%s# 2 startup shutdown n c(n-1) ... c0\n' % indent)
|
492
|
+
fd.write('%s%s[\'gencost\'] = array([\n' % (indent, prefix))
|
493
|
+
if len(gencost > 0):
|
494
|
+
if any(gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR):
|
495
|
+
n1 = 2 * max(gencost[gencost[:, IDX.cost.MODEL] == IDX.cost.PW_LINEAR, IDX.cost.NCOST])
|
496
|
+
else:
|
497
|
+
n1 = 0
|
498
|
+
if any(gencost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL):
|
499
|
+
n2 = max(gencost[gencost[:, IDX.cost.MODEL] == IDX.cost.POLYNOMIAL, IDX.cost.NCOST])
|
500
|
+
else:
|
501
|
+
n2 = 0
|
502
|
+
n = int(max([n1, n2]))
|
503
|
+
if gencost.shape[1] < n + 4:
|
504
|
+
logger.debug('savecase: gencost data claims it has more columns than it does\n')
|
505
|
+
template = '%s[%d, %.9g, %.9g, %d'
|
506
|
+
for i in range(n):
|
507
|
+
template = template + ', %.9g'
|
508
|
+
template = template + '],\n'
|
509
|
+
for i in range(gencost.shape[0]):
|
510
|
+
fd.write(template % ((indent2,) + tuple(gencost[i])))
|
511
|
+
fd.write('%s])\n' % indent)
|
512
|
+
|
513
|
+
# generalized OPF user data
|
514
|
+
if ("A" in ppc) and (len(ppc["A"]) > 0) or ("N" in ppc) and (len(ppc["N"]) > 0):
|
515
|
+
fd.write('\n%s##----- Generalized OPF User Data -----##' % indent)
|
516
|
+
|
517
|
+
# user constraints
|
518
|
+
if ("A" in ppc) and (len(ppc["A"]) > 0):
|
519
|
+
# A
|
520
|
+
fd.write('\n%s## user constraints\n' % indent)
|
521
|
+
print_sparse(fd, prefix + "['A']", ppc["A"])
|
522
|
+
if ("l" in ppc) and (len(ppc["l"]) > 0) and ("u" in ppc) and (len(ppc["u"]) > 0):
|
523
|
+
fd.write('%slu = array([\n' % indent)
|
524
|
+
for i in range(len(ppc["l"])):
|
525
|
+
fd.write('%s[%.9g, %.9g],\n' % (indent2, ppc["l"][i], ppc["u"][i]))
|
526
|
+
fd.write('%s])\n' % indent)
|
527
|
+
fd.write("%s%s['l'] = lu[:, 0]\n" % (indent, prefix))
|
528
|
+
fd.write("%s%s['u'] = lu[:, 1]\n\n" % (indent, prefix))
|
529
|
+
elif ("l" in ppc) and (len(ppc["l"]) > 0):
|
530
|
+
fd.write("%s%s['l'] = array([\n" % (indent, prefix))
|
531
|
+
for i in range(len(l)):
|
532
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["l"][i]))
|
533
|
+
fd.write('%s])\n\n' % indent)
|
534
|
+
elif ("u" in ppc) and (len(ppc["u"]) > 0):
|
535
|
+
fd.write("%s%s['u'] = array([\n" % (indent, prefix))
|
536
|
+
for i in range(len(l)):
|
537
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["u"][i]))
|
538
|
+
fd.write('%s])\n\n' % indent)
|
539
|
+
|
540
|
+
# user costs
|
541
|
+
if ("N" in ppc) and (len(ppc["N"]) > 0):
|
542
|
+
fd.write('\n%s## user costs\n' % indent)
|
543
|
+
print_sparse(fd, prefix + "['N']", ppc["N"])
|
544
|
+
if ("H" in ppc) and (len(ppc["H"]) > 0):
|
545
|
+
print_sparse(fd, prefix + "['H']", ppc["H"])
|
546
|
+
if ("fparm" in ppc) and (len(ppc["fparm"]) > 0):
|
547
|
+
fd.write("%sCw_fparm = array([\n" % indent)
|
548
|
+
for i in range(ppc["Cw"]):
|
549
|
+
fd.write('%s[%.9g, %d, %.9g, %.9g, %.9g],\n' %
|
550
|
+
((indent2,) + tuple(ppc["Cw"][i]) + tuple(ppc["fparm"][i, :])))
|
551
|
+
fd.write('%s])\n' % indent)
|
552
|
+
fd.write('%s%s[\'Cw\'] = Cw_fparm[:, 0]\n' % (indent, prefix))
|
553
|
+
fd.write("%s%s['fparm'] = Cw_fparm[:, 1:5]\n" % (indent, prefix))
|
554
|
+
else:
|
555
|
+
fd.write("%s%s['Cw'] = array([\n" % (indent, prefix))
|
556
|
+
for i in range(len(ppc["Cw"])):
|
557
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["Cw"][i]))
|
558
|
+
fd.write('%s])\n' % indent)
|
559
|
+
|
560
|
+
# user vars
|
561
|
+
if ('z0' in ppc) or ('zl' in ppc) or ('zu' in ppc):
|
562
|
+
fd.write('\n%s## user vars\n' % indent)
|
563
|
+
if ('z0' in ppc) and (len(ppc['z0']) > 0):
|
564
|
+
fd.write('%s%s["z0"] = array([\n' % (indent, prefix))
|
565
|
+
for i in range(len(ppc['z0'])):
|
566
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["z0"]))
|
567
|
+
fd.write('%s])\n' % indent)
|
568
|
+
if ('zl' in ppc) and (len(ppc['zl']) > 0):
|
569
|
+
fd.write('%s%s["zl"] = array([\n' % (indent2, prefix))
|
570
|
+
for i in range(len(ppc['zl'])):
|
571
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["zl"]))
|
572
|
+
fd.write('%s])\n' % indent)
|
573
|
+
if ('zu' in ppc) and (len(ppc['zu']) > 0):
|
574
|
+
fd.write('%s%s["zu"] = array([\n' % (indent, prefix))
|
575
|
+
for i in range(len(ppc['zu'])):
|
576
|
+
fd.write('%s[%.9g],\n' % (indent2, ppc["zu"]))
|
577
|
+
fd.write('%s])\n' % indent)
|
578
|
+
|
579
|
+
# execute userfcn callbacks for 'savecase' stage
|
580
|
+
if 'userfcn' in ppc:
|
581
|
+
run_userfcn(ppc["userfcn"], 'savecase', ppc, fd, prefix)
|
582
|
+
|
583
|
+
fd.write('\n%sreturn ppc\n' % indent)
|
584
|
+
|
585
|
+
# close file
|
586
|
+
fd.close()
|
587
|
+
|
588
|
+
return fname
|
589
|
+
|
590
|
+
|
591
|
+
def print_sparse(fd, varname, A):
|
592
|
+
A = A.tocoo()
|
593
|
+
i, j, s = A.row, A.col, A.data
|
594
|
+
m, n = A.shape
|
595
|
+
|
596
|
+
if len(s) == 0:
|
597
|
+
fd.write('%s = sparse((%d, %d))\n' % (varname, m, n))
|
598
|
+
else:
|
599
|
+
fd.write('ijs = array([\n')
|
600
|
+
for k in range(len(i)):
|
601
|
+
fd.write('[%d, %d, %.9g],\n' % (i[k], j[k], s[k]))
|
602
|
+
|
603
|
+
fd.write('])\n')
|
604
|
+
fd.write('%s = sparse(ijs[:, 0], ijs[:, 1], ijs[:, 2], %d, %d)\n' % (varname, m, n))
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""
|
2
|
+
Module for build matrices.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from ams.pypower.make.matrices import (makeAang, makeApq, makeAvl, makeAy,
|
6
|
+
makeB, makeBdc,
|
7
|
+
makeLODF, makePTDF,
|
8
|
+
makeSbus, makeYbus) # NOQA
|
9
|
+
from ams.pypower.make.pdv import (dSbus_dV, dIbr_dV, dSbr_dV,
|
10
|
+
d2Sbus_dV2, d2AIbr_dV2, d2ASbr_dV2,
|
11
|
+
d2Ibr_dV2, d2Sbr_dV2, dAbr_dV) # NOQA
|