omotes-simulator-core 0.0.3.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omotes_simulator_core-0.0.3.dev0.dist-info/LICENSE +621 -0
- omotes_simulator_core-0.0.3.dev0.dist-info/METADATA +55 -0
- omotes_simulator_core-0.0.3.dev0.dist-info/RECORD +59 -0
- omotes_simulator_core-0.0.3.dev0.dist-info/WHEEL +5 -0
- omotes_simulator_core-0.0.3.dev0.dist-info/top_level.txt +1 -0
- simulator_core/__init__.py +15 -0
- simulator_core/__main__.py +21 -0
- simulator_core/adapter/__init__.py +16 -0
- simulator_core/adapter/presentation/__init__.py +16 -0
- simulator_core/adapter/transforms/__init__.py +16 -0
- simulator_core/adapter/transforms/esdl_asset_mapper.py +53 -0
- simulator_core/adapter/transforms/mappers.py +226 -0
- simulator_core/adapter/transforms/string_to_esdl.py +66 -0
- simulator_core/adapter/transforms/transform_utils.py +34 -0
- simulator_core/entities/__init__.py +16 -0
- simulator_core/entities/assets/__init__.py +16 -0
- simulator_core/entities/assets/asset_abstract.py +116 -0
- simulator_core/entities/assets/asset_defaults.py +68 -0
- simulator_core/entities/assets/controller_classes.py +81 -0
- simulator_core/entities/assets/demand_cluster.py +117 -0
- simulator_core/entities/assets/esdl_asset_object.py +60 -0
- simulator_core/entities/assets/junction.py +64 -0
- simulator_core/entities/assets/pipe.py +174 -0
- simulator_core/entities/assets/production_cluster.py +222 -0
- simulator_core/entities/assets/utils.py +154 -0
- simulator_core/entities/esdl_object.py +90 -0
- simulator_core/entities/heat_network.py +82 -0
- simulator_core/entities/network_controller.py +67 -0
- simulator_core/entities/simulation_configuration.py +31 -0
- simulator_core/entities/utility/__init__.py +16 -0
- simulator_core/entities/utility/influxdb_reader.py +129 -0
- simulator_core/infrastructure/__init__.py +16 -0
- simulator_core/infrastructure/app.py +55 -0
- simulator_core/infrastructure/simulation_manager.py +55 -0
- simulator_core/infrastructure/utils.py +45 -0
- simulator_core/py.typed +0 -0
- simulator_core/simulation/__init__.py +18 -0
- simulator_core/simulation/mappers/__init__.py +16 -0
- simulator_core/simulation/mappers/mappers.py +35 -0
- simulator_core/simulation/networksimulation.py +63 -0
- simulator_core/solver/__init__.py +15 -0
- simulator_core/solver/matrix/__init__.py +15 -0
- simulator_core/solver/matrix/core_enum.py +26 -0
- simulator_core/solver/matrix/equation_object.py +56 -0
- simulator_core/solver/matrix/matrix.py +125 -0
- simulator_core/solver/matrix/utility.py +38 -0
- simulator_core/solver/network/__init__.py +15 -0
- simulator_core/solver/network/assets/__init__.py +15 -0
- simulator_core/solver/network/assets/base_asset.py +303 -0
- simulator_core/solver/network/assets/base_item.py +63 -0
- simulator_core/solver/network/assets/base_node_item.py +67 -0
- simulator_core/solver/network/assets/boundary.py +83 -0
- simulator_core/solver/network/assets/fall_type.py +225 -0
- simulator_core/solver/network/assets/node.py +274 -0
- simulator_core/solver/network/assets/production_asset.py +171 -0
- simulator_core/solver/network/assets/solver_pipe.py +541 -0
- simulator_core/solver/network/network.py +398 -0
- simulator_core/solver/solver.py +80 -0
- simulator_core/solver/utils/fluid_properties.py +173 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Module to read the esdl profiles from an energy system."""
|
|
17
|
+
from esdl.profiles.influxdbprofilemanager import InfluxDBProfileManager
|
|
18
|
+
from esdl.units.conversion import ENERGY_IN_J, POWER_IN_W, convert_to_unit
|
|
19
|
+
import esdl
|
|
20
|
+
from esdl.esdl_handler import EnergySystemHandler
|
|
21
|
+
from typing import Dict, Tuple
|
|
22
|
+
import pandas as pd
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_esdl_profiles(esh: EnergySystemHandler) -> Dict[str, pd.DataFrame]:
|
|
26
|
+
"""Method to parse the esdl profiles from an energy system.
|
|
27
|
+
|
|
28
|
+
This method tries to parse the esdl profiles from an energy system.
|
|
29
|
+
:param esh: EnergySystemHandler with the energy system
|
|
30
|
+
:param start_date: datetime.datetime with the start date
|
|
31
|
+
:param end_date: datetime.datetime with the end date
|
|
32
|
+
:return: dict with the parsed profiles
|
|
33
|
+
"""
|
|
34
|
+
data_set = {}
|
|
35
|
+
for profile in esh.get_all_instances_of_type(esdl.InfluxDBProfile):
|
|
36
|
+
data_set[profile.id] = get_data_from_profile(profile)
|
|
37
|
+
return data_set
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_data_from_profile(esdl_profile: esdl.InfluxDBProfile) -> pd.DataFrame:
|
|
41
|
+
"""Method to get the data from the esdl influxdb profile.
|
|
42
|
+
|
|
43
|
+
This method tries to get the data from the esdl profile.
|
|
44
|
+
:param esdl_profile: esdl.Profile with the profile
|
|
45
|
+
:return: pandas.DataFrame with the data
|
|
46
|
+
"""
|
|
47
|
+
influx_cred_map: Dict[str, Tuple[str, str]] = {}
|
|
48
|
+
profile_host = esdl_profile.host
|
|
49
|
+
ssl_setting = False
|
|
50
|
+
if "https" in profile_host:
|
|
51
|
+
profile_host = profile_host[8:]
|
|
52
|
+
ssl_setting = True
|
|
53
|
+
elif "http" in profile_host:
|
|
54
|
+
profile_host = profile_host[7:]
|
|
55
|
+
# why is this here?
|
|
56
|
+
if esdl_profile.port == 443:
|
|
57
|
+
ssl_setting = True
|
|
58
|
+
|
|
59
|
+
influx_host = "{}:{}".format(profile_host, esdl_profile.port)
|
|
60
|
+
if influx_host in influx_cred_map:
|
|
61
|
+
(username, password) = influx_cred_map[influx_host]
|
|
62
|
+
else:
|
|
63
|
+
username = None
|
|
64
|
+
password = None
|
|
65
|
+
time_series_data = InfluxDBProfileManager.create_esdl_influxdb_profile_manager(
|
|
66
|
+
esdl_profile,
|
|
67
|
+
username,
|
|
68
|
+
password,
|
|
69
|
+
ssl_setting,
|
|
70
|
+
ssl_setting,
|
|
71
|
+
)
|
|
72
|
+
# Error check start and end dates of profiles
|
|
73
|
+
|
|
74
|
+
# I do not thing this is required since you set it in mapeditor.
|
|
75
|
+
if time_series_data.end_datetime != esdl_profile.endDate:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
f"The user input profile end datetime: {esdl_profile.endDate} does not match the end"
|
|
78
|
+
f" datetime in the datbase: {time_series_data.end_datetime} for variable: "
|
|
79
|
+
f"{esdl_profile.field}"
|
|
80
|
+
)
|
|
81
|
+
if time_series_data.start_datetime != esdl_profile.startDate:
|
|
82
|
+
raise RuntimeError(
|
|
83
|
+
f"The user input profile start datetime: {esdl_profile.startDate} does not match the"
|
|
84
|
+
f" start date in the datbase: {time_series_data.start_datetime} for variable: "
|
|
85
|
+
f"{esdl_profile.field}"
|
|
86
|
+
)
|
|
87
|
+
if time_series_data.start_datetime != time_series_data.profile_data_list[0][0]:
|
|
88
|
+
raise RuntimeError(
|
|
89
|
+
f"The profile's variable value for the start datetime: "
|
|
90
|
+
f"{time_series_data.start_datetime} does not match the start datetime of the"
|
|
91
|
+
f" profile data: {time_series_data.profile_data_list[0][0]}"
|
|
92
|
+
)
|
|
93
|
+
if time_series_data.end_datetime != time_series_data.profile_data_list[-1][0]:
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
f"The profile's variable value for the end datetime: "
|
|
96
|
+
f"{time_series_data.end_datetime} does not match the end datetime of the"
|
|
97
|
+
f" profile data: {time_series_data.profile_data_list[-1][0]}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
unit = get_unit(esdl_profile)
|
|
101
|
+
dates = [time_stamp for time_stamp, _ in
|
|
102
|
+
time_series_data.profile_data_list]
|
|
103
|
+
values = [convert_to_unit(value, esdl_profile.profileQuantityAndUnit, unit)
|
|
104
|
+
* esdl_profile.multiplier
|
|
105
|
+
for _, value in time_series_data.profile_data_list]
|
|
106
|
+
data_points = {"date": dates, "values": values}
|
|
107
|
+
|
|
108
|
+
return pd.DataFrame(data_points)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_unit(profile: esdl.InfluxDBProfile) -> esdl.PhysicalQuantityEnum:
|
|
112
|
+
"""Method to get the SI unit of the profile.
|
|
113
|
+
|
|
114
|
+
This method tries to get the unit of the profile.
|
|
115
|
+
if the unit is not in the list the same unit as the profile is returned
|
|
116
|
+
:param profile: esdl.InfluxDBProfile with the profile
|
|
117
|
+
:return: esdl.PhysicalQuantityEnum with the unit
|
|
118
|
+
"""
|
|
119
|
+
conversion_dict = {
|
|
120
|
+
esdl.PhysicalQuantityEnum.POWER: POWER_IN_W,
|
|
121
|
+
esdl.PhysicalQuantityEnum.ENERGY: ENERGY_IN_J
|
|
122
|
+
}
|
|
123
|
+
try:
|
|
124
|
+
profile_unit = profile.profileQuantityAndUnit.reference.physicalQuantity
|
|
125
|
+
except AttributeError:
|
|
126
|
+
profile_unit = profile.profileQuantityAndUnit.physicalQuantity
|
|
127
|
+
if profile_unit in conversion_dict:
|
|
128
|
+
return conversion_dict[profile_unit]
|
|
129
|
+
return profile_unit
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""__init__.py file for initialization code."""
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Entry point for running simulator-core library from cmdline."""
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import sys
|
|
20
|
+
import traceback
|
|
21
|
+
import uuid
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
|
|
24
|
+
import pandas as pd
|
|
25
|
+
|
|
26
|
+
from simulator_core.entities.esdl_object import EsdlObject
|
|
27
|
+
from simulator_core.entities.simulation_configuration import SimulationConfiguration
|
|
28
|
+
from simulator_core.infrastructure.simulation_manager import SimulationManager
|
|
29
|
+
from simulator_core.infrastructure.utils import pyesdl_from_file
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def run(file_path: str | None = None) -> pd.DataFrame:
|
|
35
|
+
"""Main run function for the heatnetwork simulator."""
|
|
36
|
+
config = SimulationConfiguration(
|
|
37
|
+
simulation_id=uuid.uuid1(),
|
|
38
|
+
name="test run",
|
|
39
|
+
timestep=3600,
|
|
40
|
+
start=datetime.strptime("2019-01-01T00:00:00", "%Y-%m-%dT%H:%M:%S"),
|
|
41
|
+
stop=datetime.strptime("2019-01-01T01:00:00", "%Y-%m-%dT%H:%M:%S"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
esdl_file_path = sys.argv[1] if file_path is None else file_path
|
|
45
|
+
try:
|
|
46
|
+
app = SimulationManager(EsdlObject(pyesdl_from_file(esdl_file_path)), config)
|
|
47
|
+
result = app.execute()
|
|
48
|
+
return result
|
|
49
|
+
except Exception as error:
|
|
50
|
+
logger.error(f"Error occured: {error} at: {traceback.format_exc(limit=-1)}")
|
|
51
|
+
logger.debug(traceback.format_exc())
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
print(run(r".\testdata\test1.esdl"))
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Simulation manager creates and controls the simulation objects."""
|
|
17
|
+
|
|
18
|
+
import pandas as pd
|
|
19
|
+
|
|
20
|
+
from simulator_core.adapter.transforms.mappers import EsdlControllerMapper, EsdlEnergySystemMapper
|
|
21
|
+
from simulator_core.entities.esdl_object import EsdlObject
|
|
22
|
+
from simulator_core.entities.heat_network import HeatNetwork
|
|
23
|
+
from simulator_core.entities.simulation_configuration import SimulationConfiguration
|
|
24
|
+
from simulator_core.simulation import NetworkSimulation
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SimulationManager:
|
|
28
|
+
"""Manager class for managing the simulation."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, esdl: EsdlObject, config: SimulationConfiguration):
|
|
31
|
+
"""Constructor for SimulationManager class.
|
|
32
|
+
|
|
33
|
+
:param EsdlObject esdl: Esdlobject, which stores the network information
|
|
34
|
+
:param SimulationConfiguration config: Config object to hold the simulation start, stop, end
|
|
35
|
+
"""
|
|
36
|
+
self.esdl = esdl
|
|
37
|
+
self.config = config
|
|
38
|
+
|
|
39
|
+
def execute(self) -> pd.DataFrame:
|
|
40
|
+
"""Method to simulate the network.
|
|
41
|
+
|
|
42
|
+
First the network is converted to pandapipes and then the simulation is run.
|
|
43
|
+
|
|
44
|
+
:return: DataFrame with the result of the simulations
|
|
45
|
+
"""
|
|
46
|
+
# convert ESDL to Heat Network, NetworkController
|
|
47
|
+
network = HeatNetwork(EsdlEnergySystemMapper(self.esdl).to_entity)
|
|
48
|
+
controller = EsdlControllerMapper().to_entity(self.esdl)
|
|
49
|
+
|
|
50
|
+
worker = NetworkSimulation(network, controller)
|
|
51
|
+
worker.run(self.config)
|
|
52
|
+
|
|
53
|
+
# Run output presenter that iterates over het network (/controller?) and
|
|
54
|
+
# gathers the output into a single data object
|
|
55
|
+
return worker.gather_output()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Module containing utility functions."""
|
|
17
|
+
|
|
18
|
+
from esdl.esdl_handler import EnergySystemHandler
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def pyesdl_from_file(file_path: str) -> EnergySystemHandler:
|
|
23
|
+
"""
|
|
24
|
+
Loads esdl file into memory and returns a handle to be able to use this file.
|
|
25
|
+
|
|
26
|
+
Please note that it is not checked if the file is a valid esdl file.
|
|
27
|
+
:param file_path: string pointing to the esdl file to be loaded into memory
|
|
28
|
+
"""
|
|
29
|
+
if not Path(file_path).is_file():
|
|
30
|
+
raise FileNotFoundError("Not a valid path to an ESDL file")
|
|
31
|
+
esh = EnergySystemHandler()
|
|
32
|
+
esh.load_file(file_path)
|
|
33
|
+
return esh
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def pyesdl_from_string(input_str: str) -> EnergySystemHandler:
|
|
37
|
+
"""
|
|
38
|
+
Loads esdl file from a string into memory.
|
|
39
|
+
|
|
40
|
+
Please note that it is not checked if the contents of the string is a valid esdl.
|
|
41
|
+
:param input_str: string containing the contents of an esdl file.
|
|
42
|
+
"""
|
|
43
|
+
esh = EnergySystemHandler()
|
|
44
|
+
esh.load_from_string(input_str)
|
|
45
|
+
return esh
|
simulator_core/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""__init__.py file for initialization code."""
|
|
17
|
+
|
|
18
|
+
from .networksimulation import NetworkSimulation
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""__init__.py file for initialization code."""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Module containing the abstract class for the mappers."""
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from typing import Generic, TypeVar
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Entity = TypeVar("Entity")
|
|
23
|
+
EsdlAssetObject = TypeVar("EsdlAssetObject")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EsdlMapperAbstract(ABC, Generic[Entity, EsdlAssetObject]):
|
|
27
|
+
"""Abstract class to be used for deriving mapper classes from esdl to our own classes."""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def to_esdl(self, entity: Entity) -> EsdlAssetObject:
|
|
31
|
+
"""Map an Entity to a EsdlAsset."""
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def to_entity(self, model: EsdlAssetObject) -> Entity:
|
|
35
|
+
"""Map am esdl asset to an Entity."""
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
"""Simulates an heat network for the specified duration."""
|
|
17
|
+
|
|
18
|
+
from pandas import DataFrame
|
|
19
|
+
from simulator_core.entities.heat_network import HeatNetwork
|
|
20
|
+
from simulator_core.entities.network_controller import NetworkController
|
|
21
|
+
from simulator_core.entities.simulation_configuration import SimulationConfiguration
|
|
22
|
+
from datetime import timedelta, timezone
|
|
23
|
+
|
|
24
|
+
import logging
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class NetworkSimulation:
|
|
30
|
+
"""NetworkSimulation connects the controller and HeatNetwork (incl. assets)."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, network: HeatNetwork, controller: NetworkController):
|
|
33
|
+
"""Instantiate the NetworkSimulation object."""
|
|
34
|
+
self.network = network
|
|
35
|
+
self.controller = controller
|
|
36
|
+
|
|
37
|
+
def run(self, config: SimulationConfiguration) -> None:
|
|
38
|
+
"""Run the simulation.
|
|
39
|
+
|
|
40
|
+
:param SimulationConfiguration config: Configuration to run the simulation with.
|
|
41
|
+
"""
|
|
42
|
+
# time loop
|
|
43
|
+
number_of_time_steps = int((config.stop - config.start).total_seconds() / config.timestep)
|
|
44
|
+
for time_step in range(number_of_time_steps):
|
|
45
|
+
not_converged = True
|
|
46
|
+
time = (config.start + timedelta(seconds=time_step * config.timestep)
|
|
47
|
+
).replace(tzinfo=timezone.utc)
|
|
48
|
+
controller_input = self.controller.run_time_step(time)
|
|
49
|
+
|
|
50
|
+
while not_converged:
|
|
51
|
+
not_converged = False # for the moment we do not check on convergence,
|
|
52
|
+
# to get stuff running. Also need to add break after 10 iteration.
|
|
53
|
+
logger.debug("Simulating for timestep " + str(time))
|
|
54
|
+
self.network.run_time_step(time, controller_input)
|
|
55
|
+
self.network.store_output()
|
|
56
|
+
|
|
57
|
+
def gather_output(self) -> DataFrame:
|
|
58
|
+
"""Gathers all output and return a dict with this output.
|
|
59
|
+
|
|
60
|
+
:return: DataFrame with all the results for the simulation
|
|
61
|
+
"""
|
|
62
|
+
result = self.network.gather_output()
|
|
63
|
+
return result
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
"""__init__.py file for initialization code."""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
"""__init__.py file for initialization code."""
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
"""This file contains the enum for the core quantities of the matrix."""
|
|
16
|
+
from enum import IntEnum
|
|
17
|
+
|
|
18
|
+
NUMBER_CORE_QUANTITIES = 3
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class IndexEnum(IntEnum):
|
|
22
|
+
"""Enum for the index of the matrix."""
|
|
23
|
+
|
|
24
|
+
discharge = 0
|
|
25
|
+
pressure = 1
|
|
26
|
+
internal_energy = 2
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright (c) 2023. Deltares & TNO
|
|
2
|
+
#
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
"""Module containing class to store equations."""
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class EquationObject:
|
|
20
|
+
"""Class to store equation objects.
|
|
21
|
+
|
|
22
|
+
Indices are the location in the matrix of the coefficients
|
|
23
|
+
rhs is the rhs of the matrix.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
indices: np.ndarray
|
|
27
|
+
"""Indices of the coefficients in the matrix."""
|
|
28
|
+
|
|
29
|
+
coefficients: np.ndarray
|
|
30
|
+
"""Coefficients of the equation."""
|
|
31
|
+
|
|
32
|
+
rhs: float
|
|
33
|
+
"""Right hand side of the equation."""
|
|
34
|
+
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
"""Constructor of the EquationObject."""
|
|
37
|
+
self.indices = np.array([], dtype=int)
|
|
38
|
+
self.coefficients = np.array([], dtype=float)
|
|
39
|
+
self.rhs = 0.0
|
|
40
|
+
|
|
41
|
+
def to_list(self, length: int) -> list[float]:
|
|
42
|
+
"""Method to change the equation object to list which can be stored in the matrix.
|
|
43
|
+
|
|
44
|
+
The method creates a list with zero of the length given in the input.
|
|
45
|
+
At the indices of the class the coefficients of the class are stored.
|
|
46
|
+
:param int length: Length of the list to be returned
|
|
47
|
+
:return: a list of the coefficient which can be used in the matrix.
|
|
48
|
+
"""
|
|
49
|
+
if length < len(self.indices):
|
|
50
|
+
raise IndexError(f"Length of {length} smaller than the available number "
|
|
51
|
+
f"of coefficients {len(self.coefficients)}!")
|
|
52
|
+
|
|
53
|
+
coefficient_list: list[float] = [0.0] * length
|
|
54
|
+
for col, coefficient in zip(self.indices, self.coefficients):
|
|
55
|
+
coefficient_list[col] = coefficient
|
|
56
|
+
return coefficient_list
|