Source code for monee.model.branch

from abc import ABC, abstractmethod

import numpy as np

import monee.model.phys.core.hydraulics as hydraulicsmodel
import monee.model.phys.nonlinear.gf as ogfmodel
import monee.model.phys.nonlinear.hf as ohfmodel
import monee.model.phys.nonlinear.wf as owfmodel

from .core import BranchModel, Var, model
from .grid import GasGrid, PowerGrid, WaterGrid


[docs] @model class GenericPowerBranch(BranchModel): """ No docstring provided. """ def __init__( self, tap, shift, br_r, br_x, g_fr, b_fr, g_to, b_to, max_i_ka=3.19, backup=False, on_off=1, **kwargs, ) -> None: """_summary_ Args: tap (_type_): _description_ shift (_type_): _description_ br_r (_type_): resistence br_x (_type_): reactance g_fr (_type_): from conductance b_fr (_type_): from susceptance g_to (_type_): to conductance b_to (_type_): to susceptance """ super().__init__() self.tap = tap self.shift = shift self.br_r = br_r self.br_x = br_x self.g_fr = g_fr self.b_fr = b_fr self.g_to = g_to self.b_to = b_to self.max_i_ka = max_i_ka self.backup = backup self.on_off = on_off self.p_from_mw = Var(1) self.q_from_mvar = Var(1) self.i_from_ka = Var(1) self.loading_from_percent = Var(1) self.p_to_mw = Var(1) self.q_to_mvar = Var(1) self.i_to_ka = Var(1) self.loading_to_percent = Var(1) @property def loading_percent(self): """ No docstring provided. """ return max(self.loading_to_percent.value, self.loading_from_percent.value)
[docs] def loss_percent(self): """ No docstring provided. """ return abs((self.p_from_mw.value - self.p_to_mw.value) / self.p_from_mw.value)
[docs] def equations(self, grid: PowerGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ return [ self.loading_to_percent == self.i_to_ka / self.max_i_ka, self.loading_from_percent == self.i_from_ka / self.max_i_ka, ]
[docs] @model class PowerBranch(GenericPowerBranch, ABC): """ No docstring provided. """ def __init__(self, tap, shift, backup=False, on_off=1, **kwargs) -> None: super().__init__( tap, shift, 0, 0, 0, 0, 0, 0, backup=backup, on_off=on_off, **kwargs ) self.tap = tap self.shift = shift self.p_from_mw = Var(1) self.q_from_mvar = Var(1) self.p_to_mw = Var(1) self.q_to_mvar = Var(1)
[docs] @abstractmethod def calc_r_x(self, grid, from_node_model, to_node_model): """ No docstring provided. """
[docs] def equations(self, grid: PowerGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ self.br_r, self.br_x = self.calc_r_x(grid, from_node_model, to_node_model) return super().equations(grid, from_node_model, to_node_model, **kwargs)
[docs] @model class PowerLine(PowerBranch): """ No docstring provided. """ def __init__( self, length_m, r_ohm_per_m, x_ohm_per_m, parallel, backup=False, on_off=1, **kwargs, ) -> None: super().__init__(1, 0, backup=backup, on_off=on_off, **kwargs) self.length_m = length_m self.r_ohm_per_m = r_ohm_per_m self.x_ohm_per_m = x_ohm_per_m self.parallel = parallel
[docs] def calc_r_x(self, grid: PowerGrid, from_node_model, to_node_model): """ No docstring provided. """ base_r = from_node_model.base_kv**2 / grid.sn_mva br_r = self.r_ohm_per_m * self.length_m / base_r / self.parallel br_x = self.x_ohm_per_m * self.length_m / base_r / self.parallel return (br_r, br_x)
[docs] @model class Trafo(PowerBranch): """ No docstring provided. """ def __init__( self, vk_percent=12.2, vkr_percent=0.25, sn_trafo_mva=160, shift=0 ) -> None: super().__init__(1, shift) self.vk_percent = vk_percent self.vkr_percent = vkr_percent self.sn_trafo_mva = sn_trafo_mva self.vn_trafo_lv = 1
[docs] def calc_r_x(self, grid: PowerGrid, lv_model, hv_model): """ No docstring provided. """ tap_lv = np.square(lv_model.base_kv / hv_model.base_kv) * grid.sn_mva z_sc = self.vk_percent / 100.0 / self.sn_trafo_mva * tap_lv r_sc = self.vkr_percent / 100.0 / self.sn_trafo_mva * tap_lv x_sc = np.sign(z_sc) * np.sqrt((z_sc**2 - r_sc**2).astype(float)) return (r_sc, x_sc)
[docs] def equations(self, grid: PowerGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ self.tap = 1 return super().equations(grid, from_node_model, to_node_model, **kwargs)
def sign(v): """ No docstring provided. """ return 1 if v >= 0 else -1
[docs] @model class WaterPipe(BranchModel): """ No docstring provided. """ def __init__( self, diameter_m, length_m, temperature_ext_k=283.15, roughness=4.5e-05, lambda_insulation_w_per_k=0.025, insulation_thickness_m=0.12, on_off=1, ) -> None: super().__init__() self.diameter_m = diameter_m self.length_m = length_m self.temperature_ext_k = temperature_ext_k self.pipe_roughness = roughness self.lambda_insulation_w_per_k = lambda_insulation_w_per_k self.insulation_thickness_m = insulation_thickness_m self.on_off = on_off self.mass_flow = Var(0.1) self.velocity = Var(1) self.q_w = Var(1) self.reynolds = Var(1000) self.t_average_pu = Var(1) self.t_from_pu = Var(1) self.t_to_pu = Var(1)
[docs] def loss_percent(self): """ No docstring provided. """ return abs(self.q_w.value) / ( abs(self.mass_flow.value) * ohfmodel.SPECIFIC_HEAT_CAP_WATER * self.t_average_k.value )
[docs] def equations(self, grid: WaterGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ self._pipe_area = hydraulicsmodel.calc_pipe_area(self.diameter_m) return [ hydraulicsmodel.reynolds_equation( self.reynolds, self.mass_flow, self.diameter_m, grid.dynamic_visc, self._pipe_area, kwargs["abs_impl"], ), owfmodel.darcy_weisbach_equation( from_node_model.vars["pressure_pu"] * grid.pressure_ref, to_node_model.vars["pressure_pu"] * grid.pressure_ref, self.reynolds, self.velocity, self.length_m, self.diameter_m, grid.fluid_density, self.pipe_roughness, on_off=self.on_off, **kwargs, ), hydraulicsmodel.flow_rate_equation( mean_flow_velocity=self.velocity, flow_rate=self.mass_flow, diameter=self.diameter_m, fluid_density=grid.fluid_density, ), ohfmodel.heat_transfer_loss( heat_transfer_flow_loss_var=self.q_w, t_var=self.t_average_pu * grid.t_ref, k_insulation_w_per_k=self.lambda_insulation_w_per_k, ext_t=self.temperature_ext_k, pipe_length=self.length_m, pipe_inside_radius=self.diameter_m / 2, pipe_outside_radius=self.diameter_m / 2 + self.insulation_thickness_m, ), ohfmodel.temp_flow( t_in_scaled=from_node_model.vars["t_pu"], t_out_scaled=to_node_model.vars["t_pu"], heat_loss=self.q_w / grid.t_ref, mass_flow=self.mass_flow, sign_impl=kwargs["sign_impl"], ), self.t_average_pu == (from_node_model.vars["t_pu"] + to_node_model.vars["t_pu"]) / 2, self.t_from_pu == from_node_model.vars["t_pu"], self.t_to_pu == to_node_model.vars["t_pu"], ]
[docs] @model class HeatExchanger(BranchModel): """ No docstring provided. """ def __init__( self, q_mw, diameter_m, roughness=0.0001, length_m=2.5, temperature_ext_k=293, regulation=1, ) -> None: super().__init__() self.diameter_m = diameter_m self.temperature_ext_k = temperature_ext_k self.pipe_roughness = roughness self.length_m = length_m self.limit = 0.1 self.active = True self.regulation = regulation self.on_off = 1 self.q_w_set = -q_mw * 10**6 self.q_w = Var(-1000) self.mass_flow = Var(-0.1) self.velocity = Var(-0.01) self.reynolds = Var(1000) self.t_from_pu = Var(1) self.t_to_pu = Var(1) self.t_average_pu = Var(1)
[docs] def equations(self, grid: WaterGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ self._pipe_area = hydraulicsmodel.calc_pipe_area(self.diameter_m) return [ hydraulicsmodel.reynolds_equation( self.reynolds, self.mass_flow, self.diameter_m, grid.dynamic_visc, self._pipe_area, kwargs["abs_impl"], ), owfmodel.darcy_weisbach_equation( from_node_model.vars["pressure_pu"] * grid.pressure_ref, to_node_model.vars["pressure_pu"] * grid.pressure_ref, self.reynolds, self.velocity, self.length_m, self.diameter_m, grid.fluid_density, self.pipe_roughness, on_off=self.on_off, use_darcy_friction=True, **kwargs, ), hydraulicsmodel.flow_rate_equation( mean_flow_velocity=self.velocity, flow_rate=self.mass_flow, diameter=self.diameter_m, fluid_density=grid.fluid_density, ), ohfmodel.temp_flow( t_in_scaled=from_node_model.vars["t_pu"], t_out_scaled=to_node_model.vars["t_pu"], heat_loss=self.q_w / grid.t_ref if self.active else 0, mass_flow=self.mass_flow, sign_impl=kwargs["sign_impl"], ), self.t_from_pu == from_node_model.vars["t_pu"], self.t_to_pu == to_node_model.vars["t_pu"], self.q_w == self.q_w_set * self.regulation, self.t_average_pu == (from_node_model.vars["t_pu"] + to_node_model.vars["t_pu"]) / 2, ]
[docs] @model class HeatExchangerLoad(HeatExchanger): """ No docstring provided. """ def __init__(self, q_mw, diameter_m, temperature_ext_k=293) -> None: super().__init__(q_mw, diameter_m, temperature_ext_k)
[docs] @model class HeatExchangerGenerator(HeatExchanger): """ No docstring provided. """ def __init__(self, q_mw, diameter_m, temperature_ext_k=293) -> None: super().__init__(q_mw, diameter_m, temperature_ext_k)
[docs] @model class GasPipe(BranchModel): """ No docstring provided. """ def __init__( self, diameter_m, length_m, temperature_ext_k=296.15, roughness=0.0001, on_off=1 ) -> None: super().__init__() self.diameter_m = diameter_m self.length_m = length_m self.temperature_ext_k = temperature_ext_k self.pipe_roughness = roughness self.on_off = on_off self.mass_flow = Var(0.1) self.velocity = Var(1) self.reynolds = Var(1000) self.gas_density = Var(1) self.q_w = 0
[docs] def equations(self, grid: GasGrid, from_node_model, to_node_model, **kwargs): """ No docstring provided. """ self._pipe_area = hydraulicsmodel.calc_pipe_area(self.diameter_m) return [ hydraulicsmodel.reynolds_equation( self.reynolds, self.mass_flow, self.diameter_m, grid.dynamic_visc, self._pipe_area, kwargs["abs_impl"], ), ogfmodel.pipe_weymouth( from_node_model.vars["pressure_pu"] * grid.pressure_ref, to_node_model.vars["pressure_pu"] * grid.pressure_ref, f_a=self.mass_flow, rey=self.reynolds, diameter_m=self.diameter_m, roughness=self.pipe_roughness, length_m=self.length_m, t_k=grid.t_k, compressibility=grid.compressibility, on_off=self.on_off, **kwargs, ), hydraulicsmodel.flow_rate_equation( mean_flow_velocity=self.velocity, flow_rate=self.mass_flow, diameter=self.diameter_m, fluid_density=self.gas_density, ), self.gas_density == grid.pressure_ref * (from_node_model.vars["pressure_pu"] + to_node_model.vars["pressure_pu"]) / 2 * grid.molar_mass / (grid.universal_gas_constant * grid.t_k), ]