Source code for VeraGridEngine.DataStructures.shunt_data

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.  
# SPDX-License-Identifier: MPL-2.0
from typing import Tuple
import numpy as np
from scipy.sparse import csc_matrix, coo_matrix
import VeraGridEngine.Topology.topology as tp
from VeraGridEngine.Utils.Sparse.sparse_array import SparseObjectArray
from VeraGridEngine.basic_structures import Vec, CxVec, IntVec, StrVec, BoolVec
from VeraGridEngine.enumerations import ShuntControlMode


[docs] class ShuntData: """ ShuntData """ def __init__(self, nelm: int, nbus: int): """ Shunt data arrays :param nelm: number of shunts :param nbus: number of buses """ self.nelm: int = nelm self.nbus: int = nbus self.names: StrVec = np.empty(nelm, dtype=object) self.idtag: StrVec = np.empty(nelm, dtype=object) self.active: BoolVec = np.zeros(nelm, dtype=bool) self.control_mode_int: IntVec = np.zeros(self.nelm, dtype=int) self.Y: CxVec = np.zeros(nelm, dtype=complex) # self.Y3_delta = np.zeros(self.nelm * 3, dtype=complex) self.Y3_star = np.zeros((self.nelm * 4, 4), dtype=complex) self.Y3_delta = np.zeros((self.nelm * 4), dtype=complex) self.A_floating_star = np.zeros(self.nelm, dtype=complex) self.B_floating_star = np.zeros(self.nelm, dtype=complex) self.C_floating_star = np.zeros(self.nelm, dtype=complex) self.qmin: Vec = np.zeros(nelm, dtype=float) self.qmax: Vec = np.zeros(nelm, dtype=float) self.q_share: Vec = np.zeros(nelm, dtype=float) self.cost: Vec = np.zeros(nelm, dtype=float) self.taps = SparseObjectArray(n=self.nelm) # reliability self.mttf: Vec = np.zeros(nelm, dtype=float) self.mttr: Vec = np.zeros(nelm, dtype=float) self.bus_idx = np.zeros(nelm, dtype=int) self.controllable_bus_idx = np.zeros(nelm, dtype=int) self.original_idx: IntVec = np.zeros(nelm, dtype=int) self.vset: Vec = np.zeros(nelm, dtype=float) self.vmin: Vec = np.zeros(nelm, dtype=float) self.vmax: Vec = np.zeros(nelm, dtype=float) self.step = np.zeros(nelm, dtype=int) self.g_steps = SparseObjectArray(n=self.nelm) self.b_steps = SparseObjectArray(n=self.nelm)
[docs] def size(self) -> int: """ Get size of the structure :return: """ return self.nelm
[docs] def slice(self, elm_idx: IntVec, bus_idx: IntVec, bus_map: IntVec) -> "ShuntData": """ Slice shunt data by given indices :param elm_idx: array of branch indices :param bus_idx: array of bus indices :param bus_map: map from bus index to branch index :return: new ShuntData instance """ data = ShuntData(nelm=len(elm_idx), nbus=len(bus_idx)) data.names = self.names[elm_idx] data.idtag = self.idtag[elm_idx] data.active = self.active[elm_idx] data.control_mode_int = self.control_mode_int[elm_idx] data.Y = self.Y[elm_idx] elm_idx_4 = ((elm_idx * 4)[:, np.newaxis] + np.arange(4)).flatten() data.Y3_delta = self.Y3_delta[elm_idx_4] data.Y3_star = self.Y3_star[elm_idx_4] data.A_floating_star = self.A_floating_star[elm_idx] data.B_floating_star = self.B_floating_star[elm_idx] data.C_floating_star = self.C_floating_star[elm_idx] data.qmax = self.qmax[elm_idx] data.qmin = self.qmin[elm_idx] data.q_share = self.q_share[elm_idx] data.cost = self.cost[elm_idx] data.taps = self.taps.slice(elm_idx) data.mttf = self.mttf[elm_idx] data.mttr = self.mttr[elm_idx] data.bus_idx = self.bus_idx[elm_idx] data.controllable_bus_idx = self.controllable_bus_idx[elm_idx] # Remapping of the buses for k in range(data.nelm): data.bus_idx[k] = bus_map[data.bus_idx[k]] if data.bus_idx[k] == -1: data.active[k] = 0 if data.controllable_bus_idx[k] > -1: data.controllable_bus_idx[k] = bus_map[data.controllable_bus_idx[k]] data.original_idx = elm_idx data.vset = self.vset[elm_idx] data.vmin = self.vmin[elm_idx] data.vmax = self.vmax[elm_idx] data.step = self.step[elm_idx] data.g_steps = self.g_steps.slice(elm_idx) data.b_steps = self.b_steps.slice(elm_idx) return data
[docs] def remap(self, bus_map_arr: IntVec): """ Remapping of the elm buses :param bus_map_arr: array of old-to-new buses """ for k in range(self.nelm): i = self.bus_idx[k] self.bus_idx[k] = bus_map_arr[i] control_bus_idx = self.controllable_bus_idx[k] if control_bus_idx >= 0: self.controllable_bus_idx[k] = bus_map_arr[control_bus_idx]
[docs] def copy(self) -> "ShuntData": """ Get deep copy of this structure :return: new ShuntData instance """ data = ShuntData(nelm=self.nelm, nbus=self.nbus) data.names = self.names.copy() data.idtag = self.idtag.copy() data.active = self.active.copy() data.control_mode_int = self.control_mode_int.copy() data.Y = self.Y.copy() data.Y3_star = self.Y3_star.copy() data.Y3_delta = self.Y3_delta.copy() data.A_floating_star = self.A_floating_star.copy() data.B_floating_star = self.B_floating_star.copy() data.C_floating_star = self.C_floating_star.copy() data.qmax = self.qmax.copy() data.qmin = self.qmin.copy() data.q_share = self.q_share.copy() data.cost = self.cost.copy() data.taps = self.taps.copy() data.mttf = self.mttf.copy() data.mttr = self.mttr.copy() data.bus_idx = self.bus_idx.copy() data.controllable_bus_idx = self.controllable_bus_idx.copy() data.original_idx = self.original_idx.copy() data.vset = self.vset.copy() data.vmin = self.vmin.copy() data.vmax = self.vmax.copy() data.step = self.step.copy() data.g_steps = self.g_steps.copy() data.b_steps = self.b_steps.copy() return data
[docs] def get_array_per_bus(self, arr: Vec) -> Vec: """ Get generator array per bus :param arr: :return: """ assert len(arr) == self.nelm return tp.sum_per_bus(nbus=self.nbus, bus_indices=self.bus_idx, magnitude=arr)
[docs] def get_injections_per_bus(self) -> CxVec: """ Get Injections per bus :return: """ return tp.sum_per_bus_cx(nbus=self.nbus, bus_indices=self.bus_idx, magnitude=self.Y * self.active)
[docs] def get_fix_injections_per_bus(self) -> CxVec: """ Get fixed Injections per bus :return: """ is_pv_control = self.control_mode_int == ShuntControlMode.Continuous.idx() return tp.sum_per_bus_cx(nbus=self.nbus, bus_indices=self.bus_idx, magnitude=self.Y * self.active * (1 - is_pv_control))
[docs] def get_qmax_per_bus(self) -> Vec: """ Get generator Qmax per bus :return: """ return tp.sum_per_bus(nbus=self.nbus, bus_indices=self.bus_idx, magnitude=self.qmax * self.active)
[docs] def get_qmin_per_bus(self) -> Vec: """ Get generator Qmin per bus :return: """ return tp.sum_per_bus(nbus=self.nbus, bus_indices=self.bus_idx, magnitude=self.qmin * self.active)
def __len__(self) -> int: return self.nelm
[docs] def get_bus_indices(self) -> IntVec: """ Get the bus indices :return: array with the bus indices """ return self.bus_idx
[docs] def get_controllable_and_not_controllable_indices(self) -> Tuple[IntVec, IntVec]: """ Get the indices of controllable generators :return: idx_controllable, idx_non_controllable """ return (np.where(self.control_mode_int == ShuntControlMode.Continuous.idx())[0], np.where(self.control_mode_int != ShuntControlMode.Continuous.idx())[0])
[docs] def get_C_bus_elm(self) -> csc_matrix: """ Get the connectivity matrix :return: CSC matrix """ # C_bus_elm = lil_matrix((self.nbus, self.nelm), dtype=int) # for k, i in enumerate(self.bus_idx): # C_bus_elm[i, k] = 1 # return C_bus_elm.tocsc() j = np.arange(self.nelm, dtype=int) data = np.ones(self.nelm, dtype=int) return coo_matrix((data, (self.bus_idx, j)), shape=(self.nbus, self.nelm), dtype=int).tocsc()