import networkx
import numpy as np
import pyvista as pv
from copy import deepcopy
import matplotlib.pyplot as plt
from dataclasses import dataclass, field
from upxo._sup import dataTypeHandlers as dth
from scipy.ndimage import label as spndimg_label
from upxo.pxtal import img_essentials_01
[docs]
class IMAGE_3D:
"""
Description of slot variables
-----------------------------
img: 3D Numpy array. np.int32
fid: 0D Numpy array of list of feature IDs. np.int32
n: Number of individual features. int
neigh_fid: immediate neighbour feature ID database. dict
vox: Information on voxels in the image. dataclass
vol: Total volume
bvox:
"""
__slots__ = ('base', 'img', 'vox', 'rve', 'ctrl',
'mops', 'tops', 'sops', 'rops',
'coords', 'H',
'fid', 'n', 'neigh_fid',
'bvox',
'neigh_pairs',
'mprop',
'tprop',
'srep'
)
def __init__(self, image3d):
"""Initialise the instance."""
self.ctrl = {}
self.base = image3d
# ------------------------
self.vox = self.vox_CLS(1.0)
self.rve = self.rve_CLS(*np.flip(self.img.shape), self.vox)
# ------------------------
self.ids = self.ids_CLS()
# ------------------------
self.coords = self.build_coords()
# ------------------------
self.ctrl['part'] = self.part_cntr_CLS(1)
# ------------------------
self.mops = self.mops_CLS(ctrl=self.ctrl['part'], fx=self.mprops_CLS())
self.img, self.ids.c = self.mops.part(self.base)
# ------------------------
self.tops = self.tops_CLS(fx=self.tprops_CLS())
self.sops = self.sops_CLS(fx=self.sprops_CLS())
self.rops = self.rops_CLS(fx=self.rprops_CLS())
def __repr__(self):
"""Return a string representation of this instance."""
return f"IMAGE_3D: shape={self.img.shape}, n_features={self.ids.c}"
[docs]
def build_coords(self):
"""Build and return coords."""
self.coords = np.indices((self.rve.zn, self.rve.yn,
self.rve.xn)).reshape(3, -1).T
self.ids.v = np.arange(1, self.coords.shape[0]+1)
[docs]
def part(self):
"""Partition the 3D image into below individual features.
* closed domains (ex. grains)
* total domain boundary (ex. all grain boundary segments)
* domain boundary segments (ex. individual grain boundary segments)
* domain boundary segment edges
* domain bondarty segment edge junction points
"""
self.fdb, N = spndimg_label(self.img, structure=self.part_cntr.bstruct)
# =========================================================================
[docs]
class mops_CLS:
"""Morphological operations"""
__slots__ = ('fx', 'ctrl')
def __init__(self, ctrl, fx):
"""Initialise the instance."""
self.ctrl = ctrl
self.fx = fx
[docs]
def part(self, img):
"""Partition the 3D image into below individual features.
* closed domains (ex. grains)
* total domain boundary (ex. all grain boundary segments)
* domain boundary segments (ex. individual grain boundary segments)
* domain boundary segment edges
* domain bondarty segment edge junction points
"""
fdb, N = spndimg_label(img, structure=self.cntr.bstruct)
return fdb, N
[docs]
def find_CLS_mprops(self):
"""Find CLS mprops."""
pass
[docs]
class tops_CLS:
"""Topological operations
1. handle all ops with neighbour database
"""
__slots__ = ('DCI', 'maps', 'no', 'ntype', 'pairs',
'G')
def __init__(self, def_cls_inst):
'''def_cls_inst: Definitions class instance.'''
self.DCI = def_cls_inst
[docs]
def find_on_neighs(self, on, prob):
"""Find on neighs."""
pass
[docs]
def find_onth_neighs(self, on, prob):
"""Find onth neighs."""
pass
[docs]
def cluster(self, clustering_stats):
"""Cluster."""
pass
[docs]
def make_graph(self):
"""Build and return graph."""
pass
[docs]
def partition(self):
"""Partition."""
pass
[docs]
def crop_neigh_gid(self, neigh_gid='O(1)', gids_to_crop=None):
"""
Removes gids in gids_to_crop from neighbour order dictionary.
Both keys and appearences in values get removed.
Parameters
----------
neigh_gid: str | dict
Neighbour gid dictionary. If a string liuke 'O(1)' is entered,
then the corresponding will be extracted. Idf the neighbour
does not exist, the method should rauise an error and stop. If
the value is dictionary, then entered value will be used
without any validations. Defaults to 'O(1)'.
gids_to_crop: dth.dt.ITERABLES | integer
Grain ids to be cropped from neigh_gid. Value could be any in
dth.dt.ITERABLES or of any integrer type in dth.dt.INTEGERS.
Defaults to None.
Examples
--------
.. code-block:: python
gstlice.crop_neigh_gid(neigh_gid='O(1)', gids_to_crop=[1])
"""
# User input validations
if type(neigh_gid) != dict:
raise ValueError('neigh_gid invalid')
if type(gids_to_crop) in dth.dt.INTEGERS:
gids_to_crop = [gids_to_crop]
if type(gids_to_crop) not in dth.dt.ITERABLES:
raise ValueError('gids_to_crop invalid')
# --------------
if type(neigh_gid) == str:
if neigh_gid.lower() == 'o(1)':
neigh_gid = self.neigh_gid
else:
# Other codes for later development if needed.
# We can work on other order dictionaries here.
pass
# Remove keys and values
for gidcrop in gids_to_crop:
neigh_gid.pop(gidcrop)
# Remove gids from the values of other gids
gids_to_crop = set(gids_to_crop)
for gid in neigh_gid.keys():
neigh_gid[gid] = set(neigh_gid[gid])
neigh_gid[gid] = neigh_gid[gid] - gids_to_crop
neigh_gid[gid] = list(neigh_gid[gid])
return neigh_gid
[docs]
class sops_CLS:
"""Spatial operations"""
__slots__ = ('fx', )
def __init__(self, fx):
"""Initialise the instance."""
self.fx = fx
[docs]
def find_loc(self):
"""Find loc."""
pass
[docs]
class mprops_CLS:
"""Class to find morphological propertues"""
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class tprops_CLS:
"""Class to find topological properties"""
def __init__(self):
"""Initialise the instance."""
pass
[docs]
def G_max_ind_set(self, G):
"""G max ind set."""
return networkx.maximal_independent_set(G)
[docs]
def G_conn_comp(self, G):
"""G conn comp."""
return [set(c) for c in networkx.connected_components(G)]
[docs]
class sprops_CLS:
"""Class to find spatial properties"""
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class rprops_CLS:
"""Class to find representativeness properties"""
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class mviz_CLS:
def __init__(self, outer):
"""Initialise the instance."""
pass
[docs]
class tviz_CLS:
def __init__(self, outer):
"""Initialise the instance."""
pass
[docs]
class mpviz_CLS:
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class cell_CLS:
__slots__ = ('type')
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class xtal_CLS(cell_CLS):
__slots__ = ("a")
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class xb_CLS(cell_CLS):
"""xtal_boundary"""
__slots__= ("a")
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class xbseg_CLS(cell_CLS):
"""xtal_boundary segment"""
__slots__ = ("a")
def __init__(self):
"""Initialise the instance."""
pass
[docs]
class xjv_CLS(cell_CLS):
"""xtal_junction_voxels"""
__slots__ = ("a")
def __init__(self):
"""Initialise the instance."""
pass