{ "cells": [ { "cell_type": "markdown", "id": "nfff-intro", "metadata": {}, "source": [ "# CPFE (NF geometry + FF initial strain)\n", "\n", "Run a combined near-field + far-field CPFE simulation: the NF reconstruction supplies the high-resolution hex mesh and per-element orientations, while the FF reconstruction supplies the initial elastic-strain (residual-strain) field. Use this when you want to drive CPFE from an NF mesh with an FF residual-strain initial condition, optionally end to end from synthetic HEDM.\n", "\n", "**Needs:** the native stack: NEPER (FF/synthetic), CUBIT/SCULPT (NF mesh), MOOSE `puma-opt` + `neml2-compile`.\n", "\n", "
\n", "

Tier B: needs the full native stack

\n", "

This notebook needs neper, CUBIT's psculpt/epu, and puma-opt, 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": "nfff-inputs", "metadata": {}, "source": "## Inputs\n\n- An NF mesh and orientations, from [NF reconstruction](nf-reconstruction.ipynb) (`NearFieldMeshBuilder`): `mesh.e` plus a per-element MRP `orientations.csv`.\n- An FF per-grain elastic-strain file, from [FF reconstruction](ff-reconstruction.ipynb) (`VoronoiMeshBuilder` with `generate_mesh=False`): `reconstruction_cpfe_ee.csv`.\n\nIf the NF and FF data are not co-registered, shift the FF `x, y, z` into the NF frame first (see below). A synthetic HEDM generator can produce both stages when you do not have experimental data." }, { "cell_type": "markdown", "id": "nfff-pipeline", "metadata": {}, "source": "## Pipeline\n\n1. (optional) Generate synthetic HEDM, writing an FF CSV and NF layers.\n2. Build the NF mesh: `NearFieldMeshBuilder.reconstruct` then `NearFieldMeshBuilder.mesh` produce `mesh.e` and `orientations.csv`.\n3. Build the FF residual strain: `build_voronoi(generate_mesh=False, ...)` produces `reconstruction_cpfe_ee.csv`.\n4. Run CPFE with the NF mesh, NF orientations, and the FF strain field." }, { "cell_type": "markdown", "id": "nfff-recipe-md", "metadata": {}, "source": "## Recipe\n\nShift the FF elastic-strain file into the NF frame when the two are not co-registered:" }, { "cell_type": "code", "id": "nfff-shift-code", "metadata": {}, "execution_count": null, "outputs": [], "source": "import pandas as pd\n\nff_translation = (dx, dy, dz) # from experiment geometry\nee = pd.read_csv(\"out/ff_reconstruction/reconstruction_cpfe_ee.csv\",\n header=None, index_col=False)\nee.iloc[:, 0] += ff_translation[0]\nee.iloc[:, 1] += ff_translation[1]\nee.iloc[:, 2] += ff_translation[2]\nee.to_csv(\"out/ff_reconstruction/reconstruction_cpfe_ee_shifted.csv\",\n index=False, header=False)" }, { "cell_type": "markdown", "id": "nfff-run-md", "metadata": {}, "source": "Run the simulation:" }, { "cell_type": "code", "id": "nfff-run-code", "metadata": {}, "execution_count": null, "outputs": [], "source": "from graintrace.run_cpfe_simulation import CPFESimulation\n\nsim = CPFESimulation(\n mesh_file=\"out/nf_reconstruction/mesh.e\",\n save_simulation_folder=\"out/simulation\",\n eeres_file=\"out/ff_reconstruction/reconstruction_cpfe_ee_shifted.csv\",\n ori_file=\"out/nf_reconstruction/orientations.csv\",\n dim=3, element_order=\"FIRST\", # NF meshes are typically FIRST order\n moose_run_file=\"external/puma/puma-opt\", # your built puma-opt\n use_ff_initial_field=False, # ee comes from a DIFFERENT mesh\n)\nsim.set_parameters(\"material\", ...) # see the material-calibration tutorial\nsim.set_parameters(\"simulation_parameters\",\n device=\"cuda:0\", device_batch=1000,\n dt=0.5, total_time=2.0, initialize_time=1.0, sync_times=\"2.0\")\nsim.set_parameters(\"boundary\", bounding_box=nf_bbox, bc={...})\nsim.set_parameters(\"grid_properties\",\n number_of_elements=[10, 10, 10], bounding_box=grid_bb)\nsim.run(ncore=8)" }, { "cell_type": "markdown", "id": "nfff-key-params", "metadata": {}, "source": "## Key parameters\n\n- `use_ff_initial_field`: `False` when `eeres_file` comes from a different mesh than the geometry (FF strain on an NF mesh); `True` only when mesh and strain file are co-registered FF.\n- FF-to-NF shift: add `(dx, dy, dz)` to the first three columns of `reconstruction_cpfe_ee.csv` to align frames before passing it as `eeres_file`.\n- `nf_bbox`: derive from the NF `merged_segmented_fixed_grid.npy` coordinates (see [configuration](../configuration.rst)).\n- `sculpt_config`: configures the NF hex mesh (see [configuration](../configuration.rst)).\n- CPFE material, simulation, boundary, and grid parameters follow [CPFE simulation](cpfe-simulation.ipynb)." }, { "cell_type": "markdown", "id": "nfff-gotchas", "metadata": {}, "source": "## Gotchas\n\n- The same NEML2 v3 AOTI notes as [CPFE simulation](cpfe-simulation.ipynb) apply: material parameters are baked into the model and compiled on `run()`; there are no runtime schedulers; a device list maps to MPI ranks.\n- NF reconstruction uses multiprocessing, so the driver must sit under an `if __name__ == \"__main__\":` guard.\n- `moose_run_file` must point at your built v3 `puma-opt`." }, { "cell_type": "markdown", "id": "nfff-full-example", "metadata": {}, "source": "## Full example\n\n**Full script:** [examples/demonstrate_cpfe_nfff.py](https://github.com/applied-material-modeling/graintrace/blob/main/examples/demonstrate_cpfe_nfff.py)" } ], "metadata": { "nbsphinx": { "execute": "never" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }