Microstructure generation#
Overview#
Synthesis of a random polycrystalline microstructure with a prescribed grain-size and
grain-shape distribution, for use as synthetic test data or as a CPFE input. The stage is driven
by CrystalGenerator, which drives NEPER to build a Voronoi tessellation from
a morphology specification and can derive HEDM-like scan CSVs from it.
Method#
A microstructure is generated by tessellating a domain to a NEPER morphology (-morpho)
specification. Unlike FF Voronoi/CVT tessellation, there is no measured data: the seeds are not
given, and NEPER’s morphology optimiser places and shapes cells until the realised population
matches a requested distribution. The result is a statistically specified microstructure,
reproducible from a seed, with exact ground truth – which is what makes it the right input
for testing every downstream stage.
Morphology types#
morpho_args is a dict whose "type" selects one of seven forms. The type also decides
how the grain count is set, which is the part most easily got wrong:
|
Required keys |
|
Grain count |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
verbatim |
|
from_morpho means NEPER derives the number of cells from the requested size distribution
and the domain volume. That is the behaviour you want for a size-specified microstructure –
asking for both a mean diameter and a cell count over-determines the domain – but it means
the grain count is an output, not an input on those paths. If you need an exact count,
use "columnar"/"bamboo", or "raw" with an explicit n.
Note n means two different things in the table: for "lamellar" it is the number of
lamellae within the morphology string, for "columnar"/"bamboo" it is the total number
of cells.
Size distributions#
"diameq" constrains the equivalent diameter \(d_{\mathrm{eq}}\), the diameter of
the sphere of equal volume; "size" constrains the cell volume directly. They are not
interchangeable, and the difference is a cube:
A distribution that is lognormal in \(d_{\mathrm{eq}}\) is therefore not lognormal in
volume with the same parameters, and the spread looks very different between the two. Prefer
"diameq": it is the quantity HEDM reports as GrainRadius, so a generated structure
and a measured one are then described in the same variable.
params is a positional tuple whose length and meaning follow the distribution:
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
The tuple is validated for length and then emitted comma-joined into the NEPER string
verbatim; the parameters’ precise meaning is NEPER’s, so check its -morpho documentation
rather than assuming a convention (lognormal, in particular, takes the mean and standard
deviation of the variable itself, not of its logarithm).
Shape, and the raw escape hatch#
The six structured types cover size and the layered/columnar families. Everything else –
grain elongation, bimodal mixtures, any multi-term morphology – goes through "raw",
which passes its morpho_str to NEPER untouched. Elongation in particular has no structured
type:
morpho_args = {
"type": "raw",
"morpho_str": "diameq:lognormal(130,5),aspratio(1,1,3)",
}
aspratio(a,b,c) gives cells elongated 3:1 along the third axis here. That is the generator
behind the anisotropic-stitching benchmark, where the point is precisely that FF observables
cannot recover such a shape (see FF Voronoi/CVT tessellation).
NEPER performs the tessellation and the morphology optimisation; graintrace validates the morphology dict, assembles the string and domain, and parses the results.
Algorithm#
Validate the requested morphology type and its distribution parameters against the schema.
Assemble the NEPER
-morphostring, the domain, and the grain-count argument (-n from_morphoor an explicit count, per the table above).Invoke
neper -Twith-id <seed>,-oridescriptor euler-bunge, and-statcell id,vol,w,x,y,z,radeq, stopping the optimiser atiterations.Join the per-cell statistics and the orientation file into
voronoi.csv; optionally derive HEDM-like z-scan CSVs for stitching/reconstruction studies.Recommended check: compare the realized grain-size/shape distribution against the request.
Parameters that matter#
See Configuration reference for the full list.
bounding_boxanddim: domain extent and dimensionality (2 or 3). The domain volume together with the size distribution is what fixes the grain count on thefrom_morphopaths.morpho_args: the type and its keys, per the tables above.iterations: the morphology optimiser’s budget (-morphooptistop iter=). The default is 10, which is a fast-and-loose setting – fine for a smoke test, too few for a realised distribution that actually matches the request. The FF reconstruction path uses 1000 by comparison. Raise it and re-check the realised statistics before trusting a generated structure as a benchmark.seed: passed to NEPER as-id.None(default) draws a fresh random seed each run and prints it, so an interesting run can be reproduced after the fact; pass an int up front for a deterministic one. Verified: the same seed gives a byte-identical tessellation, a different seed gives different grains.extra_neper_args: appended to the command verbatim, for NEPER flags graintrace does not wrap.
Further details#
For the full morphology-generation and tessellation-optimization algorithm, see the NEPER
documentation: https://neper.info/doc/ (-morpho options).
See also#
Tutorial: Microstructure generation
API:
CrystalGenerator