Source code for VeraGridEngine.DataStructures.load_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

import numpy as np
import VeraGridEngine.Topology.topology as tp
from VeraGridEngine.basic_structures import Vec, CxVec, IntVec, StrVec, BoolVec


[docs] class LoadData: """ Structure to host the load calculation information """ def __init__(self, nelm: int, nbus: int): """ Load data arrays :param nelm: number of load :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.S: Vec = np.zeros(nelm, dtype=complex) self.I: Vec = np.zeros(nelm, dtype=complex) self.Y: Vec = np.zeros(nelm, dtype=complex) self.S3_delta = np.zeros(self.nelm * 4, dtype=complex) self.S3_star = np.zeros(self.nelm * 4, dtype=complex) self.S3_floatingstar = np.zeros(self.nelm * 4, dtype=complex) self.A_floatingstar = np.zeros(self.nelm, dtype=complex) self.B_floatingstar = np.zeros(self.nelm, dtype=complex) self.C_floatingstar = np.zeros(self.nelm, dtype=complex) self.I3_delta = np.zeros(self.nelm * 4, dtype=complex) self.I3_star = np.zeros(self.nelm * 4, dtype=complex) self.I3_floatingstar = np.zeros(self.nelm * 4, dtype=complex) self.Y3_delta = np.zeros(self.nelm * 4, dtype=complex) self.Y3_star = np.zeros((self.nelm * 4, 4), dtype=complex) # 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.cost: Vec = np.zeros(nelm, dtype=float) # load shedding cost self.shift_key: Vec = np.ones(nelm, dtype=float) self.scalable: BoolVec = np.ones(nelm, dtype=bool) self.original_idx = np.zeros(nelm, dtype=int)
[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) -> "LoadData": """ Slice load 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 island bus index {int(o): i for i, o in enumerate(bus_idx)} :return: new LoadData instance """ data = LoadData(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.S = self.S[elm_idx] data.I = self.I[elm_idx] data.Y = self.Y[elm_idx] elm_idx_4 = ((elm_idx * 4)[:, np.newaxis] + np.arange(4)).flatten() data.S3_delta = self.S3_delta[elm_idx_4] data.S3_star = self.S3_star[elm_idx_4] data.S3_floatingstar = self.S3_floatingstar[elm_idx_4] data.A_floatingstar = self.A_floatingstar[elm_idx] data.B_floatingstar = self.B_floatingstar[elm_idx] data.C_floatingstar = self.C_floatingstar[elm_idx] data.I3_delta = self.I3_delta[elm_idx_4] data.I3_star = self.I3_star[elm_idx_4] data.I3_floatingstar = self.I3_floatingstar[elm_idx_4] data.Y3_delta = self.Y3_delta[elm_idx_4] data.Y3_star = self.Y3_star[elm_idx_4] data.mttf = self.mttf[elm_idx] data.mttr = self.mttr[elm_idx] data.bus_idx = self.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 data.cost = self.cost[elm_idx] data.shift_key = self.shift_key[elm_idx] data.scalable = self.scalable[elm_idx] data.original_idx = 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] new_i = bus_map_arr[i] self.bus_idx[k] = new_i
[docs] def copy(self) -> "LoadData": """ Get a deep copy of this structure :return: new LoadData instance """ # TODO: review that we are copying everything data = LoadData(nelm=self.nelm, nbus=self.nbus) data.names = self.names.copy() data.idtag = self.idtag.copy() data.active = self.active.copy() data.S = self.S.copy() data.I = self.I.copy() data.Y = self.Y.copy() data.S3_delta = self.S3_delta.copy() data.S3_star = self.S3_star.copy() data.S3_floatingstar = self.S3_floatingstar.copy() data.A_floatingstar = self.A_floatingstar.copy() data.B_floatingstar = self.B_floatingstar.copy() data.C_floatingstar = self.C_floatingstar.copy() data.I3_delta = self.I3_delta.copy() data.I3_star = self.I3_star.copy() data.I3_floatingstar = self.I3_floatingstar.copy() data.Y3_delta = self.Y3_delta.copy() data.Y3_star = self.Y3_star.copy() data.mttf = self.mttf.copy() data.mttr = self.mttr.copy() data.bus_idx = self.bus_idx.copy() data.cost = self.cost.copy() data.original_idx = self.original_idx.copy() data.shift_key = self.shift_key.copy() data.scalable = self.scalable.copy() return data
[docs] def get_effective_load(self) -> CxVec: """ Get effective load :return: """ return self.S * self.active.astype(int)
[docs] def get_linear_effective_load(self) -> Vec: """ Get effective load :return: """ return self.S.real * self.active
[docs] def get_injections_per_bus(self) -> CxVec: """ Get Injections per bus with sign :return: """ return -tp.sum_per_bus_cx(self.nbus, self.bus_idx, self.get_effective_load())
[docs] def get_linear_injections_per_bus(self) -> Vec: """ Get Injections per bus with sign :return: """ return -tp.sum_per_bus(self.nbus, self.bus_idx, self.get_linear_effective_load())
[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(self.nbus, self.bus_idx, arr)
[docs] def get_array_per_bus_obj(self, arr: Vec) -> Vec: """ Sum per bus in python mode (it can add objects) :param arr: any array of size nelm :return: array of size nbus """ assert len(arr) == self.nelm res = np.zeros(self.nbus, dtype=arr.dtype) for i in range(self.nelm): res[self.bus_idx[i]] += arr[i] return res
[docs] def get_current_injections_per_bus(self) -> CxVec: """ Get current Injections per bus with sign :return: """ return -tp.sum_per_bus_cx(self.nbus, self.bus_idx, self.I * self.active.astype(int))
[docs] def get_admittance_injections_per_bus(self) -> CxVec: """ Get admittance Injections per bus with sign :return: """ return -tp.sum_per_bus_cx(self.nbus, self.bus_idx, self.Y * self.active.astype(int))
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