upxo.pxtalops.grain_boundary_zones module

upxo.pxtalops.grain_boundary_zones.introduce_boundary_zones(gs, fids=[], niterations=5, method='use_min_core_size', min_core_size=50, threshold_bz_thickness=2, structure_nx=3, structure_ny=3, reset_others=False, renumber_fid_map=True, morph_char=False, topo_char=False, remap_scalars=False, perform_topology_checks=False, see_plot=False, figure_size=(5, 5), figure_dpi=100)[source]

Introduce boundary zones and cores within grains using morphological erosion.

This function partitions each grain into a boundary zone (outer region) and a core (inner region) by applying binary erosion. The method parameter controls how the boundary zone thickness is determined.

Parameters:
  • gs (mcgs2_grain_structure) – Grain structure object (temporal slice) from UPXO. Note: This object is modified in-place; attributes bbox_bz and bbox_core are added to each grain. Pass a deep copy if you need to preserve the original.

  • fids (list of int, optional) – List of grain IDs (gid) to process. If empty (default), processes all grains in gs.gid. Use to selectively apply boundary zone detection to specific grains.

  • niterations (int, default=5) – Maximum number of morphological erosion iterations to attempt. Higher values allow thicker boundary zones but may eliminate small grains entirely.

  • method ({'use_min_core_size', 'simple', 'thresholded'}, default='use_min_core_size') –

    Algorithm for defining boundary zones:

    • ’use_min_core_size’: Erodes until core size drops below min_core_size, then backs off to maintain minimum core dimension (recommended for ensuring non-trivial cores).

    • ’simple’: Uses maximum successful erosion without size constraints (may produce very small cores).

    • ’thresholded’: Stops erosion when boundary zone reaches specific thickness defined by threshold_bz_thickness.

  • min_core_size (int, default=50) – Minimum number of pixels required in the grain core (used only with method=’use_min_core_size’). Grains smaller than this after maximum erosion will have their entire bbox assigned as boundary zone with bbox_core=None.

  • threshold_bz_thickness (int, default=2) – Number of erosion iterations to define boundary zone thickness (used only with method=’thresholded’). Boundary zone is the result of eroding exactly this many iterations.

  • structure_nx (int, default=3) – Width of the morphological structuring element (connectivity kernel). Value of 3 creates 8-connectivity for erosion (includes diagonals). Use 2 for 4-connectivity.

  • structure_ny (int, default=3) – Height of the morphological structuring element. Typically set equal to structure_nx for isotropic erosion.

  • see_plot (bool, default=False) – If True, generates a matplotlib visualization showing boundary zones overlaid on the grain structure with distinct colormap (useful for debugging).

  • figure_size (tuple of float, default=(5, 5)) – Width and height of the plot figure in inches (used only if see_plot=True).

  • figure_dpi (int, default=100) – Resolution of the plot figure in dots per inch (used only if see_plot=True).

Returns:

lgi_new – 2D label image with boundary zones visualized as separate grain IDs. Shape matches gs.lgi. Original grain cores retain their IDs; boundary zones are assigned new sequential IDs starting from max(gs.gid) + 1.

Return type:

ndarray of int

Raises:
  • ValueError – If method is not one of the recognized options.

  • Side Effects

  • ------------

  • Modifies the input gs object in-place by adding two attributes to each processed grain:

:raises - gs.g[gid][‘grain’].bbox_bz : ndarray of bool: Boolean mask of the boundary zone within the grain’s bounding box. Shape matches grain.bbox. Pixels marked True belong to the boundary zone. :raises - gs.g[gid][‘grain’].bbox_core : ndarray of bool or None: Boolean mask of the core region. If the grain is too small or erosion eliminates the core entirely, this is set to None.

Notes

  • Uses scipy.ndimage.binary_erosion for morphological operations.

  • For grains with bbox_core=None, the entire grain bbox is considered boundary zone.

  • To avoid modifying the original grain structure, pass a deep copy: lgi_new = introduce_boundary_zones(deepcopy(gs), …)

  • The returned lgi_new is for visualization only; actual boundary zone data is stored in gs.g[gid][‘grain’].bbox_bz.

Examples

>>> from upxo.pxtalops.grain_boundary_zones import introduce_boundary_zones
>>> from copy import deepcopy
>>> # Apply to all grains with minimum core size constraint
>>> lgi_bz = introduce_boundary_zones(gs, method='use_min_core_size', min_core_size=100)
>>>
>>> # Process specific grains with simple erosion
>>> lgi_bz = introduce_boundary_zones(gs, fids=[1, 5, 10], method='simple', niterations=3)
>>>
>>> # Preserve original structure
>>> gs_copy = deepcopy(gs)
>>> lgi_bz = introduce_boundary_zones(gs_copy, see_plot=True)

See also

introduce_bz__use_min_core_size

Implementation of ‘use_min_core_size’ method.

introduce_bz__simple

Implementation of ‘simple’ method.

introduce_bz__thresholded

Implementation of ‘thresholded’ method.

Usage, -----, from, Authors, -------, Dr.

upxo.pxtalops.grain_boundary_zones.introduce_bz__use_min_core_size(gs, fids=[], niterations=5, min_core_size=50, structure_nx=3, structure_ny=3, reset_others=False, renumber_fid_map=True, morph_char=False, topo_char=False, remap_scalars=False, perform_topology_checks=False, see_plot=False, figure_size=(5, 5), figure_dpi=100)[source]

Introduce boundary zones in the grains of a grain structure using minimum core size criterion.

Parameters:
  • gs (GrainStructure) – The grain structure object containing grains to process.

  • fids (list, optional) – List of grain IDs to process. If empty, all grains will be processed.

  • niterations (int, optional) – Number of erosion iterations to perform. Default is 5.

  • min_core_size (int, optional) – Minimum core size to maintain during erosion. Default is 50.

  • structure_nx (int, optional) – Size of the structuring element in x-direction. Default is 3.

  • structure_ny (int, optional) – Size of the structuring element in y-direction. Default is 3.

  • see_plot (bool, optional) – Whether to plot the resulting grain structure with boundary zones. Default is False.

  • figure_size (tuple, optional) – Size of the plot figure. Default is (5, 5).

  • figure_dpi (int, optional) – DPI of the plot figure. Default is 100.

Returns:

lgi_new – The updated grain structure image with boundary zones introduced.

Return type:

ndarray

Raises:
  • ValueError – If the fids list is empty.

  • Usage

  • -----

  • from pxtalops.grain_boundary_zones import introduce_bz__use_min_core_size

upxo.pxtalops.grain_boundary_zones.introduce_bz__simple(gs, fids=[], niterations=5, structure_nx=3, structure_ny=3, reset_others=False, renumber_fid_map=True, morph_char=False, topo_char=False, remap_scalars=False, perform_topology_checks=False, see_plot=False, figure_size=(5, 5), figure_dpi=100)[source]

Introduce boundary zones in the grains of a grain structure using simple erosion.

Parameters:
  • gs (GrainStructure) – The grain structure object containing grains to process.

  • fids (list, optional) – List of grain IDs to process. If empty, all grains will be processed.

  • niterations (int, optional) – Number of erosion iterations to perform. Default is 5.

  • structure_nx (int, optional) – Size of the structuring element in x-direction. Default is 3.

  • structure_ny (int, optional) – Size of the structuring element in y-direction. Default is 3.

  • see_plot (bool, optional) – Whether to plot the resulting grain structure with boundary zones. Default is False.

  • figure_size (tuple, optional) – Size of the plot figure. Default is (5, 5).

  • figure_dpi (int, optional) – DPI of the plot figure. Default is 100.

Returns:

lgi_new – The updated grain structure image with boundary zones introduced.

Return type:

ndarray

Raises:
  • ValueError – If the fids list is empty.

  • Usage

  • -----

  • from pxtalops.grain_boundary_zones import introduce_bz__simple

upxo.pxtalops.grain_boundary_zones.introduce_bz__thresholded(gs, fids=[], niterations=5, threshold_bz_thickness=2, structure_nx=3, structure_ny=3, reset_others=False, renumber_fid_map=True, morph_char=False, topo_char=False, remap_scalars=False, perform_topology_checks=False, see_plot=False, figure_size=(5, 5), figure_dpi=100)[source]

Introduce boundary zones in the grains of a grain structure using thresholded erosion.

Parameters:
  • gs (GrainStructure) – The grain structure object containing grains to process.

  • fids (list, optional) – List of grain IDs to process. If empty, all grains will be processed.

  • niterations (int, optional) – Number of erosion iterations to perform. Default is 5.

  • threshold_bz_thickness (int, optional) – Threshold for boundary zone thickness. Default is 2.

  • structure_nx (int, optional) – Size of the structuring element in x-direction. Default is 3.

  • structure_ny (int, optional) – Size of the structuring element in y-direction. Default is 3.

  • see_plot (bool, optional) – Whether to plot the resulting grain structure with boundary zones. Default is False.

  • figure_size (tuple, optional) – Size of the plot figure. Default is (5, 5).

  • figure_dpi (int, optional) – DPI of the plot figure. Default is 100.

Returns:

lgi_new – The updated grain structure image with boundary zones introduced.

Return type:

ndarray

Raises:
  • ValueError – If the fids list is empty.

  • Usage

  • -----

  • from pxtalops.grain_boundary_zones import introduce_bz__thresholded

upxo.pxtalops.grain_boundary_zones.determine_buffer_geometric_GS(cell, min_cell_area=5, buffer_quality_factor=0.25, min_area_retention=0.3, max_allowed_holes=2, max_iterations=20, verbose=True)[source]

Determine an appropriate buffer distance for creating a boundary zone within a grain cell using geometric properties of the cell. The function iteratively tests buffer distances to ensure that the resulting buffered cell does not create too many holes (disconnected interiors).

Parameters:
  • cell (shapely.geometry.Polygon) – The polygon representing the grain cell to buffer.

  • buffer_quality_factor (float, default=0.25) – Fraction of the inscribed radius to use as the initial buffer distance. Higher values may create thicker boundary zones but risk creating holes. Adjust based on desired balance between boundary zone thickness and core integrity.

  • min_area_retention (float, default=0.30) – Minimum fraction of the original cell area that must be retained in the buffered cell. This is used to calculate a maximum buffer distance based on area loss.

  • max_allowed_holes (int, default=2) – Maximum number of holes (disconnected interiors) allowed in the buffered cell. Set to 0 for no holes, or a higher number if some fragmentation is acceptable.

  • max_iterations (int, default=20) – Maximum number of iterations to test different buffer distances. The buffer distance is reduced iteratively if the resulting buffered cell has too many holes or is empty.

  • verbose (bool, default=True) – If True, prints detailed information about the buffering process, including geometric properties, buffer distances tested, and hole counts.

Returns:

  • bufferDist (float or None) – The final buffer distance that meets the criteria, or None if no valid buffer distance was found.

  • bufferCell (list of shapely.geometry.Polygon or None) – List of polygons representing the buffered cell structure: - If no holes created: list with single polygon (the buffered cell) - If holes created: list with outer polygon (index 0) followed by each hole as a separate polygon - None if no valid buffer distance was found.

  • boundaryZone (shapely.geometry.Polygon or shapely.geometry.MultiPolygon or None) – The boundary zone region (original cell minus buffered cell). May be a MultiPolygon if holes were created. None if no valid buffer distance was found.

  • Usage

  • —–

  • from upxo.pxtalops.grain_boundary_zones import determine_buffer_geometric_GS as find_buffer_geom

upxo.pxtalops.grain_boundary_zones.process_grain_boundary_zones(smoothed_grains, ignoreFids=[], min_cell_area=80, buffer_quality_factor=0.55, min_area_retention=0.3, max_allowed_holes=2, max_iterations=20, verbose=False)[source]

Orchestrator function to process all grains and create boundary zones.

Parameters:
  • smoothed_grains (dict) – Dictionary of grain IDs to Shapely Polygon geometries

  • min_cell_area (int, default=80) – Minimum cell area threshold for processing

  • buffer_quality_factor (float, default=0.55) – Buffer quality factor for geometric calculation

  • min_area_retention (float, default=0.30) – Minimum area fraction to retain in buffered cell

  • max_allowed_holes (int, default=2) – Maximum number of holes allowed in buffered cell

  • max_iterations (int, default=20) – Maximum iterations for buffer refinement

  • verbose (bool, default=False) – Print detailed processing information

Returns:

  • BZ_1_cells (dict) – Dictionary mapping grain IDs to boundary zone polygons

  • BZ_1_thickness (dict) – Dictionary mapping grain IDs to buffer distances

  • CZ_1_cells (dict) – Dictionary mapping grain IDs to core zone polygon lists

  • CZ1 (list) – Flat list of all core zone polygons

  • combined_multipolygon (shapely.geometry.MultiPolygon) – MultiPolygon containing all valid boundary zones and core zones for visualization

  • Usage

  • —–

  • from upxo.pxtalops.grain_boundary_zones import process_grain_boundary_zones