Source code for upxo.ggrowth.make3d

import numpy as np
import pyvista as pv
import matplotlib.pyplot as plt
import seaborn as sns
import upxo.viz.gsviz as viz

[docs] class voxel_from_pixel: __slots__ = ('gsstack', 'sstack', 's', 'q', 'lfi', 'pvgrid', 'meta_dict', 'fid', 's_fid', 'fid_s', 'coords', 'rep_coords' ) """ Slot variables -------------- gsstack: dict A dictionary containing the UPXO grain structure stack. sstack: dict A dictionary containing the State array stack. s: np.ndarray A 3D numpy array reconstructed from the (gs/s)stack. lfi: np.ndarray A 3D numpy array of Local Feature IDs, analgous to `lgi` in MCGS. pvgrid: pyvista.UniformGrid A PyVista UniformGrid object for 3D visualization. """ def __init__(self, STACK, meta_dict={'creation': 'from_sstack'}): """Initialise the instance.""" self.meta_dict = meta_dict if meta_dict['creation'] == 'from_sstack': self.sstack = STACK self.gsstack = None if meta_dict['creation'] == 'from_gsstack': self.gsstack = STACK self.sstack = {k: gs.s for k, gs in STACK.items()} # Build the 3D State array stack self.stack() self.build_pvgrid() def __repr__(self): """Return a string representation of this instance.""" if self.meta_dict['creation'] == 'from_sstack': stack_size = len(self.sstack) elif self.meta_dict['creation'] == 'from_gsstack': stack_size = len(self.gsstack) return ''.join([f"<vox_frm_pix: {id(self)}, ", f"{self.meta_dict['creation']}, ", f"{stack_size} slices>", ])
[docs] @classmethod def from_gsstack(cls, gsstack, meta_dict=dict()): """Construct this instance from gsstack.""" meta_dict.setdefault('creation', 'from_gsstack') return cls(gsstack, meta_dict=meta_dict)
[docs] @classmethod def from_sstack(cls, sstack, meta_dict=dict()): """Construct this instance from sstack.""" meta_dict.setdefault('creation', 'from_sstack') return cls(sstack, meta_dict=meta_dict)
[docs] @classmethod def from_gsgen(cls, input_dashboard=None, meta_dict=dict(), retain_gsdb=False): """Construct this instance from gsgen.""" if input_dashboard is None: raise ValueError( "input_dashboard must be provided — supply the path to your " "UPXO input Excel file (e.g. 'my_params.xls')." ) # ---------- Import MCGS ---------- from upxo.ggrowth.mcgs import mcgs pxt = mcgs(input_dashboard=input_dashboard) pxt.simulate() # --------------------------------- meta_dict.setdefault('retain_gsdb', retain_gsdb) # --------------------------------- if retain_gsdb: STACK = pxt.gs meta_dict.setdefault('creation', 'from_gsstack') return cls.from_gsstack(STACK, meta_dict=meta_dict) else: STACK = {k: gs.s for k, gs in pxt.gs.items()} meta_dict.setdefault('creation', 'from_sstack') return cls.from_sstack(STACK, meta_dict=meta_dict)
[docs] @classmethod def from_empty(cls): """Construct this instance from empty.""" meta_dict = {'creation': 'from_empty'} STACK = dict() return cls(STACK, meta_dict=meta_dict)
[docs] def stack(self): """Stack.""" self.s = np.stack([self.sstack[k] for k in sorted(self.sstack.keys())], axis=-1, dtype=np.int16) self.q = np.unique(self.s)
[docs] def add_slice(self, location, gs, gstype='2D'): """Add or insert slice.""" self.gsstack[location] = gs
[docs] def find_cells(self, method, connectivity=3): """Find cells.""" if method == 1: from upxo.gsdataops.grid_ops import detect_grains_3d self.lfi = detect_grains_3d(self.s, connectivity=connectivity, return_num_grains=False) elif method == 2: from upxo.gsdataops.grid_ops import detect_grains_3d_optimized self.lfi = detect_grains_3d_optimized(self.s, connectivity=connectivity, return_num_grains=False) elif method == 3: from upxo.gsdataops.grid_ops import detect_grains_greedy_3d self.lfi = detect_grains_greedy_3d(self.s) elif method == 4: from upxo.gsdataops.grid_ops import detect_grains_using_s self.lfi = detect_grains_using_s(self.s, self.q) elif method == 5: from upxo.gsdataops.grid_ops import detect_grains_fast_v3 self.lfi = detect_grains_fast_v3(self.s, self.q) else: raise ValueError("method must be 1, 2, or 3.") self.build_fids() self.build_coords() self.build_lfi_s() self.build_s_lfi()
[docs] def build_fids(self): """Build and return fids.""" self.fid = np.asarray(np.unique(self.lfi), dtype=np.int64)
[docs] def build_coords(self): """Build and return coords.""" coords = {} for fid in self.fid: coords[int(fid)] = np.argwhere(self.lfi == fid) self.coords = coords self.build_rep_coords()
[docs] def build_rep_coords(self): """Build and return rep coords.""" rep_coords = [] for coord in self.coords.values(): rep_coords.append(coord[0]) self.rep_coords = rep_coords
[docs] def build_lfi_s(self): """Build and return lfi s.""" self.fid_s = {int(fid): int(self.s[coord[0], coord[1], coord[2]]) for fid, coord in zip(self.fid, self.rep_coords)}
[docs] def build_s_lfi(self): """Build and return s lfi.""" self.s_fid = {int(s): [] for s in self.q} for fid, s in self.fid_s.items(): self.s_fid[s].append(fid)
[docs] def build_pvgrid(self, db='s', origin=(0, 0, 0), spacing=(1.0, 1.0, 1.0)): """Build and return pvgrid.""" if not hasattr(self, 'pvgrid'): self.pvgrid = dict() if db == 's': data = self.s elif db == 'lfi': data = self.lfi else: raise ValueError("db must be 's' or 'lfi'.") from upxo.gsdataops.grid_ops import build_pvgrid self.pvgrid[db] = build_pvgrid(data=data, origin=origin, spacing=spacing)
[docs] def see_stack(self, db='s', opacity='linear', cmap='nipy_spectral'): """See stack.""" self.pvgrid[db].plot(cmap=cmap, show_scalar_bar=True, opacity=opacity, jupyter_backend='pythreejs')
[docs] def section(self, db='s', axis=0, location=0): """Section.""" if db == 's': DB = self.s elif db == 'lfi': DB = self.lfi else: raise ValueError("db must be 's' or 'lfi'.") from upxo.gsdataops.grid_ops import section_from_3d return section_from_3d(DB, axis=axis, location=location)
[docs] def see_section(self, db='s', axis=0, location=0, preset='minimal',): """See section.""" section = self.section(db=db, axis=axis, location=location) viz.see_map(section, cmap='viridis', preset=preset, title=f"Section of {db} at axis {axis}, loc {location}", xlabel=['Simulation time', 'Simulation time', 'Y-axis'][axis], ylabel=['Y-axis', 'X-axis', 'X-axis'][axis] )