def compute_branch_results(self, V): """ Compute the branch magnitudes from the voltages :param V: Voltage vector solution in p.u. :return: CalculationResults instance with all the grid magnitudes """ # declare circuit results data = PowerFlowResults(self.nbus, self.nbr) # copy the voltage data.V = V # power at the slack nodes data.Sbus = self.Sbus.copy() data.Sbus[self.ref] = V[self.ref] * np.conj( self.Ybus[self.ref, :].dot(V)) # Reactive power at the pv nodes: keep the original P injection and set the calculated reactive power Q = (V[self.pv] * np.conj(self.Ybus[self.pv, :].dot(V))).imag data.Sbus[self.pv] = self.Sbus[self.pv].real + 1j * Q # Branches current, loading, etc data.If = self.Yf * V data.It = self.Yt * V data.Sf = self.C_branch_bus_f * V * np.conj(data.If) data.St = self.C_branch_bus_t * V * np.conj(data.It) # Branch losses in MVA data.losses = (data.Sf + data.St) # Branch current in p.u. data.Ibranch = np.maximum(data.If, data.It) # Branch power in MVA data.Sbranch = np.maximum(data.Sf, data.St) # Branch loading in p.u. data.loading = data.Sbranch / (self.branch_rates + 1e-9) return data
def outer_loop_power_flow(circuit: SnapshotData, options: PowerFlowOptions, voltage_solution, Sbus, Ibus, branch_rates, t=0, logger=bs.Logger()) -> "PowerFlowResults": """ Run a power flow simulation for a single circuit using the selected outer loop controls. This method shouldn't be called directly. :param circuit: CalculationInputs instance :param options: :param voltage_solution: vector of initial voltages :param Sbus: vector of power injections :param Ibus: vector of current injections :param branch_rates: :param t: time step :param logger: :return: PowerFlowResults instance """ # get the original types and compile this class' own lists of node types for thread independence bus_types = circuit.bus_types.copy() # vd = circuit.vd.copy() # pq = circuit.pq.copy() # pv = circuit.pv.copy() # pqpv = circuit.pqpv.copy() report = ConvergenceReport() solution = NumericPowerFlowResults(V=voltage_solution, converged=False, norm_f=1e200, Scalc=Sbus, ma=circuit.branch_data.m[:, 0], theta=circuit.branch_data.theta[:, 0], Beq=circuit.branch_data.Beq[:, 0], iterations=0, elapsed=0) # this the "outer-loop" if len(circuit.vd) == 0: voltage_solution = np.zeros(len(Sbus), dtype=complex) normF = 0 Scalc = Sbus.copy() any_q_control_issue = False converged = True logger.add_error('Not solving power flow because there is no slack bus') else: # run the power flow method that shall be run solution = solve(circuit=circuit, options=options, report=report, # is modified here V0=voltage_solution, Sbus=Sbus, Ibus=Ibus, pq=circuit.pq, pv=circuit.pv, ref=circuit.vd, pqpv=circuit.pqpv, logger=logger) if options.distributed_slack: # Distribute the slack power slack_power = Sbus[circuit.vd].real.sum() total_installed_power = circuit.bus_installed_power.sum() if total_installed_power > 0.0: delta = slack_power * circuit.bus_installed_power / total_installed_power # repeat power flow with the redistributed power solution = solve(circuit=circuit, options=options, report=report, # is modified here V0=solution.V, Sbus=Sbus + delta, Ibus=Ibus, pq=circuit.pq, pv=circuit.pv, ref=circuit.vd, pqpv=circuit.pqpv, logger=logger) # Compute the branches power and the slack buses power Sfb, Stb, If, It, Vbranch, loading, losses, \ flow_direction, Sbus = power_flow_post_process(calculation_inputs=circuit, Sbus=solution.Scalc, V=solution.V, branch_rates=branch_rates) # voltage, Sf, loading, losses, error, converged, Qpv results = PowerFlowResults(n=circuit.nbus, m=circuit.nbr, n_tr=circuit.ntr, n_hvdc=circuit.nhvdc, bus_names=circuit.bus_names, branch_names=circuit.branch_names, transformer_names=circuit.tr_names, hvdc_names=circuit.hvdc_names, bus_types=bus_types) results.Sbus = solution.Scalc * circuit.Sbase # MVA results.voltage = solution.V results.Sf = Sfb # in MVA already results.St = Stb # in MVA already results.If = If # in p.u. results.It = It # in p.u. results.ma = solution.ma results.theta = solution.theta results.Beq = solution.Beq results.Vbranch = Vbranch results.loading = loading results.losses = losses results.flow_direction = flow_direction results.transformer_tap_module = solution.ma[circuit.transformer_idx] results.convergence_reports.append(report) results.Qpv = Sbus.imag[circuit.pv] # HVDC results are gathered in the multi island power flow function due to their nature return results