{ "cells": [ { "cell_type": "markdown", "id": "msh-intro", "metadata": {}, "source": [ "# Meshing a grain grid into hex\n", "\n", "Turn a voxel or tessellation grain grid into a hexahedral CPFE mesh with `VoxelMeshBuilder`. Two paths are available through `VoxelMeshBuilder.mesh()`: `mesher=\"sculpt\"` builds a conformal hex mesh with CUBIT/SCULPT, and `mesher=\"voxel\"` writes a direct voxel-to-Exodus dump with no external tools. The recommendations below come from a 12-case microstructure study.\n", "\n", "**Needs:** CUBIT/SCULPT for the `sculpt` path (the `voxel` path needs no external tools).\n", "\n", "
\n", "

Tier B: needs CUBIT/SCULPT

\n", "

This notebook needs CUBIT's psculpt and epu, which is not available in CI or Google Colab, so it is not executed when these docs are built. It ships as an annotated code listing with no stored output \u2014 nothing on this page is a hand-written or fabricated result. Run it in a configured environment (see the installation guide) to produce the figures, and run it from the repository root so the mwe_data/ paths resolve.

\n", "
" ] }, { "cell_type": "markdown", "id": "msh-inputs", "metadata": {}, "source": [ "## Inputs\n", "\n", "A segmented grain grid (from a reconstruction or generation step) plus the Euler columns and crystal symmetry. The same `mesh()` entry point is shared by `NearFieldMeshBuilder` and by `VoronoiMeshBuilder` (`build_voronoi(generate_mesh=True)`). Grid generation lives in [concepts](../concepts.rst); see also [ff-reconstruction](ff-reconstruction.ipynb) for producing `reconstruction_reformatted.csv`." ] }, { "cell_type": "markdown", "id": "msh-sculpt-md", "metadata": {}, "source": [ "## SCULPT conformal mesh" ] }, { "cell_type": "code", "execution_count": null, "id": "msh-sculpt-code", "metadata": {}, "outputs": [], "source": [ "from graintrace.construct_voxel_mesh import VoxelMeshBuilder\n", "\n", "builder = VoxelMeshBuilder(\n", " file_path=\"voronoi.csv\", save_dir=\"out/mesh\",\n", " euler_cols=[\"Eul0\", \"Eul1\", \"Eul2\"],\n", " angle_convention=\"bunge\", angle_type=\"degrees\", symmetry=\"432\",\n", ")\n", "builder.mesh(\n", " sculpt_config={\n", " \"psculpt\": \"/path/to/cubit/bin/psculpt\",\n", " \"epu\": \"/path/to/cubit/bin/epu\",\n", " \"nprocs\": 4, # <= physical cores\n", " },\n", " sculpt_options=SCULPT_OPTS, # one of the two configs below\n", " merged_grid=merged_grid_path,\n", ")" ] }, { "cell_type": "markdown", "id": "msh-sculpt-configs", "metadata": {}, "source": [ "Only two `sculpt_options` configs are recommended, both keeping `-df 1` (defeaturing) safe. See [configuration](../configuration.rst) for the full `sculpt_config` and `sculpt_options` reference.\n", "\n", "- `adapt4`: `(\"-A\", \"4\", \"-df\", \"1\", \"-S\", \"2\", \"-CS\", \"4\")`. Grain preservation at or above 98 percent, positive Scaled Jacobian. Adapt-type 4 refines without triggering aggressive small-grain absorption.\n", "- `df1`: `(\"-df\", \"1\", \"-mvs\", \"2\", \"-S\", \"2\", \"-CS\", \"5\")`. Grain preservation at or above 95 percent, positive Scaled Jacobian. `-mvs 2` (minimum voxel size for defeaturing) prevents `-df 1` from swallowing larger grains." ] }, { "cell_type": "markdown", "id": "msh-voxel-md", "metadata": {}, "source": [ "## Direct voxel dump" ] }, { "cell_type": "code", "execution_count": null, "id": "msh-voxel-code", "metadata": {}, "outputs": [], "source": [ "builder.mesh(mesher=\"voxel\", merged_grid=merged_grid_path)\n", "# -> mesh.e (HEX8, one block per grain, ids 1..N) + .csv (MRP)" ] }, { "cell_type": "markdown", "id": "msh-voxel-notes", "metadata": {}, "source": [ "- One axis-aligned cube hex per voxel. Scaled Jacobian is 1 everywhere, so there are no inverted or sliver elements and grain preservation is 100 percent by construction. Needs no `sculpt_config` or CUBIT.\n", "- Trade-offs: stair-stepped grain boundaries (not smoothed) and a fixed one hex per filled voxel (element count equals voxel count). Control resolution through the tesr/grid size.\n", "- Use it when SCULPT smoothing produces bad elements (junction slivers) or when a guaranteed-clean mesh matters more than boundary smoothness." ] }, { "cell_type": "markdown", "id": "msh-outputs", "metadata": {}, "source": "## Outputs\n\n- `mesh.e`: Exodus hex mesh, one block per grain.\n- `.csv`: per-element MRP orientations for CPFE." }, { "cell_type": "markdown", "id": "msh-gotchas", "metadata": {}, "source": [ "## Gotchas\n", "\n", "- Verify before running CPFE. For the SCULPT path, check all three; the voxel path guarantees the first two by construction, so only the last matters there:\n", "\n", " 1. Grain preservation: `N_mesh / N_tess` at or above 98 percent for `adapt4`, 95 percent for `df1`. Lower means defeaturing has silently absorbed grains.\n", " 2. Minimum Scaled Jacobian above 0, not just the mean. A single negative-SJ element will crash the MOOSE simulation.\n", " 3. Mesh-vs-tess grain-size distribution check.\n", "\n", "- `-df 1` on its own eats grains. Without `-A 4` or `-mvs 2` it silently absorbs a large fraction of grains at 100 cubed voxels.\n", "- Do not override the smoothing method (`-S`) on irregular voxel meshes. Forcing smoothing after guaranteed-quality smoothing can diverge (minimum SJ driven to -1) and segfault SCULPT. Prefer the two configs above, or use `mesher=\"voxel\"`.\n", "- Use the minimum number of grains that faithfully represents the target distribution. Fewer grains means fewer elements and a tractable CPFE wall-clock; add grains only when the distribution or the CPFE quantity of interest does not converge." ] }, { "cell_type": "markdown", "id": "msh-full-example", "metadata": {}, "source": [ "## Full example\n", "\n", "**Full script:** [examples/demonstrate_synthetic_cpfe.py](https://github.com/applied-material-modeling/graintrace/blob/main/examples/demonstrate_synthetic_cpfe.py)" ] } ], "metadata": { "nbsphinx": { "execute": "never" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }