Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b2875c9
add ideal heat buffer tracking fill level
octavianor Dec 9, 2024
ff053a8
Merge remote-tracking branch 'remotes/origin/main' into 221-day-night…
octavianor Jan 17, 2025
83ff1b7
add volume calculation and update the comments
octavianor Jan 17, 2025
71691a1
add heat buffer mapper to remove add physical data
octavianor Jan 17, 2025
1ede1fb
add new parameters for unit test
octavianor Feb 4, 2025
d511e89
fix current volume calculation
octavianor Feb 4, 2025
f564c58
rename mapper
octavianor Feb 7, 2025
703f0e5
map esdl water buffer as heat buffer
octavianor Feb 7, 2025
c609e4a
remove supply and return temperature from controller, it is now set f…
octavianor Feb 7, 2025
4f3a415
add ideal heat buffer tracking fill level
octavianor Dec 9, 2024
198cb9e
add volume calculation and update the comments
octavianor Jan 17, 2025
7612d81
add heat buffer mapper to remove add physical data
octavianor Jan 17, 2025
86a88db
add new parameters for unit test
octavianor Feb 4, 2025
39cbbdf
fix current volume calculation
octavianor Feb 4, 2025
c0b64b6
rename mapper
octavianor Feb 7, 2025
51310f5
map esdl water buffer as heat buffer
octavianor Feb 7, 2025
77cc69c
remove supply and return temperature from controller, it is now set f…
octavianor Feb 7, 2025
623b700
Merge branch '221-day-night-buffer-asset' of https://github.com/Proje…
vanmeerkerk Apr 3, 2025
4dc972e
Minor code changes
vanmeerkerk Apr 3, 2025
1371134
Merge remote-tracking branch 'remotes/origin/main' into 221-day-night…
octavianor Aug 8, 2025
1ca1295
run formatting
octavianor Aug 8, 2025
d47c6fd
reformat heat_buffer_mapper.py
octavianor Aug 9, 2025
73bab55
implement stratified buffer tank with 5 layers
octavianor Aug 11, 2025
45b2f92
fix unit test
octavianor Aug 11, 2025
05f0321
remove fault handler
octavianor Aug 28, 2025
4d63fef
fix typo layer volume
octavianor Aug 29, 2025
e357c8e
fix test heat buffer after correction layer_mass
octavianor Aug 29, 2025
99780f0
change comparison value
octavianor Aug 29, 2025
f7b33bd
add energy calculation
octavianor Sep 10, 2025
0685f57
add stored energy calculation
octavianor Sep 11, 2025
ac27693
change to ODE solver
octavianor Sep 13, 2025
b491dce
add time in asset, integration test with ESDL
octavianor Sep 17, 2025
d961895
Merge remote-tracking branch 'remotes/origin/main' into 221-day-night…
octavianor Sep 17, 2025
3ab1f8c
fix linting, formatting, typecheck
octavianor Sep 17, 2025
721516d
fix formatting and unit test buffer with time
octavianor Sep 17, 2025
edf3df5
update typecheck for numpy
octavianor Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/win32/format.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ pushd .
cd /D "%~dp0"
cd ..\..\
black ./src/omotes_simulator_core ./unit_test/
isort --diff ./src/omotes_simulator_core ./unit_test/
isort ./src/omotes_simulator_core ./unit_test/
popd
2 changes: 1 addition & 1 deletion ci/win32/lint.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ rem @echo off
pushd .
cd /D "%~dp0"
cd ..\..\
flake8 .\src\omotes_simulator_core
flake8 .\src\omotes_simulator_core .\unit_test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you either remove this statement or explain why it is needed to also run flake8 on the unit test separately?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the linux script also include unit test, so i just want to make sure it is similar

popd
2 changes: 1 addition & 1 deletion ci/win32/typecheck.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ cd /D "%~dp0"
cd ..\..\
call .\venv\Scripts\activate
set PYTHONPATH=.\src\;%$PYTHONPATH%
python -m mypy ./src/
python -m mypy ./src/omotes_simulator_core ./unit_test/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as with the linting. Why is it necessary also call mypy on the unit test? Shouldn't the pyproject.toml handle this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the linux script also include unit test, so i just want to make sure it is similar

popd
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def to_entity(self, esdl_asset: EsdlAssetObject) -> ControllerStorage:
charge_power = esdl_asset.get_property(
esdl_property_name="maxChargeRate", default_value=np.inf
)
temperature_in = esdl_asset.get_temperature("In", "Return")
temperature_out = esdl_asset.get_temperature("Out", "Supply")
temperature_in = esdl_asset.get_temperature("In", "Supply")
temperature_out = esdl_asset.get_temperature("Out", "Return")
profile = pd.DataFrame() # esdl_asset.get_profile()
contr_storage = ControllerStorage(
name=esdl_asset.esdl_asset.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
from omotes_simulator_core.adapter.transforms.esdl_asset_mappers.consumer_mapper import (
EsdlAssetConsumerMapper,
)
from omotes_simulator_core.adapter.transforms.esdl_asset_mappers.heat_buffer_mapper import (
EsdlAssetHeatBufferMapper,
)
from omotes_simulator_core.adapter.transforms.esdl_asset_mappers.heat_pump_mapper import (
EsdlAssetHeatPumpMapper,
)
Expand Down Expand Up @@ -49,6 +52,8 @@
esdl.Pipe: EsdlAssetPipeMapper,
esdl.HeatPump: EsdlAssetHeatPumpMapper,
esdl.ATES: EsdlAssetAtesMapper,
esdl.WaterBuffer: EsdlAssetHeatBufferMapper,
esdl.HeatStorage: EsdlAssetHeatBufferMapper,
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright (c) 2023. Deltares & TNO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Module containing the Esdl to HeatBuffer asset mapper class."""

from omotes_simulator_core.entities.assets.asset_abstract import AssetAbstract
from omotes_simulator_core.entities.assets.asset_defaults import HEAT_BUFFER_DEFAULTS
from omotes_simulator_core.entities.assets.esdl_asset_object import EsdlAssetObject
from omotes_simulator_core.entities.assets.heat_buffer import HeatBuffer
from omotes_simulator_core.simulation.mappers.mappers import EsdlMapperAbstract


class EsdlAssetHeatBufferMapper(EsdlMapperAbstract):
"""Class to map an ESDL asset to a HeatBuffer entity class."""

def to_esdl(self, entity: HeatBuffer) -> EsdlAssetObject:
"""Map a HeatBuffer entity to an EsdlAsset."""
raise NotImplementedError("EsdlAssetHeatBufferMapper.to_esdl()")

def to_entity(self, esdl_asset: EsdlAssetObject) -> AssetAbstract:
"""Method to map an ESDL asset to a HeatBuffer entity class.

:param EsdlAssetObject esdl_asset: Object to be converted to a HeatBuffer entity.
:return: Ates object.
"""
heat_buffer_entity = HeatBuffer(
asset_name=esdl_asset.esdl_asset.name,
asset_id=esdl_asset.esdl_asset.id,
port_ids=esdl_asset.get_port_ids(),
volume=esdl_asset.get_property(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You won't need to call the EsdlAssetObject.get_property()[0] with the zero at the end; the method returns a float so it should work without.

esdl_property_name="volume", default_value=HEAT_BUFFER_DEFAULTS.volume
),
)

return heat_buffer_entity
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class StringEsdlAssetMapper:
esdl.Joint: "joint",
esdl.ATES: "storage",
esdl.HeatPump: "pump",
esdl.HeatStorage: "storage",
esdl.WaterBuffer: "storage",
esdl.HeatExchange: "heat_exchanger",
}

Expand Down
9 changes: 9 additions & 0 deletions src/omotes_simulator_core/entities/assets/asset_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"""Abstract class for asset."""

from abc import ABC, abstractmethod
from datetime import datetime

from pandas import DataFrame, concat

Expand Down Expand Up @@ -65,6 +66,7 @@ def __init__(self, asset_name: str, asset_id: str, connected_ports: list[str]) -
self.connected_ports = connected_ports
self.outputs = [[] for _ in range(len(self.connected_ports))]
self.time_step: float = 3600 # s
self.time = datetime.now()

def __repr__(self) -> str:
"""Method to print string with the name of the asset."""
Expand Down Expand Up @@ -146,6 +148,13 @@ def set_time_step(self, time_step: float) -> None:
"""
self.time_step = time_step

def set_time(self, time: datetime) -> None:
"""Placeholder to set the time for the asset.

:param float time: The time to set for the asset.
"""
self.time = time

def is_converged(self) -> bool:
"""Check if the asset has converged.

Expand Down
11 changes: 11 additions & 0 deletions src/omotes_simulator_core/entities/assets/asset_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ class AtesDefaults:
maximum_flow_discharge: float = 200.0 # m3/h


@dataclass
class HeatBufferDefaults:
"""Class containing the default values for Heat Buffer."""

volume: float = 1 # m3
fill_level: float = 0.5 # fraction 0-1


@dataclass
class HeatPumpDefaults:
"""Class containing the default values for a heat pump.
Expand Down Expand Up @@ -113,6 +121,8 @@ class HeatExchangerDefaults:
PROPERTY_DIAMETER = "diameter"
PROPERTY_ROUGHNESS = "roughness"
PROPERTY_ALPHA_VALUE = "alpha_value"
PROPERTY_VOLUME = "volume"
PROPERTY_FILL_LEVEL = "fill_level"
PROPERTY_PRESSURE_LOSS = "pressure_loss"
PROPERTY_PRESSURE_LOSS_PER_LENGTH = "pressure_loss_per_length"
PROPERTY_HEAT_LOSS = "heat_loss"
Expand All @@ -125,3 +135,4 @@ class HeatExchangerDefaults:
# Static members
PIPE_DEFAULTS = PipeDefaults()
ATES_DEFAULTS = AtesDefaults()
HEAT_BUFFER_DEFAULTS = HeatBufferDefaults()
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def __init__(
self.temperature_out = temperature_out
self.profile: pd.DataFrame = profile
self.start_index = 0

# Theoretical maximum charge and discharge power of the storage.
self.max_charge_power: float = max_charge_power
self.max_discharge_power: float = max_discharge_power

Expand All @@ -58,21 +60,28 @@ def get_heat_power(self, time: datetime.datetime) -> float:
:param datetime.datetime time: Time for which to get the heat demand.
:return: float with the heat demand.
"""
# Check if the selected time is in the profile.
# TODO: Current implementation loops over the entire profile; should be improved!
# TODO: Unclear why there is a timestep of 1 hour in the profile.
for index in range(self.start_index, len(self.profile)):
if abs((self.profile["date"][index].to_pydatetime() - time).total_seconds()) < 3600:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not work as expected; what is the intention? Maybe we should make an seperate issue to review this part.

self.start_index = index
if self.profile["values"][index] > self.max_charge_power:
logging.warning(
f"Storage of {self.name} is higher than maximum charge power of asset"
f" at time {time}."
"Storage of %s is higher than maximum charge power of asset at time %s.",
self.name,
time,
)
return self.max_charge_power
elif self.profile["values"][index] < self.max_discharge_power:
logging.warning(
f"Storage of {self.name} is higher than maximum discharge power of asset"
f" at time {time}."
"Storage of %s is higher than maximum discharge power of asset at time %s.",
self.name,
time,
)
return self.max_discharge_power
else:
return float(self.profile["values"][index])
return 0
# TODO: The loop is not complete as the asset also has a fill-level that should not
# surpass the maximum fill-level.
Comment on lines +85 to +86
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an implementation I made that can be merged/changed after we have completed the current PR.

return 0.0
Loading
Loading