Ejemplo n.º 1
0
    def build_linear_ac_sys_mat(self):
        """
        Get the AC linear approximation matrices
        :return:
        """
        A11 = -self.Yseries.imag[np.ix_(self.pqpv, self.pqpv)]
        A12 = self.Ybus.real[np.ix_(self.pqpv, self.pq)]
        A21 = -self.Yseries.real[np.ix_(self.pq, self.pqpv)]
        A22 = -self.Ybus.imag[np.ix_(self.pq, self.pq)]

        A = vstack_s([hstack_s([A11, A12]),
                      hstack_s([A21, A22])], format="csc")

        # form the slack system matrix
        A11s = -self.Yseries.imag[np.ix_(self.ref, self.pqpv)]
        A12s = self.Ybus.real[np.ix_(self.ref, self.pq)]
        A_slack = hstack_s([A11s, A12s], format="csr")

        self.Asys = factorized(A)
        return A, A_slack
Ejemplo n.º 2
0
    def __init__(self, Y, Ys, S, V, pv, pq, vd):
        """
        Linearized AC power flow, solved with a linear solver :o
        :param Y: Admittance matrix
        :param Ys: Admittance matrix of the series elements
        :param S: Power injections vector
        :param V: Initial voltages
        :param pv: pv node indices
        :param pq: pq node indices
        :param vd: slack node indices
        """

        # node sets
        self.pv = pv
        self.vd = vd
        self.pq = pq
        self.pvpq = r_[pv, pq]
        self.V = V.copy()

        # form the system matrix
        A11 = -Ys.imag[self.pvpq, :][:, self.pvpq]
        A12 = Y.real[self.pvpq, :][:, self.pq]
        A21 = -Ys.real[self.pq, :][:, self.pvpq]
        A22 = -Y.imag[self.pq, :][:, self.pq]
        self.H = vstack_s(
            [hstack_s([A11, A12]), hstack_s([A21, A22])], format="csr")

        # compose the right hand side (power vectors)
        self.rhs = r_[S.real[self.pvpq], S.imag[self.pq]]

        # declare the voltage angles
        self.n = self.H.shape[0]
        self.dx = [None] * self.n
        for i in range(self.n):
            self.dx[i] = LpVariable("dx" + str(i))

        # declare the generation
        self.PG = list()
Ejemplo n.º 3
0
def LACPF_2(Y, Ys, S, Vset, pq, pv):
    """
    Linearized AC Load Flow
    Args:
        Y: Admittance matrix
        Ys: Admittance matrix of the series elements
        S: Power injections vector of all the nodes
        Vset: Set voltages of all the nodes (used for the slack and PV nodes)
        pq: list of indices of the pq nodes
        pv: list of indices of the pv nodes

    Returns: Voltage vector and error
    """

    pvpq = r_[pv, pq]
    npq = len(pq)
    npv = len(pv)

    # compose the system matrix
    G = Y.real
    B = Y.imag
    Gp = Ys.real
    Bp = Ys.imag

    A11 = -Bp[np.ix_(pvpq, pvpq)]
    A12 = G[np.ix_(pvpq, pq)]
    A21 = -Gp[np.ix_(pq, pvpq)]
    A22 = -B[np.ix_(pq, pq)]

    Asys = vstack_s([hstack_s([A11, A12]),
                     hstack_s([A21, A22])], format="csc")

    # compose the right hand side (power vectors)
    rhs = r_[S.real[pvpq], S.imag[pq]]

    # solve the linear system
    x = spsolve(Asys, rhs)

    # compose the results vector
    voltages_vector = Vset.copy()

    #  set the pv voltages
    va_pv = x[0:npv]
    vm_pv = np.abs(Vset[pv])
    voltages_vector[pv] = vm_pv * np.exp(1.0j * va_pv)

    # set the PQ voltages
    va_pq = x[npv:npv + npq]
    vm_pq = np.ones(npq) - x[npv + npq::]
    voltages_vector[pq] = vm_pq * np.exp(1.0j * va_pq)

    # Calculate the error and check the convergence
    Scalc = voltages_vector * conj(Y * voltages_vector)

    # complex power mismatch
    power_mismatch = Scalc - S

    # ------------------------------------------------------------------------------------------------------------------
    drhs = r_[power_mismatch.real[pvpq], power_mismatch.imag[pq]]
    dx = spsolve(Asys, drhs)

    #  set the pv voltages
    va_pv = x[0:npv] + dx[0:npv]
    vm_pv = np.abs(Vset[pv])
    voltages_vector[pv] = vm_pv * np.exp(1.0j * va_pv)

    # set the PQ voltages
    va_pq = x[npv:npv + npq] + dx[npv:npv + npq]
    vm_pq = np.ones(npq) - x[npv + npq::] - dx[npv + npq::]
    voltages_vector[pq] = vm_pq * np.exp(1.0j * va_pq)

    # ------------------------------------------------------------------------------------------------------------------

    # concatenate error by type
    mismatch = r_[power_mismatch[pv].real, power_mismatch[pq].real, power_mismatch[pq].imag]

    # check for convergence
    normF = linalg.norm(mismatch, Inf)

    return voltages_vector, normF
Ejemplo n.º 4
0
def prepare_system_matrices(Ybus, Vbus, bus_idx, pqpv, pq, pv, ref):
    """
    Prepare the system matrices
    :param Ybus:
    :param Vbus:
    :param pqpv:
    :param ref:
    :return:
    """
    n_bus = len(Vbus)
    n_bus2 = 2 * n_bus
    npv = len(pv)
    # ##################################################################################################################
    # Compute the starting voltages
    # ##################################################################################################################

    # System matrix
    A = lil_matrix((n_bus2, n_bus2))  # lil matrices are faster to populate

    # Expanded slack voltages
    Vslack = zeros(n_bus2)

    # Populate A
    for a in pqpv:  # rows
        for ii in range(Ybus.indptr[a],
                        Ybus.indptr[a + 1]):  # columns in sparse format
            b = Ybus.indices[ii]

            A[2 * a + 0, 2 * b + 0] = Ybus[a, b].real
            A[2 * a + 0, 2 * b + 1] = -Ybus[a, b].imag
            A[2 * a + 1, 2 * b + 0] = Ybus[a, b].imag
            A[2 * a + 1, 2 * b + 1] = Ybus[a, b].real

    # set vd elements
    for a in ref:
        A[a * 2, a * 2] = 1.0
        A[a * 2 + 1, a * 2 + 1] = 1.0

        Vslack[a * 2] = Vbus[a].real
        Vslack[a * 2 + 1] = Vbus[a].imag

    # Solve starting point voltages
    Vst_expanded = factorized(A.tocsc())(Vslack)

    # Invert the voltages obtained: Get the complex voltage and voltage inverse vectors
    Vst = Vst_expanded[2 * bus_idx] + 1j * Vst_expanded[2 * bus_idx + 1]
    Wst = 1.0 / Vst

    # ##################################################################################################################
    # Compute the final system matrix
    # ##################################################################################################################

    # System matrices
    B = lil_matrix((n_bus2, npv))
    C = lil_matrix((npv, n_bus2 + npv))

    for i, a in enumerate(pv):
        # "a" is the actual bus index
        # "i" is the number of the pv bus in the pv buses list

        B[2 * a + 0, i + 0] = Wst[a].imag
        B[2 * a + 1, i + 0] = Wst[a].real

        C[i + 0, 2 * a + 0] = Vst[a].real
        C[i + 0, 2 * a + 1] = Vst[a].imag

    Asys = vstack_s([hstack_s([A, B]), C], format="csc")

    return Asys, Vst, Wst
Ejemplo n.º 5
0
    def __init__(self, circuit: MultiCircuit, voltage_band=0.1):
        """
        Linearized AC power flow, solved with a linear solver :o
        :param circuit: GridCal Circuit instance
        """

        self.vm_low = 1.0 - voltage_band
        self.vm_high = 1.0 + voltage_band
        self.load_shedding = False

        self.circuit = circuit
        self.Sbase = circuit.Sbase

        # node sets
        self.pv = circuit.power_flow_input.pv
        self.pq = circuit.power_flow_input.pq
        self.vd = circuit.power_flow_input.ref
        self.pvpq = r_[self.pv, self.pq]
        self.pvpqpq = r_[self.pv, self.pq, self.pq]

        Y = circuit.power_flow_input.Ybus
        self.B = circuit.power_flow_input.Ybus.imag
        Ys = circuit.power_flow_input.Yseries
        S = circuit.power_flow_input.Sbus
        self.V = circuit.power_flow_input.Vbus.copy()

        # form the system matrix
        A11 = -Ys.imag[self.pvpq, :][:, self.pvpq]
        A12 = Y.real[self.pvpq, :][:, self.pq]
        A21 = -Ys.real[self.pq, :][:, self.pvpq]
        A22 = -Y.imag[self.pq, :][:, self.pq]
        self.sys_mat = vstack_s([hstack_s([A11, A12]),
                                 hstack_s([A21, A22])], format="csr")

        # form the slack system matrix
        A11s = -Ys.imag[self.vd, :][:, self.pvpq]
        A12s = Y.real[self.vd, :][:, self.pq]
        self.sys_mat_slack = hstack_s([A11s, A12s], format="csr")

        # compose the right hand side (power vectors)
        self.rhs = r_[S.real[self.pvpq], S.imag[self.pq]]

        # declare the voltage increments dx
        self.nn = self.sys_mat.shape[0]
        self.nbranch = len(self.circuit.branches)
        self.nbus = len(self.circuit.buses)
        self.dx_var = [None] * self.nn

        self.flow_ij = [None] * self.nbranch
        self.flow_ji = [None] * self.nbranch

        self.theta_dict = dict()

        self.loads = np.zeros(self.nn)
        self.load_shed = [None] * self.nn

        npv = len(self.pv)
        npq = len(self.pq)
        for i in range(self.nn):
            if i < (npv+npq):
                self.dx_var[i] = LpVariable("Va" + str(i), -0.5, 0.5)
                self.theta_dict[self.pvpq[i]] = self.dx_var[i]  # dictionary to store the angles for the pvpq nodes
                self.load_shed[i] = pulp.LpVariable("LoadShed_P_" + str(i), 0.0, 1e20)
            else:
                self.dx_var[i] = LpVariable("Vm" + str(i))
                self.load_shed[i] = pulp.LpVariable("LoadShed_Q_" + str(i), 0.0, 1e20)

        # declare the slack vars
        self.slack_loading_ij_p = [None] * self.nbranch
        self.slack_loading_ji_p = [None] * self.nbranch
        self.slack_loading_ij_n = [None] * self.nbranch
        self.slack_loading_ji_n = [None] * self.nbranch

        if self.load_shedding:
            pass

        else:

            for i in range(self.nbranch):
                self.slack_loading_ij_p[i] = pulp.LpVariable("LoadingSlack_ij_p_" + str(i), 0, 1e20)
                self.slack_loading_ji_p[i] = pulp.LpVariable("LoadingSlack_ji_p_" + str(i), 0, 1e20)
                self.slack_loading_ij_n[i] = pulp.LpVariable("LoadingSlack_ij_n_" + str(i), 0, 1e20)
                self.slack_loading_ji_n[i] = pulp.LpVariable("LoadingSlack_ji_n_" + str(i), 0, 1e20)

        # declare the generation
        self.PG = list()

        # LP problem
        self.problem = None

        # potential errors flag
        self.potential_errors = False

        # Check if the problem was solved or not
        self.solved = False

        # LP problem restrictions saved on build and added to the problem with every load change
        self.s_restrictions = list()
        self.p_restrictions = list()
Ejemplo n.º 6
0
def lacpf(bus_admittances, series_admittances, complex_bus_powers, current_injections_and_extractions, bus_voltages, pq_bus_indices, pv_bus_indices):
    """
    Linearized AC Load Flow

    form the article:

    Linearized AC Load Flow Applied to Analysis in Electric Power Systems
        by: P. Rossoni, W. M da Rosa and E. A. Belati
    Args:
        bus_admittances: Admittance matrix
        series_admittances: Admittance matrix of the series elements
        complex_bus_powers: Power injections vector of all the nodes
        bus_voltages: Set voltages of all the nodes (used for the slack and PV nodes)
        pq_bus_indices: list of indices of the pq nodes
        pv_bus_indices: list of indices of the pv nodes

    Returns: Voltage vector, converged?, error, calculated power and elapsed time
    """

    start = time.time()

    pvpq = r_[pv_bus_indices, pq_bus_indices]
    npq = len(pq_bus_indices)
    npv = len(pv_bus_indices)

    # compose the system matrix
    # G = Y.real
    # B = Y.imag
    # Gp = Ys.real
    # Bp = Ys.imag

    A11 = -series_admittances.imag[pvpq, :][:, pvpq]
    A12 = bus_admittances.real[pvpq, :][:, pq_bus_indices]
    A21 = -series_admittances.real[pq_bus_indices, :][:, pvpq]
    A22 = -bus_admittances.imag[pq_bus_indices, :][:, pq_bus_indices]

    Asys = vstack_s([hstack_s([A11, A12]),
                     hstack_s([A21, A22])], format="csc")

    # compose the right hand side (power vectors)
    rhs = r_[complex_bus_powers.real[pvpq], complex_bus_powers.imag[pq_bus_indices]]

    # solve the linear system
    try:
        x = spsolve(Asys, rhs)
    except Exception as e:
        voltages_vector = bus_voltages
        # Calculate the error and check the convergence
        s_calc = voltages_vector * conj(bus_admittances * voltages_vector)
        # complex power mismatch
        power_mismatch = s_calc - complex_bus_powers
        # concatenate error by type
        mismatch = r_[power_mismatch[pv_bus_indices].real, power_mismatch[pq_bus_indices].real, power_mismatch[pq_bus_indices].imag]
        # check for convergence
        norm_f = linalg.norm(mismatch, Inf)
        end = time.time()
        elapsed = end - start
        return voltages_vector, False, norm_f, s_calc, 1, elapsed

    # compose the results vector
    voltages_vector = bus_voltages.copy()

    #  set the pv voltages
    va_pv = x[0:npv]
    vm_pv = npabs(bus_voltages[pv_bus_indices])
    voltages_vector[pv_bus_indices] = vm_pv * exp(1j * va_pv)

    # set the PQ voltages
    va_pq = x[npv:npv+npq]
    vm_pq = ones(npq) + x[npv+npq::]
    voltages_vector[pq_bus_indices] = vm_pq * exp(1j * va_pq)

    # Calculate the error and check the convergence
    s_calc = voltages_vector * conj(bus_admittances * voltages_vector)
    # complex power mismatch
    power_mismatch = s_calc - complex_bus_powers
    # concatenate error by type
    mismatch = r_[power_mismatch[pv_bus_indices].real, power_mismatch[pq_bus_indices].real, power_mismatch[pq_bus_indices].imag]

    # check for convergence
    norm_f = linalg.norm(mismatch, Inf)

    end = time.time()
    elapsed = end - start

    return voltages_vector, True, norm_f, s_calc, 1, elapsed
Ejemplo n.º 7
0
def lacpf(Y, Ys, S, I, Vset, pq, pv):
    """
    Linearized AC Load Flow

    form the article:

    Linearized AC Load Flow Applied to Analysis in Electric Power Systems
        by: P. Rossoni, W. M da Rosa and E. A. Belati
    Args:
        Y: Admittance matrix
        Ys: Admittance matrix of the series elements
        S: Power injections vector of all the nodes
        Vset: Set voltages of all the nodes (used for the slack and PV nodes)
        pq: list of indices of the pq nodes
        pv: list of indices of the pv nodes

    Returns: Voltage vector, converged?, error, calculated power and elapsed time
    """

    start = time.time()

    pvpq = r_[pv, pq]
    npq = len(pq)
    npv = len(pv)

    # compose the system matrix
    # G = Y.real
    # B = Y.imag
    # Gp = Ys.real
    # Bp = Ys.imag

    A11 = -Ys.imag[pvpq, :][:, pvpq]
    A12 = Y.real[pvpq, :][:, pq]
    A21 = -Ys.real[pq, :][:, pvpq]
    A22 = -Y.imag[pq, :][:, pq]

    Asys = vstack_s([hstack_s([A11, A12]), hstack_s([A21, A22])], format="csc")

    # compose the right hand side (power vectors)
    rhs = r_[S.real[pvpq], S.imag[pq]]

    # solve the linear system
    x = factorized(Asys)(rhs)

    # compose the results vector
    voltages_vector = Vset.copy()

    #  set the pv voltages
    va_pv = x[0:npv]
    vm_pv = npabs(Vset[pv])
    voltages_vector[pv] = vm_pv * exp(1j * va_pv)

    # set the PQ voltages
    va_pq = x[npv:npv + npq]
    vm_pq = ones(npq) + x[npv + npq::]
    voltages_vector[pq] = vm_pq * exp(1j * va_pq)

    # Calculate the error and check the convergence
    s_calc = voltages_vector * conj(Y * voltages_vector)
    # complex power mismatch
    power_mismatch = s_calc - S
    # concatenate error by type
    mismatch = r_[power_mismatch[pv].real, power_mismatch[pq].real,
                  power_mismatch[pq].imag]

    # check for convergence
    norm_f = linalg.norm(mismatch, Inf)

    end = time.time()
    elapsed = end - start

    return voltages_vector, True, norm_f, s_calc, 1, elapsed