physioblocks 1.0.0__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.
Files changed (93) hide show
  1. physioblocks/__init__.py +37 -0
  2. physioblocks/base/__init__.py +27 -0
  3. physioblocks/base/operators.py +176 -0
  4. physioblocks/base/registers.py +108 -0
  5. physioblocks/computing/__init__.py +47 -0
  6. physioblocks/computing/assembling.py +291 -0
  7. physioblocks/computing/models.py +811 -0
  8. physioblocks/computing/quantities.py +354 -0
  9. physioblocks/configuration/__init__.py +38 -0
  10. physioblocks/configuration/aliases.py +203 -0
  11. physioblocks/configuration/base.py +123 -0
  12. physioblocks/configuration/computing/__init__.py +27 -0
  13. physioblocks/configuration/computing/quantities.py +56 -0
  14. physioblocks/configuration/constants.py +121 -0
  15. physioblocks/configuration/description/__init__.py +33 -0
  16. physioblocks/configuration/description/blocks.py +239 -0
  17. physioblocks/configuration/description/nets.py +155 -0
  18. physioblocks/configuration/functions.py +695 -0
  19. physioblocks/configuration/simulation/__init__.py +32 -0
  20. physioblocks/configuration/simulation/simulations.py +280 -0
  21. physioblocks/description/__init__.py +34 -0
  22. physioblocks/description/blocks.py +418 -0
  23. physioblocks/description/flux.py +157 -0
  24. physioblocks/description/nets.py +746 -0
  25. physioblocks/io/__init__.py +29 -0
  26. physioblocks/io/aliases.py +73 -0
  27. physioblocks/io/configuration.py +125 -0
  28. physioblocks/launcher/__main__.py +285 -0
  29. physioblocks/launcher/configuration.py +231 -0
  30. physioblocks/launcher/configure/__main__.py +99 -0
  31. physioblocks/launcher/constants.py +105 -0
  32. physioblocks/launcher/files.py +150 -0
  33. physioblocks/launcher/series.py +165 -0
  34. physioblocks/library/__init__.py +27 -0
  35. physioblocks/library/aliases/blocks/c_block.json +5 -0
  36. physioblocks/library/aliases/blocks/rc_block.json +5 -0
  37. physioblocks/library/aliases/blocks/rcr_block.json +5 -0
  38. physioblocks/library/aliases/blocks/spherical_cavity_block.json +5 -0
  39. physioblocks/library/aliases/blocks/valve_rl_block.json +5 -0
  40. physioblocks/library/aliases/flux/heart_flux_dof_couples.jsonc +4 -0
  41. physioblocks/library/aliases/model_components/active_law_macro_huxley_two_moments.json +5 -0
  42. physioblocks/library/aliases/model_components/rheology_fiber_additive.json +5 -0
  43. physioblocks/library/aliases/model_components/spherical_dynamics.json +5 -0
  44. physioblocks/library/aliases/model_components/velocity_law_hht.json +5 -0
  45. physioblocks/library/aliases/nets/circulation_alone_net.json +31 -0
  46. physioblocks/library/aliases/nets/spherical_heart_net.json +93 -0
  47. physioblocks/library/aliases/simulations/circulation_alone_forward_simulation.jsonc +55 -0
  48. physioblocks/library/aliases/simulations/default_forward_simulation.jsonc +7 -0
  49. physioblocks/library/aliases/simulations/default_time.jsonc +8 -0
  50. physioblocks/library/aliases/simulations/newton_method_solver.json +5 -0
  51. physioblocks/library/aliases/simulations/spherical_heart_forward_simulation.jsonc +157 -0
  52. physioblocks/library/aliases/simulations/spherical_heart_with_respiration_forward_simulation.jsonc +45 -0
  53. physioblocks/library/blocks/__init__.py +27 -0
  54. physioblocks/library/blocks/capacitances.py +516 -0
  55. physioblocks/library/blocks/cavity.py +192 -0
  56. physioblocks/library/blocks/valves.py +281 -0
  57. physioblocks/library/functions/__init__.py +27 -0
  58. physioblocks/library/functions/base_operations.py +129 -0
  59. physioblocks/library/functions/first_order.py +113 -0
  60. physioblocks/library/functions/piecewise.py +271 -0
  61. physioblocks/library/functions/trigonometric.py +78 -0
  62. physioblocks/library/functions/watchers.py +113 -0
  63. physioblocks/library/model_components/__init__.py +27 -0
  64. physioblocks/library/model_components/active_law.py +345 -0
  65. physioblocks/library/model_components/dynamics.py +986 -0
  66. physioblocks/library/model_components/rheology.py +160 -0
  67. physioblocks/library/model_components/velocity_law.py +169 -0
  68. physioblocks/references/circulation_alone_sim.jsonc +24 -0
  69. physioblocks/references/spherical_heart_respiration_sim.jsonc +33 -0
  70. physioblocks/references/spherical_heart_sim.jsonc +29 -0
  71. physioblocks/registers/__init__.py +32 -0
  72. physioblocks/registers/load_function_register.py +93 -0
  73. physioblocks/registers/save_function_register.py +106 -0
  74. physioblocks/registers/type_register.py +97 -0
  75. physioblocks/simulation/__init__.py +48 -0
  76. physioblocks/simulation/constants.py +30 -0
  77. physioblocks/simulation/functions.py +71 -0
  78. physioblocks/simulation/runtime.py +484 -0
  79. physioblocks/simulation/saved_quantities.py +129 -0
  80. physioblocks/simulation/setup.py +576 -0
  81. physioblocks/simulation/solvers.py +235 -0
  82. physioblocks/simulation/state.py +340 -0
  83. physioblocks/simulation/time_manager.py +354 -0
  84. physioblocks/utils/__init__.py +27 -0
  85. physioblocks/utils/dynamic_import_utils.py +150 -0
  86. physioblocks/utils/exceptions_utils.py +115 -0
  87. physioblocks/utils/gradient_test_utils.py +337 -0
  88. physioblocks/utils/math_utils.py +109 -0
  89. physioblocks-1.0.0.dist-info/METADATA +127 -0
  90. physioblocks-1.0.0.dist-info/RECORD +93 -0
  91. physioblocks-1.0.0.dist-info/WHEEL +4 -0
  92. physioblocks-1.0.0.dist-info/licenses/licenses/GPL-3.0-only.txt +674 -0
  93. physioblocks-1.0.0.dist-info/licenses/licenses/LGPL-3.0-only.txt +165 -0
@@ -0,0 +1,113 @@
1
+ # SPDX-FileCopyrightText: Copyright INRIA
2
+ #
3
+ # SPDX-License-Identifier: LGPL-3.0-only
4
+ #
5
+ # Copyright INRIA
6
+ #
7
+ # This file is part of PhysioBlocks, a library mostly developed by the
8
+ # [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9
+ #
10
+ # Authors:
11
+ # - Colin Drieu
12
+ # - Dominique Chapelle
13
+ # - François Kimmig
14
+ # - Philippe Moireau
15
+ #
16
+ # PhysioBlocks is free software: you can redistribute it and/or modify it under the
17
+ # terms of the GNU Lesser General Public License as published by the Free Software
18
+ # Foundation, version 3 of the License.
19
+ #
20
+ # PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
+ # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23
+ #
24
+ # You should have received a copy of the GNU Lesser General Public License along with
25
+ # PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ from __future__ import annotations
28
+
29
+ from typing import Any
30
+
31
+ import numpy as np
32
+ from numpy.typing import NDArray
33
+
34
+ from physioblocks.registers.type_register import register_type
35
+ from physioblocks.simulation import AbstractFunction
36
+
37
+ # First order function id
38
+ FIRST_ORDER_NAME = "first_order"
39
+
40
+
41
+ @register_type(FIRST_ORDER_NAME)
42
+ class FirstOrder(AbstractFunction):
43
+ """
44
+ Defines an evaluation method to get the value of a sum of first order functions
45
+ with heavyside for the given time.
46
+ """
47
+
48
+ times_start: NDArray[np.float64]
49
+ """Start times of first order components"""
50
+
51
+ amplitudes: NDArray[np.float64]
52
+ """Amplitudes of first order components"""
53
+
54
+ time_constants: NDArray[np.float64]
55
+ """Time constants of first order components"""
56
+
57
+ baseline_value: np.float64
58
+ """Baseline value of the function"""
59
+
60
+ def __init__(
61
+ self,
62
+ times_start: NDArray[np.float64],
63
+ amplitudes: NDArray[np.float64],
64
+ time_constants: NDArray[np.float64],
65
+ baseline_value: np.float64,
66
+ ):
67
+ # test arguments size consistency
68
+ if not (
69
+ (len(times_start) == len(amplitudes))
70
+ and (len(times_start) == len(time_constants))
71
+ ):
72
+ msg_error = (
73
+ "arguments 'times_start', 'amplitudes' and 'time_constants' "
74
+ "must have the same length. Got: "
75
+ f"- times_start (len = {len(times_start)}): {times_start}; "
76
+ f"- amplitudes (len = {len(amplitudes)}): {amplitudes}; "
77
+ f"- time_constants (len = {len(time_constants)}): {time_constants}."
78
+ )
79
+ raise ValueError(msg_error)
80
+
81
+ # reorder array arguments to have ascending times_start
82
+ sorted_indices = np.argsort(times_start)
83
+ amplitudes = amplitudes[sorted_indices]
84
+ time_constants = time_constants[sorted_indices]
85
+
86
+ # assign properties
87
+ self.times_start = times_start
88
+ self.amplitudes = amplitudes
89
+ self.time_constants = time_constants
90
+ self.baseline_value = baseline_value
91
+
92
+ def eval(self, time: np.float64) -> Any:
93
+ """
94
+ Evaluate function value at the given time.
95
+
96
+ :param time: evaluation time
97
+ :type time: np.float64
98
+
99
+ :return: the function value
100
+ :rtype: np.float64
101
+ """
102
+
103
+ mask_activated = self.times_start <= time
104
+ amplitudes_activ = self.amplitudes[mask_activated]
105
+ time_cst_activ = self.time_constants[mask_activated]
106
+ times_start_activ = self.times_start[mask_activated]
107
+
108
+ output = self.baseline_value + np.sum(
109
+ amplitudes_activ
110
+ * (1 - np.exp(-(time - times_start_activ) / time_cst_activ))
111
+ )
112
+
113
+ return output
@@ -0,0 +1,271 @@
1
+ # SPDX-FileCopyrightText: Copyright INRIA
2
+ #
3
+ # SPDX-License-Identifier: LGPL-3.0-only
4
+ #
5
+ # Copyright INRIA
6
+ #
7
+ # This file is part of PhysioBlocks, a library mostly developed by the
8
+ # [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9
+ #
10
+ # Authors:
11
+ # - Colin Drieu
12
+ # - Dominique Chapelle
13
+ # - François Kimmig
14
+ # - Philippe Moireau
15
+ #
16
+ # PhysioBlocks is free software: you can redistribute it and/or modify it under the
17
+ # terms of the GNU Lesser General Public License as published by the Free Software
18
+ # Foundation, version 3 of the License.
19
+ #
20
+ # PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
+ # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23
+ #
24
+ # You should have received a copy of the GNU Lesser General Public License along with
25
+ # PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ """Declare functions to define piecewise functions in the configuration"""
28
+
29
+ from __future__ import annotations
30
+
31
+ from dataclasses import dataclass
32
+ from typing import Any
33
+
34
+ import numpy as np
35
+ from numpy.typing import NDArray
36
+
37
+ from physioblocks.registers.type_register import register_type
38
+ from physioblocks.simulation import AbstractFunction
39
+
40
+ # Piecewise linear function type name
41
+ PIECEWISE_LINEAR_NAME = "piecewise_linear"
42
+
43
+
44
+ @register_type(PIECEWISE_LINEAR_NAME)
45
+ @dataclass
46
+ class PiecewiseLinear(AbstractFunction):
47
+ """
48
+ Defines an evaluation method to get the value of a piecewise function
49
+ for the given time.
50
+ """
51
+
52
+ points_abscissas: NDArray[np.float64]
53
+ """The function abscissas"""
54
+
55
+ points_ordinates: NDArray[np.float64]
56
+ """The function ordinates"""
57
+
58
+ left_value: np.float64 | None = None
59
+ """Function value when the evaluation point is before the provided abscissas.
60
+ If it is not provided, it is the first ordinate value."""
61
+
62
+ right_value: np.float64 | None = None
63
+ """Function value when the evaluation point is after the provided abscissas.
64
+ If it is not provided, it is the last ordinate value."""
65
+
66
+ def eval(self, time: np.float64) -> Any:
67
+ """
68
+ Evaluate piecewise function for the given time.
69
+
70
+ :param time: the evaluated time
71
+ :type time: np.float64
72
+
73
+ :return: the activation point_value
74
+ :rtype: np.float64
75
+ """
76
+ return np.interp(
77
+ time,
78
+ self.points_abscissas,
79
+ self.points_ordinates,
80
+ self.left_value,
81
+ self.right_value,
82
+ )
83
+
84
+
85
+ # Piecewise linear periodic function id
86
+ PIECEWISE_LINEAR_PERIODIC_NAME = "piecewise_linear_periodic"
87
+
88
+
89
+ @register_type(PIECEWISE_LINEAR_PERIODIC_NAME)
90
+ @dataclass
91
+ class PiecewiseLinearPeriodic(AbstractFunction):
92
+ """
93
+ Defines an evaluation method to get the value of a piecewise periodic function
94
+ for the given time.
95
+ """
96
+
97
+ period: np.float64
98
+ """The function period"""
99
+
100
+ points_abscissas: NDArray[np.float64]
101
+ """The function abscissas"""
102
+
103
+ points_ordinates: NDArray[np.float64]
104
+ """The function ordinates"""
105
+
106
+ def eval(self, time: np.float64) -> Any:
107
+ """
108
+ Evaluate piecewise periodic function for the given time.
109
+
110
+ :param time: the evaluated time
111
+ :type time: np.float64
112
+
113
+ :return: the activation point_value
114
+ :rtype: np.float64
115
+ """
116
+ return np.interp(
117
+ time, self.points_abscissas, self.points_ordinates, period=self.period
118
+ )
119
+
120
+
121
+ # Rescale Two Phases function id
122
+ RESCALE_TWO_PHASES_FUNCTION_NAME = "rescale_two_phases_function"
123
+
124
+
125
+ @register_type(RESCALE_TWO_PHASES_FUNCTION_NAME)
126
+ class RescaleTwoPhasesFunction(AbstractFunction):
127
+ """
128
+ Rescale each part of the input function (a linear interpollation) depending on
129
+ the proportion of variation of phase 0 when the period differs from the
130
+ reference function.
131
+ """
132
+
133
+ rescaled_period: float
134
+ """The actual function period"""
135
+
136
+ reference_function: list[tuple[float, float]]
137
+ """The reference function. Coordinates format is ``(abscissa, ordinate)``"""
138
+
139
+ alpha: float
140
+ """Proportion of the variation of phase 0"""
141
+
142
+ phases: list[int]
143
+ """For each intervals point of the reference, determine if it belong to
144
+ phase 0 or 1."""
145
+
146
+ def __init__(
147
+ self,
148
+ rescaled_period: float,
149
+ reference_function: list[tuple[float, float]],
150
+ alpha: float,
151
+ phases: list[int],
152
+ ):
153
+ if len(phases) != len(reference_function) - 1:
154
+ raise ValueError(
155
+ "A phase should be defined for each interval defined in the "
156
+ "reference function."
157
+ )
158
+
159
+ if any([elem not in [0, 1] for elem in phases]):
160
+ raise ValueError(
161
+ str.format(
162
+ "There are only two phases allowed: 0 or 1, got {0}.", phases
163
+ )
164
+ )
165
+
166
+ if alpha >= 1.0 or alpha <= 0.0:
167
+ raise ValueError(
168
+ str.format(
169
+ "The proportion of the variation of phase 0 should be in ]0, 1[, "
170
+ "got {0}",
171
+ alpha,
172
+ )
173
+ )
174
+
175
+ # check if the reference function is sorted
176
+ if (
177
+ all(
178
+ [
179
+ reference_function[k][0] > reference_function[k - 1][0]
180
+ for k in range(1, len(reference_function))
181
+ ]
182
+ )
183
+ is False
184
+ ):
185
+ raise ValueError(
186
+ str.format(
187
+ "Reference function abscissas should be sorted, got {0}",
188
+ [coord[0] for coord in reference_function],
189
+ )
190
+ )
191
+
192
+ self.reference_function = reference_function
193
+ reference_period = (
194
+ self.reference_function[-1][0] - self.reference_function[0][0]
195
+ )
196
+ self.phases = phases
197
+ self.alpha = alpha
198
+
199
+ self.beta = rescaled_period / reference_period
200
+ duration_phase_0_ref = sum(
201
+ [
202
+ self.reference_function[index][0]
203
+ - self.reference_function[index - 1][0]
204
+ for index in range(1, len(self.reference_function))
205
+ if phases[index - 1] == 0
206
+ ]
207
+ )
208
+ duration_phase_1_ref = reference_period - duration_phase_0_ref
209
+
210
+ scale_factor_phase_0 = (
211
+ 1.0
212
+ + self.alpha * (self.beta - 1.0) * reference_period / duration_phase_0_ref
213
+ )
214
+ scale_factor_phase_1 = (
215
+ 1.0
216
+ + (1.0 - self.alpha)
217
+ * (self.beta - 1.0)
218
+ * reference_period
219
+ / duration_phase_1_ref
220
+ )
221
+
222
+ if scale_factor_phase_0 <= 0 or scale_factor_phase_1 <= 0:
223
+ raise ValueError(
224
+ str.format(
225
+ "Scale factors should not be negatives. Got ({0}, {1}) for "
226
+ "phase 0 and 1 respectivly. You can try changing alpha.",
227
+ scale_factor_phase_0,
228
+ scale_factor_phase_1,
229
+ )
230
+ )
231
+ abscissas = [self.reference_function[0][0]]
232
+ for index in range(1, len(self.reference_function)):
233
+ rescaled_abs = (
234
+ abscissas[index - 1]
235
+ + (
236
+ self.reference_function[index][0]
237
+ - self.reference_function[index - 1][0]
238
+ )
239
+ * scale_factor_phase_0
240
+ if phases[index - 1] == 0
241
+ else abscissas[index - 1]
242
+ + (
243
+ self.reference_function[index][0]
244
+ - self.reference_function[index - 1][0]
245
+ )
246
+ * scale_factor_phase_1
247
+ )
248
+ abscissas.append(rescaled_abs)
249
+
250
+ ordinates = [value[1] for value in self.reference_function]
251
+
252
+ self.rescaled_period = abscissas[-1]
253
+ self.function_abcissas = np.array(abscissas)
254
+ self.function_ordinates = np.array(ordinates)
255
+
256
+ def eval(self, time: float) -> Any:
257
+ """
258
+ Evaluate the function.
259
+
260
+ :param time: the evaluated time
261
+ :type time: float
262
+
263
+ :return: the function value
264
+ :rtype: np.float64
265
+ """
266
+ return np.interp(
267
+ time,
268
+ self.function_abcissas,
269
+ self.function_ordinates,
270
+ period=self.rescaled_period,
271
+ )
@@ -0,0 +1,78 @@
1
+ # SPDX-FileCopyrightText: Copyright INRIA
2
+ #
3
+ # SPDX-License-Identifier: LGPL-3.0-only
4
+ #
5
+ # Copyright INRIA
6
+ #
7
+ # This file is part of PhysioBlocks, a library mostly developed by the
8
+ # [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9
+ #
10
+ # Authors:
11
+ # - Colin Drieu
12
+ # - Dominique Chapelle
13
+ # - François Kimmig
14
+ # - Philippe Moireau
15
+ #
16
+ # PhysioBlocks is free software: you can redistribute it and/or modify it under the
17
+ # terms of the GNU Lesser General Public License as published by the Free Software
18
+ # Foundation, version 3 of the License.
19
+ #
20
+ # PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
+ # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23
+ #
24
+ # You should have received a copy of the GNU Lesser General Public License along with
25
+ # PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ """
28
+ Declare configuration function to set parameter with trigonometric function.
29
+ """
30
+
31
+ from dataclasses import dataclass
32
+ from typing import Any
33
+
34
+ import numpy as np
35
+
36
+ from physioblocks.registers.type_register import register_type
37
+ from physioblocks.simulation import AbstractFunction
38
+
39
+ # sinus with offset function id
40
+ SINUS_OFFSET_NAME = "sinus_offset"
41
+
42
+
43
+ @register_type(SINUS_OFFSET_NAME)
44
+ @dataclass
45
+ class SinusOffset(AbstractFunction):
46
+ """
47
+ Defines an evaluation method to get the value of a offset sinus
48
+ function.
49
+ """
50
+
51
+ offset_value: float
52
+ """Offset value of the function"""
53
+
54
+ amplitude: float
55
+ """Peak amplitude of the function"""
56
+
57
+ frequency: float
58
+ """Frequency of the function"""
59
+
60
+ phase_shift: float
61
+ """Phase shift of the function"""
62
+
63
+ def eval(self, time: float) -> Any:
64
+ """
65
+ Evaluate function value at the given time.
66
+
67
+ :param time: evaluation time
68
+ :type time: float
69
+
70
+ :return: the function value
71
+ :rtype: np.float64
72
+ """
73
+
74
+ output = self.offset_value + self.amplitude * np.sin(
75
+ 2 * np.pi * self.frequency * time + self.phase_shift
76
+ )
77
+
78
+ return output
@@ -0,0 +1,113 @@
1
+ # SPDX-FileCopyrightText: Copyright INRIA
2
+ #
3
+ # SPDX-License-Identifier: LGPL-3.0-only
4
+ #
5
+ # Copyright INRIA
6
+ #
7
+ # This file is part of PhysioBlocks, a library mostly developed by the
8
+ # [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9
+ #
10
+ # Authors:
11
+ # - Colin Drieu
12
+ # - Dominique Chapelle
13
+ # - François Kimmig
14
+ # - Philippe Moireau
15
+ #
16
+ # PhysioBlocks is free software: you can redistribute it and/or modify it under the
17
+ # terms of the GNU Lesser General Public License as published by the Free Software
18
+ # Foundation, version 3 of the License.
19
+ #
20
+ # PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
+ # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23
+ #
24
+ # You should have received a copy of the GNU Lesser General Public License along with
25
+ # PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ """
28
+ Watcher are useful functions to use to set **Output Functions**
29
+ in the configuration.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ from collections.abc import Iterable
35
+ from dataclasses import dataclass, field
36
+ from typing import Any
37
+
38
+ import numpy as np
39
+
40
+ from physioblocks.base.operators import AbstractBaseOperators
41
+ from physioblocks.computing.models import Block
42
+ from physioblocks.computing.quantities import Quantity
43
+ from physioblocks.registers.type_register import register_type
44
+ from physioblocks.simulation import AbstractFunction
45
+
46
+ # Quantity Watcher function type name
47
+ WATCH_QUANTITY_TYPE_ID = "watch_quantity"
48
+
49
+
50
+ @dataclass
51
+ @register_type(WATCH_QUANTITY_TYPE_ID)
52
+ class WatchQuantity(AbstractFunction, AbstractBaseOperators):
53
+ """
54
+ Return the current value of the watch quantity.
55
+ """
56
+
57
+ quantity: Quantity[Any]
58
+ """The quantities to watch"""
59
+
60
+ @property
61
+ def operation_value(self) -> Any:
62
+ """
63
+ Value used with base operators.
64
+
65
+ :return: the current evaluation of the function
66
+ :rtype: Any
67
+ """
68
+ return self.eval()
69
+
70
+ def eval(self) -> Any:
71
+ """Just return the watched quantity current value
72
+
73
+ :return: the watched quantity current value
74
+ :rtype: np.float64 | np.ndarray"""
75
+ return self.quantity.current
76
+
77
+
78
+ # Sum Blocks Quantity function type name
79
+ SUM_BLOCKS_QUANTITY_TYPE_ID = "sum_blocks_quantity"
80
+
81
+
82
+ @dataclass
83
+ @register_type(SUM_BLOCKS_QUANTITY_TYPE_ID)
84
+ class SumBlocksQuantity(AbstractFunction, AbstractBaseOperators):
85
+ """Sum the current values of quantities with the given name
86
+ for each the blocks."""
87
+
88
+ quantity_id: str
89
+ """block local id of the quantity to sum"""
90
+
91
+ elements: Iterable[Block] = field(default_factory=list)
92
+ """the blocks holding the quantity to sum"""
93
+
94
+ @property
95
+ def operation_value(self) -> Any:
96
+ """
97
+ Value used with base operators.
98
+
99
+ :return: the current evaluation of the function
100
+ :rtype: Any
101
+ """
102
+ return self.eval()
103
+
104
+ def eval(self) -> Any:
105
+ """
106
+ Sum the quantities
107
+
108
+ :return: the sum of the quantities
109
+ :rtype: Any
110
+ """
111
+ return np.sum(
112
+ [getattr(block, self.quantity_id).current for block in self.elements]
113
+ )
@@ -0,0 +1,27 @@
1
+ # SPDX-FileCopyrightText: Copyright INRIA
2
+ #
3
+ # SPDX-License-Identifier: LGPL-3.0-only
4
+ #
5
+ # Copyright INRIA
6
+ #
7
+ # This file is part of PhysioBlocks, a library mostly developed by the
8
+ # [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9
+ #
10
+ # Authors:
11
+ # - Colin Drieu
12
+ # - Dominique Chapelle
13
+ # - François Kimmig
14
+ # - Philippe Moireau
15
+ #
16
+ # PhysioBlocks is free software: you can redistribute it and/or modify it under the
17
+ # terms of the GNU Lesser General Public License as published by the Free Software
18
+ # Foundation, version 3 of the License.
19
+ #
20
+ # PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
+ # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23
+ #
24
+ # You should have received a copy of the GNU Lesser General Public License along with
25
+ # PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ """ "Module defining the available model components"""