{ "cells": [ { "cell_type": "markdown", "id": "md-title", "metadata": {}, "source": [ "# HEDM scan simulation and stitching\n", "\n", "Generate a synthetic crystal, simulate overlapping HEDM z-scans, stitch the scan layers into one grain set, and compare the stitched result against the ground truth. Use this to test or study HEDM stitching, examine the effect of scan overlap, or produce a stitched FF CSV from multiple scan layers.\n", "\n", "**Needs:** NEPER (crystal generation and z-scan). No MOOSE or CUBIT.\n", "\n", "
\n", "

Tier B: needs NEPER

\n", "

This notebook needs the neper binary, 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": "md-inputs", "metadata": {}, "source": "## Inputs\n\nThe example is self-generating: `CrystalGenerator` writes a `voronoi.tess` / `voronoi.csv` and a set of `hedm_scan/scan_{i}.csv` layers. For real data, feed your own per-scan CSVs to the stitcher: whitespace- or comma-delimited FF grain tables with `X,Y,Z,GrainRadius,Eul0/1/2,eKen*`, each layer already Z-shifted. See [the raw FF format](../concepts.rst)." }, { "cell_type": "markdown", "id": "md-recipe", "metadata": {}, "source": "## Recipe" }, { "cell_type": "code", "execution_count": null, "id": "code-recipe", "metadata": {}, "outputs": [], "source": "from graintrace.generate_random_crystal import CrystalGenerator\nfrom graintrace.hedm_stitching_techniques.region_base_stitching import RegionBaseStitching\nfrom graintrace.scan_stitching_comparison import ScanStitchingComparison\n\nbounding_box = [-500, 500, -500, 500, -1000, 500]\nnscan, overlap_percentage = 4, 25\n\ncg = CrystalGenerator(output_dir=\"hedm_out\", bounding_box=bounding_box, seed=42)\ncg.generate_tessellation(morpho_args={\"type\": \"diameq\", \"distribution\": \"lognormal\",\n \"params\": (130.0, 5.0)})\ncg.hedm_zscan(tess_file=\"hedm_out/voronoi.tess\", nstep=nscan,\n overlap_percentage=overlap_percentage,\n position_noise_std=0.0, orientation_noise_std=0.0, radius_noise=0.0,\n noise_seed=42)\n\nscan_files = [f\"hedm_out/hedm_scan/scan_{i}.csv\" for i in range(nscan)]\nstitcher = RegionBaseStitching(\n scan_files=scan_files, output_csv=\"hedm_out/stitched.csv\",\n position_tolerance=20, orientation_tolerance=1, radius_tolerance=0,\n weights={\"pos\": 0.1, \"ori\": 1.0, \"rad\": 0}, min_neighbors=5,\n)\nstitched = stitcher.run(zlo=bounding_box[4], zhi=bounding_box[5],\n overlap_fraction=overlap_percentage / 100.0)\n\nScanStitchingComparison(\n output_dir=\"hedm_out/comparison\", true_csv=\"hedm_out/voronoi.csv\",\n stitch_csv=\"hedm_out/stitched.csv\", position_tolerance=20,\n orientation_tolerance=5.0, radius_tolerance=0,\n weights={\"pos\": 0.1, \"ori\": 1.0, \"rad\": 0},\n).run_comparison()" }, { "cell_type": "markdown", "id": "md-key-params", "metadata": {}, "source": "## Key parameters\n\n- `morpho_args`: grain morphology passed to `CrystalGenerator` (see [microstructure generation](microstructure-generation.ipynb)).\n- `nscan`, `overlap_percentage`: number of z-scan layers and their overlap.\n- Noise, each applied only when greater than zero, with `noise_seed` for reproducibility: `position_noise_std` (absolute centroid std, length units), `orientation_noise_std` (proper misorientation, degrees), `radius_noise` (relative fraction). `remove_minimum_volume` / `min_vol` drop small grains.\n- Stitch: `position_tolerance` (length), `orientation_tolerance` (degrees), `weights`, `min_neighbors`.\n- Alternative stitchers: `NaiveStitching` and `RegionBaseStitching`.\n\nRegion classification (deciding which duplicate grain to trust or merge) uses each grain's z-extent. By default this is the equivalent-sphere estimate `z \u00b1 GrainRadius`. For elongated grains, `refine_extents=True` uses a NEPER tessellation to recover the true per-cell `[zmin, zmax]`; this re-tessellates at each fold step and is slower. See [the pitfalls page](../pitfalls.rst) for the limits of extent recovery from FF observables." }, { "cell_type": "markdown", "id": "md-outputs", "metadata": {}, "source": "## Outputs\n\n- `hedm_out/stitched.csv`: the merged single grain set.\n- `hedm_out/comparison/`: stitched-vs-true comparison from `ScanStitchingComparison`." }, { "cell_type": "markdown", "id": "md-gotchas", "metadata": {}, "source": "## Gotchas\n\n- `orientation_tolerance` is in degrees here. If a downstream step uses radians, convert with `np.deg2rad`; see [the pitfalls page](../pitfalls.rst).\n- Set `radius_tolerance=-1` to disable the radius gate in the match cost." }, { "cell_type": "markdown", "id": "md-full-script", "metadata": {}, "source": "**Full script:** [examples/demonstrate_hedm_study.py](https://github.com/applied-material-modeling/graintrace/blob/main/examples/demonstrate_hedm_study.py)" } ], "metadata": { "nbsphinx": { "execute": "never" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }