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,192 @@
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
+ Describes cavity blocks
29
+ """
30
+
31
+ from dataclasses import dataclass
32
+ from typing import Any
33
+
34
+ import numpy as np
35
+
36
+ from physioblocks.computing import Block, Expression, Quantity
37
+ from physioblocks.registers import register_type
38
+ from physioblocks.simulation import Time
39
+
40
+ # Local id for the volume saved quantity
41
+ CAVITY_VOLUME_LOCAL_ID = "volume"
42
+
43
+ # Local id for the pressure dof in the cavity
44
+ CAVITY_PRESSURE_LOCAL_ID = "pressure"
45
+
46
+ # Local id for the pressure dof in the cavity
47
+ CAVITY_DISP_LOCAL_ID = "disp"
48
+
49
+ # Constant for the cavity block type id
50
+ CAVITY_BLOCK_TYPE_ID = "spherical_cavity_block"
51
+
52
+
53
+ @register_type(CAVITY_BLOCK_TYPE_ID)
54
+ @dataclass
55
+ class SphericalCavityBlock(Block):
56
+ r"""
57
+ Spherical cavity block implementation
58
+
59
+ .. tikz:: Spherical Cavity Scheme
60
+
61
+ \filldraw [fill=gray!20] (0, 0) circle [x radius = 3.0+0.2, y radius = 3.0+0.2];
62
+ \draw [thick, dashed] (0, 0) circle [x radius = 3.0, y radius = 3.0];
63
+ \filldraw [fill=red!25] (0, 0) circle [x radius = 3.0-0.2, y radius = 3.0-0.2];
64
+ \filldraw [fill=gray!40] (0, 0) circle [x radius = 1.8 + 0.5, y radius = 1.8 + 0.5];
65
+ \draw [dashed, thick] (0, 0) circle [x radius = 1.8, y radius = 1.8];
66
+ \filldraw [fill=red!25] (0, 0) circle [x radius = 1.8 - 0.5, y radius = 1.8 - 0.5];
67
+ \draw [thick][<->] (0, 0) -- node[above]{$R_0$} (-1.8, 0);
68
+ \draw [thick][<->] (0, 1.8-0.5) -- node[anchor=west, yshift=4]{$d_0$} (0, 1.8+0.5);
69
+ \draw [thick][dashed][<-] (-3.0, 0) -- node[anchor=north]{$y$} (-1.8, 0);
70
+ \draw [thick][<->] (0, 3.0-0.2) -- node[anchor=south, yshift=5]{$d(y)$} (0, 3.0+0.2);
71
+ \draw (3.0+0.2, 0) to[short, -*, i=$Q$] (5, 0) node[above]{$P$};
72
+
73
+ **Node 1:**
74
+
75
+ :math:`Q = - \frac {dV(y)}{dt}`
76
+
77
+ **Discretised:**
78
+
79
+ :math:`Q^{n + \frac{1}{2}} = - \frac {V(y^{n + 1}) - V(y^{n})}{\Delta t^n}`
80
+
81
+ .. note::
82
+
83
+ Notice that no dynamics is given on the **DOF** in the block.
84
+ **Model components** of the cavity can access the pressure and give it a dynamics.
85
+
86
+ """ # noqa: E501
87
+
88
+ disp: Quantity[np.float64]
89
+ """Displacement y"""
90
+
91
+ radius: Quantity[np.float64]
92
+ """Initial Sphere radius R0"""
93
+
94
+ thickness: Quantity[np.float64]
95
+ """Initial thickness d0"""
96
+
97
+ time: Time
98
+ """time"""
99
+
100
+ def initialize(self) -> None:
101
+ """
102
+ Initialize block attributes from current quantity values
103
+ """
104
+ self.inv_radius = 1.0 / self.radius.current
105
+ self.sphere_volume = (4.0 / 3.0) * np.pi * np.pow(self.radius.current, 3)
106
+ self.sphere_surface = 4.0 * np.pi * np.pow(self.radius.current, 2)
107
+ self.thickness_radius_ratio = self.thickness.current * self.inv_radius
108
+ self.half_thickness_radius_ratio = 0.5 * self.thickness_radius_ratio
109
+
110
+ def fluid_volume_current(self) -> Any:
111
+ """
112
+ Compute the current fluid volume in the cavity.
113
+
114
+ :return: the fluid volume
115
+ :rtype: np.float64
116
+ """
117
+ disp_cur_ratio = 1.0 + self.disp.current * self.inv_radius
118
+ return self.sphere_volume * np.pow(
119
+ disp_cur_ratio
120
+ - np.pow(disp_cur_ratio, -2) * self.half_thickness_radius_ratio,
121
+ 3,
122
+ )
123
+
124
+ def fluid_volume_new(self) -> Any:
125
+ """
126
+ Compute the new fluid volume in the cavity.
127
+
128
+ :return: the fluid volume
129
+ :rtype: np.float64
130
+ """
131
+ disp_new_ratio = 1.0 + self.disp.new * self.inv_radius
132
+ return self.sphere_volume * np.pow(
133
+ disp_new_ratio
134
+ - np.pow(disp_new_ratio, -2) * self.half_thickness_radius_ratio,
135
+ 3,
136
+ )
137
+
138
+ def cavity_flux(self) -> Any:
139
+ """
140
+ Compute the ventricule flux at local node 1.
141
+
142
+ :return: the flux
143
+ :rtype: np.float64
144
+ """
145
+
146
+ cavity_flux = -(
147
+ (self.fluid_volume_new() - self.fluid_volume_current()) * self.time.inv_dt
148
+ )
149
+
150
+ return cavity_flux
151
+
152
+ def dcavity_flux_ddisp(self) -> Any:
153
+ """
154
+ Compute the partial derivative of the cavity flux for ``disp``
155
+
156
+ :return: the flux partial derivative
157
+ :rtype: np.float64
158
+ """
159
+
160
+ disp_new_ratio = 1.0 + self.disp.new * self.inv_radius
161
+
162
+ return -(
163
+ self.time.inv_dt
164
+ * self.sphere_surface
165
+ * np.pow(
166
+ disp_new_ratio
167
+ - np.pow(disp_new_ratio, -2) * self.half_thickness_radius_ratio,
168
+ 2,
169
+ )
170
+ * (1.0 + np.pow(disp_new_ratio, -3) * self.thickness_radius_ratio)
171
+ )
172
+
173
+
174
+ # Define the cavity block flux expression.
175
+ _cavity_block_flux_expr = Expression(
176
+ 1,
177
+ SphericalCavityBlock.cavity_flux,
178
+ {CAVITY_DISP_LOCAL_ID: SphericalCavityBlock.dcavity_flux_ddisp},
179
+ )
180
+
181
+ SphericalCavityBlock.declares_flux_expression(
182
+ 1, CAVITY_PRESSURE_LOCAL_ID, _cavity_block_flux_expr
183
+ )
184
+
185
+
186
+ # Define the cavity block volume of fluid expression.
187
+ _cavity_block_fluid_volume_expr = Expression(
188
+ 1, SphericalCavityBlock.fluid_volume_current
189
+ )
190
+ SphericalCavityBlock.declares_saved_quantity_expression(
191
+ CAVITY_VOLUME_LOCAL_ID, _cavity_block_fluid_volume_expr
192
+ )
@@ -0,0 +1,281 @@
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
+ Module describing Valve Blocks
29
+ """
30
+
31
+ from dataclasses import dataclass
32
+ from typing import Any
33
+
34
+ import numpy as np
35
+
36
+ from physioblocks.computing import (
37
+ Block,
38
+ Expression,
39
+ Quantity,
40
+ diff,
41
+ mid_alpha,
42
+ mid_point,
43
+ )
44
+ from physioblocks.registers import register_type
45
+ from physioblocks.simulation import Time
46
+
47
+ # Constant for the valve rl block type id
48
+ VALVE_RL_BLOCK_ID = "valve_rl_block"
49
+
50
+
51
+ # Flux through the block
52
+ VALVE_RL_BLOCK_FLUX_VAR_ID = "flux"
53
+
54
+ # Pressure at local node 1
55
+ VALVE_RL_BLOCK_PRESSURE_1_DOF_ID = "pressure_1"
56
+
57
+ # Pressure at local node 2
58
+ VALVE_RL_BLOCK_PRESSURE_2_DOF_ID = "pressure_2"
59
+
60
+
61
+ @dataclass
62
+ @register_type(VALVE_RL_BLOCK_ID)
63
+ class ValveRLBlock(Block):
64
+ r"""
65
+ Describes valve RL block quantities and flux definitions
66
+
67
+ .. tikz:: Valve RC Scheme
68
+
69
+ \draw (1,2) to[short, i=$Q_2$] (1,1) to[short, -*] (1,0) node[right]{$P_2$};
70
+ \draw (1,2) to[short, L=$L$] (1,4);
71
+ \draw (0,4) -- (2,4);
72
+ \draw (0,4) to[D] (0,6);
73
+ \draw (0,6) to[R=$R_{\text{back}}$] (0,8);
74
+ \draw (2,8) to[D] (2,6);
75
+ \draw (2,6) to[R=$R$] (2,4);
76
+ \draw (0,8) -- (2,8);
77
+ \draw (1,9) to[short, i=$Q$] (1,8);
78
+ \draw (1,9) to[short, i=$Q_1$] (1,10) to [short, -*] (1,10.5)
79
+ node[right]{$P_1$};
80
+
81
+ **Node 1:**
82
+
83
+ :math:`Q_1 = - Q`
84
+
85
+ **Node 2:**
86
+
87
+ :math:`Q_2 = Q`
88
+
89
+ **Internal Equations:**
90
+
91
+ .. math::
92
+
93
+ L\ \dot{Q} + P_2 - P_1 +
94
+ \begin{cases}
95
+ RQ \text{ if Q $>$ 0 } \\
96
+ R_{\text{back}}Q \text{ else }
97
+ \end{cases} = 0
98
+
99
+ **Discretisation:**
100
+
101
+
102
+ .. math:: Q_1^{{n + \frac{1}{2}}} = - Q^{{n + \frac{1}{2}}}
103
+
104
+ .. math:: Q_2^{{n + \frac{1}{2}}} = Q^{{n + \frac{1}{2}}}
105
+
106
+ .. math::
107
+
108
+ L\ \frac{Q^{n + 1} - Q^{n}}{\Delta t^n}
109
+ + P_2^{n + \frac{1}{2}} - P_1^{n + \frac{1}{2}}
110
+ + \begin{cases}
111
+ RQ^{{n + \theta}} \text{ if } Q^{{n + \theta}} > 0 \\
112
+ R_{\text{back}}Q^{{n + \theta}} \text{ else }
113
+ \end{cases} = 0
114
+
115
+ """
116
+
117
+ flux: Quantity[np.float64]
118
+ """Flux traversing the block"""
119
+
120
+ pressure_1: Quantity[np.float64]
121
+ """Pressure quantity at local node 1"""
122
+
123
+ pressure_2: Quantity[np.float64]
124
+ """Pressure quantity at local node 2"""
125
+
126
+ inductance: Quantity[np.float64]
127
+ """Inductance quantity"""
128
+
129
+ conductance: Quantity[np.float64]
130
+ """Conductance quantity for positive flux """
131
+
132
+ backward_conductance: Quantity[np.float64]
133
+ """Conductance quantity for negative flux"""
134
+
135
+ scheme_ts_flux: Quantity[np.float64]
136
+ """Scheme time shift for flux"""
137
+
138
+ time: Time
139
+ """Simulation time"""
140
+
141
+ def initialize(self) -> None:
142
+ self.k_0 = (
143
+ 2.0
144
+ * (self.conductance.current * self.backward_conductance.current)
145
+ / (self.conductance.current + self.backward_conductance.current)
146
+ )
147
+
148
+ def flux_residual(self) -> Any:
149
+ """
150
+ Compute the residual giving the dynamics on the flux in the valve.
151
+
152
+ :return: the residual value
153
+ :rtype: np.float64
154
+ """
155
+
156
+ q_mid_alpha = mid_alpha(self.flux, self.scheme_ts_flux.current)
157
+ pressure_1_mid_point = mid_point(self.pressure_1)
158
+ pressure_2_mid_point = mid_point(self.pressure_2)
159
+
160
+ conductance = self.conductance.current
161
+ if q_mid_alpha < 0:
162
+ conductance = self.backward_conductance.current
163
+
164
+ return (
165
+ self.inductance.current * self.time.inv_dt * diff(self.flux)
166
+ - pressure_1_mid_point
167
+ + pressure_2_mid_point
168
+ + q_mid_alpha / conductance
169
+ )
170
+
171
+ def flux_residual_dflux(self) -> Any:
172
+ """
173
+ Compute the residual partial derivative for ``flux``
174
+
175
+ :return: the residual partial derivative for ``flux``
176
+ :rtype: np.float64
177
+ """
178
+ q_mid_alpha = mid_alpha(self.flux, self.scheme_ts_flux.current)
179
+ conductance = self.conductance.current
180
+ if q_mid_alpha < 0:
181
+ conductance = self.backward_conductance.current
182
+ elif q_mid_alpha == 0:
183
+ conductance = self.k_0
184
+
185
+ return (
186
+ self.inductance.current * self.time.inv_dt
187
+ + (0.5 + self.scheme_ts_flux.current) / conductance
188
+ )
189
+
190
+ def flux_residual_dp1(self) -> Any:
191
+ """
192
+ Compute the residual partial derivative for ``pressure_1``
193
+
194
+ :return: the residual partial derivative for ``pressure_1``
195
+ :rtype: np.float64
196
+ """
197
+
198
+ return -0.5
199
+
200
+ def flux_residual_dp2(self) -> Any:
201
+ """
202
+ Compute the residual partial derivative for ``pressure_2``
203
+
204
+ :return: the residual partial derivative for ``pressure_2``
205
+ :rtype: np.float64
206
+ """
207
+
208
+ return 0.5
209
+
210
+ def flux_1(self) -> Any:
211
+ """
212
+ Compute the block flux at node 1
213
+
214
+
215
+ :return: the block flux at node 1
216
+ :rtype: np.float64
217
+ """
218
+ return -mid_point(self.flux)
219
+
220
+ def dflux_1_dflux(self) -> Any:
221
+ """
222
+ Compute the block flux at node 1 partial derivative for ``flux``
223
+
224
+
225
+ :return: the block flux at node 1 partial derivative for ``flux``
226
+ :rtype: np.float64
227
+ """
228
+ return -0.5
229
+
230
+ def flux_2(self) -> Any:
231
+ """
232
+ Compute the block flux at node 2
233
+
234
+ :return: the block flux at node 2
235
+ :rtype: np.float64
236
+ """
237
+ return mid_point(self.flux)
238
+
239
+ def dflux_2_dflux(self) -> Any:
240
+ """
241
+ Compute the block flux at node 2 partial derivative for ``flux``
242
+
243
+ :return: the block flux at node 2 partial derivative for ``flux``
244
+ :rtype: np.float64
245
+ """
246
+ return 0.5
247
+
248
+
249
+ # define the Valve RL internal variable residual expression
250
+ # giving the dynamics on the flux in the valve
251
+ _valve_rl_flux_residual_expr = Expression(
252
+ 1,
253
+ ValveRLBlock.flux_residual,
254
+ {
255
+ VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.flux_residual_dflux,
256
+ VALVE_RL_BLOCK_PRESSURE_1_DOF_ID: ValveRLBlock.flux_residual_dp1,
257
+ VALVE_RL_BLOCK_PRESSURE_2_DOF_ID: ValveRLBlock.flux_residual_dp2,
258
+ },
259
+ )
260
+
261
+ # define the ValveRL flux expression at node 1.
262
+ _valve_rl_flux_1_expr = Expression(
263
+ 1, ValveRLBlock.flux_1, {VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.dflux_1_dflux}
264
+ )
265
+
266
+ # define the ValveRL flux expression at node 2.
267
+ _valve_rl_flux_2_expr = Expression(
268
+ 1,
269
+ ValveRLBlock.flux_2,
270
+ {VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.dflux_2_dflux},
271
+ )
272
+
273
+ ValveRLBlock.declares_internal_expression(
274
+ VALVE_RL_BLOCK_FLUX_VAR_ID, _valve_rl_flux_residual_expr
275
+ )
276
+ ValveRLBlock.declares_flux_expression(
277
+ 1, VALVE_RL_BLOCK_PRESSURE_1_DOF_ID, _valve_rl_flux_1_expr
278
+ )
279
+ ValveRLBlock.declares_flux_expression(
280
+ 2, VALVE_RL_BLOCK_PRESSURE_2_DOF_ID, _valve_rl_flux_2_expr
281
+ )
@@ -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 configurable functions"""
@@ -0,0 +1,129 @@
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
+ """Define simple operations to initialize parameters in the configuration."""
28
+
29
+ from __future__ import annotations
30
+
31
+ from collections.abc import Iterable
32
+ from dataclasses import dataclass, field
33
+ from typing import Any
34
+
35
+ import numpy as np
36
+
37
+ from physioblocks.base.operators import AbstractBaseOperators
38
+ from physioblocks.registers.type_register import register_type
39
+ from physioblocks.simulation import AbstractFunction
40
+
41
+ # Sum funtion type id
42
+ SUM_TYPE_ID = "sum"
43
+
44
+
45
+ @dataclass
46
+ @register_type(SUM_TYPE_ID)
47
+ class Sum(AbstractFunction, AbstractBaseOperators):
48
+ """
49
+ Sum the elements in ``add`` and subtract the elements in ``subtract``.
50
+ """
51
+
52
+ add: Iterable[Any] = field(default_factory=list)
53
+ """the values to sum"""
54
+
55
+ subtract: Iterable[Any] | None = None
56
+ """the values to subtract"""
57
+
58
+ @property
59
+ def operation_value(self) -> Any:
60
+ """
61
+ Value used with base operators.
62
+
63
+ :return: the current evaluation of the function
64
+ :rtype: Any
65
+ """
66
+ return self.eval()
67
+
68
+ def eval(self) -> Any:
69
+ """
70
+ Sum the elements in ``add`` and subtract the elements in ``subtract``.
71
+
72
+ :return: the sum result
73
+ :rtype: Any
74
+ """
75
+
76
+ pos = np.sum(np.array(self.add), axis=0)
77
+
78
+ if self.subtract is None:
79
+ return pos
80
+
81
+ neg = np.sum(np.array(self.subtract), axis=0)
82
+ return pos - neg
83
+
84
+
85
+ def _multiply(elements: Iterable[Any]) -> Any:
86
+ result = 1.0
87
+ for elem in elements:
88
+ result = np.multiply(result, elem)
89
+ return result
90
+
91
+
92
+ # Product function type name
93
+ PRODUCT_TYPE_ID = "product"
94
+
95
+
96
+ @dataclass
97
+ @register_type(PRODUCT_TYPE_ID)
98
+ class Product(AbstractFunction, AbstractBaseOperators):
99
+ """
100
+ Multiply all values provided in ``factors`` list and divide the
101
+ result with the multiplication of the values in the ``inverses`` list.
102
+
103
+ ..note:: It uses the numpy multiply function
104
+
105
+ """
106
+
107
+ factors: Iterable[Any] = field(default_factory=list)
108
+ """The values to multiply"""
109
+
110
+ inverses: Iterable[Any] | None = None
111
+ """The values to inverse then multiply"""
112
+
113
+ @property
114
+ def operation_value(self) -> Any:
115
+ """
116
+ Value used with base operators.
117
+
118
+ :return: the current evaluation of the function
119
+ :rtype: Any
120
+ """
121
+ return self.eval()
122
+
123
+ def eval(self) -> Any:
124
+ product = _multiply(self.factors)
125
+ if self.inverses is None:
126
+ return product
127
+ else:
128
+ inverses_product = _multiply(self.inverses)
129
+ return product / inverses_product