Skip to content

Commit 849d664

Browse files
committed
Change logic for converting mesh from wildmeshing to dolfinx - extract facets on the interface rather than using the data from tracked surfaces coming from wildmeshinh
1 parent b4f0e1e commit 849d664

File tree

2 files changed

+112
-49
lines changed

2 files changed

+112
-49
lines changed

src/mri2mesh/mesh/__init__.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def add_mesh_parser(parser: argparse.ArgumentParser) -> None:
2727

2828
convert_parser = subparsers.add_parser("convert", help="Convert mesh to dolfinx")
2929
convert_parser.add_argument("mesh_dir", type=Path, help="Directory containing mesh files")
30+
convert_parser.add_argument(
31+
"--extract-facet-tags", action="store_true", help="Extract facet tags"
32+
)
33+
convert_parser.add_argument("--extract-submesh", action="store_true", help="Extract submesh")
3034

3135
idealized_parser = subparsers.add_parser(
3236
"idealized",
@@ -41,12 +45,7 @@ def dispatch(command, args: dict[str, typing.Any]) -> int:
4145
basic.generate_sameple_config(**args)
4246

4347
elif command == "create":
44-
mesh_dir = basic.create_mesh_from_config(**args)
45-
try:
46-
basic.convert_mesh_dolfinx(mesh_dir=mesh_dir)
47-
except ImportError:
48-
logger.debug("dolfinx not installed, skipping conversion to dolfinx")
49-
48+
basic.create_mesh_from_config(**args)
5049
elif command == "convert":
5150
basic.convert_mesh_dolfinx(**args)
5251

src/mri2mesh/mesh/basic.py

Lines changed: 107 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -156,83 +156,147 @@ def create_mesh(
156156
manifold_surface=manifold_surface,
157157
correct_surface_orientation=True,
158158
)
159-
coords, connections = tetra.get_tracked_surfaces()
160159

161160
tetra_mesh = meshio.Mesh(
162161
point_array, [("tetra", cell_array)], cell_data={"cell_tags": [marker.ravel()]}
163162
)
164-
tetra_mesh_pv = pv.from_meshio(tetra_mesh).clean()
163+
164+
tetra_mesh_pv = pv.from_meshio(tetra_mesh)
165165
pv.save_meshio(outdir / "tetra_mesh.xdmf", tetra_mesh_pv)
166166

167-
for i, coord in enumerate(coords):
168-
np.save(outdir / f"coords_{i}.npy", coord)
167+
np.save(outdir / "point_array.npy", point_array)
168+
np.save(outdir / "cell_array.npy", cell_array)
169+
np.save(outdir / "marker.npy", marker)
170+
171+
# coords, connections = tetra.get_tracked_surfaces()
172+
# for i, coord in enumerate(coords):
173+
# np.save(outdir / f"coords_{i}.npy", coord)
174+
175+
# for i, conn in enumerate(connections):
176+
# np.save(outdir / f"connections_{i}.npy", conn)
169177

170-
for i, conn in enumerate(connections):
171-
np.save(outdir / f"connections_{i}.npy", conn)
178+
# cell_tags.find
179+
# Compute incident with facets
180+
# Intersection exterior facets
172181

173182

174-
def convert_mesh_dolfinx(mesh_dir: Path):
183+
def convert_mesh_dolfinx(
184+
mesh_dir: Path, extract_facet_tags: bool = False, extract_submesh: bool = False
185+
):
175186
logger.info("Converting mesh to dolfinx in %s", mesh_dir)
176187
from mpi4py import MPI
177-
from scipy.spatial.distance import cdist
178188
import dolfinx
189+
import basix
190+
import ufl
179191

180-
threshold = 1.0
181-
fdim = 2
182-
183-
coords = []
184-
for path in sorted(mesh_dir.glob("coords_*.npy"), key=lambda x: int(x.stem.split("_")[-1])):
185-
coords.append(np.load(path))
186-
logger.debug(f"Found {len(coords)} coordinates")
192+
point_array = np.load(mesh_dir / "point_array.npy")
193+
cell_array = np.load(mesh_dir / "cell_array.npy")
194+
marker = np.load(mesh_dir / "marker.npy")
187195

188-
connections = []
189-
for path in sorted(
190-
mesh_dir.glob("connections_*.npy"), key=lambda x: int(x.stem.split("_")[-1])
191-
):
192-
connections.append(np.load(path))
193-
logger.debug(f"Found {len(connections)} connections")
196+
comm = MPI.COMM_WORLD
197+
mesh = dolfinx.mesh.create_mesh(
198+
comm,
199+
cell_array.astype(np.int64),
200+
point_array,
201+
ufl.Mesh(basix.ufl.element("Lagrange", "tetrahedron", 1, shape=(3,))),
202+
)
203+
tdim = mesh.topology.dim
204+
fdim = tdim - 1
205+
local_entities, local_values = dolfinx.io.gmshio.distribute_entity_data(
206+
mesh,
207+
tdim,
208+
cell_array.astype(np.int64),
209+
marker.flatten().astype(np.int32),
210+
)
211+
adj = dolfinx.graph.adjacencylist(local_entities)
212+
cell_tags = dolfinx.mesh.meshtags_from_entities(
213+
mesh,
214+
tdim,
215+
adj,
216+
local_values.astype(np.int32, copy=False),
217+
)
218+
if not extract_facet_tags:
219+
logger.debug("Save files")
220+
with dolfinx.io.XDMFFile(comm, mesh_dir / "mesh_full.xdmf", "w") as xdmf:
221+
xdmf.write_mesh(mesh)
222+
xdmf.write_meshtags(cell_tags, mesh.geometry)
194223

195-
assert len(connections) == len(coords)
224+
return
196225

197-
logger.debug("Loading mesh")
198-
comm = MPI.COMM_WORLD
199-
with dolfinx.io.XDMFFile(comm, mesh_dir / "tetra_mesh.xdmf", "r") as xdmf:
200-
mesh = xdmf.read_mesh(name="Grid")
201-
cell_tags = xdmf.read_meshtags(mesh, name="Grid")
226+
mesh.topology.create_connectivity(tdim - 1, tdim)
202227

203-
logger.debug("Mesh loaded")
228+
# FIXME: Here we just add hard coded values for now. This should be fixed in the future
204229

205-
facets = []
230+
entities = []
206231
values = []
207-
for i, coord in enumerate(coords, start=1):
208-
logger.debug(f"Processing coord {i}")
232+
# 1 = Parenchyma
233+
PARENCHYMA = 1
209234

210-
def locator(x):
211-
# Find the distance to all coordinates
212-
distances = cdist(x.T, coord)
213-
# And return True is they are close
214-
return np.any(distances < threshold, axis=1)
235+
cells = cell_tags.find(PARENCHYMA)
236+
exterior_facets = dolfinx.mesh.exterior_facet_indices(mesh.topology)
237+
incident_facets = dolfinx.mesh.compute_incident_entities(mesh.topology, cells, tdim, tdim - 1)
238+
exterior_facets_marker = np.intersect1d(incident_facets, exterior_facets)
239+
values.append(np.full(exterior_facets_marker.shape[0], PARENCHYMA, dtype=np.int32))
240+
entities.append(exterior_facets_marker)
215241

216-
f = dolfinx.mesh.locate_entities_boundary(mesh, dim=fdim, marker=locator)
217-
v = np.full(f.shape[0], i, dtype=np.int32)
218-
facets.append(f)
219-
values.append(v)
242+
VENTRICLES = 3
243+
all_cell_tags = np.unique(cell_tags.values)
244+
cell_not_ventricles = np.setdiff1d(all_cell_tags, [VENTRICLES])
245+
import scifem
246+
247+
interface_entities = scifem.mesh.find_interface(cell_tags, [VENTRICLES], cell_not_ventricles)
248+
entities.append(interface_entities)
249+
values.append(np.full(interface_entities.shape[0], VENTRICLES, dtype=np.int32))
220250

221-
logger.debug("Create meshtags")
222251
facet_tags = dolfinx.mesh.meshtags(
223252
mesh,
224253
fdim,
225-
np.hstack(facets),
254+
np.hstack(entities),
226255
np.hstack(values),
227256
)
228257
facet_tags.name = "facet_tags"
229258
cell_tags.name = "cell_tags"
230259
mesh.name = "mesh"
231260

232261
logger.debug("Save files")
233-
with dolfinx.io.XDMFFile(comm, mesh_dir / "mesh.xdmf", "w") as xdmf:
262+
with dolfinx.io.XDMFFile(comm, mesh_dir / "mesh_full.xdmf", "w") as xdmf:
234263
xdmf.write_mesh(mesh)
235264
xdmf.write_meshtags(facet_tags, mesh.geometry)
236265
xdmf.write_meshtags(cell_tags, mesh.geometry)
237266

238267
logger.info("Mesh saved to %s", mesh_dir / "mesh.xdmf")
268+
269+
if not extract_submesh:
270+
return
271+
submesh_data = scifem.mesh.extract_submesh(mesh, cell_tags, cell_not_ventricles)
272+
273+
# Transfer the facet tags to the submesh
274+
submesh_data.domain.topology.create_connectivity(2, 3)
275+
facet_tags_submesh, sub_to_parent_entity_map = scifem.mesh.transfer_meshtags_to_submesh(
276+
facet_tags,
277+
# geo.facet_tags, # If available
278+
submesh_data.domain,
279+
vertex_to_parent=submesh_data.vertex_map,
280+
cell_to_parent=submesh_data.cell_map,
281+
)
282+
283+
np.save(mesh_dir / "sub_to_parent_entity_map.npy", sub_to_parent_entity_map)
284+
np.save(mesh_dir / "vertex_map.npy", submesh_data.vertex_map)
285+
np.save(mesh_dir / "cell_map.npy", submesh_data.cell_map)
286+
287+
# Remove overflow values
288+
keep_indices = facet_tags_submesh.values > 0
289+
facet_tags_new = dolfinx.mesh.meshtags(
290+
submesh_data.domain,
291+
fdim,
292+
facet_tags_submesh.indices[keep_indices],
293+
facet_tags_submesh.values[keep_indices],
294+
)
295+
296+
facet_tags_new.name = "facet_tags"
297+
submesh_data.cell_tag.name = "cell_tags"
298+
299+
with dolfinx.io.XDMFFile(comm, mesh_dir / "mesh.xdmf", "w") as xdmf:
300+
xdmf.write_mesh(submesh_data.domain)
301+
xdmf.write_meshtags(submesh_data.cell_tag, submesh_data.domain.geometry)
302+
xdmf.write_meshtags(facet_tags_new, submesh_data.domain.geometry)

0 commit comments

Comments
 (0)