def ext2int(ppc, val_or_field=None, ordering=None, dim=0): """Converts external to internal indexing. This function has two forms, the old form that operates on and returns individual matrices and the new form that operates on and returns an entire PYPOWER case dict. 1. C{ppc = ext2int(ppc)} If the input is a single PYPOWER case dict, then all isolated buses, off-line generators and branches are removed along with any generators, branches or areas connected to isolated buses. Then the buses are renumbered consecutively, beginning at 0, and the generators are sorted by increasing bus number. Any 'ext2int' callback routines registered in the case are also invoked automatically. All of the related indexing information and the original data matrices are stored under the 'order' key of the dict to be used by C{int2ext} to perform the reverse conversions. If the case is already using internal numbering it is returned unchanged. Example:: ppc = ext2int(ppc) @see: L{int2ext}, L{e2i_field}, L{e2i_data} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ppc = deepcopy(ppc) if val_or_field is None: # nargin == 1 first = 'order' not in ppc if first or ppc["order"]["state"] == 'e': ## initialize order if first: o = { 'ext': { 'bus': None, 'branch': None, 'gen': None }, 'bus': { 'e2i': None, 'i2e': None, 'status': {} }, 'gen': { 'e2i': None, 'i2e': None, 'status': {} }, 'branch': { 'status': {} } } else: o = ppc["order"] ## sizes nb = ppc["bus"].shape[0] ng = ppc["gen"].shape[0] ng0 = ng if 'A' in ppc: dc = True if ppc["A"].shape[1] < (2 * nb + 2 * ng) else False elif 'N' in ppc: dc = True if ppc["N"].shape[1] < (2 * nb + 2 * ng) else False else: dc = False ## save data matrices with external ordering if 'ext' not in o: o['ext'] = {} o["ext"]["bus"] = ppc["bus"].copy() o["ext"]["branch"] = ppc["branch"].copy() o["ext"]["gen"] = ppc["gen"].copy() if 'areas' in ppc: if len(ppc["areas"]) == 0: ## if areas field is empty del ppc['areas'] ## delete it (so it's ignored) else: ## otherwise o["ext"]["areas"] = ppc["areas"].copy() ## save it ## check that all buses have a valid BUS_TYPE bt = ppc["bus"][:, BUS_TYPE] err = find(~((bt == PQ) | (bt == PV) | (bt == REF) | (bt == NONE))) if len(err) > 0: sys.stderr.write('ext2int: bus %d has an invalid BUS_TYPE\n' % err) ## determine which buses, branches, gens are connected and ## in-service n2i = sparse((range(nb), (ppc["bus"][:, BUS_I], zeros(nb))), shape=(max(ppc["bus"][:, BUS_I]) + 1, 1)) n2i = array( n2i.todense().flatten() )[0, :] # as 1D array bs = (bt != NONE) ## bus status o["bus"]["status"]["on"] = find( bs ) ## connected o["bus"]["status"]["off"] = find( ~bs ) ## isolated gs = ( (ppc["gen"][:, GEN_STATUS] > 0) & ## gen status bs[ n2i[ppc["gen"][:, GEN_BUS].astype(int)] ] ) o["gen"]["status"]["on"] = find( gs ) ## on and connected o["gen"]["status"]["off"] = find( ~gs ) ## off or isolated brs = ( ppc["branch"][:, BR_STATUS].astype(int) & ## branch status bs[n2i[ppc["branch"][:, F_BUS].astype(int)]] & bs[n2i[ppc["branch"][:, T_BUS].astype(int)]] ).astype(bool) o["branch"]["status"]["on"] = find( brs ) ## on and conn o["branch"]["status"]["off"] = find( ~brs ) if 'areas' in ppc: ar = bs[ n2i[ppc["areas"][:, PRICE_REF_BUS].astype(int)] ] o["areas"] = {"status": {}} o["areas"]["status"]["on"] = find( ar ) o["areas"]["status"]["off"] = find( ~ar ) ## delete stuff that is "out" if len(o["bus"]["status"]["off"]) > 0: # ppc["bus"][o["bus"]["status"]["off"], :] = array([]) ppc["bus"] = ppc["bus"][o["bus"]["status"]["on"], :] if len(o["branch"]["status"]["off"]) > 0: # ppc["branch"][o["branch"]["status"]["off"], :] = array([]) ppc["branch"] = ppc["branch"][o["branch"]["status"]["on"], :] if len(o["gen"]["status"]["off"]) > 0: # ppc["gen"][o["gen"]["status"]["off"], :] = array([]) ppc["gen"] = ppc["gen"][o["gen"]["status"]["on"], :] if 'areas' in ppc and (len(o["areas"]["status"]["off"]) > 0): # ppc["areas"][o["areas"]["status"]["off"], :] = array([]) ppc["areas"] = ppc["areas"][o["areas"]["status"]["on"], :] ## update size nb = ppc["bus"].shape[0] ## apply consecutive bus numbering o["bus"]["i2e"] = ppc["bus"][:, BUS_I].copy() o["bus"]["e2i"] = zeros(int(max(o["bus"]["i2e"])) + 1) o["bus"]["e2i"][o["bus"]["i2e"].astype(int)] = arange(nb) ppc["bus"][:, BUS_I] = \ o["bus"]["e2i"][ ppc["bus"][:, BUS_I].astype(int) ].copy() ppc["gen"][:, GEN_BUS] = \ o["bus"]["e2i"][ ppc["gen"][:, GEN_BUS].astype(int) ].copy() ppc["branch"][:, F_BUS] = \ o["bus"]["e2i"][ ppc["branch"][:, F_BUS].astype(int) ].copy() ppc["branch"][:, T_BUS] = \ o["bus"]["e2i"][ ppc["branch"][:, T_BUS].astype(int) ].copy() if 'areas' in ppc: ppc["areas"][:, PRICE_REF_BUS] = \ o["bus"]["e2i"][ ppc["areas"][:, PRICE_REF_BUS].astype(int) ].copy() ## reorder gens in order of increasing bus number o["gen"]["e2i"] = argsort(ppc["gen"][:, GEN_BUS]) o["gen"]["i2e"] = argsort(o["gen"]["e2i"]) ppc["gen"] = ppc["gen"][o["gen"]["e2i"].astype(int), :] if 'int' in o: del o['int'] o["state"] = 'i' ppc["order"] = o ## update gencost, A and N if 'gencost' in ppc: ordering = ['gen'] ## Pg cost only if ppc["gencost"].shape[0] == (2 * ng0): ordering.append('gen') ## include Qg cost ppc = e2i_field(ppc, 'gencost', ordering) if 'A' in ppc or 'N' in ppc: if dc: ordering = ['bus', 'gen'] else: ordering = ['bus', 'bus', 'gen', 'gen'] if 'A' in ppc: ppc = e2i_field(ppc, 'A', ordering, 1) if 'N' in ppc: ppc = e2i_field(ppc, 'N', ordering, 1) ## execute userfcn callbacks for 'ext2int' stage if 'userfcn' in ppc: ppc = run_userfcn(ppc['userfcn'], 'ext2int', ppc) else: ## convert extra data if isinstance(val_or_field, str) or isinstance(val_or_field, list): ## field warn('Calls of the form ppc = ext2int(ppc, ' '\'field_name\', ...) have been deprecated. Please ' 'replace ext2int with e2i_field.', DeprecationWarning) gen, branch = val_or_field, ordering ppc = e2i_field(ppc, gen, branch, dim) else: ## value warn('Calls of the form val = ext2int(ppc, val, ...) have been ' 'deprecated. Please replace ext2int with e2i_data.', DeprecationWarning) gen, branch = val_or_field, ordering ppc = e2i_data(ppc, gen, branch, dim) return ppc
def savecase(fname, ppc, comment=None, version='2'): """Saves a PYPOWER case file, given a filename and the data. Writes a PYPOWER case file, given a filename and data dict. The C{fname} parameter is the name of the file to be created or overwritten. Returns the filename, with extension added if necessary. The optional C{comment} argument is either string (single line comment) or a list of strings which are inserted as comments. When using a PYPOWER case dict, if the optional C{version} argument is '1' it will modify the data matrices to version 1 format before saving. @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ppc_ver = ppc["version"] = version baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] areas = ppc["areas"] if "areas" in ppc else None gencost = ppc["gencost"] if "gencost" in ppc else None ## modifications for version 1 format if ppc_ver == "1": raise NotImplementedError # ## remove extra columns of gen # if gen.shape[1] >= MU_QMIN: # gen = c_[gen[:, :PMIN], gen[:, MU_PMAX:MU_QMIN]] # else: # gen = gen[:, :PMIN] # ## use the version 1 values for column names # shift = MU_PMAX - PMIN - 1 # tmp = array([MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN]) - shift # MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN = tmp # # ## remove extra columns of branch # if branch.shape[1] >= MU_ST: # branch = c_[branch[:, :BR_STATUS], branch[:, PF:MU_ST]] # elif branch.shape[1] >= QT: # branch = c_[branch[:, :BR_STATUS], branch[:, PF:QT]] # else: # branch = branch[:, :BR_STATUS] # ## use the version 1 values for column names # shift = PF - BR_STATUS - 1 # tmp = array([PF, QF, PT, QT, MU_SF, MU_ST]) - shift # PF, QF, PT, QT, MU_SF, MU_ST = tmp ## verify valid filename l = len(fname) rootname = "" if l > 2: if fname[-3:] == ".py": rootname = fname[:-3] extension = ".py" elif l > 4: if fname[-4:] == ".mat": rootname = fname[:-4] extension = ".mat" if not rootname: rootname = fname extension = ".py" fname = rootname + extension indent = ' ' # four spaces indent2 = indent + indent ## open and write the file if extension == ".mat": ## MAT-file savemat(fname, ppc) else: ## Python file try: fd = open(fname, "wb") except Exception as detail: stderr.write("savecase: %s.\n" % detail) return fname ## function header, etc. if ppc_ver == "1": raise NotImplementedError # if (areas != None) and (gencost != None) and (len(gencost) > 0): # fd.write('function [baseMVA, bus, gen, branch, areas, gencost] = %s\n' % rootname) # else: # fd.write('function [baseMVA, bus, gen, branch] = %s\n' % rootname) # prefix = '' else: fd.write('def %s():\n' % basename(rootname)) prefix = 'ppc' if comment: if isinstance(comment, basestring): fd.write('#%s\n' % comment) elif isinstance(comment, list): for c in comment: fd.write('#%s\n' % c) fd.write('\n%s## PYPOWER Case Format : Version %s\n' % (indent, ppc_ver)) if ppc_ver != "1": fd.write("%sppc = {'version': '%s'}\n" % (indent, ppc_ver)) fd.write('\n%s##----- Power Flow Data -----##\n' % indent) fd.write('%s## system MVA base\n' % indent) fd.write("%s%s['baseMVA'] = %.9g\n" % (indent, prefix, baseMVA)) ## bus data ncols = bus.shape[1] fd.write('\n%s## bus data\n' % indent) fd.write('%s# bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin' % indent) if ncols >= MU_VMIN + 1: ## opf SOLVED, save with lambda's & mu's fd.write('lam_P lam_Q mu_Vmax mu_Vmin') fd.write("\n%s%s['bus'] = array([\n" % (indent, prefix)) if ncols < MU_VMIN + 1: ## opf NOT SOLVED, save without lambda's & mu's for i in range(bus.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(bus[i, :VMIN + 1]))) else: ## opf SOLVED, save with lambda's & mu's for i in range(bus.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(bus[:, :MU_VMIN + 1]))) fd.write('%s])\n' % indent) ## generator data ncols = gen.shape[1] fd.write('\n%s## generator data\n' % indent) fd.write('%s# bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin' % indent) if ppc_ver != "1": fd.write(' Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf') if ncols >= MU_QMIN + 1: # opf SOLVED, save with mu's fd.write(' mu_Pmax mu_Pmin mu_Qmax mu_Qmin') fd.write("\n%s%s['gen'] = array([\n" % (indent, prefix)) if ncols < MU_QMIN + 1: ## opf NOT SOLVED, save without mu's if ppc_ver == "1": for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(gen[i, :PMIN + 1]))) else: for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g],\n' % ((indent2,) + tuple(gen[i, :APF + 1]))) else: if ppc_ver == "1": for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(gen[i, :MU_QMIN + 1]))) else: for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(gen[i, :MU_QMIN + 1]))) fd.write('%s])\n' % indent) ## branch data ncols = branch.shape[1] fd.write('\n%s## branch data\n' % indent) fd.write('%s# fbus tbus r x b rateA rateB rateC ratio angle status' % indent) if ppc_ver != "1": fd.write(' angmin angmax') if ncols >= QT + 1: ## power flow SOLVED, save with line flows fd.write(' Pf Qf Pt Qt') if ncols >= MU_ST + 1: ## opf SOLVED, save with mu's fd.write(' mu_Sf mu_St') if ppc_ver != "1": fd.write(' mu_angmin mu_angmax') fd.write('\n%s%s[\'branch\'] = array([\n' % (indent, prefix)) if ncols < QT + 1: ## power flow NOT SOLVED, save without line flows or mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d],\n' % ((indent2,) + tuple(branch[i, :BR_STATUS + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(branch[i, :ANGMAX + 1]))) elif ncols < MU_ST + 1: ## power flow SOLVED, save with line flows but without mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :QT + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :QT + 1]))) else: ## opf SOLVED, save with lineflows & mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :MU_ST + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :MU_ANGMAX + 1]))) fd.write('%s])\n' % indent) ## OPF data if (areas != None) and (len(areas) > 0) or (gencost != None) and (len(gencost) > 0): fd.write('\n%s##----- OPF Data -----##' % indent) if (areas != None) and (len(areas) > 0): ## area data fd.write('\n%s## area data\n' % indent) fd.write('%s# area refbus\n' % indent) fd.write("%s%s['areas'] = array([\n" % (indent, prefix)) if len(areas) > 0: for i in range(areas.shape[0]): fd.write('%s[%d, %d],\n' % ((indent2,) + tuple(areas[i, :PRICE_REF_BUS + 1]))) fd.write('%s])\n' % indent) if gencost != None and len(gencost) > 0: ## generator cost data fd.write('\n%s## generator cost data\n' % indent) fd.write('%s# 1 startup shutdown n x1 y1 ... xn yn\n' % indent) fd.write('%s# 2 startup shutdown n c(n-1) ... c0\n' % indent) fd.write('%s%s[\'gencost\'] = array([\n' % (indent, prefix)) if len(gencost > 0): if any(gencost[:, MODEL] == PW_LINEAR): n1 = 2 * max(gencost[gencost[:, MODEL] == PW_LINEAR, NCOST]) else: n1 = 0 if any(gencost[:, MODEL] == POLYNOMIAL): n2 = max(gencost[gencost[:, MODEL] == POLYNOMIAL, NCOST]) else: n2 = 0 n = int( max([n1, n2]) ) if gencost.shape[1] < n + 4: stderr.write('savecase: gencost data claims it has more columns than it does\n') template = '%s[%d, %.9g, %.9g, %d' for i in range(n): template = template + ', %.9g' template = template + '],\n' for i in range(gencost.shape[0]): fd.write(template % ((indent2,) + tuple(gencost[i]))) fd.write('%s])\n' % indent) ## generalized OPF user data if ("A" in ppc) and (len(ppc["A"]) > 0) or ("N" in ppc) and (len(ppc["N"]) > 0): fd.write('\n%s##----- Generalized OPF User Data -----##' % indent) ## user constraints if ("A" in ppc) and (len(ppc["A"]) > 0): ## A fd.write('\n%s## user constraints\n' % indent) print_sparse(fd, prefix + "['A']", ppc["A"]) if ("l" in ppc) and (len(ppc["l"]) > 0) and ("u" in ppc) and (len(ppc["u"]) > 0): fd.write('%slu = array([\n' % indent) for i in range(len(l)): fd.write('%s[%.9g, %.9g],\n' % (indent2, ppc["l"][i], ppc["u"][i])) fd.write('%s])\n' % indent) fd.write("%s%s['l'] = lu[:, 0]\n" % (indent, prefix)) fd.write("%s%s['u'] = lu[:, 1]\n\n" % (indent, prefix)) elif ("l" in ppc) and (len(ppc["l"]) > 0): fd.write("%s%s['l'] = array([\n" % (indent, prefix)) for i in range(len(l)): fd.write('%s[%.9g],\n' % (indent2, ppc["l"][i])) fd.write('%s])\n\n' % indent) elif ("u" in ppc) and (len(ppc["u"]) > 0): fd.write("%s%s['u'] = array([\n" % (indent, prefix)) for i in range(len(l)): fd.write('%s[%.9g],\n' % (indent2, ppc["u"][i])) fd.write('%s])\n\n' % indent) ## user costs if ("N" in ppc) and (len(ppc["N"]) > 0): fd.write('\n%s## user costs\n' % indent) print_sparse(fd, prefix + "['N']", ppc["N"]) if ("H" in ppc) and (len(ppc["H"]) > 0): print_sparse(fd, prefix + "['H']", ppc["H"]) if ("fparm" in ppc) and (len(ppc["fparm"]) > 0): fd.write("%sCw_fparm = array([\n" % indent) for i in range(ppc["Cw"]): fd.write('%s[%.9g, %d, %.9g, %.9g, %.9g],\n' % ((indent2,) + tuple(ppc["Cw"][i]) + tuple(ppc["fparm"][i, :]))) fd.write('%s])\n' % indent) fd.write('%s%s[\'Cw\'] = Cw_fparm[:, 0]\n' % (indent, prefix)) fd.write("%s%s['fparm'] = Cw_fparm[:, 1:5]\n" % (indent, prefix)) else: fd.write("%s%s['Cw'] = array([\n" % (indent, prefix)) for i in range(len(ppc["Cw"])): fd.write('%s[%.9g],\n' % (indent2, ppc["Cw"][i])) fd.write('%s])\n' % indent) ## user vars if ('z0' in ppc) or ('zl' in ppc) or ('zu' in ppc): fd.write('\n%s## user vars\n' % indent) if ('z0' in ppc) and (len(ppc['z0']) > 0): fd.write('%s%s["z0"] = array([\n' % (indent, prefix)) for i in range(len(ppc['z0'])): fd.write('%s[%.9g],\n' % (indent2, ppc["z0"])) fd.write('%s])\n' % indent) if ('zl' in ppc) and (len(ppc['zl']) > 0): fd.write('%s%s["zl"] = array([\n' % (indent2, prefix)) for i in range(len(ppc['zl'])): fd.write('%s[%.9g],\n' % (indent2, ppc["zl"])) fd.write('%s])\n' % indent) if ('zu' in ppc) and (len(ppc['zu']) > 0): fd.write('%s%s["zu"] = array([\n' % (indent, prefix)) for i in range(len(ppc['zu'])): fd.write('%s[%.9g],\n' % (indent2, ppc["zu"])) fd.write('%s])\n' % indent) ## execute userfcn callbacks for 'savecase' stage if 'userfcn' in ppc: run_userfcn(ppc["userfcn"], 'savecase', ppc, fd, prefix) fd.write('\n%sreturn ppc\n' % indent) ## close file fd.close() return fname
def opf_setup(ppc, ppopt): """Constructs an OPF model object from a PYPOWER case dict. Assumes that ppc is a PYPOWER case dict with internal indexing, all equipment in-service, etc. @see: L{opf}, L{ext2int}, L{opf_execute} @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Richard Lincoln Modified by University of Kassel (Friederike Meier): Bugfix in line 110 """ ## options dc = ppopt['PF_DC'] ## 1 = DC OPF, 0 = AC OPF alg = ppopt['OPF_ALG'] verbose = ppopt['VERBOSE'] ## data dimensions nb = ppc['bus'].shape[0] ## number of buses nl = ppc['branch'].shape[0] ## number of branches ng = ppc['gen'].shape[0] ## number of dispatchable injections if 'A' in ppc: nusr = ppc['A'].shape[0] ## number of linear user constraints else: nusr = 0 if 'N' in ppc: nw = ppc['N'].shape[0] ## number of general cost vars, w else: nw = 0 if dc: ## ignore reactive costs for DC ppc['gencost'], _ = pqcost(ppc['gencost'], ng) ## reduce A and/or N from AC dimensions to DC dimensions, if needed if nusr or nw: # pragma: no cover acc = r_[nb + arange(nb), 2 * nb + ng + arange(ng)] ## Vm and Qg columns if nusr and (ppc['A'].shape[1] >= 2*nb + 2*ng): ## make sure there aren't any constraints on Vm or Qg if ppc['A'][:, acc].nnz > 0: stderr.write('opf_setup: attempting to solve DC OPF with user constraints on Vm or Qg\n') # FIXME: delete sparse matrix columns bcc = delete(arange(ppc['A'].shape[1]), acc) ppc['A'] = ppc['A'].tolil()[:, bcc].tocsr() ## delete Vm and Qg columns if nw and (ppc['N'].shape[1] >= 2*nb + 2*ng): ## make sure there aren't any costs on Vm or Qg if ppc['N'][:, acc].nnz > 0: ii, _ = nonzero(ppc['N'][:, acc]) _, ii = unique(ii, return_index=True) ## indices of w with potential non-zero cost terms from Vm or Qg if any(ppc['Cw'][ii]) | ( ('H' in ppc) & (len(ppc['H']) > 0) & any(any(ppc['H'][:, ii])) ): stderr.write('opf_setup: attempting to solve DC OPF with user costs on Vm or Qg\n') # FIXME: delete sparse matrix columns bcc = delete(arange(ppc['N'].shape[1]), acc) ppc['N'] = ppc['N'].tolil()[:, bcc].tocsr() ## delete Vm and Qg columns ## convert single-block piecewise-linear costs into linear polynomial cost pwl1 = find((ppc['gencost'][:, MODEL] == PW_LINEAR) & (ppc['gencost'][:, NCOST] == 2)) # p1 = array([]) if len(pwl1) > 0: x0 = ppc['gencost'][pwl1, COST] y0 = ppc['gencost'][pwl1, COST + 1] x1 = ppc['gencost'][pwl1, COST + 2] y1 = ppc['gencost'][pwl1, COST + 3] m = (y1 - y0) / (x1 - x0) b = y0 - m * x0 ppc['gencost'][pwl1, MODEL] = POLYNOMIAL ppc['gencost'][pwl1, NCOST] = 2 ppc['gencost'][pwl1, COST:COST + 2] = r_['1',m.reshape(len(m),1), b.reshape(len(b),1)] # changed from ppc['gencost'][pwl1, COST:COST + 2] = r_[m, b] because we need to make sure, that m and b have the same shape, resulted in a value error due to shape mismatch before ## create (read-only) copies of individual fields for convenience baseMVA, bus, gen, branch, gencost, _, lbu, ubu, ppopt, \ _, fparm, H, Cw, z0, zl, zu, userfcn, _ = opf_args(ppc, ppopt) ## warn if there is more than one reference bus refs = find(bus[:, BUS_TYPE] == REF) if len(refs) > 1 and verbose > 0: errstr = '\nopf_setup: Warning: Multiple reference buses.\n' + \ ' For a system with islands, a reference bus in each island\n' + \ ' may help convergence, but in a fully connected system such\n' + \ ' a situation is probably not reasonable.\n\n' stdout.write(errstr) ## set up initial variables and bounds gbus = gen[:, GEN_BUS].astype(int) Va = bus[:, VA] * (pi / 180.0) Vm = bus[:, VM].copy() Vm[gbus] = gen[:, VG] ## buses with gens, init Vm from gen data Pg = gen[:, PG] / baseMVA Qg = gen[:, QG] / baseMVA Pmin = gen[:, PMIN] / baseMVA Pmax = gen[:, PMAX] / baseMVA Qmin = gen[:, QMIN] / baseMVA Qmax = gen[:, QMAX] / baseMVA if dc: ## DC model ## more problem dimensions nv = 0 ## number of voltage magnitude vars nq = 0 ## number of Qg vars q1 = array([]) ## index of 1st Qg column in Ay ## power mismatch constraints B, Bf, Pbusinj, Pfinj = makeBdc(baseMVA, bus, branch) neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], arange(ng))), (nb, ng)) ## Pbus w.r.t. Pg Amis = hstack([B, neg_Cg], 'csr') bmis = -(bus[:, PD] + bus[:, GS]) / baseMVA - Pbusinj ## branch flow constraints il = find((branch[:, RATE_A] != 0) & (branch[:, RATE_A] < 1e10)) nl2 = len(il) ## number of constrained lines lpf = -Inf * ones(nl2) upf = branch[il, RATE_A] / baseMVA - Pfinj[il] upt = branch[il, RATE_A] / baseMVA + Pfinj[il] user_vars = ['Va', 'Pg'] ycon_vars = ['Pg', 'y'] else: ## AC model ## more problem dimensions nv = nb ## number of voltage magnitude vars nq = ng ## number of Qg vars q1 = ng ## index of 1st Qg column in Ay ## dispatchable load, constant power factor constraints Avl, lvl, uvl, _ = makeAvl(baseMVA, gen) ## generator PQ capability curve constraints Apqh, ubpqh, Apql, ubpql, Apqdata = makeApq(baseMVA, gen) user_vars = ['Va', 'Vm', 'Pg', 'Qg'] ycon_vars = ['Pg', 'Qg', 'y'] ## voltage angle reference constraints Vau = Inf * ones(nb) Val = -Vau Vau[refs] = Va[refs] Val[refs] = Va[refs] ## branch voltage angle difference limits Aang, lang, uang, iang = makeAang(baseMVA, branch, nb, ppopt) ## basin constraints for piece-wise linear gen cost variables if alg == 545 or alg == 550: ## SC-PDIPM or TRALM, no CCV cost vars # pragma: no cover ny = 0 Ay = None by = array([]) else: ipwl = find(gencost[:, MODEL] == PW_LINEAR) ## piece-wise linear costs ny = ipwl.shape[0] ## number of piece-wise linear cost vars Ay, by = makeAy(baseMVA, ng, gencost, 1, q1, 1+ng+nq) if any((gencost[:, MODEL] != POLYNOMIAL) & (gencost[:, MODEL] != PW_LINEAR)): stderr.write('opf_setup: some generator cost rows have invalid MODEL value\n') ## more problem dimensions nx = nb+nv + ng+nq ## number of standard OPF control variables if nusr: # pragma: no cover nz = ppc['A'].shape[1] - nx ## number of user z variables if nz < 0: stderr.write('opf_setup: user supplied A matrix must have at least %d columns.\n' % nx) else: nz = 0 ## number of user z variables if nw: ## still need to check number of columns of N if ppc['N'].shape[1] != nx: stderr.write('opf_setup: user supplied N matrix must have %d columns.\n' % nx) ## construct OPF model object om = opf_model(ppc) if len(pwl1) > 0: om.userdata('pwl1', pwl1) if dc: om.userdata('Bf', Bf) om.userdata('Pfinj', Pfinj) om.userdata('iang', iang) om.add_vars('Va', nb, Va, Val, Vau) om.add_vars('Pg', ng, Pg, Pmin, Pmax) om.add_constraints('Pmis', Amis, bmis, bmis, ['Va', 'Pg']) ## nb om.add_constraints('Pf', Bf[il, :], lpf, upf, ['Va']) ## nl om.add_constraints('Pt', -Bf[il, :], lpf, upt, ['Va']) ## nl om.add_constraints('ang', Aang, lang, uang, ['Va']) ## nang else: om.userdata('Apqdata', Apqdata) om.userdata('iang', iang) om.add_vars('Va', nb, Va, Val, Vau) om.add_vars('Vm', nb, Vm, bus[:, VMIN], bus[:, VMAX]) om.add_vars('Pg', ng, Pg, Pmin, Pmax) om.add_vars('Qg', ng, Qg, Qmin, Qmax) om.add_constraints('Pmis', nb, 'nonlinear') om.add_constraints('Qmis', nb, 'nonlinear') om.add_constraints('Sf', nl, 'nonlinear') om.add_constraints('St', nl, 'nonlinear') om.add_constraints('PQh', Apqh, array([]), ubpqh, ['Pg', 'Qg']) ## npqh om.add_constraints('PQl', Apql, array([]), ubpql, ['Pg', 'Qg']) ## npql om.add_constraints('vl', Avl, lvl, uvl, ['Pg', 'Qg']) ## nvl om.add_constraints('ang', Aang, lang, uang, ['Va']) ## nang ## y vars, constraints for piece-wise linear gen costs if ny > 0: om.add_vars('y', ny) om.add_constraints('ycon', Ay, array([]), by, ycon_vars) ## ncony ## add user vars, constraints and costs (as specified via A, ..., N, ...) if nz > 0: # pragma: no cover om.add_vars('z', nz, z0, zl, zu) user_vars.append('z') if nusr: # pragma: no cover om.add_constraints('usr', ppc['A'], lbu, ubu, user_vars) ## nusr if nw: # pragma: no cover user_cost = {} user_cost['N'] = ppc['N'] user_cost['Cw'] = Cw if len(fparm) > 0: user_cost['dd'] = fparm[:, 0] user_cost['rh'] = fparm[:, 1] user_cost['kk'] = fparm[:, 2] user_cost['mm'] = fparm[:, 3] # if len(H) > 0: user_cost['H'] = H om.add_costs('usr', user_cost, user_vars) ## execute userfcn callbacks for 'formulation' stage run_userfcn(userfcn, 'formulation', om) return om
def savecase(fname, ppc, comment=None, version='2'): """Saves a PYPOWER case file, given a filename and the data. Writes a PYPOWER case file, given a filename and data dict. The C{fname} parameter is the name of the file to be created or overwritten. Returns the filename, with extension added if necessary. The optional C{comment} argument is either string (single line comment) or a list of strings which are inserted as comments. When using a PYPOWER case dict, if the optional C{version} argument is '1' it will modify the data matrices to version 1 format before saving. @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Ray Zimmerman (PSERC Cornell) """ ppc_ver = ppc["version"] = version baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] areas = ppc["areas"] if "areas" in ppc else None gencost = ppc["gencost"] if "gencost" in ppc else None ## modifications for version 1 format if ppc_ver == "1": raise NotImplementedError # ## remove extra columns of gen # if gen.shape[1] >= MU_QMIN: # gen = c_[gen[:, :PMIN], gen[:, MU_PMAX:MU_QMIN]] # else: # gen = gen[:, :PMIN] # ## use the version 1 values for column names # shift = MU_PMAX - PMIN - 1 # tmp = array([MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN]) - shift # MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN = tmp # # ## remove extra columns of branch # if branch.shape[1] >= MU_ST: # branch = c_[branch[:, :BR_STATUS], branch[:, PF:MU_ST]] # elif branch.shape[1] >= QT: # branch = c_[branch[:, :BR_STATUS], branch[:, PF:QT]] # else: # branch = branch[:, :BR_STATUS] # ## use the version 1 values for column names # shift = PF - BR_STATUS - 1 # tmp = array([PF, QF, PT, QT, MU_SF, MU_ST]) - shift # PF, QF, PT, QT, MU_SF, MU_ST = tmp ## verify valid filename l = len(fname) rootname = "" if l > 2: if fname[-3:] == ".py": rootname = fname[:-3] extension = ".py" elif l > 4: if fname[-4:] == ".mat": rootname = fname[:-4] extension = ".mat" if not rootname: rootname = fname extension = ".py" fname = rootname + extension indent = ' ' # four spaces indent2 = indent + indent ## open and write the file if extension == ".mat": ## MAT-file savemat(fname, ppc) else: ## Python file try: fd = open(fname, "wb") except Exception as detail: stderr.write("savecase: %s.\n" % detail) return fname ## function header, etc. if ppc_ver == "1": raise NotImplementedError # if (areas != None) and (gencost != None) and (len(gencost) > 0): # fd.write('function [baseMVA, bus, gen, branch, areas, gencost] = %s\n' % rootname) # else: # fd.write('function [baseMVA, bus, gen, branch] = %s\n' % rootname) # prefix = '' else: fd.write('def %s():\n' % basename(rootname)) prefix = 'ppc' if comment: if isinstance(comment, basestring): fd.write('#%s\n' % comment) elif isinstance(comment, list): for c in comment: fd.write('#%s\n' % c) fd.write('\n%s## PYPOWER Case Format : Version %s\n' % (indent, ppc_ver)) if ppc_ver != "1": fd.write("%sppc = {'version': '%s'}\n" % (indent, ppc_ver)) fd.write('\n%s##----- Power Flow Data -----##\n' % indent) fd.write('%s## system MVA base\n' % indent) fd.write("%s%s['baseMVA'] = %.9g\n" % (indent, prefix, baseMVA)) ## bus data ncols = bus.shape[1] fd.write('\n%s## bus data\n' % indent) fd.write('%s# bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin' % indent) if ncols >= MU_VMIN + 1: ## opf SOLVED, save with lambda's & mu's fd.write('lam_P lam_Q mu_Vmax mu_Vmin') fd.write("\n%s%s['bus'] = array([\n" % (indent, prefix)) if ncols < MU_VMIN + 1: ## opf NOT SOLVED, save without lambda's & mu's for i in range(bus.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(bus[i, :VMIN + 1]))) else: ## opf SOLVED, save with lambda's & mu's for i in range(bus.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(bus[i, :MU_VMIN + 1]))) fd.write('%s])\n' % indent) ## generator data ncols = gen.shape[1] fd.write('\n%s## generator data\n' % indent) fd.write('%s# bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin' % indent) if ppc_ver != "1": fd.write(' Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf') if ncols >= MU_QMIN + 1: # opf SOLVED, save with mu's fd.write(' mu_Pmax mu_Pmin mu_Qmax mu_Qmin') fd.write("\n%s%s['gen'] = array([\n" % (indent, prefix)) if ncols < MU_QMIN + 1: ## opf NOT SOLVED, save without mu's if ppc_ver == "1": for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(gen[i, :PMIN + 1]))) else: for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g],\n' % ((indent2,) + tuple(gen[i, :APF + 1]))) else: if ppc_ver == "1": for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(gen[i, :MU_QMIN + 1]))) else: for i in range(gen.shape[0]): fd.write('%s[%d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(gen[i, :MU_QMIN + 1]))) fd.write('%s])\n' % indent) ## branch data ncols = branch.shape[1] fd.write('\n%s## branch data\n' % indent) fd.write('%s# fbus tbus r x b rateA rateB rateC ratio angle status' % indent) if ppc_ver != "1": fd.write(' angmin angmax') if ncols >= QT + 1: ## power flow SOLVED, save with line flows fd.write(' Pf Qf Pt Qt') if ncols >= MU_ST + 1: ## opf SOLVED, save with mu's fd.write(' mu_Sf mu_St') if ppc_ver != "1": fd.write(' mu_angmin mu_angmax') fd.write('\n%s%s[\'branch\'] = array([\n' % (indent, prefix)) if ncols < QT + 1: ## power flow NOT SOLVED, save without line flows or mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d],\n' % ((indent2,) + tuple(branch[i, :BR_STATUS + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g],\n' % ((indent2,) + tuple(branch[i, :ANGMAX + 1]))) elif ncols < MU_ST + 1: ## power flow SOLVED, save with line flows but without mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :QT + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :QT + 1]))) else: ## opf SOLVED, save with lineflows & mu's if ppc_ver == "1": for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :MU_ST + 1]))) else: for i in range(branch.shape[0]): fd.write('%s[%d, %d, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %.9g, %d, %.9g, %.9g, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f],\n' % ((indent2,) + tuple(branch[i, :MU_ANGMAX + 1]))) fd.write('%s])\n' % indent) ## OPF data if (areas != None) and (len(areas) > 0) or (gencost != None) and (len(gencost) > 0): fd.write('\n%s##----- OPF Data -----##' % indent) if (areas != None) and (len(areas) > 0): ## area data fd.write('\n%s## area data\n' % indent) fd.write('%s# area refbus\n' % indent) fd.write("%s%s['areas'] = array([\n" % (indent, prefix)) if len(areas) > 0: for i in range(areas.shape[0]): fd.write('%s[%d, %d],\n' % ((indent2,) + tuple(areas[i, :PRICE_REF_BUS + 1]))) fd.write('%s])\n' % indent) if gencost != None and len(gencost) > 0: ## generator cost data fd.write('\n%s## generator cost data\n' % indent) fd.write('%s# 1 startup shutdown n x1 y1 ... xn yn\n' % indent) fd.write('%s# 2 startup shutdown n c(n-1) ... c0\n' % indent) fd.write('%s%s[\'gencost\'] = array([\n' % (indent, prefix)) if len(gencost > 0): if any(gencost[:, MODEL] == PW_LINEAR): n1 = 2 * max(gencost[gencost[:, MODEL] == PW_LINEAR, NCOST]) else: n1 = 0 if any(gencost[:, MODEL] == POLYNOMIAL): n2 = max(gencost[gencost[:, MODEL] == POLYNOMIAL, NCOST]) else: n2 = 0 n = int( max([n1, n2]) ) if gencost.shape[1] < n + 4: stderr.write('savecase: gencost data claims it has more columns than it does\n') template = '%s[%d, %.9g, %.9g, %d' for i in range(n): template = template + ', %.9g' template = template + '],\n' for i in range(gencost.shape[0]): fd.write(template % ((indent2,) + tuple(gencost[i]))) fd.write('%s])\n' % indent) ## generalized OPF user data if ("A" in ppc) and (len(ppc["A"]) > 0) or ("N" in ppc) and (len(ppc["N"]) > 0): fd.write('\n%s##----- Generalized OPF User Data -----##' % indent) ## user constraints if ("A" in ppc) and (len(ppc["A"]) > 0): ## A fd.write('\n%s## user constraints\n' % indent) print_sparse(fd, prefix + "['A']", ppc["A"]) if ("l" in ppc) and (len(ppc["l"]) > 0) and ("u" in ppc) and (len(ppc["u"]) > 0): fd.write('%slu = array([\n' % indent) for i in range(len(l)): fd.write('%s[%.9g, %.9g],\n' % (indent2, ppc["l"][i], ppc["u"][i])) fd.write('%s])\n' % indent) fd.write("%s%s['l'] = lu[:, 0]\n" % (indent, prefix)) fd.write("%s%s['u'] = lu[:, 1]\n\n" % (indent, prefix)) elif ("l" in ppc) and (len(ppc["l"]) > 0): fd.write("%s%s['l'] = array([\n" % (indent, prefix)) for i in range(len(l)): fd.write('%s[%.9g],\n' % (indent2, ppc["l"][i])) fd.write('%s])\n\n' % indent) elif ("u" in ppc) and (len(ppc["u"]) > 0): fd.write("%s%s['u'] = array([\n" % (indent, prefix)) for i in range(len(l)): fd.write('%s[%.9g],\n' % (indent2, ppc["u"][i])) fd.write('%s])\n\n' % indent) ## user costs if ("N" in ppc) and (len(ppc["N"]) > 0): fd.write('\n%s## user costs\n' % indent) print_sparse(fd, prefix + "['N']", ppc["N"]) if ("H" in ppc) and (len(ppc["H"]) > 0): print_sparse(fd, prefix + "['H']", ppc["H"]) if ("fparm" in ppc) and (len(ppc["fparm"]) > 0): fd.write("%sCw_fparm = array([\n" % indent) for i in range(ppc["Cw"]): fd.write('%s[%.9g, %d, %.9g, %.9g, %.9g],\n' % ((indent2,) + tuple(ppc["Cw"][i]) + tuple(ppc["fparm"][i, :]))) fd.write('%s])\n' % indent) fd.write('%s%s[\'Cw\'] = Cw_fparm[:, 0]\n' % (indent, prefix)) fd.write("%s%s['fparm'] = Cw_fparm[:, 1:5]\n" % (indent, prefix)) else: fd.write("%s%s['Cw'] = array([\n" % (indent, prefix)) for i in range(len(ppc["Cw"])): fd.write('%s[%.9g],\n' % (indent2, ppc["Cw"][i])) fd.write('%s])\n' % indent) ## user vars if ('z0' in ppc) or ('zl' in ppc) or ('zu' in ppc): fd.write('\n%s## user vars\n' % indent) if ('z0' in ppc) and (len(ppc['z0']) > 0): fd.write('%s%s["z0"] = array([\n' % (indent, prefix)) for i in range(len(ppc['z0'])): fd.write('%s[%.9g],\n' % (indent2, ppc["z0"])) fd.write('%s])\n' % indent) if ('zl' in ppc) and (len(ppc['zl']) > 0): fd.write('%s%s["zl"] = array([\n' % (indent2, prefix)) for i in range(len(ppc['zl'])): fd.write('%s[%.9g],\n' % (indent2, ppc["zl"])) fd.write('%s])\n' % indent) if ('zu' in ppc) and (len(ppc['zu']) > 0): fd.write('%s%s["zu"] = array([\n' % (indent, prefix)) for i in range(len(ppc['zu'])): fd.write('%s[%.9g],\n' % (indent2, ppc["zu"])) fd.write('%s])\n' % indent) ## execute userfcn callbacks for 'savecase' stage if 'userfcn' in ppc: run_userfcn(ppc["userfcn"], 'savecase', ppc, fd, prefix) fd.write('\n%sreturn ppc\n' % indent) ## close file fd.close() return fname
def ext2int(ppc, val_or_field=None, ordering=None, dim=0): """Converts external to internal indexing. This function has two forms, the old form that operates on and returns individual matrices and the new form that operates on and returns an entire PYPOWER case dict. 1. C{ppc = ext2int(ppc)} If the input is a single PYPOWER case dict, then all isolated buses, off-line generators and branches are removed along with any generators, branches or areas connected to isolated buses. Then the buses are renumbered consecutively, beginning at 0, and the generators are sorted by increasing bus number. Any 'ext2int' callback routines registered in the case are also invoked automatically. All of the related indexing information and the original data matrices are stored under the 'order' key of the dict to be used by C{int2ext} to perform the reverse conversions. If the case is already using internal numbering it is returned unchanged. Example:: ppc = ext2int(ppc) @see: L{int2ext}, L{e2i_field}, L{e2i_data} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ppc = deepcopy(ppc) if val_or_field is None: # nargin == 1 first = 'order' not in ppc if first or ppc["order"]["state"] == 'e': ## initialize order if first: o = { 'ext': { 'bus': None, 'branch': None, 'gen': None }, 'bus': { 'e2i': None, 'i2e': None, 'status': {} }, 'gen': { 'e2i': None, 'i2e': None, 'status': {} }, 'branch': { 'status': {} } } else: o = ppc["order"] ## sizes nb = ppc["bus"].shape[0] ng = ppc["gen"].shape[0] ng0 = ng if 'A' in ppc: dc = True if ppc["A"].shape[1] < (2 * nb + 2 * ng) else False elif 'N' in ppc: dc = True if ppc["N"].shape[1] < (2 * nb + 2 * ng) else False else: dc = False ## save data matrices with external ordering if 'ext' not in o: o['ext'] = {} o["ext"]["bus"] = ppc["bus"].copy() o["ext"]["branch"] = ppc["branch"].copy() o["ext"]["gen"] = ppc["gen"].copy() if 'areas' in ppc: if len(ppc["areas"]) == 0: ## if areas field is empty del ppc['areas'] ## delete it (so it's ignored) else: ## otherwise o["ext"]["areas"] = ppc["areas"].copy() ## save it ## check that all buses have a valid BUS_TYPE bt = ppc["bus"][:, BUS_TYPE] err = find(~((bt == PQ) | (bt == PV) | (bt == REF) | (bt == NONE))) if len(err) > 0: sys.stderr.write('ext2int: bus %d has an invalid BUS_TYPE\n' % err) ## determine which buses, branches, gens are connected and ## in-service n2i = sparse((range(nb), (ppc["bus"][:, BUS_I], zeros(nb))), shape=(max(ppc["bus"][:, BUS_I]) + 1, 1)) n2i = array( n2i.todense().flatten() )[0, :] # as 1D array bs = (bt != NONE) ## bus status o["bus"]["status"]["on"] = find( bs ) ## connected o["bus"]["status"]["off"] = find( ~bs ) ## isolated gs = ( (ppc["gen"][:, GEN_STATUS] > 0) & ## gen status bs[ n2i[ppc["gen"][:, GEN_BUS].astype(int)] ] ) o["gen"]["status"]["on"] = find( gs ) ## on and connected o["gen"]["status"]["off"] = find( ~gs ) ## off or isolated brs = ( ppc["branch"][:, BR_STATUS].astype(int) & ## branch status bs[n2i[ppc["branch"][:, F_BUS].astype(int)]] & bs[n2i[ppc["branch"][:, T_BUS].astype(int)]] ).astype(bool) o["branch"]["status"]["on"] = find( brs ) ## on and conn o["branch"]["status"]["off"] = find( ~brs ) if 'areas' in ppc: ar = bs[ n2i[ppc["areas"][:, PRICE_REF_BUS].astype(int)] ] o["areas"] = {"status": {}} o["areas"]["status"]["on"] = find( ar ) o["areas"]["status"]["off"] = find( ~ar ) ## delete stuff that is "out" if len(o["bus"]["status"]["off"]) > 0: # ppc["bus"][o["bus"]["status"]["off"], :] = array([]) ppc["bus"] = ppc["bus"][o["bus"]["status"]["on"], :] if len(o["branch"]["status"]["off"]) > 0: # ppc["branch"][o["branch"]["status"]["off"], :] = array([]) ppc["branch"] = ppc["branch"][o["branch"]["status"]["on"], :] if len(o["gen"]["status"]["off"]) > 0: # ppc["gen"][o["gen"]["status"]["off"], :] = array([]) ppc["gen"] = ppc["gen"][o["gen"]["status"]["on"], :] if 'areas' in ppc and (len(o["areas"]["status"]["off"]) > 0): # ppc["areas"][o["areas"]["status"]["off"], :] = array([]) ppc["areas"] = ppc["areas"][o["areas"]["status"]["on"], :] ## update size nb = ppc["bus"].shape[0] ## apply consecutive bus numbering o["bus"]["i2e"] = ppc["bus"][:, BUS_I].copy() o["bus"]["e2i"] = zeros(max(o["bus"]["i2e"]) + 1) o["bus"]["e2i"][o["bus"]["i2e"].astype(int)] = arange(nb) ppc["bus"][:, BUS_I] = \ o["bus"]["e2i"][ ppc["bus"][:, BUS_I].astype(int) ].copy() ppc["gen"][:, GEN_BUS] = \ o["bus"]["e2i"][ ppc["gen"][:, GEN_BUS].astype(int) ].copy() ppc["branch"][:, F_BUS] = \ o["bus"]["e2i"][ ppc["branch"][:, F_BUS].astype(int) ].copy() ppc["branch"][:, T_BUS] = \ o["bus"]["e2i"][ ppc["branch"][:, T_BUS].astype(int) ].copy() if 'areas' in ppc: ppc["areas"][:, PRICE_REF_BUS] = \ o["bus"]["e2i"][ ppc["areas"][:, PRICE_REF_BUS].astype(int) ].copy() ## reorder gens in order of increasing bus number o["gen"]["e2i"] = argsort(ppc["gen"][:, GEN_BUS]) o["gen"]["i2e"] = argsort(o["gen"]["e2i"]) ppc["gen"] = ppc["gen"][o["gen"]["e2i"].astype(int), :] if 'int' in o: del o['int'] o["state"] = 'i' ppc["order"] = o ## update gencost, A and N if 'gencost' in ppc: ordering = ['gen'] ## Pg cost only if ppc["gencost"].shape[0] == (2 * ng0): ordering.append('gen') ## include Qg cost ppc = e2i_field(ppc, 'gencost', ordering) if 'A' in ppc or 'N' in ppc: if dc: ordering = ['bus', 'gen'] else: ordering = ['bus', 'bus', 'gen', 'gen'] if 'A' in ppc: ppc = e2i_field(ppc, 'A', ordering, 1) if 'N' in ppc: ppc = e2i_field(ppc, 'N', ordering, 1) ## execute userfcn callbacks for 'ext2int' stage if 'userfcn' in ppc: ppc = run_userfcn(ppc['userfcn'], 'ext2int', ppc) else: ## convert extra data if isinstance(val_or_field, str) or isinstance(val_or_field, list): ## field warn('Calls of the form ppc = ext2int(ppc, ' '\'field_name\', ...) have been deprecated. Please ' 'replace ext2int with e2i_field.', DeprecationWarning) gen, branch = val_or_field, ordering ppc = e2i_field(ppc, gen, branch, dim) else: ## value warn('Calls of the form val = ext2int(ppc, val, ...) have been ' 'deprecated. Please replace ext2int with e2i_data.', DeprecationWarning) gen, branch = val_or_field, ordering ppc = e2i_data(ppc, gen, branch, dim) return ppc
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].real.astype(int)], BUS_AREA] != bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA]) ## area inter-ties tap = ones(nl) ## default tap ratio = 1 for lines xfmr = find(branch[:, TAP]).real ## indices of transformers tap[xfmr] = branch[xfmr, TAP].real ## 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].real.astype(int) ]] / tap - V[e2i[ branch[:, T_BUS].real.astype(int) ]])**2 / \ (branch[:, BR_R] - 1j * branch[:, BR_X]) fchg = abs(V[e2i[branch[:, F_BUS].real.astype(int)]] / tap)**2 * branch[:, BR_B].real * baseMVA / 2 tchg = abs(V[e2i[branch[:, T_BUS].real.astype( int)]])**2 * branch[:, BR_B].real * 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].real, branch[maxi, T_BUS].real)) 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].real, branch[maxi, T_BUS].real)) 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].real.astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA] == a)) in_tie = find( (bus[e2i[branch[:, F_BUS].real.astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA] != a)) out_tie = find( (bus[e2i[branch[:, F_BUS].real.astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA] == a)) if not any(xfmr + 1): nxfmr = 0 else: nxfmr = len( find((bus[e2i[branch[xfmr, F_BUS].real.astype(int)], BUS_AREA] == a) & (bus[e2i[branch[xfmr, T_BUS].real.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 %-.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].real.astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) in_tie = find( (bus[e2i[branch[:, F_BUS].real.astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].real.astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) out_tie = find( (bus[e2i[branch[:, F_BUS].real.astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].real.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].real, branch[i, T_BUS].real, branch[i, PF].real, branch[i, QF].real, branch[i, PT].real, branch[i, QT].real, 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 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 _ppc2ppci(ppc, ppci, net): # BUS Sorting and lookups # get bus_lookup bus_lookup = net["_pd2ppc_lookups"]["bus"] # get OOS busses and place them at the end of the bus array (there are no OOS busses in the ppci) oos_busses = ppc['bus'][:, BUS_TYPE] == NONE ppci['bus'] = ppc['bus'][~oos_busses] # in ppc the OOS busses are included and at the end of the array ppc['bus'] = np.r_[ppc['bus'][~oos_busses], ppc['bus'][oos_busses]] # generate bus_lookup_ppc_ppci (ppc -> ppci lookup) ppc_former_order = (ppc['bus'][:, BUS_I]).astype(int) aranged_buses = np.arange(len(ppc["bus"])) # lookup ppc former order -> consecutive order e2i = np.zeros(len(ppc["bus"]), dtype=int) e2i[ppc_former_order] = aranged_buses # save consecutive indices in ppc and ppci ppc['bus'][:, BUS_I] = aranged_buses ppci['bus'][:, BUS_I] = ppc['bus'][:len(ppci['bus']), BUS_I] # update lookups (pandapower -> ppci internal) _update_lookup_entries(net, bus_lookup, e2i, "bus") # ToDo: The reverse lookup (ppc2pd) also needs to be updated when connectivity_check == True! if 'areas' in ppc: if len(ppc["areas"]) == 0: # if areas field is empty del ppc['areas'] # delete it (so it's ignored) # bus types bt = ppc["bus"][:, BUS_TYPE] # update branch, gen and areas bus numbering ppc['gen'][:, GEN_BUS] = e2i[np.real(ppc["gen"][:, GEN_BUS]).astype(int)].copy() ppc["branch"][:, F_BUS] = e2i[np.real(ppc["branch"][:, F_BUS]).astype(int)].copy() ppc["branch"][:, T_BUS] = e2i[np.real(ppc["branch"][:, T_BUS]).astype(int)].copy() # Note: The "update branch, gen and areas bus numbering" does the same as this: # ppc['gen'][:, GEN_BUS] = get_indices(ppc['gen'][:, GEN_BUS], bus_lookup_ppc_ppci) # ppc["branch"][:, F_BUS] = get_indices(ppc["branch"][:, F_BUS], bus_lookup_ppc_ppci) # ppc["branch"][:, T_BUS] = get_indices( ppc["branch"][:, T_BUS], bus_lookup_ppc_ppci) # but faster... if 'areas' in ppc: ppc["areas"][:, PRICE_REF_BUS] = \ e2i[np.real(ppc["areas"][:, PRICE_REF_BUS]).astype(int)].copy() # reorder gens (and gencosts) in order of increasing bus number sort_gens = ppc['gen'][:, GEN_BUS].argsort() new_gen_positions = np.arange(len(sort_gens)) new_gen_positions[sort_gens] = np.arange(len(sort_gens)) ppc['gen'] = ppc['gen'][sort_gens,] # update gen lookups _is_elements = net["_is_elements"] eg_end = np.sum(_is_elements['ext_grid']) gen_end = eg_end + np.sum(_is_elements['gen']) sgen_end = len(_is_elements["sgen_controllable"]) + gen_end if "sgen_controllable" in _is_elements else gen_end load_end = len(_is_elements["load_controllable"]) + sgen_end if "load_controllable" in _is_elements else sgen_end if eg_end > 0: _build_gen_lookups(net, "ext_grid", 0, eg_end, new_gen_positions) if gen_end > eg_end: _build_gen_lookups(net, "gen", eg_end, gen_end, new_gen_positions) if sgen_end > gen_end: _build_gen_lookups(net, "sgen_controllable", gen_end, sgen_end, new_gen_positions) if load_end > sgen_end: _build_gen_lookups(net, "load_controllable", sgen_end, load_end, new_gen_positions) # determine which buses, branches, gens are connected and # in-service n2i = ppc["bus"][:, BUS_I].astype(int) bs = (bt != NONE) # bus status gs = ((ppc["gen"][:, GEN_STATUS] > 0) & # gen status bs[n2i[np.real(ppc["gen"][:, GEN_BUS]).astype(int)]]) ppci["internal"]["gen_is"] = gs brs = (np.real(ppc["branch"][:, BR_STATUS]).astype(int) & # branch status bs[n2i[np.real(ppc["branch"][:, F_BUS]).astype(int)]] & bs[n2i[np.real(ppc["branch"][:, T_BUS]).astype(int)]]).astype(bool) ppci["internal"]["branch_is"] = brs if 'areas' in ppc: ar = bs[n2i[ppc["areas"][:, PRICE_REF_BUS].astype(int)]] # delete out of service areas ppci["areas"] = ppc["areas"][ar] # select in service elements from ppc and put them in ppci ppci["branch"] = ppc["branch"][brs] ppci["gen"] = ppc["gen"][gs] if 'dcline' in ppc: ppci['dcline'] = ppc['dcline'] # execute userfcn callbacks for 'ext2int' stage if 'userfcn' in ppci: ppci = run_userfcn(ppci['userfcn'], 'ext2int', ppci) return ppci
def opf_setup(ppc, ppopt): """Constructs an OPF model object from a PYPOWER case dict. Assumes that ppc is a PYPOWER case dict with internal indexing, all equipment in-service, etc. @see: L{opf}, L{ext2int}, L{opf_execute} @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Richard Lincoln """ ## options dc = ppopt['PF_DC'] ## 1 = DC OPF, 0 = AC OPF alg = ppopt['OPF_ALG'] verbose = ppopt['VERBOSE'] ## data dimensions nb = ppc['bus'].shape[0] ## number of buses nl = ppc['branch'].shape[0] ## number of branches ng = ppc['gen'].shape[0] ## number of dispatchable injections if 'A' in ppc: nusr = ppc['A'].shape[0] ## number of linear user constraints else: nusr = 0 if 'N' in ppc: nw = ppc['N'].shape[0] ## number of general cost vars, w else: nw = 0 if dc: ## ignore reactive costs for DC ppc['gencost'], _ = pqcost(ppc['gencost'], ng) ## reduce A and/or N from AC dimensions to DC dimensions, if needed if nusr or nw: acc = r_[nb + arange(nb), 2 * nb + ng + arange(ng)] ## Vm and Qg columns if nusr and (ppc['A'].shape[1] >= 2*nb + 2*ng): ## make sure there aren't any constraints on Vm or Qg if ppc['A'][:, acc].nnz > 0: stderr.write('opf_setup: attempting to solve DC OPF with user constraints on Vm or Qg\n') # FIXME: delete sparse matrix columns bcc = delete(arange(ppc['A'].shape[1]), acc) ppc['A'] = ppc['A'].tolil()[:, bcc].tocsr() ## delete Vm and Qg columns if nw and (ppc['N'].shape[1] >= 2*nb + 2*ng): ## make sure there aren't any costs on Vm or Qg if ppc['N'][:, acc].nnz > 0: ii, _ = nonzero(ppc['N'][:, acc]) _, ii = unique(ii, return_index=True) ## indices of w with potential non-zero cost terms from Vm or Qg if any(ppc['Cw'][ii]) | ( ('H' in ppc) & (len(ppc['H']) > 0) & any(any(ppc['H'][:, ii])) ): stderr.write('opf_setup: attempting to solve DC OPF with user costs on Vm or Qg\n') # FIXME: delete sparse matrix columns bcc = delete(arange(ppc['N'].shape[1]), acc) ppc['N'] = ppc['N'].tolil()[:, bcc].tocsr() ## delete Vm and Qg columns ## convert single-block piecewise-linear costs into linear polynomial cost pwl1 = find((ppc['gencost'][:, MODEL] == PW_LINEAR) & (ppc['gencost'][:, NCOST] == 2)) # p1 = array([]) if len(pwl1) > 0: x0 = ppc['gencost'][pwl1, COST] y0 = ppc['gencost'][pwl1, COST + 1] x1 = ppc['gencost'][pwl1, COST + 2] y1 = ppc['gencost'][pwl1, COST + 3] m = (y1 - y0) / (x1 - x0) b = y0 - m * x0 ppc['gencost'][pwl1, MODEL] = POLYNOMIAL ppc['gencost'][pwl1, NCOST] = 2 ppc['gencost'][pwl1, COST:COST + 2] = r_[m, b] ## create (read-only) copies of individual fields for convenience baseMVA, bus, gen, branch, gencost, _, lbu, ubu, ppopt, \ _, fparm, H, Cw, z0, zl, zu, userfcn, _ = opf_args(ppc, ppopt) ## warn if there is more than one reference bus refs = find(bus[:, BUS_TYPE] == REF) if len(refs) > 1 and verbose > 0: errstr = '\nopf_setup: Warning: Multiple reference buses.\n' + \ ' For a system with islands, a reference bus in each island\n' + \ ' may help convergence, but in a fully connected system such\n' + \ ' a situation is probably not reasonable.\n\n' stdout.write(errstr) ## set up initial variables and bounds gbus = gen[:, GEN_BUS].astype(int) Va = bus[:, VA] * (pi / 180.0) Vm = bus[:, VM].copy() Vm[gbus] = gen[:, VG] ## buses with gens, init Vm from gen data Pg = gen[:, PG] / baseMVA Qg = gen[:, QG] / baseMVA Pmin = gen[:, PMIN] / baseMVA Pmax = gen[:, PMAX] / baseMVA Qmin = gen[:, QMIN] / baseMVA Qmax = gen[:, QMAX] / baseMVA if dc: ## DC model ## more problem dimensions nv = 0 ## number of voltage magnitude vars nq = 0 ## number of Qg vars q1 = array([]) ## index of 1st Qg column in Ay ## power mismatch constraints B, Bf, Pbusinj, Pfinj = makeBdc(baseMVA, bus, branch) neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], arange(ng))), (nb, ng)) ## Pbus w.r.t. Pg Amis = hstack([B, neg_Cg], 'csr') bmis = -(bus[:, PD] + bus[:, GS]) / baseMVA - Pbusinj ## branch flow constraints il = find((branch[:, RATE_A] != 0) & (branch[:, RATE_A] < 1e10)) nl2 = len(il) ## number of constrained lines lpf = -Inf * ones(nl2) upf = branch[il, RATE_A] / baseMVA - Pfinj[il] upt = branch[il, RATE_A] / baseMVA + Pfinj[il] user_vars = ['Va', 'Pg'] ycon_vars = ['Pg', 'y'] else: ## AC model ## more problem dimensions nv = nb ## number of voltage magnitude vars nq = ng ## number of Qg vars q1 = ng ## index of 1st Qg column in Ay ## dispatchable load, constant power factor constraints Avl, lvl, uvl, _ = makeAvl(baseMVA, gen) ## generator PQ capability curve constraints Apqh, ubpqh, Apql, ubpql, Apqdata = makeApq(baseMVA, gen) user_vars = ['Va', 'Vm', 'Pg', 'Qg'] ycon_vars = ['Pg', 'Qg', 'y'] ## voltage angle reference constraints Vau = Inf * ones(nb) Val = -Vau Vau[refs] = Va[refs] Val[refs] = Va[refs] ## branch voltage angle difference limits Aang, lang, uang, iang = makeAang(baseMVA, branch, nb, ppopt) ## basin constraints for piece-wise linear gen cost variables if alg == 545 or alg == 550: ## SC-PDIPM or TRALM, no CCV cost vars ny = 0 Ay = None by = array([]) else: ipwl = find(gencost[:, MODEL] == PW_LINEAR) ## piece-wise linear costs ny = ipwl.shape[0] ## number of piece-wise linear cost vars Ay, by = makeAy(baseMVA, ng, gencost, 1, q1, 1+ng+nq) if any((gencost[:, MODEL] != POLYNOMIAL) & (gencost[:, MODEL] != PW_LINEAR)): stderr.write('opf_setup: some generator cost rows have invalid MODEL value\n') ## more problem dimensions nx = nb+nv + ng+nq; ## number of standard OPF control variables if nusr: nz = ppc['A'].shape[1] - nx ## number of user z variables if nz < 0: stderr.write('opf_setup: user supplied A matrix must have at least %d columns.\n' % nx) else: nz = 0 ## number of user z variables if nw: ## still need to check number of columns of N if ppc['N'].shape[1] != nx: stderr.write('opf_setup: user supplied N matrix must have %d columns.\n' % nx) ## construct OPF model object om = opf_model(ppc) if len(pwl1) > 0: om.userdata('pwl1', pwl1) if dc: om.userdata('Bf', Bf) om.userdata('Pfinj', Pfinj) om.userdata('iang', iang) om.add_vars('Va', nb, Va, Val, Vau) om.add_vars('Pg', ng, Pg, Pmin, Pmax) om.add_constraints('Pmis', Amis, bmis, bmis, ['Va', 'Pg']) ## nb om.add_constraints('Pf', Bf[il, :], lpf, upf, ['Va']) ## nl om.add_constraints('Pt', -Bf[il, :], lpf, upt, ['Va']) ## nl om.add_constraints('ang', Aang, lang, uang, ['Va']) ## nang else: om.userdata('Apqdata', Apqdata) om.userdata('iang', iang) om.add_vars('Va', nb, Va, Val, Vau) om.add_vars('Vm', nb, Vm, bus[:, VMIN], bus[:, VMAX]) om.add_vars('Pg', ng, Pg, Pmin, Pmax) om.add_vars('Qg', ng, Qg, Qmin, Qmax) om.add_constraints('Pmis', nb, 'nonlinear') om.add_constraints('Qmis', nb, 'nonlinear') om.add_constraints('Sf', nl, 'nonlinear') om.add_constraints('St', nl, 'nonlinear') om.add_constraints('PQh', Apqh, array([]), ubpqh, ['Pg', 'Qg']) ## npqh om.add_constraints('PQl', Apql, array([]), ubpql, ['Pg', 'Qg']) ## npql om.add_constraints('vl', Avl, lvl, uvl, ['Pg', 'Qg']) ## nvl om.add_constraints('ang', Aang, lang, uang, ['Va']) ## nang ## y vars, constraints for piece-wise linear gen costs if ny > 0: om.add_vars('y', ny) om.add_constraints('ycon', Ay, array([]), by, ycon_vars) ## ncony ## add user vars, constraints and costs (as specified via A, ..., N, ...) if nz > 0: om.add_vars('z', nz, z0, zl, zu) user_vars.append('z') if nusr: om.add_constraints('usr', ppc['A'], lbu, ubu, user_vars) ## nusr if nw: user_cost = {} user_cost['N'] = ppc['N'] user_cost['Cw'] = Cw if len(fparm) > 0: user_cost['dd'] = fparm[:, 0] user_cost['rh'] = fparm[:, 1] user_cost['kk'] = fparm[:, 2] user_cost['mm'] = fparm[:, 3] # if len(H) > 0: user_cost['H'] = H om.add_costs('usr', user_cost, user_vars) ## execute userfcn callbacks for 'formulation' stage run_userfcn(userfcn, 'formulation', om) return om
def int2ext(ppc, val_or_field=None, oldval=None, ordering=None, dim=0): """Converts internal to external bus numbering. C{ppc = int2ext(ppc)} If the input is a single PYPOWER case dict, then it restores all buses, generators and branches that were removed because of being isolated or off-line, and reverts to the original generator ordering and original bus numbering. This requires that the 'order' key created by L{ext2int} be in place. Example:: ppc = int2ext(ppc) @see: L{ext2int}, L{i2e_field}, L{i2e_data} @author: Ray Zimmerman (PSERC Cornell) """ ppc = deepcopy(ppc) if val_or_field is None: # nargin == 1 if 'order' not in ppc: sys.stderr.write('int2ext: ppc does not have the "order" field ' 'required for conversion back to external numbering.\n') o = ppc["order"] if o["state"] == 'i': ## execute userfcn callbacks for 'int2ext' stage if 'userfcn' in ppc: ppc = run_userfcn(ppc["userfcn"], 'int2ext', ppc) ## save data matrices with internal ordering & restore originals o["int"] = {} o["int"]["bus"] = ppc["bus"].copy() o["int"]["branch"] = ppc["branch"].copy() o["int"]["gen"] = ppc["gen"].copy() ppc["bus"] = o["ext"]["bus"].copy() ppc["branch"] = o["ext"]["branch"].copy() ppc["gen"] = o["ext"]["gen"].copy() if 'gencost' in ppc: o["int"]["gencost"] = ppc["gencost"].copy() ppc["gencost"] = o["ext"]["gencost"].copy() if 'areas' in ppc: o["int"]["areas"] = ppc["areas"].copy() ppc["areas"] = o["ext"]["areas"].copy() if 'A' in ppc: o["int"]["A"] = ppc["A"].copy() ppc["A"] = o["ext"]["A"].copy() if 'N' in ppc: o["int"]["N"] = ppc["N"].copy() ppc["N"] = o["ext"]["N"].copy() ## update data (in bus, branch and gen only) ppc["bus"][o["bus"]["status"]["on"], :] = \ o["int"]["bus"] ppc["branch"][o["branch"]["status"]["on"], :] = \ o["int"]["branch"] ppc["gen"][o["gen"]["status"]["on"], :] = \ o["int"]["gen"][o["gen"]["i2e"], :] if 'areas' in ppc: ppc["areas"][o["areas"]["status"]["on"], :] = \ o["int"]["areas"] ## revert to original bus numbers ppc["bus"][o["bus"]["status"]["on"], BUS_I] = \ o["bus"]["i2e"] \ [ ppc["bus"][o["bus"]["status"]["on"], BUS_I].astype(int) ] ppc["branch"][o["branch"]["status"]["on"], F_BUS] = \ o["bus"]["i2e"][ ppc["branch"] \ [o["branch"]["status"]["on"], F_BUS].astype(int) ] ppc["branch"][o["branch"]["status"]["on"], T_BUS] = \ o["bus"]["i2e"][ ppc["branch"] \ [o["branch"]["status"]["on"], T_BUS].astype(int) ] ppc["gen"][o["gen"]["status"]["on"], GEN_BUS] = \ o["bus"]["i2e"][ ppc["gen"] \ [o["gen"]["status"]["on"], GEN_BUS].astype(int) ] if 'areas' in ppc: ppc["areas"][o["areas"]["status"]["on"], PRICE_REF_BUS] = \ o["bus"]["i2e"][ ppc["areas"] \ [o["areas"]["status"]["on"], PRICE_REF_BUS].astype(int) ] if 'ext' in o: del o['ext'] o["state"] = 'e' ppc["order"] = o else: sys.stderr.write('int2ext: ppc claims it is already using ' 'external numbering.\n') else: ## convert extra data if isinstance(val_or_field, str) or isinstance(val_or_field, list): ## field (key) warn('Calls of the form MPC = INT2EXT(MPC, ''FIELD_NAME'', ...) have been deprecated. Please replace INT2EXT with I2E_FIELD.') bus, gen = val_or_field, oldval if ordering is not None: dim = ordering ppc = i2e_field(ppc, bus, gen, dim) else: ## value warn('Calls of the form VAL = INT2EXT(MPC, VAL, ...) have been deprecated. Please replace INT2EXT with I2E_DATA.') bus, gen, branch = val_or_field, oldval, ordering ppc = i2e_data(ppc, bus, gen, branch, dim) return ppc
def _ppc2ppci(ppc, bus_lookup): from numpy import array, zeros from scipy.sparse import csr_matrix as sparse from pypower.idx_bus import NONE, BUS_I, BUS_TYPE from pypower.idx_gen import GEN_BUS, GEN_STATUS from pypower.idx_brch import F_BUS, T_BUS, BR_STATUS, QT from pypower.idx_area import PRICE_REF_BUS from pypower.run_userfcn import run_userfcn # init ppci ppci = {"baseMVA": 1., "version": 2, "bus": np.array([], dtype=float), "branch": np.array([], dtype=np.complex128), "gen": np.array([], dtype=float), "branch_is": np.array([], dtype=bool), "gen_is": np.array([], dtype=bool)} # BUS Sorting and lookup # sort busses in descending order of column 1 (namely: 4 (OOS), 3 (REF), 2 (PV), 1 (PQ)) ppcBuses = ppc["bus"] ppc['bus'] = ppcBuses[ppcBuses[:, BUS_TYPE].argsort(axis=0)[::-1][:], ] # get OOS busses and place them at the end of the bus array (so that: 3 # (REF), 2 (PV), 1 (PQ), 4 (OOS)) oos_busses = ppc['bus'][:, BUS_TYPE] == NONE # there are no OOS busses in the ppci ppci['bus'] = ppc['bus'][~oos_busses] # in ppc the OOS busses are included and at the end of the array ppc['bus'] = np.r_[ppc['bus'][~oos_busses], ppc['bus'][oos_busses]] # generate bus_lookup_ppc_ppci (ppc -> ppci lookup) ppc_former_order = (ppc['bus'][:, BUS_I]).astype(int) arangedBuses = np.arange(len(ppcBuses)) # lookup ppc former order -> consecutive order e2i = zeros(len(ppcBuses)) e2i[ppc_former_order] = arangedBuses # save consecutive indices in ppc and ppci ppc['bus'][:, BUS_I] = arangedBuses ppci['bus'][:, BUS_I] = ppc['bus'][:len(ppci['bus']), BUS_I] # update bus_lookup (pandapower -> ppci internal) bus_lookup = {key: e2i[val] for (key, val) in bus_lookup.items()} # sizes nb = ppc["bus"].shape[0] ng = ppc["gen"].shape[0] if 'areas' in ppc: if len(ppc["areas"]) == 0: # if areas field is empty del ppc['areas'] # delete it (so it's ignored) # bus types bt = ppc["bus"][:, BUS_TYPE] # update branch, gen and areas bus numbering ppc['gen'][:, GEN_BUS] = \ e2i[np.real(ppc["gen"][:, GEN_BUS]).astype(int)].copy() ppc["branch"][:, F_BUS] = \ e2i[np.real(ppc["branch"][:, F_BUS]).astype(int)].copy() ppc["branch"][:, T_BUS] = \ e2i[np.real(ppc["branch"][:, T_BUS]).astype(int)].copy() # Note: The "update branch, gen and areas bus numbering" does the same as this: # ppc['gen'][:, GEN_BUS] = get_indices(ppc['gen'][:, GEN_BUS], bus_lookup_ppc_ppci) # ppc["branch"][:, F_BUS] = get_indices(ppc["branch"][:, F_BUS], bus_lookup_ppc_ppci) # ppc["branch"][:, T_BUS] = get_indices( ppc["branch"][:, T_BUS], bus_lookup_ppc_ppci) # but faster... if 'areas' in ppc: ppc["areas"][:, PRICE_REF_BUS] = \ e2i[np.real(ppc["areas"][:, PRICE_REF_BUS]).astype(int)].copy() # reorder gens in order of increasing bus number ppc['gen'] = ppc['gen'][ppc['gen'][:, GEN_BUS].argsort(), ] # determine which buses, branches, gens are connected and # in-service # n2i = sparse((range(nb), (ppc["bus"][:, BUS_I], zeros(nb))), # shape=(maxBus + 1, 1)) # n2i = array(n2i.todense().flatten())[0, :] # as 1D array n2i = ppc["bus"][:, BUS_I].astype(int) bs = (bt != NONE) # bus status gs = ((ppc["gen"][:, GEN_STATUS] > 0) & # gen status bs[n2i[np.real(ppc["gen"][:, GEN_BUS]).astype(int)]]) ppci["gen_is"] = gs brs = (np.real(ppc["branch"][:, BR_STATUS]).astype(int) & # branch status bs[n2i[np.real(ppc["branch"][:, F_BUS]).astype(int)]] & bs[n2i[np.real(ppc["branch"][:, T_BUS]).astype(int)]]).astype(bool) ppci["branch_is"] = brs if 'areas' in ppc: ar = bs[n2i[ppc["areas"][:, PRICE_REF_BUS].astype(int)]] # delete out of service areas ppci["areas"] = ppc["areas"][ar] # select in service elements from ppc and put them in ppci ppci["branch"] = ppc["branch"][brs] ppci["gen"] = ppc["gen"][gs] # execute userfcn callbacks for 'ext2int' stage if 'userfcn' in ppci: ppci = run_userfcn(ppci['userfcn'], 'ext2int', ppci) return ppci, bus_lookup