@@ -396,16 +396,18 @@ def compute_circularity(loop_polydata):
396396 if not isinstance (mesh , type (None )):
397397 global_nodes = mesh .points
398398 global_node_tree = cKDTree (global_nodes )
399- global_elements = mesh .cell_connectivity .reshape (- 1 , 4 )
400- global_elements = numpy .sort (global_elements , axis = 1 )
401- tet_faces = []
402- for i in tqdm .trange (global_elements .shape [0 ], desc = "Building tetrahedral faces" , leave = False ):
403- for j in range (4 ):
404- # Build each face as a sorted triple of node IDs for exact matching
405- face_nodes = numpy .delete (global_elements [i ], j )
406- face_nodes = numpy .sort (face_nodes )
407- tet_faces .append (face_nodes )
408- tet_face_tree = cKDTree (tet_faces )
399+ # Build a robust face->cell index using canonical keys (sorted tuples)
400+ face_to_cell = {}
401+ n_cells = mesh .n_cells
402+ for i in tqdm .trange (n_cells , desc = "Indexing cell faces" , leave = False ):
403+ cell = mesh .GetCell (i )
404+ nfaces = cell .GetNumberOfFaces ()
405+ for j in range (nfaces ):
406+ face = cell .GetFace (j )
407+ npts = face .GetNumberOfPoints ()
408+ # Canonicalize face nodes to a sorted tuple so orientation/order doesn't matter
409+ key = tuple (sorted (face .GetPointId (k ) for k in range (npts )))
410+ face_to_cell [key ] = i
409411 #for i, cap in enumerate(iscap):
410412 # if not cap == 1:
411413 # walls.append(faces[i])
@@ -418,27 +420,33 @@ def compute_circularity(loop_polydata):
418420 wall_cells = surface .extract_cells (walls [i ])
419421 wall_surface = wall_cells .extract_surface ()
420422 if not isinstance (mesh , type (None )):
421- wall_surface .point_data ["GlobalNodeID" ] = numpy .zeros (wall_surface .n_points , dtype = int )
422- wall_surface .cell_data ['GlobalElementID' ] = numpy .zeros (wall_surface .n_cells , dtype = int )
423- wall_surface .cell_data ['ModelFaceID' ] = numpy .ones (wall_surface .n_cells , dtype = int )
423+ wall_surface .point_data ["GlobalNodeID" ] = numpy .zeros (wall_surface .n_points , dtype = numpy . int32 )
424+ wall_surface .cell_data ['GlobalElementID' ] = numpy .zeros (wall_surface .n_cells , dtype = numpy . int32 )
425+ wall_surface .cell_data ['ModelFaceID' ] = numpy .ones (wall_surface .n_cells , dtype = numpy . int32 )
424426 _ , indices = global_node_tree .query (wall_surface .points )
425427 wall_surface .point_data ["GlobalNodeID" ] = indices .astype (int )
426428 # Assign Global Element IDs
427429 wall_faces = wall_surface .point_data ["GlobalNodeID" ][wall_surface .faces ]
428- wall_faces = wall_faces .reshape (- 1 , 4 )[:, 1 :]
429- wall_faces = numpy .sort (wall_faces , axis = 1 )
430- dists , indices = tet_face_tree .query (wall_faces )
431- if not numpy .all (numpy .isclose (dists , 0.0 )):
432- # Identify a small sample of mismatches for debugging
433- bad_idx = numpy .where (~ numpy .isclose (dists , 0.0 ))[0 ]
434- sample = bad_idx [:5 ]
435- examples = wall_faces [sample ]
436- raise ValueError (
437- f"Failed to map all wall surface faces to volume mesh faces: { bad_idx .size } mismatches. "
438- f"Example face node triples (GlobalNodeID) that failed exact match: { examples .tolist ()} "
439- )
440- wall_surface .cell_data ["GlobalElementID" ] = indices // 4
441- wall_surface .cell_data ["GlobalElementID" ] = wall_surface .cell_data ["GlobalElementID" ].astype (numpy .int32 )
430+ wall_faces = wall_faces .reshape (- 1 , 4 )[:, 1 :].tolist ()
431+ elem_ids = []
432+ for face in wall_faces :
433+ # Use the same canonical key used to build the map
434+ elem_ids .append (face_to_cell [tuple (sorted (face ))])
435+ wall_surface .cell_data ["GlobalElementID" ] = numpy .array (elem_ids , dtype = numpy .int32 )
436+ #wall_faces = numpy.sort(wall_faces, axis=1)
437+ #dists, indices = tet_face_tree.query(wall_faces)
438+ #if not numpy.all(numpy.isclose(dists, 0.0)):
439+ # # Identify a small sample of mismatches for debugging
440+ # bad_idx = numpy.where(~numpy.isclose(dists, 0.0))[0]
441+ # sample = bad_idx[:5]
442+ # examples = wall_faces[sample]
443+ # raise ValueError(
444+ # f"Failed to map all wall surface faces to volume mesh faces: {bad_idx.size} mismatches. "
445+ # f"Example face node triples (GlobalNodeID) that failed exact match: {examples.tolist()}"
446+ # )
447+ #wall_surface.cell_data["GlobalElementID"] = indices // 4
448+ #wall_surface.cell_data["GlobalElementID"] = wall_surface.cell_data["GlobalElementID"].astype(numpy.int32)
449+
442450 boundaries = wall_surface .extract_feature_edges (boundary_edges = True , manifold_edges = False ,
443451 feature_edges = False , non_manifold_edges = False )
444452 boundaries = boundaries .split_bodies ()
@@ -455,27 +463,31 @@ def compute_circularity(loop_polydata):
455463 cap_cells = surface .extract_cells (face_cap )
456464 cap_surface = cap_cells .extract_surface ()
457465 if not isinstance (mesh , type (None )):
458- cap_surface .point_data ["GlobalNodeID" ] = numpy .zeros (cap_surface .n_points , dtype = int )
459- cap_surface .cell_data ["GlobalElementID" ] = numpy .zeros (cap_surface .n_cells , dtype = int )
460- cap_surface .cell_data ["ModelFaceID" ] = numpy .ones (cap_surface .n_cells , dtype = int ) * ( i + 2 )
466+ cap_surface .point_data ["GlobalNodeID" ] = numpy .zeros (cap_surface .n_points , dtype = numpy . int32 )
467+ cap_surface .cell_data ["GlobalElementID" ] = numpy .zeros (cap_surface .n_cells , dtype = numpy . int32 )
468+ cap_surface .cell_data ["ModelFaceID" ] = numpy .ones (cap_surface .n_cells , dtype = numpy . int32 )
461469 # Assign Global Node IDs
462470 _ , indices = global_node_tree .query (cap_surface .points )
463471 cap_surface .point_data ["GlobalNodeID" ] = indices .astype (int )
464472 # Assign Global Element IDs
465473 cap_faces = cap_surface .point_data ["GlobalNodeID" ][cap_surface .faces ]
466- cap_faces = cap_faces .reshape (- 1 , 4 )[:, 1 :]
467- cap_faces = numpy .sort (cap_faces , axis = 1 )
468- dists , indices = tet_face_tree .query (cap_faces )
469- if not numpy .all (numpy .isclose (dists , 0.0 )):
470- bad_idx = numpy .where (~ numpy .isclose (dists , 0.0 ))[0 ]
471- sample = bad_idx [:5 ]
472- examples = cap_faces [sample ]
473- raise ValueError (
474- f"Failed to map all cap surface faces to volume mesh faces: { bad_idx .size } mismatches. "
475- f"Example face node triples (GlobalNodeID) that failed exact match: { examples .tolist ()} "
476- )
477- cap_surface .cell_data ["GlobalElementID" ] = indices // 4
478- cap_surface .cell_data ["GlobalElementID" ] = cap_surface .cell_data ["GlobalElementID" ].astype (numpy .int32 )
474+ cap_faces = cap_faces .reshape (- 1 , 4 )[:, 1 :].tolist ()
475+ elem_ids = []
476+ for face in cap_faces :
477+ elem_ids .append (face_to_cell [tuple (sorted (face ))])
478+ cap_surface .cell_data ["GlobalElementID" ] = numpy .array (elem_ids , dtype = numpy .int32 )
479+ #cap_faces = numpy.sort(cap_faces, axis=1)
480+ #dists, indices = tet_face_tree.query(cap_faces)
481+ #if not numpy.all(numpy.isclose(dists, 0.0)):
482+ # bad_idx = numpy.where(~numpy.isclose(dists, 0.0))[0]
483+ # sample = bad_idx[:5]
484+ # examples = cap_faces[sample]
485+ # raise ValueError(
486+ # f"Failed to map all cap surface faces to volume mesh faces: {bad_idx.size} mismatches. "
487+ # f"Example face node triples (GlobalNodeID) that failed exact match: {examples.tolist()}"
488+ # )
489+ #cap_surface.cell_data["GlobalElementID"] = indices // 4
490+ #cap_surface.cell_data["GlobalElementID"] = cap_surface.cell_data["GlobalElementID"].astype(numpy.int32)
479491 boundaries = cap_surface .extract_feature_edges (boundary_edges = True , manifold_edges = False ,
480492 feature_edges = False , non_manifold_edges = False )
481493 boundaries = boundaries .split_bodies ()
@@ -501,19 +513,23 @@ def compute_circularity(loop_polydata):
501513 lumen_surface .point_data ["GlobalNodeID" ] = indices .astype (int )
502514 # Assign Global Element IDs
503515 lumen_faces = lumen_surface .point_data ["GlobalNodeID" ][lumen_surface .faces ]
504- lumen_faces = lumen_faces .reshape (- 1 , 4 )[:, 1 :]
505- lumen_faces = numpy .sort (lumen_faces , axis = 1 )
506- dists , indices = tet_face_tree .query (lumen_faces )
507- if not numpy .all (numpy .isclose (dists , 0.0 )):
508- bad_idx = numpy .where (~ numpy .isclose (dists , 0.0 ))[0 ]
509- sample = bad_idx [:5 ]
510- examples = lumen_faces [sample ]
511- raise ValueError (
512- f"Failed to map all lumen surface faces to volume mesh faces: { bad_idx .size } mismatches. "
513- f"Example face node triples (GlobalNodeID) that failed exact match: { examples .tolist ()} "
514- )
515- lumen_surface .cell_data ["GlobalElementID" ] = indices // 4
516- lumen_surface .cell_data ["GlobalElementID" ] = lumen_surface .cell_data ["GlobalElementID" ].astype (numpy .int32 )
516+ lumen_faces = lumen_faces .reshape (- 1 , 4 )[:, 1 :].tolist ()
517+ elem_ids = []
518+ for face in lumen_faces :
519+ elem_ids .append (face_to_cell [tuple (sorted (face ))])
520+ lumen_surface .cell_data ["GlobalElementID" ] = numpy .array (elem_ids , dtype = numpy .int32 )
521+ #lumen_faces = numpy.sort(lumen_faces, axis=1)
522+ #dists, indices = tet_face_tree.query(lumen_faces)
523+ #if not numpy.all(numpy.isclose(dists, 0.0)):
524+ # bad_idx = numpy.where(~numpy.isclose(dists, 0.0))[0]
525+ # sample = bad_idx[:5]
526+ # examples = lumen_faces[sample]
527+ # raise ValueError(
528+ # f"Failed to map all lumen surface faces to volume mesh faces: {bad_idx.size} mismatches. "
529+ # f"Example face node triples (GlobalNodeID) that failed exact match: {examples.tolist()}"
530+ # )
531+ #lumen_surface.cell_data["GlobalElementID"] = indices // 4
532+ #lumen_surface.cell_data["GlobalElementID"] = lumen_surface.cell_data["GlobalElementID"].astype(numpy.int32)
517533 boundaries = lumen_surface .extract_feature_edges (boundary_edges = True , manifold_edges = False ,
518534 feature_edges = False , non_manifold_edges = False )
519535 boundaries = boundaries .split_bodies ()
0 commit comments