def runopf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs an optimal power flow. @see: L{rundcopf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt) ##----- run the optimal power flow ----- r = opf(casedata, ppopt) ##----- output results ----- if fname: fd = None try: fd = open(fname, "a") except IOError as detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally: if fd is not None: printpf(r, fd, ppopt) fd.close() else: printpf(r, stdout, ppopt) ## save solved case if solvedcase: savecase(solvedcase, r) return r
def _run_bfsw_ppc(ppc, ppopt=None): """ SPARSE version of distribution power flow solution according to [1] :References: [1] Jen-Hao Teng, "A Direct Approach for Distribution System Load Flow Solutions", IEEE Transactions on Power Delivery, vol. 18, no. 3, pp. 882-887, July 2003. :param ppc: matpower-style case data :return: results (pypower style), success (flag about PF convergence) """ ppci = ppc ppopt = ppoption(ppopt) baseMVA, bus, gen, branch = \ ppci["baseMVA"], ppci["bus"], ppci["gen"], ppci["branch"] nbus = bus.shape[0] # get bus index lists of each type of bus ref, pv, pq = bustypes(bus, gen) # depth-first-search bus ordering and generating Direct Load Flow matrix DLF = BCBV * BIBC DLF, ppc_bfsw, buses_ordered_bfsw = bibc_bcbv(ppci) baseMVA_bfsw, bus_bfsw, gen_bfsw, branch_bfsw = \ ppc_bfsw["baseMVA"], ppc_bfsw["bus"], ppc_bfsw["gen"], ppc_bfsw["branch"] time_start = time() # starting pf calculation timing # initialize voltages to flat start and buses with gens to their setpoints V0 = np.ones(nbus, dtype=complex) V0[gen[:, GEN_BUS].astype(int)] = gen[:, VG] Sbus_bfsw = makeSbus(baseMVA_bfsw, bus_bfsw, gen_bfsw) # update data matrices with solution Ybus_bfsw, Yf_bfsw, Yt_bfsw = makeYbus(baseMVA_bfsw, bus_bfsw, branch_bfsw) ## get bus index lists of each type of bus ref_bfsw, pv_bfsw, pq_bfsw = bustypes(bus_bfsw, gen_bfsw) # #----- run the power flow ----- V_final, success = bfsw(DLF, bus_bfsw, gen_bfsw, branch_bfsw, baseMVA_bfsw, Ybus_bfsw, Sbus_bfsw, V0, ref_bfsw, pv_bfsw, pq_bfsw, ppopt=ppopt) V_final = V_final[np.argsort(buses_ordered_bfsw)] # return bus voltages in original bus order # #----- output results to ppc ------ ppci["et"] = time() - time_start # pf time end # generate results for original bus ordering Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V_final, ref, pv, pq) ppci["success"] = success ppci["bus"], ppci["gen"], ppci["branch"] = bus, gen, branch return ppci, success
def __init__(self): self.name = "Stochastic Power Flow" from pypower.ppoption import ppoption opt = ppoption() opt["VERBOSE"] = 0 opt["OUT_ALL"] = 0 self.opt = opt
def _optimal_powerflow(net, verbose, suppress_warnings, **kwargs): ac = net["_options"]["ac"] ppopt = ppoption(VERBOSE=verbose, OPF_FLOW_LIM=2, PF_DC=not ac, **kwargs) net["OPF_converged"] = False net["converged"] = False _add_auxiliary_elements(net) reset_results(net) ppc, ppci = _pd2ppc(net) if not ac: ppci["bus"][:, VM] = 1.0 net["_ppc_opf"] = ppc if len(net.dcline) > 0: ppci = add_userfcn(ppci, 'formulation', _add_dcline_constraints, args=net) if suppress_warnings: with warnings.catch_warnings(): warnings.simplefilter("ignore") result = opf(ppci, ppopt) else: result = opf(ppci, ppopt) net["_ppc_opf"] = result if not result["success"]: raise OPFNotConverged("Optimal Power Flow did not converge!") # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly mode = net["_options"]["mode"] result = _copy_results_ppci_to_ppc(result, ppc, mode=mode) net["_ppc_opf"] = result net["OPF_converged"] = True _extract_results_opf(net, result) _clean_up(net)
def init(): global ppc global ppopt ppc = {"version": '2'} ppc["baseMVA"] = 100.0 ppc["bus"] = np.array([ [1, 3, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [2, 2, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [3, 2, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [4, 1, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [5, 1, 90, 30, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [6, 1, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [7, 1, 100, 35, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [8, 1, 0, 0, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9], [9, 1, 125, 50, 0, 0, 1, 1, 0, 345, 1, 1.1, 0.9] ]) ppc["branch"] = np.array([ [1, 4, 0, 0.0576, 0, 250, 250, 250, 0, 0, 1, -360, 360], [4, 5, 0.017, 0.092, 0.158, 250, 250, 250, 0, 0, 1, -360, 360], [5, 6, 0.039, 0.17, 0.358, 150, 150, 150, 0, 0, 1, -360, 360], [3, 6, 0, 0.0586, 0, 300, 300, 300, 0, 0, 1, -360, 360], [6, 7, 0.0119, 0.1008, 0.209, 150, 150, 150, 0, 0, 1, -360, 360], [7, 8, 0.0085, 0.072, 0.149, 250, 250, 250, 0, 0, 1, -360, 360], [8, 2, 0, 0.0625, 0, 250, 250, 250, 0, 0, 1, -360, 360], [8, 9, 0.032, 0.161, 0.306, 250, 250, 250, 0, 0, 1, -360, 360], [9, 4, 0.01, 0.085, 0.176, 250, 250, 250, 0, 0, 1, -360, 360] ]) ppc["gen"] = np.array([ [1, 0, 0, 300, -300, 1.0, 100, 1, 250, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 163, 0, 300, -300, 1.0, 100, 1, 300, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3, 85, 0, 300, -300, 1.0, 100, 1, 270, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ]) # OPF functions not yet implemented in GUI """ ppc["areas"] = np.array([ [1, 5] ]) ppc["gencost"] = np.array([ [2, 1500, 0, 3, 0.11, 5, 150], [2, 2000, 0, 3, 0.085, 1.2, 600], [2, 3000, 0, 3, 0.1225, 1, 335] ]) """ ppopt = ppoption() global filename filename = "" # Power flow settings global pf_settings pf_settings = {"Qlim": False, "max_iter": 25, "err_tol": 0.00001}
def runuopf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs an optimal power flow with unit-decommitment heuristic. @see: L{rundcopf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt) ##----- run the unit de-commitment / optimal power flow ----- r = uopf(casedata, ppopt) ##----- output results ----- if fname: fd = None try: fd = open(fname, "wb") except Exception as detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally: if fd is not None: printpf(r, fd, ppopt) fd.close() printpf(r, ppopt=ppopt) ## save solved case if solvedcase: savecase(solvedcase, r) return r
def test_to_ppc_and_mpc(): # pypower cases to validate functions = [ 'case4gs', 'case6ww', 'case14', 'case30', 'case24_ieee_rts', 'case39' ] for fn in functions: # get pypower results pypower_module = __import__('pypower.' + fn) pypower_submodule = getattr(pypower_module, fn) pypower_function = getattr(pypower_submodule, fn) ppc_net = pypower_function() # get net from pandapower res_pypower, status_pypower = runpf(ppc_net, ppopt=ppoption(VERBOSE=0, OUT_ALL=0)) pandapower_module = __import__('pandapower', fromlist=['networks']) pandapower_function = getattr(pandapower_module.networks, fn) net = pandapower_function() reset_results(net) # convert to ppc ppc = cv.to_ppc(net) # convert to mpc mpc = cv.to_mpc(net) # runpf from converted ppc res_converted_pp, status_converted_pp = runpf( ppc, ppopt=ppoption(VERBOSE=0, OUT_ALL=0)) if status_converted_pp and status_pypower: # get lookup pp2ppc bus_lookup = net["_pd2ppc_lookups"]["bus"] # check for equality in bus voltages pp_buses = bus_lookup[res_converted_pp['bus'][:, BUS_I].astype(int)] assert np.allclose(res_converted_pp['bus'][pp_buses, VM:VA + 1], res_pypower['bus'][:, VM:VA + 1]) # ToDo: check equality of branch and gen values # pp_gen = bus_lookup[res_converted_pp['bus'][:, BUS_I].astype(int)] # assert np.allclose(res_pypower['gen'][res_pypower['order']['gen']['e2i'], PG:QG+1] # , res_converted_pp['gen'][:, PG:QG+1]) else: raise LoadflowNotConverged("Loadflow did not converge!")
def _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs): """ Gets called by runpp or rundcpp with different arguments. """ net["converged"] = False if (ac and not init == "results") or not ac: reset_results(net) # select elements in service (time consuming, so we do it once) is_elems = _select_is_elements(net) # convert pandapower net to ppc ppc, ppci, bus_lookup = _pd2ppc(net, is_elems, calculate_voltage_angles, enforce_q_lims, trafo_model, init_results=(init == "results")) net["_ppc"] = ppc if not "VERBOSE" in kwargs: kwargs["VERBOSE"] = 0 # run the powerflow with or without warnings. If init='dc', AC PF will be # initialized with DC voltages if suppress_warnings: with warnings.catch_warnings(): warnings.simplefilter("ignore") result = _runpf(ppci, init, ac, Numba, ppopt=ppopt.ppoption(ENFORCE_Q_LIMS=enforce_q_lims, PF_TOL=tolerance_kva * 1e-3, **kwargs))[0] else: result = _runpf(ppci, init, ac, Numba, ppopt=ppopt.ppoption(ENFORCE_Q_LIMS=enforce_q_lims, PF_TOL=tolerance_kva * 1e-3, **kwargs))[0] # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly result = _copy_results_ppci_to_ppc(result, ppc) # raise if PF was not successful. If DC -> success is always 1 if result["success"] != 1: raise LoadflowNotConverged("Loadflow did not converge!") else: net["_ppc"] = result net["converged"] = True _extract_results(net, result, is_elems, bus_lookup, trafo_loading, ac) _clean_up(net)
def _runpppf_dd(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, numba, recycle, **kwargs): """ Gets called by runpp or rundcpp with different arguments. """ net["converged"] = False if (ac and not init == "results") or not ac: reset_results(net) # select elements in service (time consuming, so we do it once) is_elems = _select_is_elements(net, recycle) if recycle["ppc"] and "_ppc" in net and net[ "_ppc"] is not None and "_bus_lookup" in net: # update the ppc from last cycle ppc, ppci, bus_lookup = _update_ppc(net, is_elems, recycle, calculate_voltage_angles, enforce_q_lims, trafo_model) else: # convert pandapower net to ppc ppc, ppci, bus_lookup = _pd2ppc(net, is_elems, calculate_voltage_angles, enforce_q_lims, trafo_model, init_results=(init == "results")) # store variables net["_ppc"] = ppc net["_bus_lookup"] = bus_lookup net["_is_elems"] = is_elems if not "VERBOSE" in kwargs: kwargs["VERBOSE"] = 0 # run the powerflow result = _run_fbsw(ppci, ppopt=ppoption(ENFORCE_Q_LIMS=enforce_q_lims, PF_TOL=tolerance_kva * 1e-3, **kwargs))[0] # ppci doesn't contain out of service elements, but ppc does -> copy results accordingly result = _copy_results_ppci_to_ppc(result, ppc, bus_lookup) # raise if PF was not successful. If DC -> success is always 1 if result["success"] != 1: raise LoadflowNotConverged("Loadflow did not converge!") else: net["_ppc"] = result net["converged"] = True _extract_results(net, result, is_elems, bus_lookup, trafo_loading, ac) _clean_up(net)
def t_makeLODF(quiet=False): """Tests for C{makeLODF}. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ntests = 31 t_begin(ntests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_auction_case') verbose = 0 #not quiet ## load case ppc = loadcase(casefile) ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0) r = rundcopf(ppc, ppopt) baseMVA, bus, gen, branch = r['baseMVA'], r['bus'], r['gen'], r['branch'] _, bus, gen, branch = ext2int1(bus, gen, branch) ## compute injections and flows F0 = branch[:, PF] ## create some PTDF matrices H = makePTDF(baseMVA, bus, branch, 0) ## create some PTDF matrices try: LODF = makeLODF(branch, H) except ZeroDivisionError: pass ## take out non-essential lines one-by-one and see what happens ppc['bus'] = bus ppc['gen'] = gen branch0 = branch outages = r_[arange(12), arange(13, 15), arange(16, 18), [19], arange(26, 33), arange(34, 41)] for k in outages: ppc['branch'] = branch0.copy() ppc['branch'][k, BR_STATUS] = 0 r, _ = rundcpf(ppc, ppopt) baseMVA, bus, gen, branch = \ r['baseMVA'], r['bus'], r['gen'], r['branch'] F = branch[:, PF] t_is(LODF[:, k], (F - F0) / F0[k], 6, 'LODF[:, %d]' % k) t_end()
def rundcpf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs a DC power flow. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt, PF_DC=True) return runpf(casedata, ppopt, fname, solvedcase)
def rundcopf(casedata=None, ppopt=None, fname="", solvedcase=""): """Runs a DC optimal power flow. @see: L{runopf}, L{runduopf} @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), "case9") ppopt = ppoption(ppopt, PF_DC=True) return runopf(casedata, ppopt, fname, solvedcase)
def runduopf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs a DC optimal power flow with unit-decommitment heuristic. @see: L{rundcopf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt, PF_DC=True) return runuopf(casedata, ppopt, fname, solvedcase)
def t_makeLODF(quiet=False): """Tests for C{makeLODF}. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ntests = 31 t_begin(ntests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_auction_case') verbose = 0#not quiet ## load case ppc = loadcase(casefile) ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0) r = rundcopf(ppc, ppopt) baseMVA, bus, gen, branch = r['baseMVA'], r['bus'], r['gen'], r['branch'] _, bus, gen, branch = ext2int1(bus, gen, branch) ## compute injections and flows F0 = branch[:, PF] ## create some PTDF matrices H = makePTDF(baseMVA, bus, branch, 0) ## create some PTDF matrices try: LODF = makeLODF(branch, H) except ZeroDivisionError: pass ## take out non-essential lines one-by-one and see what happens ppc['bus'] = bus ppc['gen'] = gen branch0 = branch outages = r_[arange(12), arange(13, 15), arange(16, 18), [19], arange(26, 33), arange(34, 41)] for k in outages: ppc['branch'] = branch0.copy() ppc['branch'][k, BR_STATUS] = 0 r, _ = rundcpf(ppc, ppopt) baseMVA, bus, gen, branch = \ r['baseMVA'], r['bus'], r['gen'], r['branch'] F = branch[:, PF] t_is(LODF[:, k], (F - F0) / F0[k], 6, 'LODF[:, %d]' % k) t_end()
def dcopf(*args, **kw_args): """Solves a DC optimal power flow. This is a simple wrapper function around L{opf} that sets the C{PF_DC} option to C{True} before calling L{opf}. See L{opf} for the details of input and output arguments. @see: L{rundcopf} @author: Ray Zimmerman (PSERC Cornell) """ ppc, ppopt = opf_args2(*args, **kw_args) ppopt = ppoption(ppopt, PF_DC=1) return opf(ppc, ppopt)
def dcopf(*args, **kw_args): """Solves a DC optimal power flow. This is a simple wrapper function around L{opf} that sets the C{PF_DC} option to C{True} before calling L{opf}. See L{opf} for the details of input and output arguments. @see: L{rundcopf} @author: Ray Zimmerman (PSERC Cornell) """ ppc, ppopt = opf_args2(*args, **kw_args); ppopt = ppoption(ppopt, PF_DC=1) return opf(ppc, ppopt)
def calc_power_flow(case): # we run an opf, but real power output is fixed everywhere except a single quasi-slack bus, # so it just adjusts the voltage setpoints to minimize losses (and hopefully get more # reasonable solutions than a raw power flow) #results = runopf(case) #results = runpf(case, ppopt=ppoption(ENFORCE_Q_LIMS=1))[0] results = runpf(case, ppopt=ppoption(OUT_ALL=0))[0] slack_bus = case["slack_bus"] slack_gens = case["slack_gens"] # add in the extra slack generation introduced by the model, so the results # show the operating state accurately (even if it differs from the proposed state) results["net_injection"][slack_bus] += ( np.sum(results["gen"][slack_gens, PG] - case["gen"][slack_gens, PG]) ) return results
def rundcpf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs a DC power flow. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln Changes by University of Kassel: Different runpf is imported """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt, PF_DC=True) return runpf(casedata, ppopt, fname, solvedcase)
def solve_pf(case, hour=None, results=None, ppopt=None, set_generator_status=False, fname='./runpf.log'): ppopt = ppoption(ppopt) fname = os.path.abspath(fname) baseMVA = case.baseMVA bus = case.bus.copy(deep=True) branch = case.branch.copy(deep=True) gen = case.gen.copy(deep=True) gencost = case.gen.copy(deep=True) if hour is not None: logger.debug("Setting bus load based on case.load") bus['PD'] = case.load.loc[hour] bus = bus.fillna(0) if hour is not None and results is not None: logger.debug("Setting GEN_STATUS and PG") if set_generator_status is True: gen['GEN_STATUS'] = results.unit_commitment.loc[hour].astype(int) gen['PG'] = results.power_generated.loc[hour] value = [i + 1 for i in range(0, len(bus.index))] bus_name = bus.index bus.index = value bus.index = bus.index.astype(int) branch['F_BUS'] = branch['F_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int) branch['T_BUS'] = branch['T_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int) gen['GEN_BUS'] = gen['GEN_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int) bus = np.array(bus.reset_index()) branch = np.array(branch) gen = np.array(gen) gencost = np.array(gencost) casedata = {'baseMVA': baseMVA, 'gencost': gencost, 'gen': gen, 'branch': branch, 'bus': bus} return runpf(casedata, ppopt=ppopt, fname=fname)
def callrunpf(ppc_sol, verbose=0): if ppc_sol['branch'].shape[ 1] > 13: # check if more columns than expected are included branchcopy = ppc_sol['branch'] # create copy of the original branch branch = ppc_sol[ 'branch'][:, 0:13] # copy solution branch data except Pf Qf Pt Qt ppc_sol['branch'] = branch # replace the original branch opt = ppoption(VERBOSE=verbose, OUT_ALL=verbose) # set verbose value (0 by default) r = runpf(ppc_sol, opt) # execute power flow if 'branchcopy' in locals(): # check if branch copy was needed ppc_sol['branch'] = branchcopy # return the original branch # returns the power flow solution struct return r[0]
def draw_network(fignr=754): from matplotlib.pyplot import figure, show import networkx as nx casedata = get_topology() ppc = casedata ppopt = ppoption(PF_ALG=2) ppc = ext2int(ppc) figure(fignr) g = nx.Graph() i = ppc['bus'][:, BUS_I].astype(int) g.add_nodes_from(i, bgcolor='green') #nx.draw_networkx_nodes(g,pos=nx.spring_layout(g)) fr = ppc['branch'][:, F_BUS].astype(int) to = ppc['branch'][:, T_BUS].astype(int) g.add_edges_from(zip(fr, to), color='magenta') nx.draw(g, with_labels=True, node_size=1000,node_color='skyblue',width=0.5) show()
def _get_options(options, **kwargs): init_va_degree = options["init_va_degree"] ac = options["ac"] recycle = options["recycle"] numba = options["numba"] enforce_q_lims = options["enforce_q_lims"] tolerance_kva = options["tolerance_kva"] algorithm = options["algorithm"] max_iteration = options["max_iteration"] # algorithms implemented within pypower algorithm_pypower_dict = {'nr': 1, 'fdbx': 2, 'fdxb': 3, 'gs': 4} ppopt = ppoption(ENFORCE_Q_LIMS=enforce_q_lims, PF_TOL=tolerance_kva * 1e-3, PF_ALG=algorithm_pypower_dict[algorithm], **kwargs) ppopt['PF_MAX_IT'] = max_iteration ppopt['PF_MAX_IT_GS'] = max_iteration ppopt['PF_MAX_IT_FD'] = max_iteration ppopt['VERBOSE'] = 0 return init_va_degree, ac, numba, recycle, ppopt
def draw_network(fignr=754): from matplotlib.pyplot import figure, show import networkx as nx casedata = get_topology() ppc = casedata ppopt = ppoption(PF_ALG=2) ppc = ext2int(ppc) figure(fignr) g = nx.Graph() i = ppc['bus'][:, BUS_I].astype(int) g.add_nodes_from(i, bgcolor='green') #nx.draw_networkx_nodes(g,pos=nx.spring_layout(g)) fr = ppc['branch'][:, F_BUS].astype(int) to = ppc['branch'][:, T_BUS].astype(int) g.add_edges_from(zip(fr, to), color='magenta') nx.draw(g, with_labels=True, node_size=1000, node_color='skyblue', width=0.5) show()
def runopf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs an optimal power flow. @see: L{rundcopf}, L{runuopf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt) ##----- run the optimal power flow ----- r = opf(casedata, ppopt) ##----- output results ----- if fname: fd = None try: fd = open(fname, "wb") except IOError, detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally:
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) """ ##----- 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)
ppopt = ppoption(ppopt) ##----- run the optimal power flow ----- r = opf(casedata, ppopt) ##----- output results ----- if fname: fd = None try: fd = open(fname, "a") except IOError as detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally: if fd is not None: printpf(r, fd, ppopt) fd.close() else: printpf(r, stdout, ppopt) ## save solved case if solvedcase: savecase(solvedcase, r) return r if __name__ == '__main__': ppopt = ppoption(OPF_ALG=580) runopf(None, ppopt)
def run(self, Testsys=case24_ieee_rts(), BETAlimit=0.0017, ITER_max=10000, SIMUNIT=1000): Nb = Testsys["bus"].shape[0] # Load test system,Nb为节点数,Ng为发电机组数,Nl为馈线数 Ng = Testsys["gen"].shape[0] Nl = Testsys["branch"].shape[0] # Set initial value iter = 0 betavalue = float('inf') # The stopping criteria停止迭代的标准 row_index = 0 # Build matrices that have fix dimension to avoid changing size in each loop eqstatus_total = np.zeros( (ITER_max, Ng + Nl + 3)) # 建一个100000*(33+38+3)的矩阵 beta_table = np.zeros((1, ITER_max // SIMUNIT)) # "//"除法得到的才是整数 edns_table = np.zeros((1, ITER_max // SIMUNIT)) # 存放评价指标,大小为1*1000 lole_table = np.zeros((1, ITER_max // SIMUNIT)) plc_table = np.zeros((1, ITER_max // SIMUNIT)) genbus = np.nonzero((Testsys["bus"][:, PD]))[ 0] # 第三列(python中坐标是2)是节点的有功功率,表示节点有有功负荷,此处返回该列非零元素的索引,共有17个元素非零 sizegenbus = genbus.shape[0] # 有负荷的节点数量赋值给sizegenbus Testsys["load"] = sum(Testsys["bus"][:, PD]) # 系统需要的总有功功率 Testsys["gencost"] = np.tile([2, 0, 0, 3, 0, 0, 0], (Ng, 1)) # np.tile建立重复矩阵块(设置机组费用) # treat all load as negtive generator and set their parameters, then add these vitual generators to real gens # 将所有载荷视为负发电机,并设置其参数,然后将这些发电机加到实际的发电机中 loadcost = np.tile([2, 0, 0, 3, 0, 1, 0], (sizegenbus, 1)) # np.tile建立重复矩阵块(负荷的“机组费用”) Testsys["gencost"] = np.append(Testsys["gencost"], loadcost, axis=0) Index = copy.deepcopy(Testsys["gen"][0:sizegenbus, :]) # 将前17台机组的数据取出 Index[:, 0:10] = np.hstack( (Testsys["bus"][genbus, 0].reshape(-1, 1), -Testsys["bus"][genbus, 2].reshape(-1, 1), -Testsys["bus"][genbus, 3].reshape(-1, 1), np.zeros( (sizegenbus, 1)), -Testsys["bus"][genbus, 3].reshape(-1, 1), np.zeros((sizegenbus, 1)), Testsys["baseMVA"] * np.ones( (sizegenbus, 1)), np.ones((sizegenbus, 1)), np.zeros( (sizegenbus, 1)), -Testsys["bus"][genbus, 2].reshape(-1, 1))) # 负荷参数代替取出的机组数据,将负荷套入机组模型,上面矩阵取数注意与matlab相比坐标要减一 Testsys["gen"] = np.append(Testsys["gen"], Index, axis=0) del Index Testsys["bus"][genbus, 2:4] = 0 # 将原来节点中的第3、4列(有功、无功)负荷设为零 totalprob = failprob() # 引用前面定义的函数 ppopt = ppoption( PF_DC=1, VERBOSE=0, OUT_ALL=0, OPF_ALG_DC=200, OPF_FLOW_LIM=1 ) # 可以通过ppoption()采用默认变量来看里面需要什么样的输入,这个按照matlab来输入没问题吧? result = runopf(casedata=Testsys, ppopt=ppopt) while (betavalue > BETAlimit) & (iter < ITER_max): eqstatus_indi = mc_sampling( totalprob, SIMUNIT, Ng, Nl) # eqstatus为元件的状态矩阵,为1表示元件故障,为0表示原件正常 eqstatus_indi = np.hstack( (eqstatus_indi, np.ones((eqstatus_indi.shape[0], 1)), np.zeros((eqstatus_indi.shape[0], 2)))) # 在eqstatus_indi矩阵中加入三列,第一列代表状态重复次数,第二列记载切负荷量大小(没有切负荷则为零),第三列记载是否为容量不足 eqstatus_indi, ia1 = np.unique(eqstatus_indi, axis=0, return_inverse=True) # 找出抽样中的相同结果 for i in range(eqstatus_indi.shape[0]): eqstatus_indi[i, Ng + Nl] = sum(ia1 == i) # 将重复记录次数在第Ng + Nl + 1 if iter: x = 0 y = eqstatus_indi.shape[0] for i in range(y): indi_x = eqstatus_indi[x, 0:Ng + Nl] for j in range(row_index): if (indi_x == eqstatus_total[j, 0:Ng + Nl]).all(): eqstatus_total[j, Ng + Nl] = eqstatus_total[ j, Ng + Nl] + eqstatus_indi[ x, Ng + Nl] # 遇见相同的,就在eqstatus_total的计数中累加次数 eqstatus_indi = np.delete(eqstatus_indi, x, axis=0) x = x - 1 break x = x + 1 parfortemp = np.zeros((eqstatus_indi.shape[0], 2)) para = [0] * eqstatus_indi.shape[0] n_sample = [0] * eqstatus_indi.shape[0] for i in range(eqstatus_indi.shape[0]): para[i] = [0] * 5 para[i][0] = eqstatus_indi[i, 0:Ng + Nl] para[i][1] = Testsys para[i][2] = ppopt para[i][3] = Ng para[i][4] = Nl with Pool(self.n_processors) as p: load_shedding = list(p.map(mc_simulation, para)) parfortemp[:, 0] = np.asarray(load_shedding) parfortemp[:, 1] = (parfortemp[:, 0]) != 0 eqstatus_indi[:, Ng + Nl + 1:Ng + Nl + 3] = parfortemp eqstatus_total[row_index:row_index + eqstatus_indi.shape[0], :] = eqstatus_indi row_index = row_index + eqstatus_indi.shape[0] else: parfortemp = np.zeros((eqstatus_indi.shape[0], 2)) para = [0] * eqstatus_indi.shape[0] c = [0] * eqstatus_indi.shape[0] for i in range(eqstatus_indi.shape[0]): para[i] = [0] * 5 para[i][0] = eqstatus_indi[i, 0:Ng + Nl] para[i][1] = Testsys para[i][2] = ppopt para[i][3] = Ng para[i][4] = Nl with Pool(self.n_processors) as p: load_shedding = list(p.map(mc_simulation, para)) # 计算负荷短缺值 parfortemp[:, 0] = np.asarray(load_shedding) parfortemp[:, 1] = (parfortemp[:, 0]) != 0 # 记录是否负荷短缺 eqstatus_indi[:, Ng + Nl + 1:Ng + Nl + 3] = parfortemp eqstatus_total[row_index:row_index + eqstatus_indi.shape[0], :] = eqstatus_indi row_index = row_index + eqstatus_indi.shape[0] ## Update index edns = sum( eqstatus_total[0:row_index, Ng + Nl] * eqstatus_total[0:row_index, Ng + Nl + 1]) / (iter + SIMUNIT) lole = sum(eqstatus_total[0:row_index, Ng + Nl] * eqstatus_total[0:row_index, Ng + Nl + 2]) / ( iter + SIMUNIT) * 8760 plc = sum( eqstatus_total[0:row_index, Ng + Nl] * eqstatus_total[0:row_index, Ng + Nl + 2]) / (iter + SIMUNIT) betavalue = (sum(eqstatus_total[0:row_index, Ng + Nl] * (eqstatus_total[0:row_index, Ng + Nl + 1] - edns) **2))**0.5 / (iter + SIMUNIT) / edns beta_table[0, ((iter + SIMUNIT) // SIMUNIT) - 1] = betavalue edns_table[0, ((iter + SIMUNIT) // SIMUNIT) - 1] = edns lole_table[0, ((iter + SIMUNIT) // SIMUNIT) - 1] = lole plc_table[0, ((iter + SIMUNIT) // SIMUNIT) - 1] = plc iter = iter + SIMUNIT return edns
def t_opf_userfcns(quiet=False): """Tests for userfcn callbacks (reserves/iflims) w/OPF. Includes high-level tests of reserves and iflims implementations. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ t_begin(38, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case30_userfcns') verbose = 0#not quiet ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8, PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose, OPF_ALG=560, OPF_ALG_DC=200) #ppopt = ppoption(ppopt, OUT_ALL=-1, VERBOSE=2, OUT_GEN=1) ## run the OPF with fixed reserves t = 'fixed reserves : ' ppc = loadcase(casefile) ppc = toggle_reserves(ppc, 'on') r = runopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['reserves']['R'], [25, 15, 0, 0, 19.3906, 0.6094], 4, [t, 'reserves.R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 5.5, 5.5], 4, [t, 'reserves.prc']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0.5, 0], 4, [t, 'reserves.mu.Pmax']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 4, [t, 'reserves.mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0], 4, [t, 'reserves.mu.u']) t_ok('P' not in r['if'], [t, 'no iflims']) t_is(r['reserves']['totalcost'], 177.8047, 4, [t, 'totalcost']) t = 'toggle_reserves(ppc, \'off\') : '; ppc = toggle_reserves(ppc, 'off') r = runopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_ok('R' not in r['reserves'], [t, 'no reserves']) t_ok('P' not in r['if'], [t, 'no iflims']) t = 'interface flow lims (DC) : ' ppc = loadcase(casefile) ppc = toggle_iflims(ppc, 'on') r = rundcopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['if']['P'], [-15, 20], 4, [t, 'if.P']) t_is(r['if']['mu']['l'], [4.8427, 0], 4, [t, 'if.mu.l']) t_is(r['if']['mu']['u'], [0, 13.2573], 4, [t, 'if.mu.u']) t_is(r['branch'][13, PF], 8.244, 3, [t, 'flow in branch 14']) t_ok('R' not in r['reserves'], [t, 'no reserves']) t = 'reserves + interface flow lims (DC) : ' ppc = loadcase(casefile) ppc = toggle_reserves(ppc, 'on') ppc = toggle_iflims(ppc, 'on') r = rundcopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['if']['P'], [-15, 20], 4, [t, 'if.P']) t_is(r['if']['mu']['l'], [4.8427, 0], 4, [t, 'if.mu.l']) t_is(r['if']['mu']['u'], [0, 38.2573], 4, [t, 'if.mu.u']) t_is(r['reserves']['R'], [25, 15, 0, 0, 16.9, 3.1], 4, [t, 'reserves.R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 5.5, 5.5], 4, [t, 'reserves.prc']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0.5, 0], 4, [t, 'reserves.mu.Pmax']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 4, [t, 'reserves.mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0], 4, [t, 'reserves.mu.u']) t_is(r['reserves']['totalcost'], 179.05, 4, [t, 'totalcost']) t = 'interface flow lims (AC) : ' ppc = toggle_reserves(ppc, 'off') r = runopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['if']['P'], [-9.101, 21.432], 3, [t, 'if.P']) t_is(r['if']['mu']['l'], [0, 0], 4, [t, 'if.mu.l']) t_is(r['if']['mu']['u'], [0, 10.198], 3, [t, 'if.mu.u']) t_ok('R' not in r['reserves'], [t, 'no reserves']) t = 'interface flow lims (line out) : ' ppc = loadcase(casefile) ppc = toggle_iflims(ppc, 'on') ppc['branch'][11, BR_STATUS] = 0 ## take out line 6-10 r = rundcopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['if']['P'], [-15, 20], 4, [t, 'if.P']) t_is(r['if']['mu']['l'], [4.8427, 0], 4, [t, 'if.mu.l']) t_is(r['if']['mu']['u'], [0, 13.2573], 4, [t, 'if.mu.u']) t_is(r['branch'][13, PF], 10.814, 3, [t, 'flow in branch 14']) t_ok('R' not in r['reserves'], [t, 'no reserves']) # r['reserves']['R'] # r['reserves']['prc'] # r['reserves']['mu.Pmax'] # r['reserves']['mu']['l'] # r['reserves']['mu']['u'] # r['reserves']['totalcost'] # # r['if']['P'] # r['if']['mu']['l'] # r['if']['mu']['u'] t_end()
def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None): """Solves the power flow using a full Newton's method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see L{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ## default arguments if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0 Va = angle(V) Vm = abs(V) ## set up indexing for updating V pvpq = r_[pv, pq] npv = len(pv) npq = len(pq) j1 = 0; j2 = npv ## j1:j2 - V angle of pv buses j3 = j2; j4 = j2 + npq ## j3:j4 - V angle of pq buses j5 = j4; j6 = j4 + npq ## j5:j6 - V mag of pq buses ## evaluate F(x0) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check tolerance normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n it max P & Q mismatch (p.u.)') sys.stdout.write('\n---- ---------------------------') sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## do Newton iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ## evaluate Jacobian dS_dVm, dS_dVa = dSbus_dV(Ybus, V) J11 = dS_dVa[array([pvpq]).T, pvpq].real J12 = dS_dVm[array([pvpq]).T, pq].real J21 = dS_dVa[array([pq]).T, pvpq].imag J22 = dS_dVm[array([pq]).T, pq].imag J = vstack([ hstack([J11, J12]), hstack([J21, J22]) ], format="csr") ## compute update step dx = -1 * spsolve(J, F) ## update voltage if npv: Va[pv] = Va[pv] + dx[j1:j2] if npq: Va[pq] = Va[pq] + dx[j3:j4] Vm[pq] = Vm[pq] + dx[j5:j6] V = Vm * exp(1j * Va) Vm = abs(V) ## update Vm and Va again in case Va = angle(V) ## we wrapped around with a negative Vm ## evalute F(x) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check for convergence normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose: sys.stdout.write("\nNewton's method power flow converged in " "%d iterations.\n" % i) if verbose: if not converged: sys.stdout.write("\nNewton's method power did not converge in %d " "iterations.\n" % i) return V, converged, i
def t_makePTDF(quiet=False): """Tests for C{makePTDF}. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ ntests = 24 t_begin(ntests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_opf') verbose = 0 #not quiet ## load case ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0) r = rundcopf(casefile, ppopt) baseMVA, bus, gen, branch = r['baseMVA'], r['bus'], r['gen'], r['branch'] _, bus, gen, branch = ext2int1(bus, gen, branch) nb = bus.shape[0] nbr = branch.shape[0] ng = gen.shape[0] ## compute injections and flows Cg = sparse((ones(ng), (gen[:, GEN_BUS], arange(ng))), (nb, ng)) Pg = Cg * gen[:, PG] Pd = bus[:, PD] P = Pg - Pd ig = find(P > 0) il = find(P <= 0) F = branch[:, PF] ## create corresponding slack distribution matrices e1 = zeros((nb, 1)) e1[0] = 1 e4 = zeros((nb, 1)) e4[3] = 1 D1 = eye(nb, nb) - dot(e1, ones((1, nb))) D4 = eye(nb, nb) - dot(e4, ones((1, nb))) Deq = eye(nb, nb) - ones((nb, 1)) / nb * ones((1, nb)) Dg = eye(nb) - matrix(Pd / sum(Pd)).T * ones(nb) Dd = eye(nb) - matrix(Pg / sum(Pg)).T * ones(nb) ## create some PTDF matrices H1 = makePTDF(baseMVA, bus, branch, 0) H4 = makePTDF(baseMVA, bus, branch, 3) Heq = makePTDF(baseMVA, bus, branch, ones(nb)) Hg = makePTDF(baseMVA, bus, branch, Pd) Hd = makePTDF(baseMVA, bus, branch, Pg) ## matrices get properly transformed by slack dist matrices t_is(H1, dot(H1, D1), 8, 'H1 == H1 * D1') t_is(H4, dot(H1, D4), 8, 'H4 == H1 * D4') t_is(Heq, dot(H1, Deq), 8, 'Heq == H1 * Deq') t_is(Hg, dot(H1, Dg), 8, 'Hg == H1 * Dg') t_is(Hd, dot(H1, Dd), 8, 'Hd == H1 * Dd') t_is(H1, dot(Heq, D1), 8, 'H1 == Heq * D1') t_is(H4, dot(Heq, D4), 8, 'H4 == Heq * D4') t_is(Heq, dot(Heq, Deq), 8, 'Heq == Heq * Deq') t_is(Hg, dot(Heq, Dg), 8, 'Hg == Heq * Dg') t_is(Hd, dot(Heq, Dd), 8, 'Hd == Heq * Dd') t_is(H1, dot(Hg, D1), 8, 'H1 == Hg * D1') t_is(H4, dot(Hg, D4), 8, 'H4 == Hg * D4') t_is(Heq, dot(Hg, Deq), 8, 'Heq == Hg * Deq') t_is(Hg, dot(Hg, Dg), 8, 'Hg == Hg * Dg') t_is(Hd, dot(Hg, Dd), 8, 'Hd == Hg * Dd') ## PTDFs can reconstruct flows t_is(F, dot(H1, P), 3, 'Flow == H1 * P') t_is(F, dot(H4, P), 3, 'Flow == H4 * P') t_is(F, dot(Heq, P), 3, 'Flow == Heq * P') t_is(F, dot(Hg, P), 3, 'Flow == Hg * P') t_is(F, dot(Hd, P), 3, 'Flow == Hd * P') ## other t_is(F, dot(Hg, Pg), 3, 'Flow == Hg * Pg') t_is(F, dot(Hd, (-Pd)), 3, 'Flow == Hd * (-Pd)') t_is(zeros(nbr), dot(Hg, (-Pd)), 3, 'zeros == Hg * (-Pd)') t_is(zeros(nbr), dot(Hd, Pg), 3, 'zeros == Hd * Pg') t_end()
def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None): """Solves the power flow using a full Newton's method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see L{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0 Va = angle(V) Vm = abs(V) ## set up indexing for updating V pvpq = r_[pv, pq] npv = len(pv) npq = len(pq) j1 = 0 j2 = npv ## j1:j2 - V angle of pv buses j3 = j2 j4 = j2 + npq ## j3:j4 - V angle of pq buses j5 = j4 j6 = j4 + npq ## j5:j6 - V mag of pq buses ## evaluate F(x0) mis = V * conj(Ybus * V) - Sbus F = r_[mis[pv].real, mis[pq].real, mis[pq].imag] ## check tolerance normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n it max P & Q mismatch (p.u.)') sys.stdout.write('\n---- ---------------------------') sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## do Newton iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ## evaluate Jacobian dS_dVm, dS_dVa = dSbus_dV(Ybus, V) J11 = dS_dVa[array([pvpq]).T, pvpq].real J12 = dS_dVm[array([pvpq]).T, pq].real J21 = dS_dVa[array([pq]).T, pvpq].imag J22 = dS_dVm[array([pq]).T, pq].imag J = vstack([hstack([J11, J12]), hstack([J21, J22])], format="csr") ## compute update step dx = -1 * spsolve(J, F) ## update voltage if npv: Va[pv] = Va[pv] + dx[j1:j2] if npq: Va[pq] = Va[pq] + dx[j3:j4] Vm[pq] = Vm[pq] + dx[j5:j6] V = Vm * exp(1j * Va) Vm = abs(V) ## update Vm and Va again in case Va = angle(V) ## we wrapped around with a negative Vm ## evalute F(x) mis = V * conj(Ybus * V) - Sbus F = r_[mis[pv].real, mis[pq].real, mis[pq].imag] ## check for convergence normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose: sys.stdout.write("\nNewton's method power flow converged in " "%d iterations.\n" % i) if verbose: if not converged: sys.stdout.write("\nNewton's method power did not converge in %d " "iterations.\n" % i) return V, converged, i
def t_opf_ipopt(quiet=False): """Tests for IPOPT-based AC optimal power flow. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ num_tests = 101 t_begin(num_tests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_opf') verbose = 0#not quiet t0 = 'IPOPT : ' ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8, PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose, OPF_ALG=580) ## set up indices ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)] ib_voltage = arange(VM, VA + 1) ib_lam = arange(LAM_P, LAM_Q + 1) ib_mu = arange(MU_VMAX, MU_VMIN + 1) ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)] ig_disp = array([PG, QG, VG]) ig_mu = arange(MU_PMAX, MU_QMIN + 1) ibr_data = arange(ANGMAX + 1) ibr_flow = arange(PF, QT + 1) ibr_mu = array([MU_SF, MU_ST]) ibr_angmu = array([MU_ANGMIN, MU_ANGMAX]) ## get solved AC power flow case from MAT-file soln9_opf = loadmat(join(tdir, 'soln9_opf.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf['bus_soln'] gen_soln = soln9_opf['gen_soln'] branch_soln = soln9_opf['branch_soln'] f_soln = soln9_opf['f_soln'][0] ## run OPF t = t0 r = runopf(casefile, ppopt) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) ## run with automatic conversion of single-block pwl to linear costs t = ''.join([t0, '(single-block PWL) : ']) ppc = loadcase(casefile) ppc['gencost'][2, NCOST] = 2 r = runopf(ppc, ppopt) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) xr = r_[r['var']['val']['Va'], r['var']['val']['Vm'], r['var']['val']['Pg'], r['var']['val']['Qg'], 0, r['var']['val']['y']] t_is(r['x'], xr, 8, [t, 'check on raw x returned from OPF']) ## get solved AC power flow case from MAT-file soln9_opf_Plim = loadmat(join(tdir, 'soln9_opf_Plim.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf_Plim['bus_soln'] gen_soln = soln9_opf_Plim['gen_soln'] branch_soln = soln9_opf_Plim['branch_soln'] f_soln = soln9_opf_Plim['f_soln'][0] ## run OPF with active power line limits t = ''.join([t0, '(P line lim) : ']) ppopt1 = ppoption(ppopt, OPF_FLOW_LIM=1) r = runopf(casefile, ppopt1) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) ##----- test OPF with quadratic gen costs moved to generalized costs ----- ppc = loadcase(casefile) ppc['gencost'] = array([ [2, 1500, 0, 3, 0.11, 5, 0], [2, 2000, 0, 3, 0.085, 1.2, 0], [2, 3000, 0, 3, 0.1225, 1, 0] ]) r = runopf(ppc, ppopt) bus_soln, gen_soln, branch_soln, f_soln, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] branch_soln = branch_soln[:, :MU_ST + 1] A = None l = array([]) u = array([]) nb = ppc['bus'].shape[0] # number of buses ng = ppc['gen'].shape[0] # number of gens thbas = 0; thend = thbas + nb vbas = thend; vend = vbas + nb pgbas = vend; pgend = pgbas + ng # qgbas = pgend; qgend = qgbas + ng nxyz = 2 * nb + 2 * ng N = sparse((ppc['baseMVA'] * ones(ng), (arange(ng), arange(pgbas, pgend))), (ng, nxyz)) fparm = ones((ng, 1)) * array([[1, 0, 0, 1]]) ix = argsort(ppc['gen'][:, 0]) H = 2 * spdiags(ppc['gencost'][ix, 4], 0, ng, ng, 'csr') Cw = ppc['gencost'][ix, 5] ppc['gencost'][:, 4:7] = 0 ## run OPF with quadratic gen costs moved to generalized costs t = ''.join([t0, 'w/quadratic generalized gen cost : ']) r = opf(ppc, A, l, u, ppopt, N, fparm, H, Cw) f, bus, gen, branch, success = \ r['f'], r['bus'], r['gen'], r['branch'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) t_is(r['cost']['usr'], f, 12, [t, 'user cost']) ##----- run OPF with extra linear user constraints & costs ----- ## single new z variable constrained to be greater than or equal to ## deviation from 1 pu voltage at bus 1, linear cost on this z ## get solved AC power flow case from MAT-file soln9_opf_extras1 = loadmat(join(tdir, 'soln9_opf_extras1.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf_extras1['bus_soln'] gen_soln = soln9_opf_extras1['gen_soln'] branch_soln = soln9_opf_extras1['branch_soln'] f_soln = soln9_opf_extras1['f_soln'][0] row = [0, 0, 1, 1] col = [9, 24, 9, 24] A = sparse(([-1, 1, 1, 1], (row, col)), (2, 25)) u = array([Inf, Inf]) l = array([-1, 1]) N = sparse(([1], ([0], [24])), (1, 25)) ## new z variable only fparm = array([[1, 0, 0, 1]]) ## w = r = z H = sparse((1, 1)) ## no quadratic term Cw = array([100.0]) t = ''.join([t0, 'w/extra constraints & costs 1 : ']) r = opf(casefile, A, l, u, ppopt, N, fparm, H, Cw) f, bus, gen, branch, success = \ r['f'], r['bus'], r['gen'], r['branch'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) t_is(r['var']['val']['z'], 0.025419, 6, [t, 'user variable']) t_is(r['cost']['usr'], 2.5419, 4, [t, 'user cost']) ##----- test OPF with capability curves ----- ppc = loadcase(join(tdir, 't_case9_opfv2')) ## remove angle diff limits ppc['branch'][0, ANGMAX] = 360 ppc['branch'][8, ANGMIN] = -360 ## get solved AC power flow case from MAT-file soln9_opf_PQcap = loadmat(join(tdir, 'soln9_opf_PQcap.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf_PQcap['bus_soln'] gen_soln = soln9_opf_PQcap['gen_soln'] branch_soln = soln9_opf_PQcap['branch_soln'] f_soln = soln9_opf_PQcap['f_soln'][0] ## run OPF with capability curves t = ''.join([t0, 'w/capability curves : ']) r = runopf(ppc, ppopt) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) ##----- test OPF with angle difference limits ----- ppc = loadcase(join(tdir, 't_case9_opfv2')) ## remove capability curves ppc['gen'][ix_(arange(1, 3), [PC1, PC2, QC1MIN, QC1MAX, QC2MIN, QC2MAX])] = zeros((2, 6)) ## get solved AC power flow case from MAT-file soln9_opf_ang = loadmat(join(tdir, 'soln9_opf_ang.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf_ang['bus_soln'] gen_soln = soln9_opf_ang['gen_soln'] branch_soln = soln9_opf_ang['branch_soln'] f_soln = soln9_opf_ang['f_soln'][0] ## run OPF with angle difference limits t = ''.join([t0, 'w/angle difference limits : ']) r = runopf(ppc, ppopt) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 1, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) t_is(branch[:, ibr_angmu ], branch_soln[:, ibr_angmu ], 2, [t, 'branch angle mu']) ##----- test OPF with ignored angle difference limits ----- ## get solved AC power flow case from MAT-file soln9_opf = loadmat(join(tdir, 'soln9_opf.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_opf['bus_soln'] gen_soln = soln9_opf['gen_soln'] branch_soln = soln9_opf['branch_soln'] f_soln = soln9_opf['f_soln'][0] ## run OPF with ignored angle difference limits t = ''.join([t0, 'w/ignored angle difference limits : ']) ppopt1 = ppoption(ppopt, OPF_IGNORE_ANG_LIM=1) r = runopf(ppc, ppopt1) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] ## ang limits are not in this solution data, so let's remove them branch[0, ANGMAX] = 360 branch[8, ANGMIN] = -360 t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) t_end()
def runpf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs a power flow. Runs a power flow [full AC Newton's method by default] and optionally returns the solved values in the data matrices, a flag which is C{True} if the algorithm was successful in finding a solution, and the elapsed time in seconds. All input arguments are optional. If C{casename} is provided it specifies the name of the input data file or dict containing the power flow data. The default value is 'case9'. If the ppopt is provided it overrides the default PYPOWER options vector and can be used to specify the solution algorithm and output options among other things. If the 3rd argument is given the pretty printed output will be appended to the file whose name is given in C{fname}. If C{solvedcase} is specified the solved case will be written to a case file in PYPOWER format with the specified name. If C{solvedcase} ends with '.mat' it saves the case as a MAT-file otherwise it saves it as a Python-file. If the C{ENFORCE_Q_LIMS} options is set to C{True} [default is false] then if any generator reactive power limit is violated after running the AC power flow, the corresponding bus is converted to a PQ bus, with Qg at the limit, and the case is re-run. The voltage magnitude at the bus will deviate from the specified value in order to satisfy the reactive power limit. If the reference bus is converted to PQ, the first remaining PV bus will be used as the slack bus for the next iteration. This may result in the real power output at this generator being slightly off from the specified values. Enforcing of generator Q limits inspired by contributions from Mu Lin, Lincoln University, New Zealand (1/14/05). @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt) ## options verbose = ppopt["VERBOSE"] qlim = ppopt["ENFORCE_Q_LIMS"] ## enforce Q limits on gens? dc = ppopt["PF_DC"] ## use DC formulation? ## read data ppc = loadcase(casedata) ## add zero columns to branch for flows if needed if ppc["branch"].shape[1] < QT: ppc["branch"] = c_[ppc["branch"], zeros((ppc["branch"].shape[0], QT - ppc["branch"].shape[1] + 1))] ## convert to internal indexing ppc = ext2int(ppc) baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] ## get bus index lists of each type of bus ref, pv, pq = bustypes(bus, gen) ## generator info on = find(gen[:, GEN_STATUS] > 0) ## which generators are on? gbus = gen[on, GEN_BUS].astype(int) ## what buses are they at? ##----- run the power flow ----- t0 = time() if verbose > 0: v = ppver('all') stdout.write('PYPOWER Version %s, %s' % (v["Version"], v["Date"])) if dc: # DC formulation if verbose: stdout.write(' -- DC Power Flow\n') ## initial state Va0 = bus[:, VA] * (pi / 180) ## build B matrices and phase shift injections B, Bf, Pbusinj, Pfinj = makeBdc(baseMVA, bus, branch) ## compute complex bus power injections [generation - load] ## adjusted for phase shifters and real shunts Pbus = makeSbus(baseMVA, bus, gen).real - Pbusinj - bus[:, GS] / baseMVA ## "run" the power flow Va = dcpf(B, Pbus, Va0, ref, pv, pq) ## update data matrices with solution branch[:, [QF, QT]] = zeros((branch.shape[0], 2)) branch[:, PF] = (Bf * Va + Pfinj) * baseMVA branch[:, PT] = -branch[:, PF] bus[:, VM] = ones(bus.shape[0]) bus[:, VA] = Va * (180 / pi) ## update Pg for slack generator (1st gen at ref bus) ## (note: other gens at ref bus are accounted for in Pbus) ## Pg = Pinj + Pload + Gs ## newPg = oldPg + newPinj - oldPinj refgen = zeros(len(ref), dtype=int) for k in range(len(ref)): temp = find(gbus == ref[k]) refgen[k] = on[temp[0]] gen[refgen, PG] = gen[refgen, PG] + (B[ref, :] * Va - Pbus[ref]) * baseMVA success = 1 else: ## AC formulation alg = ppopt['PF_ALG'] if verbose > 0: if alg == 1: solver = 'Newton' elif alg == 2: solver = 'fast-decoupled, XB' elif alg == 3: solver = 'fast-decoupled, BX' elif alg == 4: solver = 'Gauss-Seidel' else: solver = 'unknown' print(' -- AC Power Flow (%s)\n' % solver) ## initial state # V0 = ones(bus.shape[0]) ## flat start V0 = bus[:, VM] * exp(1j * pi/180 * bus[:, VA]) V0[gbus] = gen[on, VG] / abs(V0[gbus]) * V0[gbus] if qlim: ref0 = ref ## save index and angle of Varef0 = bus[ref0, VA] ## original reference bus(es) limited = [] ## list of indices of gens @ Q lims fixedQg = zeros(gen.shape[0]) ## Qg of gens at Q limits repeat = True while repeat: ## build admittance matrices Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) ## compute complex bus power injections [generation - load] Sbus = makeSbus(baseMVA, bus, gen) ## run the power flow alg = ppopt["PF_ALG"] if alg == 1: V, success, _ = newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt) elif alg == 2 or alg == 3: Bp, Bpp = makeB(baseMVA, bus, branch, alg) V, success, _ = fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, ppopt) elif alg == 4: V, success, _ = gausspf(Ybus, Sbus, V0, ref, pv, pq, ppopt) else: stderr.write('Only Newton''s method, fast-decoupled, and ' 'Gauss-Seidel power flow algorithms currently ' 'implemented.\n') ## update data matrices with solution bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq) if qlim: ## enforce generator Q limits ## find gens with violated Q constraints gen_status = gen[:, GEN_STATUS] > 0 qg_max_lim = gen[:, QG] > gen[:, QMAX] qg_min_lim = gen[:, QG] < gen[:, QMIN] mx = find( gen_status & qg_max_lim ) mn = find( gen_status & qg_min_lim ) if len(mx) > 0 or len(mn) > 0: ## we have some Q limit violations # No PV generators if len(pv) == 0: if verbose: if len(mx) > 0: print('Gen %d [only one left] exceeds upper Q limit : INFEASIBLE PROBLEM\n' % mx + 1) else: print('Gen %d [only one left] exceeds lower Q limit : INFEASIBLE PROBLEM\n' % mn + 1) success = 0 break ## one at a time? if qlim == 2: ## fix largest violation, ignore the rest k = argmax(r_[gen[mx, QG] - gen[mx, QMAX], gen[mn, QMIN] - gen[mn, QG]]) if k > len(mx): mn = mn[k - len(mx)] mx = [] else: mx = mx[k] mn = [] if verbose and len(mx) > 0: for i in range(len(mx)): print('Gen ' + str(mx[i] + 1) + ' at upper Q limit, converting to PQ bus\n') if verbose and len(mn) > 0: for i in range(len(mn)): print('Gen ' + str(mn[i] + 1) + ' at lower Q limit, converting to PQ bus\n') ## save corresponding limit values fixedQg[mx] = gen[mx, QMAX] fixedQg[mn] = gen[mn, QMIN] mx = r_[mx, mn].astype(int) ## convert to PQ bus gen[mx, QG] = fixedQg[mx] ## set Qg to binding for i in range(len(mx)): ## [one at a time, since they may be at same bus] gen[mx[i], GEN_STATUS] = 0 ## temporarily turn off gen, bi = gen[mx[i], GEN_BUS] ## adjust load accordingly, bus[bi, [PD, QD]] = (bus[bi, [PD, QD]] - gen[mx[i], [PG, QG]]) if len(ref) > 1 and any(bus[gen[mx, GEN_BUS], BUS_TYPE] == REF): raise ValueError('Sorry, PYPOWER cannot enforce Q ' 'limits for slack buses in systems ' 'with multiple slacks.') bus[gen[mx, GEN_BUS].astype(int), BUS_TYPE] = PQ ## & set bus type to PQ ## update bus index lists of each type of bus ref_temp = ref ref, pv, pq = bustypes(bus, gen) if verbose and ref != ref_temp: print('Bus %d is new slack bus\n' % ref) limited = r_[limited, mx].astype(int) else: repeat = 0 ## no more generator Q limits violated else: repeat = 0 ## don't enforce generator Q limits, once is enough if qlim and len(limited) > 0: ## restore injections from limited gens [those at Q limits] gen[limited, QG] = fixedQg[limited] ## restore Qg value, for i in range(len(limited)): ## [one at a time, since they may be at same bus] bi = gen[limited[i], GEN_BUS] ## re-adjust load, bus[bi, [PD, QD]] = bus[bi, [PD, QD]] + gen[limited[i], [PG, QG]] gen[limited[i], GEN_STATUS] = 1 ## and turn gen back on if ref != ref0: ## adjust voltage angles to make original ref bus correct bus[:, VA] = bus[:, VA] - bus[ref0, VA] + Varef0 ppc["et"] = time() - t0 ppc["success"] = success ##----- output results ----- ## convert back to original bus numbering & print results ppc["bus"], ppc["gen"], ppc["branch"] = bus, gen, branch results = int2ext(ppc) ## zero out result fields of out-of-service gens & branches if len(results["order"]["gen"]["status"]["off"]) > 0: results["gen"][ix_(results["order"]["gen"]["status"]["off"], [PG, QG])] = 0 if len(results["order"]["branch"]["status"]["off"]) > 0: results["branch"][ix_(results["order"]["branch"]["status"]["off"], [PF, QF, PT, QT])] = 0 if fname: fd = None try: fd = open(fname, "a") except Exception as detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally: if fd is not None: printpf(results, fd, ppopt) fd.close() else: printpf(results, stdout, ppopt) ## save solved case if solvedcase: savecase(solvedcase, results) return results, success
def t_opf_dc_pips(quiet=False): """Tests for DC optimal power flow using PIPS solver. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ num_tests = 23 t_begin(num_tests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_opf') verbose = 0#not quiet t0 = 'DC OPF (PIPS): ' ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0, OPF_ALG_DC=200) ## run DC OPF ## set up indices ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)] ib_voltage = arange(VM, VA + 1) ib_lam = arange(LAM_P, LAM_Q + 1) ib_mu = arange(MU_VMAX, MU_VMIN + 1) ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)] ig_disp = array([PG, QG, VG]) ig_mu = arange(MU_PMAX, MU_QMIN + 1) ibr_data = arange(ANGMAX + 1) ibr_flow = arange(PF, QT + 1) ibr_mu = array([MU_SF, MU_ST]) #ibr_angmu = array([MU_ANGMIN, MU_ANGMAX]) ## get solved DC power flow case from MAT-file soln9_dcopf = loadmat(join(tdir, 'soln9_dcopf.mat'), struct_as_record=True) ## defines bus_soln, gen_soln, branch_soln, f_soln bus_soln = soln9_dcopf['bus_soln'] gen_soln = soln9_dcopf['gen_soln'] branch_soln = soln9_dcopf['branch_soln'] f_soln = soln9_dcopf['f_soln'][0] ## run OPF t = t0 r = rundcopf(casefile, ppopt) bus, gen, branch, f, success = \ r['bus'], r['gen'], r['branch'], r['f'], r['success'] t_ok(success, [t, 'success']) t_is(f, f_soln, 3, [t, 'f']) t_is( bus[:, ib_data ], bus_soln[:, ib_data ], 10, [t, 'bus data']) t_is( bus[:, ib_voltage], bus_soln[:, ib_voltage], 3, [t, 'bus voltage']) t_is( bus[:, ib_lam ], bus_soln[:, ib_lam ], 3, [t, 'bus lambda']) t_is( bus[:, ib_mu ], bus_soln[:, ib_mu ], 2, [t, 'bus mu']) t_is( gen[:, ig_data ], gen_soln[:, ig_data ], 10, [t, 'gen data']) t_is( gen[:, ig_disp ], gen_soln[:, ig_disp ], 3, [t, 'gen dispatch']) t_is( gen[:, ig_mu ], gen_soln[:, ig_mu ], 3, [t, 'gen mu']) t_is(branch[:, ibr_data ], branch_soln[:, ibr_data ], 10, [t, 'branch data']) t_is(branch[:, ibr_flow ], branch_soln[:, ibr_flow ], 3, [t, 'branch flow']) t_is(branch[:, ibr_mu ], branch_soln[:, ibr_mu ], 2, [t, 'branch mu']) ##----- run OPF with extra linear user constraints & costs ----- ## two new z variables ## 0 <= z1, P2 - P1 <= z1 ## 0 <= z2, P2 - P3 <= z2 ## with A and N sized for DC opf ppc = loadcase(casefile) row = [0, 0, 0, 1, 1, 1] col = [9, 10, 12, 10, 11, 13] ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 14)) ppc['u'] = array([0, 0]) ppc['l'] = array([-Inf, -Inf]) ppc['zl'] = array([0, 0]) ppc['N'] = sparse(([1, 1], ([0, 1], [12, 13])), (2, 14)) ## new z variables only ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]]) ## w = r = z ppc['H'] = sparse((2, 2)) ## no quadratic term ppc['Cw'] = array([1000, 1]) t = ''.join([t0, 'w/extra constraints & costs 1 : ']) r = rundcopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974']) t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974']) t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars']) t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs']) ## with A and N sized for AC opf ppc = loadcase(casefile) row = [0, 0, 0, 1, 1, 1] col = [18, 19, 24, 19, 20, 25] ppc['A'] = sparse(([-1, 1, -1, 1, -1, -1], (row, col)), (2, 26)) ppc['u'] = array([0, 0]) ppc['l'] = array([-Inf, -Inf]) ppc['zl'] = array([0, 0]) ppc['N'] = sparse(([1, 1], ([0, 1], [24, 25])), (2, 26)) ## new z variables only ppc['fparm'] = ones((2, 1)) * array([[1, 0, 0, 1]]) ## w = r = z ppc['H'] = sparse((2, 2)) ## no quadratic term ppc['Cw'] = array([1000, 1]) t = ''.join([t0, 'w/extra constraints & costs 2 : ']) r = rundcopf(ppc, ppopt) t_ok(r['success'], [t, 'success']) t_is(r['gen'][0, PG], 116.15974, 4, [t, 'Pg1 = 116.15974']) t_is(r['gen'][1, PG], 116.15974, 4, [t, 'Pg2 = 116.15974']) t_is(r['var']['val']['z'], [0, 0.3348], 4, [t, 'user vars']) t_is(r['cost']['usr'], 0.3348, 3, [t, 'user costs']) t = ''.join([t0, 'infeasible : ']) ## with A and N sized for DC opf ppc = loadcase(casefile) ppc['A'] = sparse(([1, 1], ([0, 0], [9, 10])), (1, 14)) ## Pg1 + Pg2 ppc['u'] = array([Inf]) ppc['l'] = array([600]) r = rundcopf(ppc, ppopt) t_ok(not r['success'], [t, 'no success']) t_end()
def t_runopf_w_res(quiet=False): """Tests C{runopf_w_res} and the associated callbacks. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ t_begin(46, quiet) verbose = 0#not quiet tdir = dirname(__file__) casefile = join(tdir, 't_case30_userfcns') ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8, PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose, OPF_ALG=560) t = 'runopf_w_res(''t_case30_userfcns'') : ' r = runopf_w_res(casefile, ppopt) t_is(r['reserves']['R'], [25, 15, 0, 0, 19.3906, 0.6094], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 5.5, 5.5], 6, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 7, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0], 7, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0.5, 0], 7, [t, 'mu.Pmax']) ppc = loadcase(casefile) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['qty'], ppc['reserves']['qty'], 12, [t, 'qty']) t_is(r['reserves']['totalcost'], 177.8047, 4, [t, 'totalcost']) t = 'gen 5 no reserves : '; ppc = loadcase(casefile) ppc['reserves']['zones'][:, 4] = 0 ppc['reserves']['cost'] = delete(ppc['reserves']['cost'], 4) ppc['reserves']['qty'] = delete(ppc['reserves']['qty'], 4) r = runopf_w_res(ppc, ppopt) t_is(r['reserves']['R'], [25, 15, 0, 0, 0, 20], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 0, 5.5], 6, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 7, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0], 6, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0, 0], 7, [t, 'mu.Pmax']) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['qty'], ppc['reserves']['qty'], 12, [t, 'qty']) t_is(r['reserves']['totalcost'], 187.5, 4, [t, 'totalcost']) t = 'extra offline gen : '; ppc = loadcase(casefile) idx = list(range(3)) + [4] + list(range(3, 6)) ppc['gen'] = ppc['gen'][idx, :] ppc['gencost'] = ppc['gencost'][idx, :] ppc['reserves']['zones'] = ppc['reserves']['zones'][:, idx] ppc['reserves']['cost'] = ppc['reserves']['cost'][idx] ppc['reserves']['qty'] = ppc['reserves']['qty'][idx] ppc['gen'][3, GEN_STATUS] = 0 r = runopf_w_res(ppc, ppopt) t_is(r['reserves']['R'], [25, 15, 0, 0, 0, 19.3906, 0.6094], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 5.5, 2, 5.5, 5.5], 6, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 0, 2, 0, 0], 7, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0, 0], 7, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0, 0.5, 0], 7, [t, 'mu.Pmax']) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['qty'], ppc['reserves']['qty'], 12, [t, 'qty']) t_is(r['reserves']['totalcost'], 177.8047, 4, [t, 'totalcost']) t = 'both extra & gen 6 no res : '; ppc = loadcase(casefile) idx = list(range(3)) + [4] + list(range(3, 6)) ppc['gen'] = ppc['gen'][idx, :] ppc['gencost'] = ppc['gencost'][idx, :] ppc['reserves']['zones'] = ppc['reserves']['zones'][:, idx] ppc['reserves']['cost'] = ppc['reserves']['cost'][idx] ppc['reserves']['qty'] = ppc['reserves']['qty'][idx] ppc['gen'][3, GEN_STATUS] = 0 ppc['reserves']['zones'][:, 5] = 0 ppc['reserves']['cost'] = delete(ppc['reserves']['cost'], 5) ppc['reserves']['qty'] = delete(ppc['reserves']['qty'], 5) r = runopf_w_res(ppc, ppopt) t_is(r['reserves']['R'], [25, 15, 0, 0, 0, 0, 20], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 5.5, 2, 0, 5.5], 6, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 0, 2, 0, 0], 7, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0, 0], 6, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0, 0, 0], 7, [t, 'mu.Pmax']) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['qty'], ppc['reserves']['qty'], 12, [t, 'qty']) t_is(r['reserves']['totalcost'], 187.5, 4, [t, 'totalcost']) t = 'no qty (Rmax) : ' ppc = loadcase(casefile) del ppc['reserves']['qty'] r = runopf_w_res(ppc, ppopt) t_is(r['reserves']['R'], [39.3826, 0.6174, 0, 0, 19.3818, 0.6182], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 5.5, 5.5], 5, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 5, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0, 0, 0, 0, 0, 0], 7, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0.1, 0, 0, 0, 0.5, 0], 5, [t, 'mu.Pmax']) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['totalcost'], 176.3708, 4, [t, 'totalcost']) t = 'RAMP_10, no qty (Rmax) : '; ppc = loadcase(casefile) del ppc['reserves']['qty'] ppc['gen'][0, RAMP_10] = 25 r = runopf_w_res(ppc, ppopt) t_is(r['reserves']['R'], [25, 15, 0, 0, 19.3906, 0.6094], 4, [t, 'R']) t_is(r['reserves']['prc'], [2, 2, 2, 2, 5.5, 5.5], 6, [t, 'prc']) t_is(r['reserves']['mu']['l'], [0, 0, 1, 2, 0, 0], 7, [t, 'mu.l']) t_is(r['reserves']['mu']['u'], [0.1, 0, 0, 0, 0, 0], 7, [t, 'mu.u']) t_is(r['reserves']['mu']['Pmax'], [0, 0, 0, 0, 0.5, 0], 7, [t, 'mu.Pmax']) t_is(r['reserves']['cost'], ppc['reserves']['cost'], 12, [t, 'cost']) t_is(r['reserves']['totalcost'], 177.8047, 4, [t, 'totalcost']) t_end()
def runpf(casedata=None, ppopt=None, fname='', solvedcase=''): """Runs a power flow. Runs a power flow [full AC Newton's method by default] and optionally returns the solved values in the data matrices, a flag which is C{True} if the algorithm was successful in finding a solution, and the elapsed time in seconds. All input arguments are optional. If C{casename} is provided it specifies the name of the input data file or dict containing the power flow data. The default value is 'case9'. If the ppopt is provided it overrides the default PYPOWER options vector and can be used to specify the solution algorithm and output options among other things. If the 3rd argument is given the pretty printed output will be appended to the file whose name is given in C{fname}. If C{solvedcase} is specified the solved case will be written to a case file in PYPOWER format with the specified name. If C{solvedcase} ends with '.mat' it saves the case as a MAT-file otherwise it saves it as a Python-file. If the C{ENFORCE_Q_LIMS} options is set to C{True} [default is false] then if any generator reactive power limit is violated after running the AC power flow, the corresponding bus is converted to a PQ bus, with Qg at the limit, and the case is re-run. The voltage magnitude at the bus will deviate from the specified value in order to satisfy the reactive power limit. If the reference bus is converted to PQ, the first remaining PV bus will be used as the slack bus for the next iteration. This may result in the real power output at this generator being slightly off from the specified values. Enforcing of generator Q limits inspired by contributions from Mu Lin, Lincoln University, New Zealand (1/14/05). @author: Ray Zimmerman (PSERC Cornell) """ ## default arguments if casedata is None: casedata = join(dirname(__file__), 'case9') ppopt = ppoption(ppopt) ## options verbose = ppopt["VERBOSE"] qlim = ppopt["ENFORCE_Q_LIMS"] ## enforce Q limits on gens? dc = ppopt["PF_DC"] ## use DC formulation? ## read data ppc = loadcase(casedata) ## add zero columns to branch for flows if needed if ppc["branch"].shape[1] < QT: ppc["branch"] = c_[ppc["branch"], zeros((ppc["branch"].shape[0], QT - ppc["branch"].shape[1] + 1))] ## convert to internal indexing ppc = ext2int(ppc) baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] ## get bus index lists of each type of bus ref, pv, pq = bustypes(bus, gen) ## generator info on = find(gen[:, GEN_STATUS] > 0) ## which generators are on? gbus = gen[on, GEN_BUS].astype(int) ## what buses are they at? ##----- run the power flow ----- t0 = time() if verbose > 0: v = ppver('all') stdout.write('PYPOWER Version %s, %s' % (v["Version"], v["Date"])) if dc: # DC formulation if verbose: stdout.write(' -- DC Power Flow\n') ## initial state Va0 = bus[:, VA] * (pi / 180) ## build B matrices and phase shift injections B, Bf, Pbusinj, Pfinj = makeBdc(baseMVA, bus, branch) ## compute complex bus power injections [generation - load] ## adjusted for phase shifters and real shunts Pbus = makeSbus(baseMVA, bus, gen).real - Pbusinj - bus[:, GS] / baseMVA ## "run" the power flow Va = dcpf(B, Pbus, Va0, ref, pv, pq) ## update data matrices with solution branch[:, [QF, QT]] = zeros((branch.shape[0], 2)) branch[:, PF] = (Bf * Va + Pfinj) * baseMVA branch[:, PT] = -branch[:, PF] bus[:, VM] = ones(bus.shape[0]) bus[:, VA] = Va * (180 / pi) ## update Pg for slack generator (1st gen at ref bus) ## (note: other gens at ref bus are accounted for in Pbus) ## Pg = Pinj + Pload + Gs ## newPg = oldPg + newPinj - oldPinj refgen = zeros(len(ref), dtype=int) for k in range(len(ref)): temp = find(gbus == ref[k]) refgen[k] = on[temp[0]] gen[refgen, PG] = gen[refgen, PG] + (B[ref, :] * Va - Pbus[ref]) * baseMVA success = 1 else: ## AC formulation alg = ppopt['PF_ALG'] if verbose > 0: if alg == 1: solver = 'Newton' elif alg == 2: solver = 'fast-decoupled, XB' elif alg == 3: solver = 'fast-decoupled, BX' elif alg == 4: solver = 'Gauss-Seidel' else: solver = 'unknown' print(' -- AC Power Flow (%s)\n' % solver) ## initial state # V0 = ones(bus.shape[0]) ## flat start V0 = bus[:, VM] * exp(1j * pi / 180 * bus[:, VA]) V0[gbus] = gen[on, VG] / abs(V0[gbus]) * V0[gbus] if qlim: ref0 = ref ## save index and angle of Varef0 = bus[ref0, VA] ## original reference bus(es) limited = [] ## list of indices of gens @ Q lims fixedQg = zeros(gen.shape[0]) ## Qg of gens at Q limits repeat = True while repeat: ## build admittance matrices Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) ## compute complex bus power injections [generation - load] Sbus = makeSbus(baseMVA, bus, gen) ## run the power flow alg = ppopt["PF_ALG"] if alg == 1: V, success, _ = newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppopt) elif alg == 2 or alg == 3: Bp, Bpp = makeB(baseMVA, bus, branch, alg) V, success, _ = fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, ppopt) elif alg == 4: V, success, _ = gausspf(Ybus, Sbus, V0, ref, pv, pq, ppopt) else: stderr.write('Only Newton' 's method, fast-decoupled, and ' 'Gauss-Seidel power flow algorithms currently ' 'implemented.\n') ## update data matrices with solution bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq) if qlim: ## enforce generator Q limits ## find gens with violated Q constraints gen_status = gen[:, GEN_STATUS] > 0 qg_max_lim = gen[:, QG] > gen[:, QMAX] qg_min_lim = gen[:, QG] < gen[:, QMIN] mx = find(gen_status & qg_max_lim) mn = find(gen_status & qg_min_lim) if len(mx) > 0 or len( mn) > 0: ## we have some Q limit violations # No PV generators if len(pv) == 0: if verbose: if len(mx) > 0: print( 'Gen %d [only one left] exceeds upper Q limit : INFEASIBLE PROBLEM\n' % mx + 1) else: print( 'Gen %d [only one left] exceeds lower Q limit : INFEASIBLE PROBLEM\n' % mn + 1) success = 0 break ## one at a time? if qlim == 2: ## fix largest violation, ignore the rest k = argmax(r_[gen[mx, QG] - gen[mx, QMAX], gen[mn, QMIN] - gen[mn, QG]]) if k > len(mx): mn = mn[k - len(mx)] mx = [] else: mx = mx[k] mn = [] if verbose and len(mx) > 0: for i in range(len(mx)): print('Gen ' + str(mx[i] + 1) + ' at upper Q limit, converting to PQ bus\n') if verbose and len(mn) > 0: for i in range(len(mn)): print('Gen ' + str(mn[i] + 1) + ' at lower Q limit, converting to PQ bus\n') ## save corresponding limit values fixedQg[mx] = gen[mx, QMAX] fixedQg[mn] = gen[mn, QMIN] mx = r_[mx, mn].astype(int) ## convert to PQ bus gen[mx, QG] = fixedQg[mx] ## set Qg to binding for i in range( len(mx) ): ## [one at a time, since they may be at same bus] gen[mx[i], GEN_STATUS] = 0 ## temporarily turn off gen, bi = gen[mx[i], GEN_BUS] ## adjust load accordingly, bus[bi, [PD, QD]] = (bus[bi, [PD, QD]] - gen[mx[i], [PG, QG]]) if len(ref) > 1 and any(bus[gen[mx, GEN_BUS], BUS_TYPE] == REF): raise ValueError('Sorry, PYPOWER cannot enforce Q ' 'limits for slack buses in systems ' 'with multiple slacks.') bus[gen[mx, GEN_BUS].astype(int), BUS_TYPE] = PQ ## & set bus type to PQ ## update bus index lists of each type of bus ref_temp = ref ref, pv, pq = bustypes(bus, gen) if verbose and ref != ref_temp: print('Bus %d is new slack bus\n' % ref) limited = r_[limited, mx].astype(int) else: repeat = 0 ## no more generator Q limits violated else: repeat = 0 ## don't enforce generator Q limits, once is enough if qlim and len(limited) > 0: ## restore injections from limited gens [those at Q limits] gen[limited, QG] = fixedQg[limited] ## restore Qg value, for i in range( len(limited )): ## [one at a time, since they may be at same bus] bi = gen[limited[i], GEN_BUS] ## re-adjust load, bus[bi, [PD, QD]] = bus[bi, [PD, QD]] + gen[limited[i], [PG, QG]] gen[limited[i], GEN_STATUS] = 1 ## and turn gen back on if ref != ref0: ## adjust voltage angles to make original ref bus correct bus[:, VA] = bus[:, VA] - bus[ref0, VA] + Varef0 ppc["et"] = time() - t0 ppc["success"] = success ##----- output results ----- ## convert back to original bus numbering & print results ppc["bus"], ppc["gen"], ppc["branch"] = bus, gen, branch results = int2ext(ppc) ## zero out result fields of out-of-service gens & branches if len(results["order"]["gen"]["status"]["off"]) > 0: results["gen"][ix_(results["order"]["gen"]["status"]["off"], [PG, QG])] = 0 if len(results["order"]["branch"]["status"]["off"]) > 0: results["branch"][ix_(results["order"]["branch"]["status"]["off"], [PF, QF, PT, QT])] = 0 if fname: fd = None try: fd = open(fname, "a") except Exception as detail: stderr.write("Error opening %s: %s.\n" % (fname, detail)) finally: if fd is not None: printpf(results, fd, ppopt) fd.close() else: printpf(results, stdout, ppopt) ## save solved case if solvedcase: savecase(solvedcase, results) return results, success
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 t_runmarket(quiet=False): """Tests for code in C{runmkt}, C{smartmkt} and C{auction}. @author: Ray Zimmerman (PSERC Cornell) """ n_tests = 20 t_begin(n_tests, quiet) try: from pypower.extras.smartmarket import runmarket except ImportError: t_skip(n_tests, 'smartmarket code not available') t_end return ppc = loadcase('t_auction_case') ppopt = ppoption(OPF_ALG=560, OUT_ALL_LIM=1, OUT_BRANCH=0, OUT_SYS_SUM=0) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=1) #ppopt = ppoption(ppopt, OUT_GEN=1, OUT_BRANCH=0, OUT_SYS_SUM=0) offers = {'P': {}, 'Q': {}} bids = {'P': {}, 'Q': {}} offers['P']['qty'] = array([[12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24]]) offers['P']['prc'] = array([[20, 50, 60], [20, 40, 70], [20, 42, 80], [20, 44, 90], [20, 46, 75], [20, 48, 60]]) bids['P']['qty'] = array([[10, 10, 10], [10, 10, 10], [10, 10, 10]]) bids['P']['prc'] = array([ [100, 70, 60], # [100, 64.3, 20], # [100, 30.64545, 0], [100, 50, 20], [100, 60, 50] ]) offers['Q']['qty'] = [60, 60, 60, 60, 60, 60, 0, 0, 0] offers['Q']['prc'] = [0, 0, 0, 0, 0, 3, 0, 0, 0] bids.Q['qty'] = [15, 15, 15, 15, 15, 15, 15, 12, 7.5] # bids.Q['prc'] = [ 0, 0, 0, 0, 0, 0, 0, 83.9056, 0 ] bids.Q['prc'] = [0, 0, 0, 0, 0, 0, 0, 20, 0] t = 'marginal Q offer, marginal PQ bid, auction_type = 5' mkt = {'auction_type': 5, 't': [], 'u0': [], 'lim': []} r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt) co5 = co.copy() cb5 = cb.copy() # [ co['P']['qty'] co['P']['prc'] ] # [ cb['P']['qty'] cb['P']['prc'] ] # [ co['Q']['qty'] co['Q']['prc'] ] # [ cb['Q']['qty'] cb['Q']['prc'] ] i2e = r['bus'][:, BUS_I] e2i = sparse((max(i2e), 1)) e2i[i2e] = list(range(r['bus'].size)) G = find(isload(r['gen']) == 0) ## real generators L = find(isload(r['gen'])) ## dispatchable loads Gbus = e2i[r['gen'][G, GEN_BUS]] Lbus = e2i[r['gen'][L, GEN_BUS]] t_is(co['P']['qty'], ones((6, 1)) * [12, 24, 0], 2, [t, ' : gen P quantities']) t_is(co['P']['prc'][0, :], 50.1578, 3, [t, ' : gen 1 P prices']) t_is(cb['P']['qty'], [[10, 10, 10], [10, 0.196, 0], [10, 10, 0]], 2, [t, ' : load P quantities']) t_is(cb['P']['prc'][1, :], 56.9853, 4, [t, ' : load 2 P price']) t_is(co['P']['prc'][:, 0], r['bus'][Gbus, LAM_P], 8, [t, ' : gen P prices']) t_is(cb['P']['prc'][:, 0], r['bus'][Lbus, LAM_P], 8, [t, ' : load P prices']) t_is(co['Q']['qty'], [4.2722, 11.3723, 14.1472, 22.8939, 36.7886, 12.3375, 0, 0, 0], 2, [t, ' : Q offer quantities']) t_is(co['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q offer prices']) t_is(cb['Q']['qty'], [0, 0, 0, 0, 0, 0, 15, 4.0785, 5], 2, [t, ' : Q bid quantities']) t_is(cb['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q bid prices']) t_is(co['Q']['prc'], r['bus'][[Gbus, Lbus], LAM_Q], 8, [t, ' : Q offer prices']) t_is(cb['Q']['prc'], co['Q']['prc'], 8, [t, ' : Q bid prices']) t = 'marginal Q offer, marginal PQ bid, auction_type = 0' mkt['auction_type'] = 0 r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt) t_is(co['P']['qty'], co5['P']['qty'], 8, [t, ' : gen P quantities']) t_is(cb['P']['qty'], cb5['P']['qty'], 8, [t, ' : load P quantities']) t_is(co['P']['prc'], offers['P']['prc'], 8, [t, ' : gen P prices']) t_is(cb['P']['prc'], bids['P']['prc'], 8, [t, ' : load P prices']) t_is(co['Q']['qty'], co5['Q']['qty'], 8, [t, ' : gen Q quantities']) t_is(cb['Q']['qty'], cb5['Q']['qty'], 8, [t, ' : load Q quantities']) t_is(co['Q']['prc'], offers['Q']['prc'], 8, [t, ' : gen Q prices']) t_is(cb['Q']['prc'], bids['Q']['prc'], 8, [t, ' : load Q prices']) t_end
def t_qps_pypower(quiet=False): """Tests of C{qps_pypower} QP solvers. @author: Ray Zimmerman (PSERC Cornell) """ algs = [200, 250, 400, 500, 600, 700] names = ['PIPS', 'sc-PIPS', 'IPOPT', 'CPLEX', 'MOSEK', 'Gurobi'] check = [None, None, 'ipopt', 'cplex', 'mosek', 'gurobipy'] n = 36 t_begin(n * len(algs), quiet) for k in range(len(algs)): if check[k] is not None and not have_fcn(check[k]): t_skip(n, '%s not installed' % names[k]) else: opt = {'verbose': 0, 'alg': algs[k]} if names[k] == 'PIPS' or names[k] == 'sc-PIPS': opt['pips_opt'] = {} opt['pips_opt']['comptol'] = 1e-8 if names[k] == 'CPLEX': # alg = 0 ## default uses barrier method with NaN bug in lower lim multipliers alg = 2 ## use dual simplex ppopt = ppoption(CPLEX_LPMETHOD = alg, CPLEX_QPMETHOD = min([4, alg])) opt['cplex_opt'] = cplex_options([], ppopt) if names[k] == 'MOSEK': # alg = 5 ## use dual simplex ppopt = ppoption() # ppopt = ppoption(ppopt, MOSEK_LP_ALG = alg) ppopt = ppoption(ppopt, MOSEK_GAP_TOL=1e-9) opt['mosek_opt'] = mosek_options([], ppopt) t = '%s - 3-d LP : ' % names[k] ## example from 'doc linprog' c = array([-5, -4, -6], float) A = sparse([[1, -1, 1], [3, 2, 4], [3, 2, 0]], dtype=float) l = None u = array([20, 42, 30], float) xmin = array([0, 0, 0], float) x0 = None x, f, s, _, lam = qps_pypower(None, c, A, l, u, xmin, None, None, opt) t_is(s, 1, 12, [t, 'success']) t_is(x, [0, 15, 3], 6, [t, 'x']) t_is(f, -78, 6, [t, 'f']) t_is(lam['mu_l'], [0, 0, 0], 13, [t, 'lam.mu_l']) t_is(lam['mu_u'], [0, 1.5, 0.5], 9, [t, 'lam.mu_u']) t_is(lam['lower'], [1, 0, 0], 9, [t, 'lam.lower']) t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper']) t = '%s - unconstrained 3-d quadratic : ' % names[k] ## from http://www.akiti.ca/QuadProgEx0Constr.html H = sparse([ [ 5, -2, -1], [-2, 4, 3], [-1, 3, 5] ], dtype=float) c = array([2, -35, -47], float) x0 = array([0, 0, 0], float) x, f, s, _, lam = qps_pypower(H, c, opt=opt) t_is(s, 1, 12, [t, 'success']) t_is(x, [3, 5, 7], 8, [t, 'x']) t_is(f, -249, 13, [t, 'f']) t_ok(len(lam['mu_l']) == 0, [t, 'lam.mu_l']) t_ok(len(lam['mu_u']) == 0, [t, 'lam.mu_u']) t_is(lam['lower'], zeros(shape(x)), 13, [t, 'lam.lower']) t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper']) t = '%s - constrained 2-d QP : ' % names[k] ## example from 'doc quadprog' H = sparse([[ 1, -1], [-1, 2]], dtype=float) c = array([-2, -6], float) A = sparse([[ 1, 1], [-1, 2], [ 2, 1]], dtype=float) l = None u = array([2, 2, 3], float) xmin = array([0, 0]) x0 = None x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt) t_is(s, 1, 12, [t, 'success']) t_is(x, array([2., 4.]) / 3, 7, [t, 'x']) t_is(f, -74. / 9, 6, [t, 'f']) t_is(lam['mu_l'], [0., 0., 0.], 13, [t, 'lam.mu_l']) t_is(lam['mu_u'], array([28., 4., 0.]) / 9, 7, [t, 'lam.mu_u']) t_is(lam['lower'], zeros(shape(x)), 8, [t, 'lam.lower']) t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper']) t = '%s - constrained 4-d QP : ' % names[k] ## from http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm H = sparse([[1003.1, 4.3, 6.3, 5.9], [4.3, 2.2, 2.1, 3.9], [6.3, 2.1, 3.5, 4.8], [5.9, 3.9, 4.8, 10.0]]) c = zeros(4) A = sparse([[ 1, 1, 1, 1], [0.17, 0.11, 0.10, 0.18]]) l = array([1, 0.10]) u = array([1, Inf]) xmin = zeros(4) x0 = array([1, 0, 0, 1], float) x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt) t_is(s, 1, 12, [t, 'success']) t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x']) t_is(f, 3.29 / 3, 6, [t, 'f']) t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l']) t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u']) t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower']) t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper']) t = '%s - (dict) constrained 4-d QP : ' % names[k] p = {'H': H, 'A': A, 'l': l, 'u': u, 'xmin': xmin, 'x0': x0, 'opt': opt} x, f, s, _, lam = qps_pypower(p) t_is(s, 1, 12, [t, 'success']) t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x']) t_is(f, 3.29 / 3, 6, [t, 'f']) t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l']) t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u']) t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower']) t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper']) t = '%s - infeasible LP : ' % names[k] p = {'A': sparse([1, 1]), 'c': array([1, 1]), 'u': array([-1]), 'xmin': array([0, 0]), 'opt': opt} x, f, s, _, lam = qps_pypower(p) t_ok(s <= 0, [t, 'no success']) t_end()
def t_pf(quiet=False): """Tests for power flow solvers. @author: Ray Zimmerman (PSERC Cornell) """ t_begin(33, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_pf') verbose = not quiet ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0) ## get solved AC power flow case from MAT-file ## defines bus_soln, gen_soln, branch_soln soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False) bus_soln = soln9_pf['bus_soln'] gen_soln = soln9_pf['gen_soln'] branch_soln = soln9_pf['branch_soln'] ## run Newton PF t = 'Newton PF : '; ppopt = ppoption(ppopt, PF_ALG=1) results, success = runpf(casefile, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_ok(success, [t, 'success']) t_is(bus, bus_soln, 6, [t, 'bus']) t_is(gen, gen_soln, 6, [t, 'gen']) t_is(branch, branch_soln, 6, [t, 'branch']) ## run fast-decoupled PF (XB version) t = 'Fast Decoupled (XB) PF : '; ppopt = ppoption(ppopt, PF_ALG=2) results, success = runpf(casefile, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_ok(success, [t, 'success']) t_is(bus, bus_soln, 6, [t, 'bus']) t_is(gen, gen_soln, 6, [t, 'gen']) t_is(branch, branch_soln, 6, [t, 'branch']) ## run fast-decoupled PF (BX version) t = 'Fast Decoupled (BX) PF : '; ppopt = ppoption(ppopt, PF_ALG=3) results, success = runpf(casefile, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_ok(success, [t, 'success']) t_is(bus, bus_soln, 6, [t, 'bus']) t_is(gen, gen_soln, 6, [t, 'gen']) t_is(branch, branch_soln, 6, [t, 'branch']) ## run Gauss-Seidel PF t = 'Gauss-Seidel PF : '; ppopt = ppoption(ppopt, PF_ALG=4) results, success = runpf(casefile, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_ok(success, [t, 'success']) t_is(bus, bus_soln, 5, [t, 'bus']) t_is(gen, gen_soln, 5, [t, 'gen']) t_is(branch, branch_soln, 5, [t, 'branch']) ## get solved AC power flow case from MAT-file ## defines bus_soln, gen_soln, branch_soln soln9_dcpf = loadmat(join(tdir, 'soln9_dcpf.mat'), struct_as_record=False) bus_soln = soln9_dcpf['bus_soln'] gen_soln = soln9_dcpf['gen_soln'] branch_soln = soln9_dcpf['branch_soln'] ## run DC PF t = 'DC PF : ' results, success = rundcpf(casefile, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_ok(success, [t, 'success']) t_is(bus, bus_soln, 6, [t, 'bus']) t_is(gen, gen_soln, 6, [t, 'gen']) t_is(branch, branch_soln, 6, [t, 'branch']) ## check Qg distribution, when Qmin = Qmax t = 'check Qg : ' ppopt = ppoption(ppopt, PF_ALG=1, VERBOSE=0) ppc = loadcase(casefile) ppc['gen'][0, [QMIN, QMAX]] = [20, 20] results, success = runpf(ppc, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_is(gen[0, QG], 24.07, 2, [t, 'single gen, Qmin = Qmax']) ppc['gen'] = r_[array([ ppc['gen'][0, :] ]), ppc['gen']] ppc['gen'][0, [QMIN, QMAX]] = [10, 10] ppc['gen'][1, [QMIN, QMAX]] = [ 0, 50] results, success = runpf(ppc, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_is(gen[0:2, QG], [10, 14.07], 2, [t, '2 gens, Qmin = Qmax for one']) ppc['gen'][0, [QMIN, QMAX]] = [10, 10] ppc['gen'][1, [QMIN, QMAX]] = [-50, -50] results, success = runpf(ppc, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_is(gen[0:2, QG], [12.03, 12.03], 2, [t, '2 gens, Qmin = Qmax for both']) ppc['gen'][0, [QMIN, QMAX]] = [0, 50] ppc['gen'][1, [QMIN, QMAX]] = [0, 100] results, success = runpf(ppc, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_is(gen[0:2, QG], [8.02, 16.05], 2, [t, '2 gens, proportional']) ppc['gen'][0, [QMIN, QMAX]] = [-50, 0] ppc['gen'][1, [QMIN, QMAX]] = [50, 150] results, success = runpf(ppc, ppopt) bus, gen, branch = results['bus'], results['gen'], results['branch'] t_is(gen[0:2, QG], [-50 + 8.02, 50 + 16.05], 2, [t, '2 gens, proportional']) ## network with islands t = 'network w/islands : DC PF : ' ppc0 = loadcase(casefile) ppc0['gen'][0, PG] = 60 ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] = \ ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] / 2 ppc0['gen'] = r_[array([ ppc0['gen'][0, :] ]), ppc0['gen']] ppc1 = ppc0.copy() ppc = ppc0.copy() nb = ppc['bus'].shape[0] ppc1['bus'][:, BUS_I] = ppc1['bus'][:, BUS_I] + nb ppc1['branch'][:, F_BUS] = ppc1['branch'][:, F_BUS] + nb ppc1['branch'][:, T_BUS] = ppc1['branch'][:, T_BUS] + nb ppc1['gen'][:, GEN_BUS] = ppc1['gen'][:, GEN_BUS] + nb ppc['bus'] = r_[ppc['bus'], ppc1['bus']] ppc['branch'] = r_[ppc['branch'], ppc1['branch']] ppc['gen'] = r_[ppc['gen'], ppc1['gen']] #ppopt = ppoption(ppopt, OUT_BUS=1, OUT_GEN=1, OUT_ALL=-1, VERBOSE=2) ppopt = ppoption(ppopt, VERBOSE=verbose) r = rundcpf(ppc, ppopt) t_is(r['bus'][ :9, VA], bus_soln[:, VA], 8, [t, 'voltage angles 1']) t_is(r['bus'][10:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2']) Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]] t_is(r['gen'][ :4, PG], Pg, 8, [t, 'active power generation 1']) t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1']) t = 'network w/islands : AC PF : ' ## get solved AC power flow case from MAT-file soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False) bus_soln = soln9_pf['bus_soln'] gen_soln = soln9_pf['gen_soln'] branch_soln = soln9_pf['branch_soln'] r = runpf(ppc, ppopt) t_is(r['bus'][ :9, VA], bus_soln[:, VA], 8, [t, 'voltage angles 1']) t_is(r['bus'][9:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2']) Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]] t_is(r['gen'][ :4, PG], Pg, 8, [t, 'active power generation 1']) t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1']) t_end()
def _run_fbsw_dense(ppc, ppopt=None): """ DENSE version of distribution power flow solution according to [1] :References: [1] Jen-Hao Teng, "A Direct Approach for Distribution System Load Flow Solutions", IEEE Transactions on Power Delivery, vol. 18, no. 3, pp. 882-887, July 2003. :param ppc: matpower-style case data :return: results (pypower style), success (flag about PF convergence) """ # time_start = time() # path_search = nx.shortest_path # ppci = ext2int(ppc) ppci = ppc ppopt = ppoption(ppopt) baseMVA, bus, gen, branch = \ ppci["baseMVA"], ppci["bus"], ppci["gen"], ppci["branch"] nbus = bus.shape[0] # get bus index lists of each type of bus ref, pv, pq = bustypes(bus, gen) root_bus = ref[ 0] # reference bus is assumed as root bus for a radial network DLF, ppc_fbsw, buses_ordered_fbsw = bibc_bcbv_dense(ppci) baseMVA_fbsw, bus_fbsw, gen_fbsw, branch_fbsw = \ ppc_fbsw["baseMVA"], ppc_fbsw["bus"], ppc_fbsw["gen"], ppc_fbsw["branch"] time_start = time() # initialize voltages to flat start and buses with gens to their setpoints V0 = np.ones(nbus, dtype=complex) V0[gen[:, GEN_BUS].astype(int)] = gen[:, VG] Sbus_fbsw = makeSbus(baseMVA_fbsw, bus_fbsw, gen_fbsw) # update data matrices with solution Ybus_fbsw, Yf_fbsw, Yt_fbsw = makeYbus(baseMVA_fbsw, bus_fbsw, branch_fbsw) ## get bus index lists of each type of bus ref_fbsw, pv_fbsw, pq_fbsw = bustypes(bus_fbsw, gen_fbsw) ##----- run the power flow ----- # ### # LF initialization and calculation V_final, success = fbsw_dense(DLF, bus_fbsw, gen_fbsw, branch_fbsw, baseMVA_fbsw, Ybus_fbsw, Sbus_fbsw, V0, ref_fbsw, pv_fbsw, pq_fbsw, ppopt=ppopt) V_final = V_final[np.argsort( buses_ordered_fbsw)] # return bus voltages in original bus order ppci["et"] = time() - time_start Sbus = makeSbus(baseMVA, bus, gen) # update data matrices with solution Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V_final, ref, pv, pq) ppci["success"] = success ##----- output results ----- ppci["bus"], ppci["gen"], ppci["branch"] = bus, gen, branch results = ppci return results, success
def validate_from_ppc( ppc_net, pp_net, max_diff_values={ "vm_pu": 1e-6, "va_degree": 1e-5, "p_branch_kw": 1e-3, "q_branch_kvar": 1e-3, "p_gen_kw": 1e-3, "q_gen_kvar": 1e-3 }): """ This function validates the pypower case files to pandapower net structure conversion via a \ comparison of loadflow calculations. INPUT: **ppc_net** - The pypower case file. **pp_net** - The pandapower network. OPTIONAL: **max_diff_values** - Dict of maximal allowed difference values. The keys must be 'vm_pu', 'va_degree', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw' and 'q_gen_kvar' and the values floats. OUTPUT: **conversion_success** - conversion_success is returned as False if pypower or pandapower cannot calculate a power flow or if the maximum difference values (max_diff_values ) cannot be hold. EXAMPLE: import pandapower.converter as pc from pypower import case4gs ppc_net = case4gs.case4gs() pp_net = cv.from_ppc(ppc_net, f_hz=60) cv.validate_from_ppc(ppc_net, pp_net) """ # --- run a pypower power flow without print output ppopt = ppoption.ppoption(VERBOSE=0, OUT_ALL=0) ppc_res = runpf.runpf(ppc_net, ppopt)[0] # --- store pypower power flow results ppc_res_branch = ppc_res['branch'][:, 13:17] ppc_res_bus = ppc_res['bus'][:, 7:9] ppc_res_gen = ppc_res['gen'][:, 1:3] # --- try to run a pandapower power flow try: pp.runpp(pp_net, init="dc", calculate_voltage_angles=True, trafo_model="pi") except: try: pp.runpp(pp_net, calculate_voltage_angles=True, init="flat", trafo_model="pi") except: try: pp.runpp(pp_net, trafo_model="pi") except: if (ppc_res['success'] == 1) & (~pp_net.converged): logger.error( 'The validation of ppc conversion fails because the pandapower net' ' power flow does not converge.') elif (ppc_res['success'] != 1) & (pp_net.converged): logger.error( 'The validation of ppc conversion fails because the power flow of ' 'the pypower case does not converge.') elif (ppc_res['success'] != 1) & (~pp_net.converged): logger.error( 'The power flow of both, the pypower case and the pandapower net, ' 'do not converge.') return False # --- prepare power flow result comparison by reordering pp results as they are in ppc results if (ppc_res['success'] == 1) & (pp_net.converged): # --- pandapower bus result table pp_res_bus = array(pp_net.res_bus[['vm_pu', 'va_degree']]) # --- pandapower gen result table pp_res_gen = zeros([1, 2]) # consideration of parallel generators via storing how much generators have been considered # each node already_used_gen = Series(zeros([pp_net.bus.shape[0]]), index=pp_net.bus.index).astype(int) GENS = DataFrame(ppc_res['gen'][:, [0]].astype(int)) change_q_compare = [] for i, j in GENS.iterrows(): current_bus_idx = pp.get_element_index(pp_net, 'bus', name=j[0]) current_bus_type = int(ppc_res['bus'][current_bus_idx, 1]) # ext_grid if current_bus_type == 3: if already_used_gen.at[current_bus_idx] == 0: pp_res_gen = append( pp_res_gen, array(pp_net.res_ext_grid[ pp_net.ext_grid.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape( (1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 else: pp_res_gen = append( pp_res_gen, array(pp_net.res_sgen[ pp_net.sgen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx] - 1].reshape((1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 change_q_compare += [j[0]] # gen elif current_bus_type == 2: pp_res_gen = append( pp_res_gen, array(pp_net.res_gen[pp_net.gen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)), 0) if already_used_gen.at[current_bus_idx] > 0: change_q_compare += [j[0]] already_used_gen.at[current_bus_idx] += 1 # sgen elif current_bus_type == 1: pp_res_gen = append( pp_res_gen, array(pp_net.res_sgen[pp_net.sgen.bus == current_bus_idx][[ 'p_kw', 'q_kvar' ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)), 0) already_used_gen.at[current_bus_idx] += 1 pp_res_gen = pp_res_gen[1:, :] # delete initial zero row # --- pandapower branch result table pp_res_branch = zeros([1, 4]) # consideration of parallel branches via storing how much branches have been considered # each node-to-node-connection init1 = concat([pp_net.line.from_bus, pp_net.line.to_bus], axis=1).drop_duplicates() init2 = concat([pp_net.trafo.hv_bus, pp_net.trafo.lv_bus], axis=1).drop_duplicates() init1['hv_bus'] = nan init1['lv_bus'] = nan init2['from_bus'] = nan init2['to_bus'] = nan already_used_branches = concat([init1, init2], axis=0) already_used_branches['number'] = zeros( [already_used_branches.shape[0], 1]).astype(int) BRANCHES = DataFrame(ppc_res['branch'][:, [0, 1, 8, 9]]) for i in BRANCHES.index: from_bus = pp.get_element_index(pp_net, 'bus', name=int(ppc_res['branch'][i, 0])) to_bus = pp.get_element_index(pp_net, 'bus', name=int(ppc_res['branch'][i, 1])) from_vn_kv = ppc_res['bus'][from_bus, 9] to_vn_kv = ppc_res['bus'][to_bus, 9] ratio = BRANCHES[2].at[i] angle = BRANCHES[3].at[i] # from line results if (from_vn_kv == to_vn_kv) & ((ratio == 0) | (ratio == 1)) & (angle == 0): pp_res_branch = append( pp_res_branch, array( pp_net.res_line[(pp_net.line.from_bus == from_bus) & (pp_net.line.to_bus == to_bus)] [['p_from_kw', 'q_from_kvar', 'p_to_kw', 'q_to_kvar']])[int(already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)] += 1 # from trafo results else: if from_vn_kv >= to_vn_kv: pp_res_branch = append( pp_res_branch, array(pp_net.res_trafo[ (pp_net.trafo.hv_bus == from_bus) & (pp_net.trafo.lv_bus == to_bus)][[ 'p_hv_kw', 'q_hv_kvar', 'p_lv_kw', 'q_lv_kvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)] += 1 else: # switch hv-lv-connection of pypower connection buses pp_res_branch = append( pp_res_branch, array(pp_net.res_trafo[ (pp_net.trafo.hv_bus == to_bus) & (pp_net.trafo.lv_bus == from_bus)][[ 'p_lv_kw', 'q_lv_kvar', 'p_hv_kw', 'q_hv_kvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)] += 1 pp_res_branch = pp_res_branch[1:, :] # delete initial zero row # --- do the power flow result comparison diff_res_bus = ppc_res_bus - pp_res_bus diff_res_branch = ppc_res_branch - pp_res_branch * 1e-3 diff_res_gen = ppc_res_gen + pp_res_gen * 1e-3 # comparison of buses with several generator units only as q sum GEN_uniq = GENS.drop_duplicates() for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index: next_is = GEN_uniq.index[GEN_uniq.index > i] if len(next_is) > 0: next_i = next_is[0] else: next_i = GENS.index[-1] + 1 if (next_i - i) > 1: diff_res_gen[i:next_i, 1] = sum(diff_res_gen[i:next_i, 1]) # logger info logger.debug( "Maximum voltage magnitude difference between pypower and pandapower: " "%.2e pu" % max(abs(diff_res_bus[:, 0]))) logger.debug( "Maximum voltage angle difference between pypower and pandapower: " "%.2e degree" % max(abs(diff_res_bus[:, 1]))) logger.debug( "Maximum branch flow active power difference between pypower and pandapower: " "%.2e kW" % max(abs(diff_res_branch[:, [0, 2]] * 1e3))) logger.debug( "Maximum branch flow reactive power difference between pypower and " "pandapower: %.2e kVAr" % max(abs(diff_res_branch[:, [1, 3]] * 1e3))) logger.debug( "Maximum active power generation difference between pypower and pandapower: " "%.2e kW" % max(abs(diff_res_gen[:, 0] * 1e3))) logger.debug( "Maximum reactive power generation difference between pypower and pandapower: " "%.2e kVAr" % max(abs(diff_res_gen[:, 1] * 1e3))) if (max(abs(diff_res_bus[:, 0])) < 1e-3) & (max(abs(diff_res_bus[:, 1])) < 1e-3) & \ (max(abs(diff_res_branch[:, [0, 2]])) < 1e-3) & \ (max(abs(diff_res_branch[:, [1, 3]])) < 1e-3) & \ (max(abs(diff_res_gen)) > 1e-1).any(): logger.debug( "The active/reactive power generation difference possibly results " "because of a pypower error. Please validate " "the results via pypower loadflow." ) # this occurs e.g. at ppc case9 # give a return if type(max_diff_values) == dict: if Series([ 'q_gen_kvar', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw', 'va_degree', 'vm_pu' ]).isin(Series(list(max_diff_values.keys()))).all(): if (max(abs(diff_res_bus[:, 0])) < max_diff_values['vm_pu']) & \ (max(abs(diff_res_bus[:, 1])) < max_diff_values['va_degree']) & \ (max(abs(diff_res_branch[:, [0, 2]])) < max_diff_values['p_branch_kw'] / 1e3) & \ (max(abs(diff_res_branch[:, [1, 3]])) < max_diff_values['q_branch_kvar'] / 1e3) & \ (max(abs(diff_res_gen[:, 0])) < max_diff_values['p_gen_kw'] / 1e3) & \ (max(abs(diff_res_gen[:, 1])) < max_diff_values['q_gen_kvar'] / 1e3): return True else: return False else: logger.debug('Not all requried dict keys are provided.') else: logger.debug("'max_diff_values' must be a dict.")
def t_dcline(quiet=False): """Tests for DC line extension in L{{toggle_dcline}. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ num_tests = 50 t_begin(num_tests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_dcline') if quiet: verbose = False else: verbose = False t0 = '' ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8, PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9) ppopt = ppoption(ppopt, OPF_ALG=560, OPF_ALG_DC=200) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose) ## set up indices ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)] ib_voltage = arange(VM, VA + 1) ib_lam = arange(LAM_P, LAM_Q + 1) ib_mu = arange(MU_VMAX, MU_VMIN + 1) ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)] ig_disp = array([PG, QG, VG]) ig_mu = arange(MU_PMAX, MU_QMIN + 1) ibr_data = arange(ANGMAX + 1) ibr_flow = arange(PF, QT + 1) ibr_mu = array([MU_SF, MU_ST]) ibr_angmu = array([MU_ANGMIN, MU_ANGMAX]) ## load case ppc0 = loadcase(casefile) del ppc0['dclinecost'] ppc = ppc0 ppc = toggle_dcline(ppc, 'on') ppc = toggle_dcline(ppc, 'off') ndc = ppc['dcline'].shape[0] ## run AC OPF w/o DC lines t = ''.join([t0, 'AC OPF (no DC lines) : ']) r0 = runopf(ppc0, ppopt) success = r0['success'] t_ok(success, [t, 'success']) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['f'], r0['f'], 8, [t, 'f']) t_is( r['bus'][:,ib_data ], r0['bus'][:,ib_data ], 10, [t, 'bus data']) t_is( r['bus'][:,ib_voltage], r0['bus'][:,ib_voltage], 3, [t, 'bus voltage']) t_is( r['bus'][:,ib_lam ], r0['bus'][:,ib_lam ], 3, [t, 'bus lambda']) t_is( r['bus'][:,ib_mu ], r0['bus'][:,ib_mu ], 2, [t, 'bus mu']) t_is( r['gen'][:,ig_data ], r0['gen'][:,ig_data ], 10, [t, 'gen data']) t_is( r['gen'][:,ig_disp ], r0['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is( r['gen'][:,ig_mu ], r0['gen'][:,ig_mu ], 3, [t, 'gen mu']) t_is(r['branch'][:,ibr_data ], r0['branch'][:,ibr_data ], 10, [t, 'branch data']) t_is(r['branch'][:,ibr_flow ], r0['branch'][:,ibr_flow ], 3, [t, 'branch flow']) t_is(r['branch'][:,ibr_mu ], r0['branch'][:,ibr_mu ], 2, [t, 'branch mu']) t = ''.join([t0, 'AC PF (no DC lines) : ']) ppc1 = {'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()} ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is( rp['bus'][:,ib_voltage], r['bus'][:,ib_voltage], 3, [t, 'bus voltage']) t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is(rp['branch'][:,ibr_flow ], r['branch'][:,ibr_flow ], 3, [t, 'branch flow']) ## run with DC lines t = ''.join([t0, 'AC OPF (with DC lines) : ']) ppc = toggle_dcline(ppc, 'on') r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected = array([ [10, 8.9, -10, 10, 1.0674, 1.0935], [2.2776, 2.2776, 0, 0, 1.0818, 1.0665], [0, 0, 0, 0, 1.0000, 1.0000], [10, 9.5, 0.0563, -10, 1.0778, 1.0665] ]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V']) expected = array([ [0, 0.8490, 0.6165, 0, 0, 0.2938], [0, 0, 0, 0.4290, 0.0739, 0], [0, 0, 0, 0, 0, 0], [0, 7.2209, 0, 0, 0.0739, 0] ]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu']) t = ''.join([t0, 'AC PF (with DC lines) : ']) ppc1 = {'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()} ppc1 = toggle_dcline(ppc1, 'on') ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is( rp['bus'][:,ib_voltage], r['bus'][:,ib_voltage], 3, [t, 'bus voltage']) #t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is( rp['gen'][:2,ig_disp ], r['gen'][:2,ig_disp ], 3, [t, 'gen dispatch']) t_is( rp['gen'][2,PG ], r['gen'][2,PG ], 3, [t, 'gen dispatch']) t_is( rp['gen'][2,QG]+rp['dcline'][0,c.QF], r['gen'][2,QG]+r['dcline'][0,c.QF], 3, [t, 'gen dispatch']) t_is(rp['branch'][:,ibr_flow ], r['branch'][:,ibr_flow ], 3, [t, 'branch flow']) ## add appropriate P and Q injections and check angles and generation when running PF t = ''.join([t0, 'AC PF (with equivalent injections) : ']) ppc1 = {'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()} ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 for k in range(ndc): if ppc1['dcline'][k, c.BR_STATUS]: ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS]) tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS]) ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF] ppc1['bus'][ff, QD] = ppc1['bus'][ff, QD] - r['dcline'][k, c.QF] ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT] ppc1['bus'][tt, QD] = ppc1['bus'][tt, QD] - r['dcline'][k, c.QT] ppc1['bus'][ff, VM] = r['dcline'][k, c.VF] ppc1['bus'][tt, VM] = r['dcline'][k, c.VT] ppc1['bus'][ff, BUS_TYPE] = PV ppc1['bus'][tt, BUS_TYPE] = PV rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is( rp['bus'][:,ib_voltage], r['bus'][:,ib_voltage], 3, [t, 'bus voltage']) t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is(rp['branch'][:,ibr_flow ], r['branch'][:,ibr_flow ], 3, [t, 'branch flow']) ## test DC OPF t = ''.join([t0, 'DC OPF (with DC lines) : ']) ppc = ppc0.copy() ppc['gen'][0, PMIN] = 10 ppc['branch'][4, RATE_A] = 100 ppc = toggle_dcline(ppc, 'on') r = rundcopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected = array([ [10, 8.9, 0, 0, 1.01, 1], [2, 2, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1], [10, 9.5, 0, 0, 1, 0.98] ]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V']) expected = array([ [0, 1.8602, 0, 0, 0, 0], [1.8507, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0.2681, 0, 0, 0, 0] ]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu']) t = ''.join([t0, 'DC PF (with DC lines) : ']) ppc1 = {'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()} ppc1 = toggle_dcline(ppc1, 'on') ppc1['bus'][:, VA] = 0 rp = rundcpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is( rp['bus'][:,ib_voltage], r['bus'][:,ib_voltage], 3, [t, 'bus voltage']) t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is(rp['branch'][:,ibr_flow ], r['branch'][:,ibr_flow ], 3, [t, 'branch flow']) ## add appropriate P injections and check angles and generation when running PF t = ''.join([t0, 'DC PF (with equivalent injections) : ']) ppc1 = {'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()} ppc1['bus'][:, VA] = 0 for k in range(ndc): if ppc1['dcline'][k, c.BR_STATUS]: ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS]) tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS]) ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF] ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT] ppc1['bus'][ff, BUS_TYPE] = PV ppc1['bus'][tt, BUS_TYPE] = PV rp = rundcpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is( rp['bus'][:,ib_voltage], r['bus'][:,ib_voltage], 3, [t, 'bus voltage']) t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is(rp['branch'][:,ibr_flow ], r['branch'][:,ibr_flow ], 3, [t, 'branch flow']) ## run with DC lines t = ''.join([t0, 'AC OPF (with DC lines + poly cost) : ']) ppc = loadcase(casefile) ppc = toggle_dcline(ppc, 'on') r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected1 = array([ [10, 8.9, -10, 10, 1.0663, 1.0936], [7.8429, 7.8429, 0, 0, 1.0809, 1.0667], [0, 0, 0, 0, 1.0000, 1.0000], [6.0549, 5.7522, -0.5897, -10, 1.0778, 1.0667] ]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) expected2 = array([ [0, 0.7605, 0.6226, 0, 0, 0.2980], [0, 0, 0, 0.4275, 0.0792, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0.0792, 0] ]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) ppc['dclinecost'][3, :8] = array([2, 0, 0, 4, 0, 0, 7.3, 0]) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) t = ''.join([t0, 'AC OPF (with DC lines + pwl cost) : ']) ppc['dclinecost'][3, :8] = array([1, 0, 0, 2, 0, 0, 10, 73]) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) t_end()
def opf_args(*args): """Parses and initializes OPF input arguments. Returns the full set of initialized OPF input arguments, filling in default values for missing arguments. See Examples below for the possible calling syntax options. Input arguments options:: opf_args(ppc) opf_args(ppc, ppopt) opf_args(ppc, userfcn, ppopt) opf_args(ppc, A, l, u) opf_args(ppc, A, l, u, ppopt) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw) opf_args(ppc, A, l, u, ppopt, N, fparm, H, Cw, z0, zl, zu) opf_args(baseMVA, bus, gen, branch, areas, gencost) opf_args(baseMVA, bus, gen, branch, areas, gencost, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ppopt) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw) opf_args(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... ppopt, N, fparm, H, Cw, z0, zl, zu) The data for the problem can be specified in one of three ways: 1. a string (ppc) containing the file name of a PYPOWER case which defines the data matrices baseMVA, bus, gen, branch, and gencost (areas is not used at all, it is only included for backward compatibility of the API). 2. a dict (ppc) containing the data matrices as fields. 3. the individual data matrices themselves. The optional user parameters for user constraints (C{A, l, u}), user costs (C{N, fparm, H, Cw}), user variable initializer (z0), and user variable limits (C{zl, zu}) can also be specified as fields in a case dict, either passed in directly or defined in a case file referenced by name. When specified, C{A, l, u} represent additional linear constraints on the optimization variables, C{l <= A*[x z] <= u}. If the user specifies an C{A} matrix that has more columns than the number of "C{x}" (OPF) variables, then there are extra linearly constrained "C{z}" variables. For an explanation of the formulation used and instructions for forming the C{A} matrix, see the MATPOWER manual. A generalized cost on all variables can be applied if input arguments C{N}, C{fparm}, C{H} and C{Cw} are specified. First, a linear transformation of the optimization variables is defined by means of C{r = N * [x z]}. Then, to each element of r a function is applied as encoded in the C{fparm} matrix (see Matpower manual). If the resulting vector is named C{w}, then C{H} and C{Cw} define a quadratic cost on C{w}: C{(1/2)*w'*H*w + Cw * w}. C{H} and C{N} should be sparse matrices and C{H} should also be symmetric. The optional C{ppopt} vector specifies PYPOWER options. See L{ppoption} for details and default values. @author: Ray Zimmerman (PSERC Cornell) @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad Autonoma de Manizales) @author: Richard Lincoln """ # nargin = len([arg for arg in [baseMVA, bus, gen, branch, areas, gencost, # Au, lbu, ubu, ppopt, N, fparm, H, Cw, # z0, zl, zu] if arg is not None]) nargin = len(args) userfcn = array([]) ## passing filename or dict if isinstance(args[0], basestring) or isinstance(args[0], dict): # ----opf( baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 12 opf(casefile, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 9 opf(casefile, Au, lbu, ubu, ppopt, N, fparm, H, Cw) # 5 opf(casefile, Au, lbu, ubu, ppopt) # 4 opf(casefile, Au, lbu, ubu) # 3 opf(casefile, userfcn, ppopt) # 2 opf(casefile, ppopt) # 1 opf(casefile) if nargin in [1, 2, 3, 4, 5, 9, 12]: casefile = args[0] if nargin == 12: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm = args zu = fparm zl = N z0 = ppopt Cw = ubu H = lbu fparm = Au N = gencost ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 9: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu = args zu = array([]) zl = array([]) z0 = array([]) Cw = ubu H = lbu fparm = Au N = gencost ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 5: baseMVA, bus, gen, branch, areas = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = areas ubu = branch lbu = gen Au = bus elif nargin == 4: baseMVA, bus, gen, branch = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = branch lbu = gen Au = bus elif nargin == 3: baseMVA, bus, gen = args userfcn = bus zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = gen ubu = array([]) lbu = array([]) Au = None elif nargin == 2: baseMVA, bus = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = bus ubu = array([]) lbu = array([]) Au = None elif nargin == 1: zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = array([]) lbu = array([]) Au = None else: stderr.write('opf_args: Incorrect input arg order, number or type\n') ppc = loadcase(casefile) baseMVA, bus, gen, branch, gencost = \ ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch'], ppc['gencost'] if 'areas' in ppc: areas = ppc['areas'] else: areas = array([]) if Au is None and 'A' in ppc: Au, lbu, ubu = ppc["A"], ppc["l"], ppc["u"] if N is None and 'N' in ppc: ## these two must go together N, Cw = ppc["N"], ppc["Cw"] if H is None and 'H' in ppc: ## will default to zeros H = ppc["H"] if (fparm is None or len(fparm) == 0) and 'fparm' in ppc: ## will default to [1 0 0 1] fparm = ppc["fparm"] if (z0 is None or len(z0) == 0) and 'z0' in ppc: z0 = ppc["z0"] if (zl is None or len(zl) == 0) and 'zl' in ppc: zl = ppc["zl"] if (zu is None or len(zu) == 0) and 'zu' in ppc: zu = ppc["zu"] if (userfcn is None or len(userfcn) == 0) and 'userfcn' in ppc: userfcn = ppc['userfcn'] else: ## passing individual data matrices # ----opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 17 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu) # 14 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw) # 10 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt) # 9 opf(baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu) # 8 opf(baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt) # 7 opf(baseMVA, bus, gen, branch, areas, gencost, ppopt) # 6 opf(baseMVA, bus, gen, branch, areas, gencost) if nargin in [6, 7, 8, 9, 10, 14, 17]: if nargin == 17: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw, z0, zl, zu = args elif nargin == 14: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt, N, fparm, H, Cw = args zu = array([]) zl = array([]) z0 = array([]) elif nargin == 10: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None elif nargin == 9: baseMVA, bus, gen, branch, areas, gencost, Au, lbu, ubu = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() elif nargin == 8: baseMVA, bus, gen, branch, areas, gencost, userfcn, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ubu = array([]) lbu = array([]) Au = None elif nargin == 7: baseMVA, bus, gen, branch, areas, gencost, ppopt = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ubu = array([]) lbu = array([]) Au = None elif nargin == 6: baseMVA, bus, gen, branch, areas, gencost = args zu = array([]) zl = array([]) z0 = array([]) Cw = array([]) H = None fparm = array([]) N = None ppopt = ppoption() ubu = array([]) lbu = array([]) Au = None else: stderr.write('opf_args: Incorrect input arg order, number or type\n') if N is not None: nw = N.shape[0] else: nw = 0 if nw: if Cw.shape[0] != nw: stderr.write('opf_args.m: dimension mismatch between N and Cw in ' 'generalized cost parameters\n') if len(fparm) > 0 and fparm.shape[0] != nw: stderr.write('opf_args.m: dimension mismatch between N and fparm ' 'in generalized cost parameters\n') if (H is not None) and (H.shape[0] != nw | H.shape[0] != nw): stderr.write('opf_args.m: dimension mismatch between N and H in ' 'generalized cost parameters\n') if Au is not None: if Au.shape[0] > 0 and N.shape[1] != Au.shape[1]: stderr.write('opf_args.m: A and N must have the same number ' 'of columns\n') ## make sure N and H are sparse if not issparse(N): stderr.write('opf_args.m: N must be sparse in generalized cost ' 'parameters\n') if not issparse(H): stderr.write('opf_args.m: H must be sparse in generalized cost parameters\n') if Au is not None and not issparse(Au): stderr.write('opf_args.m: Au must be sparse\n') if ppopt == None or len(ppopt) == 0: ppopt = ppoption() return baseMVA, bus, gen, branch, gencost, Au, lbu, ubu, \ ppopt, N, fparm, H, Cw, z0, zl, zu, userfcn, areas
def 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 gausspf(Ybus, Sbus, V0, ref, pv, pq, ppopt=None): """Solves the power flow using a Gauss-Seidel method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see C{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) @author: Alberto Borghetti (University of Bologna, Italy) """ ## default arguments if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT_GS'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0.copy() #Va = angle(V) Vm = abs(V) ## set up indexing for updating V npv = len(pv) npq = len(pq) pvpq = r_[pv, pq] ## evaluate F(x0) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pvpq].real, mis[pq].imag ] ## check tolerance normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n it max P & Q mismatch (p.u.)') sys.stdout.write('\n---- ---------------------------') sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## do Gauss-Seidel iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ## update voltage ## at PQ buses for k in pq[list(range(npq))]: tmp = (conj(Sbus[k] / V[k]) - Ybus[k, :] * V) / Ybus[k, k] V[k] = V[k] + asscalar(tmp) ## at PV buses if npv: for k in pv[list(range(npv))]: tmp = (V[k] * conj(Ybus[k,:] * V)).imag Sbus[k] = Sbus[k].real + 1j * asscalar(tmp) tmp = (conj(Sbus[k] / V[k]) - Ybus[k, :] * V) / Ybus[k, k] V[k] = V[k] + asscalar(tmp) # V[k] = Vm[k] * V[k] / abs(V[k]) V[pv] = Vm[pv] * V[pv] / abs(V[pv]) ## evalute F(x) mis = V * conj(Ybus * V) - Sbus F = r_[ mis[pv].real, mis[pq].real, mis[pq].imag ] ## check for convergence normF = linalg.norm(F, Inf) if verbose > 1: sys.stdout.write('\n%3d %10.3e' % (i, normF)) if normF < tol: converged = 1 if verbose: sys.stdout.write('\nGauss-Seidel power flow converged in ' '%d iterations.\n' % i) if verbose: if not converged: sys.stdout.write('Gauss-Seidel power did not converge in %d ' 'iterations.' % i) return V, converged, i
def t_hessian(quiet=False): """Numerical tests of 2nd derivative code. @author: Ray Zimmerman (PSERC Cornell) """ t_begin(44, quiet) ## run powerflow to get solved case ppopt = ppoption(VERBOSE=0, OUT_ALL=0) results, _ = runpf(case30(), ppopt) baseMVA, bus, gen, branch = \ results['baseMVA'], results['bus'], results['gen'], results['branch'] ## switch to internal bus numbering and build admittance matrices _, bus, gen, branch = ext2int1(bus, gen, branch) Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) Vm = bus[:, VM] Va = bus[:, VA] * (pi / 180) V = Vm * exp(1j * Va) f = branch[:, F_BUS] ## list of "from" buses t = branch[:, T_BUS] ## list of "to" buses nl = len(f) nb = len(V) Cf = sparse((ones(nl), (range(nl), f)), (nl, nb)) ## connection matrix for line & from buses Ct = sparse((ones(nl), (range(nl), t)), (nl, nb)) ## connection matrix for line & to buses pert = 1e-8 ##----- check d2Sbus_dV2 code ----- t = ' - d2Sbus_dV2 (complex power injections)' lam = 10 * random.rand(nb) num_Haa = zeros((nb, nb), complex) num_Hav = zeros((nb, nb), complex) num_Hva = zeros((nb, nb), complex) num_Hvv = zeros((nb, nb), complex) dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V) Haa, Hav, Hva, Hvv = d2Sbus_dV2(Ybus, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dSbus_dVm_ap, dSbus_dVa_ap = dSbus_dV(Ybus, Vap) num_Haa[:, i] = (dSbus_dVa_ap - dSbus_dVa).T * lam / pert num_Hva[:, i] = (dSbus_dVm_ap - dSbus_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dSbus_dVm_mp, dSbus_dVa_mp = dSbus_dV(Ybus, Vmp) num_Hav[:, i] = (dSbus_dVa_mp - dSbus_dVa).T * lam / pert num_Hvv[:, i] = (dSbus_dVm_mp - dSbus_dVm).T * lam / pert t_is(Haa.todense(), num_Haa, 4, ['Haa', t]) t_is(Hav.todense(), num_Hav, 4, ['Hav', t]) t_is(Hva.todense(), num_Hva, 4, ['Hva', t]) t_is(Hvv.todense(), num_Hvv, 4, ['Hvv', t]) ##----- check d2Sbr_dV2 code ----- t = ' - d2Sbr_dV2 (complex power flows)' lam = 10 * random.rand(nl) # lam = [1 zeros(nl-1, 1)] num_Gfaa = zeros((nb, nb), complex) num_Gfav = zeros((nb, nb), complex) num_Gfva = zeros((nb, nb), complex) num_Gfvv = zeros((nb, nb), complex) num_Gtaa = zeros((nb, nb), complex) num_Gtav = zeros((nb, nb), complex) num_Gtva = zeros((nb, nb), complex) num_Gtvv = zeros((nb, nb), complex) dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, _, _ = dSbr_dV(branch, Yf, Yt, V) Gfaa, Gfav, Gfva, Gfvv = d2Sbr_dV2(Cf, Yf, V, lam) Gtaa, Gtav, Gtva, Gtvv = d2Sbr_dV2(Ct, Yt, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \ dSbr_dV(branch, Yf, Yt, Vap) num_Gfaa[:, i] = (dSf_dVa_ap - dSf_dVa).T * lam / pert num_Gfva[:, i] = (dSf_dVm_ap - dSf_dVm).T * lam / pert num_Gtaa[:, i] = (dSt_dVa_ap - dSt_dVa).T * lam / pert num_Gtva[:, i] = (dSt_dVm_ap - dSt_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \ dSbr_dV(branch, Yf, Yt, Vmp) num_Gfav[:, i] = (dSf_dVa_mp - dSf_dVa).T * lam / pert num_Gfvv[:, i] = (dSf_dVm_mp - dSf_dVm).T * lam / pert num_Gtav[:, i] = (dSt_dVa_mp - dSt_dVa).T * lam / pert num_Gtvv[:, i] = (dSt_dVm_mp - dSt_dVm).T * lam / pert t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t]) t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t]) t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t]) t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t]) t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t]) t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t]) t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t]) t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t]) ##----- check d2Ibr_dV2 code ----- t = ' - d2Ibr_dV2 (complex currents)' lam = 10 * random.rand(nl) # lam = [1, zeros(nl-1)] num_Gfaa = zeros((nb, nb), complex) num_Gfav = zeros((nb, nb), complex) num_Gfva = zeros((nb, nb), complex) num_Gfvv = zeros((nb, nb), complex) num_Gtaa = zeros((nb, nb), complex) num_Gtav = zeros((nb, nb), complex) num_Gtva = zeros((nb, nb), complex) num_Gtvv = zeros((nb, nb), complex) dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, _, _ = dIbr_dV(branch, Yf, Yt, V) Gfaa, Gfav, Gfva, Gfvv = d2Ibr_dV2(Yf, V, lam) Gtaa, Gtav, Gtva, Gtvv = d2Ibr_dV2(Yt, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \ dIbr_dV(branch, Yf, Yt, Vap) num_Gfaa[:, i] = (dIf_dVa_ap - dIf_dVa).T * lam / pert num_Gfva[:, i] = (dIf_dVm_ap - dIf_dVm).T * lam / pert num_Gtaa[:, i] = (dIt_dVa_ap - dIt_dVa).T * lam / pert num_Gtva[:, i] = (dIt_dVm_ap - dIt_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \ dIbr_dV(branch, Yf, Yt, Vmp) num_Gfav[:, i] = (dIf_dVa_mp - dIf_dVa).T * lam / pert num_Gfvv[:, i] = (dIf_dVm_mp - dIf_dVm).T * lam / pert num_Gtav[:, i] = (dIt_dVa_mp - dIt_dVa).T * lam / pert num_Gtvv[:, i] = (dIt_dVm_mp - dIt_dVm).T * lam / pert t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t]) t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t]) t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t]) t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t]) t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t]) t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t]) t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t]) t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t]) ##----- check d2ASbr_dV2 code ----- t = ' - d2ASbr_dV2 (squared apparent power flows)' lam = 10 * random.rand(nl) # lam = [1 zeros(nl-1, 1)] num_Gfaa = zeros((nb, nb), complex) num_Gfav = zeros((nb, nb), complex) num_Gfva = zeros((nb, nb), complex) num_Gfvv = zeros((nb, nb), complex) num_Gtaa = zeros((nb, nb), complex) num_Gtav = zeros((nb, nb), complex) num_Gtva = zeros((nb, nb), complex) num_Gtvv = zeros((nb, nb), complex) dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V) dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \ dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St) Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, lam) Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \ dSbr_dV(branch, Yf, Yt, Vap) dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \ dAbr_dV(dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap) num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \ dSbr_dV(branch, Yf, Yt, Vmp) dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \ dAbr_dV(dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp) num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t]) t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t]) t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t]) t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t]) t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t]) t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t]) t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t]) t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t]) ##----- check d2ASbr_dV2 code ----- t = ' - d2ASbr_dV2 (squared real power flows)' lam = 10 * random.rand(nl) # lam = [1 zeros(nl-1, 1)] num_Gfaa = zeros((nb, nb), complex) num_Gfav = zeros((nb, nb), complex) num_Gfva = zeros((nb, nb), complex) num_Gfvv = zeros((nb, nb), complex) num_Gtaa = zeros((nb, nb), complex) num_Gtav = zeros((nb, nb), complex) num_Gtva = zeros((nb, nb), complex) num_Gtvv = zeros((nb, nb), complex) dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V) dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \ dAbr_dV(dSf_dVa.real, dSf_dVm.real, dSt_dVa.real, dSt_dVm.real, Sf.real, St.real) Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real, Sf.real, Cf, Yf, V, lam) Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real, St.real, Ct, Yt, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \ dSbr_dV(branch, Yf, Yt, Vap) dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \ dAbr_dV(dSf_dVa_ap.real, dSf_dVm_ap.real, dSt_dVa_ap.real, dSt_dVm_ap.real, Sf_ap.real, St_ap.real) num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \ dSbr_dV(branch, Yf, Yt, Vmp) dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \ dAbr_dV(dSf_dVa_mp.real, dSf_dVm_mp.real, dSt_dVa_mp.real, dSt_dVm_mp.real, Sf_mp.real, St_mp.real) num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t]) t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t]) t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t]) t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t]) t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t]) t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t]) t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t]) t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t]) ##----- check d2AIbr_dV2 code ----- t = ' - d2AIbr_dV2 (squared current magnitudes)' lam = 10 * random.rand(nl) # lam = [1 zeros(nl-1, 1)] num_Gfaa = zeros((nb, nb), complex) num_Gfav = zeros((nb, nb), complex) num_Gfva = zeros((nb, nb), complex) num_Gfvv = zeros((nb, nb), complex) num_Gtaa = zeros((nb, nb), complex) num_Gtav = zeros((nb, nb), complex) num_Gtva = zeros((nb, nb), complex) num_Gtvv = zeros((nb, nb), complex) dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(branch, Yf, Yt, V) dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \ dAbr_dV(dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It) Gfaa, Gfav, Gfva, Gfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, lam) Gtaa, Gtav, Gtva, Gtvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, lam) for i in range(nb): Vap = V.copy() Vap[i] = Vm[i] * exp(1j * (Va[i] + pert)) dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \ dIbr_dV(branch, Yf, Yt, Vap) dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \ dAbr_dV(dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap) num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert Vmp = V.copy() Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i]) dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \ dIbr_dV(branch, Yf, Yt, Vmp) dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \ dAbr_dV(dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp) num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert t_is(Gfaa.todense(), num_Gfaa, 3, ['Gfaa', t]) t_is(Gfav.todense(), num_Gfav, 3, ['Gfav', t]) t_is(Gfva.todense(), num_Gfva, 3, ['Gfva', t]) t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t]) t_is(Gtaa.todense(), num_Gtaa, 3, ['Gtaa', t]) t_is(Gtav.todense(), num_Gtav, 3, ['Gtav', t]) t_is(Gtva.todense(), num_Gtva, 3, ['Gtva', t]) t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t]) t_end()
def t_loadcase(quiet=False): """Test that C{loadcase} works with an object as well as case file. @author: Ray Zimmerman (PSERC Cornell) @author: Richard Lincoln """ t_begin(240, quiet) ## compare result of loading from M-file file to result of using data matrices tdir = dirname(__file__) casefile = join(tdir, 't_case9_opf') matfile = join(tdir, 't_mat9_opf') pfcasefile = join(tdir, 't_case9_pf') pfmatfile = join(tdir, 't_mat9_pf') casefilev2 = join(tdir, 't_case9_opfv2') matfilev2 = join(tdir, 't_mat9_opfv2') pfcasefilev2 = join(tdir, 't_case9_pfv2') pfmatfilev2 = join(tdir, 't_mat9_pfv2') ## read version 1 OPF data matrices baseMVA, bus, gen, branch, areas, gencost = t_case9_opf() ## save as .mat file savemat(matfile + '.mat', {'baseMVA': baseMVA, 'bus': bus, 'gen': gen, 'branch': branch, 'areas': areas, 'gencost': gencost}, oned_as='row') ## read version 2 OPF data matrices ppc = t_case9_opfv2() ## save as .mat file savemat(matfilev2 + '.mat', {'ppc': ppc}, oned_as='column') ## prepare expected matrices for v1 load ## (missing gen cap curve & branch ang diff lims) tmp1 = (ppc['baseMVA'], ppc['bus'].copy(), ppc['gen'].copy(), ppc['branch'].copy(), ppc['areas'].copy(), ppc['gencost'].copy()) tmp2 = (ppc['baseMVA'], ppc['bus'].copy(), ppc['gen'].copy(), ppc['branch'].copy(), ppc['areas'].copy(), ppc['gencost'].copy()) ## remove capability curves, angle difference limits tmp1[2][1:3, [PC1, PC2, QC1MIN, QC1MAX, QC2MIN, QC2MAX]] = zeros((2,6)) tmp1[3][0, ANGMAX] = 360 tmp1[3][8, ANGMIN] = -360 baseMVA, bus, gen, branch, areas, gencost = tmp1 ##----- load OPF data into individual matrices ----- t = 'loadcase(opf_PY_file_v1) without .py extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(casefile, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_PY_file_v1) with .py extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(casefile + '.py', False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_MAT_file_v1) without .mat extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(matfile, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_MAT_file_v1) with .mat extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(matfile + '.mat', False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) ## prepare expected matrices for v2 load baseMVA, bus, gen, branch, areas, gencost = tmp2 t = 'loadcase(opf_PY_file_v2) without .py extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(casefilev2, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_PY_file_v2) with .py extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(casefilev2 + '.py', False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_MAT_file_v2) without .mat extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(matfilev2, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_MAT_file_v2) with .mat extension : ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \ loadcase(matfilev2 + '.mat', False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t_is(areas1, areas, 12, [t, 'areas']) t_is(gencost1, gencost, 12, [t, 'gencost']) ## prepare expected matrices for v1 load baseMVA, bus, gen, branch, areas, gencost = tmp1 t = 'loadcase(opf_struct_v1) (no version): ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = t_case9_opf() c = {} c['baseMVA'] = baseMVA1 c['bus'] = bus1.copy() c['gen'] = gen1.copy() c['branch'] = branch1.copy() c['areas'] = areas1.copy() c['gencost'] = gencost1.copy() baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t_is(areas2, areas, 12, [t, 'areas']) t_is(gencost2, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_struct_v1) (version=\'1\'): ' c['version'] = '1' baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t_is(areas2, areas, 12, [t, 'areas']) t_is(gencost2, gencost, 12, [t, 'gencost']) ## prepare expected matrices for v2 load baseMVA, bus, gen, branch, areas, gencost = tmp2 t = 'loadcase(opf_struct_v2) (no version): ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['areas'] = areas.copy() c['gencost'] = gencost.copy() baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t_is(areas2, areas, 12, [t, 'areas']) t_is(gencost2, gencost, 12, [t, 'gencost']) t = 'loadcase(opf_struct_v2) (version=''2''): ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['areas'] = areas.copy() c['gencost'] = gencost.copy() c['version'] = '2' baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t_is(areas2, areas, 12, [t, 'areas']) t_is(gencost2, gencost, 12, [t, 'gencost']) ##----- load OPF data into struct ----- ## prepare expected matrices for v1 load baseMVA, bus, gen, branch, areas, gencost = tmp1 t = 'ppc = loadcase(opf_PY_file_v1) without .py extension : ' ppc1 = loadcase(casefile) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_PY_file_v1) with .py extension : ' ppc1 = loadcase(casefile + '.py') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_MAT_file_v1) without .mat extension : ' ppc1 = loadcase(matfile) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_MAT_file_v1) with .mat extension : ' ppc1 = loadcase(matfile + '.mat') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) ## prepare expected matrices for v2 load baseMVA, bus, gen, branch, areas, gencost = tmp2 t = 'ppc = loadcase(opf_PY_file_v2) without .m extension : ' ppc1 = loadcase(casefilev2) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_PY_file_v2) with .py extension : ' ppc1 = loadcase(casefilev2 + '.py') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_MAT_file_v2) without .mat extension : ' ppc1 = loadcase(matfilev2) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_MAT_file_v2) with .mat extension : ' ppc1 = loadcase(matfilev2 + '.mat') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t_is(ppc1['areas'], areas, 12, [t, 'areas']) t_is(ppc1['gencost'], gencost, 12, [t, 'gencost']) ## prepare expected matrices for v1 load baseMVA, bus, gen, branch, areas, gencost = tmp1 t = 'ppc = loadcase(opf_struct_v1) (no version): ' baseMVA1, bus1, gen1, branch1, areas1, gencost1 = t_case9_opf() c = {} c['baseMVA'] = baseMVA1 c['bus'] = bus1.copy() c['gen'] = gen1.copy() c['branch'] = branch1.copy() c['areas'] = areas1.copy() c['gencost'] = gencost1.copy() ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t_is(ppc2['areas'], areas, 12, [t, 'areas']) t_is(ppc2['gencost'], gencost, 12, [t, 'gencost']) t = 'ppc = loadcase(opf_struct_v1) (version=''1''): ' c['version'] = '1' ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t_is(ppc2['areas'], areas, 12, [t, 'areas']) t_is(ppc2['gencost'], gencost, 12, [t, 'gencost']) ## prepare expected matrices for v2 load baseMVA, bus, gen, branch, areas, gencost = tmp2 t = 'ppc = loadcase(opf_struct_v2) (no version): ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['areas'] = areas.copy() c['gencost'] = gencost.copy() ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t_is(ppc2['areas'], areas, 12, [t, 'areas']) t_is(ppc2['gencost'], gencost, 12, [t, 'gencost']) t_ok(ppc2['version'] == '2', [t, 'version']) t = 'ppc = loadcase(opf_struct_v2) (version=''2''): ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['areas'] = areas.copy() c['gencost'] = gencost.copy() c['version'] = '2' ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t_is(ppc2['areas'], areas, 12, [t, 'areas']) t_is(ppc2['gencost'], gencost, 12, [t, 'gencost']) ## read version 1 PF data matrices baseMVA, bus, gen, branch = t_case9_pf() savemat(pfmatfile + '.mat', {'baseMVA': baseMVA, 'bus': bus, 'gen': gen, 'branch': branch}, oned_as='column') ## read version 2 PF data matrices ppc = t_case9_pfv2() tmp = (ppc['baseMVA'], ppc['bus'].copy(), ppc['gen'].copy(), ppc['branch'].copy()) baseMVA, bus, gen, branch = tmp ## save as .mat file savemat(pfmatfilev2 + '.mat', {'ppc': ppc}, oned_as='column') ##----- load PF data into individual matrices ----- t = 'loadcase(pf_PY_file_v1) without .py extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfcasefile, False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_PY_file_v1) with .py extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfcasefile + '.py', False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_MAT_file_v1) without .mat extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfmatfile, False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_MAT_file_v1) with .mat extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfmatfile + '.mat', False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_PY_file_v2) without .py extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfcasefilev2, False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_PY_file_v2) with .py extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfcasefilev2 + '.py', False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_MAT_file_v2) without .mat extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfmatfilev2, False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_MAT_file_v2) with .mat extension : ' baseMVA1, bus1, gen1, branch1 = \ loadcase(pfmatfilev2 + '.mat', False, False, False) t_is(baseMVA1, baseMVA, 12, [t, 'baseMVA']) t_is(bus1, bus, 12, [t, 'bus']) t_is(gen1, gen, 12, [t, 'gen']) t_is(branch1, branch, 12, [t, 'branch']) t = 'loadcase(pf_struct_v1) (no version): ' baseMVA1, bus1, gen1, branch1 = t_case9_pf() c = {} c['baseMVA'] = baseMVA1 c['bus'] = bus1.copy() c['gen'] = gen1.copy() c['branch'] = branch1.copy() baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t = 'loadcase(pf_struct_v1) (version=''1''): ' c['version'] = '1' baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) t = 'loadcase(pf_struct_v2) : ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['version'] = '2' baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False) t_is(baseMVA2, baseMVA, 12, [t, 'baseMVA']) t_is(bus2, bus, 12, [t, 'bus']) t_is(gen2, gen, 12, [t, 'gen']) t_is(branch2, branch, 12, [t, 'branch']) ##----- load PF data into struct ----- t = 'ppc = loadcase(pf_PY_file_v1) without .py extension : ' ppc1 = loadcase(pfcasefile) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_PY_file_v1) with .py extension : ' ppc1 = loadcase(pfcasefile + '.py') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_MAT_file_v1) without .mat extension : ' ppc1 = loadcase(pfmatfile) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_MAT_file_v1) with .mat extension : ' ppc1 = loadcase(pfmatfile + '.mat') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_PY_file_v2) without .py extension : ' ppc1 = loadcase(pfcasefilev2) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_PY_file_v2) with .py extension : ' ppc1 = loadcase(pfcasefilev2 + '.py') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_MAT_file_v2) without .mat extension : ' ppc1 = loadcase(pfmatfilev2) t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_MAT_file_v2) with .mat extension : ' ppc1 = loadcase(pfmatfilev2 + '.mat') t_is(ppc1['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc1['bus'], bus, 12, [t, 'bus']) t_is(ppc1['gen'], gen, 12, [t, 'gen']) t_is(ppc1['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_struct_v1) (no version): ' baseMVA1, bus1, gen1, branch1 = t_case9_pf() c = {} c['baseMVA'] = baseMVA1 c['bus'] = bus1.copy() c['gen'] = gen1.copy() c['branch'] = branch1.copy() ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_struct_v1) (version=''1''): ' c['version'] = '1' ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) t = 'ppc = loadcase(pf_struct_v2) : ' c = {} c['baseMVA'] = baseMVA c['bus'] = bus.copy() c['gen'] = gen.copy() c['branch'] = branch.copy() c['version'] = '2' ppc2 = loadcase(c) t_is(ppc2['baseMVA'], baseMVA, 12, [t, 'baseMVA']) t_is(ppc2['bus'], bus, 12, [t, 'bus']) t_is(ppc2['gen'], gen, 12, [t, 'gen']) t_is(ppc2['branch'], branch, 12, [t, 'branch']) ## cleanup os.remove(matfile + '.mat') os.remove(pfmatfile + '.mat') os.remove(matfilev2 + '.mat') os.remove(pfmatfilev2 + '.mat') t = 'runpf(my_PY_file)' ppopt = ppoption(VERBOSE=0, OUT_ALL=0) results3, success = runpf(pfcasefile, ppopt) baseMVA3, bus3, gen3, branch3 = results3['baseMVA'], results3['bus'], \ results3['gen'], results3['branch'] t_ok( success, t ) t = 'runpf(my_object)' results4, success = runpf(c, ppopt) baseMVA4, bus4, gen4, branch4 = results4['baseMVA'], results4['bus'], \ results4['gen'], results4['branch'] t_ok( success, t ) t = 'runpf result comparison : ' t_is(baseMVA3, baseMVA4, 12, [t, 'baseMVA']) t_is(bus3, bus4, 12, [t, 'bus']) t_is(gen3, gen4, 12, [t, 'gen']) t_is(branch3, branch4, 12, [t, 'branch']) t = 'runpf(modified_struct)' c['gen'][2, 1] = c['gen'][2, 1] + 1 ## increase gen 3 output by 1 results5, success = runpf(c, ppopt) gen5 = results5['gen'] t_is(gen5[0, 1], gen4[0, 1] - 1, 1, t) ## slack bus output should decrease by 1 t_end()
def t_dcline(quiet=False): """Tests for DC line extension in L{{toggle_dcline}. @author: Ray Zimmerman (PSERC Cornell) """ num_tests = 50 t_begin(num_tests, quiet) tdir = dirname(__file__) casefile = join(tdir, 't_case9_dcline') if quiet: verbose = False else: verbose = False t0 = '' ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8, PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9) ppopt = ppoption(ppopt, OPF_ALG=560, OPF_ALG_DC=200) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose) ## set up indices ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)] ib_voltage = arange(VM, VA + 1) ib_lam = arange(LAM_P, LAM_Q + 1) ib_mu = arange(MU_VMAX, MU_VMIN + 1) ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)] ig_disp = array([PG, QG, VG]) ig_mu = arange(MU_PMAX, MU_QMIN + 1) ibr_data = arange(ANGMAX + 1) ibr_flow = arange(PF, QT + 1) ibr_mu = array([MU_SF, MU_ST]) ibr_angmu = array([MU_ANGMIN, MU_ANGMAX]) ## load case ppc0 = loadcase(casefile) del ppc0['dclinecost'] ppc = ppc0 ppc = toggle_dcline(ppc, 'on') ppc = toggle_dcline(ppc, 'off') ndc = ppc['dcline'].shape[0] ## run AC OPF w/o DC lines t = ''.join([t0, 'AC OPF (no DC lines) : ']) r0 = runopf(ppc0, ppopt) success = r0['success'] t_ok(success, [t, 'success']) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['f'], r0['f'], 8, [t, 'f']) t_is(r['bus'][:, ib_data], r0['bus'][:, ib_data], 10, [t, 'bus data']) t_is(r['bus'][:, ib_voltage], r0['bus'][:, ib_voltage], 3, [t, 'bus voltage']) t_is(r['bus'][:, ib_lam], r0['bus'][:, ib_lam], 3, [t, 'bus lambda']) t_is(r['bus'][:, ib_mu], r0['bus'][:, ib_mu], 2, [t, 'bus mu']) t_is(r['gen'][:, ig_data], r0['gen'][:, ig_data], 10, [t, 'gen data']) t_is(r['gen'][:, ig_disp], r0['gen'][:, ig_disp], 3, [t, 'gen dispatch']) t_is(r['gen'][:, ig_mu], r0['gen'][:, ig_mu], 3, [t, 'gen mu']) t_is(r['branch'][:, ibr_data], r0['branch'][:, ibr_data], 10, [t, 'branch data']) t_is(r['branch'][:, ibr_flow], r0['branch'][:, ibr_flow], 3, [t, 'branch flow']) t_is(r['branch'][:, ibr_mu], r0['branch'][:, ibr_mu], 2, [t, 'branch mu']) t = ''.join([t0, 'AC PF (no DC lines) : ']) ppc1 = { 'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy() } ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3, [t, 'bus voltage']) t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch']) t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3, [t, 'branch flow']) ## run with DC lines t = ''.join([t0, 'AC OPF (with DC lines) : ']) ppc = toggle_dcline(ppc, 'on') r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected = array([[10, 8.9, -10, 10, 1.0674, 1.0935], [2.2776, 2.2776, 0, 0, 1.0818, 1.0665], [0, 0, 0, 0, 1.0000, 1.0000], [10, 9.5, 0.0563, -10, 1.0778, 1.0665]]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V']) expected = array([[0, 0.8490, 0.6165, 0, 0, 0.2938], [0, 0, 0, 0.4290, 0.0739, 0], [0, 0, 0, 0, 0, 0], [0, 7.2209, 0, 0, 0.0739, 0]]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu']) t = ''.join([t0, 'AC PF (with DC lines) : ']) ppc1 = { 'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy() } ppc1 = toggle_dcline(ppc1, 'on') ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3, [t, 'bus voltage']) #t_is( rp['gen'][:,ig_disp ], r['gen'][:,ig_disp ], 3, [t, 'gen dispatch']) t_is(rp['gen'][:2, ig_disp], r['gen'][:2, ig_disp], 3, [t, 'gen dispatch']) t_is(rp['gen'][2, PG], r['gen'][2, PG], 3, [t, 'gen dispatch']) t_is(rp['gen'][2, QG] + rp['dcline'][0, c.QF], r['gen'][2, QG] + r['dcline'][0, c.QF], 3, [t, 'gen dispatch']) t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3, [t, 'branch flow']) ## add appropriate P and Q injections and check angles and generation when running PF t = ''.join([t0, 'AC PF (with equivalent injections) : ']) ppc1 = { 'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy() } ppc1['bus'][:, VM] = 1 ppc1['bus'][:, VA] = 0 for k in range(ndc): if ppc1['dcline'][k, c.BR_STATUS]: ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS]) tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS]) ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF] ppc1['bus'][ff, QD] = ppc1['bus'][ff, QD] - r['dcline'][k, c.QF] ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT] ppc1['bus'][tt, QD] = ppc1['bus'][tt, QD] - r['dcline'][k, c.QT] ppc1['bus'][ff, VM] = r['dcline'][k, c.VF] ppc1['bus'][tt, VM] = r['dcline'][k, c.VT] ppc1['bus'][ff, BUS_TYPE] = PV ppc1['bus'][tt, BUS_TYPE] = PV rp = runpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3, [t, 'bus voltage']) t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch']) t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3, [t, 'branch flow']) ## test DC OPF t = ''.join([t0, 'DC OPF (with DC lines) : ']) ppc = ppc0.copy() ppc['gen'][0, PMIN] = 10 ppc['branch'][4, RATE_A] = 100 ppc = toggle_dcline(ppc, 'on') r = rundcopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected = array([[10, 8.9, 0, 0, 1.01, 1], [2, 2, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1], [10, 9.5, 0, 0, 1, 0.98]]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V']) expected = array([[0, 1.8602, 0, 0, 0, 0], [1.8507, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0.2681, 0, 0, 0, 0]]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu']) t = ''.join([t0, 'DC PF (with DC lines) : ']) ppc1 = { 'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy() } ppc1 = toggle_dcline(ppc1, 'on') ppc1['bus'][:, VA] = 0 rp = rundcpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3, [t, 'bus voltage']) t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch']) t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3, [t, 'branch flow']) ## add appropriate P injections and check angles and generation when running PF t = ''.join([t0, 'DC PF (with equivalent injections) : ']) ppc1 = { 'baseMVA': r['baseMVA'], 'bus': r['bus'][:, :VMIN + 1].copy(), 'gen': r['gen'][:, :APF + 1].copy(), 'branch': r['branch'][:, :ANGMAX + 1].copy(), 'gencost': r['gencost'].copy(), 'dcline': r['dcline'][:, :c.LOSS1 + 1].copy() } ppc1['bus'][:, VA] = 0 for k in range(ndc): if ppc1['dcline'][k, c.BR_STATUS]: ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS]) tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS]) ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF] ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT] ppc1['bus'][ff, BUS_TYPE] = PV ppc1['bus'][tt, BUS_TYPE] = PV rp = rundcpf(ppc1, ppopt) success = rp['success'] t_ok(success, [t, 'success']) t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3, [t, 'bus voltage']) t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch']) t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3, [t, 'branch flow']) ## run with DC lines t = ''.join([t0, 'AC OPF (with DC lines + poly cost) : ']) ppc = loadcase(casefile) ppc = toggle_dcline(ppc, 'on') r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) expected1 = array([[10, 8.9, -10, 10, 1.0663, 1.0936], [7.8429, 7.8429, 0, 0, 1.0809, 1.0667], [0, 0, 0, 0, 1.0000, 1.0000], [6.0549, 5.7522, -0.5897, -10, 1.0778, 1.0667]]) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) expected2 = array([[0, 0.7605, 0.6226, 0, 0, 0.2980], [0, 0, 0, 0.4275, 0.0792, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0.0792, 0]]) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) ppc['dclinecost'][3, :8] = array([2, 0, 0, 4, 0, 0, 7.3, 0]) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) t = ''.join([t0, 'AC OPF (with DC lines + pwl cost) : ']) ppc['dclinecost'][3, :8] = array([1, 0, 0, 2, 0, 0, 10, 73]) r = runopf(ppc, ppopt) success = r['success'] t_ok(success, [t, 'success']) t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V']) t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu']) t_end()
def fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, ppopt=None): """Solves the power flow using a fast decoupled method. Solves for bus voltages given the full system admittance matrix (for all buses), the complex bus power injection vector (for all buses), the initial vector of complex bus voltages, the FDPF matrices B prime and B double prime, and column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, respectively. The bus voltage vector contains the set point for generator (including ref bus) buses, and the reference angle of the swing bus, as well as an initial guess for remaining magnitudes and angles. C{ppopt} is a PYPOWER options vector which can be used to set the termination tolerance, maximum number of iterations, and output options (see L{ppoption} for details). Uses default options if this parameter is not given. Returns the final complex voltages, a flag which indicates whether it converged or not, and the number of iterations performed. @see: L{runpf} @author: Ray Zimmerman (PSERC Cornell) """ if ppopt is None: ppopt = ppoption() ## options tol = ppopt['PF_TOL'] max_it = ppopt['PF_MAX_IT_FD'] verbose = ppopt['VERBOSE'] ## initialize converged = 0 i = 0 V = V0 Va = angle(V) Vm = abs(V) ## set up indexing for updating V #npv = len(pv) #npq = len(pq) pvpq = r_[pv, pq] ## evaluate initial mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write('\niteration max mismatch (p.u.) ') sys.stdout.write('\ntype # P Q ') sys.stdout.write('\n---- ---- ----------- -----------') sys.stdout.write('\n - %3d %10.3e %10.3e' % (i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose > 1: sys.stdout.write('\nConverged!\n') ## reduce B matrices Bp = Bp[array([pvpq]).T, pvpq].tocsc() # splu requires a CSC matrix Bpp = Bpp[array([pq]).T, pq].tocsc() ## factor B matrices Bp_solver = splu(Bp) Bpp_solver = splu(Bpp) ## do P and Q iterations while (not converged and i < max_it): ## update iteration counter i = i + 1 ##----- do P iteration, update Va ----- dVa = -Bp_solver.solve(P) ## update voltage Va[pvpq] = Va[pvpq] + dVa V = Vm * exp(1j * Va) ## evalute mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write("\n %s %3d %10.3e %10.3e" % (type,i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose: sys.stdout.write('\nFast-decoupled power flow converged in %d ' 'P-iterations and %d Q-iterations.\n' % (i, i - 1)) break ##----- do Q iteration, update Vm ----- dVm = -Bpp_solver.solve(Q) ## update voltage Vm[pq] = Vm[pq] + dVm V = Vm * exp(1j * Va) ## evalute mismatch mis = (V * conj(Ybus * V) - Sbus) / Vm P = mis[pvpq].real Q = mis[pq].imag ## check tolerance normP = linalg.norm(P, Inf) normQ = linalg.norm(Q, Inf) if verbose > 1: sys.stdout.write('\n Q %3d %10.3e %10.3e' % (i, normP, normQ)) if normP < tol and normQ < tol: converged = 1 if verbose: sys.stdout.write('\nFast-decoupled power flow converged in %d ' 'P-iterations and %d Q-iterations.\n' % (i, i)) break if verbose: if not converged: sys.stdout.write('\nFast-decoupled power flow did not converge in ' '%d iterations.' % i) return V, converged, i
def t_runmarket(quiet=False): """Tests for code in C{runmkt}, C{smartmkt} and C{auction}. @author: Ray Zimmerman (PSERC Cornell) """ n_tests = 20 t_begin(n_tests, quiet) try: from pypower.extras.smartmarket import runmarket except ImportError: t_skip(n_tests, 'smartmarket code not available') t_end; return ppc = loadcase('t_auction_case') ppopt = ppoption(OPF_ALG=560, OUT_ALL_LIM=1, OUT_BRANCH=0, OUT_SYS_SUM=0) ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=1) #ppopt = ppoption(ppopt, OUT_GEN=1, OUT_BRANCH=0, OUT_SYS_SUM=0) offers = {'P': {}, 'Q': {}} bids = {'P': {}, 'Q': {}} offers['P']['qty'] = array([ [12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24], [12, 24, 24] ]) offers['P']['prc'] = array([ [20, 50, 60], [20, 40, 70], [20, 42, 80], [20, 44, 90], [20, 46, 75], [20, 48, 60] ]) bids['P']['qty'] = array([ [10, 10, 10], [10, 10, 10], [10, 10, 10] ]) bids['P']['prc'] = array([ [100, 70, 60], # [100, 64.3, 20], # [100, 30.64545, 0], [100, 50, 20], [100, 60, 50] ]) offers['Q']['qty'] = [ 60, 60, 60, 60, 60, 60, 0, 0, 0 ] offers['Q']['prc'] = [ 0, 0, 0, 0, 0, 3, 0, 0, 0 ] bids.Q['qty'] = [ 15, 15, 15, 15, 15, 15, 15, 12, 7.5 ] # bids.Q['prc'] = [ 0, 0, 0, 0, 0, 0, 0, 83.9056, 0 ] bids.Q['prc'] = [ 0, 0, 0, 0, 0, 0, 0, 20, 0 ] t = 'marginal Q offer, marginal PQ bid, auction_type = 5' mkt = {'auction_type': 5, 't': [], 'u0': [], 'lim': []} r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt) co5 = co.copy() cb5 = cb.copy() # [ co['P']['qty'] co['P']['prc'] ] # [ cb['P']['qty'] cb['P']['prc'] ] # [ co['Q']['qty'] co['Q']['prc'] ] # [ cb['Q']['qty'] cb['Q']['prc'] ] i2e = r['bus'][:, BUS_I] e2i = sparse((max(i2e), 1)) e2i[i2e] = range(r['bus'].size) G = find( isload(r['gen']) == 0 ) ## real generators L = find( isload(r['gen']) ) ## dispatchable loads Gbus = e2i[r['gen'][G, GEN_BUS]] Lbus = e2i[r['gen'][L, GEN_BUS]] t_is( co['P']['qty'], ones((6, 1)) * [12, 24, 0], 2, [t, ' : gen P quantities'] ) t_is( co['P']['prc'][0, :], 50.1578, 3, [t, ' : gen 1 P prices'] ) t_is( cb['P']['qty'], [[10, 10, 10], [10, 0.196, 0], [10, 10, 0]], 2, [t, ' : load P quantities'] ) t_is( cb['P']['prc'][1, :], 56.9853, 4, [t, ' : load 2 P price'] ) t_is( co['P']['prc'][:, 0], r['bus'][Gbus, LAM_P], 8, [t, ' : gen P prices'] ) t_is( cb['P']['prc'][:, 0], r['bus'][Lbus, LAM_P], 8, [t, ' : load P prices'] ) t_is( co['Q']['qty'], [4.2722, 11.3723, 14.1472, 22.8939, 36.7886, 12.3375, 0, 0, 0], 2, [t, ' : Q offer quantities'] ) t_is( co['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q offer prices'] ) t_is( cb['Q']['qty'], [0, 0, 0, 0, 0, 0, 15, 4.0785, 5], 2, [t, ' : Q bid quantities'] ) t_is( cb['Q']['prc'], [0, 0, 0, 0, 0, 3, 0.4861, 2.5367, 1.3763], 4, [t, ' : Q bid prices'] ) t_is( co['Q']['prc'], r['bus'][[Gbus, Lbus], LAM_Q], 8, [t, ' : Q offer prices'] ) t_is( cb['Q']['prc'], co['Q']['prc'], 8, [t, ' : Q bid prices'] ) t = 'marginal Q offer, marginal PQ bid, auction_type = 0' mkt['auction_type'] = 0 r, co, cb, _, _, _, _ = runmarket(ppc, offers, bids, mkt, ppopt) t_is( co['P']['qty'], co5['P']['qty'], 8, [t, ' : gen P quantities'] ) t_is( cb['P']['qty'], cb5['P']['qty'], 8, [t, ' : load P quantities'] ) t_is( co['P']['prc'], offers['P']['prc'], 8, [t, ' : gen P prices'] ) t_is( cb['P']['prc'], bids['P']['prc'], 8, [t, ' : load P prices'] ) t_is( co['Q']['qty'], co5['Q']['qty'], 8, [t, ' : gen Q quantities'] ) t_is( cb['Q']['qty'], cb5['Q']['qty'], 8, [t, ' : load Q quantities'] ) t_is( co['Q']['prc'], offers['Q']['prc'], 8, [t, ' : gen Q prices'] ) t_is( cb['Q']['prc'], bids['Q']['prc'], 8, [t, ' : load Q prices'] ) t_end