Structural mesh generator
This package (myAceplaque.py) provides tools to convert patient information into FEM suitable meshes.
The following description was developed to load and convert meshes received from Università di Pavia.
General structure for the patient files:
│
├── wall_pXYZ.stl
├── calcio.stl
├── fibrosa.stl
└── lidpid.stl
These STL meshes need to be converted into the Mathematica-AceFEM
proper format:
O2- quadratic tetrahedrons for the solid meshP2- 3D triangles for the lumen surface (see also AceFEM Simulation docs)
The materials description is also produced based on the following logic:
Create a structured grid of points with predefined spacing
Assign a binary map for each mesh:
If (point inside the mesh)
1
else
0
Convert this into a Mathematica InterpolatingFunction for each material:
interpMatx.minterpFibr.minterpCalc.minterpLrnc.m
The structural mesh is created with the following logic:
Load the mesh in
ComsolCreate a rectangular shape lower than the mesh
Boolean intersection to clip the mesh, creating a flat top and a flat bottom
Mesh using quadratic tetrahedrons
Export the
ComsolmeshConvert the
mesh.mphtxtmesh into the desired format using mesh-importer_v2.
Comsol is run headless using a custom Matlab script, for more info see comsol headless.
Warning
THIS CAN BE IMPROVED. Ideally we should be able to remove Comsol and Matlab by using a Python-based meshing tool. I wasn’t able (yet) to find a suitable tool for this task.
Usage
See the Jupyter notebook mesh_processer_test.ipynb for a complete showcase.
You need to load the package:
import myAceplaque.mesher as plq
Define the meshes path
The mesh path can be defined using the partial name of the enclosing folder, joined with the relative paths of the meshes:
partial_name='T03_'
for root, dirs, files in os.walk(git_root):
for dir_name in dirs:
if partial_name in dir_name:
name_dir = dir_name
file_dir = os.path.join(root, name_dir)
#file_dir = os.path.join(git_root,'T03_Benchmark')
print(file_dir)
# Define the relative paths
relative_paths = {
'wall': 'original_dataset/wall_p040.stl',
'calc': 'original_dataset/lipid.stl',
'fibr': 'original_dataset/fibrosa.stl',
'lrnc': 'original_dataset/calcio.stl',
'out': '' # This represents the output directory relative to script_dir
}
# Join the script directory with the relative paths
paths = plq.join_relative_paths(file_dir, relative_paths)
Create the mesh
myMesh = plq.myMesh(paths)
Scale
scalingFactor = 0.001
myMesh.scale_meshes(scalingFactor)
myMesh.visualize_mesh(type='scaled')
Generate point maps
myMesh.assign_material_map(spacing=0.0001)
myMesh.visualize_material_map()
Create volumetric mesh
myMesh.assign_material_map(spacing=0.0001)
myMesh.visualize_material_map()
##
myMesh.write_material_map()
myMesh.create_volumetric_wall_mesh(block_height_multiplier=0.8, hmax='5E-4', hmin='3.5E-4')
Prerequisites
See the
enviroment.ymlfor the Anaconda environment creationComsol
Matlab
Jupyter notebook (optional)
Load the auxiliary libraries
This package needs to load:
import pyvista as pv
import numpy as np
import sys
import os
pv.global_theme.allow_empty_mesh = True
import subprocess
def find_git_root(path=None):
try:
# If no path is provided, use the current working directory
path = path or os.getcwd()
# Use git rev-parse to find the root directory of the repository
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
cwd=path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
# Example usage:
git_root = find_git_root()
libPath = os.path.join(git_root,'T00_Common','py')
sys.path.insert(0, libPath)
import myAceplaque.mesher as plq