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

Source Code for Module pypower.toggle_iflims

  1  # Copyright (C) 2009-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  """Enable or disable set of interface flow constraints. 
 18  """ 
 19   
 20  from sys import stderr 
 21   
 22  from pprint import pprint 
 23   
 24  from numpy import zeros, arange, unique, sign, delete, flatnonzero as find 
 25   
 26  from scipy.sparse import lil_matrix, csr_matrix as sparse 
 27   
 28  from pypower.add_userfcn import add_userfcn 
 29  from pypower.remove_userfcn import remove_userfcn 
 30  from pypower.makeBdc import makeBdc 
 31  from pypower.idx_brch import PF 
 32   
 33   
34 -def toggle_iflims(ppc, on_off):
35 """Enable or disable set of interface flow constraints. 36 37 Enables or disables a set of OPF userfcn callbacks to implement 38 interface flow limits based on a DC flow model. 39 40 These callbacks expect to find an 'if' field in the input C{ppc}, where 41 C{ppc['if']} is a dict with the following fields: 42 - C{map} C{n x 2}, defines each interface in terms of a set of 43 branch indices and directions. Interface I is defined 44 by the set of rows whose 1st col is equal to I. The 45 2nd column is a branch index multiplied by 1 or -1 46 respectively for lines whose orientation is the same 47 as or opposite to that of the interface. 48 - C{lims} C{nif x 3}, defines the DC model flow limits in MW 49 for specified interfaces. The 2nd and 3rd columns specify 50 the lower and upper limits on the (DC model) flow 51 across the interface, respectively. Normally, the lower 52 limit is negative, indicating a flow in the opposite 53 direction. 54 55 The 'int2ext' callback also packages up results and stores them in 56 the following output fields of C{results['if']}: 57 - C{P} - C{nif x 1}, actual flow across each interface in MW 58 - C{mu.l} - C{nif x 1}, shadow price on lower flow limit, ($/MW) 59 - C{mu.u} - C{nif x 1}, shadow price on upper flow limit, ($/MW) 60 61 @see: L{add_userfcn}, L{remove_userfcn}, L{run_userfcn}, 62 L{t.t_case30_userfcns}. 63 64 @author: Ray Zimmerman (PSERC Cornell) 65 @author: Richard Lincoln 66 """ 67 if on_off == 'on': 68 ## check for proper reserve inputs 69 if ('if' not in ppc) | (not isinstance(ppc['if'], dict)) | \ 70 ('map' not in ppc['if']) | \ 71 ('lims' not in ppc['if']): 72 stderr.write('toggle_iflims: case must contain an \'if\' field, a struct defining \'map\' and \'lims\'') 73 74 ## add callback functions 75 ## note: assumes all necessary data included in 1st arg (ppc, om, results) 76 ## so, no additional explicit args are needed 77 ppc = add_userfcn(ppc, 'ext2int', userfcn_iflims_ext2int) 78 ppc = add_userfcn(ppc, 'formulation', userfcn_iflims_formulation) 79 ppc = add_userfcn(ppc, 'int2ext', userfcn_iflims_int2ext) 80 ppc = add_userfcn(ppc, 'printpf', userfcn_iflims_printpf) 81 ppc = add_userfcn(ppc, 'savecase', userfcn_iflims_savecase) 82 elif on_off == 'off': 83 ppc = remove_userfcn(ppc, 'savecase', userfcn_iflims_savecase) 84 ppc = remove_userfcn(ppc, 'printpf', userfcn_iflims_printpf) 85 ppc = remove_userfcn(ppc, 'int2ext', userfcn_iflims_int2ext) 86 ppc = remove_userfcn(ppc, 'formulation', userfcn_iflims_formulation) 87 ppc = remove_userfcn(ppc, 'ext2int', userfcn_iflims_ext2int) 88 else: 89 stderr.write('toggle_iflims: 2nd argument must be either \'on\' or \'off\'') 90 91 return ppc
92 93
94 -def userfcn_iflims_ext2int(ppc, *args):
95 """This is the 'ext2int' stage userfcn callback that prepares the input 96 data for the formulation stage. It expects to find an 'if' field in 97 ppc as described above. The optional args are not currently used. 98 """ 99 ## initialize some things 100 ifmap = ppc['if']['map'] 101 o = ppc['order'] 102 nl0 = o['ext']['branch'].shape[0] ## original number of branches 103 nl = ppc['branch'].shape[0] ## number of on-line branches 104 105 ## save if.map for external indexing 106 ppc['order']['ext']['ifmap'] = ifmap 107 108 ##----- convert stuff to internal indexing ----- 109 e2i = zeros(nl0) 110 e2i[o['branch']['status']['on']] = arange(nl) ## ext->int branch index mapping 111 d = sign(ifmap[:, 1]) 112 br = abs(ifmap[:, 1]).astype(int) 113 ifmap[:, 1] = d * e2i[br] 114 115 ifmap = delete(ifmap, find(ifmap[:, 1] == 0), 0) ## delete branches that are out 116 117 ppc['if']['map'] = ifmap 118 119 return ppc
120 121
122 -def userfcn_iflims_formulation(om, *args):
123 """This is the 'formulation' stage userfcn callback that defines the 124 user costs and constraints for interface flow limits. It expects to 125 find an 'if' field in the ppc stored in om, as described above. The 126 optional args are not currently used. 127 """ 128 ## initialize some things 129 ppc = om.get_ppc() 130 baseMVA, bus, branch = ppc['baseMVA'], ppc['bus'], ppc['branch'] 131 ifmap = ppc['if']['map'] 132 iflims = ppc['if']['lims'] 133 134 ## form B matrices for DC model 135 _, Bf, _, Pfinj = makeBdc(baseMVA, bus, branch) 136 n = Bf.shape[1] ## dim of theta 137 138 ## form constraints 139 ifidx = unique(iflims[:, 0]) ## interface number list 140 nifs = len(ifidx) ## number of interfaces 141 Aif = lil_matrix((nifs, n)) 142 lif = zeros(nifs) 143 uif = zeros(nifs) 144 for k in range(nifs): 145 ## extract branch indices 146 br = ifmap[ifmap[:, 0] == ifidx[k], 1] 147 if len(br) == 0: 148 stderr.write('userfcn_iflims_formulation: interface %d has no in-service branches\n' % k) 149 150 d = sign(br) 151 br = abs(br) 152 Ak = sparse((1, n)) ## Ak = sum( d(i) * Bf(i, :) ) 153 bk = 0 ## bk = sum( d(i) * Pfinj(i) ) 154 for i in range(len(br)): 155 Ak = Ak + d[i] * Bf[br[i], :] 156 bk = bk + d[i] * Pfinj[br[i]] 157 158 Aif[k, :] = Ak 159 lif[k] = iflims[k, 1] / baseMVA - bk 160 uif[k] = iflims[k, 2] / baseMVA - bk 161 162 ## add interface constraint 163 om.add_constraints('iflims', Aif, lif, uif, ['Va']) ## nifs 164 165 return om
166 167
168 -def userfcn_iflims_int2ext(results, *args):
169 """This is the 'int2ext' stage userfcn callback that converts everything 170 back to external indexing and packages up the results. It expects to 171 find an 'if' field in the C{results} dict as described for ppc above. 172 It also expects the results to contain solved branch flows and linear 173 constraints named 'iflims' which are used to populate output fields 174 in C{results['if']}. The optional args are not currently used. 175 """ 176 ## get internal ifmap 177 ifmap = results['if']['map'] 178 iflims = results['if']['lims'] 179 180 ##----- convert stuff back to external indexing ----- 181 results['if']['map'] = results['order']['ext']['ifmap'] 182 183 ##----- results post-processing ----- 184 ifidx = unique(iflims[:, 0]) ## interface number list 185 nifs = len(ifidx) ## number of interfaces 186 results['if']['P'] = zeros(nifs) 187 for k in range(nifs): 188 ## extract branch indices 189 br = ifmap[ifmap[:, 0] == ifidx[k], 1] 190 d = sign(br) 191 br = abs(br) 192 results['if']['P'][k] = sum( d * results['branch'][br, PF] ) 193 194 if 'mu' not in results['if']: 195 results['if']['mu'] = {} 196 results['if']['mu']['l'] = results['lin']['mu']['l']['iflims'] 197 results['if']['mu']['u'] = results['lin']['mu']['u']['iflims'] 198 199 return results
200 201
202 -def userfcn_iflims_printpf(results, fd, ppopt, *args):
203 """This is the 'printpf' stage userfcn callback that pretty-prints the 204 results. It expects a C{results} dict, a file descriptor and a PYPOWER 205 options vector. The optional args are not currently used. 206 """ 207 ##----- print results ----- 208 OUT_ALL = ppopt['OUT_ALL'] 209 # ctol = ppopt['OPF_VIOLATION'] ## constraint violation tolerance 210 ptol = 1e-6 ## tolerance for displaying shadow prices 211 212 if OUT_ALL != 0: 213 iflims = results['if']['lims'] 214 fd.write('\n================================================================================') 215 fd.write('\n| Interface Flow Limits |') 216 fd.write('\n================================================================================') 217 fd.write('\n Interface Shadow Prc Lower Lim Flow Upper Lim Shadow Prc') 218 fd.write('\n # ($/MW) (MW) (MW) (MW) ($/MW) ') 219 fd.write('\n---------- ---------- ---------- ---------- ---------- -----------') 220 ifidx = unique(iflims[:, 0]) ## interface number list 221 nifs = len(ifidx) ## number of interfaces 222 for k in range(nifs): 223 fd.write('\n%6d ', iflims(k, 1)) 224 if results['if']['mu']['l'][k] > ptol: 225 fd.write('%14.3f' % results['if']['mu']['l'][k]) 226 else: 227 fd.write(' - ') 228 229 fd.write('%12.2f%12.2f%12.2f' % (iflims[k, 1], results['if']['P'][k], iflims[k, 2])) 230 if results['if']['mu']['u'][k] > ptol: 231 fd.write('%13.3f' % results['if']['mu']['u'][k]) 232 else: 233 fd.write(' - ') 234 235 fd.write('\n') 236 237 return results
238 239
240 -def userfcn_iflims_savecase(ppc, fd, prefix, *args):
241 """This is the 'savecase' stage userfcn callback that prints the Python 242 file code to save the 'if' field in the case file. It expects a 243 PYPOWER case dict (ppc), a file descriptor and variable prefix 244 (usually 'ppc'). The optional args are not currently used. 245 """ 246 ifmap = ppc['if']['map'] 247 iflims = ppc['if']['lims'] 248 249 fd.write('\n####----- Interface Flow Limit Data -----####\n') 250 fd.write('#### interface<->branch map data\n') 251 fd.write('##\tifnum\tbranchidx (negative defines opposite direction)\n') 252 fd.write('%sif.map = [\n' % prefix) 253 fd.write('\t%d\t%d;\n' % ifmap.T) 254 fd.write('];\n') 255 256 fd.write('\n#### interface flow limit data (based on DC model)\n') 257 fd.write('#### (lower limit should be negative for opposite direction)\n') 258 fd.write('##\tifnum\tlower\tupper\n') 259 fd.write('%sif.lims = [\n' % prefix) 260 fd.write('\t%d\t%g\t%g;\n' % iflims.T) 261 fd.write('];\n') 262 263 ## save output fields for solved case 264 if ('P' in ppc['if']): 265 fd.write('\n#### solved values\n') 266 fd.write('%sif.P = %s\n' % (prefix, pprint(ppc['if']['P']))) 267 fd.write('%sif.mu.l = %s\n' % (prefix, pprint(ppc['if']['mu']['l']))) 268 fd.write('%sif.mu.u = %s\n' % (prefix, pprint(ppc['if']['mu']['u']))) 269 270 return ppc
271