cardiac-geometriesx 0.0.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/__init__.py +8 -0
- cardiac_geometries/cli.py +875 -0
- cardiac_geometries/fibers/__init__.py +6 -0
- cardiac_geometries/fibers/lv_ellipsoid.py +150 -0
- cardiac_geometries/fibers/slab.py +150 -0
- cardiac_geometries/fibers/utils.py +84 -0
- cardiac_geometries/geometry.py +126 -0
- cardiac_geometries/mesh.py +727 -0
- cardiac_geometries/utils.py +173 -0
- cardiac_geometriesx-0.0.1.dist-info/METADATA +52 -0
- cardiac_geometriesx-0.0.1.dist-info/RECORD +14 -0
- cardiac_geometriesx-0.0.1.dist-info/WHEEL +5 -0
- cardiac_geometriesx-0.0.1.dist-info/entry_points.txt +2 -0
- cardiac_geometriesx-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import tempfile
|
|
3
|
+
from typing import NamedTuple, Iterable
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from mpi4py import MPI
|
|
8
|
+
from structlog import get_logger
|
|
9
|
+
import basix
|
|
10
|
+
import dolfinx
|
|
11
|
+
import meshio
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
logger = get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def element2array(el: basix.finite_element.FiniteElement) -> np.ndarray:
|
|
18
|
+
return np.array(
|
|
19
|
+
[int(el.family), int(el.cell_type), int(el.degree), int(el.discontinuous)],
|
|
20
|
+
dtype=np.uint8,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def number2Enum(num: int, enum: Iterable) -> Enum:
|
|
25
|
+
for e in enum:
|
|
26
|
+
if int(e) == num:
|
|
27
|
+
return e
|
|
28
|
+
raise ValueError(f"Invalid value {num} for enum {enum}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def array2element(arr: np.ndarray) -> basix.finite_element.FiniteElement:
|
|
32
|
+
family = number2Enum(arr[0], basix.ElementFamily)
|
|
33
|
+
cell_type = number2Enum(arr[1], basix.CellType)
|
|
34
|
+
degree = int(arr[2])
|
|
35
|
+
discontinuous = bool(arr[3])
|
|
36
|
+
# TODO: Shape is hardcoded to (3,) for now, but this should also be stored
|
|
37
|
+
return basix.ufl.element(
|
|
38
|
+
family=family,
|
|
39
|
+
cell=cell_type,
|
|
40
|
+
degree=degree,
|
|
41
|
+
discontinuous=discontinuous,
|
|
42
|
+
shape=(3,),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def handle_mesh_name(mesh_name: str = "") -> Path:
|
|
47
|
+
if mesh_name == "":
|
|
48
|
+
fd, mesh_name = tempfile.mkstemp(suffix=".msh")
|
|
49
|
+
return Path(mesh_name).with_suffix(".msh")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def json_serial(obj):
|
|
53
|
+
if isinstance(obj, (np.ndarray)):
|
|
54
|
+
return obj.tolist()
|
|
55
|
+
else:
|
|
56
|
+
try:
|
|
57
|
+
return str(obj)
|
|
58
|
+
except Exception:
|
|
59
|
+
raise TypeError("Type %s not serializable" % type(obj))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class GMshGeometry(NamedTuple):
|
|
63
|
+
mesh: dolfinx.mesh.Mesh
|
|
64
|
+
cfun: dolfinx.mesh.MeshTags | None
|
|
65
|
+
ffun: dolfinx.mesh.MeshTags | None
|
|
66
|
+
efun: dolfinx.mesh.MeshTags | None
|
|
67
|
+
vfun: dolfinx.mesh.MeshTags | None
|
|
68
|
+
markers: dict[str, tuple[int, int]]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def create_mesh(mesh, cell_type):
|
|
72
|
+
# From http://jsdokken.com/converted_files/tutorial_pygmsh.html
|
|
73
|
+
cells = mesh.get_cells_type(cell_type)
|
|
74
|
+
if cells.size == 0:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
cells = mesh.get_cells_type(cell_type)
|
|
78
|
+
cell_data = mesh.get_cell_data("gmsh:physical", cell_type)
|
|
79
|
+
out_mesh = meshio.Mesh(
|
|
80
|
+
points=mesh.points,
|
|
81
|
+
cells={cell_type: cells},
|
|
82
|
+
cell_data={"name_to_read": [cell_data]},
|
|
83
|
+
)
|
|
84
|
+
return out_mesh
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def read_ffun(mesh, filename: str | Path) -> dolfinx.mesh.MeshTags | None:
|
|
88
|
+
mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim)
|
|
89
|
+
with dolfinx.io.XDMFFile(mesh.comm, filename, "r") as xdmf:
|
|
90
|
+
ffun = xdmf.read_meshtags(mesh, name="Grid")
|
|
91
|
+
ffun.name = "Facet tags"
|
|
92
|
+
return ffun
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def read_mesh(comm, filename: str | Path) -> tuple[dolfinx.mesh.Mesh, dolfinx.mesh.MeshTags | None]:
|
|
96
|
+
with dolfinx.io.XDMFFile(comm, filename, "r") as xdmf:
|
|
97
|
+
mesh = xdmf.read_mesh(name="Grid")
|
|
98
|
+
cfun = xdmf.read_meshtags(mesh, name="Grid")
|
|
99
|
+
return mesh, cfun
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def gmsh2dolfin(comm: MPI.Intracomm, msh_file, unlink: bool = False) -> GMshGeometry:
|
|
103
|
+
logger.debug(f"Convert file {msh_file} to dolfin")
|
|
104
|
+
outdir = Path(msh_file).parent
|
|
105
|
+
|
|
106
|
+
vertex_mesh_name = outdir / "vertex_mesh.xdmf"
|
|
107
|
+
line_mesh_name = outdir / "line_mesh.xdmf"
|
|
108
|
+
triangle_mesh_name = outdir / "triangle_mesh.xdmf"
|
|
109
|
+
tetra_mesh_name = outdir / "mesh.xdmf"
|
|
110
|
+
|
|
111
|
+
if comm.rank == 0:
|
|
112
|
+
msh = meshio.gmsh.read(msh_file)
|
|
113
|
+
vertex_mesh = create_mesh(msh, "vertex")
|
|
114
|
+
line_mesh = create_mesh(msh, "line")
|
|
115
|
+
triangle_mesh = create_mesh(msh, "triangle")
|
|
116
|
+
tetra_mesh = create_mesh(msh, "tetra")
|
|
117
|
+
|
|
118
|
+
if vertex_mesh is not None:
|
|
119
|
+
meshio.write(vertex_mesh_name, vertex_mesh)
|
|
120
|
+
|
|
121
|
+
if line_mesh is not None:
|
|
122
|
+
meshio.write(line_mesh_name, line_mesh)
|
|
123
|
+
|
|
124
|
+
if triangle_mesh is not None:
|
|
125
|
+
meshio.write(triangle_mesh_name, triangle_mesh)
|
|
126
|
+
|
|
127
|
+
if tetra_mesh is not None:
|
|
128
|
+
meshio.write(
|
|
129
|
+
tetra_mesh_name,
|
|
130
|
+
tetra_mesh,
|
|
131
|
+
)
|
|
132
|
+
markers = msh.field_data
|
|
133
|
+
else:
|
|
134
|
+
markers = {}
|
|
135
|
+
# Broadcast markers
|
|
136
|
+
markers = comm.bcast(markers, root=0)
|
|
137
|
+
comm.barrier()
|
|
138
|
+
|
|
139
|
+
mesh, cfun = read_mesh(comm, tetra_mesh_name)
|
|
140
|
+
|
|
141
|
+
if triangle_mesh_name.is_file():
|
|
142
|
+
ffun = read_ffun(mesh, triangle_mesh_name)
|
|
143
|
+
else:
|
|
144
|
+
ffun = None
|
|
145
|
+
|
|
146
|
+
if line_mesh_name.is_file():
|
|
147
|
+
mesh.topology.create_connectivity(mesh.topology.dim - 2, mesh.topology.dim)
|
|
148
|
+
with dolfinx.io.XDMFFile(comm, line_mesh_name, "r") as xdmf:
|
|
149
|
+
efun = xdmf.read_meshtags(mesh, name="Grid")
|
|
150
|
+
else:
|
|
151
|
+
efun = None
|
|
152
|
+
|
|
153
|
+
if vertex_mesh_name.is_file():
|
|
154
|
+
mesh.topology.create_connectivity(mesh.topology.dim - 3, mesh.topology.dim)
|
|
155
|
+
with dolfinx.io.XDMFFile(comm, vertex_mesh_name, "r") as xdmf:
|
|
156
|
+
vfun = xdmf.read_meshtags(mesh, name="Grid")
|
|
157
|
+
else:
|
|
158
|
+
vfun = None
|
|
159
|
+
|
|
160
|
+
if unlink:
|
|
161
|
+
# Wait for all processes to finish reading
|
|
162
|
+
comm.barrier()
|
|
163
|
+
if comm.rank == 0:
|
|
164
|
+
vertex_mesh_name.unlink(missing_ok=True)
|
|
165
|
+
line_mesh_name.unlink(missing_ok=True)
|
|
166
|
+
triangle_mesh_name.unlink(missing_ok=True)
|
|
167
|
+
tetra_mesh_name.unlink(missing_ok=True)
|
|
168
|
+
vertex_mesh_name.with_suffix(".h5").unlink(missing_ok=True)
|
|
169
|
+
line_mesh_name.with_suffix(".h5").unlink(missing_ok=True)
|
|
170
|
+
triangle_mesh_name.with_suffix(".h5").unlink(missing_ok=True)
|
|
171
|
+
tetra_mesh_name.with_suffix(".h5").unlink(missing_ok=True)
|
|
172
|
+
|
|
173
|
+
return GMshGeometry(mesh, cfun, ffun, efun, vfun, markers)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cardiac-geometriesx
|
|
3
|
+
Version: 0.0.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: meshio
|
|
16
|
+
Requires-Dist: h5py
|
|
17
|
+
Requires-Dist: structlog
|
|
18
|
+
Requires-Dist: cardiac-geometries-core
|
|
19
|
+
Requires-Dist: rich-click
|
|
20
|
+
Requires-Dist: adios4dolfinx
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: bump-my-version ; extra == 'dev'
|
|
23
|
+
Requires-Dist: ipython ; extra == 'dev'
|
|
24
|
+
Requires-Dist: pdbpp ; extra == 'dev'
|
|
25
|
+
Requires-Dist: pre-commit ; extra == 'dev'
|
|
26
|
+
Requires-Dist: twine ; extra == 'dev'
|
|
27
|
+
Requires-Dist: wheel ; extra == 'dev'
|
|
28
|
+
Provides-Extra: docs
|
|
29
|
+
Provides-Extra: test
|
|
30
|
+
Requires-Dist: pre-commit ; extra == 'test'
|
|
31
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
32
|
+
Requires-Dist: pytest-cov ; extra == 'test'
|
|
33
|
+
|
|
34
|
+
# Cardiac geometries
|
|
35
|
+
|
|
36
|
+
Cardiac geometries for `dolfinx` (targeting v0.8).
|
|
37
|
+
|
|
38
|
+
Install
|
|
39
|
+
```
|
|
40
|
+
python3 -m pip install git+https://github.com/ComputationalPhysiology/cardiac-geometriesx
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Example usage
|
|
44
|
+
```
|
|
45
|
+
geox lv-ellipsoid --create-fibers lv-mesh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Authors
|
|
49
|
+
Henrik Finsberg (henriknf@simula.no)
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
cardiac_geometries/__init__.py,sha256=-I-0nXbVFRgfZ-mbXeC-OMg2jh7WnTch6_DkBbAGnGg,202
|
|
2
|
+
cardiac_geometries/cli.py,sha256=nOI56WV1fXstL3vxhux90qPnmZ69y1r-PGDYgFMgNeA,19324
|
|
3
|
+
cardiac_geometries/geometry.py,sha256=MYF9diZl9igayAuptSyOsHf7-3zJHFd8UgfWtXJgrHk,4849
|
|
4
|
+
cardiac_geometries/mesh.py,sha256=K-EEJcJNgxubnLnMkPrysnKfNe7HCfLf26lxI1lCosA,25250
|
|
5
|
+
cardiac_geometries/utils.py,sha256=cg42PP56UIVoDyur0lp6nJ3dAuZiHQB9kvYShKti1Bk,5452
|
|
6
|
+
cardiac_geometries/fibers/__init__.py,sha256=p6d-3uql8pFailBcLPPGLfRDQs38wefnarS3aSQV0FE,151
|
|
7
|
+
cardiac_geometries/fibers/lv_ellipsoid.py,sha256=DWDUV0sGrsZH9O-EtN3veSkE96U6XuHko3WUW9Ce_uc,3695
|
|
8
|
+
cardiac_geometries/fibers/slab.py,sha256=sY9VXv-J1D2wSPTcB_6opRmGMLqUXb5ix7C3gJlSJOU,3867
|
|
9
|
+
cardiac_geometries/fibers/utils.py,sha256=iozqorgu2KcxbzR52b2Not2IyJ-DrPyqn2Ds-QX2QLE,2584
|
|
10
|
+
cardiac_geometriesx-0.0.1.dist-info/METADATA,sha256=MNi78FcH9sKYLiDVgW9J_y-A45MJ-XxMxNKv1iQaHlA,1437
|
|
11
|
+
cardiac_geometriesx-0.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
12
|
+
cardiac_geometriesx-0.0.1.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
|
|
13
|
+
cardiac_geometriesx-0.0.1.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
|
|
14
|
+
cardiac_geometriesx-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cardiac_geometries
|