upxo.pxtal package

Subpackages

Submodules

Module contents

Polycrystal (pxtal) core package for UPXO grain-structure data models.

Houses:

  • MCGS temporal slices — mcgs2_temporal_slice, mcgs3_temporal_slice

  • Voronoi tessellation — vortess2d (gtess2d), vortess3d (gtess3d)

  • Hierarchical FM steel — fm_steel_3d

  • Twinned FCC — twinned_simple_3d

  • Supporting geometry / grid / image utilities

Generation drivers live in upxo.ggrowth; this package focuses on structure objects, specialised pipelines, and related operations.

class upxo.pxtal.gtess2d(sps=None, xbound=None, ybound=None, pxtals=None, uinputs=None, phid=1, gen_method='from_seed_points')[source]

Bases: object

2D Voronoi-tessellation polycrystal set (multi-instance VTGS).

Builds and manages geometric grain structures from seed points (Poisson-disk / Bridson-style sampling, random distributions, or user seeds), with hierarchical feature databases (base, twins, PAP levels, boundary zones, etc.), morphology/topology properties, and geometry linking for conformal meshing.

Typical construction

>>> from upxo.pxtal.vortess2d import gtess2d
>>> gset = gtess2d.from_seed_points(
...     sp_input='gen', xbound=[0, 50], ybound=[0, 50],
...     sp_distr='random', gr_tech='pds', smp_tech='bridson1',
...     lean='veryhigh', char_length=[4.5], n_instances=2, ...)

Key concepts

  • Instances (ninst) — independent VT realizations in one object

  • gslevel — hierarchical level (base, twins, PAP blocks, …)

  • fdb_* — feature databases linked via add_fdb / link_geom

  • mprop / tprop — morphological and topological property stores

Common ops: link_geom, get_idmap_fc / get_idmap_cf, assign_loc_tags, sf_gbz, plot / plot_cells.

gen_method
sps
pxtals
ninst
instn
uinputs
xbound
ybound
fdb_base
fdb_subgrains
fdb_paps
mprop
tprop
idmap_c_supc
idmap_c_subc
property bounds

Return dictionary of bounds.

property info

Return metadata dictionary compatible with gtess3d.

property seeds

Return primary seed points.

classmethod from_mpoint2d(mpt, bounds=None, **kwargs)[source]

Construct gtess2d from an MPoint2d instance.

classmethod from_shapely_mulpolygon(mpol, bounds=None, phid=1)[source]

Construct this instance from a Shapely MultiPolygon or list of Polygons.

classmethod from_geometrified_mcgs2d(polgs)[source]

polgs: dict: Polygonised grain structures

Examples

from upxo.pxtal.vortess2d import gtess2d
gset = gtess2d.from_geometrified_mcgs2d(PXTAL)
classmethod from_seed_points(sp_input='gen', seed_coords=None, xbound=[0, 100], ybound=[0, 100], nsp=600, n_instances=1, nsp_dev_ninstances=10, sp_distr='random', gr_tech='pds', smp_tech='bridson1', randuni_calc='by_points', lean='veryhigh', char_length=[3, 2], niter=500, ntp=25, ntrials=10, k_char_length_inc=0.1, k_char_length_dec=0.1, rep_gen=True, nseeds=25, repr_prop={'area': {'consider_boundary_grains': True, 'mean': {'dev': 10, 'val': 50}}}, make_point_objects=True, make_ckdtree=True, char_length_mean=0.24598, char_length_min=0.1111, char_length_max=0.9999, nt=10, space='linear', bounds=None, periodic=(False, False), weights=None, cvt_iterations=0, perturb_factor=0.0, sp_in=None, **kwargs)[source]

Construct 2D Voronoi tessellation polycrystal from seed points or generative sampling.

Supports high-fidelity features: - Direct coordinate arrays (N, 2) or MPoint2d instances - Periodic Boundary Conditions (PBC) across X, Y, or both - Laguerre / Power diagram tessellation via seed weights - Centroidal Voronoi (CVT / Lloyd relaxation) - Boundary interface perturbation / curvature - Poisson-disk (Bridson), dart, and uniform random generative sampling

Parameters:
  • sp_input (str or array-like or MPoint2d, optional) – Seed point input method. If ‘load’, then seed_coords must be specified. If ‘gen’, parameters concerning generating the seed points must be specified. An (N, 2) coordinate array or an MPoint2d instance may also be passed directly here, in which case it is treated the same as sp_input='load' with that value as seed_coords. Default value is ‘gen’.

  • seed_coords (np.ndarray or MPoint2d, optional) – (N, 2) coordinate array or MPoint2d instance, used when sp_input='load'. Default value is None.

  • xbound (list, optional) – Spatial bound of expected pxtal along x-axis, [xmin, xmax]. Default value is [0, 100].

  • ybound (list, optional) – Spatial bound of expected pxtal along y-axis, [ymin, ymax]. Default value is [0, 100].

  • nsp (int, optional) – Number of seed points. Default value is 600.

  • n_instances (int, optional) – Number of poly-xtal instances to be generated. Default value is 1.

  • nsp_dev_ninstances (int, optional) – Allowable deviation in number of seed points across instances. The first instance will be used as a reference. The value to be input is a percentage value. If value entered is 10, this would mean, the second and other instances will be created ensuring that the parameters needed to create them are to so as to keep the number of seed points between -5% and +5% of that of the 1st instance. This is to ensure similar morphological parameter distributions across all instances. Default value is 10.

  • sp_distr (int, optional) – Spatial distribution of the seed points desired. Options insluce ‘random’. Default value is ‘random’.

  • gr_tech (str, optional) – Gridding technique. Options include ‘random’, ‘pds’. Default value is ‘pds’.

  • smp_tech (str, optional) – Sampling technique. Options include ‘uniform’, ‘dart’, ‘bridson1’. Default value is ‘bridson1’.

  • randuni_calc (str, optional) – Random uniform calculations. Default value is ‘by_points’.

  • lean (str, optional) – UPXO point lean option used for creatinhg multipoint. Default value is ‘veryhigh’.

  • char_length (list, optional) – Characteristic lengths needed for seed point creation. In case of ‘dart’ and ‘bridson1’ sampling tecjhnique, char_length[0] determines the average spatial distance between the points. The higher the value, the greater the distane, which means the lesser the number of points and greater the mean area of poly-xtals. Default value is [3, 2].

  • niter (int, optional) – NUmber of iterations needed for seed point creation. Default value is 500.

  • ntrials (int, optional) – Number of trials used in the creation of the 1st pxtal instance. The irterations will be done to ensure pxtal parameter agrees to as prescibed by repr_prop. Default value is -1.

  • k_char_length_inc (float, optional) – Factor to increase the characteristic length. Value must be greater than 0. Prescribed domain [0.02, 0.25]. A very small value would increase the number of iterations needed to avchieve the required morphologycal parameter requirement. Too big a value may lead to oscillating iterations. Default value is 0.1.

  • k_char_length_dec (float, optional) – Factor to decrease the characteristic length. Value must be greater than 0. Prescribed domain [0.02, 0.25]. A very small value would increase the number of iterations needed to avchieve the required morphologycal parameter requirement. Too big a value may lead to oscillating iterations. Default value is 0.1.

  • repr_prop (dict, optional) –

    Representativeness requirement of properties. Default value is {‘area’: {‘mean’: 6,

    ’dev’: 10, ‘consider_boundary_grains’: True }

    }.

  • make_point_objects (bool, optional) – Default value is True.

  • make_ckdtree (bool, optional) – Default value is True.

  • char_length_mean (float, optional) – Default value is 0.24598.

  • char_length_min (float, optional) – Default value is 0.1111.

  • char_length_max (float, optional) – Default value is 0.9999.

  • nt (int, optional) – Default value is 10.

  • space (str, optional) – Default value is ‘linear’.

  • bounds (array-like, optional) – [[xmin, xmax], [ymin, ymax]] (or any format accepted by coerce_bounds_2d()). When given, overrides xbound/ybound. When omitted and sp_input='load', bounds are inferred from the seed extents. Default value is None.

  • periodic (tuple of bool, optional) – (periodic_x, periodic_y). Enables Periodic Boundary Conditions along either axis for a fully periodic RVE. Default value is (False, False).

  • weights (array-like, optional) – Per-seed weights (N,) for Laguerre / power-diagram (weighted Voronoi) tessellation. None gives a standard, unweighted Voronoi tessellation. Default value is None.

  • cvt_iterations (int, optional) – Number of Lloyd relaxation iterations for Centroidal Voronoi Tessellation (CVT). 0 disables CVT and uses the seeds as given. Default value is 0.

  • perturb_factor (float, optional) – Magnitude of non-linear grain-boundary interface perturbation (curvature), applied while preserving manifold junctions. 0 disables perturbation. Default value is 0.0.

  • sp_in (array-like or MPoint2d, optional) – Alias for seed_coords, used only when seed_coords is not already given. Default value is None.

  • **kwargs – Accepted and ignored, for forward compatibility with callers passing extra keyword arguments.

Returns:

New instance holding the generated poly-xtal instance(s) in self.pxtals (Shapely MultiPolygons, keyed by instance number) and the corresponding seed points in self.sps.

Return type:

gtess2d

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True } }

# here we get Poisson disc sampling ————> gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 100],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], ntp=10, ntrials=100, n_instances=25, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

# Here we get dart sampling ————> gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 100],

ybound = [0, 100], sp_distr=’random’, gr_tech=’random’, smp_tech=’dart’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

gset.plot()

# High-fidelity: periodic boundaries, CVT relaxation, perturbation seeds = np.random.uniform(0, 60, size=(30, 2)) gset = gtess2d.from_seed_points(

seeds, bounds=[[0, 60], [0, 60]], periodic=(True, True), cvt_iterations=5, perturb_factor=0.03)

Construct this instance from geometry link.

extract_shapely_coords_all_grains(instance=1, gslevel='base', mfname='c_rp', make_upxo_mp=True, make_upxo_mp_subfeatures=False)[source]

Extract shapely coordinates for all grains in a given instance.

Parameters:
  • instance (int, optional) – Default value is 1.

  • mfname (str, optional) –

    Options include the following:
    • ’g_rp’: grain representative point. This is a point

    guaranteed by shapely to be INSIDE a polygon, in the present case, the GRAIN. * ‘g_cp’: grain centroid point. * ‘g_vp’: grain vertex points.

    Default value is ‘g_rp’

Returns:

points –

keys include:
  • cid: coordinates arranged in order of cid

  • all: collation of points. Different when mfname is g_vp

  • mp_all: UPXO multi-POint2D of all collated coordinates

  • mp_sf: UPXO multi-POint2D of coordintes, sub-features wise

Return type:

dict

Notes

Coordinates in points[‘all’] and points[‘mp_all’] for g_vp may not be in the same order in the poly-xtal.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 225],

ybound = [0, 200], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

gset.plot() points = gset.extract_shapely_coords_all_grains(instance=1,

mfname=’c_rp’, make_upxo_mp=True,)

points.keys()

add_supcell_instances(gslevel='base', instance=1, cluster_On=2, super_cell_name='grain_clusters', cell_sep_distance=4, n_supcell_instances=2, rand_exclude_cluster_centre_cids=0.0, exclude_cluster_centre_cids=[], exclude_cluster_cids=[], ccif=1.0, remove_duplicate_cells=True, merge=True, sample_plot=False, throw=False)[source]

Identify multiple instances of super-cells.

A super-cell instance is a list of super-cell structures which are spatially selected such that the super-cell structures are seperated by cell_sep_distance. Here, the distance is the number of single cells. A super-cell structure is accompanied by a central cell and a group of other cells.

Parameters:
  • gslevel (str, optional) – Default value is ‘base’.

  • instance (int, optional) – Default value is 1.

  • cluster_On (int, optional) – Number of nearest neighbours to be used all clusters. Default value is 2.

  • super_cell_name='grain_clusters'

:param : :param cell_sep_distance: Specify the maximum seperation distance to be maintained between

any two cluster centres. Default value is 2.

Parameters:
  • n_supcell_instances (int, optional) – Number of super-cell cluster configurations to be produced. Each configuration will be a list of clusters, with each cluster having a cluster centre cid and a list of cids inclusive of both the cid itself and the cids of neighbouring cells of cluster centre cell.

  • exclude_cluster_centre_cids (list, optional) – Default value is [].

  • exclude_cluster_cids (list, optional) – Default value is [].

  • ccif (float, optional) – Cluster cell inclusion factor, a factor determining how many random samples shall be drawn from the list of cluster cids of a given cid. Bounds: (eps, 1.0], where eps is a number which results in having at-least one cell in the cluster. The eps should be large for small clusters and could be small for large clusters. Default value is 1.0.

  • merge (bool, optional) – Specify whether cells in a certain cluster is to be merged into a single cell. If True, the merge operation will be executed and will create a new list of pxtal instances (say PX). Each instance in PX can then independently become a vortess2d object in its own right! To do this, you can make use of the class method as, [from_shapely_mulpolygon(px) for px in PX]. Default value is False.

  • sample_plot (bool, optional) – Default value is False.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 20, ‘dev’: 2.5, },

‘consider_boundary_grains’: True } }

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 100],

ybound = [0, 200], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[3.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

# Calculate the cluster instances cinst = gset.add_supcell_instances(gslevel=’base’, instance=1,

cluster_On=3, cell_sep_distance=2, n_supcell_instances=4, rand_exclude_cluster_centre_cids=0.0, exclude_cluster_centre_cids=[], exclude_cluster_cids=[], ccif=1.0, remove_duplicate_cells=True, merge=True, sample_plot=False)

base_instance = 1 supgs_instance = 0

plt.figure(figsize=(5, 5), dpi=150) ‘’’ plt.figure(figsize=(5, 5), dpi=150) pxtal = gset.pxtals[base_instance] coords_cid = [np.vstack(c.boundary.xy).T for c in pxtal.geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’)’’’

pxtal = gset.fdb_supset[‘pxtals’][supgs_instance] coords_cid = [np.vstack(c.boundary.xy).T for c in pxtal.geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’)

gset.plot_cells(instance=1, cids=cids) gset.plot_cells(instance=1, cids=supercell_centres[5])

Data access

gset.fdb_supset.keys() >> dict_keys([‘name’, ‘scells’, ‘scells_coll’, ‘pxtals’, ‘info’,

‘inst’, ‘ninst’, ‘nclust’, ‘ncells’])

gset.fdb_supset[‘scells’].keys() # Super cell instance IDs >> dict_keys([1, 2, 3, 4, 5])

gset.fdb_supset[‘scells’][1].keys() >> dict_keys([‘clids’, ‘cids’, ‘clusters’])

gset.fdb_supset[‘scells’][1][‘clids’] # Cluster IDs >> [1, 2, 3, 4, 5, 6, 7]

gset.fdb_supset[‘scells’][1][‘cids’] # Cluster wise centre cell IDs >> [131, 103, 8, 136, 45, 176, 184]

gset.fdb_supset[‘scells’][1][‘clusters’] # Cluster’s centre cell IDs # [[cids of cells at & around 131],.. ,[cids of cells at & around 184]] >> [[159, 132, …, 131],…, [162, 196, …, 184]]

gset.fdb_supset[‘scells_coll’].keys() # Cluster IDs >> [1, 2, 3, 4, 5, 6, 7]

gset.fdb_supset[‘scells_coll’][1] # All cluster’s centre cell IDs >> [159, 132, 134, 166,…, 182, 185, 189, 184]

gset.fdb_supset[‘pxtals’] # Shapely Multi-Polygon objects. >> [<shapely.geometry.multipolygon.MultiPolygon at 0x18e858e4910>,

<shapely.geometry.multipolygon.MultiPolygon at 0x18e858e4580>, <shapely.geometry.multipolygon.MultiPolygon at 0x18e8cbf2e50>, <shapely.geometry.multipolygon.MultiPolygon at 0x18e8cbf2a30>, <shapely.geometry.multipolygon.MultiPolygon at 0x18ea7a25ee0>]

print(gset.fdb_supset[‘pxtals’][1].geoms[0]) # 1st instance 1st cell >> POLYGON ((4.001101245601904 92.2296115091435,

2.633867013140424 89.03895454375312, 0 88.9638129954714, 0 97.34088983027945, 4.001101245601904 92.2296115091435))

gset.fdb_supset[‘info’] >> {‘super_cell_name’: ‘grain_clusters’, ‘source.gslevel’: ‘base’,

‘source.instance’: 1, ‘cluster_On’: 2, ‘cell_sep_distance’: 2, ‘n_supcell_instances’: 5, ‘rand_exclude_cluster_centre_cids’: 0.0, ‘exclude_cluster_centre_cids’: [], ‘exclude_cluster_cids’: [], ‘ccif’: 1.0, ‘remove_duplicate_cells’: True}

gset.fdb_supset[‘inst’] # Instance IDs >> dict_keys([1, 2, 3, 4, 5])

gset.fdb_supset[‘ninst’] # Number of instances >> 5

gset.fdb_supset[‘nclust’] # Number of clusters across instances >> [7, 7, 8, 8, 8]

Notes

Note: This uses the above data access. Please refer it before reading further.

gset.fdb_supset[‘ninst’] is 5, meaning there are 5 instances of grain structures. Each instance has grain clusters. Each of the 5 pxtals can be accessed in gset.fdb_supset[‘pxtals’]. Now, we see that gset.fdb_supset[‘nclust’][pxtal_ID = 0] is 7. This means that in the pxtal gset.fdb_supset[‘pxtals’][pxtal_ID], 7 grain clusters have been created as 7 unique grains. That is, in each grain cluster, the n cell which form n participating elements of the cluster, have all been made a single cell through cell union operation. The participating cells in a particular cluster, say the 1st cluster, i.e. the cluster gset.fdb_supset[‘scells’][supcell instance ID = 1][‘clids’][0] has the cell ID gset.fdb_supset[‘scells’][supcell instance ID = 1][‘cids’][0] as 131. This means that the centre cell of the 1st cell cluster, is cid = 131. Now, gset.fdb_supset[‘scells’][supcell inst ID = 1][‘clusters’][0], is [159, 132, 134, 166, 167, 74, 111, 145, 114, 150, 119, 131]. Lets call it as Ci_Cells. These are all cells which cluster aroung cid of 131. The actual cells which have been unioned (i.e. merged) are [gset.pxtals[1].geoms[i] for i in Ci_Cells], where Ci_Cells = gset.fdb_supset[‘scells’][1][‘clusters’][0]. Lets call this Ci_Cells_geom. Ci_Cells_geom is a list of Shapely polygon objects. Its multi-polygon can be easily created as MultiPolygon(Ci_Cells_geom).

partition_cells(gslevel='base', source_gslevel_Instance_ID=1, instance_ID_source=1, reset=False, instance_ID_partition=1, cids_sd=[], partition_type='Sub-cell-0', arg={'_buffer_factor_': 0.8, '_force_select_': True, '_min_subcell_area_factor_': 0.04, 'cid_offset': -1, 'combine_small_subs': False, 'id_format': 'from_cid_max', 'niter_max': 1000, 'seed_lattice_type': 'rand_uni', 'spn': 150}, saa=True, plot_pxtal=False, throw_pxtal=False)[source]

Partition cells in a grain structure using sub-division algorithms.

Parameters:
  • gslevel (str) – Specify the grain structure level. Default value is ‘base’.

  • instance_ID (int) – Specify the grain structure instance. Default value is 1.

  • cids_sd (Iterable) – Default value if [].

  • partition_type (str) –

    Specify the type of cell partitioning. Following options are available.

    1. ’Sub-cell-0’. Voronoi-subdivision

    2. ’Sub-cell-1’. Bridson’s sampling

    3. ’Sub-cell-2’. Dart sampling.

    4. ’twin-1’.

    5. ’blocks-1’.

    6. ’sub-blocks-1’.

    7. ’twins-1’.

  • arg (dict) –

    Specify additional srguments as a dictionary. 1. When the partition_type is ‘sub-cell-0’, the following

    dictionary must be used.

    {‘cid_offset’: -1,

    ’spn’: 100, ‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.09, ‘niter_max’: 1000, ‘_force_select_’: True }

    Explanations * cid_offset.

    Specify the maximum cid Default value is -1 (Recommended).

    • spn.

      Default value is 100.

    • id_format.

      Default value is ‘from_cid_max’.

    • seed_lattice_type.

      Default value is ‘rand_uni’.

    • combine_small_subs.

      Default value is False.

    • _buffer_factor_.

      Default value is 0.8.

    • _min_subcell_area_factor_.

      Default value is 0.09.

    • niter_max.

      Default value is 1000.

    • _force_select_.

      Default value is True.

  • saa (bool, optional) – Default value is True.

  • plot_pxtal (bool, optional) – Default value is False.

  • throw_pxtal (bool, optional) – Default value is False.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5, },

‘consider_boundary_grains’: True } }

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 75],

ybound = [0, 75], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[5.], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

‘’’ instance_ID_source = 1 pxtal = gset.pxtals[instance_ID_source] plt.figure(figsize=(5, 5), dpi=150) coords_cid = [np.vstack(c.boundary.xy).T for c in pxtal.geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’) ‘’’

cids_sd = np.random.choice(range(len(gset.pxtals[1].geoms)), 30, replace=False)

sc = gset.partition_cells(gslevel=’base’, instance_ID_source=1,

instance_ID_partition=1, cids_sd=cids_sd,

partition_type=’Sub-cell-0’, arg={‘cid_offset’: -1, ‘spn’: 10,

‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.09, ‘niter_max’: 1000, ‘_force_select_’: True},

saa=True, plot_pxtal=True, throw_pxtal=True)

lets gather all the sub-cell IDs. Lets just get all those from whose parent cells have atleast 2 subcells.

cids_sd_level_1 = [] for _sc_ in sc[‘fmap’].values():

if len(_sc_) > 1:

cids_sd_level_1 += _sc_

sc = gset.partition_cells(gslevel=’subgrains’, instance_ID_source=1,

instance_ID_partition=2, cids_sd=cids_sd_level_1,

partition_type=’Sub-cell-0’, arg={‘cid_offset’: -1, ‘spn’: 10,

‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.04, ‘niter_max’: 1000, ‘_force_select_’: True},

saa=True, plot_pxtal=True, throw_pxtal=True)

cids_sd_level_1 = [] for _sc_ in sc[‘fmap’].values():

if len(_sc_) > 1:

cids_sd_level_1 += _sc_

sc = gset.partition_cells(gslevel=’subgrains’, instance_ID_source=2,

instance_ID_partition=3, cids_sd=cids_sd_level_1,

partition_type=’Sub-cell-0’, arg={‘cid_offset’: -1, ‘spn’: 10,

‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.04, ‘niter_max’: 1000, ‘_force_select_’: True},

saa=True, plot_pxtal=True, throw_pxtal=True)

static voronoi_subdivision(cell, cid, cid_offset=-1, spn=100, id_format='from_cid_max', seed_lattice_type='rand_uni', combine_small_subs=False, _buffer_factor_=0.8, _min_subcell_area_factor_=-1, niter_max=1000, _force_select_=True)[source]

Divide a cell into sub-cells using seed-point-based Voronoi tessellation.

Parameters:
  • cell (shapely.Polygon) – The grain polygon to subdivide.

  • spn (int, optional) – Number of seed points for Voronoi tessellation. Default value is 100.

  • seed_lattice_type (str, optional) – Distribution of seed points. Values: 'rand_uni', 'rand_nrm', 'bridson', 'dart', 'lattice.sq', 'lattice.tri', 'lattice.hex'. Default value is 'rand_uni'.

  • combine_small_subs (bool, optional) – Whether to combine small Voronoi cells with neighbours. Default value is False.

Notes

Example call: voronoi_subdivision(pxtal[2], seed_points, combine_small_subs)

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 50],

ybound = [0, 50], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

# ———————————————- cell, cid = gset.pxtals[1].geoms[1], 1 sc = gset.voronoi_subdivision(cell, cid, cid_offset=-1,

spn=100, id_format=’from_cid_max’, seed_lattice_type=’rand_uni’, combine_small_subs=True, _buffer_factor_=0.8,)

len(sc[‘cells’]) >> 31 # the ‘cell’ has been subdivided into 31 sub-cells.

sc[‘pxtal’] # View the actual subcell structures on command line.

get_pxtal(gslevel='base', instance_ID=1, validate=True)[source]

Retrieve a specific poly-xtal object.

Parameters:
  • gslevel (str, optional)

  • instance_ID (str, optional)

get_cells(gslevel='base', instance_ID=1, cids=[0], validate=True)[source]

Extract specific cells from the hierarchy.

Parameters:
  • gslevel (str, optional) – Specify the grain structure level. Default value is ‘base’.

  • instance_ID (int, optional) – Specify the ID of the grain structure instance. Default value is 1.

  • cids (Iterable, optional) – List of cell IDs. Default value is [0].

  • validate (bool, optional) – Specify whether data validation is to be performed. Default value is True.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 50],

ybound = [0, 50], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

# ———————————————- gset.get_cells(gslevel=’base’, instance_ID=1, cids=[0], validate=True)

get_all_cids(gslevel='base', instance_ID=1)[source]

Return the all cids.

convert_subgrains_to_paps(scinfo, pap_instance_ID=1)[source]

Translate a (L0C : L1C-SC) GS to a (PAC : PAP) GS for FM steels.

L0C: Level 0 Cell L1C-SC: Level 1 Cell - Sub-cell PAC: Prior Austenitic Cell PAPC: Prior Austenitic Packets

Parameters:
  • scinfo (dict) – Sub-cell information dictionary obtained from call to function ‘partition_cells’.

  • pap_instance_ID (int, optional) – Instance ID of the PAP GS to create.

  • variable (Data structure of the primary)

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

  • dfb_paps (a key in) – This is a slot variable in UPXO. ~~~ DO NOT ALTER ~~~ saa=True, will set up self.sfb_paps.

  • Explanations

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

  • contains (dfb_paps is primarily a 2-level dictionary. The 1st level)

  • info. (instance and the second level contains the PAP GS)

  • To (dfb_paps can contain any number of instances of pap configurations.)

  • instabce (add a new)

  • new (you will have to call this function with a)

  • as (value for pap_instance_ID. If entered pap_instance_ID exists already)

  • dfb_paps

  • overwritten. (the existing PAP GS will be)

  • function (To create a dbf_PAP using this)

  • been (a subgrains GS must have)

  • gs (previously created. To create the subgrains)

  • the (you cna use)

  • to (function gset.partition_cells(...) with input argument 'throw' set)

  • presnt (True. The returned valkue is the input argument 'scinfo' to the)

  • call. (function)

  • variable

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

  • keys (fdb_paps[instance_ID] would have the following) –

    • instance_ID: Any integer number, preferably >= 0.

  • keys –

    • gslevel_source. Same as SC[‘gslevel_source’]. The level of the

    source grain structure used to make the subgrains, which inturn is fed to this function call. * instance_ID_source. Same as SC[‘instance_ID_source’]. The instance ID number of the source grain structure. * instance_ID_paps. Same as SC[‘instance_ID_partition’]. The instance * base_cid. Base grain structure cells. * pac_cid. Prior austenitic cells. These are cells which host the PAPs. * npac_cid. Non prior austenetic cells. These are cells which do not host PAPs. * papc_cid. PAP cells. List of lists. * papc_cum_cid. PAP cells. Single cumulated list. * fmap_cid. Forward map. Map PAPs to PACs. PAP IDs for every PAC ID. * rmap_cid. Reverse map. Map PACs to PAPs. PAC IDs for every PAP ID.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5, },

‘consider_boundary_grains’: True } }

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 75],

ybound = [0, 75], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[5.], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

‘’’ pxtal = gset.pxtals[instance_ID_source] plt.figure(figsize=(5, 5), dpi=150) coords_cid = [np.vstack(c.boundary.xy).T for c in pxtal.geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’) ‘’’

cids_sd = np.random.choice(range(len(gset.pxtals[1].geoms)), 30, replace=False) sc = gset.partition_cells(gslevel=’base’, instance_ID_source=1,

instance_ID_partition=1, cids_sd=cids_sd, partition_type=’Sub-cell-0’, arg={‘cid_offset’: -1, ‘spn’: 10,

‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.09, ‘niter_max’: 1000, ‘_force_select_’: True},

saa=True, plot_pxtal=False, throw_pxtal=True)

pap = gset.convert_subgrains_to_paps(sc, pap_instance_ID=1)

make_sub_blocks_in_blocks(pxtal_blocks, cids=[], pac_instance_ID=1, base_gs_instance_ID=1, plot_base=True, plot_pac=True, plot_blocks=True)[source]

Build and return sub blocks in blocks.

make_blocks_in_paps(plot_base=True, plot_pac=True, pac_instance_ID=1, base_gs_instance_ID=1, plot_pap=True)[source]

Create the blocks inside PAPs of FM steel GS.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop = {‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5, },

‘consider_boundary_grains’: True }

}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 100],

ybound = [0, 50], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[10], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05, )

‘’’ pxtal = gset.pxtals[1] plt.figure(figsize=(5, 5), dpi=200) coords_cid = [np.vstack(c.boundary.xy).T for c in pxtal.geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=2)

plt.gca().set_aspect(‘equal’) ‘’’

cids_sd = np.random.choice(range(len(gset.pxtals[1].geoms)),

len(gset.pxtals[1].geoms), replace=False)

sc = gset.partition_cells(gslevel=’base’, instance_ID_source=1,

instance_ID_partition=1, cids_sd=cids_sd, partition_type=’Sub-cell-0’, arg={‘cid_offset’: -1, ‘spn’: 10,

‘id_format’: ‘from_cid_max’, ‘seed_lattice_type’: ‘rand_uni’, ‘combine_small_subs’: False, ‘_buffer_factor_’: 0.8, ‘_min_subcell_area_factor_’: 0.09, ‘niter_max’: 1000, ‘_force_select_’: True},

saa=True, plot_pxtal=False, throw_pxtal=True)

gset.convert_subgrains_to_paps(sc, pap_instance_ID=1)

gset.make_blocks_in_paps(plot_base=True, plot_pac=True)

assign_loc_tags(instance=1, gslevel='base', tol=1e-06, saa=True, throw=True)[source]

Assign location tags to each cell feature of gslevel database.

relate_cv_cids(instance=1, geolink={}, technique='dist', use_trees=False, tol=1e-06)[source]

Relate cell vertices to IDs of cells, it is shared with.

Use this to find the cells which share a common vertex. See example.

geolink: dict, optional

Specify the geometry linking dictionary. If empty, it will be calculated and used.

technique: str, optional

Specify the technique to establish vertex point sharing across cells. Options include the following:

  • mid: memory ids. This is quick as it uses just the equality

of UPXo point2d object memory IDs. * dist: Distance based. This would be slower as one would check for point sharing based on zero-distance criteria, wherein two points seperated by a distance less than a specified tolerance value are considered as essentially the same points.

Default value is ‘dist’.

use_trees: bool, optional

Specify whether to construct trees for distance checking. May be slow if more cells exist and cells contain small number of vertices. Only suitable when the number of vertices on each cell is very large. For example, a voronoi cell after having been roughened on its boundaries by grain boundary perturbations would possess a large number of vertex points. In these cases, it would be useful to use the tree structure. Otherwise, it is not recommended. On the contrary, if specified False, then the distances will be calculated using numpy vectorised operations, which is very fast too!

tol: float, optional

Specify the tolerance value used to assess vertex point coincidence if technique chosen is ‘dist’.

Returns:

vc_cids – An inner list provides the IDs of cells that the point at its index in vertex coordinate list, is shared with.

Return type:

list of lists

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

geolink = gset.link_geom(instance=1, saa=True, throw=True)

cv_cid = gset.relate_cv_cids(instance=1, geolink={}, technique=’mid’,

use_trees=False, tol=1.E-6)

# Choose a vertex ID vertex_id = 19

cv_cid[vertex_id] >> [5, 6, 23]

This means that the vertex number 19 of coordinates gset.geolink[‘vc’][19] (>> array([ 4.0866272 , 14.17379263])), is sharfed by the cells (a polygonal feature. This could be a grain, twin, etc.) 5, 6 and 23.

find_On_neigh(instance=1, gslevel='base', On=1, cid_exc_rules_calc=[], cid_exc_rules_results=[], include_central_grain=True, saa=True, throw=True, n_instances=1, __recall__=False)[source]
Parameters:
  • instance (int, optional) – Default value is 1.

  • On (float, optional) – Default value is 1.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 35],

ybound = [0, 30], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

non = gset.find_On_neigh(instance=2, gslevel=’base’, On=0.5,

n_instances=1)

non = gset.find_On_neigh(instance=2, gslevel=’base’, On=1.0,

n_instances=1)

non = gset.find_On_neigh(instance=2, gslevel=’base’, On=2.9,

n_instances=3)

find_neigh_nplus1(neighs_On, include_central_grain=True)[source]

Build and return (n+1)-th order neighbours from n-th order neighbour dict.

Examples

neighs_Onplus1 = gset.find_neigh_nplus1(neighs_On,
                                        include_central_grain=True)
setup_fid(pxnames=['twid', 'prid', 'tcid'])[source]
Below are the valid pxnames:
  • ‘scid’: Sub-cell ID

  • ‘twid’: Twin ID

  • ‘prid’: Precipitate ID

  • ‘clid’: Grain cluster ID. Use this to create cell clusters

    needed to represent Prior Austenitic Packets, grain cluster in materials such as CuCrZr, etc.

  • ‘tcid’: Texture component ID.

The following pxname will be automateically included:
  • ‘phid’: Phase ID

  • ‘bcid’: Base cell ID. Usually represents the graoin.

  • ‘gfid’: Gloabl feature ID

  • ‘hlid’: Hierarchy level ID

Please refer to the below explanations.

1. ‘phid’: Phase ID. Every cell will have a phase ID associated to it. It can be accessed as gset.fid[instance][‘phid’]. 2. ‘bcid’: Every grain, at first creation will be allocated a base grain ID. This will be the 1st order hierarchical feature. All other morphologcal subfeatures will be expressed in relation to this. It can be accessed as gset.fid[instance][‘bcid’]. 3. ‘gfid’: Gloabl feature ID.

It can be accessed as gset.fid[instance][‘gfid’].

  1. ‘hlid’: Hierarchy level ID

    It can be accessed as gset.fid[instance][‘hlid’].

  • ‘scid’: Sub-cell win ID.

  • ‘twid’: Twin ID

  • ‘prid’: Precipitate ID

  • ‘clid’: Grain cluster ID. Use this to create cell clusters

    needed to represent Prior Austenitic Packets, grain cluster in materials such as CuCrZr, etc.

  • ‘tcid’: Texture component ID.

get_stat(data, nan_policy='omit')[source]

Return the stat.

setup_mprop()[source]

Setup mprop.

setup_tprop()[source]

Setup tprop.

find_areas(instance=1, gslevel='base', saa=True, throw=False)[source]

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=20, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

ameans, astd = [], [] for inst in range(gset.ninst):

area = gset.find_areas(instance=inst+1, gslevel=’base’, throw=True) ameans.append(area[‘stat’][‘mean’]) astd.append(area[‘stat’][‘std’])

print(ameans) print(astd) print(ameans[0]-ameans)

find_mprop_all(mprop_name='area', mprop_kwargs={}, gslevel='base', saa=True, throw=False, collect_stats=True, collect_12i_dev=True)[source]

Find morphological property values across all available instances.

Each time the area will be re-calculated.

Parameters:
  • mprop_name (str, optional) – Specify the name of the morphological property. Default value is ‘area’.

  • mprop_kwargs (dict, optional) – Specify the kwargs needed to calculate specific morphological property values. For details refere to the function definition and its documentation of the concerning morphological parameter. Default value is {}.

  • gslevel (str, optional) – Specify name of the morphological feature. Default value is ‘base’.

  • saa (bool, optional) – Specify decision flag to save as attribute(s). Default value is True.

  • throw (bool, optional) – Specify decision flag to return results. Default value is False.

  • collect_stats (bool, optional) – Specify decision flag to collect statistics. Will be returned by default whether throw is True or False. Default value is True.

  • collect_12i_dev (bool, optional) – Specify decision flag to collect deviation of statistical values from 1st to ith instance. Will only work when the collect_stats is True. Negative value indicates that the ith instance’s morphological property statistic value is greater than the 1st instance’s morphological property statistic value. Default value is True.

Returns:

  • mprop_data (dict) – Morphological property data requested for.

  • dev_12i (dict) – Deviation between 1st to ith instance.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=4, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

mprop_data, dev_12i = gset.find_mprop_all(mprop_name=’area’,

mprop_kwargs={}, gslevel=’base’, saa=True, throw=False, collect_stats=True, collect_12i_dev=True)

mprop_data.keys() >> dict_keys([‘val’, ‘minimum’, ‘maximum’, ‘mean’, ‘variance’,

‘skewness’, ‘kurtosis’, ‘std’, ‘median’, ‘p25’, ‘p75’])

dev_12i.keys() >> dict_keys([‘minimum’, ‘maximum’, ‘mean’, ‘variance’,

‘skewness’, ‘kurtosis’, ‘std’, ‘median’, ‘p25’, ‘p75’])

find_ar(instance=1, prop_type='bbox_rot', saa=True, throw=False)[source]

Find aspect ratio of all grains in a given instance.

Three types of aspect ratio calculations can be done, although, one is not truly a measure of aspect ratio. These are:

  • using bounding box. This is the fastest, but less accurate than

using minimum rotated boundinmg box * using envelope. This computes the convex hull envelope and then calculates the aspect ratio. This is not prescibed as results are not validated yet. * using minimum rotated bounding box. This is the most prescribed. Although computational expensive, due to underlying C++ implementations in Shapely, the cost is hardly noticeable. This is more accurate, as it considers the morphological orientation of the grain.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

AR = gset.find_ar(instance=1, prop_type=’bbox_rot’, throw=True) AR = gset.find_ar(instance=1, prop_type=’bbox’, throw=True) AR = gset.find_ar(instance=1, prop_type=’envelope’, throw=True) gset.mprop[1][‘ar’]

Returns:

link –

Following are the keys:

  • vc: Vertex coordinate values: Numpy array.

  • vc_cid: cid wise arranged vc values. Numpy array of numpy

arrays. There will be as many inner numpy arrays as the number of grains. Each inner numpy array corresponds to the coordinate values of the vertex points belonging to that particular grain.

  • vc_cid_ind: Index locations of vertex coordinates of each

vertex in vc_cid, mapped from vc. List of lists. An nnner list consists of index location of the coordinate in vc numpy array.

  • mp: Muti-point object pf all p2ds. Note: This is not a newly

constructed multi-point 2D. Rather, it is extracted from the poly-xtal. So, the mp and p2d are both extracted from the poly-xtal. Important note:

  • p2d: upxo point objects of all points in mp.

  • p2d_cid: same as vc_cid, except that this consists of

UPXO point objects taken from p2d, using vc_cid_ind.

Important note: A UPXO point objects bearing the same coordinate values and occuring in p2d, p2d_cid and mp (i.e. in mp.points), all have the same Memory IDs. That is, the same UPXO point 2d object is used in different places. This provides a major advantage. When a point object is moved, the pxtal construct also changes appropriately !.

Return type:

dict

Examples

link = gset.link_geom(instance=1, saa=True, throw=True)

Notes

link[‘vc_cid_ind’][0]

[25, 18, 14, 15, 22, 25]

link[‘vc_cid_ind’][1]

[18, 28, 27, 13, 14, 18]

link[‘vc_cid’][0]
array([[ 4.79838951, 96.20757309],

[ 2.10309145, 92.63671454], [ 0. , 92.70126343], [ 0. , 100. ], [ 3.17313095, 100. ], [ 4.79838951, 96.20757309]])

link[‘vc_cid’][1]
array([[ 2.10309145, 92.63671454],

[ 5.28912901, 87.18863161], [ 5.03114206, 86.71299143], [ 0. , 86.30397593], [ 0. , 92.70126343], [ 2.10309145, 92.63671454]])

link[‘p2d’][18]

uxpo-p2d (2.1030914538410945,92.63671453775025)

link[‘p2d_cid’][0][1]

uxpo-p2d (2.1030914538410945,92.63671453775025)

link[‘mp2d’].points[18]

uxpo-p2d (2.1030914538410945,92.63671453775025)

id(link[‘p2d’][18])

2113227713792

id(link[‘p2d_cid’][0][1])

2113227713792

id(link[‘mp2d’].points[18])

2113227713792

link[‘p2d’][18]

uxpo-p2d (2.1030914538410945,92.63671453775025)

We will arbitrarily change the coordinates of this point and see it being reflected in all oher places. We will change below: link[‘p2d’][18].x = 0.0 link[‘p2d’][18].y = 90.0

Now, we see that this has reflected in all places. link[‘p2d’][18]

uxpo-p2d (0.0,90.0)

link[‘p2d_cid’][0][1]

uxpo-p2d (0.0,90.0)

link[‘mp2d’].points[18]

uxpo-p2d (0.0,90.0)

make_upxo_gs(instance=1)[source]

Build and return upxo gs.

Reconstruct pxtal from geom link.

setup_fdb()[source]

Setup fdb.

add_fdb(instance=1, gslevels=['base'], fdbs=[None])[source]

Add a feature database instance.

Parameters:
  • gslevels (list) – List of feature names.

  • fdbs (list) – List of feature data bases.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

gset.add_fdb(gslevels=[‘base’],

fdbs=[gset.link_geom(instance=1, saa=True, throw=True)])

gset.fdb_base.keys() >> dict_keys([1])

gset.fdb_base[1].keys() >> dict_keys([‘vc’, ‘instance’, ‘vc_cid’, ‘vc_cid_ind’,

‘p2d’, ‘p2d_cid’, ‘mp’])

plot(instance=1)[source]

Plot all cells of the specified grain structure instance.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True}}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=2, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

gset.plot()

plot_cells(instance=1, cids=[1])[source]

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 125],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=1, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

non = gset.find_On_neigh(instance=1, gslevel=’base’, On=3) gset.plot_cells(instance=1, cids=non[100])

get_nboundaries_cell(cell)[source]

Get the number of interiors of a cell.

Parameters:

cell (shapely.Polygon) – Specify a shapely polygon.

Examples

from shapely.geometry import box, Point
from shapely.ops import unary_union
import matplotlib.pyplot as plt

cell = box(0, 0, 10, 5)
inner = cell.buffer(-0.5)
annulus = cell.difference(inner)
hole_centers = [Point(1, 1), Point(9, 1), Point(5, 0.3), Point(5, 4.7)]
holes = [p.buffer(0.1) for p in hole_centers]
holes_within_annulus = [h for h in holes if annulus.contains(h)]
final_shape = annulus.difference(unary_union(holes_within_annulus))

fs = final_shape
fs.interiors[0]
fs.interiors[1]
fs.interiors[2]
get_cell_vertices_ext_from_cell(cell)[source]

Return the cell vertices ext from cell.

get_cell_vertices_ext_from_lr(lr)[source]

Return exterior vertices from a Shapely LinearRing.

get_cell_vertices(cell)[source]

Get cell vertices.

get_cell_edge_lengths(cell)[source]

Get edge lengths of the shapely polygon.

sf_gbz_cell(cell, k_shr, method='min_dist_centre')[source]

Sub-feature introduction: grain boundary zone: for a single cell

methodstr, optional
Following options are permitted.
  • ‘min_edge_length’

  • ‘min_dist_centre’

  • ‘smallest_skl_length’

sf_gbz(instance=1, gslevel='base', cids=[], k_shr=0.1, assemble_cells=True, assemble_sf=True, saa=True, throw=False, viz=False)[source]

Sub-feature introduction: grain boundary zone: multiple cells.

Parameters:
  • instance (int, optional)

  • gslevel (str, optional)

  • k_shr (float, optional)

  • asemble_cells (bool, optional)

  • assemble_sf (bool, optional)

  • saa (bool, optional)

  • throw (bool, optional)

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 75],

ybound = [0, 100], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=1, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

zones = gset.sf_gbz(instance=1, gslevel=’base’, k_shr=0.15,

assemble_cells=True, saa=True, throw=False, viz=True)

# Find the sub-features, parent cell wise # —————————– pcid = 0 # —————————– gset.pxtals[1].geoms[pcid] # 1 ‘’’This is the 1st parent grain, i.e. 1st base cell.’’’ # —————————– zones[‘cbz’][pcid] # 2 zones[‘ccz’][pcid] # 2 ‘’’This is the boundary and core zones of the 1st base cell.’’’ # —————————– zones[‘sf_pcwise’][pcid] # 3 ‘’’This is multi-cell: zones[‘cbz’][pcid] + zones[‘ccz’][pcid]’’’ # —————————– ‘’’below shows how to access individual geometry of multi-cell’’’ zones[‘sf_pcwise’][pcid][0] # 4 <– subfeature 1 zones[‘sf_pcwise’][pcid][1] # 5 <– subfeature 2 ‘’’Alternatively, you can also access the same as belw9’’’ zones[‘sf_pcwise’][pcid].geoms[0] # 6 <– subfeature 1 zones[‘sf_pcwise’][pcid].geoms[1] # 7 <– subfeature 2 # Note: 4 and 5 is same as 6 and 7 resepectively. # —————————– plt.figure(figsize=(5, 5), dpi=150) coords_cid = [np.vstack(c.boundary.xy).T for c in gset.pxtals[1].geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’) # —————————–

coords_cid_out = [] coords_cid_in = [] sh_mls = shapely.geometry.multilinestring.MultiLineString sh_ls = shapely.geometry.linestring.LineString for c in zones[‘pxtal’].geoms:

cbound = c.boundary if isinstance(cbound, sh_mls):

l = [cbnd.length for cbnd in cbound.geoms] lsort = [i for i in np.argsort(l)[::-1]] ls = [cbound.geoms[i] for i in lsort] # Line strings lscoords = [np.vstack(_ls_.xy).T for _ls_ in ls] coords_cid_out.append(lscoords[0]) coords_cid_in.append(lscoords[1])

if isinstance(cbound, sh_ls):

pass

plt.figure(figsize=(5, 5), dpi=150) for vc in coords_cid_out:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

for vc in coords_cid_in:

plt.plot(vc[:, 0], vc[:, 1], ‘-b’, linewidth=0.75)

plt.gca().set_aspect(‘equal’)

import math hexes = generate_hex_grid_within_bounds(

hex_area=10, x_min=0, y_min=0, x_max=100, y_max=100

)

rounded_hexes = [round_coords(h, ndigits=6) for h in hexes] combined = unary_union(rounded_hexes)

MultiPolygon(hexes)

from shapely.ops import unary_union, snap reference = hexes[0] snapped = [snap(h, reference, tolerance=1e-6) for h in hexes] combined = unary_union(snapped)

plt.figure(figsize=(5, 5), dpi=150) coords_cid = [np.vstack(c.boundary.xy).T for c in unary_union(hexes).geoms] for vc in coords_cid:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

plt.gca().set_aspect(‘equal’)

gen_pol6_grid(amin, bounds)[source]

Generate hexagonal tessellation within the bounds.

Examples

from upxo.pxtal.vortess2d import gtess2d repr_prop={‘area’: {‘mean’: {‘val’: 50, ‘dev’: 7.5,},

‘consider_boundary_grains’: True},}

gset = gtess2d.from_seed_points(sp_input=’gen’, xbound=[0, 50],

ybound = [0, 50], sp_distr=’random’, gr_tech=’pds’, smp_tech=’bridson1’, lean=’veryhigh’, char_length=[4.5], niter=10, ntrials=100, n_instances=1, repr_prop=repr_prop, k_char_length_inc=0.05, k_char_length_dec=0.05,)

zones = gset.sf_gbz(instance=1, gslevel=’base’, k_shr=0.1,

assemble_cells=True, saa=True, throw=False, viz=True)

# zones[‘ccz’][0].boundary # nedges = len(zones[‘ccz’][0].boundary.coords)-2

zones[‘ccz_hex’] = [] zones[‘cbz_new’] = [] zones[‘ccz_offcut’] = []

amin_spec = ‘by_cell’ # options: ‘uniform’, ‘by_cell’ amin_fac = 0.03

if amin_spec == ‘uniform’:
amin = amin_fac*np.array([cell.area

for cell in gset.pxtals[1].geoms]).min()

for ci, cell in enumerate(zones[‘ccz’]):
if amin_spec == ‘by_cell’:

amin = gset.pxtals[1].geoms[ci].area * amin_fac

bounds = cell.bounds hexes = gset.gen_pol6_grid(amin, bounds) hexcells = [] for i, flag in enumerate([hex.within(cell) for hex in hexes]):

if flag:

hexcells.append(hexes[i])

ccz_offcut = cell - unary_union(hexcells) zones[‘ccz_offcut’].append(ccz_offcut)

# ccz_offcut = gset._round_coords_(ccz_offcut, ndigits=6)

zones[‘cbz_new’].append(unary_union([ccz_offcut, zones[‘cbz’][ci]]))

# MultiPolygon([ccz_offcut, zones[‘cbz’][ci]])

# zones[‘cbz’][2] gset.pxtals[1].geoms[2] - unary_union(hexcells) zones[‘ccz_hex’].append(unary_union(hexcells))

coords_cid_out = [] coords_cid_in = [] sh_mls = shapely.geometry.multilinestring.MultiLineString sh_ls = shapely.geometry.linestring.LineString for c in zones[‘cbz_new’]:

cbound = c.boundary if isinstance(cbound, sh_mls):

ls = [_ls_ for _ls_ in cbound.geoms] # Line strings lscoords = [np.vstack(_ls_.xy).T for _ls_ in ls] coords_cid_out.append(lscoords[0]) coords_cid_in.append(lscoords[1])

if isinstance(cbound, sh_ls):

pass

plt.figure(figsize=(5, 5), dpi=150) for vc in coords_cid_out:

plt.plot(vc[:, 0], vc[:, 1], ‘-k’, linewidth=1.25)

for vc in coords_cid_in:

plt.plot(vc[:, 0], vc[:, 1], ‘-b’, linewidth=0.75)

plt.gca().set_aspect(‘equal’)

fid
floc
cids_base
fdb_pix
fdb_pert
fdb_supset
neighs_cid
xomap
n
gbjp
grain_locs
gpos
find_scells_in_tcell(scells, tcell)[source]

Find scells in tcell.

assemble_cells(features)[source]

Assemble cells.

perturb_feat(instance=1, gslevel='base', cid=[])[source]

Perturb feat.

fe_mesh(instance=1, gslevel='base', tool='gmsh')[source]

Fe mesh.

get_idmap_cf(gslevel, instance_ID, fname, fid, cids=[])[source]

Use this function to get cellIDs–>feature_ID mapping.

Parameters:
  • gslevel (str) – Grain structure hierarchy level name. Must be a valid name. Please refer to self._valid_gslevels_ for all permitted gslevel values.

  • instance_ID (str) – Instance number of the pxtal.

  • fname (str) – Feature name. Could be ‘ph’ for phase, etc.

  • fid (int) – Feature ID number. If fname is ‘ph’, then this would indicate which phase is needed.

  • cids (list, optional) – Cell IDs.

Returns:

mapping – A list of cell IDs belonging to the instance_ID, fname and fid.

Return type:

list

Example

gset.get_idmap_cf(‘base’, 1, ‘ph’, 1, cids=[12])

The above code accessess all the cells belonging to phase of phase_ID, in the pxtal instance specified by instance_ID.

Notes

The data can also be directly accessed as below. This, however, is not the recommended way to access the data, as its prone to human errors and complex code.

Data structure

gslevel = ‘base’ instance_ID = 1 fname = ‘ph’ fid = 1 cell_ID = 15

gset._idmap_cf_[gslevel].keys() gset._idmap_cf_[gslevel][instance_ID].keys() gset._idmap_cf_[gslevel][instance_ID][fname].keys() gset._idmap_cf_[gslevel][instance_ID][fname][fid][cell_ID]

cell_IDs = [1, 5, 20] [gset._idmap_cf_[gslevel][instance_ID][fname][fid][c] for c in cell_IDs]

Author

Dr. Sunil Anandatheertha

get_idmap_fc(gslevel, instance_ID, fname, cids=[])[source]

Use this function to get feature_ID–>cellIDs mapping.

Parameters:
  • gslevel (str) – Grain structure hierarchy level name. Must be a valid name. Please refer to self._valid_gslevels_ for all permitted gslevel values.

  • instance_ID (str) – Instance number of the pxtal.

  • fname (str) – Feature name. Could be ‘ph’ for phase, etc.

  • fid (int) – Feature ID number. If fname is ‘ph’, then this would indicate which phase is needed.

  • cids (list, optional) – Cell IDs.

Returns:

mapping – A list of cell IDs belonging to the instance_ID, fname and fid.

Return type:

list

Example

gslevel = ‘base’ instance_ID = 1 fname = ‘ph’ cell_IDs = [15, 25]

gset.get_idmap_fc(gslevel, instance_ID, fname, cell_IDs)

Notes

The data can also be directly accessed as below. This, however, is not the recommended way to access the data, as its prone to human errors and complex code.

Data structure

gset._idmap_fc_[gslevel].keys() gset._idmap_fc_[gslevel][instance_ID].keys() [gset._idmap_fc_[gslevel][instance_ID][fname][c] for c in cell_IDs]

validate_instance_ID(gslevel, instance_ID)[source]

Check or validate validate instance ID.

class upxo.pxtal.geotess2d(*, from_mcgs=False)[source]

Bases: object

Base 2D geometric / Voronoi-style tessellation grain structure.

Parent type for VTGS-style pipelines: holds seeds, junction/vertex points, grain-boundary edges, grain polygons (xtals), neighbour maps, and a property table. Prefer specialised constructors on related VT / polyxtal classes when available; many seed and neighbour helpers on this base remain stubs.

bounds

Domain bounds on x and y.

seeds

Seed multipoint / array for the tessellation.

grid

Optional underlay x/y grids.

jp, vp

Junction and vertex points (UPXO point entities).

gbedges, gbseg

Grain-boundary edges and multi-edge segments.

xtals

Grain polygons (typically Shapely).

gid

Grain IDs.

Type:

list

neigh_gid

Neighbour grain IDs per grain.

Type:

dict

prop

Morphological / other property table (e.g. DataFrame).

info

Metadata (including whether built from_mcgs).

Type:

dict

set_seed_points(upxo_mp2d=None)[source]

Set or update seed points.

make_seeds_random(nsp=50, bounds=None)[source]

Build uniform-random seed points within the domain bounds.

Parameters:
  • nsp (int, optional) – Number of seed points to generate. Default value is 50.

  • bounds (list or tuple, optional) – Domain bounds as [xmin, xmax, ymin, ymax]. If given, replaces and updates self.bounds. If None, uses the existing self.bounds, falling back to [0.0, 1.0, 0.0, 1.0] when unset.

Returns:

seeds – The generated seed points, also stored in self.seeds. Returned as an upxo.geoEntities.mulpoint2d.MPoint2d when construction from coordinates succeeds, otherwise as a plain (nsp, 2) array of x, y coordinates.

Return type:

MPoint2d or numpy.ndarray

make_seeds_pdisc(char_length=0.1, bounds=None)[source]

Build Poisson-disc seed points using Bridson sampling.

Parameters:
  • char_length (float, optional) – Minimum allowed spacing (disc radius) between seed points, in the same length units as bounds. Default value is 0.1.

  • bounds (list or tuple, optional) – Domain bounds as [xmin, xmax, ymin, ymax]. If given, replaces and updates self.bounds. If None, uses the existing self.bounds, falling back to [0.0, 1.0, 0.0, 1.0] when unset.

Returns:

seeds – The generated seed points, also stored in self.seeds. Returned as an upxo.geoEntities.mulpoint2d.MPoint2d when construction from coordinates succeeds, otherwise as a plain (n, 2) array of x, y coordinates.

Return type:

MPoint2d or numpy.ndarray

Notes

Delegates to upxo.statops.sampling.bridson_uniform_density, which samples in a width x height window before the result is translated by (xmin, ymin) back into the requested bounds.

make_seeds_dart()[source]

Build and return seeds dart.

set_seeds(seeds)[source]

Set or update seeds.

save()[source]

Save.

load()[source]

Load.

find_neighbours()[source]

Find neighbours for all grains in xtals using boundary topology.

For every pair of grain polygons, checks whether they touch or intersect and, if so, whether their intersection is a genuine shared boundary (a non-empty line with length > 1e-9, or a LineString/MultiLineString intersection geometry) rather than a single touching point. Qualifying pairs are recorded as mutual neighbours.

This is an exhaustive O(n^2) pairwise scan over self.xtals (n grains), each pairwise check itself calling into Shapely’s touches/intersects/intersection. There is no spatial index, so this does not scale well to large grain counts.

Returns:

neigh_gid – Mapping of grain ID to a list of neighbouring grain IDs. Also stored on self.neigh_gid, replacing any previous content. Keys are self.gid when its length matches len(self.xtals), otherwise range(len(self.xtals)).

Return type:

dict

Notes

Mutates self.neigh_gid in place (it is reset to an empty-list-per-grain dict at the start of the call) in addition to returning it.

find_first_nearest_neighbours(gid=None)[source]

Return first-nearest (directly touching) neighbour grain IDs.

Computes self.neigh_gid via find_neighbours() first if it has not been populated yet (i.e. is falsy/empty); an already populated self.neigh_gid is reused as-is and not recomputed.

Parameters:

gid (hashable, optional) – Grain ID to query. If None (default), results for all grains are returned.

Returns:

neighbours – If gid is given: a list of first-nearest-neighbour grain IDs for that grain ([] if gid is unknown). If gid is None: the full self.neigh_gid dict mapping every grain ID to its list of first-nearest-neighbour IDs.

Return type:

list or dict

find_second_nearest_neighbours(gid=None)[source]

Return second-nearest neighbour grain IDs (neighbours of neighbours).

For a given grain, the second-nearest neighbours are the union of first-nearest neighbours of each of its first-nearest neighbours, excluding the grain itself and excluding any grain already counted as a first-nearest neighbour.

Computes self.neigh_gid via find_neighbours() first if it has not been populated yet (i.e. is falsy/empty); an already populated self.neigh_gid is reused as-is and not recomputed.

Parameters:

gid (hashable, optional) – Grain ID to query. If None (default), results for all grains present in self.neigh_gid are returned.

Returns:

neighbours – If gid is given: a sorted list of second-nearest-neighbour grain IDs for that grain. If gid is None: a dict mapping every grain ID in self.neigh_gid to its sorted list of second-nearest-neighbour IDs.

Return type:

list or dict

filter_boundary_grains()[source]

Return grain IDs that touch or intersect the domain boundary.

Returns:

boundary_grains – Grain IDs whose polygon intersects the boundary of the domain box built from self.bounds. Empty list if self.bounds or self.xtals is unset/empty.

Return type:

list

filter_internal_grains()[source]

Return grain IDs that do not touch the domain boundary.

Returns:

internal_grains – Grain IDs in self.gid (or range(len(self.xtals)) when self.gid doesn’t match in length) that are not in the result of filter_boundary_grains().

Return type:

list

filter_grains_by_loc(loc='internal')[source]

Filter grains by loc (‘internal’ or ‘boundary’).

filter_grains_by_prop(col, op, val)[source]

Filter grains in self.prop by a comparison on one property column.

Parameters:
  • col (str) – Column name in self.prop to filter on.

  • op (str) – Comparison operator. One of '>', '>=', '<', '<=', '==', '!='.

  • val (object) – Value to compare self.prop[col] against.

Returns:

filtered – Subset of self.prop where self.prop[col] op val is True.

Return type:

pandas.DataFrame

Raises:

ValueError – If self.prop is not a pandas DataFrame, or if op is not one of the supported operator strings.

divide_all_edges_in_half()[source]

Divide all edges in half.

move_new_vertex_point()[source]

Move new vertex point.

perturb_grain_boundaries(factor=0.05, seed=None)[source]

Perturb grain boundaries with controlled curvature while keeping junctions fixed.

Parameters:
  • factor (float, optional) – Magnitude of the boundary perturbation (curvature strength), passed through to upxo.pxtal.voronoi_tessellation_2d.engine.perturb_interfaces_2d. Default value is 0.05. Larger values produce more strongly curved grain boundaries; junctions (grain-boundary triple points) remain fixed regardless of factor.

  • seed (int, optional) – Random seed for reproducible perturbation. Default value is None (non-deterministic).

Returns:

xtals – The updated list of grain polygons, also stored in self.xtals. Returned unchanged (and self.xtals is left untouched) if self.xtals is empty.

Return type:

list

convert_to_pixels()[source]

Convert to pixels.

bounds
seeds
grid
gridpoints
jp
vp
gbedges
gbseg
xtals
gid
neigh_gid
prop
info
upxo.pxtal.generate_voronoi_2d(seeds: numpy.ndarray, bounds: Sequence | Dict | None = None, periodic: Tuple[bool, bool] = (False, False), weights: numpy.ndarray | None = None, cvt_iterations: int = 0, perturb_factor: float = 0.0, clip: bool = True, random_seed: int | None = 42) → Dict[str, Dict[int, shapely.geometry.Polygon] | shapely.geometry.MultiPolygon | numpy.ndarray | List[List[float]] | Tuple[bool, bool]][source]

Main orchestration function for high-fidelity 2D Voronoi geometry generation.

Parameters:
  • seeds (np.ndarray, shape (N, 2)) – Seed point coordinates.

  • bounds (sequence or dict, optional) – Domain bounds [[xmin, xmax], [ymin, ymax]]. If None, inferred from seeds.

  • periodic (tuple of bool, optional) – (periodic_x, periodic_y) flags for Periodic Boundary Conditions.

  • weights (np.ndarray, shape (N,), optional) – Seed weights for Laguerre / Power diagram tessellation.

  • cvt_iterations (int, optional) – Number of Lloyd relaxation iterations for Centroidal Voronoi.

  • perturb_factor (float, optional) – Magnitude of non-linear grain boundary interface perturbation.

  • clip (bool, optional) – Whether to clip cells to the bounding box. Default is True.

  • random_seed (int, optional) – RNG seed for perturbation reproducibility. Default is 42.

Returns:

‘cells’ : dict of {int: Polygon} ‘pxtal’ : Shapely MultiPolygon containing all cells ‘seeds’ : np.ndarray of final seed positions ‘bounds’ : standard bounds [[xmin, xmax], [ymin, ymax]] ‘periodic’ : (bool, bool)

Return type:

dict

upxo.pxtal.compute_standard_voronoi_2d(seeds: numpy.ndarray, bounds: Sequence | Dict | None = None, periodic: Tuple[bool, bool] = (False, False), clip: bool = True) → Dict[int, shapely.geometry.Polygon][source]

Compute bounded 2D Voronoi polygons mapped exactly to seed indices.

Parameters:
  • seeds (np.ndarray, shape (N, 2)) – Seed coordinates.

  • bounds (sequence or dict, optional) – Domain bounds [[xmin, xmax], [ymin, ymax]]. If None, inferred from seeds.

  • periodic (tuple of bool, optional) – (periodic_x, periodic_y). Default is (False, False).

  • clip (bool, optional) – Whether to clip cells to the bounding box. Default is True.

Returns:

dict of {int – Mapping from seed index (0 .. N-1) to Shapely polygon.

Return type:

Polygon or MultiPolygon}

upxo.pxtal.compute_power_diagram_2d(seeds: numpy.ndarray, weights: Sequence[float] | numpy.ndarray | None = None, bounds: Sequence | Dict | None = None, periodic: Tuple[bool, bool] = (False, False), clip: bool = True) → Dict[int, shapely.geometry.Polygon][source]

Compute 2D Laguerre tessellation / Power diagram using the lifted 3D lower convex hull.

For each seed point \(\mathbf{s}_i = (x_i, y_i)\) with weight \(w_i\), the power cell is the set of points \(\mathbf{x}\) satisfying: \(\|\mathbf{x} - \mathbf{s}_i\|^2 - w_i \le \|\mathbf{x} - \mathbf{s}_j\|^2 - w_j\).

Parameters:
  • seeds (np.ndarray, shape (N, 2)) – Seed coordinates.

  • weights (sequence or np.ndarray, shape (N,), optional) – Seed weights (e.g. squared target radii). If None, defaults to uniform weights.

  • bounds (sequence or dict, optional) – Domain bounds [[xmin, xmax], [ymin, ymax]]. If None, inferred from seeds.

  • periodic (tuple of bool, optional) – (periodic_x, periodic_y). Default is (False, False).

  • clip (bool, optional) – Whether to clip cells to the bounding box. Default is True.

Returns:

dict of {int – Mapping from seed index (0 .. N-1) to Shapely polygon.

Return type:

Polygon or MultiPolygon}

upxo.pxtal.cvt_relax_2d(seeds: numpy.ndarray, bounds: Sequence | Dict | None = None, iterations: int = 10, periodic: Tuple[bool, bool] = (False, False), weights: numpy.ndarray | None = None, max_iter: int | None = None) → numpy.ndarray[source]

Perform Centroidal Voronoi Tessellation (CVT) relaxation via Lloyd’s algorithm.

Iteratively updates each seed to the centroid of its Voronoi cell, producing regular, energy-minimized, equiaxed polycrystal seed configurations.

Parameters:
  • seeds (np.ndarray, shape (N, 2)) – Initial seed coordinates.

  • bounds (sequence or dict, optional) – Domain bounds [[xmin, xmax], [ymin, ymax]]. If None, inferred from seeds.

  • iterations (int, optional) – Number of Lloyd relaxation steps. Default is 10.

  • periodic (tuple of bool, optional) – (periodic_x, periodic_y). Default is (False, False).

  • weights (np.ndarray, optional) – Optional seed weights for weighted CVT. Default is None.

  • max_iter (int, optional) – Alias for iterations.

Returns:

Relaxed seed coordinates.

Return type:

np.ndarray, shape (N, 2)

upxo.pxtal.perturb_interfaces_2d(cells: Dict[int, shapely.geometry.Polygon] | Sequence[shapely.geometry.Polygon] | shapely.geometry.MultiPolygon, bounds: Sequence | Dict | None = None, perturb_factor: float = 0.05, n_subdivisions: int = 2, random_seed: int | None = 42, factor: float | None = None, seed: int | None = None) → Dict[int, shapely.geometry.Polygon] | List[shapely.geometry.Polygon] | shapely.geometry.MultiPolygon[source]

Apply natural non-linear curvature perturbations to shared grain boundaries.

Internal grain boundaries are subdivided and displaced while domain boundary edges and triple/multiple junctions remain topologically pinned, ensuring watertight manifolds.

Parameters:
  • cells (dict, list, or MultiPolygon of Polygons) – Input Voronoi cells.

  • bounds (sequence or dict, optional) – Domain bounds [[xmin, xmax], [ymin, ymax]].

  • perturb_factor (float, optional) – Magnitude of perpendicular perturbation relative to edge length. Default 0.05.

  • n_subdivisions (int, optional) – Number of recursive midpoint subdivisions per edge. Default 2.

  • random_seed (int, optional) – RNG seed for reproducible perturbations. Default 42.

  • factor (float, optional) – Alias for perturb_factor.

  • seed (int, optional) – Alias for random_seed.

Returns:

Cells with curved/perturbed interfaces, preserving input collection type.

Return type:

dict, list, or MultiPolygon