04
Methodology
The PyAMorph pipeline transforms raw volumetric data into simulation-ready implicit
domains through a multi-stage variational approach, culminating in scalable AMReX output.
STEP 01
Segmentation
True 3D Robust Chan-Vese active contour evolves a level-set to minimise an energy
functional, suppressing image noise to produce a precise SDF (φ < 0 inside solid).
STEP 02
CSG Composition
Image-derived SDFs are freely composed with analytic primitives and STL meshes
using union, subtraction, and intersection in a unified CSG scene graph.
STEP 03
AMR Evaluation
Composite fields are evaluated onto hierarchical AMReX MultiFab structures.
AMR resolves the zero-level set at high resolution; bulk phases remain coarser.
STEP 04
Morphometry
Morphometric descriptors — volume, surface area, sphericity, curvature, mean aspect
ratio, nearest-neighbour distances, and Voronoi cell volumes — are extracted automatically.
Chan-Vese Segmentation Output (Microstructure)
FIG 4.1
SDF field recovered from a cross-sectional HEDS porous-solid micrograph via True 3D Robust
Chan-Vese segmentation. Blue = solid phase (φ < 0), red = void (φ > 0),
white contour = zero-level set.
STL to SDF
from stl2sdf import stl_to_geometry
# Convert any watertight STL mesh → composable SDF3D
geom = stl_to_geometry("my_mesh.stl")
# Compose with analytic shapes
from sdf3d import Sphere3D
result = geom - Sphere3D(0.2).translate(0, 0, 0.3)
phi = result.to_numpy(bounds=((-1,1),(-1,1),(-1,1)), resolution=(64,64,64))
FIG 4.2
Four STL meshes converted to SDF3D via stl_to_geometry() using
the pysdf C++ BVH back-end. Top-left: NASA Orion capsule plug (~2 K triangles).
Top-right: NASA Mars Curiosity rover wheel (~45 K triangles).
Bottom: artillery shell and missile geometries.
Each resulting SDF3D is fully composable with analytic primitives and TPMS metamaterials.
AMReX Adaptive Mesh Output
import amrex.space3d as amr
from sdf3d import Sphere3D, Box3D, MultiFabGrid3D
amr.initialize([])
try:
real_box = amr.RealBox([-1,-1,-1], [1,1,1])
domain = amr.Box(amr.IntVect(0,0,0), amr.IntVect(63,63,63))
geom = amr.Geometry(domain, real_box, 0, [0,0,0])
ba = amr.BoxArray(domain); ba.max_size(32)
dm = amr.DistributionMapping(ba)
grid = MultiFabGrid3D(geom, ba, dm)
mf_a = Sphere3D(0.3).to_multifab(grid)
mf_b = Box3D((0.2, 0.2, 0.2)).to_multifab(grid)
mf_u = grid.union(mf_a, mf_b) # min(a, b)
mf_s = grid.subtract(mf_b, mf_a) # box with sphere carved out
finally:
amr.finalize()
FIG 4.3
AMReX MultiFab output: SDF field of a Circle2D evaluated onto a uniform grid.
Blue = inside (φ < 0), red = outside (φ > 0).
FIG 4.4
AMReX MultiFab output: SDF of a rounded box with a spherical cavity subtracted at
its centre, demonstrating CSG subtraction on an AMReX grid.