Package pypower :: Module ext2int
[hide private]
[frames] | no frames]

Source Code for Module pypower.ext2int

  1  # Copyright (C) 1996-2011 Power System Engineering Research Center (PSERC) 
  2  # Copyright (C) 2011 Richard Lincoln 
  3  # 
  4  # PYPOWER is free software: you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published 
  6  # by the Free Software Foundation, either version 3 of the License, 
  7  # or (at your option) any later version. 
  8  # 
  9  # PYPOWER is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with PYPOWER. If not, see <http://www.gnu.org/licenses/>. 
 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: # nargin == 1 102 first = 'order' not in ppc 103 if first or ppc["order"]["state"] == 'e': 104 ## initialize order 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 ## sizes 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 ## save data matrices with external ordering 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: ## if areas field is empty 141 del ppc['areas'] ## delete it (so it's ignored) 142 else: ## otherwise 143 o["ext"]["areas"] = ppc["areas"].copy() ## save it 144 145 ## check that all buses have a valid BUS_TYPE 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 ## determine which buses, branches, gens are connected and 152 ## in-service 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, :] # as 1D array 156 bs = (bt != NONE) ## bus status 157 o["bus"]["status"]["on"] = find( bs ) ## connected 158 o["bus"]["status"]["off"] = find( ~bs ) ## isolated 159 gs = ( (ppc["gen"][:, GEN_STATUS] > 0) & ## gen status 160 bs[ n2i[ppc["gen"][:, GEN_BUS].astype(int)] ] ) 161 o["gen"]["status"]["on"] = find( gs ) ## on and connected 162 o["gen"]["status"]["off"] = find( ~gs ) ## off or isolated 163 brs = ( ppc["branch"][:, BR_STATUS].astype(int) & ## branch status 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 ) ## on and conn 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 ## delete stuff that is "out" 175 if len(o["bus"]["status"]["off"]) > 0: 176 # ppc["bus"][o["bus"]["status"]["off"], :] = array([]) 177 ppc["bus"] = ppc["bus"][o["bus"]["status"]["on"], :] 178 if len(o["branch"]["status"]["off"]) > 0: 179 # ppc["branch"][o["branch"]["status"]["off"], :] = array([]) 180 ppc["branch"] = ppc["branch"][o["branch"]["status"]["on"], :] 181 if len(o["gen"]["status"]["off"]) > 0: 182 # ppc["gen"][o["gen"]["status"]["off"], :] = array([]) 183 ppc["gen"] = ppc["gen"][o["gen"]["status"]["on"], :] 184 if 'areas' in ppc and (len(o["areas"]["status"]["off"]) > 0): 185 # ppc["areas"][o["areas"]["status"]["off"], :] = array([]) 186 ppc["areas"] = ppc["areas"][o["areas"]["status"]["on"], :] 187 188 ## update size 189 nb = ppc["bus"].shape[0] 190 191 ## apply consecutive bus numbering 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 ## reorder gens in order of increasing bus number 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 ## update gencost, A and N 220 if 'gencost' in ppc: 221 ordering = ['gen'] ## Pg cost only 222 if ppc["gencost"].shape[0] == (2 * ng0): 223 ordering.append('gen') ## include Qg cost 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 ## execute userfcn callbacks for 'ext2int' stage 236 if 'userfcn' in ppc: 237 ppc = run_userfcn(ppc['userfcn'], 'ext2int', ppc) 238 else: ## convert extra data 239 if isinstance(val_or_field, str) or isinstance(val_or_field, list): 240 ## field 241 field = val_or_field ## rename argument 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 ## value 259 val = val_or_field.copy() ## rename argument 260 261 o = ppc["order"] 262 if isinstance(ordering, str): ## single set 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: ## multiple: sets 269 b = 0 ## base 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: ## the rest 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