1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """Converts external to internal indexing.
18 """
19
20 import sys
21
22 from copy import deepcopy
23
24 from numpy import array, zeros, argsort, arange, concatenate
25 from numpy import flatnonzero as find
26
27 from scipy.sparse import issparse, vstack, hstack, csr_matrix as sparse
28
29 from idx_bus import PQ, PV, REF, NONE, BUS_I, BUS_TYPE
30 from idx_gen import GEN_BUS, GEN_STATUS
31 from idx_brch import F_BUS, T_BUS, BR_STATUS
32 from idx_area import PRICE_REF_BUS
33
34 from get_reorder import get_reorder
35 from run_userfcn import run_userfcn
36
37
38 -def ext2int(ppc, val_or_field=None, ordering=None, dim=0):
39 """Converts external to internal indexing.
40
41 This function performs several different tasks, depending on the
42 arguments passed.
43
44 1. C{ppc = ext2int(ppc)}
45
46 If the input is a single PYPOWER case dict, then all isolated
47 buses, off-line generators and branches are removed along with any
48 generators, branches or areas connected to isolated buses. Then the
49 buses are renumbered consecutively, beginning at 0, and the
50 generators are sorted by increasing bus number. All of the related
51 indexing information and the original data matrices are stored under
52 the 'order' key of the dict to be used by C{int2ext} to perform
53 the reverse conversions. If the case is already using internal
54 numbering it is returned unchanged.
55
56 Example::
57 ppc = ext2int(ppc);
58
59 2. C{val = ext2int(ppc, val, ordering)}
60
61 C{val = ext2int(ppc, val, ordering, dim)}
62
63 C{ppc = ext2int(ppc, field, ordering)}
64
65 C{ppc = ext2int(ppc, field, ordering, dim)}
66
67 When given a case dict that has already been converted to
68 internal indexing, this function can be used to convert other data
69 structures as well by passing in 2 or 3 extra parameters in
70 addition to the case dict. If the value passed in the 2nd
71 argument is a column vector, it will be converted according to the
72 C{ordering} specified by the 3rd argument (described below). If C{val}
73 is an n-dimensional matrix, then the optional 4th argument (C{dim},
74 default = 0) can be used to specify which dimension to reorder.
75 The return value in this case is the value passed in, converted
76 to internal indexing.
77
78 If the 2nd argument is a string or list of strings, it
79 specifies a field in the case dict whose value should be
80 converted as described above. In this case, the converted value
81 is stored back in the specified field, the original value is
82 saved for later use and the updated case dict is returned.
83 If C{field} is a list of strings, they specify nested fields.
84
85 The 3rd argument, C{ordering}, is used to indicate whether the data
86 corresponds to bus-, gen- or branch-ordered data. It can be one
87 of the following three strings: 'bus', 'gen' or 'branch'. For
88 data structures with multiple blocks of data, ordered by bus,
89 gen or branch, they can be converted with a single call by
90 specifying C{ordering} as a list of strings.
91
92 Any extra elements, rows, columns, etc. beyond those indicated
93 in C{ordering}, are not disturbed.
94
95 @see: L{int2ext}
96
97 @author: Ray Zimmerman (PSERC Cornell)
98 @author: Richard Lincoln
99 """
100 ppc = deepcopy(ppc)
101 if val_or_field is None:
102 first = 'order' not in ppc
103 if first or ppc["order"]["state"] == 'e':
104
105 if first:
106 o = {
107 'ext': {
108 'bus': None,
109 'branch': None,
110 'gen': None
111 },
112 'bus': { 'e2i': None,
113 'i2e': None,
114 'status': {} },
115 'gen': { 'e2i': None,
116 'i2e': None,
117 'status': {} },
118 'branch': { 'status': {} }
119 }
120 else:
121 o = ppc["order"]
122
123
124 nb = ppc["bus"].shape[0]
125 ng = ppc["gen"].shape[0]
126 ng0 = ng
127 if 'A' in ppc:
128 dc = True if ppc["A"].shape[1] < (2 * nb + 2 * ng) else False
129 elif 'N' in ppc:
130 dc = True if ppc["N"].shape[1] < (2 * nb + 2 * ng) else False
131 else:
132 dc = False
133
134
135 if 'ext' not in o: o['ext'] = {}
136 o["ext"]["bus"] = ppc["bus"].copy()
137 o["ext"]["branch"] = ppc["branch"].copy()
138 o["ext"]["gen"] = ppc["gen"].copy()
139 if 'areas' in ppc:
140 if len(ppc["areas"]) == 0:
141 del ppc['areas']
142 else:
143 o["ext"]["areas"] = ppc["areas"].copy()
144
145
146 bt = ppc["bus"][:, BUS_TYPE]
147 err = find(~((bt == PQ) | (bt == PV) | (bt == REF) | (bt == NONE)))
148 if len(err) > 0:
149 sys.stderr.write('ext2int: bus %d has an invalid BUS_TYPE\n' % err)
150
151
152
153 n2i = sparse((range(nb), (ppc["bus"][:, BUS_I], zeros(nb))),
154 shape=(max(ppc["bus"][:, BUS_I]) + 1, 1))
155 n2i = array( n2i.todense().flatten() )[0, :]
156 bs = (bt != NONE)
157 o["bus"]["status"]["on"] = find( bs )
158 o["bus"]["status"]["off"] = find( ~bs )
159 gs = ( (ppc["gen"][:, GEN_STATUS] > 0) &
160 bs[ n2i[ppc["gen"][:, GEN_BUS].astype(int)] ] )
161 o["gen"]["status"]["on"] = find( gs )
162 o["gen"]["status"]["off"] = find( ~gs )
163 brs = ( ppc["branch"][:, BR_STATUS].astype(int) &
164 bs[n2i[ppc["branch"][:, F_BUS].astype(int)]] &
165 bs[n2i[ppc["branch"][:, T_BUS].astype(int)]] ).astype(bool)
166 o["branch"]["status"]["on"] = find( brs )
167 o["branch"]["status"]["off"] = find( ~brs )
168 if 'areas' in ppc:
169 ar = bs[ n2i[ppc["areas"][:, PRICE_REF_BUS].astype(int)] ]
170 o["areas"] = {"status": {}}
171 o["areas"]["status"]["on"] = find( ar )
172 o["areas"]["status"]["off"] = find( ~ar )
173
174
175 if len(o["bus"]["status"]["off"]) > 0:
176
177 ppc["bus"] = ppc["bus"][o["bus"]["status"]["on"], :]
178 if len(o["branch"]["status"]["off"]) > 0:
179
180 ppc["branch"] = ppc["branch"][o["branch"]["status"]["on"], :]
181 if len(o["gen"]["status"]["off"]) > 0:
182
183 ppc["gen"] = ppc["gen"][o["gen"]["status"]["on"], :]
184 if 'areas' in ppc and (len(o["areas"]["status"]["off"]) > 0):
185
186 ppc["areas"] = ppc["areas"][o["areas"]["status"]["on"], :]
187
188
189 nb = ppc["bus"].shape[0]
190
191
192 o["bus"]["i2e"] = ppc["bus"][:, BUS_I].copy()
193 o["bus"]["e2i"] = zeros(max(o["bus"]["i2e"]) + 1)
194 o["bus"]["e2i"][o["bus"]["i2e"].astype(int)] = arange(nb)
195 ppc["bus"][:, BUS_I] = \
196 o["bus"]["e2i"][ ppc["bus"][:, BUS_I].astype(int) ].copy()
197 ppc["gen"][:, GEN_BUS] = \
198 o["bus"]["e2i"][ ppc["gen"][:, GEN_BUS].astype(int) ].copy()
199 ppc["branch"][:, F_BUS] = \
200 o["bus"]["e2i"][ ppc["branch"][:, F_BUS].astype(int) ].copy()
201 ppc["branch"][:, T_BUS] = \
202 o["bus"]["e2i"][ ppc["branch"][:, T_BUS].astype(int) ].copy()
203 if 'areas' in ppc:
204 ppc["areas"][:, PRICE_REF_BUS] = \
205 o["bus"]["e2i"][ ppc["areas"][:,
206 PRICE_REF_BUS].astype(int) ].copy()
207
208
209 o["gen"]["e2i"] = argsort(ppc["gen"][:, GEN_BUS])
210 o["gen"]["i2e"] = argsort(o["gen"]["e2i"])
211
212 ppc["gen"] = ppc["gen"][o["gen"]["e2i"].astype(int), :]
213
214 if 'int' in o:
215 del o['int']
216 o["state"] = 'i'
217 ppc["order"] = o
218
219
220 if 'gencost' in ppc:
221 ordering = ['gen']
222 if ppc["gencost"].shape[0] == (2 * ng0):
223 ordering.append('gen')
224 ppc = ext2int(ppc, 'gencost', ordering)
225 if 'A' in ppc or 'N' in ppc:
226 if dc:
227 ordering = ['bus', 'gen']
228 else:
229 ordering = ['bus', 'bus', 'gen', 'gen']
230 if 'A' in ppc:
231 ppc = ext2int(ppc, 'A', ordering, 1)
232 if 'N' in ppc:
233 ppc = ext2int(ppc, 'N', ordering, 1)
234
235
236 if 'userfcn' in ppc:
237 ppc = run_userfcn(ppc['userfcn'], 'ext2int', ppc)
238 else:
239 if isinstance(val_or_field, str) or isinstance(val_or_field, list):
240
241 field = val_or_field
242
243 if isinstance(field, str):
244 key = '["%s"]' % field
245 else:
246 key = '["%s"]' % '"]["'.join(field)
247
248 v_ext = ppc["order"]["ext"]
249 for fld in field:
250 if fld not in v_ext:
251 v_ext[fld] = {}
252 v_ext = v_ext[fld]
253
254 exec 'ppc["order"]["ext"]%s = ppc%s.copy()' % (key, key)
255 exec 'ppc%s = ext2int(ppc, ppc%s, ordering, dim)' % (key, key)
256
257 else:
258
259 val = val_or_field.copy()
260
261 o = ppc["order"]
262 if isinstance(ordering, str):
263 if ordering == 'gen':
264 idx = o[ordering]["status"]["on"][ o[ordering]["e2i"] ]
265 else:
266 idx = o[ordering]["status"]["on"]
267 val = get_reorder(val, idx, dim)
268 else:
269 b = 0
270 new_v = []
271 for ord in ordering:
272 n = o["ext"][ord].shape[0]
273 v = get_reorder(val, b + arange(n), dim)
274 new_v.append( ext2int(ppc, v, ord, dim) )
275 b = b + n
276 n = val.shape[dim]
277 if n > b:
278 v = get_reorder(val, arange(b, n), dim)
279 new_v.append(v)
280
281 if issparse(new_v[0]):
282 if dim == 0:
283 vstack(new_v, 'csr')
284 elif dim == 1:
285 hstack(new_v, 'csr')
286 else:
287 raise ValueError, 'dim (%d) may be 0 or 1' % dim
288 else:
289 val = concatenate(new_v, dim)
290 return val
291
292 return ppc
293
294
295 -def ext2int1(bus, gen, branch, areas=None):
296 """Converts from (possibly non-consecutive) external bus numbers to
297 consecutive internal bus numbers which start at 1. Changes are made
298 to BUS, GEN, BRANCH and optionally AREAS matrices, which are returned
299 along with a vector of indices I2E that can be passed to INT2EXT to
300 perform the reverse conversion.
301
302 @see: L{int2ext}
303 @see: U{http://www.pserc.cornell.edu/matpower/}
304 """
305 i2e = bus[:, BUS_I].astype(int)
306 e2i = zeros(max(i2e) + 1)
307 e2i[i2e] = arange(bus.shape[0])
308
309 bus[:, BUS_I] = e2i[ bus[:, BUS_I].astype(int) ]
310 gen[:, GEN_BUS] = e2i[ gen[:, GEN_BUS].astype(int) ]
311 branch[:, F_BUS] = e2i[ branch[:, F_BUS].astype(int) ]
312 branch[:, T_BUS] = e2i[ branch[:, T_BUS].astype(int) ]
313 if areas is not None and len(areas) > 0:
314 areas[:, PRICE_REF_BUS] = e2i[ areas[:, PRICE_REF_BUS].astype(int) ]
315
316 return i2e, bus, gen, branch, areas
317
318 return i2e, bus, gen, branch
319