cardiac-geometriesx 0.5.5__py3-none-any.whl → 0.6.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.
Potentially problematic release.
This version of cardiac-geometriesx might be problematic. Click here for more details.
- cardiac_geometries/cli.py +231 -1
- cardiac_geometries/fibers/cylinder_flat.py +164 -0
- cardiac_geometries/fibers/slab.py +27 -7
- cardiac_geometries/mesh.py +255 -1
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/METADATA +4 -4
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/RECORD +10 -9
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/WHEEL +0 -0
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/entry_points.txt +0 -0
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/top_level.txt +0 -0
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
|
|
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,13 +40,32 @@ def compute_system(
|
|
|
39
40
|
|
|
40
41
|
t = t_func.x.array
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
elif endo_epi_axis == "z":
|
|
52
|
+
f0 = np.array(
|
|
53
|
+
[
|
|
54
|
+
np.cos(alpha(t)),
|
|
55
|
+
np.sin(alpha(t)),
|
|
56
|
+
np.zeros_like(t),
|
|
57
|
+
],
|
|
58
|
+
)
|
|
59
|
+
elif endo_epi_axis == "x":
|
|
60
|
+
f0 = np.array(
|
|
61
|
+
[
|
|
62
|
+
np.zeros_like(t),
|
|
63
|
+
np.cos(alpha(t)),
|
|
64
|
+
np.sin(alpha(t)),
|
|
65
|
+
],
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f"Unknown endo_epi_axis: {endo_epi_axis}")
|
|
49
69
|
|
|
50
70
|
s0 = np.array(
|
|
51
71
|
[
|
cardiac_geometries/mesh.py
CHANGED
|
@@ -1063,7 +1063,7 @@ def cylinder(
|
|
|
1063
1063
|
verbose: bool = False,
|
|
1064
1064
|
comm: MPI.Comm = MPI.COMM_WORLD,
|
|
1065
1065
|
) -> Geometry:
|
|
1066
|
-
"""Create
|
|
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.
|
|
3
|
+
Version: 0.6.0
|
|
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.
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: fenics-dolfinx>=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=
|
|
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=
|
|
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=
|
|
11
|
+
cardiac_geometries/fibers/slab.py,sha256=FVcfQ4AxaOFppc9YOlkQ1BUZvlLEUp3x810ma4YmfYQ,4452
|
|
11
12
|
cardiac_geometries/fibers/utils.py,sha256=Uy0xWpQXNpOLqCYaSFmJ2rKcCeP3lXCLlQnZR1S2KKQ,3852
|
|
12
|
-
cardiac_geometriesx-0.
|
|
13
|
-
cardiac_geometriesx-0.
|
|
14
|
-
cardiac_geometriesx-0.
|
|
15
|
-
cardiac_geometriesx-0.
|
|
16
|
-
cardiac_geometriesx-0.
|
|
17
|
-
cardiac_geometriesx-0.
|
|
13
|
+
cardiac_geometriesx-0.6.0.dist-info/licenses/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
|
|
14
|
+
cardiac_geometriesx-0.6.0.dist-info/METADATA,sha256=ZWIUMPP6Cl8K8nazTGC-6EIBVDChwadVezhsbnuTuhY,4390
|
|
15
|
+
cardiac_geometriesx-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
cardiac_geometriesx-0.6.0.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
|
|
17
|
+
cardiac_geometriesx-0.6.0.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
|
|
18
|
+
cardiac_geometriesx-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
{cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{cardiac_geometriesx-0.5.5.dist-info → cardiac_geometriesx-0.6.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|