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 _run_ac_pf_without_qlims_enforced(ppci, recycle, makeYbus, ppopt): baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, V0 = _get_pf_variables_from_ppci( ppci) ppci, Ybus, Yf, Yt = _get_Y_bus(ppci, recycle, makeYbus, baseMVA, bus, branch) ## compute complex bus power injections [generation - load] Sbus = makeSbus(baseMVA, bus, gen) ## run the power flow V, success = _call_power_flow_function(baseMVA, bus, branch, Ybus, Sbus, V0, ref, pv, pq, ppopt) ## update data matrices with solution bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq) return ppci, success, bus, gen, branch
def _run_ac_pf_without_qlims_enforced(ppci, options): numba, makeYbus = _import_numba_extensions_if_flag_is_true( options["numba"]) baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, V0 = _get_pf_variables_from_ppci( ppci) ppci, Ybus, Yf, Yt = _get_Y_bus(ppci, options, makeYbus, baseMVA, bus, branch) ## compute complex bus power injections [generation - load] Sbus = makeSbus(baseMVA, bus, gen) ## run the newton power flow V, success, _ = newtonpf(Ybus, Sbus, V0, pv, pq, options, numba) ## update data matrices with solution bus, gen, branch = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq) return ppci, success, bus, gen, branch
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 _run_bfswpf(ppc, options, **kwargs): """ 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) """ time_start = time() # starting pf calculation timing tap_shift = ppc['branch'][:, SHIFT].real enforce_q_lims, tolerance_kva, max_iteration, calculate_voltage_angles, numba = _get_options( options) numba, makeYbus = _import_numba_extensions_if_flag_is_true(numba) ppci = ppc baseMVA, bus, gen, branch = \ ppci["baseMVA"], ppci["bus"], ppci["gen"], ppci["branch"] nbus = bus.shape[0] # generate results for original bus ordering Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) # get bus index lists of each type of bus ref, pv, pq = bustypes(bus, gen) # creating networkx graph from list of branches G = nx.Graph() G.add_edges_from((int(fb), int(tb), { "shift": float(shift) }) for fb, tb, shift in list( zip(branch[:, F_BUS].real, branch[:, T_BUS].real, tap_shift))) if not nx.is_connected(G): Graphs = list(nx.connected_component_subgraphs(G)) else: Graphs = [G] V_final = np.zeros(nbus, dtype=complex) V_tapshifts = np.zeros(nbus) for subi, G in enumerate(Graphs): ppci_sub = _cut_ppc(ppci, G.nodes()) nbus_sub = len(G) # depth-first-search bus ordering and generating Direct Load Flow matrix DLF = BCBV * BIBC DLF, ppc_bfsw, buses_ordered_bfsw = _bibc_bcbv(ppci_sub, G) ppc_bfsw['branch'][:, SHIFT] = 0 baseMVA_bfsw, bus_bfsw, gen_bfsw, branch_bfsw, ref_bfsw, pv_bfsw, pq_bfsw,\ on, gbus, V0 = _get_pf_variables_from_ppci(ppc_bfsw) Sbus_bfsw = makeSbus(baseMVA_bfsw, bus_bfsw, gen_bfsw) Ybus_bfsw, Yf_bfsw, Yt_bfsw = makeYbus(baseMVA_bfsw, bus_bfsw, branch_bfsw) # #----- run the power flow ----- V_res, success = _bfswpf(DLF, bus_bfsw, gen_bfsw, branch_bfsw, baseMVA, Ybus_bfsw, buses_ordered_bfsw, Sbus_bfsw, V0, ref_bfsw, pv_bfsw, pq_bfsw, enforce_q_lims, tolerance_kva, max_iteration, **kwargs) V_final[ buses_ordered_bfsw] = V_res # return bus voltages in original bus order # TODO: find the better way to consider transformer phase shift and remove this workaround if calculate_voltage_angles: predecessors = nx.bfs_predecessors(G, ref[subi]) branches = list(zip(branch[:, F_BUS].real, branch[:, T_BUS].real)) for bus_start in predecessors.iterkeys(): bus_pred = bus_start bus_next = bus_start while predecessors.get(bus_next) is not None: bus_next = predecessors.get(bus_pred) shift_angle = G.get_edge_data(bus_pred, bus_next)['shift'] if (bus_pred, bus_next) in branches: V_tapshifts[bus_start] += shift_angle else: V_tapshifts[bus_start] -= shift_angle bus_pred = bus_next V_final *= np.exp(1j * np.pi / 180 * V_tapshifts) # #----- output results to ppc ------ ppci["et"] = time() - time_start # pf time end 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 _run_bfswpf(ppci, options, **kwargs): """ 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 ppci: matpower-style case data :param options: pf options :return: results (pypower style), success (flag about PF convergence) """ time_start = time() # starting pf calculation timing baseMVA, bus, gen, branch, ref, pv, pq,\ on, gbus, V0 = _get_pf_variables_from_ppci(ppci) enforce_q_lims, tolerance_kva, max_iteration, calculate_voltage_angles, numba = _get_options( options) numba, makeYbus = _import_numba_extensions_if_flag_is_true(numba) nobus = bus.shape[0] nobranch = branch.shape[0] # generate Sbus Sbus = makeSbus(baseMVA, bus, gen) # generate results for original bus ordering Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch) # creating network graph from list of branches bus_from = branch[:, F_BUS].real.astype(int) bus_to = branch[:, T_BUS].real.astype(int) G = csr_matrix((np.ones(nobranch), (bus_from, bus_to)), shape=(nobus, nobus)) # create spanning trees using breadth-first-search # TODO add efficiency warning if a network is heavy-meshed G_trees = [] for refbus in ref: G_trees.append(csgraph.breadth_first_tree(G, refbus, directed=False)) # depth-first-search bus ordering and generating Direct Load Flow matrix DLF = BCBV * BIBC # TODO include recycling of the DLF matrix for repeated power flows with the same net topology DLF, buses_ordered_bfs_nets = _bibc_bcbv(bus, branch, G) # if there are trafos with phase-shift calculate Ybus without phase-shift for bfswpf any_trafo_shift = (branch[:, SHIFT] != 0).any() if any_trafo_shift: branch_noshift = branch.copy() branch_noshift[:, SHIFT] = 0 Ybus_noshift, Yf_noshift, Yt_noshift = makeYbus( baseMVA, bus, branch_noshift) else: Ybus_noshift = Ybus.copy() # #----- run the power flow ----- V_final, success = _bfswpf(DLF, bus, gen, branch, baseMVA, Ybus_noshift, Sbus, V0, ref, pv, pq, buses_ordered_bfs_nets, enforce_q_lims, tolerance_kva, max_iteration, **kwargs) # if phase-shifting trafos are present adjust final state vector angles accordingly if calculate_voltage_angles and any_trafo_shift: brch_shift_mask = branch[:, SHIFT] != 0 trafos_shift = dict( list( zip( list( zip(branch[brch_shift_mask, F_BUS].real.astype(int), branch[brch_shift_mask, T_BUS].real.astype(int))), branch[brch_shift_mask, SHIFT].real))) for trafo_ind, shift_degree in iteritems(trafos_shift): neti = 0 # if multiple reference nodes, find in which network trafo is located if len(ref) > 0: for refbusi in range(len(ref)): if trafo_ind[0] in buses_ordered_bfs_nets[refbusi]: neti = refbusi break G_tree = G_trees[neti] buses_ordered_bfs = buses_ordered_bfs_nets[neti] if (np.argwhere(buses_ordered_bfs == trafo_ind[0]) < np.argwhere(buses_ordered_bfs == trafo_ind[1])): lv_bus = trafo_ind[1] shift_degree *= -1 else: lv_bus = trafo_ind[0] buses_shifted_from_root = csgraph.breadth_first_order( G_tree, lv_bus, directed=True, return_predecessors=False) V_final[buses_shifted_from_root] *= np.exp(1j * np.pi / 180 * shift_degree) # #----- output results to ppc ------ ppci["et"] = time() - time_start # pf time end 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