cardiac-geometriesx 0.5.5__py3-none-any.whl → 0.6.1__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.

Potentially problematic release.


This version of cardiac-geometriesx might be problematic. Click here for more details.

cardiac_geometries/cli.py CHANGED
@@ -973,7 +973,7 @@ def slab_in_bath(
973
973
  geo.save(outdir / "slab_in_bath.bp")
974
974
 
975
975
 
976
- @click.command(help="Create BiV ellipsoidal geometry")
976
+ @click.command(help="Create cylinder geometry")
977
977
  @click.argument(
978
978
  "outdir",
979
979
  required=True,
@@ -1069,6 +1069,234 @@ def cylinder(
1069
1069
  geo.save(outdir / "cylinder.bp")
1070
1070
 
1071
1071
 
1072
+ @click.command(help="Create racetrack cylinder geometry")
1073
+ @click.argument(
1074
+ "outdir",
1075
+ required=True,
1076
+ type=click.Path(
1077
+ file_okay=False,
1078
+ dir_okay=True,
1079
+ writable=True,
1080
+ readable=True,
1081
+ resolve_path=True,
1082
+ ),
1083
+ )
1084
+ @click.option(
1085
+ "--char-length",
1086
+ default=10.0,
1087
+ type=float,
1088
+ help="Characteristic length of mesh",
1089
+ show_default=True,
1090
+ )
1091
+ @click.option(
1092
+ "--r-inner",
1093
+ default=13.0,
1094
+ type=float,
1095
+ help="Inner radius of the cylinder",
1096
+ show_default=True,
1097
+ )
1098
+ @click.option(
1099
+ "--r-outer",
1100
+ default=20.0,
1101
+ type=float,
1102
+ help="Outer radius of the cylinder",
1103
+ show_default=True,
1104
+ )
1105
+ @click.option(
1106
+ "--height",
1107
+ default=40.0,
1108
+ type=float,
1109
+ help="Height of the cylinder",
1110
+ show_default=True,
1111
+ )
1112
+ @click.option(
1113
+ "--inner-flat-face-distance",
1114
+ default=10.0,
1115
+ type=float,
1116
+ help="Distance from the inner flat face to the center",
1117
+ show_default=True,
1118
+ )
1119
+ @click.option(
1120
+ "--outer-flat-face-distance",
1121
+ default=17.0,
1122
+ type=float,
1123
+ help="Distance from the outer flat face to the center",
1124
+ show_default=True,
1125
+ )
1126
+ @click.option(
1127
+ "--create-fibers",
1128
+ default=False,
1129
+ is_flag=True,
1130
+ help="If True create analytic fibers",
1131
+ show_default=True,
1132
+ )
1133
+ @click.option(
1134
+ "--fiber-angle-endo",
1135
+ default=-60,
1136
+ type=float,
1137
+ help="Angle for the endocardium",
1138
+ show_default=True,
1139
+ )
1140
+ @click.option(
1141
+ "--fiber-angle-epi",
1142
+ default=+60,
1143
+ type=float,
1144
+ help="Angle for the epicardium",
1145
+ show_default=True,
1146
+ )
1147
+ @click.option(
1148
+ "--fiber-space",
1149
+ default="P_1",
1150
+ type=str,
1151
+ help="Function space for fibers of the form family_degree",
1152
+ show_default=True,
1153
+ )
1154
+ def cylinder_racetrack(
1155
+ outdir: Path,
1156
+ char_length: float = 10.0,
1157
+ r_inner: float = 13.0,
1158
+ r_outer: float = 20.0,
1159
+ height: float = 40.0,
1160
+ inner_flat_face_distance: float = 10.0,
1161
+ outer_flat_face_distance: float = 17.0,
1162
+ create_fibers: bool = False,
1163
+ fiber_angle_endo: float = -60,
1164
+ fiber_angle_epi: float = +60,
1165
+ fiber_space: str = "P_1",
1166
+ ):
1167
+ outdir = Path(outdir)
1168
+ outdir.mkdir(exist_ok=True)
1169
+
1170
+ geo = mesh.cylinder_racetrack(
1171
+ outdir=outdir,
1172
+ r_inner=r_inner,
1173
+ r_outer=r_outer,
1174
+ height=height,
1175
+ inner_flat_face_distance=inner_flat_face_distance,
1176
+ outer_flat_face_distance=outer_flat_face_distance,
1177
+ char_length=char_length,
1178
+ create_fibers=create_fibers,
1179
+ fiber_angle_endo=fiber_angle_endo,
1180
+ fiber_angle_epi=fiber_angle_epi,
1181
+ fiber_space=fiber_space,
1182
+ )
1183
+ geo.save(outdir / "cylinder_racetrack.bp")
1184
+
1185
+
1186
+ @click.command(help="Create D-shaped cylinder geometry")
1187
+ @click.argument(
1188
+ "outdir",
1189
+ required=True,
1190
+ type=click.Path(
1191
+ file_okay=False,
1192
+ dir_okay=True,
1193
+ writable=True,
1194
+ readable=True,
1195
+ resolve_path=True,
1196
+ ),
1197
+ )
1198
+ @click.option(
1199
+ "--char-length",
1200
+ default=10.0,
1201
+ type=float,
1202
+ help="Characteristic length of mesh",
1203
+ show_default=True,
1204
+ )
1205
+ @click.option(
1206
+ "--r-inner",
1207
+ default=13.0,
1208
+ type=float,
1209
+ help="Inner radius of the cylinder",
1210
+ show_default=True,
1211
+ )
1212
+ @click.option(
1213
+ "--r-outer",
1214
+ default=20.0,
1215
+ type=float,
1216
+ help="Outer radius of the cylinder",
1217
+ show_default=True,
1218
+ )
1219
+ @click.option(
1220
+ "--height",
1221
+ default=40.0,
1222
+ type=float,
1223
+ help="Height of the cylinder",
1224
+ show_default=True,
1225
+ )
1226
+ @click.option(
1227
+ "--inner-flat-face-distance",
1228
+ default=10.0,
1229
+ type=float,
1230
+ help="Distance from the inner flat face to the center",
1231
+ show_default=True,
1232
+ )
1233
+ @click.option(
1234
+ "--outer-flat-face-distance",
1235
+ default=17.0,
1236
+ type=float,
1237
+ help="Distance from the outer flat face to the center",
1238
+ show_default=True,
1239
+ )
1240
+ @click.option(
1241
+ "--create-fibers",
1242
+ default=False,
1243
+ is_flag=True,
1244
+ help="If True create analytic fibers",
1245
+ show_default=True,
1246
+ )
1247
+ @click.option(
1248
+ "--fiber-angle-endo",
1249
+ default=-60,
1250
+ type=float,
1251
+ help="Angle for the endocardium",
1252
+ show_default=True,
1253
+ )
1254
+ @click.option(
1255
+ "--fiber-angle-epi",
1256
+ default=+60,
1257
+ type=float,
1258
+ help="Angle for the epicardium",
1259
+ show_default=True,
1260
+ )
1261
+ @click.option(
1262
+ "--fiber-space",
1263
+ default="P_1",
1264
+ type=str,
1265
+ help="Function space for fibers of the form family_degree",
1266
+ show_default=True,
1267
+ )
1268
+ def cylinder_D_shaped(
1269
+ outdir: Path,
1270
+ char_length: float = 10.0,
1271
+ r_inner: float = 13.0,
1272
+ r_outer: float = 20.0,
1273
+ height: float = 40.0,
1274
+ inner_flat_face_distance: float = 10.0,
1275
+ outer_flat_face_distance: float = 17.0,
1276
+ create_fibers: bool = False,
1277
+ fiber_angle_endo: float = -60,
1278
+ fiber_angle_epi: float = +60,
1279
+ fiber_space: str = "P_1",
1280
+ ):
1281
+ outdir = Path(outdir)
1282
+ outdir.mkdir(exist_ok=True)
1283
+
1284
+ geo = mesh.cylinder_D_shaped(
1285
+ outdir=outdir,
1286
+ r_inner=r_inner,
1287
+ r_outer=r_outer,
1288
+ height=height,
1289
+ inner_flat_face_distance=inner_flat_face_distance,
1290
+ outer_flat_face_distance=outer_flat_face_distance,
1291
+ char_length=char_length,
1292
+ create_fibers=create_fibers,
1293
+ fiber_angle_endo=fiber_angle_endo,
1294
+ fiber_angle_epi=fiber_angle_epi,
1295
+ fiber_space=fiber_space,
1296
+ )
1297
+ geo.save(outdir / "cylinder_D_shaped.bp")
1298
+
1299
+
1072
1300
  @click.command("gui")
1073
1301
  def gui():
1074
1302
  # Make sure we can import the required packages
@@ -1088,3 +1316,5 @@ app.add_command(slab_in_bath)
1088
1316
  app.add_command(gui)
1089
1317
  app.add_command(ukb)
1090
1318
  app.add_command(cylinder)
1319
+ app.add_command(cylinder_racetrack)
1320
+ app.add_command(cylinder_D_shaped)
@@ -0,0 +1,164 @@
1
+ from pathlib import Path
2
+
3
+ import dolfinx
4
+
5
+ from . import cylinder, slab, utils
6
+
7
+
8
+ def create_microstructure(
9
+ mesh: dolfinx.mesh.Mesh,
10
+ alpha_endo: float,
11
+ alpha_epi: float,
12
+ r_inner: float,
13
+ r_outer: float,
14
+ inner_flat_face_distance: float,
15
+ ffun: dolfinx.mesh.MeshTags,
16
+ markers: dict[str, tuple[int, int]],
17
+ function_space: str = "P_1",
18
+ outdir: str | Path | None = None,
19
+ **kwargs,
20
+ ) -> utils.Microstructure:
21
+ """Generate microstructure for cylinder
22
+
23
+ Parameters
24
+ ----------
25
+ mesh : dolfinx.mesh.Mesh
26
+ A cylinder mesh
27
+ alpha_endo : float
28
+ Angle on the endocardium
29
+ alpha_epi : float
30
+ Angle on the epicardium
31
+ r_inner : float
32
+ Inner radius
33
+ r_outer : float
34
+ Outer radius
35
+ function_space : str
36
+ Function space to interpolate the fibers, by default P_1
37
+ outdir : Optional[Union[str, Path]], optional
38
+ Output directory to store the results, by default None.
39
+ If no output directory is specified the results will not be stored,
40
+ but only returned.
41
+
42
+ Returns
43
+ -------
44
+ Microstructure
45
+ Tuple with fiber, sheet and sheet normal
46
+ """
47
+
48
+ system_cylinder = cylinder.compute_system(
49
+ mesh=mesh,
50
+ function_space=function_space,
51
+ r_inner=r_inner,
52
+ r_outer=r_outer,
53
+ alpha_endo=alpha_endo,
54
+ alpha_epi=alpha_epi,
55
+ )
56
+
57
+ x = system_cylinder.f0.function_space.tabulate_dof_coordinates().T[0]
58
+
59
+ f0_arr = system_cylinder.f0.x.array.reshape((-1, 3))
60
+ s0_arr = system_cylinder.s0.x.array.reshape((-1, 3))
61
+ n0_arr = system_cylinder.n0.x.array.reshape((-1, 3))
62
+
63
+ if "INSIDE_FLAT" in markers:
64
+ # This is the D-shaped cylinder
65
+ t = utils.laplace(
66
+ mesh,
67
+ ffun,
68
+ endo_marker=markers["INSIDE_FLAT"][0],
69
+ epi_marker=markers["OUTSIDE_FLAT"][0],
70
+ function_space=function_space,
71
+ )
72
+
73
+ if outdir is not None:
74
+ try:
75
+ with dolfinx.io.VTXWriter(
76
+ mesh.comm, Path(outdir) / "laplace_flat.bp", [t], engine="BP4"
77
+ ) as file:
78
+ file.write(0.0)
79
+ except RuntimeError:
80
+ pass
81
+
82
+ system_flat = slab.compute_system(
83
+ t,
84
+ alpha_endo=-alpha_endo,
85
+ alpha_epi=-alpha_epi,
86
+ endo_epi_axis="x",
87
+ )
88
+ flat_indices = x >= inner_flat_face_distance - 1e-8
89
+ f0_arr[flat_indices, :] = system_flat.f0.x.array.reshape((-1, 3))[flat_indices, :]
90
+ s0_arr[flat_indices, :] = system_flat.s0.x.array.reshape((-1, 3))[flat_indices, :]
91
+ n0_arr[flat_indices, :] = system_flat.n0.x.array.reshape((-1, 3))[flat_indices, :]
92
+
93
+ elif "INSIDE_FLAT1" in markers:
94
+ # This is the racetrack
95
+
96
+ # First side
97
+ t = utils.laplace(
98
+ mesh,
99
+ ffun,
100
+ endo_marker=markers["INSIDE_FLAT1"][0],
101
+ epi_marker=markers["OUTSIDE_FLAT1"][0],
102
+ function_space=function_space,
103
+ )
104
+
105
+ if outdir is not None:
106
+ try:
107
+ with dolfinx.io.VTXWriter(
108
+ mesh.comm, Path(outdir) / "laplace_flat1.bp", [t], engine="BP4"
109
+ ) as file:
110
+ file.write(0.0)
111
+ except RuntimeError:
112
+ pass
113
+
114
+ system_flat1 = slab.compute_system(
115
+ t,
116
+ alpha_endo=-alpha_endo,
117
+ alpha_epi=-alpha_epi,
118
+ endo_epi_axis="x",
119
+ )
120
+ flat_indices = x >= inner_flat_face_distance - 1e-8
121
+ f0_arr[flat_indices, :] = system_flat1.f0.x.array.reshape((-1, 3))[flat_indices, :]
122
+ s0_arr[flat_indices, :] = system_flat1.s0.x.array.reshape((-1, 3))[flat_indices, :]
123
+ n0_arr[flat_indices, :] = system_flat1.n0.x.array.reshape((-1, 3))[flat_indices, :]
124
+
125
+ # Second side
126
+ t = utils.laplace(
127
+ mesh,
128
+ ffun,
129
+ endo_marker=markers["INSIDE_FLAT2"][0],
130
+ epi_marker=markers["OUTSIDE_FLAT2"][0],
131
+ function_space=function_space,
132
+ )
133
+
134
+ if outdir is not None:
135
+ try:
136
+ with dolfinx.io.VTXWriter(
137
+ mesh.comm, Path(outdir) / "laplace_flat2.bp", [t], engine="BP4"
138
+ ) as file:
139
+ file.write(0.0)
140
+ except RuntimeError:
141
+ pass
142
+
143
+ system_flat1 = slab.compute_system(
144
+ t,
145
+ alpha_endo=alpha_endo,
146
+ alpha_epi=alpha_epi,
147
+ endo_epi_axis="x",
148
+ )
149
+ flat_indices = x <= -inner_flat_face_distance + 1e-8
150
+ f0_arr[flat_indices, :] = system_flat1.f0.x.array.reshape((-1, 3))[flat_indices, :]
151
+ s0_arr[flat_indices, :] = system_flat1.s0.x.array.reshape((-1, 3))[flat_indices, :]
152
+ n0_arr[flat_indices, :] = system_flat1.n0.x.array.reshape((-1, 3))[flat_indices, :]
153
+ else:
154
+ raise ValueError(
155
+ "Markers for flat faces not found. Please provide markers for the flat faces."
156
+ )
157
+ system_cylinder.f0.x.array[:] = f0_arr.reshape(-1)
158
+ system_cylinder.s0.x.array[:] = s0_arr.reshape(-1)
159
+ system_cylinder.n0.x.array[:] = n0_arr.reshape(-1)
160
+
161
+ if outdir is not None:
162
+ utils.save_microstructure(mesh, system_cylinder, outdir)
163
+
164
+ return system_cylinder
@@ -11,6 +11,7 @@ def compute_system(
11
11
  t_func: dolfinx.fem.Function,
12
12
  alpha_endo: float = -60,
13
13
  alpha_epi: float = 60,
14
+ endo_epi_axis="y",
14
15
  ) -> utils.Microstructure:
15
16
  """Compute ldrb system for slab, assuming linear
16
17
  angle between endo and epi
@@ -39,24 +40,56 @@ def compute_system(
39
40
 
40
41
  t = t_func.x.array
41
42
 
42
- f0 = np.array(
43
- [
44
- np.cos(alpha(t)),
45
- np.zeros_like(t),
46
- np.sin(alpha(t)),
47
- ],
48
- )
49
-
50
- s0 = np.array(
51
- [
52
- np.zeros_like(t),
53
- np.ones_like(t),
54
- np.zeros_like(t),
55
- ],
56
- )
57
-
58
- n0 = np.cross(f0, s0, axis=0)
59
- n0 = utils.normalize(n0)
43
+ if endo_epi_axis == "y":
44
+ f0 = np.array(
45
+ [
46
+ np.cos(alpha(t)),
47
+ np.zeros_like(t),
48
+ np.sin(alpha(t)),
49
+ ],
50
+ )
51
+ n0 = np.array(
52
+ [
53
+ np.zeros_like(t),
54
+ np.ones_like(t),
55
+ np.zeros_like(t),
56
+ ],
57
+ )
58
+ elif endo_epi_axis == "z":
59
+ f0 = np.array(
60
+ [
61
+ np.cos(alpha(t)),
62
+ np.sin(alpha(t)),
63
+ np.zeros_like(t),
64
+ ],
65
+ )
66
+ n0 = np.array(
67
+ [
68
+ np.zeros_like(t),
69
+ np.zeros_like(t),
70
+ np.ones_like(t),
71
+ ],
72
+ )
73
+ elif endo_epi_axis == "x":
74
+ f0 = np.array(
75
+ [
76
+ np.zeros_like(t),
77
+ np.cos(alpha(t)),
78
+ np.sin(alpha(t)),
79
+ ],
80
+ )
81
+ n0 = np.array(
82
+ [
83
+ np.ones_like(t),
84
+ np.zeros_like(t),
85
+ np.zeros_like(t),
86
+ ],
87
+ )
88
+ else:
89
+ raise ValueError(f"Unknown endo_epi_axis: {endo_epi_axis}")
90
+
91
+ s0 = np.cross(f0, n0, axis=0)
92
+ s0 = utils.normalize(s0)
60
93
 
61
94
  Vv = space_from_string(
62
95
  space_string=f"{element.family_name}_{element.degree}",
@@ -1063,7 +1063,7 @@ def cylinder(
1063
1063
  verbose: bool = False,
1064
1064
  comm: MPI.Comm = MPI.COMM_WORLD,
1065
1065
  ) -> Geometry:
1066
- """Create an LV ellipsoidal geometry
1066
+ """Create a cylindrical geometry
1067
1067
 
1068
1068
  Parameters
1069
1069
  ----------
@@ -1157,3 +1157,257 @@ def cylinder(
1157
1157
  geo = Geometry.from_folder(comm=comm, folder=outdir)
1158
1158
 
1159
1159
  return geo
1160
+
1161
+
1162
+ def cylinder_racetrack(
1163
+ outdir: Path | str,
1164
+ r_inner: float = 13.0,
1165
+ r_outer: float = 20.0,
1166
+ height: float = 40.0,
1167
+ inner_flat_face_distance: float = 10.0,
1168
+ outer_flat_face_distance: float = 17.0,
1169
+ char_length: float = 10.0,
1170
+ create_fibers: bool = False,
1171
+ fiber_angle_endo: float = 60,
1172
+ fiber_angle_epi: float = -60,
1173
+ fiber_space: str = "P_1",
1174
+ aha: bool = True,
1175
+ verbose: bool = False,
1176
+ comm: MPI.Comm = MPI.COMM_WORLD,
1177
+ ) -> Geometry:
1178
+ """Create a racetrack-shaped thick cylindrical shell mesh using GMSH.
1179
+
1180
+ Both the inner and outer surfaces have two flat faces on opposite sides.
1181
+
1182
+ Parameters
1183
+ ----------
1184
+ outdir : Optional[Path], optional
1185
+ Directory where to save the results.
1186
+ r_inner : float, optional
1187
+ Radius on the endocardium layer, by default 13.0
1188
+ r_outer : float, optional
1189
+ Radius on the epicardium layer, by default 20.0
1190
+ height : float, optional
1191
+ Longest radius on the endocardium layer, by default 10.0
1192
+ inner_flat_face_distance : float
1193
+ The distance of the inner flat face from the center (along the x-axis).
1194
+ This value must be less than inner_radius. Default is 10.0.
1195
+ outer_flat_face_distance : float
1196
+ The distance of the outer flat face from the center (along the x-axis).
1197
+ This value must be less than outer_radius. Default is 17.0.
1198
+ char_length : float, optional
1199
+ Characteristic length of mesh, by default 10.0
1200
+ create_fibers : bool, optional
1201
+ If True create analytic fibers, by default False
1202
+ fiber_angle_endo : float, optional
1203
+ Angle for the endocardium, by default 60
1204
+ fiber_angle_epi : float, optional
1205
+ Angle for the epicardium, by default -60
1206
+ fiber_space : str, optional
1207
+ Function space for fibers of the form family_degree, by default "P_1"
1208
+ aha : bool, optional
1209
+ If True create 17-segment AHA regions
1210
+ verbose : bool, optional
1211
+ If True print information from gmsh, by default False
1212
+ comm : MPI.Comm, optional
1213
+ MPI communicator, by default MPI.COMM_WORLD
1214
+
1215
+ Returns
1216
+ -------
1217
+ cardiac_geometries.geometry.Geometry
1218
+ A Geometry with the mesh, markers, markers functions and fibers.
1219
+
1220
+ """
1221
+
1222
+ outdir = Path(outdir)
1223
+ mesh_name = outdir / "cylinder_racetrack.msh"
1224
+ if comm.rank == 0:
1225
+ outdir.mkdir(exist_ok=True, parents=True)
1226
+
1227
+ with open(outdir / "info.json", "w") as f:
1228
+ json.dump(
1229
+ {
1230
+ "r_inner": r_inner,
1231
+ "r_outer": r_outer,
1232
+ "height": height,
1233
+ "inner_flat_face_distance": inner_flat_face_distance,
1234
+ "outer_flat_face_distance": outer_flat_face_distance,
1235
+ "char_length": char_length,
1236
+ "create_fibers": create_fibers,
1237
+ "fiber_angle_endo": fiber_angle_endo,
1238
+ "fiber_angle_epi": fiber_angle_epi,
1239
+ "fiber_space": fiber_space,
1240
+ "aha": aha,
1241
+ "mesh_type": "cylinder",
1242
+ "cardiac_geometry_version": __version__,
1243
+ "timestamp": datetime.datetime.now().isoformat(),
1244
+ },
1245
+ f,
1246
+ indent=2,
1247
+ default=utils.json_serial,
1248
+ )
1249
+
1250
+ cgc.cylinder_racetrack(
1251
+ inner_radius=r_inner,
1252
+ outer_radius=r_outer,
1253
+ inner_flat_face_distance=inner_flat_face_distance,
1254
+ outer_flat_face_distance=outer_flat_face_distance,
1255
+ height=height,
1256
+ mesh_name=mesh_name.as_posix(),
1257
+ char_length=char_length,
1258
+ verbose=verbose,
1259
+ )
1260
+ comm.barrier()
1261
+
1262
+ geometry = utils.gmsh2dolfin(comm=comm, msh_file=mesh_name)
1263
+
1264
+ if comm.rank == 0:
1265
+ with open(outdir / "markers.json", "w") as f:
1266
+ json.dump(geometry.markers, f, default=utils.json_serial)
1267
+
1268
+ if create_fibers:
1269
+ from .fibers.cylinder_flat import create_microstructure
1270
+
1271
+ create_microstructure(
1272
+ mesh=geometry.mesh,
1273
+ function_space=fiber_space,
1274
+ r_inner=r_inner,
1275
+ r_outer=r_outer,
1276
+ inner_flat_face_distance=inner_flat_face_distance,
1277
+ ffun=geometry.ffun,
1278
+ markers=geometry.markers,
1279
+ alpha_endo=fiber_angle_endo,
1280
+ alpha_epi=fiber_angle_epi,
1281
+ outdir=outdir,
1282
+ )
1283
+
1284
+ geo = Geometry.from_folder(comm=comm, folder=outdir)
1285
+
1286
+ return geo
1287
+
1288
+
1289
+ def cylinder_D_shaped(
1290
+ outdir: Path | str,
1291
+ r_inner: float = 13.0,
1292
+ r_outer: float = 20.0,
1293
+ height: float = 40.0,
1294
+ inner_flat_face_distance: float = 10.0,
1295
+ outer_flat_face_distance: float = 17.0,
1296
+ char_length: float = 10.0,
1297
+ create_fibers: bool = False,
1298
+ fiber_angle_endo: float = 60,
1299
+ fiber_angle_epi: float = -60,
1300
+ fiber_space: str = "P_1",
1301
+ aha: bool = True,
1302
+ verbose: bool = False,
1303
+ comm: MPI.Comm = MPI.COMM_WORLD,
1304
+ ) -> Geometry:
1305
+ """Create a D-shaped thick cylindrical shell mesh using GMSH.
1306
+
1307
+ Both the inner and outer surfaces have two flat faces on opposite sides.
1308
+
1309
+ Parameters
1310
+ ----------
1311
+ outdir : Optional[Path], optional
1312
+ Directory where to save the results.
1313
+ r_inner : float, optional
1314
+ Radius on the endocardium layer, by default 13.0
1315
+ r_outer : float, optional
1316
+ Radius on the epicardium layer, by default 20.0
1317
+ height : float, optional
1318
+ Longest radius on the endocardium layer, by default 10.0
1319
+ inner_flat_face_distance : float
1320
+ The distance of the inner flat face from the center (along the x-axis).
1321
+ This value must be less than inner_radius. Default is 10.0.
1322
+ outer_flat_face_distance : float
1323
+ The distance of the outer flat face from the center (along the x-axis).
1324
+ This value must be less than outer_radius. Default is 17.0.
1325
+ char_length : float, optional
1326
+ Characteristic length of mesh, by default 10.0
1327
+ create_fibers : bool, optional
1328
+ If True create analytic fibers, by default False
1329
+ fiber_angle_endo : float, optional
1330
+ Angle for the endocardium, by default 60
1331
+ fiber_angle_epi : float, optional
1332
+ Angle for the epicardium, by default -60
1333
+ fiber_space : str, optional
1334
+ Function space for fibers of the form family_degree, by default "P_1"
1335
+ aha : bool, optional
1336
+ If True create 17-segment AHA regions
1337
+ verbose : bool, optional
1338
+ If True print information from gmsh, by default False
1339
+ comm : MPI.Comm, optional
1340
+ MPI communicator, by default MPI.COMM_WORLD
1341
+
1342
+ Returns
1343
+ -------
1344
+ cardiac_geometries.geometry.Geometry
1345
+ A Geometry with the mesh, markers, markers functions and fibers.
1346
+
1347
+ """
1348
+
1349
+ outdir = Path(outdir)
1350
+ mesh_name = outdir / "cylinder_D_shaped.msh"
1351
+ if comm.rank == 0:
1352
+ outdir.mkdir(exist_ok=True, parents=True)
1353
+
1354
+ with open(outdir / "info.json", "w") as f:
1355
+ json.dump(
1356
+ {
1357
+ "r_inner": r_inner,
1358
+ "r_outer": r_outer,
1359
+ "height": height,
1360
+ "inner_flat_face_distance": inner_flat_face_distance,
1361
+ "outer_flat_face_distance": outer_flat_face_distance,
1362
+ "char_length": char_length,
1363
+ "create_fibers": create_fibers,
1364
+ "fiber_angle_endo": fiber_angle_endo,
1365
+ "fiber_angle_epi": fiber_angle_epi,
1366
+ "fiber_space": fiber_space,
1367
+ "aha": aha,
1368
+ "mesh_type": "cylinder",
1369
+ "cardiac_geometry_version": __version__,
1370
+ "timestamp": datetime.datetime.now().isoformat(),
1371
+ },
1372
+ f,
1373
+ indent=2,
1374
+ default=utils.json_serial,
1375
+ )
1376
+
1377
+ cgc.cylinder_D_shaped(
1378
+ inner_radius=r_inner,
1379
+ outer_radius=r_outer,
1380
+ inner_flat_face_distance=inner_flat_face_distance,
1381
+ outer_flat_face_distance=outer_flat_face_distance,
1382
+ height=height,
1383
+ mesh_name=mesh_name.as_posix(),
1384
+ char_length=char_length,
1385
+ verbose=verbose,
1386
+ )
1387
+ comm.barrier()
1388
+
1389
+ geometry = utils.gmsh2dolfin(comm=comm, msh_file=mesh_name)
1390
+
1391
+ if comm.rank == 0:
1392
+ with open(outdir / "markers.json", "w") as f:
1393
+ json.dump(geometry.markers, f, default=utils.json_serial)
1394
+
1395
+ if create_fibers:
1396
+ from .fibers.cylinder_flat import create_microstructure
1397
+
1398
+ create_microstructure(
1399
+ mesh=geometry.mesh,
1400
+ function_space=fiber_space,
1401
+ r_inner=r_inner,
1402
+ r_outer=r_outer,
1403
+ inner_flat_face_distance=inner_flat_face_distance,
1404
+ ffun=geometry.ffun,
1405
+ markers=geometry.markers,
1406
+ alpha_endo=fiber_angle_endo,
1407
+ alpha_epi=fiber_angle_epi,
1408
+ outdir=outdir,
1409
+ )
1410
+
1411
+ geo = Geometry.from_folder(comm=comm, folder=outdir)
1412
+
1413
+ return geo
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardiac-geometriesx
3
- Version: 0.5.5
3
+ Version: 0.6.1
4
4
  Summary: A python library for cardiac geometries
5
5
  Author-email: Henrik Finsberg <henriknf@simula.no>
6
6
  License: MIT
@@ -9,12 +9,12 @@ Keywords: cardiac,geometry
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
- Requires-Python: >=3.8
12
+ Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: fenics-dolfinx>=0.8.0
15
+ Requires-Dist: fenics-dolfinx>=0.9.0
16
16
  Requires-Dist: structlog
17
- Requires-Dist: cardiac-geometries-core
17
+ Requires-Dist: cardiac-geometries-core>=0.4
18
18
  Requires-Dist: rich-click
19
19
  Requires-Dist: adios4dolfinx
20
20
  Requires-Dist: scifem
@@ -1,17 +1,18 @@
1
1
  cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
2
- cardiac_geometries/cli.py,sha256=bJ0ICY2KRCVBYxhTrMg66PbqSXrThMWwzQ61dJQgJo0,24018
2
+ cardiac_geometries/cli.py,sha256=a4LTlphEl_ODGFRhHjhg-RHqWNTQYgbA_apora0NuY4,29318
3
3
  cardiac_geometries/geometry.py,sha256=b-JbxV1wTgrjgQaNNG4NiGmXLs3nqRabsUUtYDnyKKA,13616
4
4
  cardiac_geometries/gui.py,sha256=9WYR850wLrqsUrVUC37E2SaO0OWA_oagSe-YNrsxz3k,8376
5
- cardiac_geometries/mesh.py,sha256=3fiCZP2mdgx5HIFUlWciVAMHUPBh6aFqx7mSJV6Jvpw,39199
5
+ cardiac_geometries/mesh.py,sha256=4aqzrPMgpV1gapRAFPHIYuroSZvcEFxtMefOpgIdhfc,48224
6
6
  cardiac_geometries/utils.py,sha256=6H0tZif7GPINdrxfPm3HQH1T4_DfDvWMejjpXPb8mLY,22206
7
7
  cardiac_geometries/fibers/__init__.py,sha256=iggELqJBQySc6ihph1-yaweOfxNvvTE2670RnUnOgDw,2229
8
8
  cardiac_geometries/fibers/cylinder.py,sha256=Q1GIuVvntPQ7pW6Z4UYSC8-8WfkClbakiW81Fl9dvk0,3345
9
+ cardiac_geometries/fibers/cylinder_flat.py,sha256=h8ZeyQdZJAOTU456TIumh3eWkZkhzf7R7CpKki5HNrk,5304
9
10
  cardiac_geometries/fibers/lv_ellipsoid.py,sha256=KMVOHg2VPg1tF2R9TKIX-vQr6dDM4HThh12WW_diNfU,6024
10
- cardiac_geometries/fibers/slab.py,sha256=IbyWyB4sFSa8Yo0gc4eiC9AXZtB5QB2Tm_IvdRZKg0o,3904
11
+ cardiac_geometries/fibers/slab.py,sha256=vQ9nYoAnoeBevEYkY3Hsy7o4tZ_gfBWaZI_p5UH_PgM,4805
11
12
  cardiac_geometries/fibers/utils.py,sha256=Uy0xWpQXNpOLqCYaSFmJ2rKcCeP3lXCLlQnZR1S2KKQ,3852
12
- cardiac_geometriesx-0.5.5.dist-info/licenses/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
13
- cardiac_geometriesx-0.5.5.dist-info/METADATA,sha256=Y0VJRaGO3GP97CvYYQ3yheEVfuRNmkL948uPpWuf_F8,4384
14
- cardiac_geometriesx-0.5.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- cardiac_geometriesx-0.5.5.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
16
- cardiac_geometriesx-0.5.5.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
17
- cardiac_geometriesx-0.5.5.dist-info/RECORD,,
13
+ cardiac_geometriesx-0.6.1.dist-info/licenses/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
14
+ cardiac_geometriesx-0.6.1.dist-info/METADATA,sha256=Cf1DsbM2vQ37J35hkvJ07MTwkIL-kTMDEh-LLsgghnY,4390
15
+ cardiac_geometriesx-0.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ cardiac_geometriesx-0.6.1.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
17
+ cardiac_geometriesx-0.6.1.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
18
+ cardiac_geometriesx-0.6.1.dist-info/RECORD,,