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,125 @@
|
|
|
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 a matrix class to store the matrix and solve it using numpy."""
|
|
16
|
+
import numpy as np
|
|
17
|
+
import csv
|
|
18
|
+
from simulator_core.solver.matrix.equation_object import EquationObject
|
|
19
|
+
from simulator_core.solver.matrix.utility import absolute_difference, relative_difference
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Matrix:
|
|
23
|
+
"""Class which stores the matrix and can be used to solve it."""
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
"""Constructor of matrix class."""
|
|
27
|
+
self.num_unknowns: int = 0
|
|
28
|
+
self.mat: list[list[float]] = []
|
|
29
|
+
self.rhs: list[float] = []
|
|
30
|
+
self.sol_new: list[float] = []
|
|
31
|
+
self.sol_old: list[float] = []
|
|
32
|
+
self.relative_convergence: float = 1e-6
|
|
33
|
+
self.absolute_convergence: float = 1e-6
|
|
34
|
+
|
|
35
|
+
def add_unknowns(self, number_unknowns: int) -> int:
|
|
36
|
+
"""Method to add unknowns to the matrix.
|
|
37
|
+
|
|
38
|
+
Adds unknowns to the matrix and returns the location of the unknowns in the solution.
|
|
39
|
+
:param int number_unknowns: Number of unknowns to add
|
|
40
|
+
:return: int Starting index of the added unknowns.
|
|
41
|
+
"""
|
|
42
|
+
if number_unknowns < 1:
|
|
43
|
+
raise ValueError("Number of unknowns should be at least 1.")
|
|
44
|
+
self.num_unknowns += number_unknowns
|
|
45
|
+
self.sol_new += [1.0] * number_unknowns
|
|
46
|
+
self.sol_old += [0.0] * number_unknowns
|
|
47
|
+
return self.num_unknowns - number_unknowns
|
|
48
|
+
|
|
49
|
+
def add_equation(self, equation_object: EquationObject) -> None:
|
|
50
|
+
"""Method to add an equation to the matrix.
|
|
51
|
+
|
|
52
|
+
Add equation to the matrix it returns a unique id to the equation for easy access.
|
|
53
|
+
:param EquationObject equation_object: Object containing all information of the equation
|
|
54
|
+
:return:
|
|
55
|
+
"""
|
|
56
|
+
row = len(self.rhs)
|
|
57
|
+
self.rhs.append(0.0)
|
|
58
|
+
self.mat.append([])
|
|
59
|
+
self.mat[row] = equation_object.to_list(self.num_unknowns)
|
|
60
|
+
self.rhs[row] = equation_object.rhs
|
|
61
|
+
|
|
62
|
+
def solve(self, equations: list[EquationObject], dumb: bool = False) -> list[float]:
|
|
63
|
+
"""Method to solve the system of equation given in the matrix.
|
|
64
|
+
|
|
65
|
+
Solves the system of equations and returns the solution. The numpy linalg
|
|
66
|
+
library solve method is used. For this the matrix is converted to np arrays.
|
|
67
|
+
:return: list containing the solution of the system of equations.
|
|
68
|
+
"""
|
|
69
|
+
# TODO add checks if enough equations have been supplied.
|
|
70
|
+
# TODO check if matrix is solvable.
|
|
71
|
+
self.rhs = []
|
|
72
|
+
self.mat = []
|
|
73
|
+
for equation in equations:
|
|
74
|
+
self.add_equation(equation)
|
|
75
|
+
if dumb:
|
|
76
|
+
self.dump_matrix()
|
|
77
|
+
self.sol_old = self.sol_new
|
|
78
|
+
a = np.array(self.mat)
|
|
79
|
+
b = np.array(self.rhs)
|
|
80
|
+
self.sol_new = np.linalg.solve(a, b).tolist()
|
|
81
|
+
return self.sol_new
|
|
82
|
+
|
|
83
|
+
def is_converged(self) -> bool:
|
|
84
|
+
"""Returns true when the solution has converged and false when not.
|
|
85
|
+
|
|
86
|
+
This method uses both the absolute difference and the relative difference to determine if
|
|
87
|
+
the solution has converged. If one of them is converged true is returned.
|
|
88
|
+
:return: Bool whether the solution has converged based on the given convergence criteria.
|
|
89
|
+
"""
|
|
90
|
+
if self.num_unknowns == 0:
|
|
91
|
+
raise ValueError("No unknowns have been added to the matrix.")
|
|
92
|
+
rel_dif = max(
|
|
93
|
+
[relative_difference(old, new) for old, new in zip(self.sol_old, self.sol_new)])
|
|
94
|
+
abs_dif = max(
|
|
95
|
+
[absolute_difference(old, new) for old, new in zip(self.sol_old, self.sol_new)])
|
|
96
|
+
return rel_dif < self.relative_convergence or abs_dif < self.absolute_convergence
|
|
97
|
+
|
|
98
|
+
def get_solution(self, index: int, number_of_unknowns: int) -> list[float]:
|
|
99
|
+
"""Method to get the solution of an asset.
|
|
100
|
+
|
|
101
|
+
Returns the solution starting at the given index and for the number of
|
|
102
|
+
unknowns supplied at the input.
|
|
103
|
+
|
|
104
|
+
:param int index:Start position for which to supply the solution
|
|
105
|
+
:param int number_of_unknowns: Number of elements for which the solution needs to
|
|
106
|
+
be provided
|
|
107
|
+
:return: list with teh solution
|
|
108
|
+
"""
|
|
109
|
+
# TODO add checks if the index and number of unknowns are within the range of the solution.
|
|
110
|
+
return self.sol_new[index:index + number_of_unknowns]
|
|
111
|
+
|
|
112
|
+
def dump_matrix(self, file_name: str = 'dump.csv') -> None:
|
|
113
|
+
"""Method to dump the matrix to a csv file.
|
|
114
|
+
|
|
115
|
+
:param str file_name: File name to dump the matrix in default=dump.csv
|
|
116
|
+
:return:
|
|
117
|
+
"""
|
|
118
|
+
with open(file_name, 'w', newline='') as f:
|
|
119
|
+
write = csv.writer(f)
|
|
120
|
+
for row, rhs in zip(self.mat, self.rhs):
|
|
121
|
+
write.writerow(row + [rhs])
|
|
122
|
+
|
|
123
|
+
def reset_solution(self) -> None:
|
|
124
|
+
"""Method to reset the solution to 1, so the new iteration can start."""
|
|
125
|
+
self.sol_new = [1.0] * len(self.sol_new)
|
|
@@ -0,0 +1,38 @@
|
|
|
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 utility functions for the matrix."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def relative_difference(value_1: float, value_2: float) -> float:
|
|
19
|
+
"""Calculates the relative difference between two points.
|
|
20
|
+
|
|
21
|
+
:param value_1: first value to be used
|
|
22
|
+
:param value_2: second value to be used
|
|
23
|
+
:return: Relative difference, return 0 when the difference is 0.
|
|
24
|
+
"""
|
|
25
|
+
diff = absolute_difference(value_1, value_2)
|
|
26
|
+
if diff > 0.0:
|
|
27
|
+
return diff / max(abs(value_1), abs(value_2))
|
|
28
|
+
return 0.0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def absolute_difference(value_1: float, value_2: float) -> float:
|
|
32
|
+
"""Calculates the absolute difference between two points.
|
|
33
|
+
|
|
34
|
+
:param value_1: first value to be used
|
|
35
|
+
:param value_2: second value to be used
|
|
36
|
+
:return: Absolute difference between value 1 and 2
|
|
37
|
+
"""
|
|
38
|
+
return abs(value_1 - value_2)
|
|
@@ -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,303 @@
|
|
|
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 BaseAsset class."""
|
|
17
|
+
import math
|
|
18
|
+
import uuid
|
|
19
|
+
from typing import Dict
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
from simulator_core.solver.matrix.core_enum import NUMBER_CORE_QUANTITIES, IndexEnum
|
|
24
|
+
from simulator_core.solver.matrix.equation_object import EquationObject
|
|
25
|
+
from simulator_core.solver.network.assets.base_item import BaseItem
|
|
26
|
+
from simulator_core.solver.network.assets.base_node_item import BaseNodeItem
|
|
27
|
+
from simulator_core.solver.utils.fluid_properties import fluid_props
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BaseAsset(BaseItem):
|
|
31
|
+
"""A base class for assets in a network.
|
|
32
|
+
|
|
33
|
+
This class inherits from BaseItem and provides methods for connecting nodes, checking connection
|
|
34
|
+
status, and adding thermal and pressure equations.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
connected_nodes: Dict[int, BaseNodeItem]
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
name: uuid.UUID,
|
|
42
|
+
number_of_unknowns: int = 6,
|
|
43
|
+
number_connection_points: int = 2,
|
|
44
|
+
supply_temperature: float = 293.15,
|
|
45
|
+
):
|
|
46
|
+
"""Initializes the BaseAsset object with the given parameters.
|
|
47
|
+
|
|
48
|
+
:param uuid.UUID name: The unique identifier of the node.
|
|
49
|
+
:param int, optional number_of_unknowns: The number of unknown variables for the node.
|
|
50
|
+
The default is 3.
|
|
51
|
+
:param int, optional number_connection_points: The number of connection points for the
|
|
52
|
+
asset. The default is 2, which corresponds to the inlet and outlet.
|
|
53
|
+
"""
|
|
54
|
+
super().__init__(
|
|
55
|
+
name=name,
|
|
56
|
+
number_of_unknowns=number_of_unknowns,
|
|
57
|
+
number_connection_points=number_connection_points,
|
|
58
|
+
)
|
|
59
|
+
self.supply_temperature = supply_temperature
|
|
60
|
+
self.connected_nodes = {}
|
|
61
|
+
|
|
62
|
+
def check_connection_point_valid(self, connection_point: int) -> bool:
|
|
63
|
+
"""Checks if the connection point is valid for the asset.
|
|
64
|
+
|
|
65
|
+
:param connection_point: The index of the connection point to check.
|
|
66
|
+
:type connection_point: int
|
|
67
|
+
:return: True if the connection point is valid, otherwise raises an IndexError.
|
|
68
|
+
:rtype: bool
|
|
69
|
+
"""
|
|
70
|
+
if connection_point > self.number_of_connection_point - 1:
|
|
71
|
+
raise IndexError(
|
|
72
|
+
f"Asset {self.name} only has {self.number_of_connection_point - 1}. "
|
|
73
|
+
f"{connection_point} is too high"
|
|
74
|
+
)
|
|
75
|
+
else:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
def connect_node(self, connection_point: int, node: BaseNodeItem) -> None:
|
|
79
|
+
"""Connects a node to a connection point of the asset.
|
|
80
|
+
|
|
81
|
+
:param connection_point: The index of the connection point to connect.
|
|
82
|
+
:type connection_point: int
|
|
83
|
+
:param node: The node to connect.
|
|
84
|
+
:type node: Node
|
|
85
|
+
:raises ValueError: If the connection point is already connected to a node.
|
|
86
|
+
"""
|
|
87
|
+
self.check_connection_point_valid(connection_point)
|
|
88
|
+
if connection_point in self.connected_nodes:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f" connection point {connection_point} of asset {self.name} "
|
|
91
|
+
f" already connected to a node"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.connected_nodes[connection_point] = node
|
|
95
|
+
|
|
96
|
+
def disconnect_node(self, connection_point: int) -> None:
|
|
97
|
+
"""Disconnects a node from a connection point of the asset.
|
|
98
|
+
|
|
99
|
+
:param connection_point: The index of the connection point to disconnect.
|
|
100
|
+
:type connection_point: int
|
|
101
|
+
:raises ValueError: If the connection point is not connected to a node.
|
|
102
|
+
"""
|
|
103
|
+
self.check_connection_point_valid(connection_point)
|
|
104
|
+
del self.connected_nodes[connection_point]
|
|
105
|
+
|
|
106
|
+
def is_connected(self, connection_point: int) -> bool:
|
|
107
|
+
"""Checks if a connection point is connected to a node.
|
|
108
|
+
|
|
109
|
+
:param connection_point: The index of the connection point to check.
|
|
110
|
+
:type connection_point: int
|
|
111
|
+
:return: True if the connection point is connected, False otherwise.
|
|
112
|
+
:rtype: bool
|
|
113
|
+
"""
|
|
114
|
+
if self.check_connection_point_valid(connection_point):
|
|
115
|
+
return connection_point in self.connected_nodes
|
|
116
|
+
else:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
def get_connected_node(self, connection_point: int) -> BaseNodeItem:
|
|
120
|
+
"""Checks if a connection point is connected to a node.
|
|
121
|
+
|
|
122
|
+
:param connection_point: The index of the connection point to check.
|
|
123
|
+
:type connection_point: int
|
|
124
|
+
:return: True if the connection point is connected, False otherwise.
|
|
125
|
+
:rtype: bool
|
|
126
|
+
"""
|
|
127
|
+
self.check_connection_point_valid(connection_point)
|
|
128
|
+
|
|
129
|
+
if self.is_connected(connection_point):
|
|
130
|
+
return self.connected_nodes[connection_point]
|
|
131
|
+
raise ValueError(str(connection_point) + " is not connected")
|
|
132
|
+
|
|
133
|
+
def is_all_connected(self) -> bool:
|
|
134
|
+
"""Checks if all connection points are connected to nodes.
|
|
135
|
+
|
|
136
|
+
:return: True if all connection points are connected, False otherwise.
|
|
137
|
+
:rtype: bool
|
|
138
|
+
"""
|
|
139
|
+
result = [self.is_connected(i) for i in range(self.number_of_connection_point)]
|
|
140
|
+
return all(result)
|
|
141
|
+
|
|
142
|
+
def add_thermal_equations(self, connection_point: int) -> EquationObject:
|
|
143
|
+
"""Adds a thermal equation for a connection point of the asset.
|
|
144
|
+
|
|
145
|
+
:param connection_point: The index of the connection point to add the equation for.
|
|
146
|
+
:type connection_point: int
|
|
147
|
+
:return: An equation object representing the thermal equation.
|
|
148
|
+
:rtype: EquationObject
|
|
149
|
+
"""
|
|
150
|
+
if self.prev_sol[IndexEnum.discharge + connection_point * NUMBER_CORE_QUANTITIES] > 0:
|
|
151
|
+
return self.add_prescribe_temp(connection_point)
|
|
152
|
+
else:
|
|
153
|
+
return self.add_temp_to_node_equation(connection_point)
|
|
154
|
+
|
|
155
|
+
def add_prescribe_temp(self, connection_point: int) -> EquationObject:
|
|
156
|
+
"""Adds a prescribed temperature equation for a connection point of the asset.
|
|
157
|
+
|
|
158
|
+
:param connection_point: The index of the connection point to add the equation for.
|
|
159
|
+
:type connection_point: int
|
|
160
|
+
:return: An equation object representing the prescribed temperature equation.
|
|
161
|
+
:rtype: EquationObject
|
|
162
|
+
"""
|
|
163
|
+
if not self.is_connected(connection_point=connection_point):
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Connection point {connection_point} of asset {self.name} is not connected to a"
|
|
166
|
+
+ " node."
|
|
167
|
+
)
|
|
168
|
+
equation_object = EquationObject()
|
|
169
|
+
equation_object.indices = np.array(
|
|
170
|
+
[
|
|
171
|
+
self.matrix_index
|
|
172
|
+
+ IndexEnum.internal_energy
|
|
173
|
+
+ connection_point * NUMBER_CORE_QUANTITIES
|
|
174
|
+
]
|
|
175
|
+
)
|
|
176
|
+
equation_object.coefficients = np.array([1.0])
|
|
177
|
+
equation_object.rhs = fluid_props.get_ie(self.supply_temperature)
|
|
178
|
+
return equation_object
|
|
179
|
+
|
|
180
|
+
def add_temp_to_node_equation(self, connection_point: int) -> EquationObject:
|
|
181
|
+
"""Adds a temperature to node equation for a connection point of the asset.
|
|
182
|
+
|
|
183
|
+
:param connection_point: The index of the connection point to add the equation for.
|
|
184
|
+
:type connection_point: int
|
|
185
|
+
:return: An equation object representing the temperature to node equation.
|
|
186
|
+
:rtype: EquationObject
|
|
187
|
+
"""
|
|
188
|
+
# Check if the connection point is connected to a node
|
|
189
|
+
if not self.is_connected(connection_point=connection_point):
|
|
190
|
+
raise ValueError(
|
|
191
|
+
f"Connection point {connection_point} of asset {self.name} is not connected to a"
|
|
192
|
+
+ " node."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
equation_object = EquationObject()
|
|
196
|
+
equation_object.indices = np.array(
|
|
197
|
+
[
|
|
198
|
+
self.matrix_index
|
|
199
|
+
+ IndexEnum.internal_energy
|
|
200
|
+
+ connection_point * NUMBER_CORE_QUANTITIES,
|
|
201
|
+
self.get_connected_node(connection_point).matrix_index + IndexEnum.internal_energy,
|
|
202
|
+
]
|
|
203
|
+
)
|
|
204
|
+
equation_object.coefficients = np.array([1.0, -1.0])
|
|
205
|
+
equation_object.rhs = 0.0
|
|
206
|
+
return equation_object
|
|
207
|
+
|
|
208
|
+
def set_physical_properties(self, physical_properties: Dict[str, float]) -> None:
|
|
209
|
+
"""Method to set the physical properties of the asset.
|
|
210
|
+
|
|
211
|
+
This method is implemented in the derived classes of this class.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
def add_press_to_node_equation(self, connection_point: int) -> EquationObject:
|
|
215
|
+
"""Adds a pressure to node equation for a connection point of the asset.
|
|
216
|
+
|
|
217
|
+
:param connection_point: The index of the connection point to add the equation for.
|
|
218
|
+
:type connection_point: int
|
|
219
|
+
:return: An equation object representing the pressure to node equation.
|
|
220
|
+
:rtype: EquationObject
|
|
221
|
+
"""
|
|
222
|
+
# Check if the connection point is connected to a node
|
|
223
|
+
if not self.is_connected(connection_point=connection_point):
|
|
224
|
+
raise ValueError(
|
|
225
|
+
f"Connection point {connection_point} of asset {self.name} is not connected to a"
|
|
226
|
+
+ " node."
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
equation_object = EquationObject()
|
|
230
|
+
equation_object.indices = np.array(
|
|
231
|
+
[
|
|
232
|
+
self.matrix_index + IndexEnum.pressure + connection_point * NUMBER_CORE_QUANTITIES,
|
|
233
|
+
self.connected_nodes[connection_point].matrix_index + IndexEnum.pressure,
|
|
234
|
+
]
|
|
235
|
+
)
|
|
236
|
+
equation_object.coefficients = np.array([1.0, -1.0])
|
|
237
|
+
equation_object.rhs = 0.0
|
|
238
|
+
return equation_object
|
|
239
|
+
|
|
240
|
+
def get_result(self) -> list[float]:
|
|
241
|
+
"""Method to get the result of the asset.
|
|
242
|
+
|
|
243
|
+
:return: a list of the unknowns which are solved.
|
|
244
|
+
"""
|
|
245
|
+
results = []
|
|
246
|
+
for i in range(self.number_of_connection_point):
|
|
247
|
+
for j in range(math.floor(self.number_of_unknowns / self.number_of_connection_point)):
|
|
248
|
+
if j == 2:
|
|
249
|
+
results.append(
|
|
250
|
+
fluid_props.get_t(
|
|
251
|
+
self.prev_sol[
|
|
252
|
+
i
|
|
253
|
+
* math.floor(
|
|
254
|
+
self.number_of_unknowns / self.number_of_connection_point
|
|
255
|
+
)
|
|
256
|
+
+ j
|
|
257
|
+
]
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
else:
|
|
261
|
+
results.append(
|
|
262
|
+
self.prev_sol[
|
|
263
|
+
i
|
|
264
|
+
* math.floor(self.number_of_unknowns / self.number_of_connection_point)
|
|
265
|
+
+ j
|
|
266
|
+
]
|
|
267
|
+
)
|
|
268
|
+
return results
|
|
269
|
+
|
|
270
|
+
def get_equations(self) -> list[EquationObject]:
|
|
271
|
+
"""Method to get the equations of the asset.
|
|
272
|
+
|
|
273
|
+
This method is implemented in the derived classes of this class.
|
|
274
|
+
|
|
275
|
+
:return: A list of equation objects representing the equations of the asset.
|
|
276
|
+
"""
|
|
277
|
+
return []
|
|
278
|
+
|
|
279
|
+
def get_mass_flow_rate(self, connection_point: int) -> float:
|
|
280
|
+
"""Method to get the mass flow rate of a connection point.
|
|
281
|
+
|
|
282
|
+
:param int connection_point: The connection point for which to get the mass flow rate.
|
|
283
|
+
:return: The mass flow rate of the connection point.
|
|
284
|
+
"""
|
|
285
|
+
return self.prev_sol[IndexEnum.discharge + connection_point * NUMBER_CORE_QUANTITIES]
|
|
286
|
+
|
|
287
|
+
def get_pressure(self, connection_point: int) -> float:
|
|
288
|
+
"""Method to get the pressure of a connection point.
|
|
289
|
+
|
|
290
|
+
:param int connection_point: The connection point for which to get the pressure.
|
|
291
|
+
:return: The pressure of the connection point.
|
|
292
|
+
"""
|
|
293
|
+
return self.prev_sol[IndexEnum.pressure + connection_point * NUMBER_CORE_QUANTITIES]
|
|
294
|
+
|
|
295
|
+
def get_temperature(self, connection_point: int) -> float:
|
|
296
|
+
"""Method to get the temperature of a connection point.
|
|
297
|
+
|
|
298
|
+
:param int connection_point: The connection point for which to get the temperature.
|
|
299
|
+
:return: The temperature of the connection point.
|
|
300
|
+
"""
|
|
301
|
+
return fluid_props.get_t(
|
|
302
|
+
self.prev_sol[IndexEnum.internal_energy + connection_point * NUMBER_CORE_QUANTITIES]
|
|
303
|
+
)
|
|
@@ -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
|
+
"""Module containing abstract BaseItem class."""
|
|
17
|
+
import uuid
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
|
|
20
|
+
from simulator_core.solver.matrix.equation_object import EquationObject
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BaseItem(ABC):
|
|
24
|
+
"""A base class for items in a network."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, number_of_unknowns: int, name: uuid.UUID, number_connection_points: int):
|
|
27
|
+
"""Initializes the BaseItem object with the given parameters.
|
|
28
|
+
|
|
29
|
+
:param int number_of_unknowns: The number of unknown variables for the item.
|
|
30
|
+
:param uuid.UUID name: The unique identifier of the item.
|
|
31
|
+
:param int number_connection_points: The number of connection points of the item.
|
|
32
|
+
"""
|
|
33
|
+
self.name = name
|
|
34
|
+
self.number_of_unknowns = number_of_unknowns
|
|
35
|
+
self.number_of_connection_point = number_connection_points
|
|
36
|
+
self.matrix_index = 0
|
|
37
|
+
self.prev_sol: list[float] = [0.0] * self.number_of_unknowns
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
"""Returns the string representation of the item."""
|
|
41
|
+
return str(self.name)
|
|
42
|
+
|
|
43
|
+
def set_matrix_index(self, index: int) -> None:
|
|
44
|
+
"""Sets the matrix index of the item.
|
|
45
|
+
|
|
46
|
+
:param int index: The index of the item in the matrix.
|
|
47
|
+
"""
|
|
48
|
+
self.matrix_index = index
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def get_equations(self) -> list[EquationObject]:
|
|
52
|
+
"""Returns the equations for the item.
|
|
53
|
+
|
|
54
|
+
:return: The equations for the item.
|
|
55
|
+
:rtype: list[EquationObject]
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def disconnect_node(self, connection_point: int) -> None:
|
|
60
|
+
"""Disconnects a node from the item.
|
|
61
|
+
|
|
62
|
+
:param int connection_point: The connection point to disconnect.
|
|
63
|
+
"""
|
|
@@ -0,0 +1,67 @@
|
|
|
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 abstract BaseNodeItem class."""
|
|
17
|
+
import uuid
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
|
|
20
|
+
from simulator_core.solver.matrix.equation_object import EquationObject
|
|
21
|
+
from simulator_core.solver.network.assets.base_item import BaseItem
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BaseNodeItem(ABC):
|
|
25
|
+
"""A base class for node items in a network."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, number_of_unknowns: int, name: uuid.UUID):
|
|
28
|
+
"""Initializes the BaseNodeItem object with the given parameters.
|
|
29
|
+
|
|
30
|
+
:param int number_of_unknowns: The number of unknown variables for the item.
|
|
31
|
+
:param uuid.UUID name: The unique identifier of the item.
|
|
32
|
+
"""
|
|
33
|
+
self.name = name
|
|
34
|
+
self.number_of_unknowns = number_of_unknowns
|
|
35
|
+
self.matrix_index = 0
|
|
36
|
+
self.prev_sol: list[float] = [0.0] * self.number_of_unknowns
|
|
37
|
+
|
|
38
|
+
def set_matrix_index(self, index: int) -> None:
|
|
39
|
+
"""Sets the matrix index of the item.
|
|
40
|
+
|
|
41
|
+
:param int index: The index of the item in the matrix.
|
|
42
|
+
"""
|
|
43
|
+
self.matrix_index = index
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def get_equations(self) -> list[EquationObject]:
|
|
47
|
+
"""Returns the equations for the item.
|
|
48
|
+
|
|
49
|
+
:return: The equations for the item.
|
|
50
|
+
:rtype: list[EquationObject]
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def connect_asset(self, asset: BaseItem, connection_point: int) -> None:
|
|
55
|
+
"""Connects the asset to the node item.
|
|
56
|
+
|
|
57
|
+
:param BaseItem asset: The asset to connect to the node item.
|
|
58
|
+
:param int connection_point: The connection point of the asset to connect to.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def get_connected_assets(self) -> list[tuple[BaseItem, int]]:
|
|
63
|
+
"""Returns the connected assets of the node item.
|
|
64
|
+
|
|
65
|
+
:return: The connected assets of the node item.
|
|
66
|
+
:rtype: Tuple[BaseItem, int]
|
|
67
|
+
"""
|