def runopf(z, nu, rho, casedata=None, ppopt=None, fname='', solvedcase=''): ppopt = ppoption(ppopt) ##----- run the optimal power flow ----- r = opf(z, nu, rho, casedata) printpf(r, stdout, ppopt) return r # if __name__ == '__main__': # ppc = case4gs() # results = runopf(z, nu, rho, casedata=ppc) # print(results["x"])
def dcopf(*args, **kw_args): """Solves a DC optimal power flow. This is a simple wrapper function around L{opf} that sets the C{PF_DC} option to C{True} before calling L{opf}. See L{opf} for the details of input and output arguments. @see: L{rundcopf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ppc, ppopt = opf_args2(*args, **kw_args); ppopt = ppoption(ppopt, PF_DC=1) return opf(ppc, ppopt)
def gausspf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None): """Solves the power flow using a Gauss-Seidel method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see C{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Alberto Borghetti (University of Bologna, Italy) @author: Richard Lincoln """ ## default arguments if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT_GS'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0.copy() #Va = angle(V) Vm = abs(V) ## set up indexing for updating V npv = len(pv) npq = len(pq) pvpq = r_[pv, pq] ## evaluate F(x0) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pvpq].real, mis[pq].imag ] ## check tolerance normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n it max P & Q mismatch (p.u.)') sys.stdout.write('\n---- ---------------------------') sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## do Gauss-Seidel iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ## update voltage ## at PQ buses for k in pq[range(npq)]: tmp = (conj(Sbus[k] / V[k]) - Ybus[k, :] * V) / Ybus[k, k] V[k] = V[k] + asscalar(tmp) ## at PV buses if npv: for k in pv[range(npv)]: tmp = (V[k] * conj(Ybus[k,:] * V)).imag Sbus[k] = Sbus[k].real + 1j * asscalar(tmp) tmp = (conj(Sbus[k] / V[k]) - Ybus[k, :] * V) / Ybus[k, k] V[k] = V[k] + asscalar(tmp) # V[k] = Vm[k] * V[k] / abs(V[k]) V[pv] = Vm[pv] * V[pv] / abs(V[pv]) ## evalute F(x) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check for convergence normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose: sys.stdout.write('\nGauss-Seidel power flow converged in ' '%d iterations.\n' % i) if verbose: if not converged: sys.stdout.write('Gauss-Seidel power did not converge in %d ' 'iterations.' % i) return V, converged, i
def fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, ppopt=None): """Solves the power flow using a fast decoupled method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, the FDPF matrices B prime and B double prime, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see L{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT_FD'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0 Va = angle(V) Vm = abs(V) ## set up indexing for updating V #npv = len(pv) #npq = len(pq) pvpq = r_[pv, pq] ## evaluate initial mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write('\niteration max mismatch (p.u.) ') sys.stdout.write('\ntype # P Q ') sys.stdout.write('\n---- ---- ----------- -----------') sys.stdout.write('\n - %3d %10.3e %10.3e' % (i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## reduce B matrices Bp = Bp[array([pvpq]).T, pvpq].tocsc() # splu requires a CSC matrix Bpp = Bpp[array([pq]).T, pq].tocsc() ## factor B matrices Bp_solver = splu(Bp) Bpp_solver = splu(Bpp) ## do P and Q iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ##----- do P iteration, update Va ----- dVa = -Bp_solver.solve(P) ## update voltage Va[pvpq] = Va[pvpq] + dVa V = Vm * exp(1j * Va) ## evalute mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write("\n %s %3d %10.3e %10.3e" % (type,i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose: sys.stdout.write('\nFast-decoupled power flow converged in %d ' 'P-iterations and %d Q-iterations.\n' % (i, i - 1)) break ##----- do Q iteration, update Vm ----- dVm = -Bpp_solver.solve(Q) ## update voltage Vm[pq] = Vm[pq] + dVm V = Vm * exp(1j * Va) ## evalute mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write('\n Q %3d %10.3e %10.3e' % (i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose: sys.stdout.write('\nFast-decoupled power flow converged in %d ' 'P-iterations and %d Q-iterations.\n' % (i, i)) break if verbose: if not converged: sys.stdout.write('\nFast-decoupled power flow did not converge in ' '%d iterations.' % i) return V, converged, i
def opf_args(*args): """Parses and initializes OPF input arguments. Returns the full set of initialized OPF input arguments, filling in default values for missing arguments. See Examples below for the possible calling syntax options. Input arguments options:: opf_args(ppc) opf_args(ppc, ppopt) opf_args(ppc, userfcn, ppopt) opf_args(ppc, A, l, u) opf_args(ppc, A, l, u, ppopt) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw, z0, zl, zu) opf_args(baseMVA, bus, gen, branch, areas, gencost) opf_args(baseMVA, bus, gen, branch, areas, gencost, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw, z0, zl, zu) The data for the problem can be specified in one of three ways: 1. a string (ppc) containing the file name of a PYPOWER case which defines the data matrices baseMVA, bus, gen, branch, and gencost (areas is not used at all, it is only included for backward compatibility of the API). 2. a dict (ppc) containing the data matrices as fields. 3. the individual data matrices themselves. The optional user parameters for user constraints (C{A, l, u}), user costs (C{N, fparm, H, Cw}), user variable initializer (z0), and user variable limits (C{zl, zu}) can also be specified as fields in a case dict, either passed in directly or defined in a case file referenced by name. When specified, C{A, l, u} represent additional linear constraints on the optimization variables, C{l <= A*[x z] <= u}. If the user specifies an C{A} matrix that has more columns than the number of "C{x}" (OPF) variables, then there are extra linearly constrained "C{z}" variables. For an explanation of the formulation used and instructions for forming the C{A} matrix, see the MATPOWER manual. A generalized cost on all variables can be applied if input arguments C{N}, C{fparm}, C{H} and C{Cw} are specified. First, a linear transformation of the optimization variables is defined by means of C{r = N * [x z]}. Then, to each element of r a function is applied as encoded in the C{fparm} matrix (see Matpower manual). If the resulting vector is named C{w}, then C{H} and C{Cw} define a quadratic cost on C{w}: C{(1/2)*w'*H*w + Cw * w}. C{H} and C{N} should be sparse matrices and C{H} should also be symmetric. The optional C{ppopt} vector specifies PYPOWER options. See L{ppoption} for details and default values. @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Richard Lincoln """ # nargin = len([arg for arg in [baseMVA, bus, gen, branch, areas, gencost, # Au, lbu, ubu, ppopt, N, fparm, H, Cw, # z0, zl, zu] if arg is not None]) nargin = len(args) userfcn = array([]) ## passing filename or dict if isinstance(args[0], basestring) or isinstance(args[0], dict): # ----opf( baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 12 opf(casefile, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 9 opf(casefile, Au, lbu, ubu, ppopt, N, fparm, H, Cw) # 5 opf(casefile, Au, lbu, ubu, ppopt) # 4 opf(casefile, Au, lbu, ubu) # 3 opf(casefile, userfcn, ppopt) # 2 opf(casefile, ppopt) # 1 opf(casefile) if nargin in [1, 2, 3, 4, 5, 9, 12]: casefile = args[0] if nargin == 12: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm = args zu = fparm zl = N z0 = ppopt Cw = ubu H = lbu fparm = Au N = gencost ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 9: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu = args zu = array([]) zl = array([]) z0 = array([]) Cw = ubu H = lbu fparm = Au N = gencost ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 5: baseMVA, bus, gen, branch, areas = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 4: baseMVA, bus, gen, branch = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = branch lbu = gen Au = bus elif nargin == 3: baseMVA, bus, gen = args userfcn = bus zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = gen ubu = array([]) lbu = array([]) Au = None elif nargin == 2: baseMVA, bus = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = bus ubu = array([]) lbu = array([]) Au = None elif nargin == 1: zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = array([]) lbu = array([]) Au = None else: stderr.write('opf_args: Incorrect input arg order, number or type\n') ppc = loadcase(casefile) baseMVA, bus, gen, branch, gencost = \ ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch'], ppc['gencost'] if 'areas' in ppc: areas = ppc['areas'] else: areas = array([]) if Au is None and 'A' in ppc: Au, lbu, ubu = ppc["A"], ppc["l"], ppc["u"] if N is None and 'N' in ppc: ## these two must go together N, Cw = ppc["N"], ppc["Cw"] if H is None and 'H' in ppc: ## will default to zeros H = ppc["H"] if (fparm is None or len(fparm) == 0) and 'fparm' in ppc: ## will default to [1 0 0 1] fparm = ppc["fparm"] if (z0 is None or len(z0) == 0) and 'z0' in ppc: z0 = ppc["z0"] if (zl is None or len(zl) == 0) and 'zl' in ppc: zl = ppc["zl"] if (zu is None or len(zu) == 0) and 'zu' in ppc: zu = ppc["zu"] if (userfcn is None or len(userfcn) == 0) and 'userfcn' in ppc: userfcn = ppc['userfcn'] else: ## passing individual data matrices # ----opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 17 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 14 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw) # 10 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt) # 9 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu) # 8 opf(baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt) # 7 opf(baseMVA, bus, gen, branch, areas, gencost, ppopt) # 6 opf(baseMVA, bus, gen, branch, areas, gencost) if nargin in [6, 7, 8, 9, 10, 14, 17]: if nargin == 17: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu = args elif nargin == 14: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw = args zu = array([]) zl = array([]) z0 = array([]) elif nargin == 10: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None elif nargin == 9: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() elif nargin == 8: baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ubu = array([]) lbu = array([]) Au = None elif nargin == 7: baseMVA, bus, gen, branch, areas, gencost, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ubu = array([]) lbu = array([]) Au = None elif nargin == 6: baseMVA, bus, gen, branch, areas, gencost = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = array([]) lbu = array([]) Au = None else: stderr.write('opf_args: Incorrect input arg order, number or type\n') if N is not None: nw = N.shape[0] else: nw = 0 if nw: if Cw.shape[0] != nw: stderr.write('opf_args.m: dimension mismatch between N and Cw in ' 'generalized cost parameters\n') if len(fparm) > 0 and fparm.shape[0] != nw: stderr.write('opf_args.m: dimension mismatch between N and fparm ' 'in generalized cost parameters\n') if (H is not None) and (H.shape[0] != nw | H.shape[0] != nw): stderr.write('opf_args.m: dimension mismatch between N and H in ' 'generalized cost parameters\n') if Au is not None: if Au.shape[0] > 0 and N.shape[1] != Au.shape[1]: stderr.write('opf_args.m: A and N must have the same number ' 'of columns\n') ## make sure N and H are sparse if not issparse(N): stderr.write('opf_args.m: N must be sparse in generalized cost ' 'parameters\n') if not issparse(H): stderr.write('opf_args.m: H must be sparse in generalized cost parameters\n') if Au is not None and not issparse(Au): stderr.write('opf_args.m: Au must be sparse\n') if ppopt == None or len(ppopt) == 0: ppopt = ppoption() return baseMVA, bus, gen, branch, gencost, Au, lbu, ubu, \ ppopt, N, fparm, H, Cw, z0, zl, zu, userfcn, areas
def uopf(*args): """Solves combined unit decommitment / optimal power flow. Solves a combined unit decommitment and optimal power flow for a single time period. Uses an algorithm similar to dynamic programming. It proceeds through a sequence of stages, where stage C{N} has C{N} generators shut down, starting with C{N=0}. In each stage, it forms a list of candidates (gens at their C{Pmin} limits) and computes the cost with each one of them shut down. It selects the least cost case as the starting point for the next stage, continuing until there are no more candidates to be shut down or no more improvement can be gained by shutting something down. If C{verbose} in ppopt (see L{ppoption} is C{true}, it prints progress info, if it is > 1 it prints the output of each individual opf. @see: L{opf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ##----- initialization ----- t0 = time() ## start timer ## process input arguments ppc, ppopt = opf_args2(*args) ## options verbose = ppopt["VERBOSE"] if verbose: ## turn down verbosity one level for calls to opf ppopt = ppoption(ppopt, VERBOSE=verbose - 1) ##----- do combined unit commitment/optimal power flow ----- ## check for sum(Pmin) > total load, decommit as necessary on = find( (ppc["gen"][:, GEN_STATUS] > 0) & ~isload(ppc["gen"]) ) ## gens in service onld = find( (ppc["gen"][:, GEN_STATUS] > 0) & isload(ppc["gen"]) ) ## disp loads in serv load_capacity = sum(ppc["bus"][:, PD]) - sum(ppc["gen"][onld, PMIN]) ## total load capacity Pmin = ppc["gen"][on, PMIN] while sum(Pmin) > load_capacity: ## shut down most expensive unit avgPmincost = totcost(ppc["gencost"][on, :], Pmin) / Pmin _, i = fairmax(avgPmincost) ## pick one with max avg cost at Pmin i = on[i] ## convert to generator index if verbose: print 'Shutting down generator %d so all Pmin limits can be satisfied.\n' % i ## set generation to zero ppc["gen"][i, [PG, QG, GEN_STATUS]] = 0 ## update minimum gen capacity on = find( (ppc["gen"][:, GEN_STATUS] > 0) & ~isload(ppc["gen"]) ) ## gens in service Pmin = ppc["gen"][on, PMIN] ## run initial opf results = opf(ppc, ppopt) ## best case so far results1 = deepcopy(results) ## best case for this stage (ie. with n gens shut down, n=0,1,2 ...) results0 = deepcopy(results1) ppc["bus"] = results0["bus"].copy() ## use these V as starting point for OPF while True: ## get candidates for shutdown candidates = find((results0["gen"][:, MU_PMIN] > 0) & (results0["gen"][:, PMIN] > 0)) if len(candidates) == 0: break ## do not check for further decommitment unless we ## see something better during this stage done = True for k in candidates: ## start with best for this stage ppc["gen"] = results0["gen"].copy() ## shut down gen k ppc["gen"][k, [PG, QG, GEN_STATUS]] = 0 ## run opf results = opf(ppc, ppopt) ## something better? if results['success'] and (results["f"] < results1["f"]): results1 = deepcopy(results) k1 = k done = False ## make sure we check for further decommitment if done: ## decommits at this stage did not help, so let's quit break else: ## shutting something else down helps, so let's keep going if verbose: print 'Shutting down generator %d.\n' % k1 results0 = deepcopy(results1) ppc["bus"] = results0["bus"].copy() ## use these V as starting point for OPF ## compute elapsed time et = time() - t0 ## finish preparing output results0['et'] = et return results0
def printpf(baseMVA, bus=None, gen=None, branch=None, f=None, success=None, et=None, fd=None, ppopt=None): """Prints power flow results. Prints power flow and optimal power flow results to C{fd} (a file descriptor which defaults to C{stdout}), with the details of what gets printed controlled by the optional C{ppopt} argument, which is a PYPOWER options vector (see L{ppoption} for details). The data can either be supplied in a single C{results} dict, or in the individual arguments: C{baseMVA}, C{bus}, C{gen}, C{branch}, C{f}, C{success} and C{et}, where C{f} is the OPF objective function value, C{success} is C{True} if the solution converged and C{False} otherwise, and C{et} is the elapsed time for the computation in seconds. If C{f} is given, it is assumed that the output is from an OPF run, otherwise it is assumed to be a simple power flow run. Examples:: ppopt = ppoptions(OUT_GEN=1, OUT_BUS=0, OUT_BRANCH=0) fd = open(fname, 'w+b') results = runopf(ppc) printpf(results) printpf(results, fd) printpf(results, fd, ppopt) printpf(baseMVA, bus, gen, branch, f, success, et) printpf(baseMVA, bus, gen, branch, f, success, et, fd) printpf(baseMVA, bus, gen, branch, f, success, et, fd, ppopt) fd.close() @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ##----- initialization ----- ## default arguments if isinstance(baseMVA, dict): have_results_struct = 1 results = baseMVA if gen is None: ppopt = ppoption() ## use default options else: ppopt = gen if (ppopt['OUT_ALL'] == 0): return ## nothin' to see here, bail out now if bus is None: fd = stdout ## print to stdout by default else: fd = bus baseMVA, bus, gen, branch, success, et = \ results["baseMVA"], results["bus"], results["gen"], \ results["branch"], results["success"], results["et"] if 'f' in results: f = results["f"] else: f = None else: have_results_struct = 0 if ppopt is None: ppopt = ppoption() ## use default options if fd is None: fd = stdout ## print to stdout by default if ppopt['OUT_ALL'] == 0: return ## nothin' to see here, bail out now isOPF = f is not None ## FALSE -> only simple PF data, TRUE -> OPF data ## options isDC = ppopt['PF_DC'] ## use DC formulation? OUT_ALL = ppopt['OUT_ALL'] OUT_ANY = OUT_ALL == 1 ## set to true if any pretty output is to be generated OUT_SYS_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_SYS_SUM']) OUT_AREA_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_AREA_SUM']) OUT_BUS = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BUS']) OUT_BRANCH = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BRANCH']) OUT_GEN = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_GEN']) OUT_ANY = OUT_ANY | ((OUT_ALL == -1) and (OUT_SYS_SUM or OUT_AREA_SUM or OUT_BUS or OUT_BRANCH or OUT_GEN)) if OUT_ALL == -1: OUT_ALL_LIM = ppopt['OUT_ALL_LIM'] elif OUT_ALL == 1: OUT_ALL_LIM = 2 else: OUT_ALL_LIM = 0 OUT_ANY = OUT_ANY or (OUT_ALL_LIM >= 1) if OUT_ALL_LIM == -1: OUT_V_LIM = ppopt['OUT_V_LIM'] OUT_LINE_LIM = ppopt['OUT_LINE_LIM'] OUT_PG_LIM = ppopt['OUT_PG_LIM'] OUT_QG_LIM = ppopt['OUT_QG_LIM'] else: OUT_V_LIM = OUT_ALL_LIM OUT_LINE_LIM = OUT_ALL_LIM OUT_PG_LIM = OUT_ALL_LIM OUT_QG_LIM = OUT_ALL_LIM OUT_ANY = OUT_ANY or ((OUT_ALL_LIM == -1) and (OUT_V_LIM or OUT_LINE_LIM or OUT_PG_LIM or OUT_QG_LIM)) ptol = 1e-4 ## tolerance for displaying shadow prices ## create map of external bus numbers to bus indices i2e = bus[:, BUS_I].astype(int) e2i = zeros(max(i2e) + 1, int) e2i[i2e] = arange(bus.shape[0]) ## sizes of things nb = bus.shape[0] ## number of buses nl = branch.shape[0] ## number of branches ng = gen.shape[0] ## number of generators ## zero out some data to make printout consistent for DC case if isDC: bus[:, r_[QD, BS]] = zeros((nb, 2)) gen[:, r_[QG, QMAX, QMIN]] = zeros((ng, 3)) branch[:, r_[BR_R, BR_B]] = zeros((nl, 2)) ## parameters ties = find(bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA]) ## area inter-ties tap = ones(nl) ## default tap ratio = 1 for lines xfmr = find(branch[:, TAP]) ## indices of transformers tap[xfmr] = branch[xfmr, TAP] ## include transformer tap ratios tap = tap * exp(1j * pi / 180 * branch[:, SHIFT]) ## add phase shifters nzld = find((bus[:, PD] != 0.0) | (bus[:, QD] != 0.0)) sorted_areas = sort(bus[:, BUS_AREA]) ## area numbers s_areas = sorted_areas[r_[1, find(diff(sorted_areas)) + 1]] nzsh = find((bus[:, GS] != 0.0) | (bus[:, BS] != 0.0)) allg = find( ~isload(gen) ) ong = find( (gen[:, GEN_STATUS] > 0) & ~isload(gen) ) onld = find( (gen[:, GEN_STATUS] > 0) & isload(gen) ) V = bus[:, VM] * exp(-1j * pi / 180 * bus[:, VA]) out = find(branch[:, BR_STATUS] == 0) ## out-of-service branches nout = len(out) if isDC: loss = zeros(nl) else: loss = baseMVA * abs(V[e2i[ branch[:, F_BUS].astype(int) ]] / tap - V[e2i[ branch[:, T_BUS].astype(int) ]])**2 / \ (branch[:, BR_R] - 1j * branch[:, BR_X]) fchg = abs(V[e2i[ branch[:, F_BUS].astype(int) ]] / tap)**2 * branch[:, BR_B] * baseMVA / 2 tchg = abs(V[e2i[ branch[:, T_BUS].astype(int) ]] )**2 * branch[:, BR_B] * baseMVA / 2 loss[out] = zeros(nout) fchg[out] = zeros(nout) tchg[out] = zeros(nout) ##----- print the stuff ----- if OUT_ANY: ## convergence & elapsed time if success: fd.write('\nConverged in %.2f seconds' % et) else: fd.write('\nDid not converge (%.2f seconds)\n' % et) ## objective function value if isOPF: fd.write('\nObjective Function Value = %.2f $/hr' % f) if OUT_SYS_SUM: fd.write('\n================================================================================') fd.write('\n| System Summary |') fd.write('\n================================================================================') fd.write('\n\nHow many? How much? P (MW) Q (MVAr)') fd.write('\n--------------------- ------------------- ------------- -----------------') fd.write('\nBuses %6d Total Gen Capacity %7.1f %7.1f to %.1f' % (nb, sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum(gen[allg, QMAX]))) fd.write('\nGenerators %5d On-line Capacity %7.1f %7.1f to %.1f' % (len(allg), sum(gen[ong, PMAX]), sum(gen[ong, QMIN]), sum(gen[ong, QMAX]))) fd.write('\nCommitted Gens %5d Generation (actual) %7.1f %7.1f' % (len(ong), sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\nLoads %5d Load %7.1f %7.1f' % (len(nzld)+len(onld), sum(bus[nzld, PD])-sum(gen[onld, PG]), sum(bus[nzld, QD])-sum(gen[onld, QG]))) fd.write('\n Fixed %5d Fixed %7.1f %7.1f' % (len(nzld), sum(bus[nzld, PD]), sum(bus[nzld, QD]))) fd.write('\n Dispatchable %5d Dispatchable %7.1f of %-7.1f%7.1f' % (len(onld), -sum(gen[onld, PG]), -sum(gen[onld, PMIN]), -sum(gen[onld, QG]))) fd.write('\nShunts %5d Shunt (inj) %7.1f %7.1f' % (len(nzsh), -sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]) )) fd.write('\nBranches %5d Losses (I^2 * Z) %8.2f %8.2f' % (nl, sum(loss.real), sum(loss.imag) )) fd.write('\nTransformers %5d Branch Charging (inj) - %7.1f' % (len(xfmr), sum(fchg) + sum(tchg) )) fd.write('\nInter-ties %5d Total Inter-tie Flow %7.1f %7.1f' % (len(ties), sum(abs(branch[ties, PF]-branch[ties, PT])) / 2, sum(abs(branch[ties, QF]-branch[ties, QT])) / 2)) fd.write('\nAreas %5d' % len(s_areas)) fd.write('\n') fd.write('\n Minimum Maximum') fd.write('\n ------------------------- --------------------------------') minv = min(bus[:, VM]) mini = argmin(bus[:, VM]) maxv = max(bus[:, VM]) maxi = argmax(bus[:, VM]) fd.write('\nVoltage Magnitude %7.3f p.u. @ bus %-4d %7.3f p.u. @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, VA]) mini = argmin(bus[:, VA]) maxv = max(bus[:, VA]) maxi = argmax(bus[:, VA]) fd.write('\nVoltage Angle %8.2f deg @ bus %-4d %8.2f deg @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) if not isDC: maxv = max(loss.real) maxi = argmax(loss.real) fd.write('\nP Losses (I^2*R) - %8.2f MW @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) maxv = max(loss.imag) maxi = argmax(loss.imag) fd.write('\nQ Losses (I^2*X) - %8.2f MVAr @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) if isOPF: minv = min(bus[:, LAM_P]) mini = argmin(bus[:, LAM_P]) maxv = max(bus[:, LAM_P]) maxi = argmax(bus[:, LAM_P]) fd.write('\nLambda P %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, LAM_Q]) mini = argmin(bus[:, LAM_Q]) maxv = max(bus[:, LAM_Q]) maxi = argmax(bus[:, LAM_Q]) fd.write('\nLambda Q %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) fd.write('\n') if OUT_AREA_SUM: fd.write('\n================================================================================') fd.write('\n| Area Summary |') fd.write('\n================================================================================') fd.write('\nArea # of # of Gens # of Loads # of # of # of # of') fd.write('\n Num Buses Total Online Total Fixed Disp Shunt Brchs Xfmrs Ties') fd.write('\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----') for i in range(len(s_areas)): a = s_areas[i] ib = find(bus[:, BUS_AREA] == a) ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) in_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a)) out_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) if not any(xfmr + 1): nxfmr = 0 else: nxfmr = len(find((bus[e2i[branch[xfmr, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[xfmr, T_BUS].astype(int)], BUS_AREA] == a))) fd.write('\n%3d %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (a, len(ib), len(ig), len(igon), \ len(inzld)+len(ildon), len(inzld), len(ildon), \ len(inzsh), len(ibrch), nxfmr, len(in_tie)+len(out_tie))) fd.write('\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----') fd.write('\nTot: %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (nb, len(allg), len(ong), len(nzld)+len(onld), len(nzld), len(onld), len(nzsh), nl, len(xfmr), len(ties))) fd.write('\n') fd.write('\nArea Total Gen Capacity On-line Gen Capacity Generation') fd.write('\n Num MW MVAr MW MVAr MW MVAr') fd.write('\n---- ------ ------------------ ------ ------------------ ------ ------') for i in range(len(s_areas)): a = s_areas[i] ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) fd.write('\n%3d %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (a, sum(gen[ig, PMAX]), sum(gen[ig, QMIN]), sum(gen[ig, QMAX]), sum(gen[igon, PMAX]), sum(gen[igon, QMIN]), sum(gen[igon, QMAX]), sum(gen[igon, PG]), sum(gen[igon, QG]) )) fd.write('\n---- ------ ------------------ ------ ------------------ ------ ------') fd.write('\nTot: %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum(gen[allg, QMAX]), sum(gen[ong, PMAX]), sum(gen[ong, QMIN]), sum(gen[ong, QMAX]), sum(gen[ong, PG]), sum(gen[ong, QG]) )) fd.write('\n') fd.write('\nArea Disp Load Cap Disp Load Fixed Load Total Load') fd.write('\n Num MW MVAr MW MVAr MW MVAr MW MVAr') fd.write('\n---- ------ ------ ------ ------ ------ ------ ------ ------') Qlim = (gen[:, QMIN] == 0) * gen[:, QMAX] + (gen[:, QMAX] == 0) * gen[:, QMIN] for i in range(len(s_areas)): a = s_areas[i] ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) fd.write('\n%3d %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (a, -sum(gen[ildon, PMIN]), -sum(Qlim[ildon]), -sum(gen[ildon, PG]), -sum(gen[ildon, QG]), sum(bus[inzld, PD]), sum(bus[inzld, QD]), -sum(gen[ildon, PG]) + sum(bus[inzld, PD]), -sum(gen[ildon, QG]) + sum(bus[inzld, QD]) )) fd.write('\n---- ------ ------ ------ ------ ------ ------ ------ ------') fd.write('\nTot: %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (-sum(gen[onld, PMIN]), -sum(Qlim[onld]), -sum(gen[onld, PG]), -sum(gen[onld, QG]), sum(bus[nzld, PD]), sum(bus[nzld, QD]), -sum(gen[onld, PG]) + sum(bus[nzld, PD]), -sum(gen[onld, QG]) + sum(bus[nzld, QD])) ) fd.write('\n') fd.write('\nArea Shunt Inj Branch Series Losses Net Export') fd.write('\n Num MW MVAr Charging MW MVAr MW MVAr') fd.write('\n---- ------ ------ -------- ------ ------ ------ ------') for i in range(len(s_areas)): a = s_areas[i] inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) in_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) out_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a) & branch[:, BR_STATUS].astype(bool)) fd.write('\n%3d %7.1f %7.1f %7.1f %7.2f %7.2f %7.1f %7.1f' % (a, -sum(bus[inzsh, VM]**2 * bus[inzsh, GS]), sum(bus[inzsh, VM]**2 * bus[inzsh, BS]), sum(fchg[ibrch]) + sum(tchg[ibrch]) + sum(fchg[out_tie]) + sum(tchg[in_tie]), sum(real(loss[ibrch])) + sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(imag(loss[ibrch])) + sum(imag(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, PT])+sum(branch[out_tie, PF]) - sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, QT])+sum(branch[out_tie, QF]) - sum(imag(loss[r_[in_tie, out_tie]])) / 2 )) fd.write('\n---- ------ ------ -------- ------ ------ ------ ------') fd.write('\nTot: %7.1f %7.1f %7.1f %7.2f %7.2f - -' % (-sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]), sum(fchg) + sum(tchg), sum(real(loss)), sum(imag(loss)) )) fd.write('\n') ## generator data if OUT_GEN: if isOPF: genlamP = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_P] genlamQ = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_Q] fd.write('\n================================================================================') fd.write('\n| Generator Data |') fd.write('\n================================================================================') fd.write('\n Gen Bus Status Pg Qg ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(ong)): i = ong[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or(gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (gen[i, PG], gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\n') if any(onld + 1): fd.write('\n================================================================================') fd.write('\n| Dispatchable Load Data |') fd.write('\n================================================================================') fd.write('\n Gen Bus Status Pd Qd ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(onld)): i = onld[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or(gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (-gen[i, PG], -gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (-sum(gen[onld, PG]), -sum(gen[onld, QG]))) fd.write('\n') ## bus data if OUT_BUS: fd.write('\n================================================================================') fd.write('\n| Bus Data |') fd.write('\n================================================================================') fd.write('\n Bus Voltage Generation Load ') if isOPF: fd.write(' Lambda($/MVA-hr)') fd.write('\n # Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr)') if isOPF: fd.write(' P Q ') fd.write('\n----- ------- -------- -------- -------- -------- --------') if isOPF: fd.write(' ------- -------') for i in range(nb): fd.write('\n%5d%7.3f%9.3f' % tuple(bus[i, [BUS_I, VM, VA]])) if bus[i, BUS_TYPE] == REF: fd.write('*') else: fd.write(' ') g = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & ~isload(gen)) ld = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & isload(gen)) if any(g + 1): fd.write('%9.2f%10.2f' % (sum(gen[g, PG]), sum(gen[g, QG]))) else: fd.write(' - - ') if logical_or(bus[i, PD], bus[i, QD]) | any(ld + 1): if any(ld + 1): fd.write('%10.2f*%9.2f*' % (bus[i, PD] - sum(gen[ld, PG]), bus[i, QD] - sum(gen[ld, QG]))) else: fd.write('%10.2f%10.2f ' % tuple(bus[i, [PD, QD]])) else: fd.write(' - - ') if isOPF: fd.write('%9.3f' % bus[i, LAM_P]) if abs(bus[i, LAM_Q]) > ptol: fd.write('%8.3f' % bus[i, LAM_Q]) else: fd.write(' -') fd.write('\n -------- -------- -------- --------') fd.write('\n Total: %9.2f %9.2f %9.2f %9.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]), sum(bus[nzld, PD]) - sum(gen[onld, PG]), sum(bus[nzld, QD]) - sum(gen[onld, QG]))) fd.write('\n') ## branch data if OUT_BRANCH: fd.write('\n================================================================================') fd.write('\n| Branch Data |') fd.write('\n================================================================================') fd.write('\nBrnch From To From Bus Injection To Bus Injection Loss (I^2 * Z) ') fd.write('\n # Bus Bus P (MW) Q (MVAr) P (MW) Q (MVAr) P (MW) Q (MVAr)') fd.write('\n----- ----- ----- -------- -------- -------- -------- -------- --------') for i in range(nl): fd.write('\n%4d%7d%7d%10.2f%10.2f%10.2f%10.2f%10.3f%10.2f' % (i, branch[i, F_BUS], branch[i, T_BUS], branch[i, PF], branch[i, QF], branch[i, PT], branch[i, QT], loss[i].real, loss[i].imag)) fd.write('\n -------- --------') fd.write('\n Total:%10.3f%10.2f' % (sum(real(loss)), sum(imag(loss)))) fd.write('\n') ##----- constraint data ----- if isOPF: ctol = ppopt['OPF_VIOLATION'] ## constraint violation tolerance ## voltage constraints if (not isDC) & (OUT_V_LIM == 2 | (OUT_V_LIM == 1 & (any(bus[:, VM] < bus[:, VMIN] + ctol) | any(bus[:, VM] > bus[:, VMAX] - ctol) | any(bus[:, MU_VMIN] > ptol) | any(bus[:, MU_VMAX] > ptol)))): fd.write('\n================================================================================') fd.write('\n| Voltage Constraints |') fd.write('\n================================================================================') fd.write('\nBus # Vmin mu Vmin |V| Vmax Vmax mu') fd.write('\n----- -------- ----- ----- ----- --------') for i in range(nb): if (OUT_V_LIM == 2) | (OUT_V_LIM == 1 & ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMIN] > ptol) | (bus[i, MU_VMAX] > ptol))): fd.write('\n%5d' % bus[i, BUS_I]) if ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, MU_VMIN] > ptol)): fd.write('%10.3f' % bus[i, MU_VMIN]) else: fd.write(' - ') fd.write('%8.3f%7.3f%7.3f' % tuple(bus[i, [VMIN, VM, VMAX]])) if (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMAX] > ptol): fd.write('%10.3f' % bus[i, MU_VMAX]) else: fd.write(' - ') fd.write('\n') ## generator P constraints if (OUT_PG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))) | \ ((not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol))))): fd.write('\n================================================================================') fd.write('\n| Generation Constraints |') fd.write('\n================================================================================') if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))): fd.write('\n Gen Bus Active Power Limits') fd.write('\n # # Pmin mu Pmin Pg Pmax Pmax mu') fd.write('\n---- ----- ------- -------- -------- -------- -------') for k in range(len(ong)): i = ong[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%4d%6d ' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [PMIN, PG, PMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [PMIN, PMAX]])) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## generator Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write('\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(ong)): i = ong[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [QMIN, QG, QMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [QMIN, QMAX]])) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load P constraints if (OUT_PG_LIM == 2) | (OUT_QG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))) | \ ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol))): fd.write('\n================================================================================') fd.write('\n| Dispatchable Load Constraints |') fd.write('\n================================================================================') if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))): fd.write('\nGen Bus Active Power Limits') fd.write('\n # # Pmin mu Pmin Pg Pmax Pmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [PMIN, PG, PMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [PMIN, PMAX]]) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write('\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen(i, GEN_BUS))) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [QMIN, QG, QMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [QMIN, QMAX]]) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## line flow constraints if (ppopt['OPF_FLOW_LIM'] == 1) | isDC: ## P limit Ff = branch[:, PF] Ft = branch[:, PT] strg = '\n # Bus Pf mu Pf |Pmax| Pt Pt mu Bus' elif ppopt['OPF_FLOW_LIM'] == 2: ## |I| limit Ff = abs( (branch[:, PF] + 1j * branch[:, QF]) / V[e2i[branch[:, F_BUS].astype(int)]] ) Ft = abs( (branch[:, PT] + 1j * branch[:, QT]) / V[e2i[branch[:, T_BUS].astype(int)]] ) strg = '\n # Bus |If| mu |If| |Imax| |It| |It| mu Bus' else: ## |S| limit Ff = abs(branch[:, PF] + 1j * branch[:, QF]) Ft = abs(branch[:, PT] + 1j * branch[:, QT]) strg = '\n # Bus |Sf| mu |Sf| |Smax| |St| |St| mu Bus' if (OUT_LINE_LIM == 2) | ((OUT_LINE_LIM == 1) & (any((branch[:, RATE_A] != 0) & (abs(Ff) > branch[:, RATE_A] - ctol)) | any((branch[:, RATE_A] != 0) & (abs(Ft) > branch[:, RATE_A] - ctol)) | any(branch[:, MU_SF] > ptol) | any(branch[:, MU_ST] > ptol))): fd.write('\n================================================================================') fd.write('\n| Branch Flow Constraints |') fd.write('\n================================================================================') fd.write('\nBrnch From "From" End Limit "To" End To') fd.write(strg) fd.write('\n----- ----- ------- -------- -------- -------- ------- -----') for i in range(nl): if (OUT_LINE_LIM == 2) | ((OUT_LINE_LIM == 1) & (((branch[i, RATE_A] != 0) & (abs(Ff[i]) > branch[i, RATE_A] - ctol)) | ((branch[i, RATE_A] != 0) & (abs(Ft[i]) > branch[i, RATE_A] - ctol)) | (branch[i, MU_SF] > ptol) | (branch[i, MU_ST] > ptol))): fd.write('\n%4d%7d' % (i, branch[i, F_BUS])) if (Ff[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_SF] > ptol): fd.write('%10.3f' % branch[i, MU_SF]) else: fd.write(' - ') fd.write('%9.2f%10.2f%10.2f' % (Ff[i], branch[i, RATE_A], Ft[i])) if (Ft[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_ST] > ptol): fd.write('%10.3f' % branch[i, MU_ST]) else: fd.write(' - ') fd.write('%6d' % branch[i, T_BUS]) fd.write('\n') ## execute userfcn callbacks for 'printpf' stage if have_results_struct & results.has_key('userfcn'): if not isOPF: ## turn off option for all constraints if it isn't an OPF ppopt = ppoption(ppopt, 'OUT_ALL_LIM', 0) run_userfcn(results["userfcn"], 'printpf', results, fd, ppopt)
def opf_args(casefile): """Parses and initializes OPF input arguments. Returns the full set of initialized OPF input arguments, filling in default values for missing arguments. See Examples below for the possible calling syntax options. Input arguments options:: opf_args(ppc) opf_args(ppc, ppopt) opf_args(ppc, userfcn, ppopt) opf_args(ppc, A, l, u) opf_args(ppc, A, l, u, ppopt) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw, z0, zl, zu) opf_args(baseMVA, bus, gen, branch, areas, gencost) opf_args(baseMVA, bus, gen, branch, areas, gencost, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw, z0, zl, zu) The data for the problem can be specified in one of three ways: 1. a string (ppc) containing the file name of a PYPOWER case which defines the data matrices baseMVA, bus, gen, branch, and gencost (areas is not used at all, it is only included for backward compatibility of the API). 2. a dict (ppc) containing the data matrices as fields. 3. the individual data matrices themselves. The optional user parameters for user constraints (C{A, l, u}), user costs (C{N, fparm, H, Cw}), user variable initializer (z0), and user variable limits (C{zl, zu}) can also be specified as fields in a case dict, either passed in directly or defined in a case file referenced by name. When specified, C{A, l, u} represent additional linear constraints on the optimization variables, C{l <= A*[x z] <= u}. If the user specifies an C{A} matrix that has more columns than the number of "C{x}" (OPF) variables, then there are extra linearly constrained "C{z}" variables. For an explanation of the formulation used and instructions for forming the C{A} matrix, see the MATPOWER manual. A generalized cost on all variables can be applied if input arguments C{N}, C{fparm}, C{H} and C{Cw} are specified. First, a linear transformation of the optimization variables is defined by means of C{r = N * [x z]}. Then, to each element of r a function is applied as encoded in the C{fparm} matrix (see Matpower manual). If the resulting vector is named C{w}, then C{H} and C{Cw} define a quadratic cost on C{w}: C{(1/2)*w'*H*w + Cw * w}. C{H} and C{N} should be sparse matrices and C{H} should also be symmetric. The optional C{ppopt} vector specifies PYPOWER options. See L{ppoption} for details and default values. @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) """ # nargin = len([arg for arg in [baseMVA, bus, gen, branch, areas, gencost, # Au, lbu, ubu, ppopt, N, fparm, H, Cw, # z0, zl, zu] if arg is not None]) ## passing filename or dict if isinstance(casefile, dict): zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = array([]) lbu = array([]) Au = None ppc = casefile baseMVA, bus, gen, branch = \ ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch'] return baseMVA, bus, gen, branch, ppopt else: stderr.write('opf_args: Incorrect input arg order, number or type\n') return array([]), array([]), array([]), array([]), array([])
def printpf(baseMVA, bus=None, gen=None, branch=None, f=None, success=None, et=None, fd=None, ppopt=None): """Prints power flow results. Prints power flow and optimal power flow results to C{fd} (a file descriptor which defaults to C{stdout}), with the details of what gets printed controlled by the optional C{ppopt} argument, which is a PYPOWER options vector (see L{ppoption} for details). The data can either be supplied in a single C{results} dict, or in the individual arguments: C{baseMVA}, C{bus}, C{gen}, C{branch}, C{f}, C{success} and C{et}, where C{f} is the OPF objective function value, C{success} is C{True} if the solution converged and C{False} otherwise, and C{et} is the elapsed time for the computation in seconds. If C{f} is given, it is assumed that the output is from an OPF run, otherwise it is assumed to be a simple power flow run. Examples:: ppopt = ppoptions(OUT_GEN=1, OUT_BUS=0, OUT_BRANCH=0) fd = open(fname, 'w+b') results = runopf(ppc) printpf(results) printpf(results, fd) printpf(results, fd, ppopt) printpf(baseMVA, bus, gen, branch, f, success, et) printpf(baseMVA, bus, gen, branch, f, success, et, fd) printpf(baseMVA, bus, gen, branch, f, success, et, fd, ppopt) fd.close() @author: Ray Zimmerman (PSERC Cornell) """ ##----- initialization ----- ## default arguments if isinstance(baseMVA, dict): have_results_struct = 1 results = baseMVA if gen is None: ppopt = ppoption() ## use default options else: ppopt = gen if (ppopt['OUT_ALL'] == 0): return ## nothin' to see here, bail out now if bus is None: fd = stdout ## print to stdout by default else: fd = bus baseMVA, bus, gen, branch, success, et = \ results["baseMVA"], results["bus"], results["gen"], \ results["branch"], results["success"], results["et"] if 'f' in results: f = results["f"] else: f = None else: have_results_struct = 0 if ppopt is None: ppopt = ppoption() ## use default options if fd is None: fd = stdout ## print to stdout by default if ppopt['OUT_ALL'] == 0: return ## nothin' to see here, bail out now isOPF = f is not None ## FALSE -> only simple PF data, TRUE -> OPF data ## options isDC = ppopt['PF_DC'] ## use DC formulation? OUT_ALL = ppopt['OUT_ALL'] OUT_ANY = OUT_ALL == 1 ## set to true if any pretty output is to be generated OUT_SYS_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_SYS_SUM']) OUT_AREA_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_AREA_SUM']) OUT_BUS = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BUS']) OUT_BRANCH = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BRANCH']) OUT_GEN = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_GEN']) OUT_ANY = OUT_ANY | ( (OUT_ALL == -1) and (OUT_SYS_SUM or OUT_AREA_SUM or OUT_BUS or OUT_BRANCH or OUT_GEN)) if OUT_ALL == -1: OUT_ALL_LIM = ppopt['OUT_ALL_LIM'] elif OUT_ALL == 1: OUT_ALL_LIM = 2 else: OUT_ALL_LIM = 0 OUT_ANY = OUT_ANY or (OUT_ALL_LIM >= 1) if OUT_ALL_LIM == -1: OUT_V_LIM = ppopt['OUT_V_LIM'] OUT_LINE_LIM = ppopt['OUT_LINE_LIM'] OUT_PG_LIM = ppopt['OUT_PG_LIM'] OUT_QG_LIM = ppopt['OUT_QG_LIM'] else: OUT_V_LIM = OUT_ALL_LIM OUT_LINE_LIM = OUT_ALL_LIM OUT_PG_LIM = OUT_ALL_LIM OUT_QG_LIM = OUT_ALL_LIM OUT_ANY = OUT_ANY or ( (OUT_ALL_LIM == -1) and (OUT_V_LIM or OUT_LINE_LIM or OUT_PG_LIM or OUT_QG_LIM)) ptol = 1e-4 ## tolerance for displaying shadow prices ## create map of external bus numbers to bus indices i2e = bus[:, BUS_I].astype(int) e2i = zeros(max(i2e) + 1, int) e2i[i2e] = arange(bus.shape[0]) ## sizes of things nb = bus.shape[0] ## number of buses nl = branch.shape[0] ## number of branches ng = gen.shape[0] ## number of generators ## zero out some data to make printout consistent for DC case if isDC: bus[:, r_[QD, BS]] = zeros((nb, 2)) gen[:, r_[QG, QMAX, QMIN]] = zeros((ng, 3)) branch[:, r_[BR_R, BR_B]] = zeros((nl, 2)) ## parameters ties = find( bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA]) ## area inter-ties tap = ones(nl) ## default tap ratio = 1 for lines xfmr = find(branch[:, TAP]) ## indices of transformers tap[xfmr] = branch[xfmr, TAP] ## include transformer tap ratios tap = tap * exp(1j * pi / 180 * branch[:, SHIFT]) ## add phase shifters nzld = find((bus[:, PD] != 0.0) | (bus[:, QD] != 0.0)) sorted_areas = sort(bus[:, BUS_AREA]) ## area numbers s_areas = sorted_areas[r_[1, find(diff(sorted_areas)) + 1]] nzsh = find((bus[:, GS] != 0.0) | (bus[:, BS] != 0.0)) allg = find(~isload(gen)) ong = find((gen[:, GEN_STATUS] > 0) & ~isload(gen)) onld = find((gen[:, GEN_STATUS] > 0) & isload(gen)) V = bus[:, VM] * exp(-1j * pi / 180 * bus[:, VA]) out = find(branch[:, BR_STATUS] == 0) ## out-of-service branches nout = len(out) if isDC: loss = zeros(nl) else: loss = baseMVA * abs(V[e2i[ branch[:, F_BUS].astype(int) ]] / tap - V[e2i[ branch[:, T_BUS].astype(int) ]])**2 / \ (branch[:, BR_R] - 1j * branch[:, BR_X]) fchg = abs(V[e2i[branch[:, F_BUS].astype(int)]] / tap)**2 * branch[:, BR_B] * baseMVA / 2 tchg = abs( V[e2i[branch[:, T_BUS].astype(int)]])**2 * branch[:, BR_B] * baseMVA / 2 loss[out] = zeros(nout) fchg[out] = zeros(nout) tchg[out] = zeros(nout) ##----- print the stuff ----- if OUT_ANY: ## convergence & elapsed time if success: fd.write('\nConverged in %.2f seconds' % et) else: fd.write('\nDid not converge (%.2f seconds)\n' % et) ## objective function value if isOPF: fd.write('\nObjective Function Value = %.2f $/hr' % f) if OUT_SYS_SUM: fd.write( '\n================================================================================' ) fd.write( '\n| System Summary |' ) fd.write( '\n================================================================================' ) fd.write( '\n\nHow many? How much? P (MW) Q (MVAr)' ) fd.write( '\n--------------------- ------------------- ------------- -----------------' ) fd.write( '\nBuses %6d Total Gen Capacity %7.1f %7.1f to %.1f' % (nb, sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum(gen[allg, QMAX]))) fd.write( '\nGenerators %5d On-line Capacity %7.1f %7.1f to %.1f' % (len(allg), sum(gen[ong, PMAX]), sum( gen[ong, QMIN]), sum(gen[ong, QMAX]))) fd.write( '\nCommitted Gens %5d Generation (actual) %7.1f %7.1f' % (len(ong), sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write( '\nLoads %5d Load %7.1f %7.1f' % (len(nzld) + len(onld), sum(bus[nzld, PD]) - sum(gen[onld, PG]), sum(bus[nzld, QD]) - sum(gen[onld, QG]))) fd.write( '\n Fixed %5d Fixed %7.1f %7.1f' % (len(nzld), sum(bus[nzld, PD]), sum(bus[nzld, QD]))) fd.write( '\n Dispatchable %5d Dispatchable %7.1f of %-7.1f%7.1f' % (len(onld), -sum(gen[onld, PG]), -sum(gen[onld, PMIN]), -sum(gen[onld, QG]))) fd.write( '\nShunts %5d Shunt (inj) %7.1f %7.1f' % (len(nzsh), -sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]))) fd.write( '\nBranches %5d Losses (I^2 * Z) %8.2f %8.2f' % (nl, sum(loss.real), sum(loss.imag))) fd.write( '\nTransformers %5d Branch Charging (inj) - %7.1f' % (len(xfmr), sum(fchg) + sum(tchg))) fd.write( '\nInter-ties %5d Total Inter-tie Flow %7.1f %7.1f' % (len(ties), sum(abs(branch[ties, PF] - branch[ties, PT])) / 2, sum(abs(branch[ties, QF] - branch[ties, QT])) / 2)) fd.write('\nAreas %5d' % len(s_areas)) fd.write('\n') fd.write( '\n Minimum Maximum') fd.write( '\n ------------------------- --------------------------------' ) minv = min(bus[:, VM]) mini = argmin(bus[:, VM]) maxv = max(bus[:, VM]) maxi = argmax(bus[:, VM]) fd.write( '\nVoltage Magnitude %7.3f p.u. @ bus %-4d %7.3f p.u. @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, VA]) mini = argmin(bus[:, VA]) maxv = max(bus[:, VA]) maxi = argmax(bus[:, VA]) fd.write( '\nVoltage Angle %8.2f deg @ bus %-4d %8.2f deg @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) if not isDC: maxv = max(loss.real) maxi = argmax(loss.real) fd.write( '\nP Losses (I^2*R) - %8.2f MW @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) maxv = max(loss.imag) maxi = argmax(loss.imag) fd.write( '\nQ Losses (I^2*X) - %8.2f MVAr @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) if isOPF: minv = min(bus[:, LAM_P]) mini = argmin(bus[:, LAM_P]) maxv = max(bus[:, LAM_P]) maxi = argmax(bus[:, LAM_P]) fd.write( '\nLambda P %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, LAM_Q]) mini = argmin(bus[:, LAM_Q]) maxv = max(bus[:, LAM_Q]) maxi = argmax(bus[:, LAM_Q]) fd.write( '\nLambda Q %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) fd.write('\n') if OUT_AREA_SUM: fd.write( '\n================================================================================' ) fd.write( '\n| Area Summary |' ) fd.write( '\n================================================================================' ) fd.write( '\nArea # of # of Gens # of Loads # of # of # of # of' ) fd.write( '\n Num Buses Total Online Total Fixed Disp Shunt Brchs Xfmrs Ties' ) fd.write( '\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----' ) for i in range(len(s_areas)): a = s_areas[i] ib = find(bus[:, BUS_AREA] == a) ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) in_tie = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a)) out_tie = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) if not any(xfmr + 1): nxfmr = 0 else: nxfmr = len( find((bus[e2i[branch[xfmr, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[xfmr, T_BUS].astype(int)], BUS_AREA] == a))) fd.write('\n%3d %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (a, len(ib), len(ig), len(igon), \ len(inzld)+len(ildon), len(inzld), len(ildon), \ len(inzsh), len(ibrch), nxfmr, len(in_tie)+len(out_tie))) fd.write( '\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----' ) fd.write( '\nTot: %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (nb, len(allg), len(ong), len(nzld) + len(onld), len(nzld), len(onld), len(nzsh), nl, len(xfmr), len(ties))) fd.write('\n') fd.write( '\nArea Total Gen Capacity On-line Gen Capacity Generation' ) fd.write( '\n Num MW MVAr MW MVAr MW MVAr' ) fd.write( '\n---- ------ ------------------ ------ ------------------ ------ ------' ) for i in range(len(s_areas)): a = s_areas[i] ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) fd.write( '\n%3d %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (a, sum(gen[ig, PMAX]), sum(gen[ig, QMIN]), sum( gen[ig, QMAX]), sum(gen[igon, PMAX]), sum(gen[igon, QMIN]), sum(gen[igon, QMAX]), sum(gen[igon, PG]), sum(gen[igon, QG]))) fd.write( '\n---- ------ ------------------ ------ ------------------ ------ ------' ) fd.write( '\nTot: %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum( gen[allg, QMAX]), sum(gen[ong, PMAX]), sum(gen[ong, QMIN]), sum(gen[ong, QMAX]), sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\n') fd.write( '\nArea Disp Load Cap Disp Load Fixed Load Total Load' ) fd.write( '\n Num MW MVAr MW MVAr MW MVAr MW MVAr' ) fd.write( '\n---- ------ ------ ------ ------ ------ ------ ------ ------' ) Qlim = (gen[:, QMIN] == 0) * gen[:, QMAX] + (gen[:, QMAX] == 0) * gen[:, QMIN] for i in range(len(s_areas)): a = s_areas[i] ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) fd.write( '\n%3d %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (a, -sum(gen[ildon, PMIN]), -sum(Qlim[ildon]), -sum(gen[ildon, PG]), -sum(gen[ildon, QG]), sum(bus[inzld, PD]), sum(bus[inzld, QD]), -sum(gen[ildon, PG]) + sum(bus[inzld, PD]), -sum(gen[ildon, QG]) + sum(bus[inzld, QD]))) fd.write( '\n---- ------ ------ ------ ------ ------ ------ ------ ------' ) fd.write( '\nTot: %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (-sum(gen[onld, PMIN]), -sum(Qlim[onld]), -sum(gen[onld, PG]), -sum(gen[onld, QG]), sum(bus[nzld, PD]), sum( bus[nzld, QD]), -sum(gen[onld, PG]) + sum(bus[nzld, PD]), -sum(gen[onld, QG]) + sum(bus[nzld, QD]))) fd.write('\n') fd.write( '\nArea Shunt Inj Branch Series Losses Net Export' ) fd.write( '\n Num MW MVAr Charging MW MVAr MW MVAr' ) fd.write( '\n---- ------ ------ -------- ------ ------ ------ ------' ) for i in range(len(s_areas)): a = s_areas[i] inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) in_tie = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) out_tie = find( (bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a) & branch[:, BR_STATUS].astype(bool)) fd.write( '\n%3d %7.1f %7.1f %7.1f %7.2f %7.2f %7.1f %7.1f' % (a, -sum(bus[inzsh, VM]**2 * bus[inzsh, GS]), sum(bus[inzsh, VM]**2 * bus[inzsh, BS]), sum(fchg[ibrch]) + sum(tchg[ibrch]) + sum(fchg[out_tie]) + sum(tchg[in_tie]), sum(real(loss[ibrch])) + sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(imag(loss[ibrch])) + sum(imag(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, PT]) + sum(branch[out_tie, PF]) - sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, QT]) + sum(branch[out_tie, QF]) - sum(imag(loss[r_[in_tie, out_tie]])) / 2)) fd.write( '\n---- ------ ------ -------- ------ ------ ------ ------' ) fd.write( '\nTot: %7.1f %7.1f %7.1f %7.2f %7.2f - -' % (-sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]), sum(fchg) + sum(tchg), sum(real(loss)), sum(imag(loss)))) fd.write('\n') ## generator data if OUT_GEN: if isOPF: genlamP = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_P] genlamQ = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_Q] fd.write( '\n================================================================================' ) fd.write( '\n| Generator Data |' ) fd.write( '\n================================================================================' ) fd.write('\n Gen Bus Status Pg Qg ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(ong)): i = ong[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or(gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (gen[i, PG], gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\n') if any(onld + 1): fd.write( '\n================================================================================' ) fd.write( '\n| Dispatchable Load Data |' ) fd.write( '\n================================================================================' ) fd.write('\n Gen Bus Status Pd Qd ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(onld)): i = onld[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or( gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (-gen[i, PG], -gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (-sum(gen[onld, PG]), -sum(gen[onld, QG]))) fd.write('\n') ## bus data if OUT_BUS: fd.write( '\n================================================================================' ) fd.write( '\n| Bus Data |' ) fd.write( '\n================================================================================' ) fd.write( '\n Bus Voltage Generation Load ') if isOPF: fd.write(' Lambda($/MVA-hr)') fd.write( '\n # Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr)') if isOPF: fd.write(' P Q ') fd.write( '\n----- ------- -------- -------- -------- -------- --------') if isOPF: fd.write(' ------- -------') for i in range(nb): fd.write('\n%5d%7.3f%9.3f' % tuple(bus[i, [BUS_I, VM, VA]])) if bus[i, BUS_TYPE] == REF: fd.write('*') else: fd.write(' ') g = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & ~isload(gen)) ld = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & isload(gen)) if any(g + 1): fd.write('%9.2f%10.2f' % (sum(gen[g, PG]), sum(gen[g, QG]))) else: fd.write(' - - ') if logical_or(bus[i, PD], bus[i, QD]) | any(ld + 1): if any(ld + 1): fd.write('%10.2f*%9.2f*' % (bus[i, PD] - sum(gen[ld, PG]), bus[i, QD] - sum(gen[ld, QG]))) else: fd.write('%10.2f%10.2f ' % tuple(bus[i, [PD, QD]])) else: fd.write(' - - ') if isOPF: fd.write('%9.3f' % bus[i, LAM_P]) if abs(bus[i, LAM_Q]) > ptol: fd.write('%8.3f' % bus[i, LAM_Q]) else: fd.write(' -') fd.write( '\n -------- -------- -------- --------') fd.write('\n Total: %9.2f %9.2f %9.2f %9.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]), sum(bus[nzld, PD]) - sum(gen[onld, PG]), sum(bus[nzld, QD]) - sum(gen[onld, QG]))) fd.write('\n') ## branch data if OUT_BRANCH: fd.write( '\n================================================================================' ) fd.write( '\n| Branch Data |' ) fd.write( '\n================================================================================' ) fd.write( '\nBrnch From To From Bus Injection To Bus Injection Loss (I^2 * Z) ' ) fd.write( '\n # Bus Bus P (MW) Q (MVAr) P (MW) Q (MVAr) P (MW) Q (MVAr)' ) fd.write( '\n----- ----- ----- -------- -------- -------- -------- -------- --------' ) for i in range(nl): fd.write('\n%4d%7d%7d%10.2f%10.2f%10.2f%10.2f%10.3f%10.2f' % (i, branch[i, F_BUS], branch[i, T_BUS], branch[i, PF], branch[i, QF], branch[i, PT], branch[i, QT], loss[i].real, loss[i].imag)) fd.write( '\n -------- --------' ) fd.write( '\n Total:%10.3f%10.2f' % (sum(real(loss)), sum(imag(loss)))) fd.write('\n') ##----- constraint data ----- if isOPF: ctol = ppopt['OPF_VIOLATION'] ## constraint violation tolerance ## voltage constraints if (not isDC) & ( OUT_V_LIM == 2 | (OUT_V_LIM == 1 & (any(bus[:, VM] < bus[:, VMIN] + ctol) | any(bus[:, VM] > bus[:, VMAX] - ctol) | any(bus[:, MU_VMIN] > ptol) | any(bus[:, MU_VMAX] > ptol)))): fd.write( '\n================================================================================' ) fd.write( '\n| Voltage Constraints |' ) fd.write( '\n================================================================================' ) fd.write('\nBus # Vmin mu Vmin |V| Vmax Vmax mu') fd.write('\n----- -------- ----- ----- ----- --------') for i in range(nb): if (OUT_V_LIM == 2) | (OUT_V_LIM == 1 & ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMIN] > ptol) | (bus[i, MU_VMAX] > ptol))): fd.write('\n%5d' % bus[i, BUS_I]) if ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, MU_VMIN] > ptol)): fd.write('%10.3f' % bus[i, MU_VMIN]) else: fd.write(' - ') fd.write('%8.3f%7.3f%7.3f' % tuple(bus[i, [VMIN, VM, VMAX]])) if (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMAX] > ptol): fd.write('%10.3f' % bus[i, MU_VMAX]) else: fd.write(' - ') fd.write('\n') ## generator P constraints if (OUT_PG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))) | \ ((not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol))))): fd.write( '\n================================================================================' ) fd.write( '\n| Generation Constraints |' ) fd.write( '\n================================================================================' ) if (OUT_PG_LIM == 2) | ( (OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))): fd.write('\n Gen Bus Active Power Limits') fd.write( '\n # # Pmin mu Pmin Pg Pmax Pmax mu' ) fd.write( '\n---- ----- ------- -------- -------- -------- -------' ) for k in range(len(ong)): i = ong[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%4d%6d ' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [PMIN, PG, PMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [PMIN, PMAX]])) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## generator Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ( (OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write( '\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write( '\n--- --- ------- -------- -------- -------- -------') for k in range(len(ong)): i = ong[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [QMIN, QG, QMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [QMIN, QMAX]])) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load P constraints if (OUT_PG_LIM == 2) | (OUT_QG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))) | \ ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol))): fd.write( '\n================================================================================' ) fd.write( '\n| Dispatchable Load Constraints |' ) fd.write( '\n================================================================================' ) if (OUT_PG_LIM == 2) | ( (OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))): fd.write('\nGen Bus Active Power Limits') fd.write( '\n # # Pmin mu Pmin Pg Pmax Pmax mu') fd.write( '\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [PMIN, PG, PMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [PMIN, PMAX]]) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write( '\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write( '\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen(i, GEN_BUS))) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [QMIN, QG, QMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [QMIN, QMAX]]) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## line flow constraints if (ppopt['OPF_FLOW_LIM'] == 1) | isDC: ## P limit Ff = branch[:, PF] Ft = branch[:, PT] strg = '\n # Bus Pf mu Pf |Pmax| Pt Pt mu Bus' elif ppopt['OPF_FLOW_LIM'] == 2: ## |I| limit Ff = abs((branch[:, PF] + 1j * branch[:, QF]) / V[e2i[branch[:, F_BUS].astype(int)]]) Ft = abs((branch[:, PT] + 1j * branch[:, QT]) / V[e2i[branch[:, T_BUS].astype(int)]]) strg = '\n # Bus |If| mu |If| |Imax| |It| |It| mu Bus' else: ## |S| limit Ff = abs(branch[:, PF] + 1j * branch[:, QF]) Ft = abs(branch[:, PT] + 1j * branch[:, QT]) strg = '\n # Bus |Sf| mu |Sf| |Smax| |St| |St| mu Bus' if (OUT_LINE_LIM == 2) | ( (OUT_LINE_LIM == 1) & (any((branch[:, RATE_A] != 0) & (abs(Ff) > branch[:, RATE_A] - ctol)) | any( (branch[:, RATE_A] != 0) & (abs(Ft) > branch[:, RATE_A] - ctol)) | any(branch[:, MU_SF] > ptol) | any(branch[:, MU_ST] > ptol))): fd.write( '\n================================================================================' ) fd.write( '\n| Branch Flow Constraints |' ) fd.write( '\n================================================================================' ) fd.write( '\nBrnch From "From" End Limit "To" End To' ) fd.write(strg) fd.write( '\n----- ----- ------- -------- -------- -------- ------- -----' ) for i in range(nl): if (OUT_LINE_LIM == 2) | ((OUT_LINE_LIM == 1) & ( ((branch[i, RATE_A] != 0) & (abs(Ff[i]) > branch[i, RATE_A] - ctol)) | ((branch[i, RATE_A] != 0) & (abs(Ft[i]) > branch[i, RATE_A] - ctol)) | (branch[i, MU_SF] > ptol) | (branch[i, MU_ST] > ptol))): fd.write('\n%4d%7d' % (i, branch[i, F_BUS])) if (Ff[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_SF] > ptol): fd.write('%10.3f' % branch[i, MU_SF]) else: fd.write(' - ') fd.write('%9.2f%10.2f%10.2f' % (Ff[i], branch[i, RATE_A], Ft[i])) if (Ft[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_ST] > ptol): fd.write('%10.3f' % branch[i, MU_ST]) else: fd.write(' - ') fd.write('%6d' % branch[i, T_BUS]) fd.write('\n') ## execute userfcn callbacks for 'printpf' stage if have_results_struct and 'userfcn' in results: if not isOPF: ## turn off option for all constraints if it isn't an OPF ppopt = ppoption(ppopt, 'OUT_ALL_LIM', 0) run_userfcn(results["userfcn"], 'printpf', results, fd, ppopt)
def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None): """Solves the power flow using a full Newton's method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see L{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ## default arguments if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0 Va = angle(V) Vm = abs(V) ## set up indexing for updating V pvpq = r_[pv, pq] npv = len(pv) npq = len(pq) j1 = 0; j2 = npv ## j1:j2 - V angle of pv buses j3 = j2; j4 = j2 + npq ## j3:j4 - V angle of pq buses j5 = j4; j6 = j4 + npq ## j5:j6 - V mag of pq buses ## evaluate F(x0) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check tolerance normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n it max P & Q mismatch (p.u.)') sys.stdout.write('\n---- ---------------------------') sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## do Newton iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ## evaluate Jacobian dS_dVm, dS_dVa = dSbus_dV(Ybus, V) J11 = dS_dVa[array([pvpq]).T, pvpq].real J12 = dS_dVm[array([pvpq]).T, pq].real J21 = dS_dVa[array([pq]).T, pvpq].imag J22 = dS_dVm[array([pq]).T, pq].imag J = vstack([ hstack([J11, J12]), hstack([J21, J22]) ], format="csr") ## compute update step dx = -1 * spsolve(J, F) ## update voltage if npv: Va[pv] = Va[pv] + dx[j1:j2] if npq: Va[pq] = Va[pq] + dx[j3:j4] Vm[pq] = Vm[pq] + dx[j5:j6] V = Vm * exp(1j * Va) Vm = abs(V) ## update Vm and Va again in case Va = angle(V) ## we wrapped around with a negative Vm ## evalute F(x) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check for convergence normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose: sys.stdout.write("\nNewton's method power flow converged in " "%d iterations.\n" % i) if verbose: if not converged: sys.stdout.write("\nNewton's method power did not converge in %d " "iterations.\n" % i) return V, converged, i