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 mesh

  • P2 - 3D triangles for the lumen surface (see also AceFEM Simulation docs)

The materials description is also produced based on the following logic:

  1. Create a structured grid of points with predefined spacing

  2. Assign a binary map for each mesh:

If (point inside the mesh)
    1
else
    0
  1. Convert this into a Mathematica InterpolatingFunction for each material:

    • interpMatx.m

    • interpFibr.m

    • interpCalc.m

    • interpLrnc.m

The structural mesh is created with the following logic:

  1. Load the mesh in Comsol

  2. Create a rectangular shape lower than the mesh

  3. Boolean intersection to clip the mesh, creating a flat top and a flat bottom

  4. Mesh using quadratic tetrahedrons

  5. Export the Comsol mesh

  6. Convert the mesh.mphtxt mesh 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.yml for the Anaconda environment creation

  • Comsol

  • 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

Extras