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.
- physioblocks/__init__.py +37 -0
- physioblocks/base/__init__.py +27 -0
- physioblocks/base/operators.py +176 -0
- physioblocks/base/registers.py +108 -0
- physioblocks/computing/__init__.py +47 -0
- physioblocks/computing/assembling.py +291 -0
- physioblocks/computing/models.py +811 -0
- physioblocks/computing/quantities.py +354 -0
- physioblocks/configuration/__init__.py +38 -0
- physioblocks/configuration/aliases.py +203 -0
- physioblocks/configuration/base.py +123 -0
- physioblocks/configuration/computing/__init__.py +27 -0
- physioblocks/configuration/computing/quantities.py +56 -0
- physioblocks/configuration/constants.py +121 -0
- physioblocks/configuration/description/__init__.py +33 -0
- physioblocks/configuration/description/blocks.py +239 -0
- physioblocks/configuration/description/nets.py +155 -0
- physioblocks/configuration/functions.py +695 -0
- physioblocks/configuration/simulation/__init__.py +32 -0
- physioblocks/configuration/simulation/simulations.py +280 -0
- physioblocks/description/__init__.py +34 -0
- physioblocks/description/blocks.py +418 -0
- physioblocks/description/flux.py +157 -0
- physioblocks/description/nets.py +746 -0
- physioblocks/io/__init__.py +29 -0
- physioblocks/io/aliases.py +73 -0
- physioblocks/io/configuration.py +125 -0
- physioblocks/launcher/__main__.py +285 -0
- physioblocks/launcher/configuration.py +231 -0
- physioblocks/launcher/configure/__main__.py +99 -0
- physioblocks/launcher/constants.py +105 -0
- physioblocks/launcher/files.py +150 -0
- physioblocks/launcher/series.py +165 -0
- physioblocks/library/__init__.py +27 -0
- physioblocks/library/aliases/blocks/c_block.json +5 -0
- physioblocks/library/aliases/blocks/rc_block.json +5 -0
- physioblocks/library/aliases/blocks/rcr_block.json +5 -0
- physioblocks/library/aliases/blocks/spherical_cavity_block.json +5 -0
- physioblocks/library/aliases/blocks/valve_rl_block.json +5 -0
- physioblocks/library/aliases/flux/heart_flux_dof_couples.jsonc +4 -0
- physioblocks/library/aliases/model_components/active_law_macro_huxley_two_moments.json +5 -0
- physioblocks/library/aliases/model_components/rheology_fiber_additive.json +5 -0
- physioblocks/library/aliases/model_components/spherical_dynamics.json +5 -0
- physioblocks/library/aliases/model_components/velocity_law_hht.json +5 -0
- physioblocks/library/aliases/nets/circulation_alone_net.json +31 -0
- physioblocks/library/aliases/nets/spherical_heart_net.json +93 -0
- physioblocks/library/aliases/simulations/circulation_alone_forward_simulation.jsonc +55 -0
- physioblocks/library/aliases/simulations/default_forward_simulation.jsonc +7 -0
- physioblocks/library/aliases/simulations/default_time.jsonc +8 -0
- physioblocks/library/aliases/simulations/newton_method_solver.json +5 -0
- physioblocks/library/aliases/simulations/spherical_heart_forward_simulation.jsonc +157 -0
- physioblocks/library/aliases/simulations/spherical_heart_with_respiration_forward_simulation.jsonc +45 -0
- physioblocks/library/blocks/__init__.py +27 -0
- physioblocks/library/blocks/capacitances.py +516 -0
- physioblocks/library/blocks/cavity.py +192 -0
- physioblocks/library/blocks/valves.py +281 -0
- physioblocks/library/functions/__init__.py +27 -0
- physioblocks/library/functions/base_operations.py +129 -0
- physioblocks/library/functions/first_order.py +113 -0
- physioblocks/library/functions/piecewise.py +271 -0
- physioblocks/library/functions/trigonometric.py +78 -0
- physioblocks/library/functions/watchers.py +113 -0
- physioblocks/library/model_components/__init__.py +27 -0
- physioblocks/library/model_components/active_law.py +345 -0
- physioblocks/library/model_components/dynamics.py +986 -0
- physioblocks/library/model_components/rheology.py +160 -0
- physioblocks/library/model_components/velocity_law.py +169 -0
- physioblocks/references/circulation_alone_sim.jsonc +24 -0
- physioblocks/references/spherical_heart_respiration_sim.jsonc +33 -0
- physioblocks/references/spherical_heart_sim.jsonc +29 -0
- physioblocks/registers/__init__.py +32 -0
- physioblocks/registers/load_function_register.py +93 -0
- physioblocks/registers/save_function_register.py +106 -0
- physioblocks/registers/type_register.py +97 -0
- physioblocks/simulation/__init__.py +48 -0
- physioblocks/simulation/constants.py +30 -0
- physioblocks/simulation/functions.py +71 -0
- physioblocks/simulation/runtime.py +484 -0
- physioblocks/simulation/saved_quantities.py +129 -0
- physioblocks/simulation/setup.py +576 -0
- physioblocks/simulation/solvers.py +235 -0
- physioblocks/simulation/state.py +340 -0
- physioblocks/simulation/time_manager.py +354 -0
- physioblocks/utils/__init__.py +27 -0
- physioblocks/utils/dynamic_import_utils.py +150 -0
- physioblocks/utils/exceptions_utils.py +115 -0
- physioblocks/utils/gradient_test_utils.py +337 -0
- physioblocks/utils/math_utils.py +109 -0
- physioblocks-1.0.0.dist-info/METADATA +127 -0
- physioblocks-1.0.0.dist-info/RECORD +93 -0
- physioblocks-1.0.0.dist-info/WHEEL +4 -0
- physioblocks-1.0.0.dist-info/licenses/licenses/GPL-3.0-only.txt +674 -0
- 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"""
|