Example #1
0
    def get_Jacobian(self, sparse=False):
        """
        Returns the grid Jacobian matrix.

        Arguments:

            **sparse** (bool, False): Return the matrix in CSR sparse format (True) or
            as full matrix (False)
        """

        numerical_circuit = self.compile()
        islands = numerical_circuit.compute()
        i = 0
        # Initial magnitudes
        pvpq = np.r_[islands[i].pv, islands[i].pq]

        J = Jacobian(Ybus=islands[i].Ybus,
                     V=islands[i].Vbus,
                     Ibus=islands[i].Ibus,
                     pq=islands[i].pq,
                     pvpq=pvpq)

        if sparse:
            return J
        else:
            return J.todense()
Example #2
0
    def get_Jacobian(self, sparse=False):
        """
        Returns the grid Jacobian matrix.

        Arguments:

            **sparse** (bool, False): Return the matrix in CSR sparse format (True) or
            as full matrix (False)
        """

        # Initial magnitudes
        pvpq = np.r_[self.numerical_circuit.pv, self.numerical_circuit.pq]

        J = Jacobian(Ybus=self.numerical_circuit.Ybus,
                     V=self.numerical_circuit.Vbus,
                     Ibus=self.numerical_circuit.Ibus,
                     pq=self.numerical_circuit.pq,
                     pvpq=pvpq)

        if sparse:
            return J
        else:
            return J.todense()
Example #3
0
from scipy.sparse import hstack as hstack_sp, vstack as vstack_sp

circuit = MultiCircuit()

b1 = Bus(name='B1')
b2 = Bus(name='B2')
l2 = Load(P=1, Q=1)
br1 = Branch(b1, b2, r=0.1, x=1)
circuit.add_bus(b1)
circuit.add_bus(b2)
circuit.add_load(b2, l2)
circuit.add_branch(br1)

islands = circuit.compile_snapshot().compute()

npv = len(islands[0].pv)
npq = len(islands[0].pq)
pvpq = np.r_[islands[0].pv, islands[0].pq]
J = Jacobian(Ybus=islands[0].Ybus,
             V=islands[0].Vbus,
             Ibus=islands[0].Ibus,
             pq=islands[0].pq,
             pvpq=pvpq)

ek = np.zeros((1, npv + npq + npq + 1))
ek[0, -1] = 1
K = np.zeros((npv + npq + npq, 1))
J2 = vstack_sp([hstack_sp([J, K]), ek], format="csr")

pass
Example #4
0
    def get_structure(self, structure_type) -> pd.DataFrame:
        """
        Get a DataFrame with the input.

        Arguments:

            **structure_type** (str): 'Vbus', 'Sbus', 'Ibus', 'Ybus', 'Yshunt', 'Yseries' or 'Types'

        Returns:

            pandas DataFrame

        """

        if structure_type == 'Vbus':

            df = pd.DataFrame(data=self.Vbus,
                              columns=['Voltage (p.u.)'],
                              index=self.bus_names)

        elif structure_type == 'Sbus':
            df = pd.DataFrame(data=self.Sbus,
                              columns=['Power (p.u.)'],
                              index=self.bus_names)

        elif structure_type == 'Ibus':
            df = pd.DataFrame(data=self.Ibus,
                              columns=['Current (p.u.)'],
                              index=self.bus_names)

        elif structure_type == 'Ybus':
            df = pd.DataFrame(data=self.Ybus.toarray(),
                              columns=self.bus_names,
                              index=self.bus_names)

        elif structure_type == 'Yf':
            df = pd.DataFrame(data=self.Yf.toarray(),
                              columns=self.bus_names,
                              index=self.branch_names)

        elif structure_type == 'Yt':
            df = pd.DataFrame(data=self.Yt.toarray(),
                              columns=self.bus_names,
                              index=self.branch_names)

        elif structure_type == 'Cf':
            df = pd.DataFrame(data=self.C_branch_bus_f.toarray(),
                              columns=self.bus_names,
                              index=self.branch_names)

        elif structure_type == 'Ct':
            df = pd.DataFrame(data=self.C_branch_bus_t.toarray(),
                              columns=self.bus_names,
                              index=self.branch_names)

        elif structure_type == 'Yshunt':
            df = pd.DataFrame(data=self.Yshunt,
                              columns=['Shunt admittance (p.u.)'],
                              index=self.bus_names)

        elif structure_type == 'Yseries':
            df = pd.DataFrame(data=self.Yseries.toarray(),
                              columns=self.bus_names,
                              index=self.bus_names)

        elif structure_type == "B'":
            df = pd.DataFrame(data=self.B1.toarray(),
                              columns=self.bus_names,
                              index=self.bus_names)

        elif structure_type == "B''":
            df = pd.DataFrame(data=self.B2.toarray(),
                              columns=self.bus_names,
                              index=self.bus_names)

        elif structure_type == 'Types':
            df = pd.DataFrame(data=self.bus_types,
                              columns=['Bus types'],
                              index=self.bus_names)

        elif structure_type == 'Qmin':
            df = pd.DataFrame(data=self.Qmin_bus,
                              columns=['Qmin'],
                              index=self.bus_names)

        elif structure_type == 'Qmax':
            df = pd.DataFrame(data=self.Qmax_bus,
                              columns=['Qmax'],
                              index=self.bus_names)

        elif structure_type == 'pq':
            df = pd.DataFrame(data=self.pq,
                              columns=['pq'],
                              index=self.bus_names[self.pq])

        elif structure_type == 'pv':
            df = pd.DataFrame(data=self.pv,
                              columns=['pv'],
                              index=self.bus_names[self.pv])

        elif structure_type == 'vd':
            df = pd.DataFrame(data=self.vd,
                              columns=['vd'],
                              index=self.bus_names[self.vd])

        elif structure_type == 'pqpv':
            df = pd.DataFrame(data=self.pqpv,
                              columns=['pqpv'],
                              index=self.bus_names[self.pqpv])

        elif structure_type == 'original_bus_idx':
            df = pd.DataFrame(data=self.original_bus_idx,
                              columns=['original_bus_idx'],
                              index=self.bus_names)

        elif structure_type == 'original_branch_idx':
            df = pd.DataFrame(data=self.original_branch_idx,
                              columns=['original_branch_idx'],
                              index=self.branch_names)

        elif structure_type == 'original_line_idx':
            df = pd.DataFrame(data=self.original_line_idx,
                              columns=['original_line_idx'],
                              index=self.line_names)

        elif structure_type == 'original_tr_idx':
            df = pd.DataFrame(data=self.original_tr_idx,
                              columns=['original_tr_idx'],
                              index=self.tr_names)

        elif structure_type == 'original_gen_idx':
            df = pd.DataFrame(data=self.original_gen_idx,
                              columns=['original_gen_idx'],
                              index=self.generator_names)

        elif structure_type == 'Jacobian':

            J = Jacobian(self.Ybus, self.Vbus, self.Ibus, self.pq, self.pqpv)
            """
            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
            """
            npq = len(self.pq)
            npv = len(self.pv)
            npqpv = npq + npv
            cols = ['dS/dVa'] * npqpv + ['dS/dVm'] * npq
            rows = cols
            df = pd.DataFrame(data=J.toarray(), columns=cols, index=rows)

        else:

            raise Exception('PF input: structure type not found')

        return df
Example #5
0
    def get_structure(self, structure_type):
        """
        Get a DataFrame with the input.

        Arguments:

            **structure_type** (str): 'Vbus', 'Sbus', 'Ibus', 'Ybus', 'Yshunt', 'Yseries' or 'Types'

        Returns:

            pandas DataFrame

        """

        if structure_type == 'Vbus':

            df = pd.DataFrame(data=self.Vbus, columns=['Voltage (p.u.)'], index=self.bus_names)

        elif structure_type == 'Sbus':
            df = pd.DataFrame(data=self.Sbus, columns=['Power (p.u.)'], index=self.bus_names)

        elif structure_type == 'Ibus':
            df = pd.DataFrame(data=self.Ibus, columns=['Current (p.u.)'], index=self.bus_names)

        elif structure_type == 'Ybus':
            df = pd.DataFrame(data=self.Ybus.toarray(), columns=self.bus_names, index=self.bus_names)

        elif structure_type == 'Yshunt':
            df = pd.DataFrame(data=self.Ysh, columns=['Shunt admittance (p.u.)'], index=self.bus_names)

        elif structure_type == 'Yseries':
            df = pd.DataFrame(data=self.Yseries.toarray(), columns=self.bus_names, index=self.bus_names)

        elif structure_type == "B'":
            df = pd.DataFrame(data=self.B1.toarray(), columns=self.bus_names, index=self.bus_names)

        elif structure_type == "B''":
            df = pd.DataFrame(data=self.B2.toarray(), columns=self.bus_names, index=self.bus_names)

        elif structure_type == 'Types':
            df = pd.DataFrame(data=self.types, columns=['Bus types'], index=self.bus_names)

        elif structure_type == 'Qmin':
            df = pd.DataFrame(data=self.Qmin, columns=['Qmin'], index=self.bus_names)

        elif structure_type == 'Qmax':
            df = pd.DataFrame(data=self.Qmax, columns=['Qmax'], index=self.bus_names)

        elif structure_type == 'Jacobian':

            J = Jacobian(self.Ybus, self.Vbus, self.Ibus, self.pq, self.pqpv)

            """
            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
            """
            npq = len(self.pq)
            npv = len(self.pv)
            npqpv = npq + npv
            cols = ['dS/dVa'] * npqpv + ['dS/dVm'] * npq
            rows = cols
            df = pd.DataFrame(data=J.toarray(), columns=cols, index=rows)

        else:

            raise Exception('PF input: structure type not found')

        return df
Example #6
0
def predictor(V, Ibus, lam, Ybus, Sxfr, pv, pq, step, z, Vprv, lamprv,
              parametrization: VCParametrization):
    """
    Computes a prediction (approximation) to the next solution of the
    continuation power flow using a normalized tangent predictor.
    :param V: complex bus voltage vector at current solution
    :param Ibus:
    :param lam: scalar lambda value at current solution
    :param Ybus: complex bus admittance matrix
    :param Sxfr: complex vector of scheduled transfers (difference between bus injections in base and target cases)
    :param pv: vector of indices of PV buses
    :param pq: vector of indices of PQ buses
    :param step: continuation step length
    :param z: normalized tangent prediction vector from previous step
    :param Vprv: complex bus voltage vector at previous solution
    :param lamprv: scalar lambda value at previous solution
    :param parametrization: Value of cpf parametrization option.
    :return: V0 : predicted complex bus voltage vector
             LAM0 : predicted lambda continuation parameter
             Z : the normalized tangent prediction vector
    """
    """    
    %   MATPOWER
    %   Copyright (c) 1996-2015 by Power System Engineering Research Center (PSERC)
    %   by Shrirang Abhyankar, Argonne National Laboratory
    %   and Ray Zimmerman, PSERC Cornell
    %
    %   $Id: cpf_predictor.m 2644 2015-03-11 19:34:22Z ray $
    %
    %   This file is part of MATPOWER.
    %   Covered by the 3-clause BSD License (see LICENSE file for details).
    %   See http://www.pserc.cornell.edu/matpower/ for more info.
    """

    # sizes
    nb = len(V)
    npv = len(pv)
    npq = len(pq)
    pvpq = r_[pv, pq]
    nj = npv + npq * 2

    # compute Jacobian for the power flow equations
    J = Jacobian(Ybus, V, Ibus, pq, pvpq)

    dF_dlam = -r_[Sxfr[pvpq].real, Sxfr[pq].imag]

    dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv, pv,
                               pq, pvpq)

    # linear operator for computing the tangent predictor
    '''
    J2 = [   J   dF_dlam
           dP_dV dP_dlam ]
    '''
    J2 = vstack(
        [hstack([J, dF_dlam.reshape(nj, 1)]),
         hstack([dP_dV, dP_dlam])],
        format="csc")

    Va_prev = np.angle(V)
    Vm_prev = np.abs(V)

    # compute normalized tangent predictor
    s = np.zeros(npv + 2 * npq + 1)

    # increase in the direction of lambda
    s[npv + 2 * npq] = 1

    # tangent vector
    z[r_[pvpq, nb + pq, 2 * nb]] = spsolve(J2, s)

    # normalize_string tangent predictor  (dividing by the euclidean norm)
    z /= linalg.norm(z)

    Va0 = Va_prev
    Vm0 = Vm_prev
    # lam0 = lam

    # prediction for next step
    Va0[pvpq] = Va_prev[pvpq] + step * z[pvpq]
    Vm0[pq] = Vm_prev[pq] + step * z[nb + pq]
    lam0 = lam + step * z[2 * nb]
    V0 = Vm0 * exp(1j * Va0)

    return V0, lam0, z
Example #7
0
def corrector_new(Ybus,
                  Ibus,
                  Sbus,
                  V0,
                  pv,
                  pq,
                  lam0,
                  Sxfr,
                  Vprv,
                  lamprv,
                  z,
                  step,
                  parametrization,
                  tol,
                  max_it,
                  verbose,
                  max_it_internal=10):
    """
    Solves the corrector step of a continuation power flow using a full Newton method
    with selected parametrization scheme.

    solves for bus voltages and lambda 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.

     Uses default options if this parameter is not given. Returns the
     final complex voltages, a flag which indicates whether it converged or not,
     the number of iterations performed, and the final lambda.

    :param Ybus: Admittance matrix (CSC sparse)
    :param Ibus: Bus current injections
    :param Sbus: Bus power injections
    :param V0:  Bus initial voltages
    :param pv: list of pv nodes
    :param pq: list of pq nodes
    :param lam0: initial value of lambda (loading parameter)
    :param Sxfr: [delP+j*delQ] transfer/loading vector for all buses
    :param Vprv: final complex V corrector solution from previous continuation step
    :param lamprv: final lambda corrector solution from previous continuation step
    :param z: normalized predictor for all buses
    :param step: continuation step size
    :param parametrization:
    :param tol:
    :param max_it:
    :param verbose:
    :return: V, CONVERGED, I, LAM
    """
    """
    # CPF_CORRECTOR  Solves the corrector step of a continuation power flow using a
    #   full Newton method with selected parametrization scheme.
    #   [V, CONVERGED, I, LAM] = CPF_CORRECTOR(YBUS, SBUS, V0, REF, PV, PQ, ...
    #                 LAM0, SXFR, VPRV, LPRV, Z, STEP, parametrization, MPOPT)
    #   solves for bus voltages and lambda 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. MPOPT is a MATPOWER options struct which can be used to
    #   set the termination tolerance, maximum number of iterations, and
    #   output options (see MPOPTION 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, the number
    #   of iterations performed, and the final lambda.
    #
    #   The extra continuation inputs are LAM0 (initial predicted lambda),
    #   SXFR ([delP+j*delQ] transfer/loading vector for all buses), VPRV
    #   (final complex V corrector solution from previous continuation step),
    #   LAMPRV (final lambda corrector solution from previous continuation step),
    #   Z (normalized predictor for all buses), and STEP (continuation step size).
    #   The extra continuation output is LAM (final corrector lambda).
    #
    #   See also RUNCPF.

    #   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
    #
    #   Modified by Alexander J. Flueck, Illinois Institute of Technology
    #   2001.02.22 - corrector.m (ver 1.0) based on newtonpf.m (MATPOWER 2.0)
    #
    #   Modified by Shrirang Abhyankar, Argonne National Laboratory
    #   (Updated to be compatible with MATPOWER version 4.1)
    #
    #   $Id: cpf_corrector.m 2644 2015-03-11 19:34:22Z ray $
    #
    #   This file is part of MATPOWER.
    #   Covered by the 3-clause BSD License (see LICENSE file for details).
    #   See http://www.pserc.cornell.edu/matpower/ for more info.
    """

    # initialize
    converged = False
    i = 0
    V = V0
    Va = angle(V)
    Vm = np.abs(V)
    dVa = np.zeros_like(Va)
    dVm = np.zeros_like(Vm)
    lam = lam0  # set lam to initial lam0

    # set up indexing for updating V
    npv = len(pv)
    npq = len(pq)
    pvpq = r_[pv, pq]
    nj = npv + npq * 2
    nb = len(V)  # number of buses
    j1 = 1
    '''
    # MATLAB code
    j2 = npv           # j1:j2 - V angle of pv buses
    j3 = j2 + 1
    j4 = j2 + npq      # j3:j4 - V angle of pq buses
    j5 = j4 + 1
    j6 = j4 + npq      # j5:j6 - V mag of pq buses
    j7 = j6 + 1
    j8 = j6 + 1        # j7:j8 - lambda
    '''

    # j1:j2 - V angle of pv buses
    j1 = 0
    j2 = npv
    # j3:j4 - V angle of pq buses
    j3 = j2
    j4 = j2 + npq
    # j5:j6 - V mag of pq buses
    j5 = j4
    j6 = j4 + npq
    j7 = j6
    j8 = j6 + 1

    # evaluate F(x0, lam0), including Sxfr transfer/loading
    mismatch = V * conj(Ybus * V) - Sbus - lam * Sxfr
    # F = r_[mismatch[pvpq].real, mismatch[pq].imag]

    # evaluate P(x0, lambda0)
    P = cpf_p(parametrization, step, z, V, lam, Vprv, lamprv, pv, pq, pvpq)

    # augment F(x,lambda) with P(x,lambda)
    F = r_[mismatch[pvpq].real, mismatch[pq].imag, P]

    # check tolerance
    last_error = linalg.norm(F, Inf)
    error = 1e20

    if last_error < tol:
        converged = True
        if verbose:
            print('\nConverged!\n')

    # do Newton iterations
    while not converged and i < max_it:

        # update iteration counter
        i += 1

        # evaluate Jacobian
        J = Jacobian(Ybus, V, Ibus, pq, pvpq)

        dF_dlam = -r_[Sxfr[pvpq].real, Sxfr[pq].imag]

        dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv,
                                   pv, pq, pvpq)

        # augment J with real/imag - Sxfr and z^T
        '''
        J = [   J   dF_dlam 
              dP_dV dP_dlam ]
        '''
        J = vstack(
            [hstack([J, dF_dlam.reshape(nj, 1)]),
             hstack([dP_dV, dP_dlam])],
            format="csc")

        # compute update step
        dx = -spsolve(J, F)

        # reassign the solution vector
        if npv:
            dVa[pv] = dx[j1:j2]
        if npq:
            dVa[pq] = dx[j3:j4]
            dVm[pq] = dx[j5:j6]

        # update lambda
        lam += dx[j7:j8][0]

        # reset mu
        mu_ = 1.0

        print('iter', i)

        it = 0
        Vm = np.abs(V)
        Va = np.angle(V)
        while error >= last_error and it < max_it_internal:

            # update voltage the Newton way (mu=1)

            Vm_new = Vm + mu_ * dVm
            Va_new = Va + mu_ * dVa
            V_new = Vm_new * exp(1j * Va_new)

            print('\t', mu_, error, last_error)

            # evaluate F(x, lam)
            mismatch = V_new * conj(Ybus * V_new) - Sbus - lam * Sxfr

            # evaluate P(x, lambda)
            P = cpf_p(parametrization, step, z, V_new, lam, Vprv, lamprv, pv,
                      pq, pvpq)

            # compose the mismatch vector
            F = r_[mismatch[pv].real, mismatch[pq].real, mismatch[pq].imag, P]

            # check for convergence
            error = linalg.norm(F, Inf)

            # modify mu
            mu_ *= 0.25

            it += 1

        V = V_new.copy()
        last_error = error

        if verbose:
            print('\n#3d        #10.3e', i, error)

        if error < tol:
            converged = True
            if verbose:
                print('\nNewton'
                      's method corrector converged in ', i, ' iterations.\n')

    if verbose:
        if not converged:
            print('\nNewton method corrector did not converge in  ', i,
                  ' iterations.\n')

    return V, converged, i, lam, error
Example #8
0
    def run_jacobian_mode(self, time_indices) -> PtdfTimeSeriesResults:
        """
        Run the PTDF with the illinois formulation
        :return: TimeSeriesResults instance
        """

        # initialize the grid time series results, we will append the island results with another function
        nc = compile_opf_time_circuit(
            circuit=self.grid,
            apply_temperature=self.pf_options.apply_temperature_correction,
            branch_tolerance_mode=self.pf_options.
            branch_impedance_tolerance_mode)

        results = PtdfTimeSeriesResults(
            n=nc.nbus,
            m=nc.nbr,
            time_array=self.grid.time_profile[time_indices],
            bus_names=nc.bus_names,
            bus_types=nc.bus_types,
            branch_names=nc.branch_names)

        # if there are valid profiles...
        if self.grid.time_profile is not None:

            # run a power flow to get the initial branch power and compose the second branch power with the increment
            driver = PowerFlowDriver(grid=self.grid, options=self.pf_options)
            driver.run()

            # compile the islands
            islands = split_opf_time_circuit_into_islands(nc)

            # compose the power injections
            Sbus_0 = driver.results.Sbus
            Pbus_0 = Sbus_0.real
            V_0 = driver.results.voltage
            Pbr_0 = driver.results.Sbranch.real

            for island in islands:

                V = island.Vbus[0, :]
                Ibus = island.Ibus[:, 0]

                n = len(V)
                # set up indexing for updating V
                pvpq = np.r_[island.pv, island.pq]
                npv = len(island.pv)
                npq = len(island.pq)
                # j1:j2 - V angle of pv and pq buses
                j1 = 0
                j2 = npv + npq
                # j2:j3 - V mag of pq buses
                j3 = j2 + npq

                # compute the Jacobian
                J = Jacobian(island.Ybus, V, Ibus, island.pq, pvpq)
                Jfact = factorized(J)
                dVa = np.zeros(n)
                dVm = np.zeros(n)

                # run the PTDF time series
                for k, t_idx in enumerate(time_indices):
                    # dP = Pbus_0[island.original_bus_idx] - island.Sbus[:, t_idx].real

                    # compute the power increment (f)
                    dS = Sbus_0 - island.Sbus[:, t_idx]
                    # dS = island.Sbus[:, t_idx]
                    f = np.r_[dS[pvpq].real, dS[island.pq].imag]

                    # solve the voltage increment
                    dx = Jfact(f)

                    # reassign the solution vector
                    dVa[pvpq] = dx[j1:j2]
                    dVm[island.pq] = dx[j2:j3]
                    dV = dVm * np.exp(1j * dVa)
                    V = V_0 - dV

                    Vf = island.C_branch_bus_f * V
                    If = np.conj(island.Yf * V)
                    Sf = (Vf * If) * island.Sbase

                    results.voltage[k, island.original_bus_idx] = np.abs(V)

                    results.Sbranch[k, island.original_branch_idx] = Sf.real

                    results.loading[
                        k, island.original_branch_idx] = Sf.real / (
                            nc.branch_rates[t_idx,
                                            island.original_branch_idx] + 1e-9)

                    results.S[
                        k, island.original_bus_idx] = island.Sbus[:,
                                                                  t_idx].real

                    progress = ((t_idx - self.start_ + 1) /
                                (self.end_ - self.start_)) * 100
                    self.progress_signal.emit(progress)
                    self.progress_text.emit('Simulating PTDF at ' +
                                            str(self.grid.time_profile[t_idx]))

        else:
            print('There are no profiles')
            self.progress_text.emit('There are no profiles')

        return results
Example #9
0
def compute_ptdf(Ybus, Yf, Yt, Cf, Ct, V, Ibus, Sbus, pq, pv):
    """

    :param Ybus:
    :param Yf:
    :param Yt:
    :param Cf:
    :param Ct:
    :param V:
    :param Ibus:
    :param Sbus:
    :param pq:
    :param pv:
    :return:
    """
    n = len(V)
    # set up indexing for updating V
    pvpq = np.r_[pv, pq]
    npv = len(pv)
    npq = len(pq)
    # j1:j2 - V angle of pv and pq buses
    j1 = 0
    j2 = npv + npq
    # j2:j3 - V mag of pq buses
    j3 = j2 + npq

    # compute the Jacobian
    J = Jacobian(Ybus, V, Ibus, pq, pvpq)

    # compute the power increment (f)
    Scalc = V * np.conj(Ybus * V - Ibus)
    dS = Scalc - Sbus
    f = np.r_[dS[pvpq].real, dS[pq].imag]

    # solve the voltage increment
    dx = spsolve(J, f)

    # reassign the solution vector
    dVa = np.zeros(n)
    dVm = np.zeros(n)
    dVa[pvpq] = dx[j1:j2]
    dVm[pq] = dx[j2:j3]

    # compute branch derivatives

    If = Yf * V
    It = Yt * V
    E = V / np.abs(V)
    Vdiag = sp.diags(V)
    Vdiag_conj = sp.diags(np.conj(V))
    Ediag = sp.diags(E)
    Ediag_conj = sp.diags(np.conj(E))
    If_diag_conj = sp.diags(np.conj(If))
    It_diag_conj = sp.diags(np.conj(It))
    Yf_conj = Yf.copy()
    Yf_conj.data = np.conj(Yf_conj.data)
    Yt_conj = Yt.copy()
    Yt_conj.data = np.conj(Yt_conj.data)

    dSf_dVa = 1j * (If_diag_conj * Cf * Vdiag -
                    sp.diags(Cf * V) * Yf_conj * Vdiag_conj)
    dSf_dVm = If_diag_conj * Cf * Ediag - sp.diags(
        Cf * V) * Yf_conj * Ediag_conj

    dSt_dVa = 1j * (It_diag_conj * Ct * Vdiag -
                    sp.diags(Ct * V) * Yt_conj * Vdiag_conj)
    dSt_dVm = It_diag_conj * Ct * Ediag - sp.diags(
        Ct * V) * Yt_conj * Ediag_conj

    # compute the PTDF

    dVmf = Cf * dVm
    dVaf = Cf * dVa
    dPf_dVa = dSf_dVa.real
    dPf_dVm = dSf_dVm.real

    dVmt = Ct * dVm
    dVat = Ct * dVa
    dPt_dVa = dSt_dVa.real
    dPt_dVm = dSt_dVm.real

    PTDF = sp.diags(dVmf) * dPf_dVm + sp.diags(dVmt) * dPt_dVm + sp.diags(
        dVaf) * dPf_dVa + sp.diags(dVat) * dPt_dVa

    return PTDF