diff --git a/src/omotes_simulator_core/adapter/transforms/controller_mapper.py b/src/omotes_simulator_core/adapter/transforms/controller_mapper.py
index 8fdfaaa3..be785de9 100644
--- a/src/omotes_simulator_core/adapter/transforms/controller_mapper.py
+++ b/src/omotes_simulator_core/adapter/transforms/controller_mapper.py
@@ -158,9 +158,15 @@ def to_entity(
"The network is looped via the heat pumps and heat exchangers, "
"which is not supported."
)
+ # find first networks with no buffers
+ for j in range(len(networks)):
+ if not networks[j].storages:
+ break
- for i in range(1, len(networks)):
- networks[i].path = graph.get_path(str(i), "0")
+ for i in range(len(networks)):
+ if i == j:
+ continue
+ networks[i].path = graph.get_path(str(i), str(j))
if len(networks[i].path) > 3:
raise RuntimeError(
"The network is connected via more then two stages which is not supported."
diff --git a/src/omotes_simulator_core/entities/assets/asset_abstract.py b/src/omotes_simulator_core/entities/assets/asset_abstract.py
index 3378041f..023af64a 100644
--- a/src/omotes_simulator_core/entities/assets/asset_abstract.py
+++ b/src/omotes_simulator_core/entities/assets/asset_abstract.py
@@ -45,8 +45,6 @@ class AssetAbstract(ABC):
connected_ports: list[str]
"""List of ids of the connected ports."""
- solver_asset: BaseAsset
- """The asset object use for the solver."""
asset_type = "asset_abstract"
"""The type of the asset."""
number_of_con_points: int = 2
diff --git a/src/omotes_simulator_core/entities/assets/asset_defaults.py b/src/omotes_simulator_core/entities/assets/asset_defaults.py
index d5b2eb91..503fe5c4 100644
--- a/src/omotes_simulator_core/entities/assets/asset_defaults.py
+++ b/src/omotes_simulator_core/entities/assets/asset_defaults.py
@@ -130,6 +130,7 @@ class HeatBufferDefaults:
PROPERTY_VELOCITY_SUPPLY = "velocity_supply"
PROPERTY_VELOCITY_RETURN = "velocity_return"
PROPERTY_SET_PRESSURE = "set_pressure"
+PROPERTY_BYPASS = "bypass"
PROPERTY_LENGTH = "length"
PROPERTY_DIAMETER = "diameter"
PROPERTY_ROUGHNESS = "roughness"
diff --git a/src/omotes_simulator_core/entities/assets/ates_cluster.py b/src/omotes_simulator_core/entities/assets/ates_cluster.py
index e024335d..80d31553 100644
--- a/src/omotes_simulator_core/entities/assets/ates_cluster.py
+++ b/src/omotes_simulator_core/entities/assets/ates_cluster.py
@@ -147,9 +147,9 @@ def _calculate_massflowrate(self) -> None:
def _set_solver_asset_setpoint(self) -> None:
"""Set the setpoint of solver asset."""
if self.mass_flowrate >= 0:
- self.solver_asset.supply_temperature = self.cold_well_temperature # injection
- else:
self.solver_asset.supply_temperature = self.hot_well_temperature # production
+ else:
+ self.solver_asset.supply_temperature = self.cold_well_temperature # injection
self.solver_asset.mass_flow_rate_set_point = self.mass_flowrate # type: ignore
def set_setpoints(self, setpoints: dict) -> None:
@@ -158,9 +158,7 @@ def set_setpoints(self, setpoints: dict) -> None:
:param Dict setpoints: The setpoints that should be set for the asset.
The keys of the dictionary are the names of the setpoints and the values are the values
"""
- if self.current_time == self.time:
- return
- self.current_time = self.time
+
# Default keys required
necessary_setpoints = {
PROPERTY_TEMPERATURE_IN,
@@ -171,23 +169,30 @@ def set_setpoints(self, setpoints: dict) -> None:
setpoints_set = set(setpoints.keys())
# Check if all setpoints are in the setpoints
if necessary_setpoints.issubset(setpoints_set):
- self.thermal_power_allocation = -1 * setpoints[PROPERTY_HEAT_DEMAND]
+ self.thermal_power_allocation = -setpoints[PROPERTY_HEAT_DEMAND]
if self.first_time_step:
- self.temperature_in = setpoints[PROPERTY_TEMPERATURE_IN]
- self.temperature_out = setpoints[PROPERTY_TEMPERATURE_OUT]
+ if self.thermal_power_allocation >= 0:
+ self.temperature_in = setpoints[PROPERTY_TEMPERATURE_OUT]
+ self.temperature_out = setpoints[PROPERTY_TEMPERATURE_IN]
+ else:
+ self.temperature_in = setpoints[PROPERTY_TEMPERATURE_IN]
+ self.temperature_out = setpoints[PROPERTY_TEMPERATURE_OUT]
self.first_time_step = False
else:
# After the first time step: use solver temperature
if self.thermal_power_allocation >= 0:
+ self.temperature_out = self.solver_asset.get_temperature(0)
self.temperature_in = self.hot_well_temperature
- self.temperature_out = self.solver_asset.get_temperature(1)
else:
- self.temperature_in = self.solver_asset.get_temperature(0)
- self.temperature_out = self.cold_well_temperature
+ self.temperature_in = self.cold_well_temperature
+ self.temperature_out = self.solver_asset.get_temperature(1)
self._calculate_massflowrate()
- self._run_rosim()
+ if self.current_time != self.time:
+ self._run_rosim()
+ self.current_time = self.time
self._set_solver_asset_setpoint()
+
else:
# Print missing setpoints
logger.error(
@@ -279,7 +284,7 @@ def _init_rosim(self) -> None:
}
# initially charging 12 weeks with 85-35 temperature 1 MW
logger.info("initializing ates with charging for 12 weeks")
- for i in range(12):
+ for i in range(0):
logger.info(f"charging ates week {i + 1}")
self.set_time_step(3600 * 24 * 7)
self.set_time(datetime(2023, 1, i + 1, 0, 0, 0))
@@ -315,3 +320,21 @@ def _run_rosim(self) -> None:
self.hot_well_temperature = celcius_to_kelvin(ates_temperature[0]) # convert to K
self.cold_well_temperature = celcius_to_kelvin(ates_temperature[1]) # convert to K
+
+ def get_heat_supplied(self) -> float:
+ """Get the actual heat supplied by the asset.
+
+ :return float: The actual heat supplied by the asset [W].
+ """
+ return (
+ self.solver_asset.get_internal_energy(1) - self.solver_asset.get_internal_energy(0)
+ ) * self.solver_asset.get_mass_flow_rate(0)
+
+ def is_converged(self) -> bool:
+ """Check if the asset has converged with accepted error of 0.1%.
+
+ :return: True if the asset has converged, False otherwise
+ """
+ return abs(self.get_heat_supplied() - self.thermal_power_allocation) < (
+ abs(self.thermal_power_allocation) * 0.001
+ )
diff --git a/src/omotes_simulator_core/entities/assets/controller/controller_heat_transfer.py b/src/omotes_simulator_core/entities/assets/controller/controller_heat_transfer.py
index f7ce1e68..acc83587 100644
--- a/src/omotes_simulator_core/entities/assets/controller/controller_heat_transfer.py
+++ b/src/omotes_simulator_core/entities/assets/controller/controller_heat_transfer.py
@@ -14,14 +14,13 @@
# along with this program. If not, see .
"""Module containing the class for a heat trasnfer asset."""
-import numpy as np
-
from omotes_simulator_core.entities.assets.asset_defaults import (
PRIMARY,
PROPERTY_HEAT_DEMAND,
PROPERTY_SET_PRESSURE,
PROPERTY_TEMPERATURE_IN,
PROPERTY_TEMPERATURE_OUT,
+ PROPERTY_BYPASS,
SECONDARY,
)
from omotes_simulator_core.entities.assets.controller.asset_controller_abstract import (
@@ -41,26 +40,39 @@ def __init__(self, name: str, identifier: str, factor: float):
super().__init__(name, identifier)
self.factor = factor
- def set_asset(self, heat_demand: float) -> dict[str, dict[str, float]]:
+ def set_asset(self, heat_demand: float, bypass: bool = False) -> dict[str, dict[str, float]]:
"""Method to set the asset to the given heat demand.
The supply and return temperatures are also set.
:param float heat_demand: Heat demand to set.
+ :param bypass: When true the heat exchange is bypassed, so the heat demand is not
+ reduced by the factor. Default is False.
"""
- # TODO set correct values also for prim and secondary side.
- return {
- self.id: {
- PRIMARY + PROPERTY_HEAT_DEMAND: heat_demand,
- PRIMARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 30,
- PRIMARY + PROPERTY_TEMPERATURE_IN: 273.15 + 40,
- SECONDARY
- + PROPERTY_HEAT_DEMAND: np.abs(heat_demand)
- * self.factor
- * (
- np.sign(heat_demand) * -1
- ), # Invert sign of secondary heat demand, as it is opposite to primary side.
- SECONDARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 80,
- SECONDARY + PROPERTY_TEMPERATURE_IN: 273.15 + 50,
- PROPERTY_SET_PRESSURE: False,
+ if bypass:
+ return {
+ self.id: {
+ PRIMARY + PROPERTY_HEAT_DEMAND: heat_demand,
+ PRIMARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 80,
+ PRIMARY + PROPERTY_TEMPERATURE_IN: 273.15 + 50,
+ SECONDARY + PROPERTY_HEAT_DEMAND: heat_demand * -1,
+ SECONDARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 80,
+ SECONDARY + PROPERTY_TEMPERATURE_IN: 273.15 + 50,
+ SECONDARY + PROPERTY_SET_PRESSURE: False,
+ PRIMARY + PROPERTY_SET_PRESSURE: False,
+ PROPERTY_BYPASS: True,
+ }
+ }
+ else:
+ return {
+ self.id: {
+ PRIMARY + PROPERTY_HEAT_DEMAND: heat_demand / self.factor,
+ PRIMARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 30,
+ PRIMARY + PROPERTY_TEMPERATURE_IN: 273.15 + 50,
+ SECONDARY + PROPERTY_HEAT_DEMAND: -heat_demand,
+ SECONDARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 80,
+ SECONDARY + PROPERTY_TEMPERATURE_IN: 273.15 + 40,
+ SECONDARY + PROPERTY_SET_PRESSURE: False,
+ PRIMARY + PROPERTY_SET_PRESSURE: False,
+ PROPERTY_BYPASS: False,
+ }
}
- }
diff --git a/src/omotes_simulator_core/entities/assets/controller/controller_network.py b/src/omotes_simulator_core/entities/assets/controller/controller_network.py
index 17442f89..ce1fb017 100644
--- a/src/omotes_simulator_core/entities/assets/controller/controller_network.py
+++ b/src/omotes_simulator_core/entities/assets/controller/controller_network.py
@@ -16,11 +16,15 @@
import datetime
+from numpy.ma.core import product
+
from omotes_simulator_core.entities.assets.asset_defaults import (
PROPERTY_HEAT_DEMAND,
PROPERTY_SET_PRESSURE,
PROPERTY_TEMPERATURE_IN,
PROPERTY_TEMPERATURE_OUT,
+ SECONDARY,
+ PRIMARY,
)
from omotes_simulator_core.entities.assets.controller.controller_consumer import ControllerConsumer
from omotes_simulator_core.entities.assets.controller.controller_heat_transfer import (
@@ -49,7 +53,7 @@ class ControllerNetwork:
"""List of all producers in the network."""
storages: list[ControllerAtesStorage | ControllerIdealHeatStorage]
"""List of all storages in the network."""
- factor_to_first_network: float
+ factor_to_first_network: list[float]
"""Factor to calculate power in the first network in the list of networks."""
path: list[str]
"""Path from this network to the first network in the total system."""
@@ -69,7 +73,7 @@ def __init__(
self.consumers = consumers_in
self.producers = producers_in
self.storages = storages_in
- self.factor_to_first_network = factor_to_first_network
+ self.factor_to_first_network = [factor_to_first_network]
self.path: list[str] = []
def exists(self, identifier: str) -> bool:
@@ -91,9 +95,9 @@ def exists(self, identifier: str) -> bool:
def get_total_heat_demand(self, time: datetime.datetime) -> float:
"""Method which the total heat demand at the given time corrected to the first network."""
- return (
+ return float(
sum([consumer.get_heat_demand(time) for consumer in self.consumers])
- * self.factor_to_first_network
+ * product(self.factor_to_first_network)
)
def get_total_discharge_storage(self) -> float:
@@ -101,9 +105,9 @@ def get_total_discharge_storage(self) -> float:
:return float: Total heat discharge of all storages.
"""
- return (
- float(sum([storage.effective_max_discharge_power for storage in self.storages]))
- * self.factor_to_first_network
+ return float(
+ sum([storage.effective_max_discharge_power for storage in self.storages])
+ * product(self.factor_to_first_network)
)
def get_total_charge_storage(self) -> float:
@@ -111,9 +115,9 @@ def get_total_charge_storage(self) -> float:
:return float: Total heat charge of all storages.
"""
- return (
- float(sum([storage.effective_max_charge_power for storage in self.storages]))
- * self.factor_to_first_network
+ return float(
+ sum([storage.effective_max_charge_power for storage in self.storages])
+ * product(self.factor_to_first_network)
)
def get_total_supply(self) -> float:
@@ -121,9 +125,9 @@ def get_total_supply(self) -> float:
:return float: Total heat supply of all producers.
"""
- return (
- float(sum([producer.power for producer in self.producers]))
- * self.factor_to_first_network
+ return float(
+ sum([producer.power for producer in self.producers])
+ * product(self.factor_to_first_network)
)
def set_supply_to_max(self, priority: int = 0) -> dict:
@@ -166,6 +170,8 @@ def set_storage_charge_power(self, factor: float = 1) -> dict:
for storage in self.storages:
storage_settings[storage.id] = {
PROPERTY_HEAT_DEMAND: +1 * storage.effective_max_charge_power * factor,
+ PROPERTY_TEMPERATURE_OUT: storage.temperature_out,
+ PROPERTY_TEMPERATURE_IN: storage.temperature_in,
}
return storage_settings
@@ -180,6 +186,8 @@ def set_storage_discharge_power(self, factor: float = 1) -> dict:
# Discharging is negative (e.g., heat from component/system to the network)
storage_settings[storage.id] = {
PROPERTY_HEAT_DEMAND: -1 * storage.effective_max_discharge_power * factor,
+ PROPERTY_TEMPERATURE_OUT: storage.temperature_out,
+ PROPERTY_TEMPERATURE_IN: storage.temperature_in,
}
return storage_settings
@@ -226,15 +234,17 @@ def get_total_supply_priority(self, priority: int) -> float:
sum([producer.power for producer in self.producers if producer.priority == priority])
)
- def set_pressure(self) -> str:
- """Returns the id of the asset for which the pressure can be set for this network.
+ def set_pressure(self) -> tuple[str, str]:
+ """Returns the id of the asset for which the pressure can be set for this network and the key in the set points dict.
The controller needs to set per hydraulic separated part of the system the pressure.
The network can thus pass back the id for which asset the pressure needs to be set.
The controller can then do this.
"""
- if self.heat_transfer_assets_sec:
- return self.heat_transfer_assets_sec[0].id
if self.producers:
- return self.producers[0].id
+ return (self.producers[0].id, PROPERTY_SET_PRESSURE)
+ if self.heat_transfer_assets_sec:
+ return (self.heat_transfer_assets_sec[0].id, SECONDARY + PROPERTY_SET_PRESSURE)
+ if self.heat_transfer_assets_prim:
+ return (self.heat_transfer_assets_prim[0].id, PRIMARY + PROPERTY_SET_PRESSURE)
raise ValueError("No asset found for which the pressure can be set.")
diff --git a/src/omotes_simulator_core/entities/assets/demand_cluster.py b/src/omotes_simulator_core/entities/assets/demand_cluster.py
index 94a9ae0b..84a8078d 100644
--- a/src/omotes_simulator_core/entities/assets/demand_cluster.py
+++ b/src/omotes_simulator_core/entities/assets/demand_cluster.py
@@ -134,6 +134,6 @@ def is_converged(self) -> bool:
:return: True if the asset has converged, False otherwise
"""
- return abs(self.get_heat_supplied() - (-self.thermal_power_allocation)) < (
- (-self.thermal_power_allocation) * 0.001
+ return abs(self.get_heat_supplied() - self.thermal_power_allocation) < (
+ self.thermal_power_allocation * 0.001
)
diff --git a/src/omotes_simulator_core/entities/assets/heat_exchanger.py b/src/omotes_simulator_core/entities/assets/heat_exchanger.py
index 42a89599..a807dd73 100644
--- a/src/omotes_simulator_core/entities/assets/heat_exchanger.py
+++ b/src/omotes_simulator_core/entities/assets/heat_exchanger.py
@@ -210,7 +210,7 @@ def write_to_output(self) -> None:
self.solver_asset.get_heat_power_primary() # type: ignore
),
PROPERTY_HEAT_LOSS: (
- self.solver_asset.get_heat_power_primary() # type: ignore
+ -self.solver_asset.get_heat_power_primary() # type: ignore
- self.solver_asset.get_heat_power_secondary() # type: ignore
),
}
diff --git a/src/omotes_simulator_core/entities/assets/heat_pump.py b/src/omotes_simulator_core/entities/assets/heat_pump.py
index 6f298ab4..6b266152 100644
--- a/src/omotes_simulator_core/entities/assets/heat_pump.py
+++ b/src/omotes_simulator_core/entities/assets/heat_pump.py
@@ -29,6 +29,7 @@
PROPERTY_TEMPERATURE_IN,
PROPERTY_TEMPERATURE_OUT,
SECONDARY,
+ PROPERTY_BYPASS,
)
from omotes_simulator_core.entities.assets.utils import heat_demand_and_temperature_to_mass_flow
from omotes_simulator_core.solver.network.assets.heat_transfer_asset import HeatTransferAsset
@@ -63,6 +64,12 @@ class HeatPump(AssetAbstract):
and the pressure is predescribed.
"""
+ control_mass_flow_primary: bool
+ """Flag to indicate whether the mass flow rate on the primary side is controlled.
+ If True, the mass flow rate is controlled. If False, the mass flow rate is not controlled
+ and the pressure is predescribed.
+ """
+
coefficient_of_performance: float
"""Coefficient of perfomance for the heat pump."""
@@ -95,6 +102,7 @@ def __init__(
pressure_set_point_secondary=DEFAULT_PRESSURE,
heat_transfer_coefficient=self.coefficient_of_performance,
)
+ self.first_time_step = True
def _set_setpoints_secondary(self, setpoints_secondary: Dict) -> None:
"""The secondary side of the heat pump acts as a producer of heat.
@@ -110,7 +118,8 @@ def _set_setpoints_secondary(self, setpoints_secondary: Dict) -> None:
SECONDARY + PROPERTY_TEMPERATURE_IN,
SECONDARY + PROPERTY_TEMPERATURE_OUT,
SECONDARY + PROPERTY_HEAT_DEMAND,
- PROPERTY_SET_PRESSURE,
+ SECONDARY + PROPERTY_SET_PRESSURE,
+ PROPERTY_BYPASS,
}
# Dict to set
setpoints_set = set(setpoints_secondary.keys())
@@ -122,24 +131,34 @@ def _set_setpoints_secondary(self, setpoints_secondary: Dict) -> None:
)
# Assign setpoints to the HeatPump asset
- self.temperature_in_secondary = setpoints_secondary[SECONDARY + PROPERTY_TEMPERATURE_IN]
+ if self.first_time_step or self.solver_asset.prev_sol[0] == 0.0:
+ self.temperature_in_secondary = setpoints_secondary[SECONDARY + PROPERTY_TEMPERATURE_IN]
+ else:
+ self.temperature_in_secondary = self.solver_asset.get_temperature(0)
+
+ # self.temperature_in_secondary = setpoints_secondary[SECONDARY + PROPERTY_TEMPERATURE_IN]
self.temperature_out_secondary = setpoints_secondary[SECONDARY + PROPERTY_TEMPERATURE_OUT]
- self.mass_flow_secondary = heat_demand_and_temperature_to_mass_flow(
+ self.mass_flow_secondary = -heat_demand_and_temperature_to_mass_flow(
thermal_demand=setpoints_secondary[SECONDARY + PROPERTY_HEAT_DEMAND],
temperature_in=self.temperature_in_secondary,
temperature_out=self.temperature_out_secondary,
)
- self.control_mass_flow_secondary = not (setpoints_secondary[PROPERTY_SET_PRESSURE])
+ self.control_mass_flow_secondary = not (
+ setpoints_secondary[SECONDARY + PROPERTY_SET_PRESSURE]
+ )
# Assign setpoints to the HeatTransferAsset solver asset
self.solver_asset.temperature_in_secondary = self.temperature_in_secondary # type: ignore
self.solver_asset.temperature_out_secondary = ( # type: ignore
self.temperature_out_secondary
)
- self.solver_asset.mass_flow_rate_secondary = self.mass_flow_secondary # type: ignore
+ self.solver_asset.mass_flow_rate_rate_set_point_secondary = (
+ self.mass_flow_secondary
+ ) # type: ignore
self.solver_asset.pre_scribe_mass_flow_secondary = ( # type: ignore
self.control_mass_flow_secondary
)
+ self.solver_asset.bypass_mode = setpoints_secondary[PROPERTY_BYPASS] # type: ignore
def _set_setpoints_primary(self, setpoints_primary: Dict) -> None:
"""The primary side of the heat pump acts as a consumer of heat.
@@ -158,6 +177,7 @@ def _set_setpoints_primary(self, setpoints_primary: Dict) -> None:
PRIMARY + PROPERTY_TEMPERATURE_IN,
PRIMARY + PROPERTY_TEMPERATURE_OUT,
PRIMARY + PROPERTY_HEAT_DEMAND,
+ PRIMARY + PROPERTY_SET_PRESSURE,
}
# Dict to set
setpoints_set = set(setpoints_primary.keys())
@@ -169,13 +189,19 @@ def _set_setpoints_primary(self, setpoints_primary: Dict) -> None:
)
# Assign setpoints to the HeatPump asset
- self.temperature_in_primary = setpoints_primary[PRIMARY + PROPERTY_TEMPERATURE_IN]
+ if self.first_time_step or self.solver_asset.prev_sol[0] == 0.0:
+ self.temperature_in_primary = setpoints_primary[SECONDARY + PROPERTY_TEMPERATURE_IN]
+ else:
+ self.temperature_in_primary = self.solver_asset.get_temperature(0)
+
+ # self.temperature_in_primary = setpoints_primary[PRIMARY + PROPERTY_TEMPERATURE_IN]
self.temperature_out_primary = setpoints_primary[PRIMARY + PROPERTY_TEMPERATURE_OUT]
- self.mass_flow_initialization_primary = heat_demand_and_temperature_to_mass_flow(
+ self.mass_flow_initialization_primary = -heat_demand_and_temperature_to_mass_flow(
thermal_demand=setpoints_primary[PRIMARY + PROPERTY_HEAT_DEMAND],
temperature_in=self.temperature_in_primary,
temperature_out=self.temperature_out_primary,
)
+ self.control_mass_flow_primary = not (setpoints_primary[PRIMARY + PROPERTY_SET_PRESSURE])
# Assign setpoints to the HeatTransferAsset solver asset
self.solver_asset.temperature_in_primary = self.temperature_in_primary # type: ignore
@@ -183,6 +209,9 @@ def _set_setpoints_primary(self, setpoints_primary: Dict) -> None:
self.solver_asset.mass_flow_initialization_primary = ( # type: ignore
self.mass_flow_initialization_primary
)
+ self.solver_asset.pre_scribe_mass_flow_primary = ( # type: ignore
+ self.control_mass_flow_primary
+ )
def set_setpoints(self, setpoints: Dict) -> None:
"""Placeholder to set the setpoints of an asset prior to a simulation.
@@ -194,6 +223,7 @@ def set_setpoints(self, setpoints: Dict) -> None:
self._set_setpoints_primary(setpoints_primary=setpoints)
# Set the setpoints for the secondary side of the heat pump
self._set_setpoints_secondary(setpoints_secondary=setpoints)
+ self.first_time_step = False
def write_to_output(self) -> None:
"""Get output power and electricity consumption of the asset.
diff --git a/src/omotes_simulator_core/entities/assets/production_cluster.py b/src/omotes_simulator_core/entities/assets/production_cluster.py
index 24567386..74fbcecb 100644
--- a/src/omotes_simulator_core/entities/assets/production_cluster.py
+++ b/src/omotes_simulator_core/entities/assets/production_cluster.py
@@ -124,8 +124,8 @@ def _set_heat_demand(self, heat_demand: float) -> None:
"""
# Calculate the mass flow rate
self.heat_demand_set_point = heat_demand
- self.controlled_mass_flow = heat_demand_and_temperature_to_mass_flow(
- thermal_demand=-1 * heat_demand,
+ self.controlled_mass_flow = -heat_demand_and_temperature_to_mass_flow(
+ thermal_demand=heat_demand,
temperature_in=self.temperature_in,
temperature_out=self.temperature_out,
)
@@ -248,7 +248,7 @@ def is_converged(self) -> bool:
:return: True if the asset has converged, False otherwise
"""
if self.solver_asset.pre_scribe_mass_flow: # type: ignore
- return abs(self.get_actual_heat_supplied() - self.heat_demand_set_point) < (
+ return abs(self.get_actual_heat_supplied() + self.heat_demand_set_point) < (
abs(self.heat_demand_set_point * 0.001)
)
else:
diff --git a/src/omotes_simulator_core/entities/assets/utils.py b/src/omotes_simulator_core/entities/assets/utils.py
index be434324..128c72e8 100644
--- a/src/omotes_simulator_core/entities/assets/utils.py
+++ b/src/omotes_simulator_core/entities/assets/utils.py
@@ -35,8 +35,9 @@ def heat_demand_and_temperature_to_mass_flow(
:param float temperature_in: The temperature that the asset receives from the
"from_junction". The temperature should be supplied in Kelvin.
"""
- heat_capacity = fluid_props.get_heat_capacity((temperature_in + temperature_out) / 2)
- return thermal_demand / ((temperature_out - temperature_in) * float(heat_capacity))
+ internal_energy1 = fluid_props.get_ie(temperature_in)
+ internal_energy2 = fluid_props.get_ie(temperature_out)
+ return thermal_demand / (internal_energy2 - internal_energy1)
def mass_flow_and_temperature_to_heat_demand(
diff --git a/src/omotes_simulator_core/entities/network_controller.py b/src/omotes_simulator_core/entities/network_controller.py
index 7e5d5392..e0e90c1e 100644
--- a/src/omotes_simulator_core/entities/network_controller.py
+++ b/src/omotes_simulator_core/entities/network_controller.py
@@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-"""Module for new controller which can also cope with Heat pumps and heat exchangers."""
+"""Module for controller which can also cope with Heat pumps and heat exchangers."""
import datetime
import logging
@@ -53,20 +53,19 @@ def update_networks_factor(self) -> None:
"""Method to update the factor of the networks taken into account the changing COP."""
for network in self.networks:
current_network = network
- network.factor_to_first_network = 1
+ network.factor_to_first_network = [1]
for step in network.path:
if current_network == self.networks[int(step)]:
continue
for asset in current_network.heat_transfer_assets_prim:
if self.networks[int(step)].exists(asset.id):
- network.factor_to_first_network *= asset.factor
- current_network = self.networks[int(step)]
+ network.factor_to_first_network.append(asset.factor)
break
for asset in current_network.heat_transfer_assets_sec:
if self.networks[int(step)].exists(asset.id):
- network.factor_to_first_network /= asset.factor
- current_network = self.networks[int(step)]
+ network.factor_to_first_network.append(1 / asset.factor)
break
+ current_network = self.networks[int(step)]
def update_setpoints(self, time: datetime.datetime) -> dict:
"""Method to get the controller inputs for the network.
@@ -86,52 +85,53 @@ def update_setpoints(self, time: datetime.datetime) -> dict:
self.update_networks_factor()
total_demand = sum([network.get_total_heat_demand(time) for network in self.networks])
total_supply = sum([network.get_total_supply() for network in self.networks])
- total_charge_storage = sum(
- [network.get_total_charge_storage() for network in self.networks]
- )
- total_discharge_storage = sum(
- [network.get_total_discharge_storage() for network in self.networks]
- )
# Initialize the producer, consumer, and storage setpoints dicts.
producer_setpoints: AssetSetpointsDict = {}
consumer_setpoints: AssetSetpointsDict = {}
storage_setpoints: AssetSetpointsDict = {}
-
- if (total_supply + total_discharge_storage) <= total_demand:
- logger.warning(
- "Total supply + storage is lower than total demand at time: %s"
- "Consumers are capped to the available power.",
- time,
+ if total_supply > total_demand:
+ # total supply is larger than demand, so demand can be set to required demand.
+ consumer_setpoints = self._set_consumer_to_demand(time)
+ surplus_supply = total_supply - total_demand
+ # Check charge capacity from storage
+ total_charge_storage = sum(
+ [network.get_total_charge_storage() for network in self.networks]
)
- factor = (total_supply + total_discharge_storage) / total_demand
- # Define setpoints
- producer_setpoints = self._set_producers_to_max()
- storage_setpoints = self._set_all_storages_discharge_to_max()
- consumer_setpoints = self._set_consumer_to_demand(time, factor=factor)
+ if total_charge_storage > surplus_supply:
+ # there is more charge capacity than surplus supply, so we can set source to
+ # max and storages to charge with the surplus supply.
+ producer_setpoints = self._set_producers_to_max()
+ storage_setpoints = self._set_storages_charge_power(surplus_supply)
+ else:
+ # The storage can charge to max. The sources need to be capped.
+ storage_setpoints = self._set_all_storages_charge_to_max()
+ producer_setpoints = self._set_producers_based_on_priority(
+ total_demand + total_charge_storage
+ )
else:
- # Set consumer to requested demand.
- consumer_setpoints = self._set_consumer_to_demand(time, factor=1.0)
- # Set producers and storages based on the supply and demand, and the charge and
- # discharge capacity of the storage.
- if total_supply >= total_demand:
- # there is a surplus of supply we can charge the storage, storage becomes consumer.
- surplus_supply = total_supply - total_demand
- if surplus_supply <= total_charge_storage:
- storage_setpoints = self._set_storages_charge_power(surplus_supply)
- producer_setpoints = self._set_producers_to_max()
- elif surplus_supply > total_charge_storage:
- # need to cap the power of the source based on priority
- storage_setpoints = self._set_storages_charge_power(total_charge_storage)
- producer_setpoints = self._set_producers_based_on_priority(
- total_demand + total_charge_storage
- )
+ # total supply is lower than demand, so we need to check if there is enough discharge
+ # capacity from storage.
+ total_discharge_storage = sum(
+ [network.get_total_discharge_storage() for network in self.networks]
+ )
+ if (total_supply + total_discharge_storage) <= total_demand:
+ logger.warning(
+ f"Total supply + storage is lower than total demand at time: {time}"
+ f"Consumers are capped to the available power."
+ )
+ factor = (total_supply + total_discharge_storage) / total_demand
+ producer_setpoints = self._set_producers_to_max()
+
+ storage_setpoints = self._set_all_storages_discharge_to_max()
+ consumer_setpoints = self._set_consumer_to_demand(time, factor=factor)
else:
- # there is a deficit of supply we can discharge the storage, storage becomes
- # producer.
- deficit_supply = total_demand - total_supply
- storage_setpoints = self._set_storages_discharge_power(deficit_supply)
+ # there is enough supply + storage to cover the demand. sources to max and
+ # storages to deliver the rest.
+ consumer_setpoints = self._set_consumer_to_demand(time)
+ surplus_demand = total_demand - total_supply
producer_setpoints = self._set_producers_to_max()
+ storage_setpoints = self._set_storages_discharge_power(surplus_demand)
# Update the asset setpoints with the setpoints of the producers, consumers,
# and storages.
@@ -165,17 +165,23 @@ def update_setpoints(self, time: datetime.datetime) -> dict:
# this might look weird, but we know there is only one primary or secondary asset.
# So we can directly set it.
for asset in network.heat_transfer_assets_prim:
- heat_transfer.update(asset.set_asset(total_heat_supply))
+ if total_heat_supply > 0:
+ heat_transfer.update(asset.set_asset(total_heat_supply))
+ else:
+ heat_transfer.update(asset.set_asset(-total_heat_supply, True))
for asset in network.heat_transfer_assets_sec:
- heat_transfer.update(asset.set_asset(-total_heat_supply))
+ if total_heat_supply > 0:
+ heat_transfer.update(asset.set_asset(-total_heat_supply, True))
+ else:
+ heat_transfer.update(asset.set_asset(-total_heat_supply))
# Update the asset setpoints with the heat transfer setpoints.
asset_setpoints.update(heat_transfer)
# Set the pressure.
for network in self.networks:
- pressure_set_asset = network.set_pressure()
- asset_setpoints[pressure_set_asset][PROPERTY_SET_PRESSURE] = True
+ pressure_set_asset, key = network.set_pressure()
+ asset_setpoints[pressure_set_asset][key] = True
return asset_setpoints
diff --git a/src/omotes_simulator_core/infrastructure/app.py b/src/omotes_simulator_core/infrastructure/app.py
index a7f9d91e..936e98e1 100644
--- a/src/omotes_simulator_core/infrastructure/app.py
+++ b/src/omotes_simulator_core/infrastructure/app.py
@@ -41,9 +41,9 @@ def run(file_path: str | None = None) -> pd.DataFrame:
config = SimulationConfiguration(
simulation_id=uuid.uuid1(),
name="test run",
- timestep=3600,
- start=datetime.strptime("2019-01-01T00:00:00", "%Y-%m-%dT%H:%M:%S"),
- stop=datetime.strptime("2019-01-01T01:00:00", "%Y-%m-%dT%H:%M:%S"),
+ timestep=24 * 3600,
+ start=datetime.strptime("2019-01-18T00:00:00", "%Y-%m-%dT%H:%M:%S"),
+ stop=datetime.strptime("2019-02-01T00:00:00", "%Y-%m-%dT%H:%M:%S"),
)
esdl_file_path = sys.argv[1] if file_path is None else file_path
@@ -63,9 +63,10 @@ def run(file_path: str | None = None) -> pd.DataFrame:
level=logging.INFO, format="%(asctime)s [%(levelname)s]:%(name)s - %(message)s"
)
t1 = datetime.now()
- result = run(r".\testdata\test1.esdl")
+ result = run(r".\testdata\heat_pump_bypass.esdl")
t2 = datetime.now()
logger.info(f"Results dataframe shape=({result.shape})")
+ result.to_csv(r".\testdata\heat_pump_bypass_results.csv", index=False)
logger.info(f"Execution time: {t2 - t1}")
logger.debug(result.head())
diff --git a/src/omotes_simulator_core/solver/network/assets/heat_transfer_asset.py b/src/omotes_simulator_core/solver/network/assets/heat_transfer_asset.py
index 8f17d98f..df27920a 100644
--- a/src/omotes_simulator_core/solver/network/assets/heat_transfer_asset.py
+++ b/src/omotes_simulator_core/solver/network/assets/heat_transfer_asset.py
@@ -94,15 +94,21 @@ def __init__(
# Define the flag that indicates whether the mass flow rate or the pressure is prescribed
# at the hot side of the heat pump
self.pre_scribe_mass_flow_secondary = pre_scribe_mass_flow_secondary
+ # Define the flag that indicates whether the mass flow rate or the pressure is prescribed
+ # at the hot side of the heat pump
+ self.pre_scribe_mass_flow_primary = pre_scribe_mass_flow_secondary
# Define the mass flow rate set point for the asset on the secondary side
self.mass_flow_rate_rate_set_point_secondary = mass_flow_rate_set_point_secondary
# Define the pressure set point for the asset
self.pressure_set_point_secondary = pressure_set_point_secondary
# Define flow directions
self.flow_direction_primary = self.flow_direction(self.mass_flow_initialization_primary)
+ self.iteration_flow_direction_primary = self.flow_direction_primary
self.flow_direction_secondary = self.flow_direction(
self.mass_flow_rate_rate_set_point_secondary
)
+ self.iteration_flow_direction_secondary = self.flow_direction_secondary
+
# Define connection points
(
self.primary_side_inflow,
@@ -110,6 +116,7 @@ def __init__(
self.secondary_side_inflow,
self.secondary_side_outflow,
) = self.get_ordered_connection_point_list()
+ self.bypass_mode = False
def flow_direction(self, mass_flow: float) -> FlowDirection:
"""Returns the flow direction of the heat transfer asset.
@@ -209,6 +216,12 @@ def get_ordered_connection_point_list(self) -> list[int]:
return [0, 1, 2, 3]
def get_equations(self) -> list[EquationObject]:
+
+ if self.bypass_mode:
+ return self.get_equations_bypass()
+ return self.get_equations_normal()
+
+ def get_equations_normal(self) -> list[EquationObject]:
r"""Return the heat transfer equations.
The method returns the heat transfer equations for the heat transfer asset.
@@ -258,10 +271,8 @@ def get_equations(self) -> list[EquationObject]:
if self.number_of_unknowns != 12:
raise ValueError("The number of unknowns must be 12!")
# Set connection points based on the flow direction
- self.flow_direction_primary = self.flow_direction(self.mass_flow_initialization_primary)
- self.flow_direction_secondary = self.flow_direction(
- self.mass_flow_rate_rate_set_point_secondary
- )
+ self.flow_direction_primary = self.flow_direction(self.prev_sol[0])
+ self.flow_direction_secondary = self.flow_direction(self.prev_sol[6])
(
self.primary_side_inflow,
self.primary_side_outflow,
@@ -270,7 +281,7 @@ def get_equations(self) -> list[EquationObject]:
) = self.get_ordered_connection_point_list()
if np.all(np.abs(self.prev_sol[0:-1:3]) < MASSFLOW_ZERO_LIMIT):
- iteration_flow_direction_primary = self.flow_direction(
+ self.iteration_flow_direction_primary = self.flow_direction(
self.prev_sol[
self.get_index_matrix(
property_name="mass_flow_rate",
@@ -279,7 +290,7 @@ def get_equations(self) -> list[EquationObject]:
)
]
)
- iteration_flow_direction_secondary = self.flow_direction(
+ self.iteration_flow_direction_secondary = self.flow_direction(
self.prev_sol[
self.get_index_matrix(
property_name="mass_flow_rate",
@@ -289,8 +300,8 @@ def get_equations(self) -> list[EquationObject]:
]
)
else:
- iteration_flow_direction_primary = self.flow_direction_primary
- iteration_flow_direction_secondary = self.flow_direction_secondary
+ self.iteration_flow_direction_primary = self.flow_direction_primary
+ self.iteration_flow_direction_secondary = self.flow_direction_secondary
# Initialize the equations list
equations = []
@@ -305,7 +316,7 @@ def get_equations(self) -> list[EquationObject]:
)
# Add the internal energy equations at connection points 1, and 3 to set
# the temperature through internal energy at the outlet of the heat transfer asset.
- if iteration_flow_direction_primary != FlowDirection.ZERO:
+ if self.iteration_flow_direction_primary != FlowDirection.ZERO:
equations.append(
self.prescribe_temperature_at_connection_point(
connection_point=self.primary_side_outflow,
@@ -318,7 +329,7 @@ def get_equations(self) -> list[EquationObject]:
connection_point=self.primary_side_outflow
)
)
- if iteration_flow_direction_secondary != FlowDirection.ZERO:
+ if self.iteration_flow_direction_secondary != FlowDirection.ZERO:
equations.append(
self.prescribe_temperature_at_connection_point(
connection_point=self.secondary_side_outflow,
@@ -334,28 +345,28 @@ def get_equations(self) -> list[EquationObject]:
# -- Mass flow rate or pressure on secondary side (2x) --
# Prescribe the pressure at the secondary side of the heat transfer asset.
if self.pre_scribe_mass_flow_secondary:
- if iteration_flow_direction_secondary == FlowDirection.ZERO:
- mset = 0.0
+ if self.iteration_flow_direction_secondary == FlowDirection.ZERO:
+ mset = self.mass_flow_rate_rate_set_point_secondary
else:
mset = self.mass_flow_rate_rate_set_point_secondary
equations.append(
self.prescribe_mass_flow_at_connection_point(
connection_point=self.secondary_side_inflow,
- mass_flow_value=mset * self.flow_direction_secondary.value,
+ mass_flow_value=-mset,
)
)
equations.append(
self.prescribe_mass_flow_at_connection_point(
connection_point=self.secondary_side_outflow,
- mass_flow_value=mset * self.flow_direction_secondary.value * -1,
+ mass_flow_value=mset,
)
)
else:
- if iteration_flow_direction_secondary == FlowDirection.ZERO:
+ if self.iteration_flow_direction_secondary == FlowDirection.ZERO:
pset_out = self.pressure_set_point_secondary
pset_in = self.pressure_set_point_secondary
else:
- if iteration_flow_direction_secondary == FlowDirection.POSITIVE:
+ if self.iteration_flow_direction_secondary == FlowDirection.POSITIVE:
pset_out = self.pressure_set_point_secondary / 2
pset_in = self.pressure_set_point_secondary
else:
@@ -385,36 +396,231 @@ def get_equations(self) -> list[EquationObject]:
# -- Internal continuity (1x) --
# Add the internal continuity equation at the primary side.
- equations.append(
- self.add_continuity_equation(
- connection_point_1=self.primary_side_inflow,
- connection_point_2=self.primary_side_outflow,
- )
- )
+
# -- Energy balance equation for the heat transfer asset (1x) --
# Defines the energy balance between the primary and secondary side of the
# heat transfer asset.
# If the mass flow at the inflow node of the primary and secondary side is not zero,
- if (iteration_flow_direction_primary != FlowDirection.ZERO) or (
- iteration_flow_direction_secondary != FlowDirection.ZERO
- ):
+ if self.pre_scribe_mass_flow_primary:
equations.append(
- self.prescribe_mass_flow_at_connection_point(
- connection_point=self.primary_side_inflow,
- mass_flow_value=self.get_mass_flow_from_prev_solution(),
+ self.add_continuity_equation(
+ connection_point_1=self.primary_side_inflow,
+ connection_point_2=self.primary_side_outflow,
)
)
- # If the mass flow at the inflow node of the primary and secondary side is zero,
+ if (self.iteration_flow_direction_primary != FlowDirection.ZERO) or (
+ self.iteration_flow_direction_secondary != FlowDirection.ZERO
+ ):
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=self.primary_side_inflow,
+ mass_flow_value=self.mass_flow_initialization_primary,
+ )
+ )
+ # If the mass flow at the inflow node of the primary and secondary side is zero,
+ else:
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=self.primary_side_inflow,
+ mass_flow_value=self.mass_flow_initialization_primary,
+ )
+ )
else:
+ if self.iteration_flow_direction_primary == FlowDirection.ZERO:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary
+ else:
+ if self.iteration_flow_direction_primary == FlowDirection.POSITIVE:
+ pset_out = self.pressure_set_point_secondary / 2
+ pset_in = self.pressure_set_point_secondary
+ else:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary / 2
equations.append(
- self.prescribe_mass_flow_at_connection_point(
+ self.prescribe_pressure_at_connection_point(
connection_point=self.primary_side_inflow,
- mass_flow_value=0,
+ pressure_value=pset_in,
+ )
+ )
+ equations.append(
+ self.prescribe_pressure_at_connection_point(
+ connection_point=self.primary_side_outflow,
+ pressure_value=pset_out,
)
)
# Return the equations
return equations
+ def get_equations_bypass(self) -> list[EquationObject]:
+ r"""Return the heat transfer equations.
+
+ The method returns the heat transfer equations for the heat transfer asset.
+
+ The internal energy at the connection points with mass inflow are linked to the nodes.
+
+ .. math::
+
+ u_{connection_point} = u_{node}
+
+ The temperature is prescribed through the internal energy at the outlet on the
+ primary and secondary side of the heat transfer asset.
+
+ .. math::
+
+ u_{connection_point} = u_{supply_temperature}
+
+ The mass flow rate or pressure is prescribed at the secondary side of the heat transfer
+ asset.
+
+ On the primary side, continuity of mass flow rate is enforced.
+
+ .. math::
+
+ \dot{m}_{0} + \dot{m}_{1} = 0
+
+ If the mass flow at the inflow node of the primary and secondary side is not zero, we
+ prescribe the follwoing energy balance equation for the heat transfer asset:
+
+ .. math::
+
+ \dot{m}_0 \left{ u_0 - u_1 \right} + C \left{ u_2 \dot{m}_2 + u_3 \dot{m}_3 \right} = 0
+
+ If the mass flow at the inflow node of the primary and secondary side is zero, we prescribe
+ the mass flow rate at the primary side of the heat transfer asset.
+
+ .. math::
+
+ \dot{m}_{asset} = 10.0
+
+ :return: List[EquationObject]
+ """
+ equations = []
+ # pressure to node equations
+ for connection_point in range(4):
+ equations.append(self.get_press_to_node_equation(connection_point=connection_point))
+
+ # Internal energy to node equations
+ self.set_internal_energy_equations_bypass(equations)
+
+ # set mass flow rate or pressure
+ if self.pre_scribe_mass_flow_secondary:
+ mset = self.mass_flow_rate_rate_set_point_secondary
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=2,
+ mass_flow_value=-mset,
+ )
+ )
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=3,
+ mass_flow_value=mset,
+ )
+ )
+ else:
+ if self.iteration_flow_direction_secondary == FlowDirection.ZERO:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary
+ else:
+ if self.iteration_flow_direction_secondary == FlowDirection.POSITIVE:
+ pset_out = self.pressure_set_point_secondary / 2
+ pset_in = self.pressure_set_point_secondary
+ else:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary / 2
+ equations.append(
+ self.prescribe_pressure_at_connection_point(
+ connection_point=2,
+ pressure_value=pset_in,
+ )
+ )
+ equations.append(
+ self.prescribe_pressure_at_connection_point(
+ connection_point=3,
+ pressure_value=pset_out,
+ )
+ )
+ # set mass flow rate or pressure
+ if self.pre_scribe_mass_flow_primary:
+ mset = self.mass_flow_initialization_primary
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=0,
+ mass_flow_value=mset,
+ )
+ )
+ equations.append(
+ self.prescribe_mass_flow_at_connection_point(
+ connection_point=1,
+ mass_flow_value=mset * -1,
+ )
+ )
+ else:
+ if self.iteration_flow_direction_secondary == FlowDirection.ZERO:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary
+ else:
+ if self.iteration_flow_direction_secondary == FlowDirection.POSITIVE:
+ pset_out = self.pressure_set_point_secondary / 2
+ pset_in = self.pressure_set_point_secondary
+ else:
+ pset_out = self.pressure_set_point_secondary
+ pset_in = self.pressure_set_point_secondary / 2
+ equations.append(
+ self.prescribe_pressure_at_connection_point(
+ connection_point=0,
+ pressure_value=pset_in,
+ )
+ )
+ equations.append(
+ self.prescribe_pressure_at_connection_point(
+ connection_point=1,
+ pressure_value=pset_out,
+ )
+ )
+ return equations
+
+ def set_internal_energy_equations_bypass(self, equations):
+ equations.append(self.get_internal_energy_to_node_equation(connection_point=0))
+ equations.append(self.get_internal_energy_to_node_equation(connection_point=3))
+ equation_object = EquationObject()
+ # Short-circuiting the primary and secondary side of the heat transfer asset.
+ equation_object.indices = np.array(
+ [
+ self.get_index_matrix(
+ property_name="internal_energy",
+ connection_point=1,
+ use_relative_indexing=False,
+ ),
+ self.get_index_matrix(
+ property_name="internal_energy",
+ connection_point=3,
+ use_relative_indexing=False,
+ ),
+ ]
+ )
+ equation_object.coefficients = np.array([1.0, -1.0])
+ equation_object.rhs = 0.0
+ equations.append(equation_object)
+ equation_object2 = EquationObject()
+ equation_object2.indices = np.array(
+ [
+ self.get_index_matrix(
+ property_name="internal_energy",
+ connection_point=0,
+ use_relative_indexing=False,
+ ),
+ self.get_index_matrix(
+ property_name="internal_energy",
+ connection_point=2,
+ use_relative_indexing=False,
+ ),
+ ]
+ )
+ equation_object2.coefficients = np.array([1.0, -1.0])
+ equation_object2.rhs = 0.0
+ equations.append(equation_object2)
+
def get_mass_flow_from_prev_solution(self) -> float:
r"""Determine the mass flow rate from the previous solution.
@@ -691,12 +897,9 @@ def get_electric_power_consumption(self) -> float:
"""Calculate the electric power consumption of the heat transfer asset.
The electric power consumption is calculated as the absolute difference between the
- heat power on the primary and secondary side, divided by the heat transfer coefficient.
+ heat power on the primary and secondary side.
:return: float
The electric power consumption of the heat transfer asset.
"""
- return (
- abs(self.get_heat_power_primary() - self.get_heat_power_secondary())
- / self.heat_transfer_coefficient
- )
+ return abs(abs(self.get_heat_power_primary()) - abs(self.get_heat_power_secondary()))
diff --git a/unit_test/entities/controller/test_controller_network.py b/unit_test/entities/controller/test_controller_network.py
index f035b6dc..92103ef3 100644
--- a/unit_test/entities/controller/test_controller_network.py
+++ b/unit_test/entities/controller/test_controller_network.py
@@ -61,7 +61,7 @@ def test_init(self):
self.assertEqual(self.controller_network.consumers, self.consumers)
self.assertEqual(self.controller_network.producers, self.producers)
self.assertEqual(self.controller_network.storages, self.storages)
- self.assertEqual(self.controller_network.factor_to_first_network, self.factor)
+ self.assertEqual(self.controller_network.factor_to_first_network, [self.factor])
self.assertEqual(self.controller_network.path, [])
def test_exists(self):
@@ -248,9 +248,13 @@ def test_set_all_storages_discharge_to_max(self):
{
storage1.id: {
PROPERTY_HEAT_DEMAND: -20,
+ PROPERTY_TEMPERATURE_OUT: 50,
+ PROPERTY_TEMPERATURE_IN: 40,
},
storage2.id: {
PROPERTY_HEAT_DEMAND: -25,
+ PROPERTY_TEMPERATURE_OUT: 50,
+ PROPERTY_TEMPERATURE_IN: 40,
},
},
)
@@ -278,9 +282,13 @@ def test_set_all_storages_charge_to_max(self):
{
storage1.id: {
PROPERTY_HEAT_DEMAND: 10,
+ PROPERTY_TEMPERATURE_OUT: 50,
+ PROPERTY_TEMPERATURE_IN: 40,
},
storage2.id: {
PROPERTY_HEAT_DEMAND: 15,
+ PROPERTY_TEMPERATURE_OUT: 50,
+ PROPERTY_TEMPERATURE_IN: 40,
},
},
)
diff --git a/unit_test/entities/controller/test_controller_new_class.py b/unit_test/entities/controller/test_controller_new_class.py
index aaf724d7..d984b39b 100644
--- a/unit_test/entities/controller/test_controller_new_class.py
+++ b/unit_test/entities/controller/test_controller_new_class.py
@@ -81,9 +81,9 @@ def test_update_networks_factor_prim(self):
# act
self.controller.update_networks_factor()
# assert
- self.assertEqual(self.network1.factor_to_first_network, 1)
- self.assertEqual(self.network2.factor_to_first_network, 2)
- self.assertEqual(self.network3.factor_to_first_network, 6)
+ self.assertEqual(self.network1.factor_to_first_network, [1])
+ self.assertEqual(self.network2.factor_to_first_network, [1, 2])
+ self.assertEqual(self.network3.factor_to_first_network, [1, 3, 2])
def test_update_networks_factor_sec(self):
# arrange
@@ -99,9 +99,9 @@ def test_update_networks_factor_sec(self):
# act
self.controller.update_networks_factor()
# assert
- self.assertEqual(self.network1.factor_to_first_network, 1)
- self.assertEqual(self.network2.factor_to_first_network, 0.5)
- self.assertEqual(self.network3.factor_to_first_network, 0.16666666666666666)
+ self.assertEqual(self.network1.factor_to_first_network, [1])
+ self.assertEqual(self.network2.factor_to_first_network, [1, 0.5])
+ self.assertEqual(self.network3.factor_to_first_network, [1, 0.3333333333333333, 0.5])
def setup_update_set_points(self):
"""Helper method to set up the networks with assets.
diff --git a/unit_test/entities/test_ates_cluster.py b/unit_test/entities/test_ates_cluster.py
index 43bc0698..b06059f8 100644
--- a/unit_test/entities/test_ates_cluster.py
+++ b/unit_test/entities/test_ates_cluster.py
@@ -74,7 +74,7 @@ def test_injection_ates(self) -> None:
self.ates_cluster.set_setpoints(setpoints=setpoints)
# Assert
- self.assertAlmostEqual(self.ates_cluster.hot_well_temperature, 358.15, delta=0.1)
+ self.assertAlmostEqual(self.ates_cluster.hot_well_temperature, 358.6696, delta=0.1)
self.assertAlmostEqual(self.ates_cluster.cold_well_temperature, 290.15, delta=0.1)
def test_production_ates(self) -> None:
@@ -93,5 +93,5 @@ def test_production_ates(self) -> None:
self.ates_cluster.set_setpoints(setpoints=setpoints)
# Assert
- self.assertAlmostEqual(self.ates_cluster.hot_well_temperature, 355.54, delta=0.1)
+ self.assertAlmostEqual(self.ates_cluster.hot_well_temperature, 290.1549, delta=0.1)
self.assertAlmostEqual(self.ates_cluster.cold_well_temperature, 308.17, delta=0.1)
diff --git a/unit_test/entities/test_heat_exchanger.py b/unit_test/entities/test_heat_exchanger.py
index 33fef9c7..0f0cba67 100644
--- a/unit_test/entities/test_heat_exchanger.py
+++ b/unit_test/entities/test_heat_exchanger.py
@@ -55,8 +55,12 @@ def setUp(self) -> None:
self.heat_exchanger.solver_asset.get_index_matrix(
property_name="mass_flow_rate", connection_point=0, use_relative_indexing=False
)
+ ] = -2.0
+ self.heat_exchanger.solver_asset.prev_sol[
+ self.heat_exchanger.solver_asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=1, use_relative_indexing=False
+ )
] = 2.0
-
self.heat_exchanger.solver_asset.prev_sol[
self.heat_exchanger.solver_asset.get_index_matrix(
property_name="internal_energy", connection_point=1, use_relative_indexing=False
@@ -73,7 +77,11 @@ def setUp(self) -> None:
property_name="mass_flow_rate", connection_point=2, use_relative_indexing=False
)
] = 1.0
-
+ self.heat_exchanger.solver_asset.prev_sol[
+ self.heat_exchanger.solver_asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=3, use_relative_indexing=False
+ )
+ ] = -1.0
self.heat_exchanger.solver_asset.prev_sol[
self.heat_exchanger.solver_asset.get_index_matrix(
property_name="internal_energy", connection_point=3, use_relative_indexing=False
@@ -89,6 +97,6 @@ def test_write_to_output(self):
self.heat_exchanger.write_to_output()
# Assert
- self.assertEqual(self.heat_exchanger.outputs[1][-1][PROPERTY_HEAT_POWER_PRIMARY], 10.0)
+ self.assertEqual(self.heat_exchanger.outputs[1][-1][PROPERTY_HEAT_POWER_PRIMARY], -10.0)
self.assertEqual(self.heat_exchanger.outputs[1][-1][PROPERTY_HEAT_LOSS], 5.0)
self.assertEqual(self.heat_exchanger.outputs[0][-1][PROPERTY_HEAT_POWER_SECONDARY], 5.0)
diff --git a/unit_test/entities/test_heat_pump.py b/unit_test/entities/test_heat_pump.py
index c491964f..e7d9f852 100644
--- a/unit_test/entities/test_heat_pump.py
+++ b/unit_test/entities/test_heat_pump.py
@@ -63,6 +63,11 @@ def setUp(self) -> None:
property_name="mass_flow_rate", connection_point=0, use_relative_indexing=False
)
] = 2.0
+ self.heat_pump.solver_asset.prev_sol[
+ self.heat_pump.solver_asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=1, use_relative_indexing=False
+ )
+ ] = -2.0
self.heat_pump.solver_asset.prev_sol[
self.heat_pump.solver_asset.get_index_matrix(
@@ -80,6 +85,11 @@ def setUp(self) -> None:
property_name="mass_flow_rate", connection_point=2, use_relative_indexing=False
)
] = 1.0
+ self.heat_pump.solver_asset.prev_sol[
+ self.heat_pump.solver_asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=3, use_relative_indexing=False
+ )
+ ] = -1.0
self.heat_pump.solver_asset.prev_sol[
self.heat_pump.solver_asset.get_index_matrix(
@@ -91,27 +101,29 @@ def test_set_setpoints_secondary(self):
setpoints = {
SECONDARY + PROPERTY_TEMPERATURE_IN: 273.15 + 15.0,
SECONDARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 25.0,
- SECONDARY + PROPERTY_HEAT_DEMAND: 310,
+ SECONDARY + PROPERTY_HEAT_DEMAND: -310,
PROPERTY_SET_PRESSURE: True, # Boolean value
}
with patch(
"omotes_simulator_core.entities.assets.heat_pump."
"heat_demand_and_temperature_to_mass_flow",
- return_value=321.0,
+ return_value=-321.0,
) as mock_calc:
self.heat_pump._set_setpoints_secondary(setpoints)
# Self attributes
self.assertEqual(self.heat_pump.temperature_in_secondary, 273.15 + 15.0)
self.assertEqual(self.heat_pump.temperature_out_secondary, 273.15 + 25.0)
- self.assertEqual(self.heat_pump.mass_flow_secondary, 321.0)
+ self.assertEqual(self.heat_pump.mass_flow_secondary, -321.0)
self.assertEqual(self.heat_pump.control_mass_flow_secondary, False)
# Solver asset attributes
self.assertEqual(self.heat_pump.solver_asset.temperature_in_secondary, 273.15 + 15.0)
self.assertEqual(self.heat_pump.solver_asset.temperature_out_secondary, 273.15 + 25.0)
- self.assertEqual(self.heat_pump.solver_asset.mass_flow_rate_secondary, 321.0)
+ self.assertEqual(
+ self.heat_pump.solver_asset.mass_flow_rate_rate_set_point_secondary, -321.0
+ )
self.assertEqual(self.heat_pump.solver_asset.pre_scribe_mass_flow_secondary, False)
mock_calc.assert_called_once_with(
@@ -143,6 +155,7 @@ def test_set_setpoints_primary(self):
PRIMARY + PROPERTY_TEMPERATURE_IN: 273.15 + 10.0,
PRIMARY + PROPERTY_TEMPERATURE_OUT: 273.15 + 20.0,
PRIMARY + PROPERTY_HEAT_DEMAND: 300,
+ PROPERTY_SET_PRESSURE: False,
}
with patch(
@@ -155,12 +168,12 @@ def test_set_setpoints_primary(self):
# Self attributes
self.assertEqual(self.heat_pump.temperature_in_primary, 273.15 + 10.0)
self.assertEqual(self.heat_pump.temperature_out_primary, 273.15 + 20.0)
- self.assertEqual(self.heat_pump.mass_flow_initialization_primary, 125)
+ self.assertEqual(self.heat_pump.mass_flow_initialization_primary, -125)
# Solver asset attributes
self.assertEqual(self.heat_pump.solver_asset.temperature_in_primary, 273.15 + 10.0)
self.assertEqual(self.heat_pump.solver_asset.temperature_out_primary, 273.15 + 20.0)
- self.assertEqual(self.heat_pump.solver_asset.mass_flow_initialization_primary, 125)
+ self.assertEqual(self.heat_pump.solver_asset.mass_flow_initialization_primary, -125)
mock_calc.assert_called_once_with(
thermal_demand=300, temperature_in=273.15 + 10.0, temperature_out=273.15 + 20.0
@@ -209,7 +222,7 @@ def test_set_setpoints_calls_both_primary_and_secondary(self):
self.assertEqual(self.heat_pump.solver_asset.temperature_in_secondary, 280.0)
self.assertEqual(self.heat_pump.solver_asset.temperature_out_secondary, 270.0)
self.assertEqual(self.heat_pump.solver_asset.pre_scribe_mass_flow_secondary, True)
- self.assertEqual(self.heat_pump.mass_flow_initialization_primary, 125)
+ self.assertEqual(self.heat_pump.mass_flow_initialization_primary, -125)
self.assertEqual(self.heat_pump.mass_flow_secondary, 125)
self.assertEqual(mock_calc.call_count, 2)
diff --git a/unit_test/entities/test_production_cluster.py b/unit_test/entities/test_production_cluster.py
index 92b40cb7..c7d2e4c7 100644
--- a/unit_test/entities/test_production_cluster.py
+++ b/unit_test/entities/test_production_cluster.py
@@ -284,10 +284,10 @@ def test_is_converged_pass(self):
The convergence criteria is set to 0.1% of the heat demand set point.
"""
# Arrange
- self.production_cluster.heat_demand_set_point = 100.0
+ self.production_cluster.heat_demand_set_point = -100.0
def get_actual_heat_supplied(_):
- return self.production_cluster.heat_demand_set_point * (1 - 0.001)
+ return -self.production_cluster.heat_demand_set_point * (1 - 0.001)
with patch(
"omotes_simulator_core.entities.assets.production_cluster."
diff --git a/unit_test/integration/test_heat_transfer_asset.py b/unit_test/integration/test_heat_transfer_asset.py
index 7d899cdc..01c16655 100644
--- a/unit_test/integration/test_heat_transfer_asset.py
+++ b/unit_test/integration/test_heat_transfer_asset.py
@@ -90,8 +90,10 @@ def test_heat_transfer_asset_primary_positive_secondary_positive_flow(self) -> N
self.heat_transfer_asset.temperature_out_primary = 20 + 273.15
self.heat_transfer_asset.temperature_out_secondary = 70 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 - 1.0 / 3.0
- self.heat_transfer_asset.mass_flow_initialization_primary = -1
+ self.heat_transfer_asset.mass_flow_initialization_primary = -77.55
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -1
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -187,8 +189,10 @@ def test_heat_transfer_asset_primary_negative_secondary_positive_flow(self) -> N
self.heat_transfer_asset.temperature_out_primary = 20 + 273.15
self.heat_transfer_asset.temperature_out_secondary = 70 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 - 1.0 / 3.0
- self.heat_transfer_asset.mass_flow_initialization_primary = +1
+ self.heat_transfer_asset.mass_flow_initialization_primary = 77.55
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -1
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -283,8 +287,10 @@ def test_heat_transfer_asset_primary_positive_secondary_negative_flow(self) -> N
self.heat_transfer_asset.temperature_out_primary = 20 + 273.15
self.heat_transfer_asset.temperature_out_secondary = 70 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 - 1.0 / 3.0
- self.heat_transfer_asset.mass_flow_initialization_primary = -1
+ self.heat_transfer_asset.mass_flow_initialization_primary = -77.55
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = +1
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -380,7 +386,10 @@ def test_heat_transfer_asset_positive_heat_transfer_coefficient(self) -> None:
self.heat_transfer_asset.temperature_out_primary = 20 + 273.15
self.heat_transfer_asset.temperature_out_secondary = 70 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 - 1.0 / 5.0
- self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -38.76
+ self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -20.0
+ self.heat_transfer_asset.mass_flow_initialization_primary = -38.76
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -406,7 +415,7 @@ def test_heat_transfer_asset_positive_heat_transfer_coefficient(self) -> None:
property_name="mass_flow_rate", connection_point=0, use_relative_indexing=False
)
],
- -93.07,
+ -38.76,
2,
)
self.assertAlmostEqual(
@@ -467,6 +476,9 @@ def test_heat_transfer_asset_heat_transfer_coefficient_of_one(self) -> None:
self.heat_transfer_asset.temperature_out_secondary = 70 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 # - 1.0 / 5.0
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -38.76
+ self.heat_transfer_asset.mass_flow_initialization_primary = -38.76
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -561,8 +573,10 @@ def test_heat_transfer_asset_negative_heat_transfer_coefficient(self) -> None:
self.heat_transfer_asset.temperature_out_primary = 30 + 273.15
self.heat_transfer_asset.temperature_out_secondary = 40 + 273.15
self.heat_transfer_asset.heat_transfer_coefficient = -1 * (1.0 - 1.0 / 5.0)
- self.heat_transfer_asset.mass_flow_initialization_primary = -1
+ self.heat_transfer_asset.mass_flow_initialization_primary = -93.07
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = -1
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 70 + 273.15
@@ -679,6 +693,8 @@ def test_heat_transfer_asset_zero_flow(self) -> None:
self.heat_transfer_asset.heat_transfer_coefficient = 1.0 - 1.0 / 5.0
self.heat_transfer_asset.mass_flow_initialization_primary = 0.0
self.heat_transfer_asset.mass_flow_rate_rate_set_point_secondary = 0.0
+ self.heat_transfer_asset.pre_scribe_mass_flow_primary = True
+ self.heat_transfer_asset.pre_scribe_mass_flow_secondary = False
# Set the temperature of the demand
self.demand_asset.supply_temperature = 40 + 273.15
@@ -723,7 +739,7 @@ def test_heat_transfer_asset_zero_flow(self) -> None:
property_name="internal_energy", connection_point=0, use_relative_indexing=False
)
],
- fluid_props.get_ie(self.network.get_node(primary_in).initial_temperature),
+ fluid_props.get_ie(20 + 273.15),
2,
)
self.assertAlmostEqual(
@@ -741,7 +757,7 @@ def test_heat_transfer_asset_zero_flow(self) -> None:
property_name="internal_energy", connection_point=2, use_relative_indexing=False
)
],
- fluid_props.get_ie(self.network.get_node(secondary_in).initial_temperature),
+ fluid_props.get_ie(70 + 273.15),
2,
)
self.assertAlmostEqual(
diff --git a/unit_test/solver/network/assets/test_heat_transfer_asset.py b/unit_test/solver/network/assets/test_heat_transfer_asset.py
index 691cdf80..4a9f7e53 100644
--- a/unit_test/solver/network/assets/test_heat_transfer_asset.py
+++ b/unit_test/solver/network/assets/test_heat_transfer_asset.py
@@ -74,12 +74,12 @@ def test_get_equations_initial_conditions_prescribe_pressure_secondary(
# Assert
self.assertEqual(len(equations), 12)
- self.assertEqual(mock_add_continuity_equation.call_count, 1)
+ self.assertEqual(mock_add_continuity_equation.call_count, 0)
self.assertEqual(mock_get_press_to_node_equation.call_count, 4)
- self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 2)
- self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 1)
- self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 0)
- self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 4)
+ self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 4)
+ self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 0)
+ self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 4)
+ self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 0)
self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 0)
self.assertEqual(
(
@@ -127,12 +127,12 @@ def test_get_equations_initial_conditions_prescribe_mass_flow_secondary(
# Assert
self.assertEqual(len(equations), 12)
- self.assertEqual(mock_add_continuity_equation.call_count, 1)
+ self.assertEqual(mock_add_continuity_equation.call_count, 0)
self.assertEqual(mock_get_press_to_node_equation.call_count, 4)
- self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 0)
- self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 3)
- self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 0)
- self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 4)
+ self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 2)
+ self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 2)
+ self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 4)
+ self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 0)
self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 0)
self.assertEqual(
(
@@ -210,12 +210,12 @@ def test_get_equations_zero_flow_prescribe_pressure_secondary(
# Assert
self.assertEqual(len(equations), 12)
- self.assertEqual(mock_add_continuity_equation.call_count, 1)
+ self.assertEqual(mock_add_continuity_equation.call_count, 0)
self.assertEqual(mock_get_press_to_node_equation.call_count, 4)
- self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 2)
- self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 1)
- self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 0)
- self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 4)
+ self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 4)
+ self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 0)
+ self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 4)
+ self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 0)
self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 0)
self.assertEqual(
(
@@ -294,13 +294,13 @@ def test_get_equations_flow_prescribe_mass_flow_secondary(
# Assert
self.assertEqual(len(equations), 12)
- self.assertEqual(mock_add_continuity_equation.call_count, 1)
+ self.assertEqual(mock_add_continuity_equation.call_count, 0)
self.assertEqual(mock_get_press_to_node_equation.call_count, 4)
- self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 0)
- self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 3)
+ self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 2)
+ self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 2)
self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 2)
self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 2)
- self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 1)
+ self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 0)
self.assertEqual(
(
mock_add_continuity_equation.call_count
@@ -377,13 +377,13 @@ def test_get_equations_with_flow_prescribe_pressure_secondary(
# Assert
self.assertEqual(len(equations), 12)
- self.assertEqual(mock_add_continuity_equation.call_count, 1)
+ self.assertEqual(mock_add_continuity_equation.call_count, 0)
self.assertEqual(mock_get_press_to_node_equation.call_count, 4)
- self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 2)
- self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 1)
+ self.assertEqual(mock_prescribe_pressure_at_connection_point.call_count, 4)
+ self.assertEqual(mock_prescribe_mass_flow_at_connection_point.call_count, 0)
self.assertEqual(mock_prescribe_temperature_at_connection_point.call_count, 2)
self.assertEqual(mock_get_internal_energy_to_node_equation.call_count, 2)
- self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 1)
+ self.assertEqual(mock_get_mass_flow_from_prev_solution.call_count, 0)
self.assertEqual(
(
mock_add_continuity_equation.call_count
@@ -414,7 +414,11 @@ def test_get_heat_power_primary(self):
property_name="mass_flow_rate", connection_point=0, use_relative_indexing=False
)
] = 1.0
-
+ self.asset.prev_sol[
+ self.asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=1, use_relative_indexing=False
+ )
+ ] = -1.0
# Act
heat_power = self.asset.get_heat_power_primary()
@@ -439,6 +443,11 @@ def test_get_heat_power_secondary(self):
property_name="mass_flow_rate", connection_point=2, use_relative_indexing=False
)
] = 1.0
+ self.asset.prev_sol[
+ self.asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=3, use_relative_indexing=False
+ )
+ ] = -1.0
# Act
heat_power = self.asset.get_heat_power_secondary()
@@ -466,7 +475,11 @@ def test_get_electric_power_consumption(self):
property_name="mass_flow_rate", connection_point=0, use_relative_indexing=False
)
] = 2.0
-
+ self.asset.prev_sol[
+ self.asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=1, use_relative_indexing=False
+ )
+ ] = 2.0
# --- Secondary side
self.asset.prev_sol[
self.asset.get_index_matrix(
@@ -483,7 +496,11 @@ def test_get_electric_power_consumption(self):
property_name="mass_flow_rate", connection_point=2, use_relative_indexing=False
)
] = 1.0
-
+ self.asset.prev_sol[
+ self.asset.get_index_matrix(
+ property_name="mass_flow_rate", connection_point=3, use_relative_indexing=False
+ )
+ ] = 1.0
# Act
electric_power = self.asset.get_electric_power_consumption()