def scale_load(load, bus, gen=None, load_zone=None, opt=None): """Scales fixed and/or dispatchable loads. Assumes consecutive bus numbering when dealing with dispatchable loads. @param load: Each element specifies the amount of scaling for the corresponding load zone, either as a direct scale factor or as a target quantity. If there are C{nz} load zones this vector has C{nz} elements. @param bus: Standard C{bus} matrix with C{nb} rows, where the fixed active and reactive loads available for scaling are specified in columns C{PD} and C{QD} @param gen: (optional) standard C{gen} matrix with C{ng} rows, where the dispatchable loads available for scaling are specified by columns C{PG}, C{QG}, C{PMIN}, C{QMIN} and C{QMAX} (in rows for which C{isload(gen)} returns C{true}). If C{gen} is empty, it assumes there are no dispatchable loads. @param load_zone: (optional) C{nb} element vector where the value of each element is either zero or the index of the load zone to which the corresponding bus belongs. If C{load_zone[b] = k} then the loads at bus C{b} will be scaled according to the value of C{load[k]}. If C{load_zone[b] = 0}, the loads at bus C{b} will not be modified. If C{load_zone} is empty, the default is determined by the dimensions of the C{load} vector. If C{load} is a scalar, a single system-wide zone including all buses is used, i.e. C{load_zone = ones(nb)}. If C{load} is a vector, the default C{load_zone} is defined as the areas specified in the C{bus} matrix, i.e. C{load_zone = bus[:, BUS_AREA]}, and C{load} should have dimension C{= max(bus[:, BUS_AREA])}. @param opt: (optional) dict with three possible fields, 'scale', 'pq' and 'which' that determine the behavior as follows: - C{scale} (default is 'FACTOR') - 'FACTOR' : C{load} consists of direct scale factors, where C{load[k] =} scale factor C{R[k]} for zone C{k} - 'QUANTITY' : C{load} consists of target quantities, where C{load[k] =} desired total active load in MW for zone C{k} after scaling by an appropriate C{R(k)} - C{pq} (default is 'PQ') - 'PQ' : scale both active and reactive loads - 'P' : scale only active loads - C{which} (default is 'BOTH' if GEN is provided, else 'FIXED') - 'FIXED' : scale only fixed loads - 'DISPATCHABLE' : scale only dispatchable loads - 'BOTH' : scale both fixed and dispatchable loads @see: L{total_load} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ nb = bus.shape[0] ## number of buses ##----- process inputs ----- bus = bus.copy() if gen is None: gen = array([]) else: gen = gen.copy() if load_zone is None: load_zone = array([], int) if opt is None: opt = {} ## fill out and check opt if len(gen) == 0: opt["which"] = 'FIXED' if 'pq' not in opt: opt["pq"] = 'PQ' ## 'PQ' or 'P' if 'which' not in opt: opt["which"] = 'BOTH' ## 'FIXED', 'DISPATCHABLE' or 'BOTH' if 'scale' not in opt: opt["scale"] = 'FACTOR' ## 'FACTOR' or 'QUANTITY' if (opt["pq"] != 'P') and (opt["pq"] != 'PQ'): stderr.write("scale_load: opt['pq'] must equal 'PQ' or 'P'\n") if (opt["which"][0] != 'F') and (opt["which"][0] != 'D') and (opt["which"][0] != 'B'): stderr.write("scale_load: opt.which should be 'FIXED, 'DISPATCHABLE or 'BOTH'\n") if (opt["scale"][0] != 'F') and (opt["scale"][0] != 'Q'): stderr.write("scale_load: opt.scale should be 'FACTOR or 'QUANTITY'\n") if (len(gen) == 0) and (opt["which"][0] != 'F'): stderr.write('scale_load: need gen matrix to scale dispatchable loads\n') ## create dispatchable load connection matrix if len(gen) > 0: ng = gen.shape[0] is_ld = isload(gen) & (gen[:, GEN_STATUS] > 0) ld = find(is_ld) ## create map of external bus numbers to bus indices i2e = bus[:, BUS_I].astype(int) e2i = zeros(max(i2e) + 1, int) e2i[i2e] = arange(nb) gbus = gen[:, GEN_BUS].astype(int) Cld = sparse((is_ld, (e2i[gbus], arange(ng))), (nb, ng)) else: ng = 0 ld = array([], int) if len(load_zone) == 0: if len(load) == 1: ## make a single zone of all load buses load_zone = zeros(nb, int) ## initialize load_zone[bus[:, PD] != 0 or bus[:, QD] != 0] = 1 ## FIXED loads if len(gen) > 0: gbus = gen[ld, GEN_BUS].astype(int) load_zone[e2i[gbus]] = 1 ## DISPATCHABLE loads else: ## use areas defined in bus data as zones load_zone = bus[:, BUS_AREA] ## check load_zone to make sure it's consistent with size of load vector if max(load_zone) > len(load): stderr.write('scale_load: load vector must have a value for each load zone specified\n') ##----- compute scale factors for each zone ----- scale = load.copy() Pdd = zeros(nb) ## dispatchable P at each bus if opt["scale"][0] == 'Q': ## 'QUANTITY' ## find load capacity from dispatchable loads if len(gen) > 0: Pdd = -Cld * gen[:, PMIN] ## compute scale factors for k in range(len(load)): idx = find(load_zone == k + 1) fixed = sum(bus[idx, PD]) dispatchable = sum(Pdd[idx]) total = fixed + dispatchable if opt["which"][0] == 'B': ## 'BOTH' if total != 0: scale[k] = load[k] / total elif load[k] == total: scale[k] = 1 else: raise ScalingError('scale_load: impossible to make zone %d load equal %g by scaling non-existent loads\n' % (k, load[k])) elif opt["which"][0] == 'F': ## 'FIXED' if fixed != 0: scale[k] = (load[k] - dispatchable) / fixed elif load[k] == dispatchable: scale[k] = 1 else: raise ScalingError('scale_load: impossible to make zone %d load equal %g by scaling non-existent fixed load\n' % (k, load[k])) elif opt["which"][0] == 'D': ## 'DISPATCHABLE' if dispatchable != 0: scale[k] = (load[k] - fixed) / dispatchable elif load[k] == fixed: scale[k] = 1 else: raise ScalingError('scale_load: impossible to make zone %d load equal %g by scaling non-existent dispatchable load\n' % (k, load[k])) ##----- do the scaling ----- ## fixed loads if opt["which"][0] != 'D': ## includes 'FIXED', not 'DISPATCHABLE' only for k in range(len(scale)): idx = find(load_zone == k + 1) bus[idx, PD] = bus[idx, PD] * scale[k] if opt["pq"] == 'PQ': bus[idx, QD] = bus[idx, QD] * scale[k] ## dispatchable loads if opt["which"][0] != 'F': ## includes 'DISPATCHABLE', not 'FIXED' only for k in range(len(scale)): idx = find(load_zone == k + 1) gbus = gen[ld, GEN_BUS].astype(int) i = find( in1d(e2i[gbus], idx) ) ig = ld[i] gen[ix_(ig, [PG, PMIN])] = gen[ix_(ig, [PG, PMIN])] * scale[k] if opt["pq"] == 'PQ': gen[ix_(ig, [QG, QMIN, QMAX])] = gen[ix_(ig, [QG, QMIN, QMAX])] * scale[k] return bus, gen
def total_load(bus, gen=None, load_zone=None, which_type=None): """Returns vector of total load in each load zone. @param bus: standard C{bus} matrix with C{nb} rows, where the fixed active and reactive loads are specified in columns C{PD} and C{QD} @param gen: (optional) standard C{gen} matrix with C{ng} rows, where the dispatchable loads are specified by columns C{PG}, C{QG}, C{PMIN}, C{QMIN} and C{QMAX} (in rows for which C{isload(GEN)} returns C{True}). If C{gen} is empty, it assumes there are no dispatchable loads. @param load_zone: (optional) C{nb} element vector where the value of each element is either zero or the index of the load zone to which the corresponding bus belongs. If C{load_zone(b) = k} then the loads at bus C{b} will added to the values of C{Pd[k]} and C{Qd[k]}. If C{load_zone} is empty, the default is defined as the areas specified in the C{bus} matrix, i.e. C{load_zone = bus[:, BUS_AREA]} and load will have dimension C{= max(bus[:, BUS_AREA])}. If C{load_zone = 'all'}, the result is a scalar with the total system load. @param which_type: (default is 'BOTH' if C{gen} is provided, else 'FIXED') - 'FIXED' : sum only fixed loads - 'DISPATCHABLE' : sum only dispatchable loads - 'BOTH' : sum both fixed and dispatchable loads @see: L{scale_load} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ nb = bus.shape[0] ## number of buses if gen is None: gen = array([]) if load_zone is None: load_zone = array([], int) ## fill out and check which_type if len(gen) == 0: which_type = 'FIXED' if (which_type == None) and (len(gen) > 0): which_type = 'BOTH' ## 'FIXED', 'DISPATCHABLE' or 'BOTH' if (which_type[0] != 'F') and (which_type[0] != 'D') and (which_type[0] != 'B'): stderr.write("total_load: which_type should be 'FIXED, 'DISPATCHABLE or 'BOTH'\n") want_Q = True want_fixed = (which_type[0] == 'B') | (which_type[0] == 'F') want_disp = (which_type[0] == 'B') | (which_type[0] == 'D') ## initialize load_zone if isinstance(load_zone, basestring) & (load_zone == 'all'): load_zone = ones(nb, int) ## make a single zone of all buses elif len(load_zone) == 0: load_zone = bus[:, BUS_AREA].astype(int) ## use areas defined in bus data as zones nz = max(load_zone) ## number of load zones ## fixed load at each bus, & initialize dispatchable if want_fixed: Pdf = bus[:, PD] ## real power if want_Q: Qdf = bus[:, QD] ## reactive power else: Pdf = zeros(nb) ## real power if want_Q: Qdf = zeros(nb) ## reactive power ## dispatchable load at each bus if want_disp: ## need dispatchable ng = gen.shape[0] is_ld = isload(gen) & (gen[:, GEN_STATUS] > 0) ld = find(is_ld) ## create map of external bus numbers to bus indices i2e = bus[:, BUS_I].astype(int) e2i = zeros(max(i2e) + 1) e2i[i2e] = arange(nb) gbus = gen[:, GEN_BUS].astype(int) Cld = sparse((is_ld, (e2i[gbus], arange(ng))), (nb, ng)) Pdd = -Cld * gen[:, PMIN] ## real power if want_Q: Q = zeros(ng) Q[ld] = (gen[ld, QMIN] == 0) * gen[ld, QMAX] + \ (gen[ld, QMAX] == 0) * gen[ld, QMIN] Qdd = -Cld * Q ## reactive power else: Pdd = zeros(nb) if want_Q: Qdd = zeros(nb) ## compute load sums Pd = zeros(nz) if want_Q: Qd = zeros(nz) for k in range(1, nz + 1): idx = find(load_zone == k) Pd[k - 1] = sum(Pdf[idx]) + sum(Pdd[idx]) if want_Q: Qd[k - 1] = sum(Qdf[idx]) + sum(Qdd[idx]) return Pd, Qd
def makeAvl(baseMVA, gen): """Construct linear constraints for constant power factor var loads. Constructs parameters for the following linear constraint enforcing a constant power factor constraint for dispatchable loads:: lvl <= Avl * [Pg, Qg] <= uvl C{ivl} is the vector of indices of generators representing variable loads. @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Richard Lincoln """ ## data dimensions ng = gen.shape[0] ## number of dispatchable injections Pg = gen[:, PG] / baseMVA Qg = gen[:, QG] / baseMVA Pmin = gen[:, PMIN] / baseMVA Qmin = gen[:, QMIN] / baseMVA Qmax = gen[:, QMAX] / baseMVA # Find out if any of these "generators" are actually dispatchable loads. # (see 'help isload' for details on what constitutes a dispatchable load) # Dispatchable loads are modeled as generators with an added constant # power factor constraint. The power factor is derived from the original # value of Pmin and either Qmin (for inductive loads) or Qmax (for # capacitive loads). If both Qmin and Qmax are zero, this implies a unity # power factor without the need for an additional constraint. ivl = find( isload(gen) & ((Qmin != 0) | (Qmax != 0)) ) nvl = ivl.shape[0] ## number of dispatchable loads ## at least one of the Q limits must be zero (corresponding to Pmax == 0) if any( (Qmin[ivl] != 0) & (Qmax[ivl] != 0) ): stderr.write('makeAvl: either Qmin or Qmax must be equal to zero for ' 'each dispatchable load.\n') # Initial values of PG and QG must be consistent with specified power # factor This is to prevent a user from unknowingly using a case file which # would have defined a different power factor constraint under a previous # version which used PG and QG to define the power factor. Qlim = (Qmin[ivl] == 0) * Qmax[ivl] + (Qmax[ivl] == 0) * Qmin[ivl] if any( abs( Qg[ivl] - Pg[ivl] * Qlim / Pmin[ivl] ) > 1e-6 ): stderr.write('makeAvl: For a dispatchable load, PG and QG must be ' 'consistent with the power factor defined by PMIN and ' 'the Q limits.\n') # make Avl, lvl, uvl, for lvl <= Avl * [Pg Qg] <= uvl if nvl > 0: xx = Pmin[ivl] yy = Qlim pftheta = arctan2(yy, xx) pc = sin(pftheta) qc = -cos(pftheta) ii = r_[ arange(nvl), arange(nvl) ] jj = r_[ ivl, ivl + ng ] Avl = sparse((r_[pc, qc], (ii, jj)), (nvl, 2 * ng)) lvl = zeros(nvl) uvl = lvl else: Avl = zeros((0, 2*ng)) lvl = array([]) uvl = array([]) return Avl, lvl, uvl, ivl
def uopf(*args): """Solves combined unit decommitment / optimal power flow. Solves a combined unit decommitment and optimal power flow for a single time period. Uses an algorithm similar to dynamic programming. It proceeds through a sequence of stages, where stage C{N} has C{N} generators shut down, starting with C{N=0}. In each stage, it forms a list of candidates (gens at their C{Pmin} limits) and computes the cost with each one of them shut down. It selects the least cost case as the starting point for the next stage, continuing until there are no more candidates to be shut down or no more improvement can be gained by shutting something down. If C{verbose} in ppopt (see L{ppoption} is C{true}, it prints progress info, if it is > 1 it prints the output of each individual opf. @see: L{opf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ##----- initialization ----- t0 = time() ## start timer ## process input arguments ppc, ppopt = opf_args2(*args) ## options verbose = ppopt["VERBOSE"] if verbose: ## turn down verbosity one level for calls to opf ppopt = ppoption(ppopt, VERBOSE=verbose - 1) ##----- do combined unit commitment/optimal power flow ----- ## check for sum(Pmin) > total load, decommit as necessary on = find( (ppc["gen"][:, GEN_STATUS] > 0) & ~isload(ppc["gen"]) ) ## gens in service onld = find( (ppc["gen"][:, GEN_STATUS] > 0) & isload(ppc["gen"]) ) ## disp loads in serv load_capacity = sum(ppc["bus"][:, PD]) - sum(ppc["gen"][onld, PMIN]) ## total load capacity Pmin = ppc["gen"][on, PMIN] while sum(Pmin) > load_capacity: ## shut down most expensive unit avgPmincost = totcost(ppc["gencost"][on, :], Pmin) / Pmin _, i = fairmax(avgPmincost) ## pick one with max avg cost at Pmin i = on[i] ## convert to generator index if verbose: print 'Shutting down generator %d so all Pmin limits can be satisfied.\n' % i ## set generation to zero ppc["gen"][i, [PG, QG, GEN_STATUS]] = 0 ## update minimum gen capacity on = find( (ppc["gen"][:, GEN_STATUS] > 0) & ~isload(ppc["gen"]) ) ## gens in service Pmin = ppc["gen"][on, PMIN] ## run initial opf results = opf(ppc, ppopt) ## best case so far results1 = deepcopy(results) ## best case for this stage (ie. with n gens shut down, n=0,1,2 ...) results0 = deepcopy(results1) ppc["bus"] = results0["bus"].copy() ## use these V as starting point for OPF while True: ## get candidates for shutdown candidates = find((results0["gen"][:, MU_PMIN] > 0) & (results0["gen"][:, PMIN] > 0)) if len(candidates) == 0: break ## do not check for further decommitment unless we ## see something better during this stage done = True for k in candidates: ## start with best for this stage ppc["gen"] = results0["gen"].copy() ## shut down gen k ppc["gen"][k, [PG, QG, GEN_STATUS]] = 0 ## run opf results = opf(ppc, ppopt) ## something better? if results['success'] and (results["f"] < results1["f"]): results1 = deepcopy(results) k1 = k done = False ## make sure we check for further decommitment if done: ## decommits at this stage did not help, so let's quit break else: ## shutting something else down helps, so let's keep going if verbose: print 'Shutting down generator %d.\n' % k1 results0 = deepcopy(results1) ppc["bus"] = results0["bus"].copy() ## use these V as starting point for OPF ## compute elapsed time et = time() - t0 ## finish preparing output results0['et'] = et return results0
def printpf(baseMVA, bus=None, gen=None, branch=None, f=None, success=None, et=None, fd=None, ppopt=None): """Prints power flow results. Prints power flow and optimal power flow results to C{fd} (a file descriptor which defaults to C{stdout}), with the details of what gets printed controlled by the optional C{ppopt} argument, which is a PYPOWER options vector (see L{ppoption} for details). The data can either be supplied in a single C{results} dict, or in the individual arguments: C{baseMVA}, C{bus}, C{gen}, C{branch}, C{f}, C{success} and C{et}, where C{f} is the OPF objective function value, C{success} is C{True} if the solution converged and C{False} otherwise, and C{et} is the elapsed time for the computation in seconds. If C{f} is given, it is assumed that the output is from an OPF run, otherwise it is assumed to be a simple power flow run. Examples:: ppopt = ppoptions(OUT_GEN=1, OUT_BUS=0, OUT_BRANCH=0) fd = open(fname, 'w+b') results = runopf(ppc) printpf(results) printpf(results, fd) printpf(results, fd, ppopt) printpf(baseMVA, bus, gen, branch, f, success, et) printpf(baseMVA, bus, gen, branch, f, success, et, fd) printpf(baseMVA, bus, gen, branch, f, success, et, fd, ppopt) fd.close() @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ##----- initialization ----- ## default arguments if isinstance(baseMVA, dict): have_results_struct = 1 results = baseMVA if gen is None: ppopt = ppoption() ## use default options else: ppopt = gen if (ppopt['OUT_ALL'] == 0): return ## nothin' to see here, bail out now if bus is None: fd = stdout ## print to stdout by default else: fd = bus baseMVA, bus, gen, branch, success, et = \ results["baseMVA"], results["bus"], results["gen"], \ results["branch"], results["success"], results["et"] if 'f' in results: f = results["f"] else: f = None else: have_results_struct = 0 if ppopt is None: ppopt = ppoption() ## use default options if fd is None: fd = stdout ## print to stdout by default if ppopt['OUT_ALL'] == 0: return ## nothin' to see here, bail out now isOPF = f is not None ## FALSE -> only simple PF data, TRUE -> OPF data ## options isDC = ppopt['PF_DC'] ## use DC formulation? OUT_ALL = ppopt['OUT_ALL'] OUT_ANY = OUT_ALL == 1 ## set to true if any pretty output is to be generated OUT_SYS_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_SYS_SUM']) OUT_AREA_SUM = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_AREA_SUM']) OUT_BUS = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BUS']) OUT_BRANCH = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_BRANCH']) OUT_GEN = (OUT_ALL == 1) or ((OUT_ALL == -1) and ppopt['OUT_GEN']) OUT_ANY = OUT_ANY | ((OUT_ALL == -1) and (OUT_SYS_SUM or OUT_AREA_SUM or OUT_BUS or OUT_BRANCH or OUT_GEN)) if OUT_ALL == -1: OUT_ALL_LIM = ppopt['OUT_ALL_LIM'] elif OUT_ALL == 1: OUT_ALL_LIM = 2 else: OUT_ALL_LIM = 0 OUT_ANY = OUT_ANY or (OUT_ALL_LIM >= 1) if OUT_ALL_LIM == -1: OUT_V_LIM = ppopt['OUT_V_LIM'] OUT_LINE_LIM = ppopt['OUT_LINE_LIM'] OUT_PG_LIM = ppopt['OUT_PG_LIM'] OUT_QG_LIM = ppopt['OUT_QG_LIM'] else: OUT_V_LIM = OUT_ALL_LIM OUT_LINE_LIM = OUT_ALL_LIM OUT_PG_LIM = OUT_ALL_LIM OUT_QG_LIM = OUT_ALL_LIM OUT_ANY = OUT_ANY or ((OUT_ALL_LIM == -1) and (OUT_V_LIM or OUT_LINE_LIM or OUT_PG_LIM or OUT_QG_LIM)) ptol = 1e-4 ## tolerance for displaying shadow prices ## create map of external bus numbers to bus indices i2e = bus[:, BUS_I].astype(int) e2i = zeros(max(i2e) + 1, int) e2i[i2e] = arange(bus.shape[0]) ## sizes of things nb = bus.shape[0] ## number of buses nl = branch.shape[0] ## number of branches ng = gen.shape[0] ## number of generators ## zero out some data to make printout consistent for DC case if isDC: bus[:, r_[QD, BS]] = zeros((nb, 2)) gen[:, r_[QG, QMAX, QMIN]] = zeros((ng, 3)) branch[:, r_[BR_R, BR_B]] = zeros((nl, 2)) ## parameters ties = find(bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA]) ## area inter-ties tap = ones(nl) ## default tap ratio = 1 for lines xfmr = find(branch[:, TAP]) ## indices of transformers tap[xfmr] = branch[xfmr, TAP] ## include transformer tap ratios tap = tap * exp(1j * pi / 180 * branch[:, SHIFT]) ## add phase shifters nzld = find((bus[:, PD] != 0.0) | (bus[:, QD] != 0.0)) sorted_areas = sort(bus[:, BUS_AREA]) ## area numbers s_areas = sorted_areas[r_[1, find(diff(sorted_areas)) + 1]] nzsh = find((bus[:, GS] != 0.0) | (bus[:, BS] != 0.0)) allg = find( ~isload(gen) ) ong = find( (gen[:, GEN_STATUS] > 0) & ~isload(gen) ) onld = find( (gen[:, GEN_STATUS] > 0) & isload(gen) ) V = bus[:, VM] * exp(-1j * pi / 180 * bus[:, VA]) out = find(branch[:, BR_STATUS] == 0) ## out-of-service branches nout = len(out) if isDC: loss = zeros(nl) else: loss = baseMVA * abs(V[e2i[ branch[:, F_BUS].astype(int) ]] / tap - V[e2i[ branch[:, T_BUS].astype(int) ]])**2 / \ (branch[:, BR_R] - 1j * branch[:, BR_X]) fchg = abs(V[e2i[ branch[:, F_BUS].astype(int) ]] / tap)**2 * branch[:, BR_B] * baseMVA / 2 tchg = abs(V[e2i[ branch[:, T_BUS].astype(int) ]] )**2 * branch[:, BR_B] * baseMVA / 2 loss[out] = zeros(nout) fchg[out] = zeros(nout) tchg[out] = zeros(nout) ##----- print the stuff ----- if OUT_ANY: ## convergence & elapsed time if success: fd.write('\nConverged in %.2f seconds' % et) else: fd.write('\nDid not converge (%.2f seconds)\n' % et) ## objective function value if isOPF: fd.write('\nObjective Function Value = %.2f $/hr' % f) if OUT_SYS_SUM: fd.write('\n================================================================================') fd.write('\n| System Summary |') fd.write('\n================================================================================') fd.write('\n\nHow many? How much? P (MW) Q (MVAr)') fd.write('\n--------------------- ------------------- ------------- -----------------') fd.write('\nBuses %6d Total Gen Capacity %7.1f %7.1f to %.1f' % (nb, sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum(gen[allg, QMAX]))) fd.write('\nGenerators %5d On-line Capacity %7.1f %7.1f to %.1f' % (len(allg), sum(gen[ong, PMAX]), sum(gen[ong, QMIN]), sum(gen[ong, QMAX]))) fd.write('\nCommitted Gens %5d Generation (actual) %7.1f %7.1f' % (len(ong), sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\nLoads %5d Load %7.1f %7.1f' % (len(nzld)+len(onld), sum(bus[nzld, PD])-sum(gen[onld, PG]), sum(bus[nzld, QD])-sum(gen[onld, QG]))) fd.write('\n Fixed %5d Fixed %7.1f %7.1f' % (len(nzld), sum(bus[nzld, PD]), sum(bus[nzld, QD]))) fd.write('\n Dispatchable %5d Dispatchable %7.1f of %-7.1f%7.1f' % (len(onld), -sum(gen[onld, PG]), -sum(gen[onld, PMIN]), -sum(gen[onld, QG]))) fd.write('\nShunts %5d Shunt (inj) %7.1f %7.1f' % (len(nzsh), -sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]) )) fd.write('\nBranches %5d Losses (I^2 * Z) %8.2f %8.2f' % (nl, sum(loss.real), sum(loss.imag) )) fd.write('\nTransformers %5d Branch Charging (inj) - %7.1f' % (len(xfmr), sum(fchg) + sum(tchg) )) fd.write('\nInter-ties %5d Total Inter-tie Flow %7.1f %7.1f' % (len(ties), sum(abs(branch[ties, PF]-branch[ties, PT])) / 2, sum(abs(branch[ties, QF]-branch[ties, QT])) / 2)) fd.write('\nAreas %5d' % len(s_areas)) fd.write('\n') fd.write('\n Minimum Maximum') fd.write('\n ------------------------- --------------------------------') minv = min(bus[:, VM]) mini = argmin(bus[:, VM]) maxv = max(bus[:, VM]) maxi = argmax(bus[:, VM]) fd.write('\nVoltage Magnitude %7.3f p.u. @ bus %-4d %7.3f p.u. @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, VA]) mini = argmin(bus[:, VA]) maxv = max(bus[:, VA]) maxi = argmax(bus[:, VA]) fd.write('\nVoltage Angle %8.2f deg @ bus %-4d %8.2f deg @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) if not isDC: maxv = max(loss.real) maxi = argmax(loss.real) fd.write('\nP Losses (I^2*R) - %8.2f MW @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) maxv = max(loss.imag) maxi = argmax(loss.imag) fd.write('\nQ Losses (I^2*X) - %8.2f MVAr @ line %d-%d' % (maxv, branch[maxi, F_BUS], branch[maxi, T_BUS])) if isOPF: minv = min(bus[:, LAM_P]) mini = argmin(bus[:, LAM_P]) maxv = max(bus[:, LAM_P]) maxi = argmax(bus[:, LAM_P]) fd.write('\nLambda P %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) minv = min(bus[:, LAM_Q]) mini = argmin(bus[:, LAM_Q]) maxv = max(bus[:, LAM_Q]) maxi = argmax(bus[:, LAM_Q]) fd.write('\nLambda Q %8.2f $/MWh @ bus %-4d %8.2f $/MWh @ bus %-4d' % (minv, bus[mini, BUS_I], maxv, bus[maxi, BUS_I])) fd.write('\n') if OUT_AREA_SUM: fd.write('\n================================================================================') fd.write('\n| Area Summary |') fd.write('\n================================================================================') fd.write('\nArea # of # of Gens # of Loads # of # of # of # of') fd.write('\n Num Buses Total Online Total Fixed Disp Shunt Brchs Xfmrs Ties') fd.write('\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----') for i in range(len(s_areas)): a = s_areas[i] ib = find(bus[:, BUS_AREA] == a) ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) in_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a)) out_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a)) if not any(xfmr + 1): nxfmr = 0 else: nxfmr = len(find((bus[e2i[branch[xfmr, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[xfmr, T_BUS].astype(int)], BUS_AREA] == a))) fd.write('\n%3d %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (a, len(ib), len(ig), len(igon), \ len(inzld)+len(ildon), len(inzld), len(ildon), \ len(inzsh), len(ibrch), nxfmr, len(in_tie)+len(out_tie))) fd.write('\n---- ----- ----- ------ ----- ----- ----- ----- ----- ----- -----') fd.write('\nTot: %6d %5d %5d %5d %5d %5d %5d %5d %5d %5d' % (nb, len(allg), len(ong), len(nzld)+len(onld), len(nzld), len(onld), len(nzsh), nl, len(xfmr), len(ties))) fd.write('\n') fd.write('\nArea Total Gen Capacity On-line Gen Capacity Generation') fd.write('\n Num MW MVAr MW MVAr MW MVAr') fd.write('\n---- ------ ------------------ ------ ------------------ ------ ------') for i in range(len(s_areas)): a = s_areas[i] ig = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & ~isload(gen)) igon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & ~isload(gen)) fd.write('\n%3d %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (a, sum(gen[ig, PMAX]), sum(gen[ig, QMIN]), sum(gen[ig, QMAX]), sum(gen[igon, PMAX]), sum(gen[igon, QMIN]), sum(gen[igon, QMAX]), sum(gen[igon, PG]), sum(gen[igon, QG]) )) fd.write('\n---- ------ ------------------ ------ ------------------ ------ ------') fd.write('\nTot: %7.1f %7.1f to %-7.1f %7.1f %7.1f to %-7.1f %7.1f %7.1f' % (sum(gen[allg, PMAX]), sum(gen[allg, QMIN]), sum(gen[allg, QMAX]), sum(gen[ong, PMAX]), sum(gen[ong, QMIN]), sum(gen[ong, QMAX]), sum(gen[ong, PG]), sum(gen[ong, QG]) )) fd.write('\n') fd.write('\nArea Disp Load Cap Disp Load Fixed Load Total Load') fd.write('\n Num MW MVAr MW MVAr MW MVAr MW MVAr') fd.write('\n---- ------ ------ ------ ------ ------ ------ ------ ------') Qlim = (gen[:, QMIN] == 0) * gen[:, QMAX] + (gen[:, QMAX] == 0) * gen[:, QMIN] for i in range(len(s_areas)): a = s_areas[i] ildon = find((bus[e2i[gen[:, GEN_BUS].astype(int)], BUS_AREA] == a) & (gen[:, GEN_STATUS] > 0) & isload(gen)) inzld = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, PD], bus[:, QD])) fd.write('\n%3d %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (a, -sum(gen[ildon, PMIN]), -sum(Qlim[ildon]), -sum(gen[ildon, PG]), -sum(gen[ildon, QG]), sum(bus[inzld, PD]), sum(bus[inzld, QD]), -sum(gen[ildon, PG]) + sum(bus[inzld, PD]), -sum(gen[ildon, QG]) + sum(bus[inzld, QD]) )) fd.write('\n---- ------ ------ ------ ------ ------ ------ ------ ------') fd.write('\nTot: %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (-sum(gen[onld, PMIN]), -sum(Qlim[onld]), -sum(gen[onld, PG]), -sum(gen[onld, QG]), sum(bus[nzld, PD]), sum(bus[nzld, QD]), -sum(gen[onld, PG]) + sum(bus[nzld, PD]), -sum(gen[onld, QG]) + sum(bus[nzld, QD])) ) fd.write('\n') fd.write('\nArea Shunt Inj Branch Series Losses Net Export') fd.write('\n Num MW MVAr Charging MW MVAr MW MVAr') fd.write('\n---- ------ ------ -------- ------ ------ ------ ------') for i in range(len(s_areas)): a = s_areas[i] inzsh = find((bus[:, BUS_AREA] == a) & logical_or(bus[:, GS], bus[:, BS])) ibrch = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) in_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] != a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] == a) & branch[:, BR_STATUS].astype(bool)) out_tie = find((bus[e2i[branch[:, F_BUS].astype(int)], BUS_AREA] == a) & (bus[e2i[branch[:, T_BUS].astype(int)], BUS_AREA] != a) & branch[:, BR_STATUS].astype(bool)) fd.write('\n%3d %7.1f %7.1f %7.1f %7.2f %7.2f %7.1f %7.1f' % (a, -sum(bus[inzsh, VM]**2 * bus[inzsh, GS]), sum(bus[inzsh, VM]**2 * bus[inzsh, BS]), sum(fchg[ibrch]) + sum(tchg[ibrch]) + sum(fchg[out_tie]) + sum(tchg[in_tie]), sum(real(loss[ibrch])) + sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(imag(loss[ibrch])) + sum(imag(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, PT])+sum(branch[out_tie, PF]) - sum(real(loss[r_[in_tie, out_tie]])) / 2, sum(branch[in_tie, QT])+sum(branch[out_tie, QF]) - sum(imag(loss[r_[in_tie, out_tie]])) / 2 )) fd.write('\n---- ------ ------ -------- ------ ------ ------ ------') fd.write('\nTot: %7.1f %7.1f %7.1f %7.2f %7.2f - -' % (-sum(bus[nzsh, VM]**2 * bus[nzsh, GS]), sum(bus[nzsh, VM]**2 * bus[nzsh, BS]), sum(fchg) + sum(tchg), sum(real(loss)), sum(imag(loss)) )) fd.write('\n') ## generator data if OUT_GEN: if isOPF: genlamP = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_P] genlamQ = bus[e2i[gen[:, GEN_BUS].astype(int)], LAM_Q] fd.write('\n================================================================================') fd.write('\n| Generator Data |') fd.write('\n================================================================================') fd.write('\n Gen Bus Status Pg Qg ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(ong)): i = ong[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or(gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (gen[i, PG], gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]))) fd.write('\n') if any(onld + 1): fd.write('\n================================================================================') fd.write('\n| Dispatchable Load Data |') fd.write('\n================================================================================') fd.write('\n Gen Bus Status Pd Qd ') if isOPF: fd.write(' Lambda ($/MVA-hr)') fd.write('\n # # (MW) (MVAr) ') if isOPF: fd.write(' P Q ') fd.write('\n---- ----- ------ -------- --------') if isOPF: fd.write(' -------- --------') for k in range(len(onld)): i = onld[k] fd.write('\n%3d %6d %2d ' % (i, gen[i, GEN_BUS], gen[i, GEN_STATUS])) if (gen[i, GEN_STATUS] > 0) & logical_or(gen[i, PG], gen[i, QG]): fd.write('%10.2f%10.2f' % (-gen[i, PG], -gen[i, QG])) else: fd.write(' - - ') if isOPF: fd.write('%10.2f%10.2f' % (genlamP[i], genlamQ[i])) fd.write('\n -------- --------') fd.write('\n Total: %9.2f%10.2f' % (-sum(gen[onld, PG]), -sum(gen[onld, QG]))) fd.write('\n') ## bus data if OUT_BUS: fd.write('\n================================================================================') fd.write('\n| Bus Data |') fd.write('\n================================================================================') fd.write('\n Bus Voltage Generation Load ') if isOPF: fd.write(' Lambda($/MVA-hr)') fd.write('\n # Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr)') if isOPF: fd.write(' P Q ') fd.write('\n----- ------- -------- -------- -------- -------- --------') if isOPF: fd.write(' ------- -------') for i in range(nb): fd.write('\n%5d%7.3f%9.3f' % tuple(bus[i, [BUS_I, VM, VA]])) if bus[i, BUS_TYPE] == REF: fd.write('*') else: fd.write(' ') g = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & ~isload(gen)) ld = find((gen[:, GEN_STATUS] > 0) & (gen[:, GEN_BUS] == bus[i, BUS_I]) & isload(gen)) if any(g + 1): fd.write('%9.2f%10.2f' % (sum(gen[g, PG]), sum(gen[g, QG]))) else: fd.write(' - - ') if logical_or(bus[i, PD], bus[i, QD]) | any(ld + 1): if any(ld + 1): fd.write('%10.2f*%9.2f*' % (bus[i, PD] - sum(gen[ld, PG]), bus[i, QD] - sum(gen[ld, QG]))) else: fd.write('%10.2f%10.2f ' % tuple(bus[i, [PD, QD]])) else: fd.write(' - - ') if isOPF: fd.write('%9.3f' % bus[i, LAM_P]) if abs(bus[i, LAM_Q]) > ptol: fd.write('%8.3f' % bus[i, LAM_Q]) else: fd.write(' -') fd.write('\n -------- -------- -------- --------') fd.write('\n Total: %9.2f %9.2f %9.2f %9.2f' % (sum(gen[ong, PG]), sum(gen[ong, QG]), sum(bus[nzld, PD]) - sum(gen[onld, PG]), sum(bus[nzld, QD]) - sum(gen[onld, QG]))) fd.write('\n') ## branch data if OUT_BRANCH: fd.write('\n================================================================================') fd.write('\n| Branch Data |') fd.write('\n================================================================================') fd.write('\nBrnch From To From Bus Injection To Bus Injection Loss (I^2 * Z) ') fd.write('\n # Bus Bus P (MW) Q (MVAr) P (MW) Q (MVAr) P (MW) Q (MVAr)') fd.write('\n----- ----- ----- -------- -------- -------- -------- -------- --------') for i in range(nl): fd.write('\n%4d%7d%7d%10.2f%10.2f%10.2f%10.2f%10.3f%10.2f' % (i, branch[i, F_BUS], branch[i, T_BUS], branch[i, PF], branch[i, QF], branch[i, PT], branch[i, QT], loss[i].real, loss[i].imag)) fd.write('\n -------- --------') fd.write('\n Total:%10.3f%10.2f' % (sum(real(loss)), sum(imag(loss)))) fd.write('\n') ##----- constraint data ----- if isOPF: ctol = ppopt['OPF_VIOLATION'] ## constraint violation tolerance ## voltage constraints if (not isDC) & (OUT_V_LIM == 2 | (OUT_V_LIM == 1 & (any(bus[:, VM] < bus[:, VMIN] + ctol) | any(bus[:, VM] > bus[:, VMAX] - ctol) | any(bus[:, MU_VMIN] > ptol) | any(bus[:, MU_VMAX] > ptol)))): fd.write('\n================================================================================') fd.write('\n| Voltage Constraints |') fd.write('\n================================================================================') fd.write('\nBus # Vmin mu Vmin |V| Vmax Vmax mu') fd.write('\n----- -------- ----- ----- ----- --------') for i in range(nb): if (OUT_V_LIM == 2) | (OUT_V_LIM == 1 & ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMIN] > ptol) | (bus[i, MU_VMAX] > ptol))): fd.write('\n%5d' % bus[i, BUS_I]) if ((bus[i, VM] < bus[i, VMIN] + ctol) | (bus[i, MU_VMIN] > ptol)): fd.write('%10.3f' % bus[i, MU_VMIN]) else: fd.write(' - ') fd.write('%8.3f%7.3f%7.3f' % tuple(bus[i, [VMIN, VM, VMAX]])) if (bus[i, VM] > bus[i, VMAX] - ctol) | (bus[i, MU_VMAX] > ptol): fd.write('%10.3f' % bus[i, MU_VMAX]) else: fd.write(' - ') fd.write('\n') ## generator P constraints if (OUT_PG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))) | \ ((not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol))))): fd.write('\n================================================================================') fd.write('\n| Generation Constraints |') fd.write('\n================================================================================') if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & (any(gen[ong, PG] < gen[ong, PMIN] + ctol) | any(gen[ong, PG] > gen[ong, PMAX] - ctol) | any(gen[ong, MU_PMIN] > ptol) | any(gen[ong, MU_PMAX] > ptol))): fd.write('\n Gen Bus Active Power Limits') fd.write('\n # # Pmin mu Pmin Pg Pmax Pmax mu') fd.write('\n---- ----- ------- -------- -------- -------- -------') for k in range(len(ong)): i = ong[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%4d%6d ' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [PMIN, PG, PMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [PMIN, PMAX]])) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## generator Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[ong, QG] < gen[ong, QMIN] + ctol) | any(gen[ong, QG] > gen[ong, QMAX] - ctol) | any(gen[ong, MU_QMIN] > ptol) | any(gen[ong, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write('\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(ong)): i = ong[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % tuple(gen[i, [QMIN, QG, QMAX]])) else: fd.write('%10.2f - %10.2f' % tuple(gen[i, [QMIN, QMAX]])) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load P constraints if (OUT_PG_LIM == 2) | (OUT_QG_LIM == 2) | \ ((OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))) | \ ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol))): fd.write('\n================================================================================') fd.write('\n| Dispatchable Load Constraints |') fd.write('\n================================================================================') if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & (any(gen[onld, PG] < gen[onld, PMIN] + ctol) | any(gen[onld, PG] > gen[onld, PMAX] - ctol) | any(gen[onld, MU_PMIN] > ptol) | any(gen[onld, MU_PMAX] > ptol))): fd.write('\nGen Bus Active Power Limits') fd.write('\n # # Pmin mu Pmin Pg Pmax Pmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_PG_LIM == 2) | ((OUT_PG_LIM == 1) & ((gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMIN] > ptol) | (gen[i, MU_PMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen[i, GEN_BUS])) if (gen[i, PG] < gen[i, PMIN] + ctol) | (gen[i, MU_PMIN] > ptol): fd.write('%8.3f' % gen[i, MU_PMIN]) else: fd.write(' - ') if gen[i, PG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [PMIN, PG, PMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [PMIN, PMAX]]) if (gen[i, PG] > gen[i, PMAX] - ctol) | (gen[i, MU_PMAX] > ptol): fd.write('%9.3f' % gen[i, MU_PMAX]) else: fd.write(' - ') fd.write('\n') ## dispatchable load Q constraints if (not isDC) & ((OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & (any(gen[onld, QG] < gen[onld, QMIN] + ctol) | any(gen[onld, QG] > gen[onld, QMAX] - ctol) | any(gen[onld, MU_QMIN] > ptol) | any(gen[onld, MU_QMAX] > ptol)))): fd.write('\nGen Bus Reactive Power Limits') fd.write('\n # # Qmin mu Qmin Qg Qmax Qmax mu') fd.write('\n--- --- ------- -------- -------- -------- -------') for k in range(len(onld)): i = onld[k] if (OUT_QG_LIM == 2) | ((OUT_QG_LIM == 1) & ((gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMIN] > ptol) | (gen[i, MU_QMAX] > ptol))): fd.write('\n%3d%5d' % (i, gen(i, GEN_BUS))) if (gen[i, QG] < gen[i, QMIN] + ctol) | (gen[i, MU_QMIN] > ptol): fd.write('%8.3f' % gen[i, MU_QMIN]) else: fd.write(' - ') if gen[i, QG]: fd.write('%10.2f%10.2f%10.2f' % gen[i, [QMIN, QG, QMAX]]) else: fd.write('%10.2f - %10.2f' % gen[i, [QMIN, QMAX]]) if (gen[i, QG] > gen[i, QMAX] - ctol) | (gen[i, MU_QMAX] > ptol): fd.write('%9.3f' % gen[i, MU_QMAX]) else: fd.write(' - ') fd.write('\n') ## line flow constraints if (ppopt['OPF_FLOW_LIM'] == 1) | isDC: ## P limit Ff = branch[:, PF] Ft = branch[:, PT] strg = '\n # Bus Pf mu Pf |Pmax| Pt Pt mu Bus' elif ppopt['OPF_FLOW_LIM'] == 2: ## |I| limit Ff = abs( (branch[:, PF] + 1j * branch[:, QF]) / V[e2i[branch[:, F_BUS].astype(int)]] ) Ft = abs( (branch[:, PT] + 1j * branch[:, QT]) / V[e2i[branch[:, T_BUS].astype(int)]] ) strg = '\n # Bus |If| mu |If| |Imax| |It| |It| mu Bus' else: ## |S| limit Ff = abs(branch[:, PF] + 1j * branch[:, QF]) Ft = abs(branch[:, PT] + 1j * branch[:, QT]) strg = '\n # Bus |Sf| mu |Sf| |Smax| |St| |St| mu Bus' if (OUT_LINE_LIM == 2) | ((OUT_LINE_LIM == 1) & (any((branch[:, RATE_A] != 0) & (abs(Ff) > branch[:, RATE_A] - ctol)) | any((branch[:, RATE_A] != 0) & (abs(Ft) > branch[:, RATE_A] - ctol)) | any(branch[:, MU_SF] > ptol) | any(branch[:, MU_ST] > ptol))): fd.write('\n================================================================================') fd.write('\n| Branch Flow Constraints |') fd.write('\n================================================================================') fd.write('\nBrnch From "From" End Limit "To" End To') fd.write(strg) fd.write('\n----- ----- ------- -------- -------- -------- ------- -----') for i in range(nl): if (OUT_LINE_LIM == 2) | ((OUT_LINE_LIM == 1) & (((branch[i, RATE_A] != 0) & (abs(Ff[i]) > branch[i, RATE_A] - ctol)) | ((branch[i, RATE_A] != 0) & (abs(Ft[i]) > branch[i, RATE_A] - ctol)) | (branch[i, MU_SF] > ptol) | (branch[i, MU_ST] > ptol))): fd.write('\n%4d%7d' % (i, branch[i, F_BUS])) if (Ff[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_SF] > ptol): fd.write('%10.3f' % branch[i, MU_SF]) else: fd.write(' - ') fd.write('%9.2f%10.2f%10.2f' % (Ff[i], branch[i, RATE_A], Ft[i])) if (Ft[i] > branch[i, RATE_A] - ctol) | (branch[i, MU_ST] > ptol): fd.write('%10.3f' % branch[i, MU_ST]) else: fd.write(' - ') fd.write('%6d' % branch[i, T_BUS]) fd.write('\n') ## execute userfcn callbacks for 'printpf' stage if have_results_struct & results.has_key('userfcn'): if not isOPF: ## turn off option for all constraints if it isn't an OPF ppopt = ppoption(ppopt, 'OUT_ALL_LIM', 0) run_userfcn(results["userfcn"], 'printpf', results, fd, ppopt)
def 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)