def get_raw_circuit(self, add_generation, add_storage) -> CalculationInputs: """ :param add_generation: :param add_storage: :return: """ # Declare object to store the calculation inputs circuit = CalculationInputs(self.nbus, self.nbr, self.ntime, self.n_batt, self.n_ctrl_gen) # branches circuit.branch_rates = self.br_rates circuit.F = self.F circuit.T = self.T circuit.tap_f = self.tap_f circuit.tap_t = self.tap_t circuit.bus_names = self.bus_names circuit.branch_names = self.branch_names # connectivity matrices circuit.C_load_bus = self.C_load_bus circuit.C_batt_bus = self.C_batt_bus circuit.C_sta_gen_bus = self.C_sta_gen_bus circuit.C_ctrl_gen_bus = self.C_gen_bus circuit.C_shunt_bus = self.C_shunt_bus # needed for the tap changer circuit.is_bus_to_regulated = self.is_bus_to_regulated circuit.tap_position = self.tap_position circuit.min_tap = self.min_tap circuit.max_tap = self.max_tap circuit.tap_inc_reg_up = self.tap_inc_reg_up circuit.tap_inc_reg_down = self.tap_inc_reg_down circuit.vset = self.vset circuit.tap_ang = self.tap_ang circuit.tap_mod = self.tap_mod # active power control circuit.controlled_gen_pmin = self.generator_pmin circuit.controlled_gen_pmax = self.generator_pmax circuit.controlled_gen_enabled = self.generator_active circuit.controlled_gen_dispatchable = self.generator_dispatchable circuit.battery_pmin = self.battery_pmin circuit.battery_pmax = self.battery_pmax circuit.battery_Enom = self.battery_Enom circuit.battery_soc_0 = self.battery_soc_0 circuit.battery_discharge_efficiency = self.battery_discharge_efficiency circuit.battery_charge_efficiency = self.battery_charge_efficiency circuit.battery_min_soc = self.battery_min_soc circuit.battery_max_soc = self.battery_max_soc circuit.battery_enabled = self.battery_active circuit.battery_dispatchable = self.battery_dispatchable ################################################################################################################ # loads, generators, batteries, etc... ################################################################################################################ # Shunts Ysh = self.C_shunt_bus.T * (self.shunt_admittance / self.Sbase) # Loads S = self.C_load_bus.T * (-self.load_power / self.Sbase * self.load_active) I = self.C_load_bus.T * (-self.load_current / self.Sbase * self.load_active) Ysh += self.C_load_bus.T * (self.load_admittance / self.Sbase * self.load_active) if add_generation: # static generators S += self.C_sta_gen_bus.T * (self.static_gen_power / self.Sbase * self.static_gen_active) # generators pf2 = np.power(self.generator_power_factor, 2.0) # compute the reactive power from the active power and the power factor pf_sign = (self.generator_power_factor + 1e-20) / np.abs(self.generator_power_factor + 1e-20) Q = pf_sign * self.generator_power * np.sqrt( (1.0 - pf2) / (pf2 + 1e-20)) gen_S = self.generator_power + 1j * Q S += self.C_gen_bus.T * (gen_S / self.Sbase * self.generator_active) # batteries if add_storage: S += self.C_batt_bus.T * (self.battery_power / self.Sbase * self.battery_active) # Qmax q_max = self.C_gen_bus.T * (self.generator_qmax / self.Sbase) q_max += self.C_batt_bus.T * (self.battery_qmax / self.Sbase) # Qmin q_min = self.C_gen_bus.T * (self.generator_qmin / self.Sbase) q_min += self.C_batt_bus.T * (self.battery_qmin / self.Sbase) # assign the values circuit.Ysh = Ysh circuit.Sbus = S circuit.Ibus = I circuit.Vbus = self.V0 circuit.Sbase = self.Sbase circuit.types = self.bus_types circuit.Qmax = q_max circuit.Qmin = q_min # if there are profiles... if self.ntime > 0: # Shunts Ysh_prof = self.C_shunt_bus.T * (self.shunt_admittance_profile / self.Sbase * self.shunt_active).T # Loads I_prof = self.C_load_bus.T * (-self.load_current_profile / self.Sbase * self.load_active).T Ysh_prof += self.C_load_bus.T * (self.load_admittance_profile / self.Sbase * self.load_active).T Sbus_prof = self.C_load_bus.T * (-self.load_power_profile / self.Sbase * self.load_active).T if add_generation: # static generators Sbus_prof += self.C_sta_gen_bus.T * ( self.static_gen_power_profile / self.Sbase * self.static_gen_active).T # generators pf2 = np.power(self.generator_power_factor_profile, 2.0) # compute the reactive power from the active power and the power factor pf_sign = (self.generator_power_factor_profile + 1e-20 ) / np.abs(self.generator_power_factor_profile + 1e-20) Q = pf_sign * self.generator_power_profile * np.sqrt( (1.0 - pf2) / (pf2 + 1e-20)) gen_S = self.generator_power_profile + 1j * Q Sbus_prof += self.C_gen_bus.T * (gen_S / self.Sbase * self.generator_active).T # batteries if add_storage: Sbus_prof += self.C_batt_bus.T * (self.battery_power_profile / self.Sbase * self.battery_active).T circuit.Ysh_prof = Ysh_prof circuit.Sbus_prof = Sbus_prof circuit.Ibus_prof = I_prof circuit.time_array = self.time_array return circuit
def calc_islands(circuit: CalculationInputs, C_bus_bus, C_branch_bus, C_gen_bus, C_batt_bus, nbus, nbr, time_idx=None) -> List[CalculationInputs]: """ Partition the circuit in islands for the designated time intervals :param circuit: CalculationInputs instance with all the data regardless of the islands and the branch states :param C_bus_bus: bus-bus connectivity matrix :param C_branch_bus: branch-bus connectivity matrix :param C_gen_bus: gen-bus connectivity matrix :param C_batt_bus: battery-bus connectivity matrix :param nbus: number of buses :param nbr: number of branches :param time_idx: array with the time indices where this set of islands belongs to (if None all the time series are kept) :return: list of CalculationInputs instances """ # find the islands of the circuit islands = Graph(csc_matrix(C_bus_bus)).find_islands() # clear the list of circuits calculation_islands = list() # find the branches that belong to each island island_branches = list() if len(islands) > 1: # there are islands, pack the islands into sub circuits for island_bus_idx in islands: # get the branch indices of the island island_br_idx = get_branches_of_the_island(island_bus_idx, C_branch_bus) island_br_idx = np.sort(island_br_idx) # sort island_branches.append(island_br_idx) # indices of batteries and controlled generators that belong to this island gen_idx = np.where(C_gen_bus[:, island_bus_idx].sum(axis=0) > 0)[0] bat_idx = np.where( C_batt_bus[:, island_bus_idx].sum(axis=0) > 0)[0] # Get the island circuit (the bus types are computed automatically) # The island original indices are generated within the get_island function circuit_island = circuit.get_island(island_bus_idx, island_br_idx, gen_idx, bat_idx) if time_idx is not None: circuit_island.trim_profiles(time_idx=time_idx) # store the island calculation_islands.append(circuit_island) else: # Only one island # compile bus types circuit.consolidate() # only one island, no need to split anything calculation_islands.append(circuit) island_bus_idx = np.arange(start=0, stop=nbus, step=1, dtype=int) island_br_idx = np.arange(start=0, stop=nbr, step=1, dtype=int) # set the indices in the island too circuit.original_bus_idx = island_bus_idx circuit.original_branch_idx = island_br_idx if time_idx is not None: circuit.trim_profiles(time_idx=time_idx) # append a list with all the branch indices for completeness island_branches.append(island_br_idx) # return the list of islands return calculation_islands