def vd(self): if self.vd_ is None: self.vd_, self.pq_, self.pv_, self.pqpv_ = compile_types( Sbus=self.Sbus[:, 0], types=self.bus_data.bus_types) return self.vd_
def consolidate(self): """ Computes the parameters given the filled-in information :return: """ self.compute_injections() self.vd, self.pq, self.pv, self.pqpv = compile_types(Sbus=self.Sbus, types=self.bus_types) self.compute_reactive_power_limits()
def consolidate(self): """ Computes the parameters given the filled-in information :return: """ self.compute_injections() self.vd, self.pq, self.pv, self.pqpv = compile_types( Sbus=self.Sbus[:, 0], types=self.bus_types) self.compute_admittance_matrices()
def compute_dynamic_types(self): """ Compute bus types profiles :return: """ self.vd_prof_ = list() self.pq_prof_ = list() self.pv_prof_ = list() self.pqpv_prof_ = list() for t in range(self.ntime): vd, pq, pv, pqpv = compile_types( Sbus=self.Sbus[:, t], types=self.bus_data.bus_types_prof[:, t]) self.vd_prof_.append(vd) self.pq_prof_.append(pq) self.pv_prof_.append(pv) self.pqpv_prof_.append(pqpv)
def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Ibus_base, Ibus_target, Sbus_base, Sbus_target, V, distributed_slack, bus_installed_power, vd, pv, pq, step, approximation_order: CpfParametrization, adapt_step, step_min, step_max, error_tol=1e-3, tol=1e-6, max_it=20, stop_at=CpfStopAt.Nose, control_q=ReactivePowerControlMode.NoControl, qmax_bus=None, qmin_bus=None, original_bus_types=None, base_overload_number=0, verbose=False, call_back_fx=None, logger=Logger()) -> CpfNumericResults: """ Runs a full AC continuation power flow using a normalized tangent predictor and selected approximation_order scheme. :param Ybus: Admittance matrix :param Cf: Connectivity matrix of the branches and the "from" nodes :param Ct: Connectivity matrix of the branches and the "to" nodes :param Yf: Admittance matrix of the "from" nodes :param Yt: Admittance matrix of the "to" nodes :param branch_rates: array of branch rates to check the overload condition :param Ibus_base: :param Ibus_target: :param Sbus_base: Power array of the base solvable case :param Sbus_target: Power array of the case to be solved :param V: Voltage array of the base solved case :param distributed_slack: Distribute the slack? :param bus_installed_power: array of installed power per bus :param vd: Array of slack bus indices :param pv: Array of pv bus indices :param pq: Array of pq bus indices :param step: Adaptation step :param approximation_order: order of the approximation {Natural, Arc, Pseudo arc} :param adapt_step: use adaptive step size? :param step_min: minimum step size :param step_max: maximum step size :param error_tol: Error tolerance :param tol: Solutions tolerance :param max_it: Maximum iterations :param stop_at: Value of Lambda to stop at. It can be a number or {'NOSE', 'FULL'} :param control_q: Type of reactive power control :param qmax_bus: Array of maximum reactive power per node :param qmin_bus: Array of minimum reactive power per node :param original_bus_types: array of bus types :param base_overload_number: number of overloads in the base situation (used when stop_at=CpfStopAt.ExtraOverloads) :param verbose: Display additional intermediate information? :param call_back_fx: Function to call on every iteration passing the lambda parameter :param logger: Logger instance :return: CpfNumericResults instance Ported from MATPOWER Copyright (c) 1996-2015 by Power System Engineering Research Center (PSERC) by Ray Zimmerman, PSERC Cornell, Shrirang Abhyankar, Argonne National Laboratory, and Alexander Flueck, IIT $Id: runcpf.m 2644 2015-03-11 19:34:22Z ray $ MATPOWER is covered by the 3-clause BSD License (see LICENSE file for details). See http://www.pserc.cornell.edu/matpower/ for more info. """ ######################################## # INITIALIZATION ######################################## # scheduled transfer Sxfr = Sbus_target - Sbus_base nb = len(Sbus_base) lam = 0 lam_prev = lam # lam at previous step V_prev = V # V at previous step continuation = True cont_steps = 0 pvpq = np.r_[pv, pq] bus_types = original_bus_types.copy() z = np.zeros(2 * nb + 1) z[2 * nb] = 1.0 # generate lookup pvpq -> index pvpq (used in createJ) pvpq_lookup = np.zeros(np.max(Ybus.indices) + 1, dtype=int) pvpq_lookup[pvpq] = np.arange(len(pvpq)) # compute total bus installed power total_installed_power = bus_installed_power.sum() # result arrays results = CpfNumericResults() # Simulation while continuation: cont_steps += 1 # prediction for next step ------------------------------------------------------------------------------------- V0, lam0, z = predictor(V=V, Ibus=Ibus_base, lam=lam, Ybus=Ybus, Sxfr=Sxfr, pv=pv, pq=pq, step=step, z=z, Vprv=V_prev, lamprv=lam_prev, parametrization=approximation_order, pvpq_lookup=pvpq_lookup) # save previous voltage, lambda before updating V_prev = V.copy() lam_prev = lam # correction --------------------------------------------------------------------------------------------------- V, success, i, lam, normF, Scalc = corrector( Ybus=Ybus, Ibus=Ibus_base, Sbus=Sbus_base, V0=V0, pv=pv, pq=pq, lam0=lam0, Sxfr=Sxfr, Vprv=V_prev, lamprv=lam_prev, z=z, step=step, parametrization=approximation_order, tol=tol, max_it=max_it, pvpq_lookup=pvpq_lookup, verbose=verbose) if distributed_slack: # Distribute the slack power slack_power = Scalc[vd].real.sum() if total_installed_power > 0.0: delta = slack_power * bus_installed_power / total_installed_power # rerun with the slack distributed and replace the results # also, initialize with the last voltage V, success, i, lam, normF, Scalc = corrector( Ybus=Ybus, Ibus=Ibus_base, Sbus=Sbus_base + delta, V0=V, pv=pv, pq=pq, lam0=lam0, Sxfr=Sxfr, Vprv=V_prev, lamprv=lam_prev, z=z, step=step, parametrization=approximation_order, tol=tol, max_it=max_it, pvpq_lookup=pvpq_lookup, verbose=verbose) if success: # branch values -------------------------------------------------------------------------------------------- # Branches current, loading, etc Vf = Cf * V Vt = Ct * V If = Yf * V # in p.u. It = Yt * V # in p.u. Sf = Vf * np.conj(If) * Sbase # in MVA St = Vt * np.conj(It) * Sbase # in MVA # Branch losses in MVA losses = Sf + St # Branch loading in p.u. loading = Sf.real / (branch_rates + 1e-9) # store series values -------------------------------------------------------------------------------------- results.add(V, Scalc, Sf, St, lam, losses, loading, normF, success) if verbose: print('Step: ', cont_steps, ' Lambda prev: ', lam_prev, ' Lambda: ', lam) print(V) # Check controls if control_q == ReactivePowerControlMode.Direct: Vm = np.abs(V) V, \ Qnew, \ types_new, \ any_q_control_issue = control_q_direct(V=V, Vm=Vm, Vset=Vm, Q=Scalc.imag, Qmax=qmax_bus, Qmin=qmin_bus, types=bus_types, original_types=original_bus_types, verbose=verbose) else: # did not check Q limits any_q_control_issue = False types_new = bus_types Qnew = Scalc.imag # Check the actions of the Q-control if any_q_control_issue: bus_types = types_new Sbus = Scalc.real + 1j * Qnew Sxfr = Sbus_target - Sbus # TODO: really? vd, pq, pv, pqpv = compile_types(Sbus, types_new, logger) else: if verbose: print('Q controls Ok') if stop_at == CpfStopAt.Full: if abs(lam) < 1e-8: # traced the full continuation curve if verbose: print('\nTraced full continuation curve in ', cont_steps, ' continuation steps\n') continuation = False elif (lam < lam_prev) and (lam - step < 0): # next step will overshoot # modify step-size step = lam # change to natural parametrization approximation_order = CpfParametrization.Natural # disable step-adaptivity adapt_step = 0 elif stop_at == CpfStopAt.Nose: if lam < lam_prev: # reached the nose point if verbose: print('\nReached steady state loading limit in ', cont_steps, ' continuation steps\n') continuation = False elif stop_at == CpfStopAt.ExtraOverloads: # look for overloads and determine if there are more overloads than in the base situation idx = np.where(np.abs(loading) > 1)[0] if len(idx) > base_overload_number: continuation = False else: raise Exception('Stop point ' + stop_at.value + ' not recognised.') if adapt_step and continuation: # Adapt step size fx = np.r_[np.angle(V[pq]), np.abs(V[pvpq]), lam] - np.r_[np.angle(V0[pq]), np.abs(V0[pvpq]), lam0] cpf_error = np.linalg.norm(fx, np.Inf) if cpf_error == 0: cpf_error = 1e-20 if cpf_error < error_tol: # Increase step size step = step * error_tol / cpf_error if step > step_max: step = step_max else: # Decrease step size step = step * error_tol / cpf_error if step < step_min: step = step_min # call callback function if call_back_fx is not None: call_back_fx(lam) else: continuation = False if verbose: print('step ', cont_steps, ' : lambda = ', lam, ', corrector did not converge in ', i, ' iterations\n') return results