upxo.meshing.confMesh3d.surface_nets module
surface_nets.py
vtkSurfaceNets3D wrapper for multi-label grain surface extraction.
Pipeline
Pad LGI with wall_label on all 6 faces (prevents RVE-face shrinkage).
Run vtkSurfaceNets3D → PyVista PolyData with BoundaryLabels cell array.
Project wall-adjacent mesh points back to exact RVE face planes (residual ±0.016 vox overshoot from smoothing).
Separate output into interior faces (grain-grain) and cap faces (grain-wall → the RVE face closing patches).
Optional PyVista visualisation at each step.
- class upxo.meshing.confMesh3d.surface_nets.SurfaceNetsResult(full_mesh: pyvista.PolyData, interior_cells: numpy.ndarray, cap_cells: numpy.ndarray, wall_label: int, voxel_size: float, rve_shape: Tuple[int, int, int], grain_ids: numpy.ndarray, grain_cell_masks: Dict[int, numpy.ndarray] = None)[source]
Bases:
objectOutput of the vtkSurfaceNets3D multi-label surface extraction stage.
Separates grain–grain interior faces from grain–wall cap faces (RVE boundary patches). Produced by
run_surface_nets().- full_mesh: pyvista.PolyData
- interior_cells: numpy.ndarray
- cap_cells: numpy.ndarray
- grain_ids: numpy.ndarray
- grain_cell_masks: Dict[int, numpy.ndarray] = None
- upxo.meshing.confMesh3d.surface_nets.run_surface_nets(lgi: numpy.ndarray, voxel_size: float, config: SurfaceNetsConfig | None = None, verbose: bool = True) SurfaceNetsResult[source]
Extract the multi-label grain boundary surface from a 3-D label array.
- Parameters:
- Return type:
- upxo.meshing.confMesh3d.surface_nets.apply_volume_correction(result: SurfaceNetsResult, lgi: numpy.ndarray, config: SurfaceNetsConfig | None = None, verbose: bool = True) SurfaceNetsResult[source]
Iterative volume-conservative normal displacement for grains whose SurfaceNets3D surface mesh volume differs from the voxel volume.
For each grain G: - Compute V_mesh (divergence theorem on triangle mesh) - Compute V_voxel = voxel_count × voxel_size³ - If |V_mesh - V_voxel| / V_voxel > volume_tol:
Iteratively displace vertices along outward normal by dV/A
Guard: vertex pinned if it would come within min_clearance of a neighbouring grain surface
- upxo.meshing.confMesh3d.surface_nets.visualize_surface_nets(result: SurfaceNetsResult, mode: str = 'full', grain_id: int | None = None, show: bool = True) pyvista.Plotter[source]
PyVista visualisation of the SurfaceNets3D output.
- Parameters:
result (SurfaceNetsResult)
mode ('full' — colour by first BoundaryLabel (grain label)) – ‘interior’ — show only grain-grain faces ‘caps’ — show only grain-wall faces ‘grain’ — show one specific grain’s surface (requires grain_id)
grain_id (int, required when mode='grain')
show (bool — call pvp.show() immediately)