import math
from .core import Intermediate, IntermediateEq, NodeModel, Var, model
from .phys.core.hydraulics import junction_mass_flow_balance
from .phys.nonlinear.ac import power_balance_equation
[docs]
@model
class Bus(NodeModel):
"""
No docstring provided.
"""
def __init__(self, base_kv) -> None:
super().__init__()
self.base_kv = base_kv
self.vm_pu = Var(1, min=0, name="vm_pu")
self.vm_pu_squared = Var(1, min=0, name="vm_pu_squared")
self.va_radians = Var(0, name="va_radians")
self.va_degree = Intermediate()
self.p_mw = Intermediate()
self.q_mvar = Intermediate()
[docs]
def calc_signed_power_values(
self, from_branch_models, to_branch_models, connected_node_models
):
"""
No docstring provided.
"""
signed_active_power = (
[
model.vars["p_from_mw"] * model.vars["on_off"]
for model in from_branch_models
]
+ [
model.vars["p_to_mw"] * model.vars["on_off"]
for model in to_branch_models
]
+ [
model.vars["p_mw"] * model.vars["regulation"]
for model in connected_node_models
]
)
signed_reactive_power = (
[
model.vars["q_from_mvar"] * model.vars["on_off"]
for model in from_branch_models
]
+ [
model.vars["q_to_mvar"] * model.vars["on_off"]
for model in to_branch_models
]
+ [
model.vars["q_mvar"] * model.vars["regulation"]
for model in connected_node_models
]
)
return (signed_active_power, signed_reactive_power)
[docs]
def p_mw_equation(self, child_models):
"""
No docstring provided.
"""
return IntermediateEq(
"p_mw",
sum(
[
model.vars["p_mw"] * model.vars["regulation"]
for model in child_models
]
),
)
[docs]
def q_mvar_equation(self, child_models):
"""
No docstring provided.
"""
return IntermediateEq(
"q_mvar",
sum(
[
model.vars["q_mvar"] * model.vars["regulation"]
for model in child_models
]
),
)
[docs]
def equations(
self,
grid,
from_branch_models,
to_branch_models,
connected_node_models,
**kwargs,
):
"""
No docstring provided.
"""
signed_ap, signed_rp = self.calc_signed_power_values(
from_branch_models, to_branch_models, connected_node_models
)
return [
self.p_mw_equation(connected_node_models),
self.q_mvar_equation(connected_node_models),
power_balance_equation(signed_ap),
power_balance_equation(signed_rp),
IntermediateEq("va_degree", 180 / math.pi * self.va_radians),
]
[docs]
@model
class Junction(NodeModel):
"""
No docstring provided.
"""
def __init__(self) -> None:
self.t_k = Intermediate()
self.t_pu = Var(1, min=0, max=2, name="t_pu")
self.pressure_squared_pu = Var(1, min=0, max=2, name="p_squared_pu")
self.pressure_pu = Var(1, min=0, max=2, name="p_pu")
self.mass_flow = Intermediate(1)
[docs]
def calc_signed_mass_flow(
self, from_branch_models, to_branch_models, connected_node_models
):
"""
No docstring provided.
"""
return (
[
model.vars["from_mass_flow"] * model.vars["on_off"]
for model in from_branch_models
if "from_mass_flow" in model.vars
]
+ [
model.vars["to_mass_flow"] * model.vars["on_off"]
for model in to_branch_models
if "to_mass_flow" in model.vars
]
+ [
-model.vars["mass_flow_pos"] * model.vars["on_off"]
for model in from_branch_models
if "mass_flow_pos" in model.vars
]
+ [
model.vars["mass_flow_pos"] * model.vars["on_off"]
for model in to_branch_models
if "mass_flow_pos" in model.vars
]
+ [
model.vars["mass_flow_neg"] * model.vars["on_off"]
for model in from_branch_models
if "mass_flow_neg" in model.vars
]
+ [
-model.vars["mass_flow_neg"] * model.vars["on_off"]
for model in to_branch_models
if "mass_flow_neg" in model.vars
]
+ [
model.vars["mass_flow"] * model.vars["regulation"]
for model in connected_node_models
if "mass_flow" in model.vars
]
)
[docs]
def calc_signed_heat_flow(
self, from_branch_models, to_branch_models, connected_node_models, grid
):
"""
No docstring provided.
"""
temp_supported = (
len(from_branch_models) > 0
and "t_to_pu" in from_branch_models[0].vars
or (len(to_branch_models) > 0 and "t_to_pu" in to_branch_models[0].vars)
)
if temp_supported:
Tn = self.t_pu
terms = []
# node is FROM-end of these branches (branch orientation: this node -> other node)
for bm in from_branch_models:
if "mass_flow_pos" not in bm.vars or "mass_flow_neg" not in bm.vars:
continue
mpos = bm.vars["mass_flow_pos"] * bm.vars.get("on_off", 1)
mneg = bm.vars["mass_flow_neg"] * bm.vars.get("on_off", 1)
Tin = bm.vars["t_from_pu"]
Tout = self.t_pu * bm.vars.get("on_off", 1)
terms.append(mneg * Tout - mpos * Tin)
# node is TO-end of these branches (branch orientation: other node -> this node)
for bm in to_branch_models:
if "mass_flow_pos" not in bm.vars or "mass_flow_neg" not in bm.vars:
continue
mpos = bm.vars["mass_flow_pos"] * bm.vars.get("on_off", 1)
mneg = bm.vars["mass_flow_neg"] * bm.vars.get("on_off", 1)
Tin = bm.vars["t_to_pu"] # inflow at to-end
Tout = self.t_pu * bm.vars.get("on_off", 1)
terms.append(-mneg * Tin + mpos * Tout)
for nm in connected_node_models:
if "mass_flow" not in nm.vars:
continue
m_ext = nm.vars["mass_flow"] * nm.vars.get("regulation", 1)
terms.append(m_ext * Tn)
return terms
else:
return [0]
[docs]
def equations(
self,
grid,
from_branch_models,
to_branch_models,
connected_node_models,
**kwargs,
):
"""
No docstring provided.
"""
mass_flow_signed_list = self.calc_signed_mass_flow(
from_branch_models, to_branch_models, connected_node_models
)
energy_flow_list = self.calc_signed_heat_flow(
from_branch_models, to_branch_models, connected_node_models, grid
)
if mass_flow_signed_list:
return [
junction_mass_flow_balance(mass_flow_signed_list),
junction_mass_flow_balance(energy_flow_list),
IntermediateEq("t_k", self.t_pu * grid.t_ref),
IntermediateEq(
"mass_flow",
sum(
[
model.vars["mass_flow"] * model.vars["regulation"]
for model in connected_node_models
if "mass_flow" in model.vars
]
),
),
]
return []