Microgen modules
Phase module
Phase 2.0 — implicit-first, CAD-optional, Piece-aware container.
A Phase is a region of space identified by an implicit scalar
field (the canonical representation), with derived materialisations on
demand:
grid()/surface_mesh()/volume_mesh()— PyVista viewscad— OCCT BREP viamicrogen.cad.shape_to_cad()pieces— connected components of{field < iso}(the “Phase = collection of cut/split sub-solids” invariant)center_of_mass/inertia_matrix— moments via grid quadrature (field-backed) or BRepGProp (CAD-backed)
Three construction paths:
Phase(field=..., bounds=..., iso=..., period=...)— field-first (no CAD required).Phase.from_shape()— sugar over the field-first path; bridges from aShape.Phase.from_cad()— CAD-backed; required when loading a STEP file or wrapping a pre-built BREP.
The CAD seam is isolated in _materialise_cad(). Switching from
microgen.cad to pyvista-cad later means swapping that one method;
no other code in microgen needs to change.
A Phase is immutable: transforms (translated(),
scaled(), rotated(), tiled()) return a new instance.
This makes cache invalidation impossible by construction.
- class microgen.phase.Phase(*, field: Field | None = None, bounds: BoundsType | None = None, iso: float = 0.0, period: PeriodType | None = None, name: str | None = None, resolution: int = 50)
Bases:
objectMicrostructure phase (implicit-first, CAD-optional).
A phase is one of the three:
field-backed: a callable
field(x,y,z) -> arraywith negative values inside, plus an AABBboundsand anisovalue (the solid is{p : field(p) < iso}).mesh-backed: a triangulated surface
pv.PolyData.CAD-backed: a CAD shape (
microgen.cad.CadShapetoday, any duck-typed CAD object — including futurepyvista-cadshapes — tomorrow).
The other two materialisations are derived on demand.
- Parameters:
field – SDF / level-set
(x, y, z) -> array; negative inside. Required for field-backed construction.bounds – axis-aligned bbox
(xmin, xmax, ymin, ymax, zmin, zmax)spanning the field. Required iffieldis set.iso – iso-value; the solid is
{p : field(p) < iso}. Defaults to0.0.period –
(Lx, Ly, Lz)if the field is intrinsically periodic. Optional.name – phase name (defaults to auto-generated
Phase_N).resolution – default sampling resolution used by lazy
grid()/surface_mesh()/pieces().
Use
from_shape(),from_cad()orfrom_mesh()to build from aShape, a pre-built CAD object, or a triangulated mesh, respectively.- property bounds: BoundsType | None
AABB
(xmin, xmax, ymin, ymax, zmin, zmax).For field-backed phases this is set at construction. For CAD- or mesh-backed phases it’s derived from the underlying representation.
- property cad: Any
The CAD representation (
microgen.cad.CadShapetoday, lazy).For CAD-backed phases this returns the stored shape. For field-backed or mesh-backed phases it’s lazily materialised via
_materialise_cad().Requires the
[cad]extra (raisesImportErrorotherwise).
- property center_of_mass: npt.NDArray[np.float64]
Volumetric center of mass.
For field-backed phases this is computed by quadrature on the sampled grid (no OCCT needed). For CAD-backed phases this uses
BRepGProp.VolumeProperties_s.
- property field: Field | None
The implicit scalar field, or
Nonefor non-field-backed phases.
- classmethod from_cad(cad: Any, *, name: str | None = None) Phase
Construct a CAD-backed
Phase.cadmay be amicrogen.cad.CadShapeor any duck-typed object with.solids(),.center(),.volume(),.bounding_box()methods (this is the seam that lets a futurepyvista-cadbackend drop in without touchingPhase).- Parameters:
cad – a CAD shape (
CadShapetoday)name – phase name (auto-generated if omitted)
- classmethod from_mesh(mesh: pv.PolyData, *, name: str | None = None) Phase
Construct a mesh-backed
Phasefrom a closed surface mesh.- Parameters:
mesh – closed triangulated surface
name – phase name (auto-generated if omitted)
- classmethod from_shape(shape: Shape, *, bounds: BoundsType | None = None, iso: float = 0.0, name: str | None = None, resolution: int = 50) Phase
Construct a field-backed
Phasefrom an implicitShape.Inherits
field,bounds, andperiodfrom the shape.boundsmay be overridden (e.g., to clip a periodic field to a sub-region).- Parameters:
shape – source implicit shape; must have
func is not None.bounds – override the shape’s bounds; defaults to
shape.bounds.iso – iso-value (default
0.0).name – phase name (auto-generated if omitted).
resolution – default sampling resolution.
- grid(resolution: int | None = None) pv.StructuredGrid
Return a structured grid sampling of the field.
Only meaningful for field-backed phases.
- property inertia_matrix: npt.NDArray[np.float64]
Inertia tensor (about the origin) of the phase.
Field-backed: grid quadrature. CAD-backed:
BRepGProp.
- property is_empty: bool
True if the phase has no backing representation.
- property iso: float
Iso-value for the implicit field (the solid is
{field < iso}).
- property period: PeriodType | None
Intrinsic period
(Lx, Ly, Lz)if the field is periodic.
- property pieces: list[Piece]
Connected components of the phase (the “sub-pieces” invariant).
CAD-backed phase: one
PieceperTopoDS_Solid.Field-backed phase:
scipy.ndimage.labelongrid_field < iso; one piece per connected component.Mesh-backed phase:
polydata.connectivity().split_bodies().
- property resolution: int
Default sampling resolution for lazy grid/mesh/pieces materialisation.
- scaled(factor: float | tuple[float, float, float]) Phase
Return a new
Phasescaled byfactorabout its center of mass.CAD-backed phases use OCCT
BRepBuilderAPI_GTransformabout the BRep center. Field-backed phases compose the field viaf'(p) = f((p - c) / s + c) * s_min(uniform scale only; a per-axis scale is not exact for an SDF, so non-uniform factors rescale the bbox only and leave the field’s iso-distance approximate — caller’s responsibility).
- surface_mesh(resolution: int | None = None) pv.PolyData
Return a triangulated surface mesh of the solid boundary.
Mesh-backed phase: returns the stored mesh.
Field-backed phase: marching cubes on the sampled grid.
CAD-backed phase: tessellates via OCCT incremental mesh.
- tiled(rve: Rve, grid: tuple[int, int, int]) Phase
Return a new
Phaseperiodically tiled on the RVE.Builds
∏ gridtranslated copies of the current phase and fuses them. Only implemented for CAD-backed phases today (the field-backed equivalent — domain folding viamod— lands in a follow-up; the periodic-shape work inmicrogen.shape.implicit_opsalready covers it forShapedirectly).
- volume_mesh(resolution: int | None = None) pv.UnstructuredGrid
Return the volumetric cells where
field < iso.Only meaningful for field-backed phases.
- class microgen.phase.Piece(com: tuple[float, float, float], volume: float, bounds: BoundsType, cad: Any | None = None, mesh: pv.PolyData | None = None, voxel_mask: npt.NDArray[np.bool_] | None = None)
Bases:
objectOne connected sub-region of a
Phase.Pieces are what survives “split this phase under periodicity” or “raster this phase into a per-cell grid” — they expose the per-piece geometric moments without forcing every Phase to be a list of solids.
Payload fields are populated lazily and may be
Nonedepending on how the parentPhasewas constructed: a CAD-backed phase populatescad; a field-backed phase populatesvoxel_mask; a mesh-backed phase populatesmesh.- bounds: BoundsType
- cad: Any | None = None
- com: tuple[float, float, float]
- mesh: pv.PolyData | None = None
- volume: float
- voxel_mask: npt.NDArray[np.bool_] | None = None
Operations
Boolean operations.
All OCP imports are deferred so the module loads cleanly in a mesh-only
install. Functions that use OCCT raise a clear ImportError (via
microgen.cad.require_cad()) if the [cad] extra isn’t installed.
- microgen.operations.cut_phase_by_shape_list(phase_to_cut: Phase, shapes: list[CadShape]) Phase
Cut a phase by a list of shapes.
- Parameters:
phase_to_cut – phase to cut (must be CAD-backed)
shapes – list of cutting shapes
- Return resultCut:
cut phase
- microgen.operations.cut_phases(phases: list[Phase], *, reverse_order: bool = True) list[Phase]
Cut list of phases in the given order (or reverse) and fuse them.
- Parameters:
phases – list of phases to cut (each must be CAD-backed)
reverse_order – order for cutting shapes; when
True, the last shape of the list is not cut
- Returns:
list of phases
- microgen.operations.cut_phases_by_shape(phases: list[Phase], cut_obj: CadShape) list[Phase]
Cut list of phases by a given shape.
- Parameters:
phases – list of phases (must be CAD-backed)
cut_obj – cutting object
- Return phase_cut:
final result
- microgen.operations.cut_shapes(shapes: list[CadShape], *, reverse_order: bool = True) list[CadShape]
Cut list of shapes in the given order (or reverse) and fuse them.
- Parameters:
shapes – list of shapes to cut
reverse_order – bool, order for cutting shapes, when True: the last shape of the list is not cut
- Return cutted_shapes:
list of CadShape
- microgen.operations.fuse_shapes(shapes: list[CadShape], *, retain_edges: bool) CadShape
Fuse all shapes in the list.
- Parameters:
shapes – list of shapes to fuse
retain_edges – retain intersecting edges
- Returns:
fused shape
- microgen.operations.raster_phase(phase: Phase, rve: Rve, grid: list[int], *, phase_per_raster: bool = True) Phase | list[Phase]
Raster a phase according to the RVE divided by the given grid.
Each solid in the phase is split by the (grid-1) interior planes per axis (CAD-backed phases only). When
phase_per_rasteris true, each non-empty grid cell becomes onePhase; otherwise the split sub-solids are fused into one newPhase.- Parameters:
phase – CAD-backed phase to raster
rve – RVE divided by the given grid
grid – number of divisions in each direction
[x, y, z]phase_per_raster – if True, returns list of phases
- Returns:
Phase or list of Phases
- microgen.operations.repeat_polydata(mesh: pv.PolyData, rve: Rve, grid: tuple[int, int, int]) pv.PolyData
Repeat mesh in each direction according to the given grid.
- Parameters:
mesh – pv.PolyData to repeat
rve – RVE of the geometry to repeat
grid – list of number of geometry repetitions in each direction
- Returns:
pv.PolyData of the repeated geometry
- microgen.operations.repeat_shape(unit_geom: CadShape, rve: Rve, grid: tuple[int, int, int]) CadShape
Repeat unit geometry in each direction according to the given grid.
- Parameters:
unit_geom – Shape to repeat
rve – RVE of the geometry to repeat
grid – list of number of geometry repetitions in each direction
- Returns:
CadShape of the repeated geometry
- microgen.operations.rescale(shape: CadShape, scale: float | tuple[float, float, float]) CadShape
Rescale
shapebyscale = (sx, sy, sz)(or a scalar) about its centroid.Preserves the shape’s center of mass — scaling is performed about it.
- microgen.operations.rotate(obj: CadShape, center: npt.NDArray[np.float64] | Sequence[float], rotation: Rotation) CadShape
- microgen.operations.rotate(obj: PolyData, center: npt.NDArray[np.float64] | Sequence[float], rotation: Rotation) PolyData
- microgen.operations.rotate(obj: UnstructuredGrid, center: npt.NDArray[np.float64] | Sequence[float], rotation: Rotation) UnstructuredGrid
Rotate object according to given rotation.
Supports
microgen.cad.CadShapeand anypyvista.DataSet(PolyData,UnstructuredGrid,StructuredGrid, …) — i.e. any pyvista mesh exposingrotate_vector.- Parameters:
obj – Object to rotate
center – numpy array (x, y, z)
rotation – scipy Rotation object
- Returns:
Rotated object (same type as input)
- Raises:
ValueError – if object type is not supported
- microgen.operations.rotate_euler(obj: CadShape, center: npt.NDArray[np.float64] | Sequence[float], angles_or_rotation: Sequence[float] | Rotation) CadShape
- microgen.operations.rotate_euler(obj: PolyData, center: npt.NDArray[np.float64] | Sequence[float], angles_or_rotation: Sequence[float] | Rotation) PolyData
Rotate object according to ZXZ Euler angle convention.
Accepts
CadShapeorpyvista.PolyData.- Parameters:
obj – Object to rotate
center – numpy array (x, y, z)
angles_or_rotation – list of Euler angles (psi, theta, phi) in degrees, or a scipy
Rotationobject
- Returns:
Rotated object
Rve
Representative Volume Element (RVE).
Frozen, immutable container for the RVE bounding box and its periodicity flags.
Rve.box is a CadShape wrapping an OCCT box; it is
built lazily on first access and requires the [cad] extra. Rve.grid
returns a pyvista.StructuredGrid aligned with the cell — used by
implicit shapes to sample SDF/level-set fields.
- class microgen.rve.Rve(center: Vector3DType = (0, 0, 0), dim: float | Vector3DType = 1, pbc: bool | tuple[bool, bool, bool] | Sequence[bool] = (True, True, True))
Bases:
objectRepresentative Volume Element (RVE) — frozen.
- Parameters:
center – center of the RVE
dim – dimensions of the RVE (scalar → cube)
pbc – periodic-boundary-condition flags per axis
(x, y, z); defaults to fully periodic. A singleboolis broadcast to all axes.
- property box: CadShape
Return a
CadShapebox of the RVE (cached).Requires the
[cad]extra.
- center: ndarray
- dim: ndarray
- classmethod from_min_max(min_point: Vector3DType = (-0.5, -0.5, -0.5), max_point: Vector3DType = (0.5, 0.5, 0.5), pbc: bool | tuple[bool, bool, bool] | Sequence[bool] = (True, True, True)) Rve
Generate a Rve from min and max corner points.
- Parameters:
min_point –
(x_min, y_min, z_min)corner of the RVEmax_point –
(x_max, y_max, z_max)corner of the RVEpbc – periodic-boundary-condition flags (see
__init__)
- grid(resolution: ResolutionType) pv.StructuredGrid
Return a structured grid aligned with the RVE.
- Parameters:
resolution – points per axis — int (broadcast to all 3 axes) or length-3 sequence. The grid spans
min_point→max_pointwith endpoints included on every axis.
- property max_point: ndarray
Max corner
center + 0.5 * dim.
- property min_point: ndarray
Min corner
center - 0.5 * dim.
- pbc: tuple[bool, bool, bool]
Periodic
Periodic cut — rearrange a shape so it wraps around an RVE.
Pure OCP implementation (cadquery-ocp-novtk); no cadquery dependency.
Requires the [cad] extra.
Mesh
Mesh using gmsh.
- exception microgen.mesh.OutputMeshNotPeriodicError
Bases:
ExceptionRaised when output mesh from mesh_periodic is not periodic.
- microgen.mesh.is_periodic(nodes_coords: ndarray[tuple[Any, ...], dtype[float64]], tol: float = 1e-08) bool
Check whether a mesh is periodic, given its nodes’ coordinates.
- Parameters:
nodes_coords – list of nodes coordinates of the analyzed mesh
tol – tolerance
- microgen.mesh.mesh(mesh_file: str, list_phases: list[Phase], size: float, order: int, output_file: str = 'Mesh.msh', msh_file_version: int = 4) None
Mesh step file with gmsh with list of phases management.
- Parameters:
mesh_file – step file to mesh
list_phases – list of phases to mesh
size – mesh size constraint (see: gmsh.model.mesh.setSize(dimTags, size))
order – see gmsh.model.mesh.setOrder(order)
output_file – output file (.msh, .vtk)
msh_file_version – gmsh file version
- microgen.mesh.mesh_periodic(mesh_file: str, rve: Rve, list_phases: list[Phase], size: float, order: int, output_file: str = 'MeshPeriodic.msh', msh_file_version: int = 4, tol: float = 1e-08) None
Mesh periodic geometries with gmsh.
- Parameters:
mesh_file – step file to mesh
rve – RVE for periodicity
list_phases – list of phases to mesh
size – mesh size constraint (see: gmsh.model.mesh.setSize(dimTags, size))
order – see gmsh.model.mesh.setOrder(order)
output_file – output file (.msh, .vtk)
msh_file_version – gmsh file version
tol – tolerance for periodicity check
Remesh
Remesh a mesh using mmg while keeping boundaries untouched.
- exception microgen.remesh.InputMeshNotPeriodicError
Bases:
ExceptionRaised when the input mesh is not periodic.
Triggered when
periodic=Trueis passed toremesh_keeping_boundaries_for_fem()but the supplied input mesh fails the periodicity check.
- exception microgen.remesh.OutputMeshNotPeriodicError
Bases:
ExceptionRaised when the remeshed output is not periodic.
Triggered when
periodic=Trueis passed toremesh_keeping_boundaries_for_fem()but mmg’s output fails the periodicity check.
- microgen.remesh.remesh_keeping_boundaries_for_fem(input_mesh: BoxMesh, *, periodic: bool = True, mesh_version: int = 2, dimension: int = 3, tol: float = 1e-08, hausd: float | None = None, hgrad: float | None = None, hmax: float | None = None, hmin: float | None = None, hsiz: float | None = None) BoxMesh
- microgen.remesh.remesh_keeping_boundaries_for_fem(input_mesh: UnstructuredGrid, *, periodic: bool = True, mesh_version: int = 2, dimension: int = 3, tol: float = 1e-08, hausd: float | None = None, hgrad: float | None = None, hmax: float | None = None, hmin: float | None = None, hsiz: float | None = None) UnstructuredGrid
Remesh a mesh using mmg while keeping boundary elements untouched.
See https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options for the full reference on each
h*parameter.- Parameters:
input_mesh – BoxMesh or pv.UnstructuredGrid mesh to be remeshed
periodic – whether the mesh is periodic and must stay periodic
mesh_version – mesh file version
dimension – mesh dimension
tol – tolerance for the periodicity check
hausd – maximal Hausdorff distance for the boundaries approximation
hgrad – gradation value, i.e. ratio between lengths of adjacent mesh edges
hmax – maximal edge size
hmin – minimal edge size
hsiz – build a constant size map of size
hsiz
External
Wrappers around external command-line tools.
- class microgen.external.Mmg
Bases:
objectWrapper around the
mmg2d_O3/mmgs_O3/mmg3d_O3binaries.Each method exposes the underlying mmg CLI flags as keyword arguments using the same short names as the binaries themselves (
input,output,ls,nr,A,ar, …). See the mmg documentation for the full reference.A larger redesign of this interface is planned; for now it intentionally mirrors the original flat-kwarg shape.
- static mmg2d(d=None, h=None, m=None, v=None, val=None, default=None, input=None, output=None, solution=None, metric=None, A=None, ar=None, hausd=None, hgrad=None, hmax=None, hmin=None, hsiz=None, lag=None, ls=None, _3dMedit=None, noinsert=None, nomove=None, nosurf=None, noswap=None, nr=None, nreg=None, nsd=None, optim=None, opnbdy=None, rmc=None)
Run mmg2d_O3 from the command line with given arguments.
- static mmg3d(d=None, h=None, m=None, v=None, val=None, default=None, input=None, output=None, solution=None, metric=None, A=None, ar=None, octree=None, hausd=None, hgrad=None, hmax=None, hmin=None, hsiz=None, lag=None, ls=None, nofem=None, noinsert=None, nomove=None, nosurf=None, noswap=None, nr=None, nreg=None, nsd=None, optim=None, optimLES=None, opnbdy=None, rmc=None, rn=None)
Run mmg3d_O3 from the command line with given arguments.
- static mmgs(d=None, h=None, m=None, v=None, val=None, default=None, input=None, output=None, solution=None, metric=None, A=None, ar=None, hausd=None, hgrad=None, hmax=None, hmin=None, hsiz=None, ls=None, noinsert=None, nomove=None, nosurf=None, noswap=None, nr=None, nreg=None, nsd=None, optim=None, rn=None)
Run mmgs_O3 from the command line with given arguments.
- exception microgen.external.MmgError
Bases:
ExceptionRaised when an mmg command fails.
- class microgen.external.Neper
Bases:
objectWrapper around the
nepercommand-line tool.- static parse_tess(filename: str) dict[str, dict]
Parse a tessellation (.tess) file generated by neper.
Returns a dictionary with keys
cells,vertices,edges,faces,polyhedra. Follows the .tess structure from `neper's documentation`_.
- static run(filename: str, n_cells: int, cube_dim: tuple[float, float, float]) None
Run a neper tessellation from the command line.
Equivalent to:
neper -T -n n_cells -id 1 -dim 3 \ -domain 'cube(cube_dim[0], cube_dim[1], cube_dim[2])' \ -morpho gg -o filename
- Parameters:
filename – output file
n_cells – number of cells of the tessellation
cube_dim – see `neper's documentation`_
- static voronoi_from_tess_file(filename: str) list[Polyhedron]
Build
Polyhedronshapes from a neper-generated .tess file.