From c5c2763e1f975865ad709dcd69ab9f304bd93e52 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 11 Mar 2022 22:22:12 +0100 Subject: [PATCH 1/8] several improvements - DataFrame.append is deprecated - restored special case `None` for Grid.vicinity_offset and Grid.clean - sorted procedures of Grid according to functionality --- python/damask/_grid.py | 731 +++++++++++++++++++------------------- python/damask/_table.py | 2 +- python/tests/test_Grid.py | 62 ++-- 3 files changed, 393 insertions(+), 402 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 14177417c..733cc3f44 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -717,6 +717,368 @@ class Grid: .show('material',colormap) + def canvas(self, + cells: IntSequence = None, + offset: IntSequence = None, + fill: int = None) -> 'Grid': + """ + Crop or enlarge/pad grid. + + Parameters + ---------- + cells : sequence of int, len (3), optional + Number of cells x,y,z direction. + offset : sequence of int, len (3), optional + Offset (measured in cells) from old to new grid. + Defaults to [0,0,0]. + fill : int, optional + Material ID to fill the background. + Defaults to material.max() + 1. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + Examples + -------- + Remove lower 1/2 of the microstructure in z-direction. + + >>> import numpy as np + >>> import damask + >>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4) + >>> g.canvas([32,32,16],[0,0,16]) + cells : 33 x 32 x 16 + size : 0.0001 x 0.0001 x 5e-05 m³ + origin: 0.0 0.0 5e-05 m + # materials: 1 + + """ + offset_ = np.array(offset,int) if offset is not None else np.zeros(3,int) + cells_ = np.array(cells,int) if cells is not None else self.cells + + canvas = np.full(cells_,np.nanmax(self.material) + 1 if fill is None else fill,self.material.dtype) + + LL = np.clip( offset_, 0,np.minimum(self.cells, cells_+offset_)) + UR = np.clip( offset_+cells_, 0,np.minimum(self.cells, cells_+offset_)) + ll = np.clip(-offset_, 0,np.minimum( cells_,self.cells-offset_)) + ur = np.clip(-offset_+self.cells,0,np.minimum( cells_,self.cells-offset_)) + + 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, + size = self.size/self.cells*np.asarray(canvas.shape), + origin = self.origin+offset_*self.size/self.cells, + comments = self.comments+[util.execution_stamp('Grid','canvas')], + ) + + + def mirror(self, + directions: Sequence[str], + reflect: bool = False) -> 'Grid': + """ + Mirror grid along given directions. + + Parameters + ---------- + directions : (sequence of) {'x', 'y', 'z'} + Direction(s) along which the grid is mirrored. + reflect : bool, optional + Reflect (include) outermost layers. Defaults to False. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + Examples + -------- + Mirror along x- and y-direction. + + >>> import numpy as np + >>> import damask + >>> g = damask.Grid(np.zeros([32]*3,int), np.ones(3)*1e-4) + >>> g.mirror('xy',True) + cells : 64 x 64 x 32 + size : 0.0002 x 0.0002 x 0.0001 m³ + origin: 0.0 0.0 0.0 m + # materials: 1 + + """ + if not set(directions).issubset(valid := ['x', 'y', 'z']): + raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified') + + limits: Sequence[Optional[int]] = [None,None] if reflect else [-2,0] + mat = self.material.copy() + + if 'x' in directions: + mat = np.concatenate([mat,mat[limits[0]:limits[1]:-1,:,:]],0) + if 'y' in directions: + mat = np.concatenate([mat,mat[:,limits[0]:limits[1]:-1,:]],1) + if 'z' in directions: + mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2) + + return Grid(material = mat, + size = self.size/self.cells*np.asarray(mat.shape), + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','mirror')], + ) + + + def flip(self, + directions: Sequence[str]) -> 'Grid': + """ + Flip grid along given directions. + + Parameters + ---------- + directions : (sequence of) {'x', 'y', 'z'} + Direction(s) along which the grid is flipped. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + """ + if not set(directions).issubset(valid := ['x', 'y', 'z']): + raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified') + + + mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid]) + + return Grid(material = mat, + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','flip')], + ) + + + def rotate(self, + R: Rotation, + fill: int = None) -> 'Grid': + """ + Rotate grid (and pad if required). + + Parameters + ---------- + R : damask.Rotation + Rotation to apply to the grid. + fill : int, optional + Material ID to fill enlarged bounding box. + Defaults to material.max() + 1. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + """ + material = self.material + # These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'') + # see https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf + for angle,axes in zip(R.as_Euler_angles(degrees=True)[::-1], [(0,1),(1,2),(0,1)]): + material_temp = ndimage.rotate(material,angle,axes,order=0,prefilter=False, + output=self.material.dtype, + cval=np.nanmax(self.material) + 1 if fill is None else fill) + # avoid scipy interpolation errors for rotations close to multiples of 90° + material = material_temp if np.prod(material_temp.shape) != np.prod(material.shape) else \ + np.rot90(material,k=np.rint(angle/90.).astype(int),axes=axes) + + origin = self.origin-(np.asarray(material.shape)-self.cells)*.5 * self.size/self.cells + + return Grid(material = material, + size = self.size/self.cells*np.asarray(material.shape), + origin = origin, + comments = self.comments+[util.execution_stamp('Grid','rotate')], + ) + + + def scale(self, + cells: IntSequence, + periodic: bool = True) -> 'Grid': + """ + Scale grid to new cells. + + Parameters + ---------- + cells : sequence of int, len (3) + Number of cells in x,y,z direction. + periodic : bool, optional + Assume grid to be periodic. Defaults to True. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + Examples + -------- + Double resolution. + + >>> import numpy as np + >>> import damask + >>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4) + >>> g.scale(g.cells*2) + cells : 64 x 64 x 64 + size : 0.0001 x 0.0001 x 0.0001 m³ + origin: 0.0 0.0 0.0 m + # materials: 1 + + """ + return Grid(material = ndimage.interpolation.zoom( + self.material, + cells/self.cells, + output=self.material.dtype, + order=0, + mode='wrap' if periodic else 'nearest', + prefilter=False + ), + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','scale')], + ) + + + def renumber(self) -> 'Grid': + """ + Renumber sorted material indices as 0,...,N-1. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + """ + _,renumbered = np.unique(self.material,return_inverse=True) + + return Grid(material = renumbered.reshape(self.cells), + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','renumber')], + ) + + + def substitute(self, + from_material: Union[int,IntSequence], + to_material: Union[int,IntSequence]) -> 'Grid': + """ + Substitute material indices. + + Parameters + ---------- + from_material : int or sequence of int + Material indices to be substituted. + to_material : int or sequence of int + New material indices. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + """ + material = self.material.copy() + for f,t in zip(from_material if isinstance(from_material,(Sequence,np.ndarray)) else [from_material], + 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 + + return Grid(material = material, + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','substitute')], + ) + + + def sort(self) -> 'Grid': + """ + Sort material indices such that min(material) is located at (0,0,0). + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + """ + a = self.material.flatten(order='F') + from_ma = pd.unique(a) + sort_idx = np.argsort(from_ma) + ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)] + + return Grid(material = ma.reshape(self.cells,order='F'), + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','sort')], + ) + + + def clean(self, + distance: float = np.sqrt(3), + selection: IntCollection = None, + invert_selection: bool = False, + periodic: bool = True, + rng_seed: NumpyRngSeed = None) -> 'Grid': + """ + Smooth grid by selecting most frequent material ID within given stencil at each location. + + Parameters + ---------- + distance : float, optional + Voxel distance checked for presence of other materials. + Defaults to sqrt(3). + selection : int or collection of int, optional + Material IDs to consider. Defaults to all. + invert_selection : bool, optional + Consider all material IDs except those in selection. Defaults to False. + periodic : bool, optional + Assume grid to be periodic. Defaults to True. + rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional + A seed to initialize the BitGenerator. Defaults to None. + If None, then fresh, unpredictable entropy will be pulled from the OS. + + Returns + ------- + updated : damask.Grid + Updated grid-based geometry. + + Notes + ----- + If multiple material IDs are most frequent within a stencil, a random choice is taken. + + """ + def most_frequent(stencil: np.ndarray, + selection: Union[None,set], + rng): + me = stencil[stencil.size//2] + if selection is None or me in selection: + unique, counts = np.unique(stencil,return_counts=True) + return rng.choice(unique[counts==np.max(counts)]) + else: + return me + + rng = np.random.default_rng(rng_seed) + + d = np.floor(distance).astype(int) + ext = np.linspace(-d,d,1+2*d,dtype=float), + xx,yy,zz = np.meshgrid(ext,ext,ext) + footprint = xx**2+yy**2+zz**2 <= distance**2+distance*1e-8 + selection_ = None if selection is None else \ + set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \ + set(self.material.flatten()) & set(util.aslist(selection)) + material = ndimage.filters.generic_filter( + self.material, + most_frequent, + footprint=footprint, + mode='wrap' if periodic else 'nearest', + extra_keywords=dict(selection=selection_,rng=rng), + ).astype(self.material.dtype) + return Grid(material = material, + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Grid','clean')], + ) + + def add_primitive(self, dimension: Union[FloatSequence, IntSequence], center: Union[FloatSequence, IntSequence], @@ -809,366 +1171,6 @@ class Grid: ) - def mirror(self, - directions: Sequence[str], - reflect: bool = False) -> 'Grid': - """ - Mirror grid along given directions. - - Parameters - ---------- - directions : (sequence of) {'x', 'y', 'z'} - Direction(s) along which the grid is mirrored. - reflect : bool, optional - Reflect (include) outermost layers. Defaults to False. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - Examples - -------- - Mirror along x- and y-direction. - - >>> import numpy as np - >>> import damask - >>> g = damask.Grid(np.zeros([32]*3,int), np.ones(3)*1e-4) - >>> g.mirror('xy',True) - cells : 64 x 64 x 32 - size : 0.0002 x 0.0002 x 0.0001 m³ - origin: 0.0 0.0 0.0 m - # materials: 1 - - """ - if not set(directions).issubset(valid := ['x', 'y', 'z']): - raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified') - - limits: Sequence[Optional[int]] = [None,None] if reflect else [-2,0] - mat = self.material.copy() - - if 'x' in directions: - mat = np.concatenate([mat,mat[limits[0]:limits[1]:-1,:,:]],0) - if 'y' in directions: - mat = np.concatenate([mat,mat[:,limits[0]:limits[1]:-1,:]],1) - if 'z' in directions: - mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2) - - return Grid(material = mat, - size = self.size/self.cells*np.asarray(mat.shape), - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','mirror')], - ) - - - def flip(self, - directions: Sequence[str]) -> 'Grid': - """ - Flip grid along given directions. - - Parameters - ---------- - directions : (sequence of) {'x', 'y', 'z'} - Direction(s) along which the grid is flipped. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - """ - if not set(directions).issubset(valid := ['x', 'y', 'z']): - raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified') - - - mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid]) - - return Grid(material = mat, - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','flip')], - ) - - - def scale(self, - cells: IntSequence, - periodic: bool = True) -> 'Grid': - """ - Scale grid to new cells. - - Parameters - ---------- - cells : sequence of int, len (3) - Number of cells in x,y,z direction. - periodic : bool, optional - Assume grid to be periodic. Defaults to True. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - Examples - -------- - Double resolution. - - >>> import numpy as np - >>> import damask - >>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4) - >>> g.scale(g.cells*2) - cells : 64 x 64 x 64 - size : 0.0001 x 0.0001 x 0.0001 m³ - origin: 0.0 0.0 0.0 m - # materials: 1 - - """ - return Grid(material = ndimage.interpolation.zoom( - self.material, - cells/self.cells, - output=self.material.dtype, - order=0, - mode='wrap' if periodic else 'nearest', - prefilter=False - ), - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','scale')], - ) - - - def clean(self, - distance: float = np.sqrt(3), - selection: IntCollection = None, - invert_selection: bool = False, - periodic: bool = True, - rng_seed: NumpyRngSeed = None) -> 'Grid': - """ - Smooth grid by selecting most frequent material ID within given stencil at each location. - - Parameters - ---------- - distance : float, optional - Voxel distance checked for presence of other materials. - Defaults to sqrt(3). - selection : int or collection of int, optional - Material IDs to consider. - invert_selection : bool, optional - Consider all material IDs except those in selection. Defaults to False. - periodic : bool, optional - Assume grid to be periodic. Defaults to True. - rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional - A seed to initialize the BitGenerator. Defaults to None. - If None, then fresh, unpredictable entropy will be pulled from the OS. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - Notes - ----- - If multiple material IDs are most frequent within a stencil, a random choice is taken. - - """ - def most_frequent(stencil: np.ndarray, - selection: set, - rng): - me = stencil[stencil.size//2] - if not selection or me in selection: - unique, counts = np.unique(stencil,return_counts=True) - return rng.choice(unique[counts==np.max(counts)]) - else: - return me - - rng = np.random.default_rng(rng_seed) - d = np.floor(distance).astype(int) - ext = np.linspace(-d,d,1+2*d,dtype=float), - xx,yy,zz = np.meshgrid(ext,ext,ext) - footprint = xx**2+yy**2+zz**2 <= distance**2+distance*1e-8 - selection_ = set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \ - set(util.aslist(selection)) - material = ndimage.filters.generic_filter( - self.material, - most_frequent, - footprint=footprint, - mode='wrap' if periodic else 'nearest', - extra_keywords=dict(selection=selection_,rng=rng), - ).astype(self.material.dtype) - return Grid(material = material, - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','clean')], - ) - - - def renumber(self) -> 'Grid': - """ - Renumber sorted material indices as 0,...,N-1. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - """ - _,renumbered = np.unique(self.material,return_inverse=True) - - return Grid(material = renumbered.reshape(self.cells), - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','renumber')], - ) - - - def rotate(self, - R: Rotation, - fill: int = None) -> 'Grid': - """ - Rotate grid (and pad if required). - - Parameters - ---------- - R : damask.Rotation - Rotation to apply to the grid. - fill : int, optional - Material ID to fill enlarged bounding box. - Defaults to material.max() + 1. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - """ - material = self.material - # These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'') - # see https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf - for angle,axes in zip(R.as_Euler_angles(degrees=True)[::-1], [(0,1),(1,2),(0,1)]): - material_temp = ndimage.rotate(material,angle,axes,order=0,prefilter=False, - output=self.material.dtype, - cval=np.nanmax(self.material) + 1 if fill is None else fill) - # avoid scipy interpolation errors for rotations close to multiples of 90° - material = material_temp if np.prod(material_temp.shape) != np.prod(material.shape) else \ - np.rot90(material,k=np.rint(angle/90.).astype(int),axes=axes) - - origin = self.origin-(np.asarray(material.shape)-self.cells)*.5 * self.size/self.cells - - return Grid(material = material, - size = self.size/self.cells*np.asarray(material.shape), - origin = origin, - comments = self.comments+[util.execution_stamp('Grid','rotate')], - ) - - - def canvas(self, - cells: IntSequence = None, - offset: IntSequence = None, - fill: int = None) -> 'Grid': - """ - Crop or enlarge/pad grid. - - Parameters - ---------- - cells : sequence of int, len (3), optional - Number of cells x,y,z direction. - offset : sequence of int, len (3), optional - Offset (measured in cells) from old to new grid. - Defaults to [0,0,0]. - fill : int, optional - Material ID to fill the background. - Defaults to material.max() + 1. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - Examples - -------- - Remove lower 1/2 of the microstructure in z-direction. - - >>> import numpy as np - >>> import damask - >>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4) - >>> g.canvas([32,32,16],[0,0,16]) - cells : 33 x 32 x 16 - size : 0.0001 x 0.0001 x 5e-05 m³ - origin: 0.0 0.0 5e-05 m - # materials: 1 - - """ - offset_ = np.array(offset,int) if offset is not None else np.zeros(3,int) - cells_ = np.array(cells,int) if cells is not None else self.cells - - canvas = np.full(cells_,np.nanmax(self.material) + 1 if fill is None else fill,self.material.dtype) - - LL = np.clip( offset_, 0,np.minimum(self.cells, cells_+offset_)) - UR = np.clip( offset_+cells_, 0,np.minimum(self.cells, cells_+offset_)) - ll = np.clip(-offset_, 0,np.minimum( cells_,self.cells-offset_)) - ur = np.clip(-offset_+self.cells,0,np.minimum( cells_,self.cells-offset_)) - - 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, - size = self.size/self.cells*np.asarray(canvas.shape), - origin = self.origin+offset_*self.size/self.cells, - comments = self.comments+[util.execution_stamp('Grid','canvas')], - ) - - - def substitute(self, - from_material: Union[int,IntSequence], - to_material: Union[int,IntSequence]) -> 'Grid': - """ - Substitute material indices. - - Parameters - ---------- - from_material : int or sequence of int - Material indices to be substituted. - to_material : int or sequence of int - New material indices. - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - """ - material = self.material.copy() - for f,t in zip(from_material if isinstance(from_material,(Sequence,np.ndarray)) else [from_material], - 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 - - return Grid(material = material, - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','substitute')], - ) - - - def sort(self) -> 'Grid': - """ - Sort material indices such that min(material) is located at (0,0,0). - - Returns - ------- - updated : damask.Grid - Updated grid-based geometry. - - """ - a = self.material.flatten(order='F') - from_ma = pd.unique(a) - sort_idx = np.argsort(from_ma) - ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)] - - return Grid(material = ma.reshape(self.cells,order='F'), - size = self.size, - origin = self.origin, - comments = self.comments+[util.execution_stamp('Grid','sort')], - ) - - def vicinity_offset(self, distance: float = np.sqrt(3), offset: int = None, @@ -1204,9 +1206,9 @@ class Grid: Updated grid-based geometry. """ - def tainted_neighborhood(stencil: np.ndarray, selection: set): + def tainted_neighborhood(stencil: np.ndarray, selection: Union[None,set]): me = stencil[stencil.size//2] - return np.any(stencil != me if not selection else + return np.any(stencil != me if selection is None else np.in1d(stencil,np.array(list(selection - {me})))) d = np.floor(distance).astype(int) @@ -1214,8 +1216,9 @@ class Grid: xx,yy,zz = np.meshgrid(ext,ext,ext) footprint = xx**2+yy**2+zz**2 <= distance**2+distance*1e-8 offset_ = np.nanmax(self.material)+1 if offset is None else offset - selection_ = set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \ - set(util.aslist(selection)) + selection_ = None if selection is None else \ + set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \ + set(self.material.flatten()) & set(util.aslist(selection)) mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, footprint=footprint, diff --git a/python/damask/_table.py b/python/damask/_table.py index f4385ca99..9aab51b18 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -535,7 +535,7 @@ class Table: raise KeyError('mismatch of shapes or labels or their order') dup = self.copy() - dup.data = dup.data.append(other.data,ignore_index=True) + dup.data = pd.concat([dup.data,other.data],ignore_index=True) return dup diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 5bdfd9e5b..f1934a14c 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -12,11 +12,6 @@ from damask import seeds from damask import grid_filters -def grid_equal(a,b): - return np.all(a.material == b.material) and \ - np.all(a.cells == b.cells) and \ - np.allclose(a.size, b.size) - @pytest.fixture def default(): """Simple geometry.""" @@ -66,7 +61,7 @@ class TestGrid: def test_read_write_vtr(self,default,tmp_path): default.save(tmp_path/'default') new = Grid.load(tmp_path/'default.vti') - assert grid_equal(new,default) + assert new == default 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) @@ -90,7 +85,7 @@ class TestGrid: def test_save_load_ASCII(self,default,tmp_path): default.save_ASCII(tmp_path/'ASCII') default.material -= 1 - assert grid_equal(Grid.load_ASCII(tmp_path/'ASCII'),default) + assert Grid.load_ASCII(tmp_path/'ASCII') == default def test_invalid_origin(self,default): with pytest.raises(ValueError): @@ -124,8 +119,7 @@ class TestGrid: tag = f'directions_{"-".join(directions)}+reflect_{reflect}' reference = ref_path/f'mirror_{tag}.vti' if update: modified.save(reference) - assert grid_equal(Grid.load(reference), - modified) + assert Grid.load(reference) == modified @pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]]) @@ -146,17 +140,16 @@ class TestGrid: tag = f'directions_{"-".join(directions)}' reference = ref_path/f'flip_{tag}.vti' if update: modified.save(reference) - assert grid_equal(Grid.load(reference), - modified) + assert Grid.load(reference) == modified def test_flip_invariant(self,default): - assert grid_equal(default,default.flip([])) + assert default == default.flip([]) @pytest.mark.parametrize('direction',[['x'],['x','y']]) def test_flip_double(self,default,direction): - assert grid_equal(default,default.flip(direction).flip(direction)) + assert default == default.flip(direction).flip(direction) @pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]]) @@ -173,7 +166,7 @@ class TestGrid: reference = ref_path/f'clean_{distance}_{"+".join(map(str,util.aslist(selection)))}_{periodic}.vti' if update: current.save(reference) - assert grid_equal(Grid.load(reference),current) + assert Grid.load(reference) == current @pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),set(np.random.randint(1,20,6)),np.random.randint(1,20,6)]) @pytest.mark.parametrize('invert',[True,False]) @@ -201,8 +194,7 @@ class TestGrid: tag = f'grid_{util.srepr(cells,"-")}' reference = ref_path/f'scale_{tag}.vti' if update: modified.save(reference) - assert grid_equal(Grid.load(reference), - modified) + assert Grid.load(reference) == modified def test_renumber(self,default): @@ -213,9 +205,8 @@ class TestGrid: modified = Grid(material, default.size, default.origin) - assert not grid_equal(modified,default) - assert grid_equal(default, - modified.renumber()) + assert not default == modified + assert default == modified.renumber() def test_substitute(self,default): @@ -223,10 +214,9 @@ class TestGrid: modified = Grid(default.material + offset, default.size, default.origin) - assert not grid_equal(modified,default) - assert grid_equal(default, - modified.substitute(np.arange(default.material.max())+1+offset, - np.arange(default.material.max())+1)) + assert not default == modified + assert default == modified.substitute(np.arange(default.material.max())+1+offset, + np.arange(default.material.max())+1) def test_substitute_integer_list(self,random): f = np.random.randint(30) @@ -237,8 +227,8 @@ class TestGrid: f = np.unique(default.material.flatten())[:np.random.randint(1,default.material.max())] t = np.random.permutation(f) modified = default.substitute(f,t) - assert np.array_equiv(t,f) or (not grid_equal(modified,default)) - assert grid_equal(default, modified.substitute(t,f)) + assert np.array_equiv(t,f) or modified != default + assert default == modified.substitute(t,f) def test_sort(self): cells = np.random.randint(5,20,3) @@ -252,7 +242,7 @@ class TestGrid: modified = default.copy() for i in range(np.rint(360/axis_angle[3]).astype(int)): modified.rotate(Rotation.from_axis_angle(axis_angle,degrees=True)) - assert grid_equal(default,modified) + assert default == modified @pytest.mark.parametrize('Eulers',[[32.0,68.0,21.0], @@ -262,8 +252,7 @@ class TestGrid: tag = f'Eulers_{util.srepr(Eulers,"-")}' reference = ref_path/f'rotate_{tag}.vti' if update: modified.save(reference) - assert grid_equal(Grid.load(reference), - modified) + assert Grid.load(reference) == modified def test_canvas_extend(self,default): @@ -321,7 +310,7 @@ class TestGrid: 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_2 = Grid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic) - assert grid_equal(G_1,G_2) + assert G_1 == G_2 @pytest.mark.parametrize('selection',[1,None]) @@ -346,11 +335,10 @@ class TestGrid: @pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),set(np.random.randint(1,20,6)),np.random.randint(1,20,6)]) @pytest.mark.parametrize('invert',[True,False]) - def test_vicinit_offset_invert(self,random,selection,invert): + def test_vicinity_offset_invert(self,random,selection,invert): selection_inverse = set(random.material.flatten()) - set(selection) - assert selection_inverse == set() or \ - (random.vicinity_offset(selection=selection,invert_selection=invert) == - random.vicinity_offset(selection=selection_inverse,invert_selection=not invert)) + assert random.vicinity_offset(selection=selection ,invert_selection=not invert) == \ + random.vicinity_offset(selection=selection_inverse,invert_selection= invert) def test_vicinity_offset_selection_empty(self,random): assert random.vicinity_offset(selection=None,invert_selection=False) == random.vicinity_offset() and \ @@ -372,7 +360,7 @@ class TestGrid: 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) Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic) - assert grid_equal(Laguerre,Voronoi) + assert Laguerre == Voronoi def test_Laguerre_weights(self): @@ -462,7 +450,7 @@ class TestGrid: grid = Grid.from_Voronoi_tessellation(cells,size,s) coords = grid_filters.coordinates0_point(cells,size) t = Table(np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))),{'c':3,'m':1}) - assert grid_equal(grid.sort().renumber(),Grid.from_table(t,'c',['m'])) + assert grid.sort().renumber() == Grid.from_table(t,'c',['m']) @pytest.mark.parametrize('periodic',[True,False]) @@ -496,7 +484,7 @@ class TestGrid: if update: current.save(ref_path/'measured.vti') - assert grid_equal(current,reference) + assert current == reference def test_load_Neper_reference(self,ref_path,update): current = Grid.load_Neper(ref_path/'n10-id1_scaled.vtk') @@ -504,4 +492,4 @@ class TestGrid: if update: current.save(ref_path/'n10-id1_scaled.vti') - assert grid_equal(current,reference) + assert current == reference From 0d22cfb83d266c2d9db41778e3e8f87a7fb3fc80 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 11 Mar 2022 22:31:35 +0100 Subject: [PATCH 2/8] table.__init__ now has common order of arguments (label, data) --- PRIVATE | 2 +- python/damask/_colormap.py | 2 +- python/damask/_table.py | 19 +++++++++-------- python/tests/test_ConfigMaterial.py | 4 ++-- python/tests/test_Grid.py | 8 ++++---- python/tests/test_Table.py | 32 +++++++++++++++-------------- python/tests/test_VTK.py | 2 +- 7 files changed, 36 insertions(+), 33 deletions(-) diff --git a/PRIVATE b/PRIVATE index 9c1f83bab..317345ab8 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 9c1f83babb7894bfaa16255d6c15a4a438c7f168 +Subproject commit 317345ab8fffbb120630846a47ab25922d466e14 diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index d01c18c02..b4d184786 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -373,7 +373,7 @@ class Colormap(mpl.colors.ListedColormap): """ labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3} - t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}') + t = Table(labels,self.colors,f'Creator: {util.execution_stamp("Colormap")}') t.save(self._get_file_handle(fname,'.txt')) diff --git a/python/damask/_table.py b/python/damask/_table.py index 9aab51b18..36a11734a 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -13,26 +13,27 @@ class Table: """Manipulate multi-dimensional spreadsheet-like data.""" def __init__(self, - data: np.ndarray, shapes: dict, + data: np.ndarray, comments: Union[str, list] = None): """ New spreadsheet. Parameters ---------- - data : numpy.ndarray or pandas.DataFrame - Data. Column labels from a pandas.DataFrame will be replaced. shapes : dict with str:tuple pairs - Shapes of the columns. Example 'F':(3,3) for a deformation gradient. + Shapes of the data columns. + For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar. + data : numpy.ndarray or pandas.DataFrame + Data. Existing column labels of a pandas.DataFrame will be replaced. comments : str or iterable of str, optional Additional, human-readable information. """ comments_ = [comments] if isinstance(comments,str) else comments self.comments = [] if comments_ is None else [c for c in comments_] - self.data = pd.DataFrame(data=data) self.shapes = { k:(v,) if isinstance(v,(np.int64,np.int32,int)) else v for k,v in shapes.items() } + self.data = pd.DataFrame(data=data) self._relabel('uniform') @@ -70,8 +71,8 @@ class Table: -------- >>> import damask >>> import numpy as np - >>> tbl = damask.Table(data=np.arange(12).reshape((4,3)), - ... shapes=dict(colA=(1,),colB=(1,),colC=(1,))) + >>> tbl = damask.Table(shapes=dict(colA=(1,),colB=(1,),colC=(1,)), + ... data=np.arange(12).reshape((4,3))) >>> tbl['colA','colB'] colA colB 0 0 1 @@ -282,7 +283,7 @@ class Table: data = pd.read_csv(f,names=list(range(len(labels))),sep=r'\s+') - return Table(data,shapes,comments) + return Table(shapes,data,comments) @staticmethod @@ -329,7 +330,7 @@ class Table: if (remainder := data.shape[1]-sum(shapes.values())) > 0: shapes['unknown'] = remainder - return Table(data,shapes,comments) + return Table(shapes,data,comments) @property diff --git a/python/tests/test_ConfigMaterial.py b/python/tests/test_ConfigMaterial.py index b8b5df52a..ea6beae13 100644 --- a/python/tests/test_ConfigMaterial.py +++ b/python/tests/test_ConfigMaterial.py @@ -90,7 +90,7 @@ class TestConfigMaterial: np.ones(N*2),np.zeros(N*2),np.ones(N*2),np.ones(N*2), np.ones(N*2), )).T - t = Table(a,{'varying':1,'constant':4,'ones':1}) + t = Table({'varying':1,'constant':4,'ones':1},a) c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':'ones'}) assert len(c['material']) == N for i,m in enumerate(c['material']): @@ -102,7 +102,7 @@ class TestConfigMaterial: np.ones(N*2),np.zeros(N*2),np.ones(N*2),np.ones(N*2), np.ones(N*2), )).T - t = Table(a,{'varying':1,'constant':4,'ones':1}) + t = Table({'varying':1,'constant':4,'ones':1},a) c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':1}) assert len(c['material']) == N for i,m in enumerate(c['material']): diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index f1934a14c..3ac8bcb6c 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -435,9 +435,9 @@ class TestGrid: cells = np.random.randint(60,100,3) size = np.ones(3)+np.random.rand(3) coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3,order='F') - z=np.ones(cells.prod()) - z[cells[:2].prod()*int(cells[2]/2):]=0 - t = Table(np.column_stack((coords,z)),{'coords':3,'z':1}) + z = np.ones(cells.prod()) + z[cells[:2].prod()*int(cells[2]/2):] = 0 + t = Table({'coords':3,'z':1},np.column_stack((coords,z))) t = t.add('indicator',t.get('coords')[:,0]) g = Grid.from_table(t,'coords',['indicator','z']) assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all() @@ -449,7 +449,7 @@ class TestGrid: s = seeds.from_random(size,np.random.randint(60,100)) grid = Grid.from_Voronoi_tessellation(cells,size,s) coords = grid_filters.coordinates0_point(cells,size) - t = Table(np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))),{'c':3,'m':1}) + 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']) diff --git a/python/tests/test_Table.py b/python/tests/test_Table.py index 1f89026a3..707353879 100644 --- a/python/tests/test_Table.py +++ b/python/tests/test_Table.py @@ -8,7 +8,9 @@ from damask import Table def default(): """Simple Table.""" x = np.ones((5,13),dtype=float) - return Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['test data','contains five rows of only ones']) + return Table({'F':(3,3),'v':(3,),'s':(1,)}, + x, + ['test data','contains five rows of only ones']) @pytest.fixture def ref_path(ref_path_base): @@ -22,7 +24,7 @@ class TestTable: @pytest.mark.parametrize('N',[10,40]) def test_len(self,N): - assert len(Table(np.random.rand(N,3),{'X':3})) == N + assert len(Table({'X':3},np.random.rand(N,3))) == N def test_get_scalar(self,default): d = default.get('s') @@ -110,7 +112,7 @@ class TestTable: def test_rename_equivalent(self): x = np.random.random((5,13)) - t = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) + t = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) s = t.get('s') u = t.rename('s','u').get('u') assert np.all(s == u) @@ -129,35 +131,35 @@ class TestTable: def test_join(self): x = np.random.random((5,13)) - a = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) + a = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) y = np.random.random((5,3)) - b = Table(y,{'u':(3,)},['random test data']) + b = Table({'u':(3,)},y,['random test data']) c = a.join(b) assert np.array_equal(c.get('u'), b.get('u')) def test_join_invalid(self): x = np.random.random((5,13)) - a = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) + a = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) with pytest.raises(KeyError): a.join(a) def test_append(self): x = np.random.random((5,13)) - a = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) + a = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) b = a.append(a) assert np.array_equal(b.data[:5].to_numpy(),b.data[5:].to_numpy()) def test_append_invalid(self): x = np.random.random((5,13)) - a = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) - b = Table(x,{'F':(3,3),'u':(3,),'s':(1,)},['random test data']) + a = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) + b = Table({'F':(3,3),'u':(3,),'s':(1,)},x,['random test data']) with pytest.raises(KeyError): a.append(b) def test_invalid_initialization(self): x = np.random.random((5,10)) with pytest.raises(ValueError): - Table(x,{'F':(3,3)}) + Table({'F':(3,3)},x) def test_invalid_set(self,default): x = default.get('v') @@ -170,27 +172,27 @@ class TestTable: def test_sort_scalar(self): x = np.random.random((5,13)) - t = Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['random test data']) + t = Table({'F':(3,3),'v':(3,),'s':(1,)},x,['random test data']) unsort = t.get('s') sort = t.sort_by('s').get('s') assert np.all(np.sort(unsort,0)==sort) def test_sort_component(self): x = np.random.random((5,12)) - t = Table(x,{'F':(3,3),'v':(3,)},['random test data']) + t = Table({'F':(3,3),'v':(3,)},x,['random test data']) unsort = t.get('F')[:,1,0] sort = t.sort_by('F[1,0]').get('F')[:,1,0] assert np.all(np.sort(unsort,0)==sort) def test_sort_revert(self): x = np.random.random((5,12)) - t = Table(x,{'F':(3,3),'v':(3,)},['random test data']) + t = Table({'F':(3,3),'v':(3,)},x,['random test data']) sort = t.sort_by('F[1,0]',ascending=False).get('F')[:,1,0] assert np.all(np.sort(sort,0)==sort[::-1]) def test_sort(self): - t = Table(np.array([[0,1,],[2,1,]]), - {'v':(2,)}, + t = Table({'v':(2,)}, + np.array([[0,1,],[2,1,]]), ['test data'])\ .add('s',np.array(['b','a']))\ .sort_by('s') diff --git a/python/tests/test_VTK.py b/python/tests/test_VTK.py index c776135e1..4b0f9aa20 100644 --- a/python/tests/test_VTK.py +++ b/python/tests/test_VTK.py @@ -179,7 +179,7 @@ class TestVTK: for k,s in shapes.items(): d[k] = dict(shape = s, data = np.random.random(N*np.prod(s)).reshape((N,-1))) - new = default.add(Table(np.column_stack([d[k]['data'] for k in shapes.keys()]),shapes)) + new = default.add(Table(shapes,np.column_stack([d[k]['data'] for k in shapes.keys()]))) for k,s in shapes.items(): assert np.allclose(np.squeeze(d[k]['data']),new.get(k),rtol=1e-7) From d5a093397857798adbaf2a21871a2950b9c945f6 Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 12 Mar 2022 01:45:01 +0100 Subject: [PATCH 3/8] [skip ci] updated version information after successful test of v3.0.0-alpha6-134-g0d22cfb83 --- python/damask/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/VERSION b/python/damask/VERSION index bfedb5d0f..cf22db1a7 100644 --- a/python/damask/VERSION +++ b/python/damask/VERSION @@ -1 +1 @@ -v3.0.0-alpha6-126-g8d9d13c15 +v3.0.0-alpha6-134-g0d22cfb83 From 56c33b8a5ce2b0efe2168022825554bb2b4f1552 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 11 Mar 2022 20:07:18 -0500 Subject: [PATCH 4/8] flipped VTK.add to use (label,data) to be consistent with other functionality --- python/damask/_grid.py | 6 +++--- python/damask/_result.py | 4 ++-- python/damask/_vtk.py | 39 ++++++++++++++++++++++++++------------- python/tests/test_Grid.py | 2 +- python/tests/test_VTK.py | 28 +++++++++++++++++----------- 5 files changed, 49 insertions(+), 30 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 733cc3f44..1b184d6e7 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -662,9 +662,9 @@ class Grid: """ v = VTK.from_image_data(self.cells,self.size,self.origin)\ - .add(self.material.flatten(order='F'),'material') + .add('material',self.material.flatten(order='F')) for label,data in self.ic.items(): - v = v.add(data.flatten(order='F'),label) + v = v.add(label,data.flatten(order='F')) v.comments = self.comments v.save(fname,parallel=False,compress=compress) @@ -713,7 +713,7 @@ class Grid: """ VTK.from_image_data(self.cells,self.size,self.origin) \ - .add(self.material.flatten('F'),'material') \ + .add('material',self.material.flatten('F'),) \ .show('material',colormap) diff --git a/python/damask/_result.py b/python/damask/_result.py index fb6ba2ae2..227685b59 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -1621,7 +1621,7 @@ class Result: for inc in util.show_progress(self.visible['increments']): u = _read(f['/'.join([inc,'geometry','u_n' if mode.lower() == 'cell' else 'u_p'])]) - v = v.add(u,'u') + v = v.add('u',u) for ty in ['phase','homogenization']: for field in self.visible['fields']: @@ -1648,7 +1648,7 @@ class Result: outs[out][at_cell_ho[label]] = data[in_data_ho[label]] for label,dataset in outs.items(): - v = v.add(dataset,' / '.join(['/'.join([ty,field,label]),dataset.dtype.metadata['unit']])) + v = v.add(' / '.join(['/'.join([ty,field,label]),dataset.dtype.metadata['unit']]),dataset) v.save(f'{self.fname.stem}_inc{inc[10:].zfill(N_digits)}',parallel=parallel) diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index f8dce1754..4f2658cd7 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -402,24 +402,32 @@ class VTK: # Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data def add(self, - data: Union[np.ndarray, np.ma.MaskedArray, 'Table'], - label: str = None): + label: str = None, + data: Union[np.ndarray, np.ma.MaskedArray] = None, + *, + table: 'Table' = None): """ Add data to either cells or points. + Data can either be a numpy.array, which requires a corresponding label, + or a damask.Table. + Parameters ---------- - data : numpy.ndarray, numpy.ma.MaskedArray, or damask.Table + label : str, optional + Label of data array. + data : numpy.ndarray or numpy.ma.MaskedArray, optional Data to add. First dimension needs to match either number of cells or number of points. - label : str, optional if data is damask.Table - Data label. + table: damask.Table, optional + Data to add. Number of rows needs to match either + number of cells or number of points. """ def _add_array(vtk_data, - data: np.ndarray, - label: str): + label: str, + data: np.ndarray): N_data = data.shape[0] data_ = data.reshape(N_data,-1) \ @@ -441,17 +449,22 @@ class VTK: else: raise ValueError(f'data count mismatch ({N_data} ≠ {self.N_points} & {self.N_cells})') + if data is None and table is None: + raise KeyError('no data given') + if data is not None and table is not None: + raise KeyError('cannot use both, data and table') + dup = self.copy() if isinstance(data,np.ndarray): if label is not None: _add_array(dup.vtk_data, - np.where(data.mask,data.fill_value,data) if isinstance(data,np.ma.MaskedArray) else data, - label) + label, + np.where(data.mask,data.fill_value,data) if isinstance(data,np.ma.MaskedArray) else data) else: - raise ValueError('no label defined for numpy.ndarray') - elif isinstance(data,Table): - for l in data.labels: - _add_array(dup.vtk_data,data.get(l),l) + raise ValueError('no label defined for data') + elif isinstance(table,Table): + for l in table.labels: + _add_array(dup.vtk_data,l,table.get(l)) else: raise TypeError diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 3ac8bcb6c..eedf05ae6 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -58,7 +58,7 @@ class TestGrid: def test_repr(self,default): print(default) - def test_read_write_vtr(self,default,tmp_path): + def test_read_write_vti(self,default,tmp_path): default.save(tmp_path/'default') new = Grid.load(tmp_path/'default.vti') assert new == default diff --git a/python/tests/test_VTK.py b/python/tests/test_VTK.py index 4b0f9aa20..44226bf44 100644 --- a/python/tests/test_VTK.py +++ b/python/tests/test_VTK.py @@ -147,16 +147,22 @@ class TestVTK: def test_invalid_add_shape(self,default): with pytest.raises(ValueError): - default.add(np.ones(3),'valid') + default.add('valid',np.ones(3)) def test_invalid_add_missing_label(self,default): data = np.random.randint(9,size=np.prod(np.array(default.vtk_data.GetDimensions())-1)) with pytest.raises(ValueError): - default.add(data) + default.add(data=data) def test_invalid_add_type(self,default): with pytest.raises(TypeError): - default.add('invalid_type','valid') + default.add(label='valid',data='invalid_type') + with pytest.raises(TypeError): + default.add(label='valid',table='invalid_type') + + def test_invalid_add_dual(self,default): + with pytest.raises(KeyError): + default.add(label='valid',data=0,table=0) @pytest.mark.parametrize('data_type,shape',[(float,(3,)), (float,(3,3)), @@ -166,7 +172,7 @@ class TestVTK: @pytest.mark.parametrize('N_values',[5*6*7,6*7*8]) def test_add_get(self,default,data_type,shape,N_values): data = np.squeeze(np.random.randint(0,100,(N_values,)+shape)).astype(data_type) - new = default.add(data,'data') + new = default.add('data',data) assert (np.squeeze(data.reshape(N_values,-1)) == new.get('data')).all() @@ -179,7 +185,7 @@ class TestVTK: for k,s in shapes.items(): d[k] = dict(shape = s, data = np.random.random(N*np.prod(s)).reshape((N,-1))) - new = default.add(Table(shapes,np.column_stack([d[k]['data'] for k in shapes.keys()]))) + new = default.add(table=Table(shapes,np.column_stack([d[k]['data'] for k in shapes.keys()]))) for k,s in shapes.items(): assert np.allclose(np.squeeze(d[k]['data']),new.get(k),rtol=1e-7) @@ -187,8 +193,8 @@ class TestVTK: def test_add_masked(self,default): data = np.random.rand(5*6*7,3) masked = ma.MaskedArray(data,mask=data<.4,fill_value=42.) - mask_auto = default.add(masked,'D') - mask_manual = default.add(np.where(masked.mask,masked.fill_value,masked),'D') + mask_auto = default.add('D',masked) + mask_manual = default.add('D',np.where(masked.mask,masked.fill_value,masked)) assert mask_manual == mask_auto @@ -202,7 +208,7 @@ class TestVTK: data = np.squeeze(np.random.randint(0,100,(N_values,)+shape)).astype(data_type) ALPHABET = np.array(list(string.ascii_lowercase + ' ')) label = ''.join(np.random.choice(ALPHABET, size=10)) - new = default.add(data,label) + new = default.add(label,data) if N_values == default.N_points: assert label in new.labels['Point Data'] if N_values == default.N_cells: assert label in new.labels['Cell Data'] @@ -217,7 +223,7 @@ class TestVTK: @pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA') def test_compare_reference_polyData(self,update,ref_path,tmp_path): points=np.dstack((np.linspace(0.,1.,10),np.linspace(0.,2.,10),np.linspace(-1.,1.,10))).squeeze() - polyData = VTK.from_poly_data(points).add(points,'coordinates') + polyData = VTK.from_poly_data(points).add('coordinates',points) if update: polyData.save(ref_path/'polyData') else: @@ -234,8 +240,8 @@ class TestVTK: c = coords[:-1,:-1,:-1,:].reshape(-1,3,order='F') n = coords[:,:,:,:].reshape(-1,3,order='F') rectilinearGrid = VTK.from_rectilinear_grid(grid) \ - .add(np.ascontiguousarray(c),'cell') \ - .add(np.ascontiguousarray(n),'node') + .add('cell',np.ascontiguousarray(c)) \ + .add('node',np.ascontiguousarray(n)) if update: rectilinearGrid.save(ref_path/'rectilinearGrid') else: From fea00ff65df9d8e8e341c5337b4c0447adcf9e19 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 12 Mar 2022 09:05:20 +0100 Subject: [PATCH 5/8] fixed mesh_MPI test (PETSc with working ml) --- .gitlab-ci.yml | 2 +- PRIVATE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 834fd68ee..558c12c13 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,7 +45,7 @@ variables: # ++++++++++++ PETSc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PETSC_GNU: "Libraries/PETSc/3.16.4/GNU-10-OpenMPI-4.1.2" PETSC_INTELLLVM: "Libraries/PETSc/3.16.3/oneAPI-2022.0.1-IntelMPI-2021.5.0" - PETSC_INTEL: "Libraries/PETSc/3.16.4/Intel-2022.0.1-IntelMPI-2021.5.0" + PETSC_INTEL: "Libraries/PETSc/3.16.5/Intel-2022.0.1-IntelMPI-2021.5.0" # ++++++++++++ MSC Marc +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MSC: "FEM/MSC/2021.3.1" IntelMarc: "Compiler/Intel/19.1.2 Libraries/IMKL/2020" diff --git a/PRIVATE b/PRIVATE index 317345ab8..00b3eb79e 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 317345ab8fffbb120630846a47ab25922d466e14 +Subproject commit 00b3eb79ee6f8df2ca50276d2111008e5f79b3e1 From 746e02db6b0c00eb72e95a316930d0ee458de34b Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 12 Mar 2022 13:21:25 +0100 Subject: [PATCH 6/8] [skip ci] updated version information after successful test of v3.0.0-alpha6-137-g00ef0c6b6 --- python/damask/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/VERSION b/python/damask/VERSION index cf22db1a7..e32e2a355 100644 --- a/python/damask/VERSION +++ b/python/damask/VERSION @@ -1 +1 @@ -v3.0.0-alpha6-134-g0d22cfb83 +v3.0.0-alpha6-137-g00ef0c6b6 From cf49310df77b01c2415b117837d1b5cfc540d4c6 Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 12 Mar 2022 16:13:32 +0100 Subject: [PATCH 7/8] [skip ci] updated version information after successful test of v3.0.0-alpha6-140-g527c1c222 --- python/damask/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/VERSION b/python/damask/VERSION index e32e2a355..df45c2443 100644 --- a/python/damask/VERSION +++ b/python/damask/VERSION @@ -1 +1 @@ -v3.0.0-alpha6-137-g00ef0c6b6 +v3.0.0-alpha6-140-g527c1c222 From e04df124e6dcdb0f0ec8a072115c4c18a60f7e52 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Sat, 12 Mar 2022 14:37:35 -0500 Subject: [PATCH 8/8] use PRIVATE with most recent plot-commithistory.py --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 00b3eb79e..0509f684d 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 00b3eb79ee6f8df2ca50276d2111008e5f79b3e1 +Subproject commit 0509f684d3b5b8e30386ac156fff6644905908dc