upxo.gsdataops.grid_ops module

Grid operations for Labelled Feature Image workflows.

This module provides utilities for sectioning, interpolation/resampling, bounding-box extraction, feature-ID transformations, neighborhood-aware smoothing, and synthetic LFI test-pattern generation in 2D/3D.

Imports

import upxo.gsdataops.grid_ops as gridOps

Metadata

  • Module: upxo.gsdataops.grid_ops

  • Package: upxo

  • License: GPL-3.0-only

  • Author: Dr. Sunil Anandatheertha

  • Email: vaasu.anandatheertha@ukaea.uk

  • Status: Active development

  • Last updated: 2026-03-12

Applications

  • 2D/3D Labelled Feature Image section extraction

  • Grid upscaling/downscaling and anisotropic stretching

  • Per-feature extended bounding-box extraction

  • Feature-ID shuffling and merge operations

  • Majority-filter smoothing for grain-label fields

  • Seed generation and synthetic LFI benchmark creation

Definitions

  • LFI: Labelled Feature Image

upxo.gsdataops.grid_ops.section_from_3d(db, axis=0, location=0)[source]

Extract a 2D section from a 3D grid along a specified axis.

Parameters:
  • db (ndarray) – 3D input array from which to extract the section.

  • axis (int, optional) – Axis along which to take the section (0, 1, or 2). Default is 0.

  • location (int, optional) – Location index along the specified axis to extract the section. Default is 0.

upxo.gsdataops.grid_ops.build_pvgrid(data=None, origin=(0, 0, 0), spacing=(1.0, 1.0, 1.0))[source]

Build a PyVista ImageData grid from a NumPy array.

Parameters:
  • data (ndarray, optional) – Input scalar array to assign as cell data.

  • origin (tuple, optional) – Grid origin coordinates.

  • spacing (tuple, optional) – Grid spacing along each axis.

Returns:

Configured PyVista image grid.

Return type:

pyvista.ImageData

upxo.gsdataops.grid_ops.mask_featIDImg_at_coords(featIDImg, bsegCoords, local_seg_ids, featName='fbseg', maskDType=numpy.int32)[source]

Example

mask_featIDImg_at_coords(lgi_boundaries, bsegCoords, local_seg_ids,

featName=’fbseg’, maskDType=np.int32)

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.mask_featIDImg_at_coords

upxo.gsdataops.grid_ops.find_feature_extended_bbox_pix(fid=None, lfi=None, make_binary=False)[source]

Find the extended bounded box of a given fid in a 2D local feature ID array.

Parameters:
  • fid (int) – Feature ID for which to find the extended bounding box. Feature ID is generally the grain ID. Default is None.

  • lfi (np.ndarray) – 2D Labelled Feature Image. Default is None.

  • make_binary (bool, optional) – If True, the returned bounding box array is a binary mask. Default is False.

Returns:

feat_lfi_ExtBBox – Extended bounding box of the specified feature ID.

Return type:

np.ndarray

Example

from upxo.ggrowth.mcgs import mcgs pxtal = mcgs(study=’independent’,

input_dashboard=’input_dashboard_for_testing_50x50_alg202.xls’)

pxtal.simulate() pxtal.detect_grains() pxtal.gs[16].find_extended_bounding_box(10)

Notes

Applicable only for 2D grain structures of pixellated type.

The extended bounding box adds a one-pixel margin around the feature’s actual bounding box, taking care to handle edge cases where the feature touches the edges of the array. You could also use this function independently to find the extended bounding box of any feature in a 2D local feature ID array. For example, youcould use this to find the extended bounding box of a given grain boundary segment ID in a grain boundary segment local feature ID array. You could use either local or global feature IDs for this purpose, but make sure to use the right lfi array.

Comments

The line pxtal.gs[16].find_extended_bounding_box(fid) is an orchestrator function call in the temporal slice object. The present function is called internally by that function.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.find_feature_extended_bbox_pix

upxo.gsdataops.grid_ops.find_extended_bbox_pix_fids(fids=None, lfi=None, make_binary=False)[source]

Find the extended bounded box of a given fid in a 2D local feature ID array.

Parameters:
  • fid (int) – Feature ID for which to find the extended bounding box. Feature ID is generally the grain ID. Default is None.

  • lfi (np.ndarray) – 2D Labelled Feature Image. Default is None.

  • make_binary (bool, optional) – If True, the returned bounding box arrays are binary masks. Default is False.

Returns:

bboxes – Dictionary with feature IDs as keys and their extended bounding boxes as values.

Return type:

dict

Notes

Refer to find_feature_extended_bbox_pix for detailed documentation.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.find_extended_bbox_pix_fids

upxo.gsdataops.grid_ops.find_extended_bounding_box_all_grains(fids=None, lfi=None, make_binary=False)[source]

Return extended bounding boxes for all requested feature IDs.

Parameters:
  • fids (int or iterable, optional) – Feature IDs to process.

  • lfi (ndarray, optional) – 2D Labelled Feature Image.

  • make_binary (bool, optional) – If True, output bounding boxes as binary masks.

Returns:

Mapping fid -> extended bounding-box array.

Return type:

dict

From upxo.gsdataops.grid_ops.find_extended_bbox_pix_fids:

Find the extended bounded box of a given fid in a 2D local feature ID array.

Parameters:
  • fid (int) – Feature ID for which to find the extended bounding box. Feature ID is generally the grain ID. Default is None.

  • lfi (np.ndarray) – 2D Labelled Feature Image. Default is None.

  • make_binary (bool, optional) – If True, the returned bounding box arrays are binary masks. Default is False.

Returns:

bboxes – Dictionary with feature IDs as keys and their extended bounding boxes as values.

Return type:

dict

Notes

Refer to find_feature_extended_bbox_pix for detailed documentation.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.find_extended_bbox_pix_fids

upxo.gsdataops.grid_ops.rescale_grid_2d(data, scale_factor, method='nearest')[source]

Rescale a 2D grid by a uniform scale factor using interpolation.

Parameters:
  • data (ndarray) – 2D input array to be rescaled.

  • scale_factor (float) – Uniform scaling factor to apply to both dimensions. Values > 1 enlarge the grid, values < 1 shrink it.

  • method (str, optional) – Interpolation method to use. Options are ‘nearest’, ‘linear’, etc. Default is ‘nearest’.

Returns:

  • ndarray – Rescaled 2D array with shape determined by scale_factor, maintaining the original data type.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

upxo.gsdataops.grid_ops.stretch_grid_2d(data, stretch_x=1.0, stretch_y=1.0, px_size_x=1.0, px_size_y=1.0, method='nearest')[source]

Stretch a 2D grid by different factors in each dimension while accounting for pixel size and physical dimensions.

Parameters:
  • data (ndarray) – 2D input array to be stretched.

  • stretch_x (float, optional) – Stretch factor in the x (width) dimension. Default is 1.0 (no stretch).

  • stretch_y (float, optional) – Stretch factor in the y (height) dimension. Default is 1.0 (no stretch).

  • px_size_x (float, optional) – Physical pixel size in the x dimension. Default is 1.0.

  • px_size_y (float, optional) – Physical pixel size in the y dimension. Default is 1.0.

  • method (str, optional) – Interpolation method to use. Options are ‘nearest’, ‘linear’, etc. Default is ‘nearest’.

Returns:

  • stretched_data (ndarray) – Stretched 2D array maintaining the original data type.

  • px_size_x (float) – Physical pixel size in the x dimension (unchanged).

  • px_size_y (float) – Physical pixel size in the y dimension (unchanged).

  • new_shape (tuple) – New shape of the stretched data as (new_h, new_w).

Notes

The stretch is applied to the physical dimensions of the grid, with final grid size determined by dividing new physical dimensions by pixel sizes.

Usage

import upxo.gsdataops.grid_ops as gridOps

upxo.gsdataops.grid_ops.resample_grid_2d(data, uigrid, sf=0.5, method='nearest')[source]

Resample a 2D array at every nth row and column.

Parameters:
  • data (np.ndarray) – 2D state matrix to resample

  • uigrid (object or None) – Grid configuration object with attributes: xmin, xmax, xinc, ymin, ymax, yinc. If None, grid attributes are inferred from data shape: xmin=ymin=0, xinc=yinc=1, xmax=data.shape[1]-1, ymax=data.shape[0]-1.

  • sf (float) – Sampling factor (0 < sf <= 1). sf=0.5 means every 2nd pixel, sf=0.33 means every 3rd pixel

  • method (str, optional) – Interpolation method (‘nearest’, ‘linear’, etc.). Default is ‘nearest’.

Returns:

  • resampled_data (np.ndarray) – Resampled 2D state matrix

  • x_new (np.ndarray) – New x grid coordinates

  • y_new (np.ndarray) – New y grid coordinates

  • xinc_new (float) – New x increment

  • yinc_new (float) – New y increment

upxo.gsdataops.grid_ops.rescale_grid_3d(data, scale_factor, method='nearest')[source]

Rescale a 3D grid by a uniform scale factor using interpolation.

Parameters:
  • data (ndarray) – 3D input array to be rescaled.

  • scale_factor (float) – Uniform scaling factor applied to all three dimensions. Values > 1 enlarge, values < 1 shrink.

  • method (str, optional) – Interpolation method. Options: ‘nearest’, ‘linear’, etc. Default is ‘nearest’.

Returns:

  • ndarray – Rescaled 3D array with shape determined by scale_factor, maintaining original dtype.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Call

  • —-

  • gridOps.rescale_grid_3d(data, scale_factor, method)

upxo.gsdataops.grid_ops.detect_grains_cc3d(image_data, connectivity=18, delta=0, return_num_grains=True, verbose=False)[source]

THe following documentation taken verbatim from https://seunglab.org/connected-components-3d/ to help UPXO users.

Only a littlbit of doicumentation has been provided below. For a comprehensive documentation, the user is referred to the above link.

# Only 4,8 (2D) and 26, 18, and 6 (3D) are allowed # By default, cc3d works on multivalued labelings

If you need the borders to wrap around specify periodic_boundary=True, currently only supported for 4 and 8 (2d) and 6 (3d) connectivities.

If you’re working with continuously valued images like microscopy images you can use cc3d to perform a very rough segmentation. If delta = 0, standard high speed processing. If delta > 0, then neighbor voxel values <= delta are considered the same component. The algorithm can be 2-10x slower though. Zero is considered background and will not join to any other voxel.

If you’re working with an image that’s larger than memory you can use mmapped files. The input and output files can be used independently. In this case an array labels.bin that is 5000x5000x2000 voxels and uint32_t in Fortran order is computed and the results are written to out.bin in Fortran order. You can find the properties of the file (shape, dtype, order) by inspecting labels_out. labels_in = np.memmap(“labels.bin”, order=”F”, dtype=np.uint32, shape=(5000, 5000, 2000)) labels_out = cc3d.connected_components(labels_in, out_file=”out.bin”)

Here’s another strategy that you can use for huge files that won’t even take up any disk space. Provide any iterator to this function that produces thick z sections of the input array that are in sequential order. The output is a highly compressed CrackleArray that is still random access. See: https://github.com/seung-lab/crackle You need to pip install connected-components-3d[stack] to get the extra modules.

def sections(labels_in): ‘’’ A generator that produces thick Z slices of an image ‘’’ for z in range(0, labels_in.shape[2], 100):

yield labels_in[:,:,z:z+100]

# You can access compressed_labels_out using array notation compressed_labels_out = cc3d.connected_components_stack(sections(labels)) # convert to numpy array, probably a big mistake since # you probably expected it was going to blow up RAM cc_labels = compressed_labels_out.numpy() # if you don’t like hanging onto this exotic format, you # can write it as a numpy array to disk in a memory efficient way. compressed_labels_out.save(“example.npy.gz”) # or hang onto it compressed_labels_out.save(“example.ckl”)

upxo.gsdataops.grid_ops.detect_grains_3d(state_array, connectivity=3, return_num_grains=False)[source]

Detect grains in a 3D Monte Carlo state array using connected component labeling.

Grains are identified as connected regions of voxels with the same state ID. Returns a grain ID (lfi - Local Feature ID) array with the same shape as input.

Parameters:
  • state_array (ndarray) – 3D integer array where each value represents a state ID (0 to S-1). Shape: (nx, ny, nz)

  • connectivity (int, optional) – Connectivity type for 3D neighbor detection: - 1: Face connectivity (6 neighbors, most restrictive) - 2: Face + edge connectivity (18 neighbors) - 3: Face + edge + corner connectivity (26 neighbors, default)

  • return_num_grains (bool, optional) – If True, returns tuple (lfi_array, num_grains). Default is False.

Returns:

  • lfi_array (ndarray) – 3D integer array of grain IDs with same shape as state_array. Grain IDs start from 1. Background (if any) is labeled 0.

  • num_grains (int (only if return_num_grains=True)) – Total number of grains detected.

Notes

  • Uses scipy.ndimage.label for connected component analysis

  • Connectivity=1 (6-neighbor) is strictest, useful for well-separated grains

  • Connectivity=3 (26-neighbor) is most common, matches typical grain definitions

  • Processing time scales with array size: ~0.1s for 100³, ~1s for 300³ voxels

  • Memory usage: ~2x input array size for intermediate calculations

Examples

>>> import numpy as np
>>> from upxo.gsdataops.grid_ops import detect_grains_3d
>>>
>>> # Simple 3D state array with two grains
>>> s = np.zeros((10, 10, 10), dtype=np.int16)
>>> s[:5, :, :] = 1  # State 1 in left half
>>> s[5:, :, :] = 2  # State 2 in right half
>>>
>>> # Detect grains
>>> lfi = detect_grains_3d(s)
>>> print(f"Grain IDs: {np.unique(lfi)}")  # [1, 2]
>>>
>>> # With grain count
>>> lfi, num_grains = detect_grains_3d(s, return_num_grains=True)
>>> print(f"Detected {num_grains} grains")
>>>
>>> # Use strict connectivity
>>> lfi_strict = detect_grains_3d(s, connectivity=1)

See also

scipy.ndimage.label

Underlying labeling function

upxo.ggrowth.mcgs.detect_grains

2D/3D grain detection in MCGS objects

upxo.gsdataops.grid_ops.detect_grains_3d_optimized(state_array, connectivity=3, return_num_grains=False)[source]

Detect connected grains in a 3D state array using grouped labeling.

Parameters:
  • state_array (ndarray) – 3D state array.

  • connectivity (int, optional) – Connectivity order for 3D labeling (1, 2, or 3).

  • return_num_grains (bool, optional) – If True, also return number of detected grains.

Returns:

3D Labelled Feature Image, optionally with grain count.

Return type:

ndarray or tuple

upxo.gsdataops.grid_ops.detect_grains_using_s(scalar_data, scalar_ids)[source]

Detect and relabel connected regions for selected scalar IDs.

Parameters:
  • scalar_data (ndarray) – 3D scalar/state field.

  • scalar_ids (iterable) – Scalar IDs to segment and relabel.

Returns:

3D Labelled Feature Image with unique global labels.

Return type:

ndarray

upxo.gsdataops.grid_ops.detect_grains_fast_v3(scalar_data, scalar_ids)[source]

Fast 3D grain labeling by state-wise grouped bounding-box labeling.

Parameters:
  • scalar_data (ndarray) – 3D scalar/state field.

  • scalar_ids (iterable) – Scalar IDs to include in detection.

Returns:

3D Labelled Feature Image.

Return type:

ndarray

upxo.gsdataops.grid_ops.detect_grains_greedy_3d(state_array)[source]

Detect 3D grains with greedy flood-fill using 26-neighbour traversal.

Parameters:

state_array (ndarray) – 3D state array.

Returns:

3D Labelled Feature Image.

Return type:

ndarray

upxo.gsdataops.grid_ops.shuffle_feature_IDs(lfi)[source]

Shuffle the feature IDs in a local feature ID array (lfi) while keeping the same number of features and their spatial distribution intact.

Parameters:

lfi (np.ndarray) – N-dimensional Labelled Feature Image.

Returns:

  • np.ndarray – Local feature ID array with shuffled feature IDs.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.shuffle_feature_IDs)

upxo.gsdataops.grid_ops.merge_features_to_neighs(lfi, fids, neigh_fids)[source]

Update the labelled feature ID array (lfi) by merging specified fids into their corresponding neighboring feature IDs (neigh_fids).

Parameters:
  • lfi (np.ndarray) – N-dimensional Labelled Feature Image.

  • fids (list or array-like) – List of feature IDs to be merged.

  • neigh_fids (dict) – Dictionary mapping each feature ID in fids to its neighboring feature ID.

Returns:

  • np.ndarray – Updated lfi array with specified fids merged into their neighbors.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.merge_features_to_neighs)

upxo.gsdataops.grid_ops.get_ball_footprint(fpSize, removeEndVox=True)[source]

Create a spherical morphology footprint for 3D operations.

Parameters:
  • fpSize (int) – Radius/size argument passed to skimage.morphology.ball.

  • removeEndVox (bool, optional) – If True, remove extremal voxels along each axis.

Returns:

3D boolean footprint.

Return type:

ndarray

upxo.gsdataops.grid_ops.smooth_voxMorph_npass(lfi, niterations=2, DILfpSizes=[4, 4], ERSfpSizes=[4, 4], footprints=['ball', 'ball'], removeEndVox=[True, True])[source]

Apply multiple morphology smoothing passes to a 3D LFI.

Parameters:
  • lfi (ndarray) – 3D Labelled Feature Image.

  • niterations (int, optional) – Number of smoothing passes.

  • DILfpSizes (list, optional) – Dilation footprint sizes per pass.

  • ERSfpSizes (list, optional) – Erosion footprint sizes per pass.

  • footprints (list, optional) – Footprint type per pass.

  • removeEndVox (list, optional) – End-voxel trimming flags per pass.

Returns:

Smoothed 3D Labelled Feature Image.

Return type:

ndarray

upxo.gsdataops.grid_ops.smooth_voxMorph_1pass(lfi, DILfpSize=4, ERSfpSize=4, footprint='ball', removeEndVox=True)[source]

Apply one morphology smoothing pass (dilation then erosion).

Parameters:
  • lfi (ndarray) – 3D Labelled Feature Image.

  • DILfpSize (int, optional) – Dilation footprint size.

  • ERSfpSize (int, optional) – Erosion footprint size.

  • footprint (str, optional) – Footprint type, currently 'ball'/'sphere'.

  • removeEndVox (bool, optional) – Reserved control for endpoint-voxel handling.

Returns:

Smoothed 3D Labelled Feature Image.

Return type:

ndarray

upxo.gsdataops.grid_ops.majority_filter_2d(lfi)

Apply a 2D majority filter to the local feature ID array (lfi) to smooth the grain structure by replacing each pixel’s feature ID with the most common feature ID among its 8 neighbors (including itself).

Parameters:

lfi (np.ndarray) – 2D Labelled Feature Image.

Returns:

  • np.ndarray – Smoothed 2D array of feature IDs after applying the majority filter.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.majority_filter_2d)

upxo.gsdataops.grid_ops.majority_filter_3d_npass(lfi=None, n=2, sizes=[3, 3])[source]

Apply multiple passes of a 3D majority filter to the local feature ID array (lfi) to iteratively smooth the grain structure.

Parameters:
  • lfi (np.ndarray) – 3D Labelled Feature Image to be smoothed. Default is None, which will raise an error if not provided.

  • n (int) – Number of passes to apply. Default is 2.

  • sizes (list of int) – List of window sizes for each pass. Must have length n. Default is [3, 3].

Returns:

Smoothed 3D array of feature IDs after applying n passes of the majority filter.

Return type:

np.ndarray

upxo.gsdataops.grid_ops.majority_filter_3d_1pass(lfi=None, size=3)[source]

Apply a 3D majority filter to the local feature ID array (lfi) to smooth the grain structure by replacing each voxel’s feature ID with the most common feature ID among its neighbors in a 3D window.

Parameters:
  • lfi (np.ndarray) – 3D Labelled Feature Image. Default is None, which will raise an error if not provided.

  • size (int, optional) – Size of the neighborhood window (must be odd). Default is 3 for a 3x3x3 window.

Returns:

  • np.ndarray – Smoothed 3D array of feature IDs after applying the majority filter.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.majority_filter_3d)

upxo.gsdataops.grid_ops.compute_grain_bounding_boxes(lfi, padding=1)[source]

Identifies the min/max spatial extent for every grain ID in the volume. Parameters: ———– lfi : ndarray

3D Labelled Feature Image.

paddingint

Extra voxels to include around the box to ensure boundary gradients are captured.

Returns:

bboxesdict

Mapping of GrainID -> tuple(slice_x, slice_y, slice_z)

upxo.gsdataops.grid_ops.compute_local_grain_mask(lfi, bounding_box, grain_id)[source]

Extracts a local boolean mask for a specific grain within its bounding box. Parameters: ———– lfi : ndarray

3D Labelled Feature Image (can be the original or lfiex).

bounding_boxtuple of slices

The (slice_x, slice_y, slice_z) identified for this grain.

grain_idint

The ID of the grain to mask.

Returns:

grain_maskndarray[bool]

A 3D boolean array of the same shape as the bounding box crop, True where the voxel belongs to the grain_id.

upxo.gsdataops.grid_ops.generate_test_2D_LFI_1(plotlfi=True, figsize=(6, 6), dpi=100)[source]

Generate a 2D Local Feature ID (LFI) array with multiple grains and features for testing purposes. The array includes distinct quadrants, a central feature, an island, a thin neck, and a triple point cluster to provide a variety of grain structures for testing grain detection and analysis algorithms.

Returns:

  • np.ndarray – A 2D array of shape (200, 200) representing the LFI with various features.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.generate_test_2D_LFI_1)

upxo.gsdataops.grid_ops.generate_constrained_hybrid_seeds(lfi, target_spacing=0.5, bulk_spacing=10.0, jitter_factor=1.0, margin=0.0, padding=1.0, plot_seeds=False, figsize=(8, 8), dpi=50, markersize=2)[source]

Seeding with Rigid Guard Rails to eliminate RVE boundary irregularities.

Parameters:
  • lfi (np.ndarray) – 2D Labelled Feature Image.

  • target_spacing (float) – Desired spacing between seeds along the boundary. Default is 0.5 units.

  • bulk_spacing (float) – Desired spacing between seeds in the bulk (internal) region. Default is 10.0 units.

  • jitter_factor (float) – Factor to control the amount of jitter applied to bulk seeds. Default is 1.0 (0 means no jitter, 1 means up to ±bulk_spacing/2 jitter).

  • margin (float) – Margin to define an internal buffer to prevent bulk seeds from pushing against RVE edges. Default is 0.0.

  • padding (float) – Padding to define an additional buffer around the domain edges for guard rails. Default is 1.0.

  • plot_seeds (bool) – Whether to plot the seeds on top of the LFI for visualization. Default is False.

  • figsize (tuple) – Size of the figure for plotting seeds if plot_seeds is True. Default is (8, 8).

  • dpi (int) – Dots per inch for the seed plot if plot_seeds is True. Default is 50.

  • markersize (int) – Size of the markers for the seeds if plot_seeds is True. Default is 2.

Returns:

Array of seed coordinates with shape (num_seeds, 2), where each row is [x, y].

Return type:

np.ndarray

Notes

  • The function first detects the grain boundaries in the LFI and samples seeds along these boundaries at a specified target spacing.

  • It then identifies internal regions that are sufficiently far from the boundaries and samples seeds in these bulk areas with a specified bulk spacing, applying jitter

    to avoid regular patterns.

  • Finally, it adds rigid guard rails of seeds along the domain edges to ensure that the Voronoi tessellation produces straight edges at the boundaries, eliminating

    irregularities caused by boundary effects.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.constrained_hybrid_seeds

upxo.gsdataops.grid_ops.generate_constrained_hybrid_seeds_3d(lfi, target_spacing=0.5, bulk_spacing=10.0, jitter_factor=1.0, margin=0.0, padding=1.0)[source]

3D Seeding with Guard Sheets to eliminate RVE boundary irregularities.

Parameters:
  • lfi (np.ndarray) – 3D Labelled Feature Volume (D, H, W).

  • target_spacing (float) – Spacing along the grain boundary surfaces.

  • bulk_spacing (float) – Spacing within the interior of grains.

  • jitter_factor (float) – Magnitude of random displacement for bulk seeds.

  • margin (float) – Internal buffer to keep bulk seeds away from RVE faces.

  • padding (float) – Distance outside the RVE where guard seeds are placed.

Returns:

Array of seed coordinates with shape (num_seeds, 3) as [x, y, z].

Return type:

np.ndarray

upxo.gsdataops.grid_ops.generate_poisson_disk_seeds(xbound, ybound, radius=5, k=6, see_seeds=False, **plotKwargs)[source]

Generate Poisson Disk Sampling seeds within a specified rectangular domain defined by xbound and ybound.

Parameters:
  • xbound (tuple) – A tuple (x_min, x_max) defining the horizontal bounds of the sampling area.

  • ybound (tuple) – A tuple (y_min, y_max) defining the vertical bounds of the sampling area.

  • radius (float) – The minimum distance between any two seeds. Default is 5 units.

  • k (int) – The number of attempts to place a new seed around an existing seed before giving up. Default is 6.

Returns:

An array of seed coordinates with shape (num_seeds, 2), where each row is [x, y].

Return type:

np.ndarray

Notes

  • Poisson Disk Sampling is a method for generating points that are evenly distributed while maintaining

    a minimum distance between them.

  • The algorithm typically starts with an initial random seed and iteratively attempts to place new seeds

    around existing seeds, ensuring that they are at least ‘radius’ distance apart. The ‘k’ parameter controls how many attempts are made to place a new seed around an existing seed before it is discarded.

  • This method is particularly useful for applications like seeding in Voronoi tessellations, where a more

    uniform distribution of seeds is desired compared to purely random sampling.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.generate_poisson_disk_seeds

upxo.gsdataops.grid_ops.generate_darted_seeds(xbound, ybound, radius=5, k=6, see_seeds=False, **plotKwargs)[source]

Generate Darted Sampling seeds within a specified rectangular domain defined by xbound and ybound.

Parameters:
  • xbound (tuple) – A tuple (x_min, x_max) defining the horizontal bounds of the sampling area.

  • ybound (tuple) – A tuple (y_min, y_max) defining the vertical bounds of the sampling area.

  • radius (float) – The minimum distance between any two seeds. Default is 5 units.

  • k (int) – The number of attempts to place a new seed around an existing seed before giving up. Default is 6.

Returns:

An array of seed coordinates with shape (num_seeds, 2), where each row is [x, y].

Return type:

np.ndarray

Notes

  • Darted Sampling is a method for generating points that are evenly distributed while maintaining

    a minimum distance between them, similar to Poisson Disk Sampling. However, Darted Sampling typically involves a more aggressive rejection of candidate points, which can lead to a more uniform distribution in certain cases.

  • The algorithm starts with an initial random seed and iteratively attempts to place new seeds around

    existing seeds. If a candidate seed is too close to an existing seed (within the specified radius), it is rejected (or “darted”). The ‘k’ parameter controls how many attempts are made to place a new seed around an existing seed before it is discarded.

  • This method can be particularly effective for applications like seeding in Voronoi tessellations,

    where a more uniform distribution of seeds is desired compared to purely random sampling, and can sometimes produce better results than Poisson Disk Sampling in terms of uniformity.

  • The ‘darting’ aspect of the algorithm can help to break up clusters of points that might occur in

    Poisson Disk Sampling, leading to a more even distribution of seeds across the domain.

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.generate_darted_seeds

upxo.gsdataops.grid_ops.pad_lfi(lfi, pad_width, padder)[source]

Pad a local feature ID array (lfi) with a specified value on all sides.

Parameters:
  • lfi (np.ndarray) – N-dimensional Labelled Feature Image to be padded.

  • pad_width (int or tuple) – The width of the padding to be applied on each side. If an integer is provided, the same padding width will be applied to all sides. If a tuple is provided, it should specify the padding width for each side in the format ((before_1, after_1), (before_2, after_2), …).

  • padder (int) – The value to use for padding the array. This value will be assigned to the padded regions around the original array.

Returns:

  • np.ndarray – The padded local feature ID array with the specified padding width and padder value.

  • Usage

  • —–

  • import upxo.gsdataops.grid_ops as gridOps

  • Use as (gridOps.pad_lfi)

upxo.gsdataops.grid_ops.find_gb_v1(gsimage, plot_gb=True, figsize=(6, 6), dpi=100, cmap='nipy_spectral')[source]

Find gb v1.

upxo.gsdataops.grid_ops.segment_grain_boundaries(gsimage, gbimage, neigh_fid, connectivity=8)[source]

Segment grain boundaries.

upxo.gsdataops.grid_ops.make_gbsegImage(gbMask, segments, nsegments, neigh_fid)[source]

Build and return gbsegImage.

upxo.gsdataops.grid_ops.combine_partitions(image_data, combinations)[source]

Combine multiple partition IDs in an image array according to specified groupings. This method merges partition regions by replacing multiple partition IDs with a single target ID for each group. After combining, the partition IDs are renumbered sequentially starting from 1.

Parameters:
  • image_data (numpy.ndarray) – Input image array containing partition IDs as integer values.

  • combinations (list of list of int) – List of groups where each group is a list of partition IDs to be combined. The first valid ID in each group becomes the target ID for that group.

Returns:

Modified image array with combined partitions and renumbered IDs starting from 1. Has the same shape as the input image_data.

Return type:

numpy.ndarray

Notes

  • Only partition IDs that are present in the image_data are considered valid.

  • Groups with fewer than 2 valid IDs are skipped.

  • The final renumbering ensures sequential partition IDs without gaps.

Example

import numpy as np image_data = np.array([[1, 1, 2, 2],

[1, 3, 3, 2], [4, 4, 3, 2]])

combinations = [[1, 2], [3, 4]] combined_image = combine_partitions(image_data, combinations) print(combined_image) # Output: # [[1 1 1 1] # [1 2 2 1] # [2 2 2 1]]

Usage

import upxo.gsdataops.grid_ops as gridOps Use as: gridOps.combine_partitions

upxo.gsdataops.grid_ops.detect_features_in_image_MCstateWise_2d(image_data, binary_structure_order=2)[source]

Detect features in an image and label them uniquely.

image_datanumpy.ndarray

Input image array containing different states as integer values.

binary_structure_orderint, optional

Order of the binary structure for connectivity. Default is 2 (8-connectivity).

labeled_imagenumpy.ndarray

Labeled image where each detected feature has a unique integer label.

original_to_labelsdict

Mapping from original state values to lists of new feature labels.

labels_to_originaldict

Mapping from new feature labels to their corresponding original state values.

import numpy as np image_data = np.array([[1, 1, 0, 2, 2],

[1, 0, 0, 2, 2], [0, 0, 3, 3, 0], [4, 4, 0, 0, 0]])

labeled_image, orig_to_labels, labels_to_orig = detect_features_in_image_MCstateWise_2d(image_data, binary_structure_order=2) print(“Labeled Image:

“, labeled_image)

print(“Original to Labels Mapping:

“, orig_to_labels)

print(“Labels to Original Mapping:

“, labels_to_orig)

upxo.gsdataops.grid_ops.compute_twin_thickness_stats(parent_info: dict, prop_ebsd: dict, step_size_um: float, thickness_key=None, lfi=None, abrupt_threshold: float = 0.8) dict[source]

Compute twin lamella thickness statistics from EBSD grain properties.

Parameters:
  • parent_info (dict) – Output of identify_parent_grains.

  • prop_ebsd (dict) – {grain_id: {'minor_axis_length': ..., ...}}.

  • step_size_um (float) – EBSD step size in µm/pixel.

  • thickness_key (str or None) – Property key to use as thickness proxy. Defaults to 'minor_axis_length' when available, else 'eq_diameter'.

  • lfi (ndarray or None) – EBSD label field image. When supplied, abrupt-twin detection is performed by comparing each twin’s extent along the parent’s major axis direction against the parent’s own extent.

  • abrupt_threshold (float) – Twins with twin_span / parent_span < abrupt_threshold are counted as abruptly-ending. Default 0.8.

Returns:

  • dict with keys (gids, thick_px, thick_um, col,)

  • step_um, mean, median, std, min, max,

  • pct10, pct90, n_abrupt_ebsd, abrupt_frac_ebsd.

upxo.gsdataops.grid_ops.compute_grain_intercept_lengths(rp, lfi, n_sample_pts=None) numpy.ndarray[source]

Compute chord (intercept) lengths through a grain perpendicular to its major axis, by ray-casting from evenly-spaced sample points along the major axis.

Parameters:
  • rp (skimage.measure.RegionProperties) – regionprops object for the grain — pre-computed by the caller so the LFI is only iterated once for the full grain set.

  • lfi (ndarray (ny, nx)) – Label field image.

  • n_sample_pts (int or None) – Number of sample points along the major axis. Defaults to int(major_axis_length), capped from above by that value.

Returns:

Intercept lengths in pixels, one value per sample point.

Return type:

ndarray(n,)