refactor(smread): broke sparse matrix debug utilities into smaller functions

This commit is contained in:
2025-06-03 08:11:39 -04:00
parent 2e9de49f88
commit cf153e0644
3 changed files with 110 additions and 1 deletions

View File

@@ -1 +1 @@
from .smread import loadSparseMatrixBinary, analyze_sparse_matrix, load_and_analyze_sparse_matrix
from .smread import loadSparseMatrixBinary, analyze_sparse_matrix, load_and_analyze_sparse_matrix

View File

@@ -26,6 +26,9 @@ def loadSparseMatrixBinary(f):
EXPECTED_MAGIC = b'CSRB'
EXPECTED_VERSION = 1
if isinstance(f, str):
f = open(f, 'rb')
try:
# --- Read Header ---
magic = f.read(4)

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env python3
import argparse
import meshio
import pyvista as pv
import numpy as np
import matplotlib.pyplot as plt
import warnings
def analyze_mesh_quality(mesh_filepath):
"""
Reads a mesh file, computes various quality metrics using the current
PyVista API (cell_quality), and prints statistics.
"""
print(f"--- Analyzing Mesh: {mesh_filepath} ---")
try:
mesh_mshio = meshio.read(mesh_filepath)
except FileNotFoundError:
print(f"ERROR: Mesh file '{mesh_filepath}' not found.")
return
except Exception as e:
print(f"ERROR: Could not read mesh file '{mesh_filepath}' with meshio: {e}")
return
points = mesh_mshio.points
cells_list = []
cell_types_list = []
supported_3d_types = {
"tetra": pv.CellType.TETRA,
"tetra10": pv.CellType.QUADRATIC_TETRA
}
found_3d_cells = False
for cells_block in mesh_mshio.cells:
if cells_block.type in supported_3d_types:
print(f"Found cell block of type '{cells_block.type}' with {len(cells_block.data)} cells.")
num_points_per_cell = cells_block.data.shape[1]
pv_cell_block = np.hstack((
np.full((len(cells_block.data), 1), num_points_per_cell, dtype=cells_block.data.dtype),
cells_block.data
)).ravel()
cells_list.append(pv_cell_block)
cell_types_list.extend([supported_3d_types[cells_block.type]] * len(cells_block.data))
found_3d_cells = True
if not found_3d_cells:
print("ERROR: No supported 3D cell types (e.g., tetra, tetra10, hexahedron) found in the mesh.")
print("Meshio cell types found in file:", [block.type for block in mesh_mshio.cells])
return
if len(cells_list) > 1:
print("Warning: Multiple 3D cell blocks found and concatenated. Ensure these are compatible for a single UnstructuredGrid.")
flat_cells = np.concatenate(cells_list)
elif len(cells_list) == 1:
flat_cells = cells_list[0]
else: # Should have been caught by "not found_3d_cells"
return
try:
mesh_pv = pv.UnstructuredGrid(flat_cells, cell_types_list, points)
print(f"\nSuccessfully converted to PyVista mesh with {mesh_pv.n_points} points and {mesh_pv.n_cells} cells.")
except Exception as e:
print(f"ERROR: Could not create PyVista UnstructuredGrid: {e}")
return
quality_measures_to_try = [
('aspect_ratio', "Aspect Ratio"),
('condition', "Condition Number of Element Jacobian"),
('distortion', "Distortion (0=perfect, 1=degenerated)"),
('jacobian', "Determinant of Element Jacobian (should be > 0)"),
('radius_ratio', "Radius Ratio (for tets: inscribed/circumscribed, 1 is best)"),
('scaled_jacobian', "Scaled Jacobian (1 is ideal, <0 bad)"),
('skew', "Skewness (0 is ideal, higher is worse)"),
('volume', "Volume (should be > 0)"),
('min_angle', "Minimum Dihedral/Face Angle (larger is better)"),
('max_angle', "Maximum Dihedral/Face Angle (smaller is better, less 'flat')")
]
# Suppress common warnings for cleaner output, adjust as needed
warnings.filterwarnings("ignore", category=UserWarning, message="`quality_measure`.*not implemented for this cell type.")
warnings.filterwarnings("ignore", category=UserWarning, message="Cannot compute quality of a point cell.") # If points/lines exist
warnings.filterwarnings("ignore", category=UserWarning, message="Mesh contains non-tetrahedral cells. Radius ratio is only defined for tetrahedra.")
warnings.filterwarnings("ignore", category=RuntimeWarning) # For potential NaN in stats from empty arrays etc.
for measure, description in quality_measures_to_try:
if not mesh_pv.n_cells > 0:
continue
# Use the recommended cell_quality method
quality_array = mesh_pv.cell_quality(quality_measure=measure)
range = quality_array.get_data_range(measure)
print(f"Range for {measure} is: {range[0]:0.3E}{range[1]:0.3E}")
warnings.resetwarnings()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Analyze mesh quality using PyVista.")
parser.add_argument("mesh_filepath", type=str, help="Path to the mesh file (e.g., .msh, .vtk).")
args = parser.parse_args()
analyze_mesh_quality(args.mesh_filepath)