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,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
|