cardiac-geometriesx 0.1.1__py3-none-any.whl → 0.1.3__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 +3 -1
- cardiac_geometries/fibers/lv_ellipsoid.py +5 -3
- cardiac_geometries/fibers/slab.py +4 -3
- cardiac_geometries/fibers/utils.py +4 -2
- cardiac_geometries/geometry.py +82 -32
- cardiac_geometries/mesh.py +45 -22
- cardiac_geometries/utils.py +262 -12
- cardiac_geometriesx-0.1.3.dist-info/LICENSE +21 -0
- cardiac_geometriesx-0.1.3.dist-info/METADATA +87 -0
- cardiac_geometriesx-0.1.3.dist-info/RECORD +15 -0
- {cardiac_geometriesx-0.1.1.dist-info → cardiac_geometriesx-0.1.3.dist-info}/WHEEL +1 -1
- cardiac_geometriesx-0.1.1.dist-info/METADATA +0 -51
- cardiac_geometriesx-0.1.1.dist-info/RECORD +0 -14
- {cardiac_geometriesx-0.1.1.dist-info → cardiac_geometriesx-0.1.3.dist-info}/entry_points.txt +0 -0
- {cardiac_geometriesx-0.1.1.dist-info → cardiac_geometriesx-0.1.3.dist-info}/top_level.txt +0 -0
cardiac_geometries/cli.py
CHANGED
|
@@ -8,8 +8,10 @@ from . import mesh
|
|
|
8
8
|
|
|
9
9
|
meta = metadata("cardiac-geometriesx")
|
|
10
10
|
__version__ = meta["Version"]
|
|
11
|
-
__author__ = meta["Author"]
|
|
11
|
+
__author__ = meta["Author-email"]
|
|
12
12
|
__license__ = meta["License"]
|
|
13
|
+
__email__ = meta["Author-email"]
|
|
14
|
+
__program_name__ = meta["Name"]
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
@click.group()
|
|
@@ -131,9 +131,11 @@ def create_microstructure(
|
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
if outdir is not None:
|
|
134
|
-
with dolfinx.io.
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
with dolfinx.io.VTXWriter(
|
|
135
|
+
mesh.comm, Path(outdir) / "laplace.bp", [t], engine="BP4"
|
|
136
|
+
) as file:
|
|
137
|
+
file.write(0.0)
|
|
138
|
+
|
|
137
139
|
system = compute_system(
|
|
138
140
|
t,
|
|
139
141
|
function_space=function_space,
|
|
@@ -134,9 +134,10 @@ def create_microstructure(
|
|
|
134
134
|
function_space=function_space,
|
|
135
135
|
)
|
|
136
136
|
if outdir is not None:
|
|
137
|
-
with dolfinx.io.
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
with dolfinx.io.VTXWriter(
|
|
138
|
+
mesh.comm, Path(outdir) / "laplace.bp", [t], engine="BP4"
|
|
139
|
+
) as file:
|
|
140
|
+
file.write(0.0)
|
|
140
141
|
|
|
141
142
|
system = compute_system(
|
|
142
143
|
t,
|
|
@@ -20,9 +20,11 @@ def save_microstructure(
|
|
|
20
20
|
from ..utils import element2array
|
|
21
21
|
|
|
22
22
|
# Save for paraview visualization
|
|
23
|
-
with dolfinx.io.VTXWriter(
|
|
23
|
+
with dolfinx.io.VTXWriter(
|
|
24
|
+
mesh.comm, Path(outdir) / "microstructure-viz.bp", functions, engine="BP4"
|
|
25
|
+
) as file:
|
|
24
26
|
file.write(0.0)
|
|
25
|
-
|
|
27
|
+
|
|
26
28
|
# Save with proper function space
|
|
27
29
|
filename = Path(outdir) / "microstructure.bp"
|
|
28
30
|
for function in functions:
|
cardiac_geometries/geometry.py
CHANGED
|
@@ -12,12 +12,14 @@ import numpy as np
|
|
|
12
12
|
from . import utils
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@dataclass#(frozen=True, slots=True)
|
|
15
|
+
@dataclass # (frozen=True, slots=True)
|
|
16
16
|
class Geometry:
|
|
17
17
|
mesh: dolfinx.mesh.Mesh
|
|
18
|
-
markers: dict[str, tuple[
|
|
19
|
-
ffun: dolfinx.mesh.MeshTags | None = None
|
|
18
|
+
markers: dict[str, tuple[int, int]] = field(default_factory=dict)
|
|
20
19
|
cfun: dolfinx.mesh.MeshTags | None = None
|
|
20
|
+
ffun: dolfinx.mesh.MeshTags | None = None
|
|
21
|
+
efun: dolfinx.mesh.MeshTags | None = None
|
|
22
|
+
vfun: dolfinx.mesh.MeshTags | None = None
|
|
21
23
|
f0: dolfinx.fem.Function | None = None
|
|
22
24
|
s0: dolfinx.fem.Function | None = None
|
|
23
25
|
n0: dolfinx.fem.Function | None = None
|
|
@@ -25,8 +27,7 @@ class Geometry:
|
|
|
25
27
|
def save(self, path: str | Path) -> None:
|
|
26
28
|
path = Path(path)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
shutil.rmtree(path)
|
|
30
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
30
31
|
self.mesh.comm.barrier()
|
|
31
32
|
adios4dolfinx.write_mesh(mesh=self.mesh, filename=path)
|
|
32
33
|
|
|
@@ -37,11 +38,33 @@ class Geometry:
|
|
|
37
38
|
attributes={k: np.array(v, dtype=np.uint8) for k, v in self.markers.items()},
|
|
38
39
|
)
|
|
39
40
|
|
|
41
|
+
if self.cfun is not None:
|
|
42
|
+
adios4dolfinx.write_meshtags(
|
|
43
|
+
meshtags=self.cfun,
|
|
44
|
+
mesh=self.mesh,
|
|
45
|
+
filename=path,
|
|
46
|
+
meshtag_name="Cell tags",
|
|
47
|
+
)
|
|
40
48
|
if self.ffun is not None:
|
|
41
49
|
adios4dolfinx.write_meshtags(
|
|
42
50
|
meshtags=self.ffun,
|
|
43
51
|
mesh=self.mesh,
|
|
44
52
|
filename=path,
|
|
53
|
+
meshtag_name="Facet tags",
|
|
54
|
+
)
|
|
55
|
+
if self.efun is not None:
|
|
56
|
+
adios4dolfinx.write_meshtags(
|
|
57
|
+
meshtags=self.efun,
|
|
58
|
+
mesh=self.mesh,
|
|
59
|
+
filename=path,
|
|
60
|
+
meshtag_name="Edge tags",
|
|
61
|
+
)
|
|
62
|
+
if self.vfun is not None:
|
|
63
|
+
adios4dolfinx.write_meshtags(
|
|
64
|
+
meshtags=self.vfun,
|
|
65
|
+
mesh=self.mesh,
|
|
66
|
+
filename=path,
|
|
67
|
+
meshtag_name="Vertex tags",
|
|
45
68
|
)
|
|
46
69
|
|
|
47
70
|
if self.f0 is not None:
|
|
@@ -60,26 +83,49 @@ class Geometry:
|
|
|
60
83
|
if self.n0 is not None:
|
|
61
84
|
adios4dolfinx.write_function(u=self.n0, filename=path, name="n0")
|
|
62
85
|
|
|
86
|
+
self.mesh.comm.barrier()
|
|
87
|
+
|
|
63
88
|
@classmethod
|
|
64
89
|
def from_file(cls, comm: MPI.Intracomm, path: str | Path) -> "Geometry":
|
|
65
90
|
path = Path(path)
|
|
91
|
+
|
|
66
92
|
mesh = adios4dolfinx.read_mesh(comm=comm, filename=path)
|
|
67
93
|
markers = adios4dolfinx.read_attributes(comm=comm, filename=path, name="markers")
|
|
68
|
-
|
|
94
|
+
tags = {}
|
|
95
|
+
for name, meshtag_name in (
|
|
96
|
+
("cfun", "Cell tags"),
|
|
97
|
+
("ffun", "Facet tags"),
|
|
98
|
+
("efun", "Edge tags"),
|
|
99
|
+
("vfun", "Vertex tags"),
|
|
100
|
+
):
|
|
101
|
+
try:
|
|
102
|
+
tags[name] = adios4dolfinx.read_meshtags(
|
|
103
|
+
mesh=mesh, meshtag_name=meshtag_name, filename=path
|
|
104
|
+
)
|
|
105
|
+
except KeyError:
|
|
106
|
+
tags[name] = None
|
|
107
|
+
|
|
108
|
+
functions = {}
|
|
69
109
|
function_space = adios4dolfinx.read_attributes(
|
|
70
110
|
comm=comm, filename=path, name="function_space"
|
|
71
111
|
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
112
|
+
for name, el in function_space.items():
|
|
113
|
+
element = utils.array2element(el)
|
|
114
|
+
V = dolfinx.fem.functionspace(mesh, element)
|
|
115
|
+
f = dolfinx.fem.Function(V, name=name)
|
|
116
|
+
try:
|
|
117
|
+
adios4dolfinx.read_function(u=f, filename=path, name=name)
|
|
118
|
+
except KeyError:
|
|
119
|
+
continue
|
|
120
|
+
else:
|
|
121
|
+
functions[name] = f
|
|
122
|
+
|
|
123
|
+
return cls(
|
|
124
|
+
mesh=mesh,
|
|
125
|
+
markers=markers,
|
|
126
|
+
**functions,
|
|
127
|
+
**tags,
|
|
128
|
+
)
|
|
83
129
|
|
|
84
130
|
@classmethod
|
|
85
131
|
def from_folder(cls, comm: MPI.Intracomm, folder: str | Path) -> "Geometry":
|
|
@@ -87,7 +133,7 @@ class Geometry:
|
|
|
87
133
|
|
|
88
134
|
# Read mesh
|
|
89
135
|
if (folder / "mesh.xdmf").exists():
|
|
90
|
-
mesh,
|
|
136
|
+
mesh, tags = utils.read_mesh(comm=comm, filename=folder / "mesh.xdmf")
|
|
91
137
|
else:
|
|
92
138
|
raise ValueError("No mesh file found")
|
|
93
139
|
|
|
@@ -101,22 +147,26 @@ class Geometry:
|
|
|
101
147
|
else:
|
|
102
148
|
markers = {}
|
|
103
149
|
|
|
150
|
+
functions = {}
|
|
104
151
|
microstructure_path = folder / "microstructure.bp"
|
|
105
152
|
if microstructure_path.exists():
|
|
106
153
|
function_space = adios4dolfinx.read_attributes(
|
|
107
154
|
comm=MPI.COMM_WORLD, filename=microstructure_path, name="function_space"
|
|
108
155
|
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
156
|
+
for name, el in function_space.items():
|
|
157
|
+
element = utils.array2element(el)
|
|
158
|
+
V = dolfinx.fem.functionspace(mesh, element)
|
|
159
|
+
f = dolfinx.fem.Function(V, name=name)
|
|
160
|
+
try:
|
|
161
|
+
adios4dolfinx.read_function(u=f, filename=microstructure_path, name=name)
|
|
162
|
+
except KeyError:
|
|
163
|
+
continue
|
|
164
|
+
else:
|
|
165
|
+
functions[name] = f
|
|
166
|
+
|
|
167
|
+
return cls(
|
|
168
|
+
mesh=mesh,
|
|
169
|
+
markers=markers,
|
|
170
|
+
**functions,
|
|
171
|
+
**tags,
|
|
172
|
+
)
|
cardiac_geometries/mesh.py
CHANGED
|
@@ -40,8 +40,8 @@ def biv_ellipsoid(
|
|
|
40
40
|
b_epi_rv: float = 2.5,
|
|
41
41
|
c_epi_rv: float = 2.0,
|
|
42
42
|
create_fibers: bool = False,
|
|
43
|
-
fiber_angle_endo: float =
|
|
44
|
-
fiber_angle_epi: float =
|
|
43
|
+
fiber_angle_endo: float = 60,
|
|
44
|
+
fiber_angle_epi: float = -60,
|
|
45
45
|
fiber_space: str = "P_1",
|
|
46
46
|
verbose: bool = False,
|
|
47
47
|
) -> Geometry:
|
|
@@ -92,9 +92,9 @@ def biv_ellipsoid(
|
|
|
92
92
|
create_fibers : bool, optional
|
|
93
93
|
If True create analytic fibers, by default False
|
|
94
94
|
fiber_angle_endo : float, optional
|
|
95
|
-
Angle for the endocardium, by default
|
|
95
|
+
Angle for the endocardium, by default 60
|
|
96
96
|
fiber_angle_epi : float, optional
|
|
97
|
-
Angle for the epicardium, by default
|
|
97
|
+
Angle for the epicardium, by default -60
|
|
98
98
|
fiber_space : str, optional
|
|
99
99
|
Function space for fibers of the form family_degree, by default "P_1"
|
|
100
100
|
verbose : bool, optional
|
|
@@ -102,7 +102,7 @@ def biv_ellipsoid(
|
|
|
102
102
|
|
|
103
103
|
Returns
|
|
104
104
|
-------
|
|
105
|
-
Geometry
|
|
105
|
+
cardiac_geometries.geometry.Geometry
|
|
106
106
|
A Geometry with the mesh, markers, markers functions and fibers.
|
|
107
107
|
|
|
108
108
|
"""
|
|
@@ -178,7 +178,30 @@ def biv_ellipsoid(
|
|
|
178
178
|
json.dump(geometry.markers, f, default=utils.json_serial)
|
|
179
179
|
comm.barrier()
|
|
180
180
|
if create_fibers:
|
|
181
|
-
|
|
181
|
+
try:
|
|
182
|
+
import ldrb
|
|
183
|
+
except ImportError:
|
|
184
|
+
msg = (
|
|
185
|
+
"To create fibers you need to install the ldrb package "
|
|
186
|
+
"which you can install with pip install fenicsx-ldrb"
|
|
187
|
+
)
|
|
188
|
+
raise ImportError(msg)
|
|
189
|
+
|
|
190
|
+
system = ldrb.dolfinx_ldrb(
|
|
191
|
+
mesh=geometry.mesh,
|
|
192
|
+
ffun=geometry.ffun,
|
|
193
|
+
markers=geometry.markers,
|
|
194
|
+
alpha_endo_lv=fiber_angle_endo,
|
|
195
|
+
alpha_epi_lv=fiber_angle_epi,
|
|
196
|
+
beta_endo_lv=0,
|
|
197
|
+
beta_epi_lv=0,
|
|
198
|
+
fiber_space=fiber_space,
|
|
199
|
+
)
|
|
200
|
+
from .fibers.utils import save_microstructure
|
|
201
|
+
|
|
202
|
+
save_microstructure(
|
|
203
|
+
mesh=geometry.mesh, functions=(system.f0, system.s0, system.n0), outdir=outdir
|
|
204
|
+
)
|
|
182
205
|
# from .fibers._biv_ellipsoid import create_biv_fibers
|
|
183
206
|
|
|
184
207
|
# create_biv_fibers(
|
|
@@ -222,8 +245,8 @@ def biv_ellipsoid_torso(
|
|
|
222
245
|
b_epi_rv: float = 2.5,
|
|
223
246
|
c_epi_rv: float = 2.0,
|
|
224
247
|
create_fibers: bool = False,
|
|
225
|
-
fiber_angle_endo: float =
|
|
226
|
-
fiber_angle_epi: float =
|
|
248
|
+
fiber_angle_endo: float = 60,
|
|
249
|
+
fiber_angle_epi: float = -60,
|
|
227
250
|
fiber_space: str = "P_1",
|
|
228
251
|
verbose: bool = False,
|
|
229
252
|
) -> Geometry:
|
|
@@ -286,9 +309,9 @@ def biv_ellipsoid_torso(
|
|
|
286
309
|
create_fibers : bool, optional
|
|
287
310
|
If True create analytic fibers, by default False
|
|
288
311
|
fiber_angle_endo : float, optional
|
|
289
|
-
Angle for the endocardium, by default
|
|
312
|
+
Angle for the endocardium, by default 60
|
|
290
313
|
fiber_angle_epi : float, optional
|
|
291
|
-
Angle for the epicardium, by default
|
|
314
|
+
Angle for the epicardium, by default -60
|
|
292
315
|
fiber_space : str, optional
|
|
293
316
|
Function space for fibers of the form family_degree, by default "P_1"
|
|
294
317
|
verbose : bool, optional
|
|
@@ -296,7 +319,7 @@ def biv_ellipsoid_torso(
|
|
|
296
319
|
|
|
297
320
|
Returns
|
|
298
321
|
-------
|
|
299
|
-
Geometry
|
|
322
|
+
cardiac_geometries.geometry.Geometry
|
|
300
323
|
A Geometry with the mesh, markers, markers functions and fibers.
|
|
301
324
|
|
|
302
325
|
"""
|
|
@@ -417,8 +440,8 @@ def lv_ellipsoid(
|
|
|
417
440
|
mu_apex_epi: float = -math.pi,
|
|
418
441
|
mu_base_epi: float = -math.acos(5 / 20),
|
|
419
442
|
create_fibers: bool = False,
|
|
420
|
-
fiber_angle_endo: float =
|
|
421
|
-
fiber_angle_epi: float =
|
|
443
|
+
fiber_angle_endo: float = 60,
|
|
444
|
+
fiber_angle_epi: float = -60,
|
|
422
445
|
fiber_space: str = "P_1",
|
|
423
446
|
aha: bool = True,
|
|
424
447
|
verbose: bool = False,
|
|
@@ -450,9 +473,9 @@ def lv_ellipsoid(
|
|
|
450
473
|
create_fibers : bool, optional
|
|
451
474
|
If True create analytic fibers, by default False
|
|
452
475
|
fiber_angle_endo : float, optional
|
|
453
|
-
Angle for the endocardium, by default
|
|
476
|
+
Angle for the endocardium, by default 60
|
|
454
477
|
fiber_angle_epi : float, optional
|
|
455
|
-
Angle for the epicardium, by default
|
|
478
|
+
Angle for the epicardium, by default -60
|
|
456
479
|
fiber_space : str, optional
|
|
457
480
|
Function space for fibers of the form family_degree, by default "P_1"
|
|
458
481
|
aha : bool, optional
|
|
@@ -462,7 +485,7 @@ def lv_ellipsoid(
|
|
|
462
485
|
|
|
463
486
|
Returns
|
|
464
487
|
-------
|
|
465
|
-
Geometry
|
|
488
|
+
cardiac_geometries.geometry.Geometry
|
|
466
489
|
A Geometry with the mesh, markers, markers functions and fibers.
|
|
467
490
|
|
|
468
491
|
"""
|
|
@@ -569,8 +592,8 @@ def slab(
|
|
|
569
592
|
lz: float = 3.0,
|
|
570
593
|
dx: float = 1.0,
|
|
571
594
|
create_fibers: bool = True,
|
|
572
|
-
fiber_angle_endo: float =
|
|
573
|
-
fiber_angle_epi: float =
|
|
595
|
+
fiber_angle_endo: float = 60,
|
|
596
|
+
fiber_angle_epi: float = -60,
|
|
574
597
|
fiber_space: str = "P_1",
|
|
575
598
|
verbose: bool = False,
|
|
576
599
|
) -> Geometry:
|
|
@@ -591,9 +614,9 @@ def slab(
|
|
|
591
614
|
create_fibers : bool, optional
|
|
592
615
|
If True create analytic fibers, by default True
|
|
593
616
|
fiber_angle_endo : float, optional
|
|
594
|
-
Angle for the endocardium, by default
|
|
617
|
+
Angle for the endocardium, by default 60
|
|
595
618
|
fiber_angle_epi : float, optional
|
|
596
|
-
Angle for the epicardium, by default
|
|
619
|
+
Angle for the epicardium, by default -60
|
|
597
620
|
fiber_space : str, optional
|
|
598
621
|
Function space for fibers of the form family_degree, by default "P_1"
|
|
599
622
|
verbose : bool, optional
|
|
@@ -601,7 +624,7 @@ def slab(
|
|
|
601
624
|
|
|
602
625
|
Returns
|
|
603
626
|
-------
|
|
604
|
-
Geometry
|
|
627
|
+
cardiac_geometries.geometry.Geometry
|
|
605
628
|
A Geometry with the mesh, markers, markers functions and fibers.
|
|
606
629
|
|
|
607
630
|
"""
|
|
@@ -701,7 +724,7 @@ def slab_in_bath(
|
|
|
701
724
|
|
|
702
725
|
Returns
|
|
703
726
|
-------
|
|
704
|
-
Geometry
|
|
727
|
+
cardiac_geometries.geometry.Geometry
|
|
705
728
|
A Geometry with the mesh, markers, markers functions and fibers.
|
|
706
729
|
|
|
707
730
|
"""
|
cardiac_geometries/utils.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import tempfile
|
|
2
|
+
import typing
|
|
2
3
|
from enum import Enum
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Iterable, NamedTuple
|
|
@@ -13,6 +14,238 @@ from structlog import get_logger
|
|
|
13
14
|
logger = get_logger()
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
class GMshModel(NamedTuple):
|
|
18
|
+
mesh: dolfinx.mesh.Mesh
|
|
19
|
+
cell_tags: dolfinx.mesh.MeshTags
|
|
20
|
+
facet_tags: dolfinx.mesh.MeshTags
|
|
21
|
+
edge_tags: dolfinx.mesh.MeshTags
|
|
22
|
+
vertex_tags: dolfinx.mesh.MeshTags
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# copied from https://github.com/FEniCS/dolfinx/blob/main/python/dolfinx/io/gmshio.py
|
|
26
|
+
def model_to_mesh(
|
|
27
|
+
model,
|
|
28
|
+
comm: MPI.Comm,
|
|
29
|
+
rank: int,
|
|
30
|
+
gdim: int = 3,
|
|
31
|
+
partitioner: typing.Optional[
|
|
32
|
+
typing.Callable[
|
|
33
|
+
[MPI.Comm, int, int, dolfinx.cpp.graph.AdjacencyList_int32],
|
|
34
|
+
dolfinx.cpp.graph.AdjacencyList_int32,
|
|
35
|
+
]
|
|
36
|
+
] = None,
|
|
37
|
+
dtype=dolfinx.default_real_type,
|
|
38
|
+
) -> GMshModel:
|
|
39
|
+
"""Create a Mesh from a Gmsh model.
|
|
40
|
+
|
|
41
|
+
Creates a :class:`dolfinx.mesh.Mesh` from the physical entities of
|
|
42
|
+
the highest topological dimension in the Gmsh model. In parallel,
|
|
43
|
+
the gmsh model is processed on one MPI rank, and the
|
|
44
|
+
:class:`dolfinx.mesh.Mesh` is distributed across ranks.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
model: Gmsh model.
|
|
48
|
+
comm: MPI communicator to use for mesh creation.
|
|
49
|
+
rank: MPI rank that the Gmsh model is initialized on.
|
|
50
|
+
gdim: Geometrical dimension of the mesh.
|
|
51
|
+
partitioner: Function that computes the parallel
|
|
52
|
+
distribution of cells across MPI ranks.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
A tuple containing the :class:`dolfinx.mesh.Mesh` and
|
|
56
|
+
:class:`dolfinx.mesh.MeshTags` for cells, facets, edges and
|
|
57
|
+
vertices.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
Note:
|
|
61
|
+
For performance, this function should only be called once for
|
|
62
|
+
large problems. For re-use, it is recommended to save the mesh
|
|
63
|
+
and corresponding tags using :class:`dolfinxio.XDMFFile` after
|
|
64
|
+
creation for efficient access.
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
if comm.rank == rank:
|
|
68
|
+
assert model is not None, "Gmsh model is None on rank responsible for mesh creation."
|
|
69
|
+
# Get mesh geometry and mesh topology for each element
|
|
70
|
+
x = dolfinx.io.gmshio.extract_geometry(model)
|
|
71
|
+
topologies = dolfinx.io.gmshio.extract_topology_and_markers(model)
|
|
72
|
+
|
|
73
|
+
# Extract Gmsh cell id, dimension of cell and number of nodes to
|
|
74
|
+
# cell for each
|
|
75
|
+
num_cell_types = len(topologies.keys())
|
|
76
|
+
cell_information = dict()
|
|
77
|
+
cell_dimensions = np.zeros(num_cell_types, dtype=np.int32)
|
|
78
|
+
for i, element in enumerate(topologies.keys()):
|
|
79
|
+
_, dim, _, num_nodes, _, _ = model.mesh.getElementProperties(element)
|
|
80
|
+
cell_information[i] = {"id": element, "dim": dim, "num_nodes": num_nodes}
|
|
81
|
+
cell_dimensions[i] = dim
|
|
82
|
+
|
|
83
|
+
# Sort elements by ascending dimension
|
|
84
|
+
perm_sort = np.argsort(cell_dimensions)
|
|
85
|
+
|
|
86
|
+
# Broadcast cell type data and geometric dimension
|
|
87
|
+
cell_id = cell_information[perm_sort[-1]]["id"]
|
|
88
|
+
tdim = cell_information[perm_sort[-1]]["dim"]
|
|
89
|
+
num_nodes = cell_information[perm_sort[-1]]["num_nodes"]
|
|
90
|
+
cell_id, num_nodes = comm.bcast([cell_id, num_nodes], root=rank)
|
|
91
|
+
|
|
92
|
+
# Check for facet data and broadcast relevant info if True
|
|
93
|
+
has_facet_data = False
|
|
94
|
+
if tdim - 1 in cell_dimensions:
|
|
95
|
+
has_facet_data = True
|
|
96
|
+
has_edge_data = False
|
|
97
|
+
if tdim - 2 in cell_dimensions:
|
|
98
|
+
has_edge_data = True
|
|
99
|
+
has_vertex_data = False
|
|
100
|
+
if tdim - 3 in cell_dimensions:
|
|
101
|
+
has_vertex_data = True
|
|
102
|
+
|
|
103
|
+
has_facet_data = comm.bcast(has_facet_data, root=rank)
|
|
104
|
+
if has_facet_data:
|
|
105
|
+
num_facet_nodes = comm.bcast(cell_information[perm_sort[-2]]["num_nodes"], root=rank)
|
|
106
|
+
gmsh_facet_id = cell_information[perm_sort[-2]]["id"]
|
|
107
|
+
marked_facets = np.asarray(topologies[gmsh_facet_id]["topology"], dtype=np.int64)
|
|
108
|
+
facet_values = np.asarray(topologies[gmsh_facet_id]["cell_data"], dtype=np.int32)
|
|
109
|
+
|
|
110
|
+
has_edge_data = comm.bcast(has_edge_data, root=rank)
|
|
111
|
+
if has_edge_data:
|
|
112
|
+
num_edge_nodes = comm.bcast(cell_information[perm_sort[-3]]["num_nodes"], root=rank)
|
|
113
|
+
gmsh_edge_id = cell_information[perm_sort[-3]]["id"]
|
|
114
|
+
marked_edges = np.asarray(topologies[gmsh_edge_id]["topology"], dtype=np.int64)
|
|
115
|
+
edge_values = np.asarray(topologies[gmsh_edge_id]["cell_data"], dtype=np.int32)
|
|
116
|
+
|
|
117
|
+
has_vertex_data = comm.bcast(has_vertex_data, root=rank)
|
|
118
|
+
if has_vertex_data:
|
|
119
|
+
num_vertex_nodes = comm.bcast(cell_information[perm_sort[-4]]["num_nodes"], root=rank)
|
|
120
|
+
gmsh_vertex_id = cell_information[perm_sort[-4]]["id"]
|
|
121
|
+
marked_vertices = np.asarray(topologies[gmsh_vertex_id]["topology"], dtype=np.int64)
|
|
122
|
+
vertex_values = np.asarray(topologies[gmsh_vertex_id]["cell_data"], dtype=np.int32)
|
|
123
|
+
|
|
124
|
+
cells = np.asarray(topologies[cell_id]["topology"], dtype=np.int64)
|
|
125
|
+
cell_values = np.asarray(topologies[cell_id]["cell_data"], dtype=np.int32)
|
|
126
|
+
else:
|
|
127
|
+
cell_id, num_nodes = comm.bcast([None, None], root=rank)
|
|
128
|
+
cells, x = np.empty([0, num_nodes], dtype=np.int32), np.empty([0, gdim], dtype=dtype)
|
|
129
|
+
cell_values = np.empty((0,), dtype=np.int32)
|
|
130
|
+
|
|
131
|
+
has_facet_data = comm.bcast(None, root=rank)
|
|
132
|
+
if has_facet_data:
|
|
133
|
+
num_facet_nodes = comm.bcast(None, root=rank)
|
|
134
|
+
marked_facets = np.empty((0, num_facet_nodes), dtype=np.int32)
|
|
135
|
+
facet_values = np.empty((0,), dtype=np.int32)
|
|
136
|
+
|
|
137
|
+
has_edge_data = comm.bcast(None, root=rank)
|
|
138
|
+
if has_edge_data:
|
|
139
|
+
num_edge_nodes = comm.bcast(None, root=rank)
|
|
140
|
+
marked_edges = np.empty((0, num_edge_nodes), dtype=np.int32)
|
|
141
|
+
edge_values = np.empty((0,), dtype=np.int32)
|
|
142
|
+
|
|
143
|
+
has_vertex_data = comm.bcast(None, root=rank)
|
|
144
|
+
if has_vertex_data:
|
|
145
|
+
num_vertex_nodes = comm.bcast(None, root=rank)
|
|
146
|
+
marked_vertices = np.empty((0, num_vertex_nodes), dtype=np.int32)
|
|
147
|
+
vertex_values = np.empty((0,), dtype=np.int32)
|
|
148
|
+
|
|
149
|
+
# Create distributed mesh
|
|
150
|
+
ufl_domain = dolfinx.io.gmshio.ufl_mesh(cell_id, gdim, dtype=dtype)
|
|
151
|
+
gmsh_cell_perm = dolfinx.io.gmshio.cell_perm_array(
|
|
152
|
+
dolfinx.cpp.mesh.to_type(str(ufl_domain.ufl_cell())), num_nodes
|
|
153
|
+
)
|
|
154
|
+
cells = cells[:, gmsh_cell_perm].copy()
|
|
155
|
+
mesh = dolfinx.mesh.create_mesh(
|
|
156
|
+
comm, cells, x[:, :gdim].astype(dtype, copy=False), ufl_domain, partitioner
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Create MeshTags for cells
|
|
160
|
+
local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
|
|
161
|
+
mesh._cpp_object, mesh.topology.dim, cells, cell_values
|
|
162
|
+
)
|
|
163
|
+
mesh.topology.create_connectivity(mesh.topology.dim, 0)
|
|
164
|
+
adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
|
|
165
|
+
ct = dolfinx.mesh.meshtags_from_entities(
|
|
166
|
+
mesh, mesh.topology.dim, adj, local_values.astype(np.int32, copy=False)
|
|
167
|
+
)
|
|
168
|
+
ct.name = "Cell tags"
|
|
169
|
+
|
|
170
|
+
# Create MeshTags for facets
|
|
171
|
+
topology = mesh.topology
|
|
172
|
+
tdim = topology.dim
|
|
173
|
+
if has_facet_data:
|
|
174
|
+
# Permute facets from MSH to DOLFINx ordering
|
|
175
|
+
# FIXME: This does not work for prism meshes
|
|
176
|
+
if (
|
|
177
|
+
topology.cell_type == dolfinx.mesh.CellType.prism
|
|
178
|
+
or topology.cell_type == dolfinx.mesh.CellType.pyramid
|
|
179
|
+
):
|
|
180
|
+
raise RuntimeError(f"Unsupported cell type {topology.cell_type}")
|
|
181
|
+
|
|
182
|
+
facet_type = dolfinx.cpp.mesh.cell_entity_type(
|
|
183
|
+
dolfinx.cpp.mesh.to_type(str(ufl_domain.ufl_cell())), tdim - 1, 0
|
|
184
|
+
)
|
|
185
|
+
gmsh_facet_perm = dolfinx.io.gmshio.cell_perm_array(facet_type, num_facet_nodes)
|
|
186
|
+
marked_facets = marked_facets[:, gmsh_facet_perm]
|
|
187
|
+
|
|
188
|
+
local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
|
|
189
|
+
mesh._cpp_object, tdim - 1, marked_facets, facet_values
|
|
190
|
+
)
|
|
191
|
+
mesh.topology.create_connectivity(topology.dim - 1, tdim)
|
|
192
|
+
adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
|
|
193
|
+
ft = dolfinx.io.gmshio.meshtags_from_entities(
|
|
194
|
+
mesh, tdim - 1, adj, local_values.astype(np.int32, copy=False)
|
|
195
|
+
)
|
|
196
|
+
ft.name = "Facet tags"
|
|
197
|
+
else:
|
|
198
|
+
ft = dolfinx.mesh.meshtags(
|
|
199
|
+
mesh, tdim - 1, np.empty(0, dtype=np.int32), np.empty(0, dtype=np.int32)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if has_edge_data:
|
|
203
|
+
# Permute edges from MSH to DOLFINx ordering
|
|
204
|
+
edge_type = dolfinx.cpp.mesh.cell_entity_type(
|
|
205
|
+
dolfinx.cpp.mesh.to_type(str(ufl_domain.ufl_cell())), tdim - 2, 0
|
|
206
|
+
)
|
|
207
|
+
gmsh_edge_perm = dolfinx.io.gmshio.cell_perm_array(edge_type, num_edge_nodes)
|
|
208
|
+
marked_edges = marked_edges[:, gmsh_edge_perm]
|
|
209
|
+
|
|
210
|
+
local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
|
|
211
|
+
mesh._cpp_object, tdim - 2, marked_edges, edge_values
|
|
212
|
+
)
|
|
213
|
+
mesh.topology.create_connectivity(topology.dim - 2, tdim)
|
|
214
|
+
adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
|
|
215
|
+
et = dolfinx.io.gmshio.meshtags_from_entities(
|
|
216
|
+
mesh, tdim - 2, adj, local_values.astype(np.int32, copy=False)
|
|
217
|
+
)
|
|
218
|
+
et.name = "Edge tags"
|
|
219
|
+
else:
|
|
220
|
+
et = dolfinx.mesh.meshtags(
|
|
221
|
+
mesh, tdim - 2, np.empty(0, dtype=np.int32), np.empty(0, dtype=np.int32)
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
if has_vertex_data:
|
|
225
|
+
# Permute vertices from MSH to DOLFINx ordering
|
|
226
|
+
vertex_type = dolfinx.cpp.mesh.cell_entity_type(
|
|
227
|
+
dolfinx.cpp.mesh.to_type(str(ufl_domain.ufl_cell())), tdim - 3, 0
|
|
228
|
+
)
|
|
229
|
+
gmsh_vertex_perm = dolfinx.io.gmshio.cell_perm_array(vertex_type, num_vertex_nodes)
|
|
230
|
+
marked_vertices = marked_vertices[:, gmsh_vertex_perm]
|
|
231
|
+
|
|
232
|
+
local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
|
|
233
|
+
mesh._cpp_object, tdim - 3, marked_vertices, vertex_values
|
|
234
|
+
)
|
|
235
|
+
mesh.topology.create_connectivity(topology.dim - 3, tdim)
|
|
236
|
+
adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
|
|
237
|
+
vt = dolfinx.io.gmshio.meshtags_from_entities(
|
|
238
|
+
mesh, tdim - 3, adj, local_values.astype(np.int32, copy=False)
|
|
239
|
+
)
|
|
240
|
+
vt.name = "Vertex tags"
|
|
241
|
+
else:
|
|
242
|
+
vt = dolfinx.mesh.meshtags(
|
|
243
|
+
mesh, tdim - 3, np.empty(0, dtype=np.int32), np.empty(0, dtype=np.int32)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
return GMshModel(mesh, ct, ft, et, vt)
|
|
247
|
+
|
|
248
|
+
|
|
16
249
|
def element2array(el: basix.finite_element.FiniteElement) -> np.ndarray:
|
|
17
250
|
return np.array(
|
|
18
251
|
[int(el.family), int(el.cell_type), int(el.degree), int(el.discontinuous)],
|
|
@@ -69,13 +302,23 @@ class GMshGeometry(NamedTuple):
|
|
|
69
302
|
|
|
70
303
|
def read_mesh(
|
|
71
304
|
comm, filename: str | Path
|
|
72
|
-
) -> tuple[dolfinx.mesh.Mesh,
|
|
305
|
+
) -> tuple[dolfinx.mesh.Mesh, dict[str, dolfinx.mesh.MeshTags]]:
|
|
306
|
+
tags = {}
|
|
73
307
|
with dolfinx.io.XDMFFile(comm, filename, "r") as xdmf:
|
|
74
308
|
mesh = xdmf.read_mesh(name="Mesh")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
309
|
+
for var, name, dim in [
|
|
310
|
+
("cfun", "Cell tags", mesh.topology.dim),
|
|
311
|
+
("ffun", "Facet tags", mesh.topology.dim - 1),
|
|
312
|
+
("efun", "Edge tags", mesh.topology.dim - 2),
|
|
313
|
+
("vfun", "Vertex tags", mesh.topology.dim - 3),
|
|
314
|
+
]:
|
|
315
|
+
mesh.topology.create_connectivity(dim, mesh.topology.dim)
|
|
316
|
+
try:
|
|
317
|
+
tags[var] = xdmf.read_meshtags(mesh, name=name)
|
|
318
|
+
except RuntimeError:
|
|
319
|
+
continue
|
|
320
|
+
|
|
321
|
+
return mesh, tags
|
|
79
322
|
|
|
80
323
|
|
|
81
324
|
def gmsh2dolfin(comm: MPI.Intracomm, msh_file, rank: int = 0) -> GMshGeometry:
|
|
@@ -90,33 +333,40 @@ def gmsh2dolfin(comm: MPI.Intracomm, msh_file, rank: int = 0) -> GMshGeometry:
|
|
|
90
333
|
gmsh.initialize()
|
|
91
334
|
gmsh.model.add("Mesh from file")
|
|
92
335
|
gmsh.merge(str(msh_file))
|
|
93
|
-
mesh, ct, ft =
|
|
336
|
+
mesh, ct, ft, et, vt = model_to_mesh(gmsh.model, comm, 0)
|
|
94
337
|
markers = {
|
|
95
338
|
gmsh.model.getPhysicalName(*v): tuple(reversed(v))
|
|
96
339
|
for v in gmsh.model.getPhysicalGroups()
|
|
97
340
|
}
|
|
98
341
|
gmsh.finalize()
|
|
99
342
|
else:
|
|
100
|
-
mesh, ct, ft =
|
|
343
|
+
mesh, ct, ft, et, vt = model_to_mesh(gmsh.model, comm, 0)
|
|
101
344
|
markers = {}
|
|
102
345
|
mesh.name = "Mesh"
|
|
103
346
|
ct.name = "Cell tags"
|
|
104
347
|
ft.name = "Facet tags"
|
|
348
|
+
et.name = "Edge tags"
|
|
349
|
+
vt.name = "Vertex tags"
|
|
105
350
|
|
|
106
351
|
markers = comm.bcast(markers, root=rank)
|
|
107
352
|
|
|
108
353
|
# Save tags to xdmf
|
|
109
354
|
with dolfinx.io.XDMFFile(comm, outdir / "mesh.xdmf", "w") as xdmf:
|
|
110
355
|
xdmf.write_mesh(mesh)
|
|
111
|
-
mesh.topology.create_connectivity(2, 3)
|
|
112
356
|
xdmf.write_meshtags(
|
|
113
357
|
ct, mesh.geometry, geometry_xpath=f"/Xdmf/Domain/Grid[@Name='{mesh.name}']/Geometry"
|
|
114
358
|
)
|
|
359
|
+
mesh.topology.create_connectivity(2, 3)
|
|
115
360
|
xdmf.write_meshtags(
|
|
116
361
|
ft, mesh.geometry, geometry_xpath=f"/Xdmf/Domain/Grid[@Name='{mesh.name}']/Geometry"
|
|
117
362
|
)
|
|
363
|
+
mesh.topology.create_connectivity(1, 3)
|
|
364
|
+
xdmf.write_meshtags(
|
|
365
|
+
et, mesh.geometry, geometry_xpath=f"/Xdmf/Domain/Grid[@Name='{mesh.name}']/Geometry"
|
|
366
|
+
)
|
|
367
|
+
mesh.topology.create_connectivity(0, 3)
|
|
368
|
+
xdmf.write_meshtags(
|
|
369
|
+
vt, mesh.geometry, geometry_xpath=f"/Xdmf/Domain/Grid[@Name='{mesh.name}']/Geometry"
|
|
370
|
+
)
|
|
118
371
|
|
|
119
|
-
|
|
120
|
-
efun = None
|
|
121
|
-
|
|
122
|
-
return GMshGeometry(mesh, ct, ft, efun, vfun, markers)
|
|
372
|
+
return GMshGeometry(mesh, ct, ft, et, vt, markers)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Computational Physiology at Simula Research Laboratory
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cardiac-geometriesx
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A python library for cardiac geometries
|
|
5
|
+
Author-email: Henrik Finsberg <henriknf@simula.no>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/finsberg/cardiac-geometriesx
|
|
8
|
+
Keywords: cardiac,geometry
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: fenics-dolfinx >=0.8.0
|
|
16
|
+
Requires-Dist: structlog
|
|
17
|
+
Requires-Dist: cardiac-geometries-core
|
|
18
|
+
Requires-Dist: rich-click
|
|
19
|
+
Requires-Dist: adios4dolfinx
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: bump-my-version ; extra == 'dev'
|
|
22
|
+
Requires-Dist: ipython ; extra == 'dev'
|
|
23
|
+
Requires-Dist: pdbpp ; extra == 'dev'
|
|
24
|
+
Requires-Dist: pre-commit ; extra == 'dev'
|
|
25
|
+
Requires-Dist: twine ; extra == 'dev'
|
|
26
|
+
Requires-Dist: wheel ; extra == 'dev'
|
|
27
|
+
Provides-Extra: docs
|
|
28
|
+
Requires-Dist: jupyter-book ; extra == 'docs'
|
|
29
|
+
Requires-Dist: jupytext ; extra == 'docs'
|
|
30
|
+
Requires-Dist: jupyter ; extra == 'docs'
|
|
31
|
+
Requires-Dist: pyvista[all] >=0.43.0 ; extra == 'docs'
|
|
32
|
+
Requires-Dist: trame-vuetify ; extra == 'docs'
|
|
33
|
+
Requires-Dist: ipywidgets ; extra == 'docs'
|
|
34
|
+
Requires-Dist: fenicsx-ldrb ; extra == 'docs'
|
|
35
|
+
Provides-Extra: test
|
|
36
|
+
Requires-Dist: pre-commit ; extra == 'test'
|
|
37
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
38
|
+
Requires-Dist: pytest-cov ; extra == 'test'
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
[](https://github.com/ComputationalPhysiology/cardiac-geometriesx/actions/workflows/docker-image.yml)
|
|
43
|
+
[](https://github.com/ComputationalPhysiology/cardiac-geometriesx/actions/workflows/test.yml)
|
|
44
|
+
[](https://github.com/ComputationalPhysiology/cardiac-geometriesx/actions/workflows/test-mpi.yml)
|
|
45
|
+
[](https://github.com/ComputationalPhysiology/cardiac-geometriesx/actions/workflows/pre-commit.yml)
|
|
46
|
+
[](https://badge.fury.io/py/cardiac-geometriesx)
|
|
47
|
+
|
|
48
|
+
# Cardiac geometries
|
|
49
|
+
|
|
50
|
+
Cardiac geometries is a software package built on top of [`cariac-geometries-core`](https://github.com/ComputationalPhysiology/cardiac-geometries-core) that adds support for creating idealized cardiac geometries for dolfinx.
|
|
51
|
+
|
|
52
|
+
There are two ways you can use `cardiac-geomtries`, either using the command line interface, e.g
|
|
53
|
+
```
|
|
54
|
+
geox lv-ellipsoid --create-fibers lv-mesh --fiber-space P_2
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
or using the python API e.g
|
|
58
|
+
```python
|
|
59
|
+
geo = cardiac_geometries.mesh.lv_ellipsoid(outdir="lv-mesh", create_fibers=True, fiber_space="P_2")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
To install the package you can use `pip`
|
|
65
|
+
```
|
|
66
|
+
python3 -m pip install cardiac-geometriesx
|
|
67
|
+
```
|
|
68
|
+
however, this assumes that you already have `dolfinx` pre-installed. You can also use the provided docker image e.g
|
|
69
|
+
```
|
|
70
|
+
docker pull ghcr.io/computationalphysiology/cardiac-geometriesx:latest
|
|
71
|
+
```
|
|
72
|
+
To start a new container interactive you can do
|
|
73
|
+
```
|
|
74
|
+
docker run --name geox -v $PWD:/home/shared -w /home/shared -it ghcr.io/computationalphysiology/cardiac-geometriesx:latest
|
|
75
|
+
```
|
|
76
|
+
or if you just want to create a mesh and exit you can run the command line interface directly e.g
|
|
77
|
+
```
|
|
78
|
+
docker run --rm -v $PWD:/home/shared -w /home/shared -it ghcr.io/computationalphysiology/cardiac-geometriesx:latest geox lv-ellipsoid --create-fibers lv-mesh --fiber-space P_2
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Authors
|
|
82
|
+
Henrik Finsberg (henriknf@simula.no)
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
MIT
|
|
86
|
+
|
|
87
|
+
## Contributing
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
|
|
2
|
+
cardiac_geometries/cli.py,sha256=hOv1muw33MY1GedXnIR1xvh488lWIzRDq29LajK6PY0,19394
|
|
3
|
+
cardiac_geometries/geometry.py,sha256=UWOasa3l7BM1tdr3au5Bu0hPnOe1TyoP8KMMrwtJjyM,5650
|
|
4
|
+
cardiac_geometries/mesh.py,sha256=JSm69BTS7WRUldwaQ9-Gnjq_KbX66FTnl2ouFKRtFhA,26825
|
|
5
|
+
cardiac_geometries/utils.py,sha256=vO9Ov385JBfODH-3exVVgK9xKvAoNLThi_QyiM2w7iE,14312
|
|
6
|
+
cardiac_geometries/fibers/__init__.py,sha256=WpRrn9Iakl-3m8IGtFkqP0LXGjw5EZHZ8Eg9JCnCdrg,137
|
|
7
|
+
cardiac_geometries/fibers/lv_ellipsoid.py,sha256=jdRek3v_V2a9IQHqH7P-lK0JBwa1dUNpBBmABzKGje4,3690
|
|
8
|
+
cardiac_geometries/fibers/slab.py,sha256=h_iVs_e1F9LJaXJOzam336f0LcTAXXBvApsFZGZSnZs,3861
|
|
9
|
+
cardiac_geometries/fibers/utils.py,sha256=hMTAKy32ow10tpNE1-WuvCYk7PVXO1qL0dHPa3LjecQ,2434
|
|
10
|
+
cardiac_geometriesx-0.1.3.dist-info/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
|
|
11
|
+
cardiac_geometriesx-0.1.3.dist-info/METADATA,sha256=M9ntsIWoEz5VILHZa2nWKMDjvdM25_7QsV9kvvFDFWI,3871
|
|
12
|
+
cardiac_geometriesx-0.1.3.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
13
|
+
cardiac_geometriesx-0.1.3.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
|
|
14
|
+
cardiac_geometriesx-0.1.3.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
|
|
15
|
+
cardiac_geometriesx-0.1.3.dist-info/RECORD,,
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: cardiac-geometriesx
|
|
3
|
-
Version: 0.1.1
|
|
4
|
-
Summary: A python library for cardiac geometries
|
|
5
|
-
Author-email: Henrik Finsberg <henriknf@simula.no>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/finsberg/cardiac-geometriesx
|
|
8
|
-
Keywords: cardiac,geometry
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
-
Requires-Python: >=3.8
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
Requires-Dist: fenics-dolfinx >=0.8.0
|
|
15
|
-
Requires-Dist: structlog
|
|
16
|
-
Requires-Dist: cardiac-geometries-core
|
|
17
|
-
Requires-Dist: rich-click
|
|
18
|
-
Requires-Dist: adios4dolfinx
|
|
19
|
-
Provides-Extra: dev
|
|
20
|
-
Requires-Dist: bump-my-version ; extra == 'dev'
|
|
21
|
-
Requires-Dist: ipython ; extra == 'dev'
|
|
22
|
-
Requires-Dist: pdbpp ; extra == 'dev'
|
|
23
|
-
Requires-Dist: pre-commit ; extra == 'dev'
|
|
24
|
-
Requires-Dist: twine ; extra == 'dev'
|
|
25
|
-
Requires-Dist: wheel ; extra == 'dev'
|
|
26
|
-
Provides-Extra: docs
|
|
27
|
-
Provides-Extra: test
|
|
28
|
-
Requires-Dist: pre-commit ; extra == 'test'
|
|
29
|
-
Requires-Dist: pytest ; extra == 'test'
|
|
30
|
-
Requires-Dist: pytest-cov ; extra == 'test'
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Cardiac geometries
|
|
34
|
-
|
|
35
|
-
Cardiac geometries for `dolfinx` (targeting v0.8).
|
|
36
|
-
|
|
37
|
-
Install
|
|
38
|
-
```
|
|
39
|
-
python3 -m pip install cardiac-geometriesx
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Example usage
|
|
43
|
-
```
|
|
44
|
-
geox lv-ellipsoid --create-fibers lv-mesh
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Authors
|
|
48
|
-
Henrik Finsberg (henriknf@simula.no)
|
|
49
|
-
|
|
50
|
-
## License
|
|
51
|
-
MIT
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
|
|
2
|
-
cardiac_geometries/cli.py,sha256=2-99xmcBltdotzxp4aDZLrh46gyA5U_PZc6lHen7LIM,19323
|
|
3
|
-
cardiac_geometries/geometry.py,sha256=rhtq219q06ta1ZS_WIyqfjr00rN1L099bfX_Fwhe29g,4656
|
|
4
|
-
cardiac_geometries/mesh.py,sha256=cJAcwdDaYmO8MlfocaxvV6pkBcfEWybMSBAaycr6q3s,25987
|
|
5
|
-
cardiac_geometries/utils.py,sha256=-fH13vimCYrirDZubQdxRpX-7I9iCFsOJ8Xo1NL5Nvc,3596
|
|
6
|
-
cardiac_geometries/fibers/__init__.py,sha256=WpRrn9Iakl-3m8IGtFkqP0LXGjw5EZHZ8Eg9JCnCdrg,137
|
|
7
|
-
cardiac_geometries/fibers/lv_ellipsoid.py,sha256=zcCTcst08-xcG5c2j8rPLFp0cgNjXt1Q0mVGhs5r5Ps,3695
|
|
8
|
-
cardiac_geometries/fibers/slab.py,sha256=-EWG4cHjtFYo4VyoFfVnsbHhfdf8qKWphYimJ1jB56o,3867
|
|
9
|
-
cardiac_geometries/fibers/utils.py,sha256=K_C_G1az_SnwBAeKvvvZN4V4M_6z0DAAqOsV7M3T5aI,2428
|
|
10
|
-
cardiac_geometriesx-0.1.1.dist-info/METADATA,sha256=w_cEg_5ZBV2Ptl9OxH2VN4Psll0wjlLU0WTR4GIaB8o,1349
|
|
11
|
-
cardiac_geometriesx-0.1.1.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
|
|
12
|
-
cardiac_geometriesx-0.1.1.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
|
|
13
|
-
cardiac_geometriesx-0.1.1.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
|
|
14
|
-
cardiac_geometriesx-0.1.1.dist-info/RECORD,,
|
{cardiac_geometriesx-0.1.1.dist-info → cardiac_geometriesx-0.1.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|