merged the newest development

This commit is contained in:
Cathy Bing 2023-11-28 17:28:58 -05:00
commit 4542d97725
68 changed files with 244 additions and 243 deletions

@ -1 +1 @@
Subproject commit 6f4a7a8598dfceae5c2178c8c2554245d8164cb2 Subproject commit bc2c8e3b8f405fdda0d69a2900d9b94c7cc0936f

View File

@ -1 +1 @@
3.0.0-alpha8-50-gf02c1dc44 3.0.0-alpha8-53-g05c4fcbea

View File

@ -193,7 +193,7 @@ if filenames == []: filenames = [None]
for name in filenames: for name in filenames:
print(script_name+': '+name) print(script_name+': '+name)
geom = damask.Grid.load(StringIO(''.join(sys.stdin.read())) if name is None else name) geom = damask.GeomGrid.load(StringIO(''.join(sys.stdin.read())) if name is None else name)
material = geom.material.flatten(order='F') material = geom.material.flatten(order='F')
cmds = [\ cmds = [\

View File

@ -26,5 +26,5 @@ from ._vtk import VTK # noqa
from ._config import Config # noqa from ._config import Config # noqa
from ._configmaterial import ConfigMaterial # noqa from ._configmaterial import ConfigMaterial # noqa
from ._loadcasegrid import LoadcaseGrid # noqa from ._loadcasegrid import LoadcaseGrid # noqa
from ._grid import Grid # noqa from ._geomgrid import GeomGrid # noqa
from ._result import Result # noqa from ._result import Result # noqa

View File

@ -144,7 +144,7 @@ class ConfigMaterial(Config):
Notes Notes
----- -----
damask.Grid.load_DREAM3D gives the corresponding geometry for damask.GeomGrid.load_DREAM3D gives the corresponding geometry for
the grid solver. the grid solver.
For cell-wise data, only unique combinations of For cell-wise data, only unique combinations of

View File

@ -28,7 +28,7 @@ def numba_njit_wrapper(**kwargs):
return (lambda function: nb.njit(function) if nb else function) return (lambda function: nb.njit(function) if nb else function)
class Grid: class GeomGrid:
""" """
Geometry definition for grid solvers. Geometry definition for grid solvers.
@ -89,7 +89,7 @@ class Grid:
]+(['initial_conditions:']+[f' - {f}' for f in self.initial_conditions] if self.initial_conditions else [])) ]+(['initial_conditions:']+[f' - {f}' for f in self.initial_conditions] if self.initial_conditions else []))
def __copy__(self) -> 'Grid': def __copy__(self) -> 'GeomGrid':
""" """
Return deepcopy(self). Return deepcopy(self).
@ -110,11 +110,11 @@ class Grid:
Parameters Parameters
---------- ----------
other : damask.Grid other : damask.GeomGrid
Grid to compare self against. GeomGrid to compare self against.
""" """
if not isinstance(other, Grid): if not isinstance(other, GeomGrid):
return NotImplemented return NotImplemented
return bool( np.allclose(other.size,self.size) return bool( np.allclose(other.size,self.size)
and np.allclose(other.origin,self.origin) and np.allclose(other.origin,self.origin)
@ -197,20 +197,20 @@ class Grid:
@staticmethod @staticmethod
def load(fname: Union[str, Path]) -> 'Grid': def load(fname: Union[str, Path]) -> 'GeomGrid':
""" """
Load from VTK ImageData file. Load from VTK ImageData file.
Parameters Parameters
---------- ----------
fname : str or pathlib.Path fname : str or pathlib.Path
Grid file to read. GeomGrid file to read.
Valid extension is .vti, which will be appended if not given. Valid extension is .vti, which will be appended if not given.
Returns Returns
------- -------
loaded : damask.Grid loaded : damask.GeomGrid
Grid-based geometry from file. GeomGrid-based geometry from file.
""" """
v = VTK.load(fname if str(fname).endswith('.vti') else str(fname)+'.vti') v = VTK.load(fname if str(fname).endswith('.vti') else str(fname)+'.vti')
@ -218,17 +218,17 @@ class Grid:
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
ic = {label:v.get(label).reshape(cells,order='F') for label in set(v.labels['Cell Data']) - {'material'}} ic = {label:v.get(label).reshape(cells,order='F') for label in set(v.labels['Cell Data']) - {'material'}}
return Grid(material = v.get('material').reshape(cells,order='F'), return GeomGrid(material = v.get('material').reshape(cells,order='F'),
size = bbox[1] - bbox[0], size = bbox[1] - bbox[0],
origin = bbox[0], origin = bbox[0],
initial_conditions = ic, initial_conditions = ic,
comments = v.comments, comments = v.comments,
) )
@typing.no_type_check @typing.no_type_check
@staticmethod @staticmethod
def load_ASCII(fname)-> 'Grid': def load_ASCII(fname)-> 'GeomGrid':
""" """
Load from geom file. Load from geom file.
@ -242,8 +242,8 @@ class Grid:
Returns Returns
------- -------
loaded : damask.Grid loaded : damask.GeomGrid
Grid-based geometry from file. GeomGrid-based geometry from file.
""" """
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2) warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2)
@ -296,14 +296,15 @@ class Grid:
if not np.any(np.mod(material,1) != 0.0): # no float present if not np.any(np.mod(material,1) != 0.0): # no float present
material = material.astype(np.int64) - (1 if material.min() > 0 else 0) material = material.astype(np.int64) - (1 if material.min() > 0 else 0)
return Grid(material = material.reshape(cells,order='F'), return GeomGrid(material = material.reshape(cells,order='F'),
size = size, size = size,
origin = origin, origin = origin,
comments = comments) comments = comments,
)
@staticmethod @staticmethod
def load_Neper(fname: Union[str, Path]) -> 'Grid': def load_Neper(fname: Union[str, Path]) -> 'GeomGrid':
""" """
Load from Neper VTK file. Load from Neper VTK file.
@ -314,8 +315,8 @@ class Grid:
Returns Returns
------- -------
loaded : damask.Grid loaded : damask.GeomGrid
Grid-based geometry from file. GeomGrid-based geometry from file.
Notes Notes
----- -----
@ -330,7 +331,7 @@ class Grid:
>>> N_grains = 20 >>> N_grains = 20
>>> cells = (32,32,32) >>> cells = (32,32,32)
>>> damask.util.run(f'neper -T -n {N_grains} -tesrsize {cells[0]}:{cells[1]}:{cells[2]} -periodicity all -format vtk') >>> damask.util.run(f'neper -T -n {N_grains} -tesrsize {cells[0]}:{cells[1]}:{cells[2]} -periodicity all -format vtk')
>>> damask.Grid.load_Neper(f'n{N_grains}-id1.vtk').renumber() >>> damask.GeomGrid.load_Neper(f'n{N_grains}-id1.vtk').renumber()
cells: 32 × 32 × 32 cells: 32 × 32 × 32
size: 1.0 × 1.0 × 1.0 size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -341,11 +342,11 @@ class Grid:
cells = np.array(v.vtk_data.GetDimensions())-1 cells = np.array(v.vtk_data.GetDimensions())-1
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
return Grid(material = v.get('MaterialId').reshape(cells,order='F').astype('int32',casting='unsafe'), return GeomGrid(material = v.get('MaterialId').reshape(cells,order='F').astype('int32',casting='unsafe'),
size = bbox[1] - bbox[0], size = bbox[1] - bbox[0],
origin = bbox[0], origin = bbox[0],
comments = util.execution_stamp('Grid','load_Neper'), comments = util.execution_stamp('GeomGrid','load_Neper'),
) )
@staticmethod @staticmethod
@ -354,7 +355,7 @@ class Grid:
cell_data: Optional[str] = None, cell_data: Optional[str] = None,
phases: str = 'Phases', phases: str = 'Phases',
Euler_angles: str = 'EulerAngles', Euler_angles: str = 'EulerAngles',
base_group: Optional[str] = None) -> 'Grid': base_group: Optional[str] = None) -> 'GeomGrid':
""" """
Load DREAM.3D (HDF5) file. Load DREAM.3D (HDF5) file.
@ -389,8 +390,8 @@ class Grid:
Returns Returns
------- -------
loaded : damask.Grid loaded : damask.GeomGrid
Grid-based geometry from file. GeomGrid-based geometry from file.
Notes Notes
----- -----
@ -418,17 +419,17 @@ class Grid:
else: else:
ma = f['/'.join([b,c,feature_IDs])][()].flatten() ma = f['/'.join([b,c,feature_IDs])][()].flatten()
return Grid(material = ma.reshape(cells,order='F'), return GeomGrid(material = ma.reshape(cells,order='F'),
size = size, size = size,
origin = origin, origin = origin,
comments = util.execution_stamp('Grid','load_DREAM3D'), comments = util.execution_stamp('GeomGrid','load_DREAM3D'),
) )
@staticmethod @staticmethod
def from_table(table: Table, def from_table(table: Table,
coordinates: str, coordinates: str,
labels: Union[str, Sequence[str]]) -> 'Grid': labels: Union[str, Sequence[str]]) -> 'GeomGrid':
""" """
Create grid from ASCII table. Create grid from ASCII table.
@ -445,8 +446,8 @@ class Grid:
Returns Returns
------- -------
new : damask.Grid new : damask.GeomGrid
Grid-based geometry from values in table. GeomGrid-based geometry from values in table.
""" """
cells,size,origin = grid_filters.cellsSizeOrigin_coordinates0_point(table.get(coordinates)) cells,size,origin = grid_filters.cellsSizeOrigin_coordinates0_point(table.get(coordinates))
@ -457,11 +458,11 @@ class Grid:
ma = np.arange(cells.prod()) if len(unique) == cells.prod() else \ ma = np.arange(cells.prod()) if len(unique) == cells.prod() else \
np.arange(unique.size)[np.argsort(pd.unique(unique_inverse))][unique_inverse] np.arange(unique.size)[np.argsort(pd.unique(unique_inverse))][unique_inverse]
return Grid(material = ma.reshape(cells,order='F'), return GeomGrid(material = ma.reshape(cells,order='F'),
size = size, size = size,
origin = origin, origin = origin,
comments = util.execution_stamp('Grid','from_table'), comments = util.execution_stamp('GeomGrid','from_table'),
) )
@staticmethod @staticmethod
@ -500,8 +501,8 @@ class Grid:
Returns Returns
------- -------
new : damask.Grid new : damask.GeomGrid
Grid-based geometry from tessellation. GeomGrid-based geometry from tessellation.
""" """
weights_p: FloatSequence weights_p: FloatSequence
@ -517,17 +518,17 @@ class Grid:
coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3)
pool = mp.Pool(int(os.environ.get('OMP_NUM_THREADS',4))) pool = mp.Pool(int(os.environ.get('OMP_NUM_THREADS',4)))
result = pool.map_async(partial(Grid._find_closest_seed,seeds_p,weights_p), coords) result = pool.map_async(partial(GeomGrid._find_closest_seed,seeds_p,weights_p), coords)
pool.close() pool.close()
pool.join() pool.join()
material_ = np.array(result.get()).reshape(cells) material_ = np.array(result.get()).reshape(cells)
if periodic: material_ %= len(weights) if periodic: material_ %= len(weights)
return Grid(material = material_ if material is None else np.array(material)[material_], return GeomGrid(material = material_ if material is None else np.array(material)[material_],
size = size, size = size,
comments = util.execution_stamp('Grid','from_Laguerre_tessellation'), comments = util.execution_stamp('GeomGrid','from_Laguerre_tessellation'),
) )
@staticmethod @staticmethod
@ -535,7 +536,7 @@ class Grid:
size: FloatSequence, size: FloatSequence,
seeds: np.ndarray, seeds: np.ndarray,
material: Optional[IntSequence] = None, material: Optional[IntSequence] = None,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'GeomGrid':
""" """
Create grid from Voronoi tessellation. Create grid from Voronoi tessellation.
@ -556,8 +557,8 @@ class Grid:
Returns Returns
------- -------
new : damask.Grid new : damask.GeomGrid
Grid-based geometry from tessellation. GeomGrid-based geometry from tessellation.
""" """
coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3)
@ -568,10 +569,10 @@ class Grid:
except TypeError: except TypeError:
material_ = tree.query(coords, n_jobs = int(os.environ.get('OMP_NUM_THREADS',4)))[1] # scipy <1.6 material_ = tree.query(coords, n_jobs = int(os.environ.get('OMP_NUM_THREADS',4)))[1] # scipy <1.6
return Grid(material = (material_ if material is None else np.array(material)[material_]).reshape(cells), return GeomGrid(material = (material_ if material is None else np.array(material)[material_]).reshape(cells),
size = size, size = size,
comments = util.execution_stamp('Grid','from_Voronoi_tessellation'), comments = util.execution_stamp('GeomGrid','from_Voronoi_tessellation'),
) )
_minimal_surface = \ _minimal_surface = \
@ -622,7 +623,7 @@ class Grid:
surface: str, surface: str,
threshold: float = 0.0, threshold: float = 0.0,
periods: int = 1, periods: int = 1,
materials: IntSequence = (0,1)) -> 'Grid': materials: IntSequence = (0,1)) -> 'GeomGrid':
""" """
Create grid from definition of triply-periodic minimal surface. Create grid from definition of triply-periodic minimal surface.
@ -643,8 +644,8 @@ class Grid:
Returns Returns
------- -------
new : damask.Grid new : damask.GeomGrid
Grid-based geometry from definition of minimal surface. GeomGrid-based geometry from definition of minimal surface.
Notes Notes
----- -----
@ -679,7 +680,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid') >>> damask.GeomGrid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
cells : 64 × 64 × 64 cells : 64 × 64 × 64
size : 0.0001 × 0.0001 × 0.0001 size : 0.0001 × 0.0001 × 0.0001
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -689,7 +690,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4, >>> damask.GeomGrid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
... 'Neovius',materials=(1,5)) ... 'Neovius',materials=(1,5))
cells : 80 × 80 × 80 cells : 80 × 80 × 80
size : 0.0005 × 0.0005 × 0.0005 size : 0.0005 × 0.0005 × 0.0005
@ -701,10 +702,10 @@ class Grid:
periods*2.0*np.pi*(np.arange(cells[1])+0.5)/cells[1], periods*2.0*np.pi*(np.arange(cells[1])+0.5)/cells[1],
periods*2.0*np.pi*(np.arange(cells[2])+0.5)/cells[2], periods*2.0*np.pi*(np.arange(cells[2])+0.5)/cells[2],
indexing='ij',sparse=True) indexing='ij',sparse=True)
return Grid(material = np.where(threshold < Grid._minimal_surface[surface](x,y,z),materials[1],materials[0]), return GeomGrid(material = np.where(threshold < GeomGrid._minimal_surface[surface](x,y,z),materials[1],materials[0]),
size = size, size = size,
comments = util.execution_stamp('Grid','from_minimal_surface'), comments = util.execution_stamp('GeomGrid','from_minimal_surface'),
) )
def save(self, def save(self,
@ -781,7 +782,7 @@ class Grid:
def canvas(self, def canvas(self,
cells: Optional[IntSequence] = None, cells: Optional[IntSequence] = None,
offset: Optional[IntSequence] = None, offset: Optional[IntSequence] = None,
fill: Optional[int] = None) -> 'Grid': fill: Optional[int] = None) -> 'GeomGrid':
""" """
Crop or enlarge/pad grid. Crop or enlarge/pad grid.
@ -798,7 +799,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -807,7 +808,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-3) >>> g = damask.GeomGrid(np.zeros([32]*3,int),np.ones(3)*1e-3)
>>> g.canvas([32,32,16],[0,0,16]) >>> g.canvas([32,32,16],[0,0,16])
cells: 32 × 32 × 16 cells: 32 × 32 × 16
size: 0.001 × 0.001 × 0.0005 size: 0.001 × 0.001 × 0.0005
@ -827,16 +828,16 @@ class Grid:
canvas[ll[0]:ur[0],ll[1]:ur[1],ll[2]:ur[2]] = self.material[LL[0]:UR[0],LL[1]:UR[1],LL[2]:UR[2]] canvas[ll[0]:ur[0],ll[1]:ur[1],ll[2]:ur[2]] = self.material[LL[0]:UR[0],LL[1]:UR[1],LL[2]:UR[2]]
return Grid(material = canvas, return GeomGrid(material = canvas,
size = self.size/self.cells*np.asarray(canvas.shape), size = self.size/self.cells*np.asarray(canvas.shape),
origin = self.origin+offset_*self.size/self.cells, origin = self.origin+offset_*self.size/self.cells,
comments = self.comments+[util.execution_stamp('Grid','canvas')], comments = self.comments+[util.execution_stamp('GeomGrid','canvas')],
) )
def mirror(self, def mirror(self,
directions: Sequence[str], directions: Sequence[str],
reflect: bool = False) -> 'Grid': reflect: bool = False) -> 'GeomGrid':
""" """
Mirror grid along given directions. Mirror grid along given directions.
@ -849,7 +850,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -858,7 +859,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3))) >>> (g := damask.GeomGrid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
cells: 4 × 5 × 6 cells: 4 × 5 × 6
size: 1.0 × 1.0 × 1.0 size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -896,15 +897,15 @@ class Grid:
if 'z' in directions: if 'z' in directions:
mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2) mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2)
return Grid(material = mat, return GeomGrid(material = mat,
size = self.size/self.cells*np.asarray(mat.shape), size = self.size/self.cells*np.asarray(mat.shape),
origin = self.origin, origin = self.origin,
comments = self.comments+[util.execution_stamp('Grid','mirror')], comments = self.comments+[util.execution_stamp('GeomGrid','mirror')],
) )
def flip(self, def flip(self,
directions: Sequence[str]) -> 'Grid': directions: Sequence[str]) -> 'GeomGrid':
""" """
Flip grid along given directions. Flip grid along given directions.
@ -915,7 +916,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -924,7 +925,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3))) >>> (g := damask.GeomGrid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
cells: 4 × 5 × 6 cells: 4 × 5 × 6
size: 1.0 × 1.0 × 1.0 size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -943,16 +944,16 @@ class Grid:
mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid]) mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid])
return Grid(material = mat, return GeomGrid(material = mat,
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
comments = self.comments+[util.execution_stamp('Grid','flip')], comments = self.comments+[util.execution_stamp('GeomGrid','flip')],
) )
def rotate(self, def rotate(self,
R: Rotation, R: Rotation,
fill: Optional[int] = None) -> 'Grid': fill: Optional[int] = None) -> 'GeomGrid':
""" """
Rotate grid (possibly extending its bounding box). Rotate grid (possibly extending its bounding box).
@ -966,7 +967,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -975,7 +976,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3))) >>> (g := damask.GeomGrid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
cells: 4 × 5 × 6 cells: 4 × 5 × 6
size: 1.0 × 1.0 × 1.0 size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -997,15 +998,15 @@ class Grid:
origin = self.origin-(np.asarray(material.shape)-self.cells)*.5 * self.size/self.cells origin = self.origin-(np.asarray(material.shape)-self.cells)*.5 * self.size/self.cells
return Grid(material = material, return GeomGrid(material = material,
size = self.size/self.cells*np.asarray(material.shape), size = self.size/self.cells*np.asarray(material.shape),
origin = origin, origin = origin,
comments = self.comments+[util.execution_stamp('Grid','rotate')], comments = self.comments+[util.execution_stamp('GeomGrid','rotate')],
) )
def scale(self, def scale(self,
cells: IntSequence) -> 'Grid': cells: IntSequence) -> 'GeomGrid':
""" """
Scale grid to new cell counts. Scale grid to new cell counts.
@ -1016,7 +1017,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -1025,7 +1026,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> (g := damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)) >>> (g := damask.GeomGrid(np.zeros([32]*3,int),np.ones(3)*1e-4))
cells: 32 × 32 × 32 cells: 32 × 32 × 32
size: 0.0001 × 0.0001 × 0.0001 size: 0.0001 × 0.0001 × 0.0001
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m
@ -1043,28 +1044,28 @@ class Grid:
points=orig,method='nearest',bounds_error=False,fill_value=None) points=orig,method='nearest',bounds_error=False,fill_value=None)
new = grid_filters.coordinates0_point(cells,self.size,self.origin) new = grid_filters.coordinates0_point(cells,self.size,self.origin)
return Grid(material = interpolator(values=self.material)(new).astype(int), return GeomGrid(material = interpolator(values=self.material)(new).astype(int),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = {k: interpolator(values=v)(new) initial_conditions = {k: interpolator(values=v)(new)
for k,v in self.initial_conditions.items()}, for k,v in self.initial_conditions.items()},
comments = self.comments+[util.execution_stamp('Grid','scale')], comments = self.comments+[util.execution_stamp('GeomGrid','scale')],
) )
def assemble(self, def assemble(self,
idx: np.ndarray) -> 'Grid': idx: np.ndarray) -> 'GeomGrid':
""" """
Assemble new grid from index map. Assemble new grid from index map.
Parameters Parameters
---------- ----------
idx : numpy.ndarray of int, shape (:,:,:) or (:,:,:,3) idx : numpy.ndarray of int, shape (:,:,:) or (:,:,:,3)
Grid of flat indices or coordinate indices. GeomGrid of flat indices or coordinate indices.
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Cell count of resulting grid matches shape of index map. Cell count of resulting grid matches shape of index map.
@ -1073,37 +1074,37 @@ class Grid:
flat = (idx if len(idx.shape)==3 else grid_filters.ravel_index(idx)).flatten(order='F') flat = (idx if len(idx.shape)==3 else grid_filters.ravel_index(idx)).flatten(order='F')
ic = {k: v.flatten(order='F')[flat].reshape(cells,order='F') for k,v in self.initial_conditions.items()} ic = {k: v.flatten(order='F')[flat].reshape(cells,order='F') for k,v in self.initial_conditions.items()}
return Grid(material = self.material.flatten(order='F')[flat].reshape(cells,order='F'), return GeomGrid(material = self.material.flatten(order='F')[flat].reshape(cells,order='F'),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = ic, initial_conditions = ic,
comments = self.comments+[util.execution_stamp('Grid','assemble')], comments = self.comments+[util.execution_stamp('GeomGrid','assemble')],
) )
def renumber(self) -> 'Grid': def renumber(self) -> 'GeomGrid':
""" """
Renumber sorted material indices as 0,...,N-1. Renumber sorted material indices as 0,...,N-1.
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
""" """
_,renumbered = np.unique(self.material,return_inverse=True) _,renumbered = np.unique(self.material,return_inverse=True)
return Grid(material = renumbered.reshape(self.cells), return GeomGrid(material = renumbered.reshape(self.cells),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','renumber')], comments = self.comments+[util.execution_stamp('GeomGrid','renumber')],
) )
def substitute(self, def substitute(self,
from_material: Union[int,IntSequence], from_material: Union[int,IntSequence],
to_material: Union[int,IntSequence]) -> 'Grid': to_material: Union[int,IntSequence]) -> 'GeomGrid':
""" """
Substitute material indices. Substitute material indices.
@ -1116,7 +1117,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
""" """
@ -1125,21 +1126,21 @@ class Grid:
to_material if isinstance(to_material,(Sequence,np.ndarray)) else [to_material]): # ToDo Python 3.10 has strict mode for zip to_material if isinstance(to_material,(Sequence,np.ndarray)) else [to_material]): # ToDo Python 3.10 has strict mode for zip
material[self.material==f] = t material[self.material==f] = t
return Grid(material = material, return GeomGrid(material = material,
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','substitute')], comments = self.comments+[util.execution_stamp('GeomGrid','substitute')],
) )
def sort(self) -> 'Grid': def sort(self) -> 'GeomGrid':
""" """
Sort material indices such that min(material ID) is located at (0,0,0). Sort material indices such that min(material ID) is located at (0,0,0).
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
""" """
@ -1148,12 +1149,12 @@ class Grid:
sort_idx = np.argsort(from_ma) sort_idx = np.argsort(from_ma)
ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)] ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)]
return Grid(material = ma.reshape(self.cells,order='F'), return GeomGrid(material = ma.reshape(self.cells,order='F'),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','sort')], comments = self.comments+[util.execution_stamp('GeomGrid','sort')],
) )
def clean(self, def clean(self,
@ -1161,7 +1162,7 @@ class Grid:
selection: Optional[IntSequence] = None, selection: Optional[IntSequence] = None,
invert_selection: bool = False, invert_selection: bool = False,
periodic: bool = True, periodic: bool = True,
rng_seed: Optional[NumpyRngSeed] = None) -> 'Grid': rng_seed: Optional[NumpyRngSeed] = None) -> 'GeomGrid':
""" """
Smooth grid by selecting most frequent material ID within given stencil at each location. Smooth grid by selecting most frequent material ID within given stencil at each location.
@ -1182,7 +1183,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Notes Notes
@ -1216,12 +1217,12 @@ class Grid:
mode='wrap' if periodic else 'nearest', mode='wrap' if periodic else 'nearest',
extra_keywords=dict(selection=selection_,rng=rng), extra_keywords=dict(selection=selection_,rng=rng),
).astype(self.material.dtype) ).astype(self.material.dtype)
return Grid(material = material, return GeomGrid(material = material,
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','clean')], comments = self.comments+[util.execution_stamp('GeomGrid','clean')],
) )
def add_primitive(self, def add_primitive(self,
@ -1231,7 +1232,7 @@ class Grid:
fill: Optional[int] = None, fill: Optional[int] = None,
R: Rotation = Rotation(), R: Rotation = Rotation(),
inverse: bool = False, inverse: bool = False,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'GeomGrid':
""" """
Insert a primitive geometric object at a given position. Insert a primitive geometric object at a given position.
@ -1261,7 +1262,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
Examples Examples
@ -1270,7 +1271,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4) >>> g = damask.GeomGrid(np.zeros([64]*3,int), np.ones(3)*1e-4)
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1) >>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
cells : 64 × 64 × 64 cells : 64 × 64 × 64
size : 0.0001 × 0.0001 × 0.0001 size : 0.0001 × 0.0001 × 0.0001
@ -1281,7 +1282,7 @@ class Grid:
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4) >>> g = damask.GeomGrid(np.zeros([64]*3,int), np.ones(3)*1e-4)
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf) >>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
cells : 64 × 64 × 64 cells : 64 × 64 × 64
size : 0.0001 × 0.0001 × 0.0001 size : 0.0001 × 0.0001 × 0.0001
@ -1307,14 +1308,14 @@ class Grid:
if periodic: # translate back to center if periodic: # translate back to center
mask = np.roll(mask,((c/self.size-0.5)*self.cells).round().astype(np.int64),(0,1,2)) mask = np.roll(mask,((c/self.size-0.5)*self.cells).round().astype(np.int64),(0,1,2))
return Grid(material = np.where(np.logical_not(mask) if inverse else mask, return GeomGrid(material = np.where(np.logical_not(mask) if inverse else mask,
self.material, self.material,
np.nanmax(self.material)+1 if fill is None else fill), np.nanmax(self.material)+1 if fill is None else fill),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','add_primitive')], comments = self.comments+[util.execution_stamp('GeomGrid','add_primitive')],
) )
def vicinity_offset(self, def vicinity_offset(self,
@ -1322,7 +1323,7 @@ class Grid:
offset: Optional[int] = None, offset: Optional[int] = None,
selection: Optional[IntSequence] = None, selection: Optional[IntSequence] = None,
invert_selection: bool = False, invert_selection: bool = False,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'GeomGrid':
""" """
Offset material ID of points in the vicinity of selected (or just other) material IDs. Offset material ID of points in the vicinity of selected (or just other) material IDs.
@ -1348,7 +1349,7 @@ class Grid:
Returns Returns
------- -------
updated : damask.Grid updated : damask.GeomGrid
Updated grid-based geometry. Updated grid-based geometry.
""" """
@ -1380,12 +1381,12 @@ class Grid:
extra_keywords=dict(selection=selection_), extra_keywords=dict(selection=selection_),
) )
return Grid(material = np.where(mask, self.material + offset_,self.material), return GeomGrid(material = np.where(mask, self.material + offset_,self.material),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = self.initial_conditions, initial_conditions = self.initial_conditions,
comments = self.comments+[util.execution_stamp('Grid','vicinity_offset')], comments = self.comments+[util.execution_stamp('GeomGrid','vicinity_offset')],
) )
def get_grain_boundaries(self, def get_grain_boundaries(self,

View File

@ -116,7 +116,7 @@ def from_grid(grid,
Parameters Parameters
---------- ----------
grid : damask.Grid grid : damask.GeomGrid
Grid from which the material IDs are used as seeds. Grid from which the material IDs are used as seeds.
selection : (sequence of) int, optional selection : (sequence of) int, optional
Material IDs to consider. Material IDs to consider.
@ -138,7 +138,7 @@ def from_grid(grid,
----- -----
The origin is not considered in order to obtain coordinates The origin is not considered in order to obtain coordinates
in a coordinate system located at the origin. This is expected in a coordinate system located at the origin. This is expected
by damask.Grid.from_Voronoi_tessellation. by damask.GeomGrid.from_Voronoi_tessellation.
Examples Examples
-------- --------
@ -148,7 +148,7 @@ def from_grid(grid,
>>> import scipy.spatial >>> import scipy.spatial
>>> import damask >>> import damask
>>> seeds = damask.seeds.from_random(np.ones(3),29,[128]*3) >>> seeds = damask.seeds.from_random(np.ones(3),29,[128]*3)
>>> (g := damask.Grid.from_Voronoi_tessellation([128]*3,np.ones(3),seeds)) >>> (g := damask.GeomGrid.from_Voronoi_tessellation([128]*3,np.ones(3),seeds))
cells: 128 × 128 × 128 cells: 128 × 128 × 128
size: 1.0 × 1.0 × 1.0 size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 0.0 m

View File

@ -1 +1 @@
../Grid/2phase_irregularGrid.dream3d ../GeomGrid/2phase_irregularGrid.dream3d

View File

@ -1 +1 @@
../Grid/2phase_irregularGrid.json ../GeomGrid/2phase_irregularGrid.json

View File

@ -1 +1 @@
../Grid/2phase_irregularGrid.xdmf ../GeomGrid/2phase_irregularGrid.xdmf

View File

@ -1 +1 @@
../Grid/measured.dream3d ../GeomGrid/measured.dream3d

View File

@ -1 +1 @@
../Grid/measured.xdmf ../GeomGrid/measured.xdmf

View File

@ -6,7 +6,7 @@ import numpy as np
from damask import ConfigMaterial from damask import ConfigMaterial
from damask import Table from damask import Table
from damask import Rotation from damask import Rotation
from damask import Grid from damask import GeomGrid
@pytest.fixture @pytest.fixture
def res_path(res_path_base): def res_path(res_path_base):
@ -182,8 +182,8 @@ class TestConfigMaterial:
assert point_c.is_valid and grain_c.is_valid and \ assert point_c.is_valid and grain_c.is_valid and \
len(point_c['material'])+1 == len(grain_c['material']) len(point_c['material'])+1 == len(grain_c['material'])
grain_m = Grid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d','FeatureIds').material.flatten() grain_m = GeomGrid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d','FeatureIds').material.flatten()
point_m = Grid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d').material.flatten() point_m = GeomGrid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d').material.flatten()
for i in np.unique(point_m): for i in np.unique(point_m):
j = int(grain_m[(point_m==i).nonzero()[0][0]]) j = int(grain_m[(point_m==i).nonzero()[0][0]])

View File

@ -5,7 +5,7 @@ import numpy as np
from vtkmodules.vtkCommonCore import vtkVersion from vtkmodules.vtkCommonCore import vtkVersion
from damask import VTK from damask import VTK
from damask import Grid from damask import GeomGrid
from damask import Table from damask import Table
from damask import Rotation from damask import Rotation
from damask import Colormap from damask import Colormap
@ -19,7 +19,7 @@ def default():
"""Simple geometry.""" """Simple geometry."""
g = np.array([8,5,4]) g = np.array([8,5,4])
l = np.prod(g[:2]) l = np.prod(g[:2])
return Grid(np.concatenate((np.ones (l,dtype=int), return GeomGrid(np.concatenate((np.ones (l,dtype=int),
np.arange(l,dtype=int)+2, np.arange(l,dtype=int)+2,
np.ones (l,dtype=int)*2, np.ones (l,dtype=int)*2,
np.arange(l,dtype=int)+1)).reshape(g,order='F'), np.arange(l,dtype=int)+1)).reshape(g,order='F'),
@ -31,15 +31,15 @@ def random():
size = (1+np.random.rand(3))*1e-5 size = (1+np.random.rand(3))*1e-5
cells = np.random.randint(10,20,3) cells = np.random.randint(10,20,3)
s = seeds.from_random(size,np.random.randint(5,25),cells) s = seeds.from_random(size,np.random.randint(5,25),cells)
return Grid.from_Voronoi_tessellation(cells,size,s) return GeomGrid.from_Voronoi_tessellation(cells,size,s)
@pytest.fixture @pytest.fixture
def res_path(res_path_base): def res_path(res_path_base):
"""Directory containing testing resources.""" """Directory containing testing resources."""
return res_path_base/'Grid' return res_path_base/'GeomGrid'
class TestGrid: class TestGeomGrid:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def _patch_execution_stamp(self, patch_execution_stamp): def _patch_execution_stamp(self, patch_execution_stamp):
@ -65,49 +65,49 @@ class TestGrid:
def test_read_write_vti(self,default,tmp_path): def test_read_write_vti(self,default,tmp_path):
default.save(tmp_path/'default') default.save(tmp_path/'default')
new = Grid.load(tmp_path/'default.vti') new = GeomGrid.load(tmp_path/'default.vti')
assert new == default assert new == default
def test_invalid_no_material(self,tmp_path): def test_invalid_no_material(self,tmp_path):
v = VTK.from_image_data(np.random.randint(5,10,3)*2,np.random.random(3) + 1.0) v = VTK.from_image_data(np.random.randint(5,10,3)*2,np.random.random(3) + 1.0)
v.save(tmp_path/'no_materialpoint.vti',parallel=False) v.save(tmp_path/'no_materialpoint.vti',parallel=False)
with pytest.raises(KeyError): with pytest.raises(KeyError):
Grid.load(tmp_path/'no_materialpoint.vti') GeomGrid.load(tmp_path/'no_materialpoint.vti')
def test_invalid_material_type(self): def test_invalid_material_type(self):
with pytest.raises(TypeError): with pytest.raises(TypeError):
Grid(np.zeros((3,3,3),dtype='complex'),np.ones(3)) GeomGrid(np.zeros((3,3,3),dtype='complex'),np.ones(3))
def test_cast_to_int(self): def test_cast_to_int(self):
g = Grid(np.zeros((3,3,3)),np.ones(3)) g = GeomGrid(np.zeros((3,3,3)),np.ones(3))
assert g.material.dtype in np.sctypes['int'] assert g.material.dtype in np.sctypes['int']
def test_invalid_size(self,default): def test_invalid_size(self,default):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Grid(default.material[1:,1:,1:], GeomGrid(default.material[1:,1:,1:],
size=np.ones(2)) size=np.ones(2))
def test_save_load_ASCII(self,default,tmp_path): def test_save_load_ASCII(self,default,tmp_path):
default.save_ASCII(tmp_path/'ASCII') default.save_ASCII(tmp_path/'ASCII')
default.material -= 1 default.material -= 1
assert Grid.load_ASCII(tmp_path/'ASCII') == default assert GeomGrid.load_ASCII(tmp_path/'ASCII') == default
def test_invalid_origin(self,default): def test_invalid_origin(self,default):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Grid(default.material[1:,1:,1:], GeomGrid(default.material[1:,1:,1:],
size=np.ones(3), size=np.ones(3),
origin=np.ones(4)) origin=np.ones(4))
def test_invalid_materials_shape(self,default): def test_invalid_materials_shape(self,default):
material = np.ones((3,3)) material = np.ones((3,3))
with pytest.raises(ValueError): with pytest.raises(ValueError):
Grid(material, GeomGrid(material,
size=np.ones(3)) size=np.ones(3))
def test_invalid_materials_type(self,default): def test_invalid_materials_type(self,default):
material = np.random.randint(1,300,(3,4,5))==1 material = np.random.randint(1,300,(3,4,5))==1
with pytest.raises(TypeError): with pytest.raises(TypeError):
Grid(material) GeomGrid(material)
@pytest.mark.parametrize('directions,reflect',[ @pytest.mark.parametrize('directions,reflect',[
(['x'], False), (['x'], False),
@ -121,7 +121,7 @@ class TestGrid:
tag = f'directions_{"-".join(directions)}+reflect_{reflect}' tag = f'directions_{"-".join(directions)}+reflect_{reflect}'
reference = res_path/f'mirror_{tag}.vti' reference = res_path/f'mirror_{tag}.vti'
if update: modified.save(reference) if update: modified.save(reference)
assert Grid.load(reference) == modified assert GeomGrid.load(reference) == modified
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]]) @pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
def test_mirror_invalid(self,default,directions): def test_mirror_invalid(self,default,directions):
@ -146,7 +146,7 @@ class TestGrid:
tag = f'directions_{"-".join(directions)}' tag = f'directions_{"-".join(directions)}'
reference = res_path/f'flip_{tag}.vti' reference = res_path/f'flip_{tag}.vti'
if update: modified.save(reference) if update: modified.save(reference)
assert Grid.load(reference) == modified assert GeomGrid.load(reference) == modified
def test_flip_order_invariant(self,default): def test_flip_order_invariant(self,default):
direction = np.array(['x','y','z']) direction = np.array(['x','y','z'])
@ -180,7 +180,7 @@ class TestGrid:
reference = res_path/f'clean_{distance}_{util.srepr(selection,"+")}_{periodic}.vti' reference = res_path/f'clean_{distance}_{util.srepr(selection,"+")}_{periodic}.vti'
if update: if update:
current.save(reference) current.save(reference)
assert Grid.load(reference) == current assert GeomGrid.load(reference) == current
@pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),np.random.randint(1,20,6)]) @pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),np.random.randint(1,20,6)])
@pytest.mark.parametrize('invert',[True,False]) @pytest.mark.parametrize('invert',[True,False])
@ -207,14 +207,14 @@ class TestGrid:
tag = f'grid_{util.srepr(cells,"-")}' tag = f'grid_{util.srepr(cells,"-")}'
reference = res_path/f'scale_{tag}.vti' reference = res_path/f'scale_{tag}.vti'
if update: modified.save(reference) if update: modified.save(reference)
assert Grid.load(reference) == modified assert GeomGrid.load(reference) == modified
def test_renumber(self,default): def test_renumber(self,default):
material = default.material.copy() material = default.material.copy()
for m in np.unique(material): for m in np.unique(material):
material[material==m] = material.max() + np.random.randint(1,30) material[material==m] = material.max() + np.random.randint(1,30)
default.material -= 1 default.material -= 1
modified = Grid(material, modified = GeomGrid(material,
default.size, default.size,
default.origin) default.origin)
assert not default == modified assert not default == modified
@ -223,13 +223,13 @@ class TestGrid:
def test_assemble(self): def test_assemble(self):
cells = np.random.randint(8,16,3) cells = np.random.randint(8,16,3)
N = cells.prod() N = cells.prod()
g = Grid(np.arange(N).reshape(cells),np.ones(3)) g = GeomGrid(np.arange(N).reshape(cells),np.ones(3))
idx = np.random.randint(0,N,N).reshape(cells) idx = np.random.randint(0,N,N).reshape(cells)
assert (idx == g.assemble(idx).material).all assert (idx == g.assemble(idx).material).all
def test_substitute(self,default): def test_substitute(self,default):
offset = np.random.randint(1,500) offset = np.random.randint(1,500)
modified = Grid(default.material + offset, modified = GeomGrid(default.material + offset,
default.size, default.size,
default.origin) default.origin)
assert not default == modified assert not default == modified
@ -250,7 +250,7 @@ class TestGrid:
def test_sort(self): def test_sort(self):
cells = np.random.randint(5,20,3) cells = np.random.randint(5,20,3)
m = Grid(np.random.randint(1,20,cells)*3,np.ones(3)).sort().material.flatten(order='F') m = GeomGrid(np.random.randint(1,20,cells)*3,np.ones(3)).sort().material.flatten(order='F')
for i,v in enumerate(m): for i,v in enumerate(m):
assert i==0 or v > m[:i].max() or v in m[:i] assert i==0 or v > m[:i].max() or v in m[:i]
@ -269,7 +269,7 @@ class TestGrid:
tag = f'Eulers_{util.srepr(Eulers,"-")}' tag = f'Eulers_{util.srepr(Eulers,"-")}'
reference = res_path/f'rotate_{tag}.vti' reference = res_path/f'rotate_{tag}.vti'
if update: modified.save(reference) if update: modified.save(reference)
assert Grid.load(reference) == modified assert GeomGrid.load(reference) == modified
def test_canvas_extend(self,default): def test_canvas_extend(self,default):
cells = default.cells cells = default.cells
@ -280,7 +280,7 @@ class TestGrid:
@pytest.mark.parametrize('sign',[+1,-1]) @pytest.mark.parametrize('sign',[+1,-1])
@pytest.mark.parametrize('extra_offset',[0,-1]) @pytest.mark.parametrize('extra_offset',[0,-1])
def test_canvas_move_out(self,sign,extra_offset): def test_canvas_move_out(self,sign,extra_offset):
g = Grid(np.zeros(np.random.randint(3,30,(3)),int),np.ones(3)) g = GeomGrid(np.zeros(np.random.randint(3,30,(3)),int),np.ones(3))
o = sign*np.ones(3)*g.cells.min() +extra_offset*sign o = sign*np.ones(3)*g.cells.min() +extra_offset*sign
if extra_offset == 0: if extra_offset == 0:
assert np.all(g.canvas(offset=o).material == 1) assert np.all(g.canvas(offset=o).material == 1)
@ -288,7 +288,7 @@ class TestGrid:
assert np.all(np.unique(g.canvas(offset=o).material) == (0,1)) assert np.all(np.unique(g.canvas(offset=o).material) == (0,1))
def test_canvas_cells(self,default): def test_canvas_cells(self,default):
g = Grid(np.zeros(np.random.randint(3,30,(3)),int),np.ones(3)) g = GeomGrid(np.zeros(np.random.randint(3,30,(3)),int),np.ones(3))
cells = np.random.randint(1,30,(3)) cells = np.random.randint(1,30,(3))
offset = np.random.randint(-30,30,(3)) offset = np.random.randint(-30,30,(3))
assert np.all(g.canvas(cells,offset).cells == cells) assert np.all(g.canvas(cells,offset).cells == cells)
@ -308,8 +308,8 @@ class TestGrid:
o = np.random.random(3)-.5 o = np.random.random(3)-.5
g = np.random.randint(8,32,(3)) g = np.random.randint(8,32,(3))
s = np.random.random(3)+.5 s = np.random.random(3)+.5
G_1 = Grid(np.ones(g,'i'),s,o).add_primitive(diameter,center1,exponent) G_1 = GeomGrid(np.ones(g,'i'),s,o).add_primitive(diameter,center1,exponent)
G_2 = Grid(np.ones(g,'i'),s,o).add_primitive(diameter,center2,exponent) G_2 = GeomGrid(np.ones(g,'i'),s,o).add_primitive(diameter,center2,exponent)
assert np.count_nonzero(G_1.material!=2) == np.count_nonzero(G_2.material!=2) assert np.count_nonzero(G_1.material!=2) == np.count_nonzero(G_2.material!=2)
@pytest.mark.parametrize('center',[np.random.randint(4,10,(3)), @pytest.mark.parametrize('center',[np.random.randint(4,10,(3)),
@ -323,8 +323,8 @@ class TestGrid:
g = np.random.randint(8,32,(3)) g = np.random.randint(8,32,(3))
s = np.random.random(3)+.5 s = np.random.random(3)+.5
fill = np.random.randint(10)+2 fill = np.random.randint(10)+2
G_1 = Grid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic) G_1 = GeomGrid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic)
G_2 = Grid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic) G_2 = GeomGrid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic)
assert G_1 == G_2 assert G_1 == G_2
@pytest.mark.parametrize('exponent',[1,np.inf,np.random.random(3)*2.]) @pytest.mark.parametrize('exponent',[1,np.inf,np.random.random(3)*2.])
@ -332,7 +332,7 @@ class TestGrid:
"""Shapes defined in the center should always produce a grid with reflection symmetry along the coordinate axis.""" """Shapes defined in the center should always produce a grid with reflection symmetry along the coordinate axis."""
o = np.random.random(3)-.5 o = np.random.random(3)-.5
s = np.random.random(3)*5. s = np.random.random(3)*5.
grid = Grid(np.zeros(np.random.randint(8,32,3),'i'),s,o).add_primitive(np.random.random(3)*3.,o+s/2.,exponent) grid = GeomGrid(np.zeros(np.random.randint(8,32,3),'i'),s,o).add_primitive(np.random.random(3)*3.,o+s/2.,exponent)
for axis in [0,1,2]: for axis in [0,1,2]:
assert np.all(grid.material==np.flip(grid.material,axis=axis)) assert np.all(grid.material==np.flip(grid.material,axis=axis))
@ -352,7 +352,7 @@ class TestGrid:
if selection == 1: if selection == 1:
m2[m==1] = 1 m2[m==1] = 1
grid = Grid(m,np.random.rand(3)).vicinity_offset(distance,offset,selection=selection) grid = GeomGrid(m,np.random.rand(3)).vicinity_offset(distance,offset,selection=selection)
assert np.all(m2==grid.material) assert np.all(m2==grid.material)
@ -379,8 +379,8 @@ class TestGrid:
size = np.random.random(3) + 1.0 size = np.random.random(3) + 1.0
N_seeds= np.random.randint(10,30) N_seeds= np.random.randint(10,30)
seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3)) seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3))
Voronoi = Grid.from_Voronoi_tessellation( cells,size,seeds, np.arange(N_seeds)+5,periodic) Voronoi = GeomGrid.from_Voronoi_tessellation( cells,size,seeds, np.arange(N_seeds)+5,periodic)
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic) Laguerre = GeomGrid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic)
assert Laguerre == Voronoi assert Laguerre == Voronoi
def test_Laguerre_weights(self): def test_Laguerre_weights(self):
@ -391,7 +391,7 @@ class TestGrid:
weights= np.full((N_seeds),-np.inf) weights= np.full((N_seeds),-np.inf)
ms = np.random.randint(N_seeds) ms = np.random.randint(N_seeds)
weights[ms] = np.random.random() weights[ms] = np.random.random()
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5) Laguerre = GeomGrid.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5)
assert np.all(Laguerre.material == ms) assert np.all(Laguerre.material == ms)
@pytest.mark.parametrize('approach',['Laguerre','Voronoi']) @pytest.mark.parametrize('approach',['Laguerre','Voronoi'])
@ -402,9 +402,9 @@ class TestGrid:
material = np.zeros(cells) material = np.zeros(cells)
material[:,cells[1]//2:,:] = 1 material[:,cells[1]//2:,:] = 1
if approach == 'Laguerre': if approach == 'Laguerre':
grid = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(2),periodic=np.random.random()>0.5) grid = GeomGrid.from_Laguerre_tessellation(cells,size,seeds,np.ones(2),periodic=np.random.random()>0.5)
elif approach == 'Voronoi': elif approach == 'Voronoi':
grid = Grid.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5) grid = GeomGrid.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5)
assert np.all(grid.material == material) assert np.all(grid.material == material)
@pytest.mark.parametrize('surface',['Schwarz P', @pytest.mark.parametrize('surface',['Schwarz P',
@ -426,7 +426,7 @@ class TestGrid:
threshold = 2*np.random.rand()-1. threshold = 2*np.random.rand()-1.
periods = np.random.randint(2)+1 periods = np.random.randint(2)+1
materials = np.random.randint(0,40,2) materials = np.random.randint(0,40,2)
grid = Grid.from_minimal_surface(cells,size,surface,threshold,periods,materials) grid = GeomGrid.from_minimal_surface(cells,size,surface,threshold,periods,materials)
assert set(grid.material.flatten()) | set(materials) == set(materials) \ assert set(grid.material.flatten()) | set(materials) == set(materials) \
and (grid.size == size).all() and (grid.cells == cells).all() and (grid.size == size).all() and (grid.cells == cells).all()
@ -445,7 +445,7 @@ class TestGrid:
]) ])
def test_minimal_surface_volume(self,surface,threshold): def test_minimal_surface_volume(self,surface,threshold):
cells = np.ones(3,dtype=int)*64 cells = np.ones(3,dtype=int)*64
grid = Grid.from_minimal_surface(cells,np.ones(3),surface,threshold) grid = GeomGrid.from_minimal_surface(cells,np.ones(3),surface,threshold)
assert np.isclose(np.count_nonzero(grid.material==1)/np.prod(grid.cells),.5,rtol=1e-3) assert np.isclose(np.count_nonzero(grid.material==1)/np.prod(grid.cells),.5,rtol=1e-3)
def test_from_table(self): def test_from_table(self):
@ -456,23 +456,23 @@ class TestGrid:
z[cells[:2].prod()*int(cells[2]/2):] = 0 z[cells[:2].prod()*int(cells[2]/2):] = 0
t = Table({'coords':3,'z':1},np.column_stack((coords,z))) t = Table({'coords':3,'z':1},np.column_stack((coords,z)))
t = t.set('indicator',t.get('coords')[:,0]) t = t.set('indicator',t.get('coords')[:,0])
g = Grid.from_table(t,'coords',['indicator','z']) g = GeomGrid.from_table(t,'coords',['indicator','z'])
assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all() assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all()
def test_from_table_recover(self,tmp_path): def test_from_table_recover(self,tmp_path):
cells = np.random.randint(60,100,3) cells = np.random.randint(60,100,3)
size = np.ones(3)+np.random.rand(3) size = np.ones(3)+np.random.rand(3)
s = seeds.from_random(size,np.random.randint(60,100)) s = seeds.from_random(size,np.random.randint(60,100))
grid = Grid.from_Voronoi_tessellation(cells,size,s) grid = GeomGrid.from_Voronoi_tessellation(cells,size,s)
coords = grid_filters.coordinates0_point(cells,size) coords = grid_filters.coordinates0_point(cells,size)
t = Table({'c':3,'m':1},np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F')))) t = Table({'c':3,'m':1},np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))))
assert grid.sort().renumber() == Grid.from_table(t,'c',['m']) assert grid.sort().renumber() == GeomGrid.from_table(t,'c',['m'])
@pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('periodic',[True,False])
@pytest.mark.parametrize('direction',['x','y','z',['x','y'],'zy','xz',['x','y','z']]) @pytest.mark.parametrize('direction',['x','y','z',['x','y'],'zy','xz',['x','y','z']])
@pytest.mark.xfail(vtkVersion.GetVTKMajorVersion()<8, reason='missing METADATA') @pytest.mark.xfail(vtkVersion.GetVTKMajorVersion()<8, reason='missing METADATA')
def test_get_grain_boundaries(self,update,res_path,periodic,direction): def test_get_grain_boundaries(self,update,res_path,periodic,direction):
grid = Grid.load(res_path/'get_grain_boundaries_8g12x15x20.vti') grid = GeomGrid.load(res_path/'get_grain_boundaries_8g12x15x20.vti')
current = grid.get_grain_boundaries(periodic,direction) current = grid.get_grain_boundaries(periodic,direction)
if update: if update:
current.save(res_path/f'get_grain_boundaries_8g12x15x20_{direction}_{periodic}.vtu',parallel=False) current.save(res_path/f'get_grain_boundaries_8g12x15x20_{direction}_{periodic}.vtu',parallel=False)
@ -485,24 +485,24 @@ class TestGrid:
default.get_grain_boundaries(directions=directions) default.get_grain_boundaries(directions=directions)
def test_load_DREAM3D(self,res_path): def test_load_DREAM3D(self,res_path):
grain = Grid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d','FeatureIds') grain = GeomGrid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d','FeatureIds')
point = Grid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d') point = GeomGrid.load_DREAM3D(res_path/'2phase_irregularGrid.dream3d')
assert np.allclose(grain.origin,point.origin) and \ assert np.allclose(grain.origin,point.origin) and \
np.allclose(grain.size,point.size) and \ np.allclose(grain.size,point.size) and \
(grain.sort().material == point.material+1).all() (grain.sort().material == point.material+1).all()
def test_load_DREAM3D_reference(self,res_path,update): def test_load_DREAM3D_reference(self,res_path,update):
current = Grid.load_DREAM3D(res_path/'measured.dream3d') current = GeomGrid.load_DREAM3D(res_path/'measured.dream3d')
reference = Grid.load(res_path/'measured.vti') reference = GeomGrid.load(res_path/'measured.vti')
if update: if update:
current.save(res_path/'measured.vti') current.save(res_path/'measured.vti')
assert current == reference assert current == reference
def test_load_Neper_reference(self,res_path,update): def test_load_Neper_reference(self,res_path,update):
current = Grid.load_Neper(res_path/'n10-id1_scaled.vtk').renumber() current = GeomGrid.load_Neper(res_path/'n10-id1_scaled.vtk').renumber()
reference = Grid.load(res_path/'n10-id1_scaled.vti') reference = GeomGrid.load(res_path/'n10-id1_scaled.vti')
if update: if update:
current.save(res_path/'n10-id1_scaled.vti') current.save(res_path/'n10-id1_scaled.vti')

View File

@ -3,8 +3,8 @@ import numpy as np
from damask import grid_filters from damask import grid_filters
from damask import mechanics from damask import mechanics
from damask import Grid
from damask import seeds from damask import seeds
from damask import GeomGrid
class TestGridFilters: class TestGridFilters:
@ -205,7 +205,7 @@ class TestGridFilters:
def test_regrid_double_cells(self): def test_regrid_double_cells(self):
size = np.random.random(3) # noqa size = np.random.random(3) # noqa
cells = np.random.randint(8,32,(3)) cells = np.random.randint(8,32,(3))
g = Grid.from_Voronoi_tessellation(cells,size,seeds.from_random(size,10)) g = GeomGrid.from_Voronoi_tessellation(cells,size,seeds.from_random(size,10))
F = np.broadcast_to(np.eye(3), (*cells,3,3)) F = np.broadcast_to(np.eye(3), (*cells,3,3))
assert g.scale(cells*2) == g.assemble(grid_filters.regrid(size,F,cells*2)) assert g.scale(cells*2) == g.assemble(grid_filters.regrid(size,F,cells*2))

View File

@ -4,7 +4,7 @@ from scipy.spatial import cKDTree
from damask import seeds from damask import seeds
from damask import grid_filters from damask import grid_filters
from damask import Grid from damask import GeomGrid
class TestSeeds: class TestSeeds:
@ -40,9 +40,9 @@ class TestSeeds:
N_seeds = np.random.randint(30,300) N_seeds = np.random.randint(30,300)
size = np.ones(3) + np.random.random(3) size = np.ones(3) + np.random.random(3)
coords = seeds.from_random(size,N_seeds,cells) coords = seeds.from_random(size,N_seeds,cells)
grid_1 = Grid.from_Voronoi_tessellation(cells,size,coords) grid_1 = GeomGrid.from_Voronoi_tessellation(cells,size,coords)
coords,material = seeds.from_grid(grid_1) coords,material = seeds.from_grid(grid_1)
grid_2 = Grid.from_Voronoi_tessellation(cells,size,coords,material) grid_2 = GeomGrid.from_Voronoi_tessellation(cells,size,coords,material)
assert (grid_2.material==grid_1.material).all() assert (grid_2.material==grid_1.material).all()
@pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('periodic',[True,False])
@ -52,9 +52,9 @@ class TestSeeds:
size = np.ones(3) + np.random.random(3) size = np.ones(3) + np.random.random(3)
coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3)
np.random.shuffle(coords) np.random.shuffle(coords)
grid_1 = Grid.from_Voronoi_tessellation(cells,size,coords) grid_1 = GeomGrid.from_Voronoi_tessellation(cells,size,coords)
coords,material = seeds.from_grid(grid_1,average=average,periodic=periodic) coords,material = seeds.from_grid(grid_1,average=average,periodic=periodic)
grid_2 = Grid.from_Voronoi_tessellation(cells,size,coords,material) grid_2 = GeomGrid.from_Voronoi_tessellation(cells,size,coords,material)
assert (grid_2.material==grid_1.material).all() assert (grid_2.material==grid_1.material).all()
@pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('periodic',[True,False])
@ -65,7 +65,7 @@ class TestSeeds:
N_seeds = np.random.randint(30,300) N_seeds = np.random.randint(30,300)
size = np.ones(3) + np.random.random(3) size = np.ones(3) + np.random.random(3)
coords = seeds.from_random(size,N_seeds,cells) coords = seeds.from_random(size,N_seeds,cells)
grid = Grid.from_Voronoi_tessellation(cells,size,coords) grid = GeomGrid.from_Voronoi_tessellation(cells,size,coords)
selection=np.random.randint(N_seeds)+1 selection=np.random.randint(N_seeds)+1
coords,material = seeds.from_grid(grid,average=average,periodic=periodic,invert_selection=invert,selection=[selection]) coords,material = seeds.from_grid(grid,average=average,periodic=periodic,invert_selection=invert,selection=[selection])
assert selection not in material if invert else (selection==material).all() assert selection not in material if invert else (selection==material).all()