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

Source Code for Module pypower.opf_execute

  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  """Executes the OPF specified by an OPF model object. 
 18  """ 
 19   
 20  from sys import stdout, stderr 
 21   
 22  from numpy import array, arange, pi, zeros, r_ 
 23   
 24  from pypower.ppver import ppver 
 25  from pypower.dcopf_solver import dcopf_solver 
 26  from pypower.pipsopf_solver import pipsopf_solver 
 27  from pypower.ipoptopf_solver import ipoptopf_solver 
 28  from pypower.update_mupq import update_mupq 
 29  from pypower.makeYbus import makeYbus 
 30  from pypower.opf_consfcn import opf_consfcn 
 31  from pypower.opf_costfcn import opf_costfcn 
 32   
 33  from pypower.idx_bus import VM 
 34  from pypower.idx_gen import GEN_BUS, VG 
 35  from pypower.idx_brch import MU_ANGMIN, MU_ANGMAX 
 36   
 37   
38 -def opf_execute(om, ppopt):
39 """Executes the OPF specified by an OPF model object. 40 41 C{results} are returned with internal indexing, all equipment 42 in-service, etc. 43 44 @see: L{opf}, L{opf_setup} 45 46 @author: Ray Zimmerman (PSERC Cornell) 47 @author: Richard Lincoln 48 """ 49 ##----- setup ----- 50 ## options 51 dc = ppopt['PF_DC'] ## 1 = DC OPF, 0 = AC OPF 52 alg = ppopt['OPF_ALG'] 53 verbose = ppopt['VERBOSE'] 54 55 ## build user-defined costs 56 om.build_cost_params() 57 58 ## get indexing 59 vv, ll, nn, _ = om.get_idx() 60 61 if verbose > 0: 62 v = ppver('all') 63 stdout.write('PYPOWER Version %s, %s' % (v['Version'], v['Date'])) 64 65 ##----- run DC OPF solver ----- 66 if dc: 67 if verbose > 0: 68 stdout.write(' -- DC Optimal Power Flow\n') 69 70 results, success, raw = dcopf_solver(om, ppopt) 71 else: 72 ##----- run AC OPF solver ----- 73 if verbose > 0: 74 stdout.write(' -- AC Optimal Power Flow\n') 75 76 ## if OPF_ALG not set, choose best available option 77 if alg == 0: 78 alg = 560 ## MIPS 79 80 ## update deprecated algorithm codes to new, generalized formulation equivalents 81 if alg == 100 | alg == 200: ## CONSTR 82 alg = 300 83 elif alg == 120 | alg == 220: ## dense LP 84 alg = 320 85 elif alg == 140 | alg == 240: ## sparse (relaxed) LP 86 alg = 340 87 elif alg == 160 | alg == 260: ## sparse (full) LP 88 alg = 360 89 90 ppopt['OPF_ALG_POLY'] = alg 91 92 ## run specific AC OPF solver 93 if alg == 560 or alg == 565: ## PIPS 94 results, success, raw = pipsopf_solver(om, ppopt) 95 elif alg == 580: ## IPOPT 96 try: 97 __import__('pyipopt') 98 results, success, raw = ipoptopf_solver(om, ppopt) 99 except ImportError: 100 raise ImportError, 'OPF_ALG %d requires IPOPT (see https://projects.coin-or.org/Ipopt/)' % alg 101 else: 102 stderr.write('opf_execute: OPF_ALG %d is not a valid algorithm code\n' % alg) 103 104 if ('output' not in raw) or ('alg' not in raw['output']): 105 raw['output']['alg'] = alg 106 107 if success: 108 if not dc: 109 ## copy bus voltages back to gen matrix 110 results['gen'][:, VG] = results['bus'][results['gen'][:, GEN_BUS].astype(int), VM] 111 112 ## gen PQ capability curve multipliers 113 if (ll['N']['PQh'] > 0) | (ll['N']['PQl'] > 0): 114 mu_PQh = results['mu']['lin']['l'][ll['i1']['PQh']:ll['iN']['PQh']] - results['mu']['lin']['u'][ll['i1']['PQh']:ll['iN']['PQh']] 115 mu_PQl = results['mu']['lin']['l'][ll['i1']['PQl']:ll['iN']['PQl']] - results['mu']['lin']['u'][ll['i1']['PQl']:ll['iN']['PQl']] 116 Apqdata = om.userdata('Apqdata') 117 results['gen'] = update_mupq(results['baseMVA'], results['gen'], mu_PQh, mu_PQl, Apqdata) 118 119 ## compute g, dg, f, df, d2f if requested by RETURN_RAW_DER = 1 120 if ppopt['RETURN_RAW_DER']: 121 ## move from results to raw if using v4.0 of MINOPF or TSPOPF 122 if 'dg' in results: 123 raw = {} 124 raw['dg'] = results['dg'] 125 raw['g'] = results['g'] 126 127 ## compute g, dg, unless already done by post-v4.0 MINOPF or TSPOPF 128 if 'dg' not in raw: 129 ppc = om.get_ppc() 130 Ybus, Yf, Yt = makeYbus(ppc['baseMVA'], ppc['bus'], ppc['branch']) 131 g, geq, dg, dgeq = opf_consfcn(results['x'], om, Ybus, Yf, Yt, ppopt) 132 raw['g'] = r_[geq, g] 133 raw['dg'] = r_[dgeq.T, dg.T] ## true Jacobian organization 134 135 ## compute df, d2f 136 _, df, d2f = opf_costfcn(results['x'], om, True) 137 raw['df'] = df 138 raw['d2f'] = d2f 139 140 ## delete g and dg fieldsfrom results if using v4.0 of MINOPF or TSPOPF 141 if 'dg' in results: 142 del results['dg'] 143 del results['g'] 144 145 ## angle limit constraint multipliers 146 if ll['N']['ang'] > 0: 147 iang = om.userdata('iang') 148 results['branch'][iang, MU_ANGMIN] = results['mu']['lin']['l'][ll['i1']['ang']:ll['iN']['ang']] * pi / 180 149 results['branch'][iang, MU_ANGMAX] = results['mu']['lin']['u'][ll['i1']['ang']:ll['iN']['ang']] * pi / 180 150 else: 151 ## assign empty g, dg, f, df, d2f if requested by RETURN_RAW_DER = 1 152 if not dc and ppopt['RETURN_RAW_DER']: 153 raw['dg'] = array([]) 154 raw['g'] = array([]) 155 raw['df'] = array([]) 156 raw['d2f'] = array([]) 157 158 ## assign values and limit shadow prices for variables 159 if om.var['order']: 160 results['var'] = {'val': {}, 'mu': {'l': {}, 'u': {}}} 161 for name in om.var['order']: 162 if om.getN('var', name): 163 idx = arange(vv['i1'][name], vv['iN'][name]) 164 results['var']['val'][name] = results['x'][idx] 165 results['var']['mu']['l'][name] = results['mu']['var']['l'][idx] 166 results['var']['mu']['u'][name] = results['mu']['var']['u'][idx] 167 168 ## assign shadow prices for linear constraints 169 if om.lin['order']: 170 results['lin'] = {'mu': {'l': {}, 'u': {}}} 171 for name in om.lin['order']: 172 if om.getN('lin', name): 173 idx = arange(ll['i1'][name], ll['iN'][name]) 174 results['lin']['mu']['l'][name] = results['mu']['lin']['l'][idx] 175 results['lin']['mu']['u'][name] = results['mu']['lin']['u'][idx] 176 177 ## assign shadow prices for nonlinear constraints 178 if not dc: 179 if om.nln['order']: 180 results['nln'] = {'mu': {'l': {}, 'u': {}}} 181 for name in om.nln['order']: 182 if om.getN('nln', name): 183 idx = arange(nn['i1'][name], nn['iN'][name]) 184 results['nln']['mu']['l'][name] = results['mu']['nln']['l'][idx] 185 results['nln']['mu']['u'][name] = results['mu']['nln']['u'][idx] 186 187 ## assign values for components of user cost 188 if om.cost['order']: 189 results['cost'] = {} 190 for name in om.cost['order']: 191 if om.getN('cost', name): 192 results['cost'][name] = om.compute_cost(results['x'], name) 193 194 ## if single-block PWL costs were converted to POLY, insert dummy y into x 195 ## Note: The "y" portion of x will be nonsense, but everything should at 196 ## least be in the expected locations. 197 pwl1 = om.userdata('pwl1') 198 if (len(pwl1) > 0) and (alg != 545) and (alg != 550): 199 ## get indexing 200 vv, _, _, _ = om.get_idx() 201 if dc: 202 nx = vv['iN']['Pg'] 203 else: 204 nx = vv['iN']['Qg'] 205 206 y = zeros(len(pwl1)) 207 raw['xr'] = r_[raw['xr'][:nx], y, raw['xr'][nx:]] 208 results['x'] = r_[results['x'][:nx], y, results['x'][nx:]] 209 210 return results, success, raw
211