Coverage for physioblocks / library / blocks / cavity.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-09 16:40 +0100

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

28Describes cavity blocks 

29""" 

30 

31from dataclasses import dataclass 

32from typing import Any 

33 

34import numpy as np 

35 

36from physioblocks.computing import Block, Expression, Quantity 

37from physioblocks.registers import register_type 

38from physioblocks.simulation import Time 

39 

40# Local id for the volume saved quantity 

41CAVITY_VOLUME_LOCAL_ID = "volume" 

42 

43# Local id for the pressure dof in the cavity 

44CAVITY_PRESSURE_LOCAL_ID = "pressure" 

45 

46# Local id for the pressure dof in the cavity 

47CAVITY_DISP_LOCAL_ID = "disp" 

48 

49# Constant for the cavity block type id 

50CAVITY_BLOCK_TYPE_ID = "spherical_cavity_block" 

51 

52 

53@register_type(CAVITY_BLOCK_TYPE_ID) 

54@dataclass 

55class 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 

181SphericalCavityBlock.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) 

190SphericalCavityBlock.declares_saved_quantity_expression( 

191 CAVITY_VOLUME_LOCAL_ID, _cavity_block_fluid_volume_expr 

192)