@@ -156,83 +156,149 @@ 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)
169174
170- for i , conn in enumerate (connections ):
171- np .save (outdir / f"connections_{ i } .npy" , conn )
175+ # for i, conn in enumerate(connections):
176+ # np.save(outdir / f"connections_{i}.npy", conn)
172177
178+ # cell_tags.find
179+ # Compute incident with facets
180+ # Intersection exterior facets
173181
174- def convert_mesh_dolfinx (mesh_dir : Path ):
182+
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
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" )
182195
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" )
187-
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+ cell_tags .name = "cell_tags"
219+ if not extract_facet_tags :
220+ logger .debug ("Save files" )
221+ with dolfinx .io .XDMFFile (comm , mesh_dir / "mesh.xdmf" , "w" ) as xdmf :
222+ xdmf .write_mesh (mesh )
223+ xdmf .write_meshtags (cell_tags , mesh .geometry )
194224
195- assert len ( connections ) == len ( coords )
225+ return
196226
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" )
227+ mesh .topology .create_connectivity (tdim - 1 , tdim )
202228
203- logger . debug ( "Mesh loaded" )
229+ # FIXME: Here we just add hard coded values for now. This should be fixed in the future.
204230
205- facets = []
231+ entities = []
206232 values = []
207- for i , coord in enumerate (coords , start = 1 ):
208- logger .debug (f"Processing coord { i } " )
233+ # 1 = Parenchyma
234+ PARENCHYMA = 1
235+
236+ cells = cell_tags .find (PARENCHYMA )
237+ exterior_facets = dolfinx .mesh .exterior_facet_indices (mesh .topology )
238+ incident_facets = dolfinx .mesh .compute_incident_entities (mesh .topology , cells , tdim , tdim - 1 )
239+ exterior_facets_marker = np .intersect1d (incident_facets , exterior_facets )
240+ values .append (np .full (exterior_facets_marker .shape [0 ], PARENCHYMA , dtype = np .int32 ))
241+ entities .append (exterior_facets_marker )
209242
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 )
243+ VENTRICLES = 3
244+ all_cell_tags = np .unique (cell_tags .values )
245+ cell_not_ventricles = np .setdiff1d (all_cell_tags , [VENTRICLES ])
246+ import scifem
215247
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 )
248+ interface_entities = scifem .mesh .find_interface (cell_tags , [VENTRICLES ], cell_not_ventricles )
249+ entities .append (interface_entities )
250+ values .append (np .full (interface_entities .shape [0 ], VENTRICLES , dtype = np .int32 ))
220251
221- logger .debug ("Create meshtags" )
222252 facet_tags = dolfinx .mesh .meshtags (
223253 mesh ,
224254 fdim ,
225- np .hstack (facets ),
255+ np .hstack (entities ),
226256 np .hstack (values ),
227257 )
228258 facet_tags .name = "facet_tags"
229- cell_tags . name = "cell_tags"
259+
230260 mesh .name = "mesh"
231261
232262 logger .debug ("Save files" )
233- with dolfinx .io .XDMFFile (comm , mesh_dir / "mesh.xdmf" , "w" ) as xdmf :
263+ meshname = "mesh_full.xdmf" if extract_submesh else "mesh.xdmf"
264+ with dolfinx .io .XDMFFile (comm , mesh_dir / meshname , "w" ) as xdmf :
234265 xdmf .write_mesh (mesh )
235266 xdmf .write_meshtags (facet_tags , mesh .geometry )
236267 xdmf .write_meshtags (cell_tags , mesh .geometry )
237268
238- logger .info ("Mesh saved to %s" , mesh_dir / "mesh.xdmf" )
269+ logger .info ("Mesh saved to %s" , mesh_dir / meshname )
270+
271+ if not extract_submesh :
272+ return
273+ submesh_data = scifem .mesh .extract_submesh (mesh , cell_tags , cell_not_ventricles )
274+
275+ # Transfer the facet tags to the submesh
276+ submesh_data .domain .topology .create_connectivity (2 , 3 )
277+ facet_tags_submesh , sub_to_parent_entity_map = scifem .mesh .transfer_meshtags_to_submesh (
278+ facet_tags ,
279+ # geo.facet_tags, # If available
280+ submesh_data .domain ,
281+ vertex_to_parent = submesh_data .vertex_map ,
282+ cell_to_parent = submesh_data .cell_map ,
283+ )
284+
285+ np .save (mesh_dir / "sub_to_parent_entity_map.npy" , sub_to_parent_entity_map )
286+ np .save (mesh_dir / "vertex_map.npy" , submesh_data .vertex_map )
287+ np .save (mesh_dir / "cell_map.npy" , submesh_data .cell_map )
288+
289+ # Remove overflow values
290+ keep_indices = facet_tags_submesh .values > 0
291+ facet_tags_new = dolfinx .mesh .meshtags (
292+ submesh_data .domain ,
293+ fdim ,
294+ facet_tags_submesh .indices [keep_indices ],
295+ facet_tags_submesh .values [keep_indices ],
296+ )
297+
298+ facet_tags_new .name = "facet_tags"
299+ submesh_data .cell_tag .name = "cell_tags"
300+
301+ with dolfinx .io .XDMFFile (comm , mesh_dir / "mesh.xdmf" , "w" ) as xdmf :
302+ xdmf .write_mesh (submesh_data .domain )
303+ xdmf .write_meshtags (submesh_data .cell_tag , submesh_data .domain .geometry )
304+ xdmf .write_meshtags (facet_tags_new , submesh_data .domain .geometry )
0 commit comments