Workflows ========= .. contents:: On this page :local: :depth: 2 This page shows complete, annotated code examples for common UPXO tasks. All examples follow patterns taken directly from the demo notebooks in ``src/upxo/demos/``. .. note:: UPXO reads simulation parameters from an Excel dashboard file (``input_dashboard.xls``). The examples below use a placeholder path — replace it with the path to your own dashboard file. Template dashboards are provided under ``src/upxo/interfaces/user_inputs/``. ---- Workflow 1 — MCGS2D: Simulate, Detect Grains, Characterise ------------------------------------------------------------ This is the standard MCGS2D pipeline, equivalent to what ``gschar1.ipynb`` demonstrates. .. code-block:: python from upxo.ggrowth.mcgs import mcgs # Step 1 — Load dashboard and run the MC simulation pxt = mcgs(input_dashboard='path/to/input_dashboard.xls') pxt.simulate() # Step 2 — Detect grains at every saved time slice pxt.detect_grains() # Step 3 — Pick a time slice # pxt.m is the list of saved MCS step indices tslice = pxt.m[-1] # last saved step gs = pxt.gs[tslice] # mcgs2_grain_structure object # Step 4 — Characterise: request exactly the properties you need gs.char_morph_2d( use_version=2, npixels=True, area=True, aspect_ratio=True, solidity=True, circularity=True, char_gb=False, make_skim_prop=True, get_grain_coords=True, ) # Step 5 — Inspect results print(f"Number of grains: {gs.n}") print(gs.prop.columns.tolist()) # shows which columns were computed print(gs.prop.head()) Properties are only present in ``gs.prop`` if the matching flag was set to ``True`` in the ``char_morph_2d`` call. Available flags include: ``npixels``, ``area``, ``aspect_ratio``, ``solidity``, ``circularity``, ``eccentricity``, ``major_axis_length``, ``minor_axis_length``, ``perimeter``, ``eq_diameter``, ``compactness``, ``morph_ori``, ``euler_number``. ---- Workflow 2 — Visualise the Labelled Grain Image ------------------------------------------------- After ``detect_grains()``, the labelled grain image is stored in ``gs.lgi``. .. code-block:: python import matplotlib.pyplot as plt tslice = pxt.m[-1] gs = pxt.gs[tslice] plt.figure() plt.imshow(gs.lgi, cmap='tab20') plt.colorbar(label='Grain ID') plt.title(f'MCGS2D — tslice {tslice}, {gs.n} grains') plt.axis('off') plt.tight_layout() plt.show() To visualise the raw MC spin state (before grain detection): .. code-block:: python plt.imshow(pxt.S, cmap='nipy_spectral') plt.title('MC spin state (final)') plt.show() ---- Workflow 3 — Grain Size Distribution -------------------------------------- Request ``npixels=True`` (pixel count per grain) when calling ``char_morph_2d``, then plot the distribution. .. code-block:: python import matplotlib.pyplot as plt gs.char_morph_2d(use_version=2, npixels=True, make_skim_prop=True) pixel_counts = gs.prop['npixels'].values plt.figure() plt.hist(pixel_counts, bins=20, edgecolor='k') plt.xlabel('Grain size (pixels)') plt.ylabel('Count') plt.title('Grain size distribution') plt.tight_layout() plt.show() ---- Workflow 4 — Grain Neighbourhood ---------------------------------- .. code-block:: python tslice = pxt.m[-1] gs = pxt.gs[tslice] # Characterise first so bounding boxes exist for the neighbour search gs.char_morph_2d(use_version=2, bbox=True, bbox_ex=True, make_skim_prop=True) # Compute neighbours for every grain gs.find_neigh(include_central_grain=False, print_msg=True, use_numba=True) # Neighbours of grain with ID 10 print(gs.neigh_gid[10]) .. note:: A known bug in some builds causes the central grain to appear in its own neighbour list when ``include_central_grain=False``. The workaround used in the demo notebooks is: .. code-block:: python for gid in gs.neigh_gid.keys(): if gid in gs.neigh_gid[gid]: gs.neigh_gid[gid].remove(gid) ---- Workflow 5 — Finding Small Grains and Boundary Grains ------------------------------------------------------- Use the ``gid_ops`` module to query the labelled image directly. .. code-block:: python import upxo.gsdataops.gid_ops as gidOps lfi = gs.lgi # Grains with 5 pixels or fewer small_grains = gidOps.find_small_fids(lfi, threshold=5) print("Small grain IDs:", small_grains) # Grains whose pixels touch the domain boundary boundary_grains = gidOps.find_boundary_fids2d(lfi) print("Boundary grain IDs:", boundary_grains) ---- Workflow 6 — Resampling and Rescaling the Grid ------------------------------------------------ Use ``grid_ops`` to change the resolution of the state array or labelled image. .. code-block:: python from upxo.gsdataops.grid_ops import resample_grid_2d, rescale_grid_2d # Downsample by factor 0.25 using the simulation's own grid object resampled, x_new, y_new, xinc_new, yinc_new = resample_grid_2d( pxt.S, pxt.uigrid, sf=0.25, method='nearest' ) print("Original shape:", pxt.S.shape) print("Resampled shape:", resampled.shape) # Rescale to twice the resolution scaled = rescale_grid_2d(pxt.S, scale_factor=2, method='nearest') print("Scaled shape:", scaled.shape) ---- Workflow 7 — Merging Small Grains ----------------------------------- Single-pixel or sub-threshold grains can be absorbed into their largest neighbour before downstream analysis. .. code-block:: python import numpy as np from upxo.pxtalops.gssmooth2d import _merge_small_grains lfi = gs.lgi lfi_clean = _merge_small_grains(lfi, area_threshold=3) print("Unique grains before:", len(np.unique(lfi))) print("Unique grains after :", len(np.unique(lfi_clean))) ---- Workflow 8 — Comparing Grain Size Across Time Slices ------------------------------------------------------ Iterate over saved time slices to track how mean grain size evolves. .. code-block:: python import numpy as np import matplotlib.pyplot as plt mean_sizes = [] for tslice in pxt.m: gs = pxt.gs[tslice] gs.char_morph_2d(use_version=2, npixels=True, make_skim_prop=True) mean_sizes.append(gs.prop['npixels'].mean()) plt.figure() plt.plot(pxt.m, mean_sizes, marker='o') plt.xlabel('Monte-Carlo step (tslice)') plt.ylabel('Mean grain size (pixels)') plt.title('Grain growth kinetics') plt.tight_layout() plt.show() ---- Next Steps ---------- - :doc:`concepts` — understand the data model behind these examples - `API Reference `_ — full module and class documentation - `Grain Characterisation wiki `_ — extended characterisation workflows - `Visualisation wiki `_ — 2D and 3D plotting - `Meshing wiki `_ — FE mesh generation