From 8a84f6b07f84f3502fa894e219330dedea21a4b1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Feb 2022 11:24:54 +0100 Subject: [PATCH 01/28] origin can be negative --- src/grid/discretization_grid.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index ced5f8eff..47c0ffc06 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -98,7 +98,7 @@ subroutine discretization_grid_init(restart) print'(/,1x,a,i0,a,i0,a,i0)', 'cells: ', cells(1), ' × ', cells(2), ' × ', cells(3) print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'size: ', geomSize(1), ' × ', geomSize(2), ' × ', geomSize(3), ' m³' - print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' m' + print '(1x,a,es9.2,a,es9.2,a,es9.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' m' if (worldsize>cells(3)) call IO_error(894, ext_msg='number of processes exceeds cells(3)') From a78da9dca729dd76371f640ce6b6c167f06c4983 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Feb 2022 11:25:21 +0100 Subject: [PATCH 02/28] older gfortran does not support %re and %im for complex numbers --- cmake/Compiler-GNU.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Compiler-GNU.cmake b/cmake/Compiler-GNU.cmake index c204d1af2..164f115a0 100644 --- a/cmake/Compiler-GNU.cmake +++ b/cmake/Compiler-GNU.cmake @@ -1,7 +1,7 @@ ################################################################################################### # GNU Compiler ################################################################################################### -if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0) +if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 9.0) message (FATAL_ERROR "GCC Compiler version: ${CMAKE_Fortran_COMPILER_VERSION} not supported") endif () From 28ffdb7c1c2627158ad0deb288074d9a9c9aa283 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Feb 2022 12:41:14 +0100 Subject: [PATCH 03/28] simplified --- src/phase_mechanical.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/phase_mechanical.f90 b/src/phase_mechanical.f90 index 4c4e703f0..b13675e38 100644 --- a/src/phase_mechanical.f90 +++ b/src/phase_mechanical.f90 @@ -920,11 +920,11 @@ subroutine results(group,ph) call results_writeDataset(phase_mechanical_S(ph)%data,group//'/mechanical/','S', & 'second Piola-Kirchhoff stress','Pa') case('O') - call results_writeDataset(to_quaternion(phase_O(ph)%data),group//'/mechanical',output_mechanical(ph)%label(ou),& + call results_writeDataset(to_quaternion(phase_O(ph)%data),group//'/mechanical','O', & 'crystal orientation as quaternion','q_0 (q_1 q_2 q_3)') - call results_addAttribute('lattice',phase_lattice(ph),group//'/mechanical/'//output_mechanical(ph)%label(ou)) + call results_addAttribute('lattice',phase_lattice(ph),group//'/mechanical/O') if (any(phase_lattice(ph) == ['hP', 'tI'])) & - call results_addAttribute('c/a',phase_cOverA(ph),group//'/mechanical/'//output_mechanical(ph)%label(ou)) + call results_addAttribute('c/a',phase_cOverA(ph),group//'/mechanical/O') end select end do From 3ee04348361d5234c85be4c3b602b24779a3dd67 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Feb 2022 15:18:37 +0100 Subject: [PATCH 04/28] avoid nasty error in MPI parallel situations --- src/results.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/results.f90 b/src/results.f90 index dc77d5a7f..11728e595 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -455,7 +455,7 @@ subroutine results_writeVectorDataset_int(dataset,group,label,description,SIunit if (present(systems)) then - if (size(systems)*size(dataset,2) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar) + if (size(systems) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar) end if groupHandle = results_openGroup(group) From a314e63ed2e3e99734ef5be31052129801a64d88 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 26 Feb 2022 14:22:00 +0100 Subject: [PATCH 05/28] homogenize: (material index, material ID) -> material ID mutable describes meaning of parameter better --- python/damask/_grid.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 5d4396d3b..094e8a529 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -907,17 +907,17 @@ class Grid: def clean(self, stencil: int = 3, - selection: IntSequence = None, + mutable: IntSequence = None, periodic: bool = True) -> 'Grid': """ - Smooth grid by selecting most frequent material index within given stencil at each location. + Smooth grid by selecting most frequent material ID within given stencil at each location. Parameters ---------- stencil : int, optional - Size of smoothing stencil. - selection : sequence of int, optional - Field values that can be altered. Defaults to all. + Size of smoothing stencil. Defaults to 3. + mutable : sequence of int, optional + Material ID that can be altered. Defaults to all. periodic : bool, optional Assume grid to be periodic. Defaults to True. @@ -927,9 +927,9 @@ class Grid: Updated grid-based geometry. """ - def mostFrequent(arr: np.ndarray, selection = None): + def mostFrequent(arr: np.ndarray, mutable = None): me = arr[arr.size//2] - if selection is None or me in selection: + if selection is None or me in mutable: unique, inverse = np.unique(arr, return_inverse=True) return unique[np.argmax(np.bincount(inverse))] else: @@ -938,9 +938,9 @@ class Grid: return Grid(material = ndimage.filters.generic_filter( self.material, mostFrequent, - size=(stencil if selection is None else stencil//2*2+1,)*3, + size=(stencil if mutable is None else stencil//2*2+1,)*3, mode=('wrap' if periodic else 'nearest'), - extra_keywords=dict(selection=selection), + extra_keywords=dict(mutable=mutable), ).astype(self.material.dtype), size = self.size, origin = self.origin, @@ -978,7 +978,7 @@ class Grid: R : damask.Rotation Rotation to apply to the grid. fill : int, optional - Material index to fill the corners. Defaults to material.max() + 1. + Material ID to fill the corners. Defaults to material.max() + 1. Returns ------- @@ -1020,7 +1020,7 @@ class Grid: offset : sequence of int, len (3), optional Offset (measured in cells) from old to new grid [0,0,0]. fill : int, optional - Material index to fill the background. Defaults to material.max() + 1. + Material ID to fill the background. Defaults to material.max() + 1. Returns ------- @@ -1118,7 +1118,7 @@ class Grid: trigger: IntSequence = [], periodic: bool = True) -> 'Grid': """ - Offset material index of points in the vicinity of xxx. + Offset material ID of points in the vicinity of xxx. Different from themselves (or listed as triggers) within a given (cubic) vicinity, i.e. within the region close to a grain/phase boundary. From c7b512a94e3e92adfceb7ed4eb66395ceb4285bd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 26 Feb 2022 17:40:12 +0100 Subject: [PATCH 06/28] support the user --- python/damask/_crystal.py | 555 +++++++++++++++++----------------- python/damask/_orientation.py | 32 +- python/tests/test_Crystal.py | 8 + 3 files changed, 319 insertions(+), 276 deletions(-) diff --git a/python/damask/_crystal.py b/python/damask/_crystal.py index 26451d64d..2ad21c8bd 100644 --- a/python/damask/_crystal.py +++ b/python/damask/_crystal.py @@ -27,6 +27,276 @@ lattice_symmetries: Dict[CrystalLattice, CrystalFamily] = { 'cF': 'cubic', } +orientation_relationships: Dict[str, Dict[CrystalLattice,np.ndarray]] = { + 'KS': { + 'cF': np.array([ + [[-1, 0, 1],[ 1, 1, 1]], + [[-1, 0, 1],[ 1, 1, 1]], + [[ 0, 1,-1],[ 1, 1, 1]], + [[ 0, 1,-1],[ 1, 1, 1]], + [[ 1,-1, 0],[ 1, 1, 1]], + [[ 1,-1, 0],[ 1, 1, 1]], + [[ 1, 0,-1],[ 1,-1, 1]], + [[ 1, 0,-1],[ 1,-1, 1]], + [[-1,-1, 0],[ 1,-1, 1]], + [[-1,-1, 0],[ 1,-1, 1]], + [[ 0, 1, 1],[ 1,-1, 1]], + [[ 0, 1, 1],[ 1,-1, 1]], + [[ 0,-1, 1],[-1, 1, 1]], + [[ 0,-1, 1],[-1, 1, 1]], + [[-1, 0,-1],[-1, 1, 1]], + [[-1, 0,-1],[-1, 1, 1]], + [[ 1, 1, 0],[-1, 1, 1]], + [[ 1, 1, 0],[-1, 1, 1]], + [[-1, 1, 0],[ 1, 1,-1]], + [[-1, 1, 0],[ 1, 1,-1]], + [[ 0,-1,-1],[ 1, 1,-1]], + [[ 0,-1,-1],[ 1, 1,-1]], + [[ 1, 0, 1],[ 1, 1,-1]], + [[ 1, 0, 1],[ 1, 1,-1]], + ],dtype=float), + 'cI': np.array([ + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + [[-1,-1, 1],[ 0, 1, 1]], + [[-1, 1,-1],[ 0, 1, 1]], + ],dtype=float), + }, + 'GT': { + 'cF': np.array([ + [[ -5,-12, 17],[ 1, 1, 1]], + [[ 17, -5,-12],[ 1, 1, 1]], + [[-12, 17, -5],[ 1, 1, 1]], + [[ 5, 12, 17],[ -1, -1, 1]], + [[-17, 5,-12],[ -1, -1, 1]], + [[ 12,-17, -5],[ -1, -1, 1]], + [[ -5, 12,-17],[ -1, 1, 1]], + [[ 17, 5, 12],[ -1, 1, 1]], + [[-12,-17, 5],[ -1, 1, 1]], + [[ 5,-12,-17],[ 1, -1, 1]], + [[-17, -5, 12],[ 1, -1, 1]], + [[ 12, 17, 5],[ 1, -1, 1]], + [[ -5, 17,-12],[ 1, 1, 1]], + [[-12, -5, 17],[ 1, 1, 1]], + [[ 17,-12, -5],[ 1, 1, 1]], + [[ 5,-17,-12],[ -1, -1, 1]], + [[ 12, 5, 17],[ -1, -1, 1]], + [[-17, 12, -5],[ -1, -1, 1]], + [[ -5,-17, 12],[ -1, 1, 1]], + [[-12, 5,-17],[ -1, 1, 1]], + [[ 17, 12, 5],[ -1, 1, 1]], + [[ 5, 17, 12],[ 1, -1, 1]], + [[ 12, -5,-17],[ 1, -1, 1]], + [[-17,-12, 5],[ 1, -1, 1]], + ],dtype=float), + 'cI': np.array([ + [[-17, -7, 17],[ 1, 0, 1]], + [[ 17,-17, -7],[ 1, 1, 0]], + [[ -7, 17,-17],[ 0, 1, 1]], + [[ 17, 7, 17],[ -1, 0, 1]], + [[-17, 17, -7],[ -1, -1, 0]], + [[ 7,-17,-17],[ 0, -1, 1]], + [[-17, 7,-17],[ -1, 0, 1]], + [[ 17, 17, 7],[ -1, 1, 0]], + [[ -7,-17, 17],[ 0, 1, 1]], + [[ 17, -7,-17],[ 1, 0, 1]], + [[-17,-17, 7],[ 1, -1, 0]], + [[ 7, 17, 17],[ 0, -1, 1]], + [[-17, 17, -7],[ 1, 1, 0]], + [[ -7,-17, 17],[ 0, 1, 1]], + [[ 17, -7,-17],[ 1, 0, 1]], + [[ 17,-17, -7],[ -1, -1, 0]], + [[ 7, 17, 17],[ 0, -1, 1]], + [[-17, 7,-17],[ -1, 0, 1]], + [[-17,-17, 7],[ -1, 1, 0]], + [[ -7, 17,-17],[ 0, 1, 1]], + [[ 17, 7, 17],[ -1, 0, 1]], + [[ 17, 17, 7],[ 1, -1, 0]], + [[ 7,-17,-17],[ 0, -1, 1]], + [[-17, -7, 17],[ 1, 0, 1]], + ],dtype=float), + }, + 'GT_prime': { + 'cF' : np.array([ + [[ 0, 1, -1],[ 7, 17, 17]], + [[ -1, 0, 1],[ 17, 7, 17]], + [[ 1, -1, 0],[ 17, 17, 7]], + [[ 0, -1, -1],[ -7,-17, 17]], + [[ 1, 0, 1],[-17, -7, 17]], + [[ 1, -1, 0],[-17,-17, 7]], + [[ 0, 1, -1],[ 7,-17,-17]], + [[ 1, 0, 1],[ 17, -7,-17]], + [[ -1, -1, 0],[ 17,-17, -7]], + [[ 0, -1, -1],[ -7, 17,-17]], + [[ -1, 0, 1],[-17, 7,-17]], + [[ -1, -1, 0],[-17, 17, -7]], + [[ 0, -1, 1],[ 7, 17, 17]], + [[ 1, 0, -1],[ 17, 7, 17]], + [[ -1, 1, 0],[ 17, 17, 7]], + [[ 0, 1, 1],[ -7,-17, 17]], + [[ -1, 0, -1],[-17, -7, 17]], + [[ -1, 1, 0],[-17,-17, 7]], + [[ 0, -1, 1],[ 7,-17,-17]], + [[ -1, 0, -1],[ 17, -7,-17]], + [[ 1, 1, 0],[ 17,-17, -7]], + [[ 0, 1, 1],[ -7, 17,-17]], + [[ 1, 0, -1],[-17, 7,-17]], + [[ 1, 1, 0],[-17, 17, -7]], + ],dtype=float), + 'cI' : np.array([ + [[ 1, 1, -1],[ 12, 5, 17]], + [[ -1, 1, 1],[ 17, 12, 5]], + [[ 1, -1, 1],[ 5, 17, 12]], + [[ -1, -1, -1],[-12, -5, 17]], + [[ 1, -1, 1],[-17,-12, 5]], + [[ 1, -1, -1],[ -5,-17, 12]], + [[ -1, 1, -1],[ 12, -5,-17]], + [[ 1, 1, 1],[ 17,-12, -5]], + [[ -1, -1, 1],[ 5,-17,-12]], + [[ 1, -1, -1],[-12, 5,-17]], + [[ -1, -1, 1],[-17, 12, -5]], + [[ -1, -1, -1],[ -5, 17,-12]], + [[ 1, -1, 1],[ 12, 17, 5]], + [[ 1, 1, -1],[ 5, 12, 17]], + [[ -1, 1, 1],[ 17, 5, 12]], + [[ -1, 1, 1],[-12,-17, 5]], + [[ -1, -1, -1],[ -5,-12, 17]], + [[ -1, 1, -1],[-17, -5, 12]], + [[ -1, -1, 1],[ 12,-17, -5]], + [[ -1, 1, -1],[ 5,-12,-17]], + [[ 1, 1, 1],[ 17, -5,-12]], + [[ 1, 1, 1],[-12, 17, -5]], + [[ 1, -1, -1],[ -5, 12,-17]], + [[ 1, 1, -1],[-17, 5,-12]], + ],dtype=float), + }, + 'NW': { + 'cF' : np.array([ + [[ 2, -1, -1],[ 1, 1, 1]], + [[ -1, 2, -1],[ 1, 1, 1]], + [[ -1, -1, 2],[ 1, 1, 1]], + [[ -2, -1, -1],[ -1, 1, 1]], + [[ 1, 2, -1],[ -1, 1, 1]], + [[ 1, -1, 2],[ -1, 1, 1]], + [[ 2, 1, -1],[ 1, -1, 1]], + [[ -1, -2, -1],[ 1, -1, 1]], + [[ -1, 1, 2],[ 1, -1, 1]], + [[ 2, -1, 1],[ -1, -1, 1]], + [[ -1, 2, 1],[ -1, -1, 1]], + [[ -1, -1, -2],[ -1, -1, 1]], + ],dtype=float), + 'cI' : np.array([ + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + [[ 0, -1, 1],[ 0, 1, 1]], + ],dtype=float), + }, + 'Pitsch': { + 'cF' : np.array([ + [[ 1, 0, 1],[ 0, 1, 0]], + [[ 1, 1, 0],[ 0, 0, 1]], + [[ 0, 1, 1],[ 1, 0, 0]], + [[ 0, 1, -1],[ 1, 0, 0]], + [[ -1, 0, 1],[ 0, 1, 0]], + [[ 1, -1, 0],[ 0, 0, 1]], + [[ 1, 0, -1],[ 0, 1, 0]], + [[ -1, 1, 0],[ 0, 0, 1]], + [[ 0, -1, 1],[ 1, 0, 0]], + [[ 0, 1, 1],[ 1, 0, 0]], + [[ 1, 0, 1],[ 0, 1, 0]], + [[ 1, 1, 0],[ 0, 0, 1]], + ],dtype=float), + 'cI' : np.array([ + [[ 1, -1, 1],[ -1, 0, 1]], + [[ 1, 1, -1],[ 1, -1, 0]], + [[ -1, 1, 1],[ 0, 1, -1]], + [[ -1, 1, -1],[ 0, -1, -1]], + [[ -1, -1, 1],[ -1, 0, -1]], + [[ 1, -1, -1],[ -1, -1, 0]], + [[ 1, -1, -1],[ -1, 0, -1]], + [[ -1, 1, -1],[ -1, -1, 0]], + [[ -1, -1, 1],[ 0, -1, -1]], + [[ -1, 1, 1],[ 0, -1, 1]], + [[ 1, -1, 1],[ 1, 0, -1]], + [[ 1, 1, -1],[ -1, 1, 0]], + ],dtype=float), + }, + 'Bain': { + 'cF' : np.array([ + [[ 0, 1, 0],[ 1, 0, 0]], + [[ 0, 0, 1],[ 0, 1, 0]], + [[ 1, 0, 0],[ 0, 0, 1]], + ],dtype=float), + 'cI' : np.array([ + [[ 0, 1, 1],[ 1, 0, 0]], + [[ 1, 0, 1],[ 0, 1, 0]], + [[ 1, 1, 0],[ 0, 0, 1]], + ],dtype=float), + }, + 'Burgers' : { + 'cI' : np.array([ + [[ -1, 1, 1],[ 1, 1, 0]], + [[ -1, 1, -1],[ 1, 1, 0]], + [[ 1, 1, 1],[ 1, -1, 0]], + [[ 1, 1, -1],[ 1, -1, 0]], + + [[ 1, 1, -1],[ 1, 0, 1]], + [[ -1, 1, 1],[ 1, 0, 1]], + [[ 1, 1, 1],[ -1, 0, 1]], + [[ 1, -1, 1],[ -1, 0, 1]], + + [[ -1, 1, -1],[ 0, 1, 1]], + [[ 1, 1, -1],[ 0, 1, 1]], + [[ -1, 1, 1],[ 0, -1, 1]], + [[ 1, 1, 1],[ 0, -1, 1]], + ],dtype=float), + 'hP' : np.array([ + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], + [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], + ],dtype=float), + }, + } class Crystal(): """ @@ -200,6 +470,15 @@ class Crystal(): return _immutable[self.family] + @property + def orientation_relationships(self): + """Return labels of orientation relationships.""" + labels = [] + for k,v in orientation_relationships.items(): + if list(v.items())[1][0] == self.lattice: labels.append(k) + return labels + + @property def standard_triangle(self) -> Union[Dict[str, np.ndarray], None]: """ @@ -768,280 +1047,10 @@ class Crystal(): https://doi.org/10.1016/j.actamat.2004.11.021 """ - _orientation_relationships: Dict[str, Dict[CrystalLattice,np.ndarray]] = { - 'KS': { - 'cF' : np.array([ - [[-1, 0, 1],[ 1, 1, 1]], - [[-1, 0, 1],[ 1, 1, 1]], - [[ 0, 1,-1],[ 1, 1, 1]], - [[ 0, 1,-1],[ 1, 1, 1]], - [[ 1,-1, 0],[ 1, 1, 1]], - [[ 1,-1, 0],[ 1, 1, 1]], - [[ 1, 0,-1],[ 1,-1, 1]], - [[ 1, 0,-1],[ 1,-1, 1]], - [[-1,-1, 0],[ 1,-1, 1]], - [[-1,-1, 0],[ 1,-1, 1]], - [[ 0, 1, 1],[ 1,-1, 1]], - [[ 0, 1, 1],[ 1,-1, 1]], - [[ 0,-1, 1],[-1, 1, 1]], - [[ 0,-1, 1],[-1, 1, 1]], - [[-1, 0,-1],[-1, 1, 1]], - [[-1, 0,-1],[-1, 1, 1]], - [[ 1, 1, 0],[-1, 1, 1]], - [[ 1, 1, 0],[-1, 1, 1]], - [[-1, 1, 0],[ 1, 1,-1]], - [[-1, 1, 0],[ 1, 1,-1]], - [[ 0,-1,-1],[ 1, 1,-1]], - [[ 0,-1,-1],[ 1, 1,-1]], - [[ 1, 0, 1],[ 1, 1,-1]], - [[ 1, 0, 1],[ 1, 1,-1]], - ],dtype=float), - 'cI' : np.array([ - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - [[-1,-1, 1],[ 0, 1, 1]], - [[-1, 1,-1],[ 0, 1, 1]], - ],dtype=float), - }, - 'GT': { - 'cF' : np.array([ - [[ -5,-12, 17],[ 1, 1, 1]], - [[ 17, -5,-12],[ 1, 1, 1]], - [[-12, 17, -5],[ 1, 1, 1]], - [[ 5, 12, 17],[ -1, -1, 1]], - [[-17, 5,-12],[ -1, -1, 1]], - [[ 12,-17, -5],[ -1, -1, 1]], - [[ -5, 12,-17],[ -1, 1, 1]], - [[ 17, 5, 12],[ -1, 1, 1]], - [[-12,-17, 5],[ -1, 1, 1]], - [[ 5,-12,-17],[ 1, -1, 1]], - [[-17, -5, 12],[ 1, -1, 1]], - [[ 12, 17, 5],[ 1, -1, 1]], - [[ -5, 17,-12],[ 1, 1, 1]], - [[-12, -5, 17],[ 1, 1, 1]], - [[ 17,-12, -5],[ 1, 1, 1]], - [[ 5,-17,-12],[ -1, -1, 1]], - [[ 12, 5, 17],[ -1, -1, 1]], - [[-17, 12, -5],[ -1, -1, 1]], - [[ -5,-17, 12],[ -1, 1, 1]], - [[-12, 5,-17],[ -1, 1, 1]], - [[ 17, 12, 5],[ -1, 1, 1]], - [[ 5, 17, 12],[ 1, -1, 1]], - [[ 12, -5,-17],[ 1, -1, 1]], - [[-17,-12, 5],[ 1, -1, 1]], - ],dtype=float), - 'cI' : np.array([ - [[-17, -7, 17],[ 1, 0, 1]], - [[ 17,-17, -7],[ 1, 1, 0]], - [[ -7, 17,-17],[ 0, 1, 1]], - [[ 17, 7, 17],[ -1, 0, 1]], - [[-17, 17, -7],[ -1, -1, 0]], - [[ 7,-17,-17],[ 0, -1, 1]], - [[-17, 7,-17],[ -1, 0, 1]], - [[ 17, 17, 7],[ -1, 1, 0]], - [[ -7,-17, 17],[ 0, 1, 1]], - [[ 17, -7,-17],[ 1, 0, 1]], - [[-17,-17, 7],[ 1, -1, 0]], - [[ 7, 17, 17],[ 0, -1, 1]], - [[-17, 17, -7],[ 1, 1, 0]], - [[ -7,-17, 17],[ 0, 1, 1]], - [[ 17, -7,-17],[ 1, 0, 1]], - [[ 17,-17, -7],[ -1, -1, 0]], - [[ 7, 17, 17],[ 0, -1, 1]], - [[-17, 7,-17],[ -1, 0, 1]], - [[-17,-17, 7],[ -1, 1, 0]], - [[ -7, 17,-17],[ 0, 1, 1]], - [[ 17, 7, 17],[ -1, 0, 1]], - [[ 17, 17, 7],[ 1, -1, 0]], - [[ 7,-17,-17],[ 0, -1, 1]], - [[-17, -7, 17],[ 1, 0, 1]], - ],dtype=float), - }, - 'GT_prime': { - 'cF' : np.array([ - [[ 0, 1, -1],[ 7, 17, 17]], - [[ -1, 0, 1],[ 17, 7, 17]], - [[ 1, -1, 0],[ 17, 17, 7]], - [[ 0, -1, -1],[ -7,-17, 17]], - [[ 1, 0, 1],[-17, -7, 17]], - [[ 1, -1, 0],[-17,-17, 7]], - [[ 0, 1, -1],[ 7,-17,-17]], - [[ 1, 0, 1],[ 17, -7,-17]], - [[ -1, -1, 0],[ 17,-17, -7]], - [[ 0, -1, -1],[ -7, 17,-17]], - [[ -1, 0, 1],[-17, 7,-17]], - [[ -1, -1, 0],[-17, 17, -7]], - [[ 0, -1, 1],[ 7, 17, 17]], - [[ 1, 0, -1],[ 17, 7, 17]], - [[ -1, 1, 0],[ 17, 17, 7]], - [[ 0, 1, 1],[ -7,-17, 17]], - [[ -1, 0, -1],[-17, -7, 17]], - [[ -1, 1, 0],[-17,-17, 7]], - [[ 0, -1, 1],[ 7,-17,-17]], - [[ -1, 0, -1],[ 17, -7,-17]], - [[ 1, 1, 0],[ 17,-17, -7]], - [[ 0, 1, 1],[ -7, 17,-17]], - [[ 1, 0, -1],[-17, 7,-17]], - [[ 1, 1, 0],[-17, 17, -7]], - ],dtype=float), - 'cI' : np.array([ - [[ 1, 1, -1],[ 12, 5, 17]], - [[ -1, 1, 1],[ 17, 12, 5]], - [[ 1, -1, 1],[ 5, 17, 12]], - [[ -1, -1, -1],[-12, -5, 17]], - [[ 1, -1, 1],[-17,-12, 5]], - [[ 1, -1, -1],[ -5,-17, 12]], - [[ -1, 1, -1],[ 12, -5,-17]], - [[ 1, 1, 1],[ 17,-12, -5]], - [[ -1, -1, 1],[ 5,-17,-12]], - [[ 1, -1, -1],[-12, 5,-17]], - [[ -1, -1, 1],[-17, 12, -5]], - [[ -1, -1, -1],[ -5, 17,-12]], - [[ 1, -1, 1],[ 12, 17, 5]], - [[ 1, 1, -1],[ 5, 12, 17]], - [[ -1, 1, 1],[ 17, 5, 12]], - [[ -1, 1, 1],[-12,-17, 5]], - [[ -1, -1, -1],[ -5,-12, 17]], - [[ -1, 1, -1],[-17, -5, 12]], - [[ -1, -1, 1],[ 12,-17, -5]], - [[ -1, 1, -1],[ 5,-12,-17]], - [[ 1, 1, 1],[ 17, -5,-12]], - [[ 1, 1, 1],[-12, 17, -5]], - [[ 1, -1, -1],[ -5, 12,-17]], - [[ 1, 1, -1],[-17, 5,-12]], - ],dtype=float), - }, - 'NW': { - 'cF' : np.array([ - [[ 2, -1, -1],[ 1, 1, 1]], - [[ -1, 2, -1],[ 1, 1, 1]], - [[ -1, -1, 2],[ 1, 1, 1]], - [[ -2, -1, -1],[ -1, 1, 1]], - [[ 1, 2, -1],[ -1, 1, 1]], - [[ 1, -1, 2],[ -1, 1, 1]], - [[ 2, 1, -1],[ 1, -1, 1]], - [[ -1, -2, -1],[ 1, -1, 1]], - [[ -1, 1, 2],[ 1, -1, 1]], - [[ 2, -1, 1],[ -1, -1, 1]], - [[ -1, 2, 1],[ -1, -1, 1]], - [[ -1, -1, -2],[ -1, -1, 1]], - ],dtype=float), - 'cI' : np.array([ - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - [[ 0, -1, 1],[ 0, 1, 1]], - ],dtype=float), - }, - 'Pitsch': { - 'cF' : np.array([ - [[ 1, 0, 1],[ 0, 1, 0]], - [[ 1, 1, 0],[ 0, 0, 1]], - [[ 0, 1, 1],[ 1, 0, 0]], - [[ 0, 1, -1],[ 1, 0, 0]], - [[ -1, 0, 1],[ 0, 1, 0]], - [[ 1, -1, 0],[ 0, 0, 1]], - [[ 1, 0, -1],[ 0, 1, 0]], - [[ -1, 1, 0],[ 0, 0, 1]], - [[ 0, -1, 1],[ 1, 0, 0]], - [[ 0, 1, 1],[ 1, 0, 0]], - [[ 1, 0, 1],[ 0, 1, 0]], - [[ 1, 1, 0],[ 0, 0, 1]], - ],dtype=float), - 'cI' : np.array([ - [[ 1, -1, 1],[ -1, 0, 1]], - [[ 1, 1, -1],[ 1, -1, 0]], - [[ -1, 1, 1],[ 0, 1, -1]], - [[ -1, 1, -1],[ 0, -1, -1]], - [[ -1, -1, 1],[ -1, 0, -1]], - [[ 1, -1, -1],[ -1, -1, 0]], - [[ 1, -1, -1],[ -1, 0, -1]], - [[ -1, 1, -1],[ -1, -1, 0]], - [[ -1, -1, 1],[ 0, -1, -1]], - [[ -1, 1, 1],[ 0, -1, 1]], - [[ 1, -1, 1],[ 1, 0, -1]], - [[ 1, 1, -1],[ -1, 1, 0]], - ],dtype=float), - }, - 'Bain': { - 'cF' : np.array([ - [[ 0, 1, 0],[ 1, 0, 0]], - [[ 0, 0, 1],[ 0, 1, 0]], - [[ 1, 0, 0],[ 0, 0, 1]], - ],dtype=float), - 'cI' : np.array([ - [[ 0, 1, 1],[ 1, 0, 0]], - [[ 1, 0, 1],[ 0, 1, 0]], - [[ 1, 1, 0],[ 0, 0, 1]], - ],dtype=float), - }, - 'Burgers' : { - 'cI' : np.array([ - [[ -1, 1, 1],[ 1, 1, 0]], - [[ -1, 1, -1],[ 1, 1, 0]], - [[ 1, 1, 1],[ 1, -1, 0]], - [[ 1, 1, -1],[ 1, -1, 0]], - - [[ 1, 1, -1],[ 1, 0, 1]], - [[ -1, 1, 1],[ 1, 0, 1]], - [[ 1, 1, 1],[ -1, 0, 1]], - [[ 1, -1, 1],[ -1, 0, 1]], - - [[ -1, 1, -1],[ 0, 1, 1]], - [[ 1, 1, -1],[ 0, 1, 1]], - [[ -1, 1, 1],[ 0, -1, 1]], - [[ 1, 1, 1],[ 0, -1, 1]], - ],dtype=float), - 'hP' : np.array([ - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - [[ -1, 2, -1, 0],[ 0, 0, 0, 1]], - [[ -1, -1, 2, 0],[ 0, 0, 0, 1]], - ],dtype=float), - }, - } - orientation_relationships = {k:v for k,v in _orientation_relationships.items() if self.lattice in v} - if model not in orientation_relationships: + my_relationships = {k:v for k,v in orientation_relationships.items() if self.lattice in v} + if model not in my_relationships: raise KeyError(f'unknown orientation relationship "{model}"') - r = orientation_relationships[model] + r = my_relationships[model] sl = self.lattice ol = (set(r)-{sl}).pop() diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index c6427c85c..703e2411f 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -823,7 +823,7 @@ class Orientation(Rotation,Crystal): Parameters ---------- - N_slip|N_twin : '*' or iterable of int + N_slip|N_twin : '*' or sequence of int Number of deformation systems per family of the deformation system. Use '*' to select all. @@ -871,8 +871,34 @@ class Orientation(Rotation,Crystal): """ Orientations derived from the given relationship. - One dimension (length according to number of related orientations) - is added to the left of the Rotation array. + Parameters + ---------- + model : str + Model for orientation relationship. + Must be out of self.orientation_relationships. + + Returns + ------- + Orientations with crystal structure according to + the selected model for the orienation relationship. + + Examples + -------- + Rotations of the Bain orientation relationship (cI -> cF) + of a crystal in "Cube" orientation. + + >>> import numpy as np + >>> import damask + >>> np.set_printoptions(3,suppress=True,floatmode='fixed') + >>> damask.Orientation(lattice='cI').related('Bain') + Crystal family: cubic + Bravais lattice: cF + a=1 m, b=1 m, c=1 m + α=90°, β=90°, γ=90° + Quaternions of shape (3,) + [[0.924 0.383 0.000 0.000] + [0.924 0.000 0.383 0.000] + [0.924 0.000 0.000 0.383]] """ lattice,o = self.relation_operations(model) diff --git a/python/tests/test_Crystal.py b/python/tests/test_Crystal.py index 235ed554a..bd4a7235b 100644 --- a/python/tests/test_Crystal.py +++ b/python/tests/test_Crystal.py @@ -102,3 +102,11 @@ class TestCrystal: assert [len(s) for s in crystal.kinematics('twin')['direction']] == length assert [len(s) for s in crystal.kinematics('twin')['plane']] == length + @pytest.mark.parametrize('crystal', [Crystal(lattice='cF'), + Crystal(lattice='cI'), + Crystal(lattice='hP'), + Crystal(lattice='tI',c=1.2)]) + def test_related(self,crystal): + for r in crystal.orientation_relationships: + crystal.relation_operations(r) + From f78c422af9cc49eb15666d9300f524625502c956 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 27 Feb 2022 03:12:30 +0100 Subject: [PATCH 07/28] easier to understand the condition is there to avoid problems if the dataset is not created because it is empty (e.g. requesting xi_sl for Nslip=[0]) --- src/results.f90 | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/results.f90 b/src/results.f90 index 11728e595..9fccff03e 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -388,14 +388,11 @@ subroutine results_writeVectorDataset_real(dataset,group,label,description,SIuni integer(HID_T) :: groupHandle - if (present(systems)) then - if (size(systems)*size(dataset,2) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar) - end if - groupHandle = results_openGroup(group) call HDF5_write(dataset,groupHandle,label) call executionStamp(group//'/'//label,description,SIunit) - if (present(systems)) call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) + if (present(systems) .and. HDF5_objectExists(groupHandle,label)) & + call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) call HDF5_closeGroup(groupHandle) end subroutine results_writeVectorDataset_real @@ -454,14 +451,11 @@ subroutine results_writeVectorDataset_int(dataset,group,label,description,SIunit integer(HID_T) :: groupHandle - if (present(systems)) then - if (size(systems) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar) - end if - groupHandle = results_openGroup(group) call HDF5_write(dataset,groupHandle,label) call executionStamp(group//'/'//label,description,SIunit) - if (present(systems)) call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) + if (present(systems) .and. HDF5_objectExists(groupHandle,label)) & + call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) call HDF5_closeGroup(groupHandle) end subroutine results_writeVectorDataset_int From 53fe11484dc8481fdb9735a3fdad55c0452b661d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 27 Feb 2022 15:20:28 +0100 Subject: [PATCH 08/28] not used --- cmake/Compiler-GNU.cmake | 3 +-- src/grid/DAMASK_grid.f90 | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/cmake/Compiler-GNU.cmake b/cmake/Compiler-GNU.cmake index 164f115a0..6eedffc21 100644 --- a/cmake/Compiler-GNU.cmake +++ b/cmake/Compiler-GNU.cmake @@ -102,12 +102,11 @@ set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure") -set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter") +set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunused-parameter") set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffpe-summary=all") # print summary of floating point exeptions (invalid,zero,overflow,underflow,inexact,denormal) # Additional options -# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?) # -Wimplicit-interface: no interfaces for lapack/MPI routines # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions diff --git a/src/grid/DAMASK_grid.f90 b/src/grid/DAMASK_grid.f90 index 918f477b1..8c4ae5fca 100644 --- a/src/grid/DAMASK_grid.f90 +++ b/src/grid/DAMASK_grid.f90 @@ -56,9 +56,6 @@ program DAMASK_grid !-------------------------------------------------------------------------------------------------- ! loop variables, convergence etc. - real(pReal), dimension(3,3), parameter :: & - ones = 1.0_pReal, & - zeros = 0.0_pReal integer, parameter :: & subStepFactor = 2 !< for each substep, divide the last time increment by 2.0 real(pReal) :: & From f9e04bc4cbe3054c54cd2ed08addba8a2f0ffeff Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 27 Feb 2022 16:16:09 +0100 Subject: [PATCH 09/28] unifying interface same same for same functionality, allow user to specify single integer for convenience --- python/damask/_grid.py | 67 +++++++++++++++++++++---------------- python/damask/_typehints.py | 3 +- python/damask/seeds.py | 12 ++++--- python/damask/util.py | 10 ++++-- python/tests/test_Grid.py | 12 +++---- 5 files changed, 61 insertions(+), 43 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 094e8a529..5ef592f45 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -4,7 +4,7 @@ import warnings import multiprocessing as mp from functools import partial import typing -from typing import Union, Optional, TextIO, List, Sequence +from typing import Union, Optional, TextIO, List, Sequence, Collection from pathlib import Path import numpy as np @@ -17,7 +17,7 @@ from . import util from . import grid_filters from . import Rotation from . import Table -from ._typehints import FloatSequence, IntSequence +from ._typehints import FloatSequence, IntSequence, IntCollection class Grid: """ @@ -907,7 +907,8 @@ class Grid: def clean(self, stencil: int = 3, - mutable: IntSequence = None, + selection: IntCollection = None, + invert_selection: bool = False, periodic: bool = True) -> 'Grid': """ Smooth grid by selecting most frequent material ID within given stencil at each location. @@ -916,8 +917,10 @@ class Grid: ---------- stencil : int, optional Size of smoothing stencil. Defaults to 3. - mutable : sequence of int, optional - Material ID that can be altered. Defaults to all. + 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. @@ -927,21 +930,23 @@ class Grid: Updated grid-based geometry. """ - def mostFrequent(arr: np.ndarray, mutable = None): + def mostFrequent(arr: np.ndarray, selection: List, invert: bool): me = arr[arr.size//2] - if selection is None or me in mutable: - unique, inverse = np.unique(arr, return_inverse=True) + if len(selection) == 0 or np.isin(me,selection,invert=invert): + unique, inverse = np.unique(arr,return_inverse=True) return unique[np.argmax(np.bincount(inverse))] else: return me - return Grid(material = ndimage.filters.generic_filter( - self.material, - mostFrequent, - size=(stencil if mutable is None else stencil//2*2+1,)*3, - mode=('wrap' if periodic else 'nearest'), - extra_keywords=dict(mutable=mutable), - ).astype(self.material.dtype), + extra_keywords = dict(selection=util.tbd(selection),invert=invert_selection) + material = ndimage.filters.generic_filter( + self.material, + mostFrequent, + size=(stencil if selection is None else stencil//2*2+1,)*3, + mode=('wrap' if periodic else 'nearest'), + extra_keywords=extra_keywords, + ).astype(self.material.dtype) + return Grid(material = material, size = self.size, origin = self.origin, comments = self.comments+[util.execution_stamp('Grid','clean')], @@ -1061,16 +1066,16 @@ class Grid: def substitute(self, - from_material: IntSequence, - to_material: IntSequence) -> 'Grid': + from_material: Union[int,IntSequence], + to_material: Union[int,IntSequence]) -> 'Grid': """ Substitute material indices. Parameters ---------- - from_material : sequence of int + from_material : int or sequence of int Material indices to be substituted. - to_material : sequence of int + to_material : int or sequence of int New material indices. Returns @@ -1080,7 +1085,8 @@ class Grid: """ material = self.material.copy() - for f,t in zip(from_material,to_material): # ToDo Python 3.10 has strict mode for zip + 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, @@ -1115,14 +1121,14 @@ class Grid: def vicinity_offset(self, vicinity: int = 1, offset: int = None, - trigger: IntSequence = [], + selection: IntCollection = None, + invert_selection: bool = False, periodic: bool = True) -> 'Grid': """ Offset material ID of points in the vicinity of xxx. Different from themselves (or listed as triggers) within a given (cubic) vicinity, i.e. within the region close to a grain/phase boundary. - ToDo: use include/exclude as in seeds.from_grid Parameters ---------- @@ -1132,9 +1138,10 @@ class Grid: offset : int, optional Offset (positive or negative) to tag material indices, defaults to material.max()+1. - trigger : sequence of int, optional - List of material indices that trigger a change. - Defaults to [], meaning that any different neighbor triggers a change. + selection : int or collection of int, optional + Material IDs to that triger xxx. + 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. @@ -1144,17 +1151,19 @@ class Grid: Updated grid-based geometry. """ - def tainted_neighborhood(stencil: np.ndarray, trigger): + def tainted_neighborhood(stencil: np.ndarray, selection): me = stencil[stencil.shape[0]//2] - return np.any(stencil != me if len(trigger) == 0 else - np.in1d(stencil,np.array(list(set(trigger) - {me})))) + return np.any(stencil != me if len(selection) == 0 else + np.in1d(stencil,np.array(list(set(selection) - {me})))) offset_ = np.nanmax(self.material)+1 if offset is None else offset + selection_ = util.tbd(selection) if not invert_selection else \ + list(set(self.material) - set(util.tbd(selection))) mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, size=1+2*vicinity, mode='wrap' if periodic else 'nearest', - extra_keywords={'trigger':trigger}) + extra_keywords=dict(selection=selection_)) return Grid(material = np.where(mask, self.material + offset_,self.material), size = self.size, diff --git a/python/damask/_typehints.py b/python/damask/_typehints.py index 5fcf39a41..f836e1f59 100644 --- a/python/damask/_typehints.py +++ b/python/damask/_typehints.py @@ -1,6 +1,6 @@ """Functionality for typehints.""" -from typing import Sequence, Union, Literal, TextIO +from typing import Sequence, Union, Literal, TextIO, Collection from pathlib import Path import numpy as np @@ -8,6 +8,7 @@ import numpy as np FloatSequence = Union[np.ndarray,Sequence[float]] IntSequence = Union[np.ndarray,Sequence[int]] +IntCollection = Union[np.ndarray,Collection[int]] FileHandle = Union[TextIO, str, Path] CrystalFamily = Union[None,Literal['triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 'hexagonal', 'cubic']] CrystalLattice = Union[None,Literal['aP', 'mP', 'mS', 'oP', 'oS', 'oI', 'oF', 'tP', 'tI', 'hP', 'cP', 'cI', 'cF']] diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 620395f3c..d5e1ec7ed 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -6,7 +6,8 @@ from typing import Tuple as _Tuple from scipy import spatial as _spatial import numpy as _np -from ._typehints import FloatSequence as _FloatSequence, IntSequence as _IntSequence, NumpyRngSeed as _NumpyRngSeed +from ._typehints import FloatSequence as _FloatSequence, IntSequence as _IntSequence, \ + NumpyRngSeed as _NumpyRngSeed, IntCollection as _IntCollection from . import util as _util from . import grid_filters as _grid_filters @@ -106,7 +107,7 @@ def from_Poisson_disc(size: _FloatSequence, def from_grid(grid, - selection: _IntSequence = None, + selection: _IntCollection = None, invert_selection: bool = False, average: bool = False, periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]: @@ -117,7 +118,7 @@ def from_grid(grid, ---------- grid : damask.Grid Grid from which the material IDs are used as seeds. - selection : sequence of int, optional + 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. @@ -133,8 +134,9 @@ def from_grid(grid, """ material = grid.material.reshape((-1,1),order='F') - mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \ - _np.isin(material,selection,invert=invert_selection).flatten() + selection_ = _util.tbd(selection) + mask = _np.full(grid.cells.prod(),True,dtype=bool) if len(selection_) == 0 else \ + _np.isin(material,selection_,invert=invert_selection).flatten() coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') if not average: diff --git a/python/damask/util.py b/python/damask/util.py index 7ecb5ba54..55d1eb24c 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -9,7 +9,7 @@ import re import fractions from collections import abc from functools import reduce -from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal +from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal, Collection from pathlib import Path import numpy as np @@ -720,7 +720,13 @@ def dict_flatten(d: Dict) -> Dict: return new - +def tbd(arg) -> List: + if arg is None: + return [] + elif isinstance(arg,(np.ndarray,Collection)): + return list(arg) + else: + return [arg] #################################################################################################### # Classes diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 6dd94f4bb..cfeb7be4a 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -155,7 +155,7 @@ class TestGrid: @pytest.mark.parametrize('selection',[None,[1],[1,2,3]]) @pytest.mark.parametrize('periodic',[True,False]) def test_clean(self,default,update,ref_path,stencil,selection,periodic): - current = default.clean(stencil,selection,periodic) + current = default.clean(stencil,selection,periodic=periodic) reference = ref_path/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}.vti' if update and stencil > 1: current.save(reference) @@ -296,8 +296,8 @@ class TestGrid: assert grid_equal(G_1,G_2) - @pytest.mark.parametrize('trigger',[[1],[]]) - def test_vicinity_offset(self,trigger): + @pytest.mark.parametrize('selection',[[1],[]]) + def test_vicinity_offset(self,selection): offset = np.random.randint(2,4) vicinity = np.random.randint(2,4) @@ -309,17 +309,17 @@ class TestGrid: for i in [0,1,2]: m2[(np.roll(m,+vicinity,i)-m)!=0] += offset m2[(np.roll(m,-vicinity,i)-m)!=0] += offset - if len(trigger) > 0: + if len(selection) > 0: m2[m==1] = 1 - grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,trigger=trigger) + grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,selection=selection) assert np.all(m2==grid.material) @pytest.mark.parametrize('periodic',[True,False]) def test_vicinity_offset_invariant(self,default,periodic): - offset = default.vicinity_offset(trigger=[default.material.max()+1, + offset = default.vicinity_offset(selection=[default.material.max()+1, default.material.min()-1]) assert np.all(offset.material==default.material) From ad8758b340e10af33170bdcc5965c7ca5379e6c0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 28 Feb 2022 16:15:07 +0100 Subject: [PATCH 10/28] better don't have unlimited time for planning as default --- src/grid/spectral_utilities.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 2a675c9b6..525f68d7e 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -256,7 +256,7 @@ subroutine spectral_utilities_init !-------------------------------------------------------------------------------------------------- ! general initialization of FFTW (see manual on fftw.org for more details) if (pReal /= C_DOUBLE .or. kind(1) /= C_INT) error stop 'C and Fortran datatypes do not match' - call fftw_set_timelimit(num_grid%get_asFloat('fftw_timelimit',defaultVal=-1.0_pReal)) + call fftw_set_timelimit(num_grid%get_asFloat('fftw_timelimit',defaultVal=300.0_pReal)) print'(/,1x,a)', 'FFTW initialized'; flush(IO_STDOUT) From 2cf904fe49a7b1de6a2e63fa031b674f34c5253a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 28 Feb 2022 18:54:46 +0100 Subject: [PATCH 11/28] output to logfile helfulf for debug, especially with MPI --- src/DAMASK_interface.f90 | 3 +-- src/parallelization.f90 | 36 ++++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/DAMASK_interface.f90 b/src/DAMASK_interface.f90 index f5233f2f0..e958c8a29 100644 --- a/src/DAMASK_interface.f90 +++ b/src/DAMASK_interface.f90 @@ -70,9 +70,8 @@ subroutine DAMASK_interface_init external :: & quit - print'(/,1x,a)', '<<<+- DAMASK_interface init -+>>>' - if(worldrank == 0) open(OUTPUT_UNIT, encoding='UTF-8') ! for special characters in output + print'(/,1x,a)', '<<<+- DAMASK_interface init -+>>>' ! http://patorjk.com/software/taag/#p=display&f=Lean&t=DAMASK%203 #ifdef DEBUG diff --git a/src/parallelization.f90 b/src/parallelization.f90 index 28ad70d94..cea4a8d94 100644 --- a/src/parallelization.f90 +++ b/src/parallelization.f90 @@ -86,17 +86,27 @@ subroutine parallelization_init if (err_MPI /= 0_MPI_INTEGER_KIND) & error stop 'Could not determine worldrank' - if (worldrank == 0) then - print'(/,1x,a)', '<<<+- parallelization init -+>>>' - - call MPI_Get_library_version(MPI_library_version,devNull,err_MPI) - print'(/,1x,a)', trim(MPI_library_version) - call MPI_Get_version(version,subversion,err_MPI) - print'(1x,a,i0,a,i0)', 'MPI standard: ',version,'.',subversion -#ifdef _OPENMP - print'(1x,a,i0)', 'OpenMP version: ',openmp_version +#ifdef LOGFILE + write(rank_str,'(i4.4)') worldrank + open(OUTPUT_UNIT,file='log.'//rank_str,status='replace',encoding='UTF-8') +#else + if (worldrank /= 0) then + close(OUTPUT_UNIT) ! disable output + open(OUTPUT_UNIT,file='/dev/null',status='replace') ! close() alone will leave some temp files in cwd + else + open(OUTPUT_UNIT,encoding='UTF-8') ! for special characters in output + endif +#endif + + print'(/,1x,a)', '<<<+- parallelization init -+>>>' + + call MPI_Get_library_version(MPI_library_version,devNull,err_MPI) + print'(/,1x,a)', trim(MPI_library_version) + call MPI_Get_version(version,subversion,err_MPI) + print'(1x,a,i0,a,i0)', 'MPI standard: ',version,'.',subversion +#ifdef _OPENMP + print'(1x,a,i0)', 'OpenMP version: ',openmp_version #endif - end if call MPI_Comm_size(MPI_COMM_WORLD,worldsize,err_MPI) if (err_MPI /= 0_MPI_INTEGER_KIND) & @@ -121,12 +131,6 @@ subroutine parallelization_init if (typeSize*8_MPI_INTEGER_KIND /= int(storage_size(0.0_pReal),MPI_INTEGER_KIND)) & error stop 'Mismatch between MPI_DOUBLE and DAMASK pReal' - if (worldrank /= 0) then - close(OUTPUT_UNIT) ! disable output - write(rank_str,'(i4.4)') worldrank ! use for MPI debug filenames - open(OUTPUT_UNIT,file='/dev/null',status='replace') ! close() alone will leave some temp files in cwd - endif - !$ call get_environment_variable(name='OMP_NUM_THREADS',value=NumThreadsString,STATUS=got_env) !$ if(got_env /= 0) then !$ print'(1x,a)', 'Could not get $OMP_NUM_THREADS, using default' From 0604d94e3144600e380c9ecbd53f2d8ad16970d3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 28 Feb 2022 19:02:46 +0100 Subject: [PATCH 12/28] also store stdout --- src/parallelization.f90 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/parallelization.f90 b/src/parallelization.f90 index cea4a8d94..8cc6d3abb 100644 --- a/src/parallelization.f90 +++ b/src/parallelization.f90 @@ -4,7 +4,8 @@ !-------------------------------------------------------------------------------------------------- module parallelization use, intrinsic :: ISO_fortran_env, only: & - OUTPUT_UNIT + OUTPUT_UNIT, & + ERROR_UNIT #ifdef PETSC #include @@ -88,7 +89,8 @@ subroutine parallelization_init #ifdef LOGFILE write(rank_str,'(i4.4)') worldrank - open(OUTPUT_UNIT,file='log.'//rank_str,status='replace',encoding='UTF-8') + open(OUTPUT_UNIT,file='out.'//rank_str,status='replace',encoding='UTF-8') + open(ERROR_UNIT,file='error.'//rank_str,status='replace',encoding='UTF-8') #else if (worldrank /= 0) then close(OUTPUT_UNIT) ! disable output From dd68aad83b84eb4b04de44691464f59ad3e908f5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 28 Feb 2022 19:03:56 +0100 Subject: [PATCH 13/28] not used --- python/damask/_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 5ef592f45..d4101e9ab 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -4,7 +4,7 @@ import warnings import multiprocessing as mp from functools import partial import typing -from typing import Union, Optional, TextIO, List, Sequence, Collection +from typing import Union, Optional, TextIO, List, Sequence from pathlib import Path import numpy as np From 161e4b6815c5bf8b8c25d92a30c07584f350af33 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 4 Mar 2022 10:39:02 +0100 Subject: [PATCH 14/28] testing new functionality --- python/damask/_grid.py | 2 +- python/damask/util.py | 2 +- python/tests/test_Grid.py | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 88ab3bb45..df60b64a8 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -1170,7 +1170,7 @@ class Grid: offset_ = np.nanmax(self.material)+1 if offset is None else offset selection_ = util.tbd(selection) if not invert_selection else \ - list(set(self.material) - set(util.tbd(selection))) + list(set(self.material.flatten()) - set(util.tbd(selection))) mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, size=1+2*vicinity, diff --git a/python/damask/util.py b/python/damask/util.py index 74095e6e1..f19b6a54a 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -9,7 +9,7 @@ import re import fractions from collections import abc from functools import reduce -from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any +from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection from pathlib import Path import numpy as np diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 81d9e82a3..6be2bc18a 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -25,6 +25,14 @@ def default(): np.arange(1,41))).reshape(8,5,4,order='F') return Grid(x,[8e-6,5e-6,4e-6]) +@pytest.fixture +def random(): + """Simple geometry.""" + size = (1+np.random.rand(3))*1e-5 + cells = np.random.randint(10,20,3) + s = seeds.from_random(size,np.random.randint(5,25),cells) + return Grid.from_Voronoi_tessellation(cells,size,s) + @pytest.fixture def ref_path(ref_path_base): """Directory containing reference results.""" @@ -158,7 +166,7 @@ class TestGrid: @pytest.mark.parametrize('stencil',[1,2,3,4]) @pytest.mark.parametrize('selection',[None,[1],[1,2,3]]) @pytest.mark.parametrize('periodic',[True,False]) - def test_clean(self,default,update,ref_path,stencil,selection,periodic): + def test_clean_reference(self,default,update,ref_path,stencil,selection,periodic): current = default.clean(stencil,selection,periodic=periodic) reference = ref_path/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}.vti' if update and stencil > 1: @@ -167,6 +175,12 @@ class TestGrid: 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]) + def test_clean_invert(self,random,selection,invert): + selection_inverse = set(random.material.flatten()) - set(selection) + assert random.clean(selection=selection,invert_selection=invert) == \ + random.clean(selection=selection_inverse,invert_selection=not invert) @pytest.mark.parametrize('cells',[ (10,11,10), @@ -209,6 +223,11 @@ class TestGrid: 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) + t = np.random.randint(30) + assert random.substitute(f,t) == random.substitute([f],[t]) + def test_substitute_invariant(self,default): f = np.unique(default.material.flatten())[:np.random.randint(1,default.material.max())] t = np.random.permutation(f) @@ -300,7 +319,7 @@ class TestGrid: assert grid_equal(G_1,G_2) - @pytest.mark.parametrize('selection',[[1],[]]) + @pytest.mark.parametrize('selection',[1,[]]) def test_vicinity_offset(self,selection): offset = np.random.randint(2,4) vicinity = np.random.randint(2,4) @@ -313,18 +332,25 @@ class TestGrid: for i in [0,1,2]: m2[(np.roll(m,+vicinity,i)-m)!=0] += offset m2[(np.roll(m,-vicinity,i)-m)!=0] += offset - if len(selection) > 0: + if selection == 1: m2[m==1] = 1 grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,selection=selection) assert np.all(m2==grid.material) + @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): + selection_inverse = set(random.material.flatten()) - set(selection) + assert random.vicinity_offset(selection=selection,invert_selection=invert) == \ + random.vicinity_offset(selection=selection_inverse,invert_selection=not invert) + @pytest.mark.parametrize('periodic',[True,False]) def test_vicinity_offset_invariant(self,default,periodic): offset = default.vicinity_offset(selection=[default.material.max()+1, - default.material.min()-1]) + default.material.min()-1]) assert np.all(offset.material==default.material) From bafc45d259fce7025cecedb509b32920c9a30b20 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 4 Mar 2022 17:17:03 +0100 Subject: [PATCH 15/28] guide users --- python/damask/_grid.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index df60b64a8..0eb376e11 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -282,6 +282,20 @@ class Grid: loaded : damask.Grid Grid-based geometry from file. + Examples + -------- + Read a periodic polycrystal generated with Neper. + + >>> import damask + >>> N_grains = 20 + >>> 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.Grid.load_Neper(f'n{N_grains}-id1.vtk') + cells: 32 × 32 × 32 + size: 1.0 × 1.0 × 1.0 m³ + origin: 0.0 0.0 0.0 m + # materials: 20 + """ v = VTK.load(fname,'ImageData') cells = np.array(v.vtk_data.GetDimensions())-1 @@ -952,10 +966,10 @@ class Grid: extra_keywords = dict(selection=util.tbd(selection),invert=invert_selection) material = ndimage.filters.generic_filter( - self.material, - mostFrequent, - size=(stencil if selection is None else stencil//2*2+1,)*3, - mode=('wrap' if periodic else 'nearest'), + self.material, + mostFrequent, + size=(stencil if selection is None else stencil//2*2+1,)*3, + mode=('wrap' if periodic else 'nearest'), extra_keywords=extra_keywords, ).astype(self.material.dtype) return Grid(material = material, From a77b63718c1f8f5d67de7a4e4b05b928de7a6a19 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 4 Mar 2022 20:00:33 +0100 Subject: [PATCH 16/28] remove deprecated interface options --- python/damask/_result.py | 65 ++++++++++++------------------------- python/tests/test_Result.py | 24 ++++++-------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 820e5d09f..2bd832aad 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -4,7 +4,6 @@ import fnmatch import os import copy import datetime -import warnings import xml.etree.ElementTree as ET # noqa import xml.dom.minidom from pathlib import Path @@ -28,12 +27,7 @@ h5py3 = h5py.__version__[0] == '3' chunk_size = 1024**2//8 # for compression in HDF5 -def _view_transition(what,datasets,increments,times,phases,homogenizations,fields): - if (datasets is not None and what is None) or (what is not None and datasets is None): - raise ValueError('"what" and "datasets" need to be used as a pair') - if datasets is not None or what is not None: - warnings.warn('arguments "what" and "datasets" will be removed in DAMASK v3.0.0-alpha7', DeprecationWarning,2) - return what,datasets +def _view_transition(increments,times,phases,homogenizations,fields): if sum(1 for _ in filter(None.__ne__, [increments,times,phases,homogenizations,fields])) > 1: raise ValueError('only one out of "increments", "times", "phases", "homogenizations", and "fields" can be used') else: @@ -213,14 +207,12 @@ class Result: choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ [datasets] - what_ = what if what.endswith('s') else what+'s' - - if what_ == 'increments': + if what == 'increments': choice = [c if isinstance(c,str) and c.startswith('increment_') else self.increments[c] if isinstance(c,int) and c<0 else f'increment_{c}' for c in choice] - elif what_ == 'times': - what_ = 'increments' + elif what == 'times': + what = 'increments' if choice == ['*']: choice = self.increments else: @@ -234,18 +226,18 @@ class Result: elif np.isclose(c,self.times[idx+1]): choice.append(self.increments[idx+1]) - valid = _match(choice,getattr(self,what_)) - existing = set(self.visible[what_]) + valid = _match(choice,getattr(self,what)) + existing = set(self.visible[what]) dup = self.copy() if action == 'set': - dup.visible[what_] = sorted(set(valid), key=util.natural_sort) + dup.visible[what] = sorted(set(valid), key=util.natural_sort) elif action == 'add': add = existing.union(valid) - dup.visible[what_] = sorted(add, key=util.natural_sort) + dup.visible[what] = sorted(add, key=util.natural_sort) elif action == 'del': diff = existing.difference(valid) - dup.visible[what_] = sorted(diff, key=util.natural_sort) + dup.visible[what] = sorted(diff, key=util.natural_sort) return dup @@ -298,7 +290,7 @@ class Result: return selected - def view(self,what=None,datasets=None,*, + def view(self,*, increments=None, times=None, phases=None, @@ -313,11 +305,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -351,24 +338,24 @@ class Result: >>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0)) """ - v = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) + v = _view_transition(increments,times,phases,homogenizations,fields) if protected is not None: if v is None: dup = self.copy() else: - what_,datasets_ = v - dup = self._manage_view('set',what_,datasets_) + what,datasets = v + dup = self._manage_view('set',what,datasets) if not protected: print(util.warn('Warning: Modification of existing datasets allowed!')) dup._protected = protected else: - what_,datasets_ = v - dup = self._manage_view('set',what_,datasets_) + what,datasets = v + dup = self._manage_view('set',what,datasets) return dup - def view_more(self,what=None,datasets=None,*, + def view_more(self,*, increments=None, times=None, phases=None, @@ -382,11 +369,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -413,11 +395,11 @@ class Result: >>> r_first_and_last = r.first.view_more(increments=-1) """ - what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) - return self._manage_view('add',what_,datasets_) + what, datasets = _view_transition(increments,times,phases,homogenizations,fields) + return self._manage_view('add',what,datasets) - def view_less(self,what=None,datasets=None,*, + def view_less(self,*, increments=None, times=None, phases=None, @@ -431,11 +413,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -461,8 +438,8 @@ class Result: >>> r_deformed = r_all.view_less(increments=0) """ - what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) - return self._manage_view('del',what_,datasets_) + what, datasets = _view_transition(increments,times,phases,homogenizations,fields) + return self._manage_view('del',what,datasets) def rename(self,name_src,name_dst): diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 18e09513f..9124cff99 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -69,8 +69,8 @@ class TestResult: @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_none(self,default,what): - n0 = default.view(what,False) - n1 = default.view(what,[]) + n0 = default.view(**{what:False}) + n1 = default.view(**{what:[]}) label = 'increments' if what == 'times' else what @@ -79,29 +79,25 @@ class TestResult: @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_more(self,default,what): - empty = default.view(what,False) + empty = default.view(**{what:False}) - a = empty.view_more(what,'*').get('F') - b = empty.view_more(what,True).get('F') + a = empty.view_more(**{what:'*'}).get('F') + b = empty.view_more(**{what:True}).get('F') assert dict_equal(a,b) @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_less(self,default,what): - full = default.view(what,True) + full = default.view(**{what:True}) - n0 = full.view_less(what,'*') - n1 = full.view_less(what,True) + n0 = full.view_less(**{what:'*'}) + n1 = full.view_less(**{what:True}) label = 'increments' if what == 'times' else what assert n0.get('F') is n1.get('F') is None and \ len(n0.visible[label]) == len(n1.visible[label]) == 0 - def test_view_invalid(self,default): - with pytest.raises(AttributeError): - default.view('invalid',True) - def test_add_invalid(self,default): default.add_absolute('xxxx') @@ -469,7 +465,7 @@ class TestResult: def test_get(self,update,request,ref_path,view,output,flatten,prune): result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') for key,value in view.items(): - result = result.view(key,value) + result = result.view(**{key:value}) fname = request.node.name cur = result.get(output,flatten,prune) @@ -494,7 +490,7 @@ class TestResult: def test_place(self,update,request,ref_path,view,output,flatten,prune,constituents): result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') for key,value in view.items(): - result = result.view(key,value) + result = result.view(**{key:value}) fname = request.node.name cur = result.place(output,flatten,prune,constituents) From d7ba85385978ba652dc144e92eee38f32d50d2ed Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Mar 2022 20:37:47 +0100 Subject: [PATCH 17/28] use None for no selection, empty list is 'nothing' --- python/damask/_grid.py | 4 ++-- python/damask/seeds.py | 2 +- python/damask/util.py | 2 +- python/tests/test_Grid.py | 11 ++++++++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 0eb376e11..61b64e018 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -958,7 +958,7 @@ class Grid: """ def mostFrequent(arr: np.ndarray, selection: List, invert: bool): me = arr[arr.size//2] - if len(selection) == 0 or np.isin(me,selection,invert=invert): + if selection is None or np.isin(me,selection,invert=invert): unique, inverse = np.unique(arr, return_inverse=True) return unique[np.argmax(np.bincount(inverse))] else: @@ -1179,7 +1179,7 @@ class Grid: """ def tainted_neighborhood(stencil: np.ndarray, selection): me = stencil[stencil.shape[0]//2] - return np.any(stencil != me if len(selection) == 0 else + return np.any(stencil != me if selection is None else np.in1d(stencil,np.array(list(set(selection) - {me})))) offset_ = np.nanmax(self.material)+1 if offset is None else offset diff --git a/python/damask/seeds.py b/python/damask/seeds.py index d5e1ec7ed..8a61bb040 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -135,7 +135,7 @@ def from_grid(grid, """ material = grid.material.reshape((-1,1),order='F') selection_ = _util.tbd(selection) - mask = _np.full(grid.cells.prod(),True,dtype=bool) if len(selection_) == 0 else \ + mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection_ is None else \ _np.isin(material,selection_,invert=invert_selection).flatten() coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') diff --git a/python/damask/util.py b/python/damask/util.py index f19b6a54a..1588906a2 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -754,7 +754,7 @@ def tail_repack(extended: Union[str, Sequence[str]], def tbd(arg) -> List: if arg is None: - return [] + return None elif isinstance(arg,(np.ndarray,Collection)): return list(arg) else: diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 6be2bc18a..a66b47719 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -182,6 +182,11 @@ class TestGrid: assert random.clean(selection=selection,invert_selection=invert) == \ random.clean(selection=selection_inverse,invert_selection=not invert) + def test_clean_selection_empty(self,random): + assert random.clean(selection=[],invert_selection=False) == random and \ + random.clean(selection=[],invert_selection=True) == random.clean() + + @pytest.mark.parametrize('cells',[ (10,11,10), [10,13,10], @@ -319,7 +324,7 @@ class TestGrid: assert grid_equal(G_1,G_2) - @pytest.mark.parametrize('selection',[1,[]]) + @pytest.mark.parametrize('selection',[1,None]) def test_vicinity_offset(self,selection): offset = np.random.randint(2,4) vicinity = np.random.randint(2,4) @@ -346,6 +351,10 @@ class TestGrid: assert random.vicinity_offset(selection=selection,invert_selection=invert) == \ random.vicinity_offset(selection=selection_inverse,invert_selection=not invert) + def test_vicinity_offset_selection_empty(self,random): + assert random.vicinity_offset(selection=[],invert_selection=False) == random and \ + random.vicinity_offset(selection=[],invert_selection=True) == random.vicinity_offset() + @pytest.mark.parametrize('periodic',[True,False]) def test_vicinity_offset_invariant(self,default,periodic): From 612f7397941b6d9c011d7f15b1698f8c2a9ceb06 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 6 Mar 2022 08:28:48 +0100 Subject: [PATCH 18/28] homogenization state is not integrated --- src/homogenization.f90 | 9 +++++++++ src/phase.f90 | 26 ++++++++++++++++++++++++++ src/prec.f90 | 25 ------------------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 0b0121b82..203c7bb1c 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -21,6 +21,15 @@ module homogenization implicit none private + type :: tState + integer :: & + sizeState = 0 !< size of state + ! http://stackoverflow.com/questions/3948210 + real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer + state0, & + state + end type + enum, bind(c); enumerator :: & THERMAL_UNDEFINED_ID, & THERMAL_PASS_ID, & diff --git a/src/phase.f90 b/src/phase.f90 index 9987a5252..2ce559a99 100644 --- a/src/phase.f90 +++ b/src/phase.f90 @@ -22,6 +22,32 @@ module phase implicit none private + type :: tState + integer :: & + sizeState = 0, & !< size of state + sizeDotState = 0, & !< size of dot state, i.e. state(1:sizeDot) follows time evolution by dotState rates + offsetDeltaState = 0, & !< index offset of delta state + sizeDeltaState = 0 !< size of delta state, i.e. state(offset+1:offset+sizeDelta) follows time evolution by deltaState increments + real(pReal), allocatable, dimension(:) :: & + atol + ! http://stackoverflow.com/questions/3948210 + real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer + state0, & + state, & !< state + dotState, & !< rate of state change + deltaState !< increment of state change + real(pReal), pointer, dimension(:,:) :: & + deltaState2 + end type + + type, extends(tState) :: tPlasticState + logical :: nonlocal = .false. + end type + + type :: tSourceState + type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase + end type + character(len=2), allocatable, dimension(:) :: phase_lattice real(pReal), allocatable, dimension(:) :: phase_cOverA diff --git a/src/prec.f90 b/src/prec.f90 index 61fa141ba..d0753790e 100644 --- a/src/prec.f90 +++ b/src/prec.f90 @@ -31,31 +31,6 @@ module prec real(pReal), parameter :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation) - type :: tState - integer :: & - sizeState = 0, & !< size of state - sizeDotState = 0, & !< size of dot state, i.e. state(1:sizeDot) follows time evolution by dotState rates - offsetDeltaState = 0, & !< index offset of delta state - sizeDeltaState = 0 !< size of delta state, i.e. state(offset+1:offset+sizeDelta) follows time evolution by deltaState increments - real(pReal), allocatable, dimension(:) :: & - atol - ! http://stackoverflow.com/questions/3948210 - real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer - state0, & - state, & !< state - dotState, & !< rate of state change - deltaState !< increment of state change - real(pReal), pointer, dimension(:,:) :: & - deltaState2 - end type - - type, extends(tState) :: tPlasticState - logical :: nonlocal = .false. - end type - - type :: tSourceState - type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase - end type real(pReal), private, parameter :: PREAL_EPSILON = epsilon(0.0_pReal) !< minimum positive number such that 1.0 + EPSILON /= 1.0. real(pReal), private, parameter :: PREAL_MIN = tiny(0.0_pReal) !< smallest normalized floating point number From 425d148ea8fc32beb7cdb965b364a44682173451 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 6 Mar 2022 19:37:46 +0100 Subject: [PATCH 19/28] mypy-safe --- python/damask/_grid.py | 5 +++-- python/damask/util.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 61b64e018..561f851be 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -1183,8 +1183,9 @@ class Grid: np.in1d(stencil,np.array(list(set(selection) - {me})))) offset_ = np.nanmax(self.material)+1 if offset is None else offset - selection_ = util.tbd(selection) if not invert_selection else \ - list(set(self.material.flatten()) - set(util.tbd(selection))) + selection_ = util.tbd(selection) + if selection_ is not None and invert_selection: + selection_ = list(set(self.material.flatten()) - set(selection_)) mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, size=1+2*vicinity, diff --git a/python/damask/util.py b/python/damask/util.py index 1588906a2..880e815e8 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -16,7 +16,7 @@ import numpy as np import h5py from . import version -from ._typehints import FloatSequence, NumpyRngSeed +from ._typehints import FloatSequence, NumpyRngSeed, IntCollection # limit visibility __all__=[ @@ -752,7 +752,7 @@ def tail_repack(extended: Union[str, Sequence[str]], list(extended[len(existing):])) -def tbd(arg) -> List: +def tbd(arg: Union[IntCollection,int,None]) -> Union[List,None]: if arg is None: return None elif isinstance(arg,(np.ndarray,Collection)): From 445d5ec7201a86458182f89b1b26417341dadf4f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 6 Mar 2022 21:09:46 +0100 Subject: [PATCH 20/28] propagate signals to running commands otherwise, we have long running processes when GitLab terminates jobs in a pipeline --- python/damask/util.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/python/damask/util.py b/python/damask/util.py index 880e815e8..7408bdfe4 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -6,9 +6,10 @@ import os import subprocess import shlex import re +import signal import fractions from collections import abc -from functools import reduce +from functools import reduce, partial from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection from pathlib import Path @@ -174,21 +175,35 @@ def run(cmd: str, Output of the executed command. """ + def pass_signal(sig,_,proc,default): + proc.send_signal(sig) + signal.signal(sig,default) + signal.raise_signal(sig) + + signals = [signal.SIGINT,signal.SIGTERM] + print(f"running '{cmd}' in '{wd}'") - process = subprocess.run(shlex.split(cmd), + process = subprocess.Popen(shlex.split(cmd), stdout = subprocess.PIPE, stderr = subprocess.PIPE, env = os.environ if env is None else env, cwd = wd, - encoding = 'utf-8', - timeout = timeout) + encoding = 'utf-8') + # ensure that process is terminated (https://stackoverflow.com/questions/22916783) + sig_states = [signal.signal(sig,partial(pass_signal,proc=process,default=signal.getsignal(sig))) for sig in signals] + + try: + stdout,stderr = process.communicate(timeout=timeout) + finally: + for sig,state in zip(signals,sig_states): + signal.signal(sig,state) if process.returncode != 0: - print(process.stdout) - print(process.stderr) + print(stdout) + print(stderr) raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}") - return process.stdout, process.stderr + return stdout, stderr execute = run From 20e056e26a20d07375a09976a137cf20a5be2e2d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Mar 2022 21:09:24 +0100 Subject: [PATCH 21/28] consistent interface also for internal functionality allows to change multiple 'what's at the same time --- python/damask/_result.py | 136 ++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 74 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 2bd832aad..0a1c1c825 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -27,16 +27,6 @@ h5py3 = h5py.__version__[0] == '3' chunk_size = 1024**2//8 # for compression in HDF5 -def _view_transition(increments,times,phases,homogenizations,fields): - if sum(1 for _ in filter(None.__ne__, [increments,times,phases,homogenizations,fields])) > 1: - raise ValueError('only one out of "increments", "times", "phases", "homogenizations", and "fields" can be used') - else: - if increments is not None: return "increments", increments - if times is not None: return "times", times - if phases is not None: return "phases", phases - if homogenizations is not None: return "homogenizations", homogenizations - if fields is not None: return "fields", fields - def _read(dataset): """Read a dataset and its metadata into a numpy.ndarray.""" metadata = {k:(v.decode() if not h5py3 and type(v) is bytes else v) for k,v in dataset.attrs.items()} @@ -179,7 +169,13 @@ class Result: return util.srepr([util.deemph(header)] + first + in_between + last) - def _manage_view(self,action,what,datasets): + def _manage_view(self, + action, + increments=None, + times=None, + phases=None, + homogenizations=None, + fields=None): """ Manages the visibility of the groups. @@ -187,11 +183,6 @@ class Result: ---------- action : str Select from 'set', 'add', and 'del'. - what : str - Attribute to change (must be from self.visible). - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. - True is equivalent to '*', False is equivalent to []. Returns ------- @@ -199,45 +190,52 @@ class Result: Modified or new view on the DADF5 file. """ - # allow True/False and string arguments - if datasets is True: - datasets = '*' - elif datasets is False or datasets is None: - datasets = [] - choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ - [datasets] - - if what == 'increments': - choice = [c if isinstance(c,str) and c.startswith('increment_') else - self.increments[c] if isinstance(c,int) and c<0 else - f'increment_{c}' for c in choice] - elif what == 'times': - what = 'increments' - if choice == ['*']: - choice = self.increments - else: - iterator = map(float,choice) - choice = [] - for c in iterator: - idx = np.searchsorted(self.times,c) - if idx >= len(self.times): continue - if np.isclose(c,self.times[idx]): - choice.append(self.increments[idx]) - elif np.isclose(c,self.times[idx+1]): - choice.append(self.increments[idx+1]) - - valid = _match(choice,getattr(self,what)) - existing = set(self.visible[what]) + if increments is not None and times is not None: + raise ValueError('cannot use "increments" and "times" at the same time to change view') dup = self.copy() - if action == 'set': - dup.visible[what] = sorted(set(valid), key=util.natural_sort) - elif action == 'add': - add = existing.union(valid) - dup.visible[what] = sorted(add, key=util.natural_sort) - elif action == 'del': - diff = existing.difference(valid) - dup.visible[what] = sorted(diff, key=util.natural_sort) + for what,datasets in zip(['increments','times','phases','homogenizations','fields'], + [ increments, times, phases, homogenizations, fields ]): + if datasets is None: + continue + # allow True/False and string arguments + elif datasets is True: + datasets = '*' + elif datasets is False: + datasets = [] + choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ + [datasets] + + if what == 'increments': + choice = [c if isinstance(c,str) and c.startswith('increment_') else + self.increments[c] if isinstance(c,int) and c<0 else + f'increment_{c}' for c in choice] + elif what == 'times': + what = 'increments' + if choice == ['*']: + choice = self.increments + else: + iterator = map(float,choice) + choice = [] + for c in iterator: + idx = np.searchsorted(self.times,c) + if idx >= len(self.times): continue + if np.isclose(c,self.times[idx]): + choice.append(self.increments[idx]) + elif np.isclose(c,self.times[idx+1]): + choice.append(self.increments[idx+1]) + + valid = _match(choice,getattr(self,what)) + existing = set(self.visible[what]) + + if action == 'set': + dup.visible[what] = sorted(set(valid), key=util.natural_sort) + elif action == 'add': + add = existing.union(valid) + dup.visible[what] = sorted(add, key=util.natural_sort) + elif action == 'del': + diff = existing.difference(valid) + dup.visible[what] = sorted(diff, key=util.natural_sort) return dup @@ -291,12 +289,12 @@ class Result: def view(self,*, - increments=None, - times=None, - phases=None, - homogenizations=None, - fields=None, - protected=None): + increments=None, + times=None, + phases=None, + homogenizations=None, + fields=None, + protected=None): """ Set view. @@ -338,19 +336,11 @@ class Result: >>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0)) """ - v = _view_transition(increments,times,phases,homogenizations,fields) + dup = self._manage_view('set',increments,times,phases,homogenizations,fields) if protected is not None: - if v is None: - dup = self.copy() - else: - what,datasets = v - dup = self._manage_view('set',what,datasets) if not protected: print(util.warn('Warning: Modification of existing datasets allowed!')) dup._protected = protected - else: - what,datasets = v - dup = self._manage_view('set',what,datasets) return dup @@ -395,8 +385,7 @@ class Result: >>> r_first_and_last = r.first.view_more(increments=-1) """ - what, datasets = _view_transition(increments,times,phases,homogenizations,fields) - return self._manage_view('add',what,datasets) + return self._manage_view('add',increments,times,phases,homogenizations,fields) def view_less(self,*, @@ -438,8 +427,7 @@ class Result: >>> r_deformed = r_all.view_less(increments=0) """ - what, datasets = _view_transition(increments,times,phases,homogenizations,fields) - return self._manage_view('del',what,datasets) + return self._manage_view('del',increments,times,phases,homogenizations,fields) def rename(self,name_src,name_dst): @@ -1816,9 +1804,9 @@ class Result: d = obj.attrs['description'] if h5py3 else obj.attrs['description'].decode() if not Path(name).exists() or overwrite: with open(name,'w') as f_out: f_out.write(obj[0].decode()) - print(f"Exported {d} to '{name}'.") + print(f'Exported {d} to "{name}".') else: - print(f"'{name}' exists, {d} not exported.") + print(f'"{name}" exists, {d} not exported.') elif type(obj) == h5py.Group: os.makedirs(name, exist_ok=True) From 05541736a639dc2196e0766d4b0d45afdb0ed885 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 9 Mar 2022 15:18:18 +0100 Subject: [PATCH 22/28] clearer message --- python/damask/_result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 0a1c1c825..fb6ba2ae2 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -191,7 +191,7 @@ class Result: """ if increments is not None and times is not None: - raise ValueError('cannot use "increments" and "times" at the same time to change view') + raise ValueError('"increments" and "times" are mutually exclusive') dup = self.copy() for what,datasets in zip(['increments','times','phases','homogenizations','fields'], From 4c941c608fb642407cd1ee619d68ce824e7ab6c1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 9 Mar 2022 15:35:36 +0100 Subject: [PATCH 23/28] better names and description --- python/damask/_grid.py | 14 +++++++------- python/damask/seeds.py | 2 +- python/damask/util.py | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index c86d83c79..3b7e00480 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -665,7 +665,7 @@ class Grid: .add(self.material.flatten(order='F'),'material') for label,data in self.ic.items(): v = v.add(data.flatten(order='F'),label) - v.comments += self.comments + v.comments = self.comments v.save(fname,parallel=False,compress=compress) @@ -969,7 +969,7 @@ class Grid: else: return me - extra_keywords = dict(selection=util.tbd(selection),invert=invert_selection) + extra_keywords = dict(selection=util.ensure_integer_list(selection),invert=invert_selection) material = ndimage.filters.generic_filter( self.material, mostFrequent, @@ -1156,10 +1156,10 @@ class Grid: invert_selection: bool = False, periodic: bool = True) -> 'Grid': """ - Offset material ID of points in the vicinity of xxx. + Offset material ID of points in the vicinity of a trigger point. - Different from themselves (or listed as triggers) within a given (cubic) vicinity, - i.e. within the region close to a grain/phase boundary. + Trigger points are variations in material ID, i.e. grain/phase + boundaries or explicitly given material IDs. Parameters ---------- @@ -1170,7 +1170,7 @@ class Grid: Offset (positive or negative) to tag material indices, defaults to material.max()+1. selection : int or collection of int, optional - Material IDs to that triger xxx. + Material IDs that triger the offset. invert_selection : bool, optional Consider all material IDs except those in selection. Defaults to False. periodic : bool, optional @@ -1188,7 +1188,7 @@ class Grid: np.in1d(stencil,np.array(list(set(selection) - {me})))) offset_ = np.nanmax(self.material)+1 if offset is None else offset - selection_ = util.tbd(selection) + selection_ = util.ensure_integer_list(selection) if selection_ is not None and invert_selection: selection_ = list(set(self.material.flatten()) - set(selection_)) mask = ndimage.filters.generic_filter(self.material, diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 8a61bb040..9f4df1ed1 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -134,7 +134,7 @@ def from_grid(grid, """ material = grid.material.reshape((-1,1),order='F') - selection_ = _util.tbd(selection) + selection_ = _util.ensure_integer_list(selection) mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection_ is None else \ _np.isin(material,selection_,invert=invert_selection).flatten() coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') diff --git a/python/damask/util.py b/python/damask/util.py index 7408bdfe4..1ad17443d 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -767,7 +767,8 @@ def tail_repack(extended: Union[str, Sequence[str]], list(extended[len(existing):])) -def tbd(arg: Union[IntCollection,int,None]) -> Union[List,None]: +def ensure_integer_list(arg: Union[IntCollection,int,None]) -> Union[List,None]: + """Convert to list of Integers.""" if arg is None: return None elif isinstance(arg,(np.ndarray,Collection)): From 98033e41dc0856c278da4b19b8c821f455e2d6d2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 9 Mar 2022 15:36:20 +0100 Subject: [PATCH 24/28] test only use modern Result.view API --- PRIVATE | 2 +- python/damask/_grid.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/PRIVATE b/PRIVATE index 68111b8fc..80152236e 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 68111b8fc3fb45f77d7471ae0f57961b4c77641d +Subproject commit 80152236ef4259e97e10838fdd3bce1dc8b50105 diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 3b7e00480..d4dc456a2 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -971,10 +971,10 @@ class Grid: extra_keywords = dict(selection=util.ensure_integer_list(selection),invert=invert_selection) material = ndimage.filters.generic_filter( - self.material, - mostFrequent, - size=(stencil if selection is None else stencil//2*2+1,)*3, - mode=('wrap' if periodic else 'nearest'), + self.material, + mostFrequent, + size=(stencil if selection is None else stencil//2*2+1,)*3, + mode=('wrap' if periodic else 'nearest'), extra_keywords=extra_keywords, ).astype(self.material.dtype) return Grid(material = material, From f84800787899fb76aa2a58481e22a3d87694a6a1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 9 Mar 2022 22:42:38 +0100 Subject: [PATCH 25/28] did not work, not needed --- .gitlab-ci.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 738d2aecb..834fd68ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,6 @@ stages: - compile - fortran - performance - - deploy - finalize @@ -212,14 +211,6 @@ grid_runtime: - if [ ${CI_COMMIT_BRANCH} == development ]; then git commit -am ${CI_PIPELINE_ID}_${CI_COMMIT_SHA}; git push; fi -################################################################################################### -source_distribution: - stage: deploy - script: - - cd $(mktemp -d) - - ${CI_PROJECT_DIR}/PRIVATE/releasing/tar.xz/create.sh ${CI_PROJECT_DIR} ${CI_COMMIT_SHA} - - ################################################################################################### update_revision: stage: finalize From 3d9ac817bbe09c1e75df240626dd2ad0e33adf4a Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 9 Mar 2022 12:00:17 -0500 Subject: [PATCH 26/28] shorter code --- python/damask/_crystal.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/python/damask/_crystal.py b/python/damask/_crystal.py index 34baf93cf..05a3d3384 100644 --- a/python/damask/_crystal.py +++ b/python/damask/_crystal.py @@ -473,10 +473,7 @@ class Crystal(): @property def orientation_relationships(self): """Return labels of orientation relationships.""" - labels = [] - for k,v in orientation_relationships.items(): - if list(v.items())[1][0] == self.lattice: labels.append(k) - return labels + return [k for k,v in orientation_relationships.items() if self.lattice in v] @property @@ -1006,12 +1003,10 @@ class Crystal(): } } master = _kinematics[self.lattice][mode] - if self.lattice == 'hP': - return {'direction':[util.Bravais_to_Miller(uvtw=m[:,0:4]) for m in master], - 'plane': [util.Bravais_to_Miller(hkil=m[:,4:8]) for m in master]} - else: - return {'direction':[m[:,0:3] for m in master], - 'plane': [m[:,3:6] for m in master]} + return {'direction':[util.Bravais_to_Miller(uvtw=m[:,0:4]) if self.lattice == 'hP' + else m[:,0:3] for m in master], + 'plane': [util.Bravais_to_Miller(hkil=m[:,4:8]) if self.lattice == 'hP' + else m[:,3:6] for m in master]} def relation_operations(self, From f13a4c82dae1ab9fe1f9124fc64d7e674a67d21f Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 9 Mar 2022 18:24:05 -0500 Subject: [PATCH 27/28] grid.clean/vicinity now uses ball neighborhood; lots of polishing --- python/damask/_grid.py | 122 +++++++++++------- python/damask/_orientation.py | 14 +- python/damask/seeds.py | 5 +- python/damask/util.py | 25 ++-- ...3_1_True.vti => clean_1.0_1+2+3_False.vti} | 2 +- ...2+3_False.vti => clean_1.0_1+2+3_True.vti} | 2 +- ...ean_2_1_True.vti => clean_1.0_1_False.vti} | 2 +- ...ean_3_1_False.vti => clean_1.0_1_True.vti} | 2 +- ..._2_1+2+3_True.vti => clean_1.0__False.vti} | 4 +- .../tests/reference/Grid/clean_1.0__True.vti | 19 +++ ... clean_1.7320508075688772_1+2+3_False.vti} | 2 +- .../clean_1.7320508075688772_1+2+3_True.vti | 19 +++ ...i => clean_1.7320508075688772_1_False.vti} | 2 +- ...ti => clean_1.7320508075688772_1_True.vti} | 2 +- ...ti => clean_1.7320508075688772__False.vti} | 4 +- ...vti => clean_1.7320508075688772__True.vti} | 4 +- .../reference/Grid/clean_3_1+2+3_True.vti | 19 --- .../reference/Grid/clean_3_None_False.vti | 19 --- .../reference/Grid/clean_3_None_True.vti | 19 --- .../reference/Grid/clean_4_1+2+3_False.vti | 19 --- .../reference/Grid/clean_4_1+2+3_True.vti | 19 --- .../tests/reference/Grid/clean_4_1_True.vti | 19 --- .../reference/Grid/clean_4_None_False.vti | 19 --- .../reference/Grid/clean_4_None_True.vti | 19 --- python/tests/test_Grid.py | 38 +++--- python/tests/test_util.py | 4 + 26 files changed, 173 insertions(+), 251 deletions(-) rename python/tests/reference/Grid/{clean_3_1_True.vti => clean_1.0_1+2+3_False.vti} (87%) rename python/tests/reference/Grid/{clean_2_1+2+3_False.vti => clean_1.0_1+2+3_True.vti} (87%) rename python/tests/reference/Grid/{clean_2_1_True.vti => clean_1.0_1_False.vti} (87%) rename python/tests/reference/Grid/{clean_3_1_False.vti => clean_1.0_1_True.vti} (87%) rename python/tests/reference/Grid/{clean_2_1+2+3_True.vti => clean_1.0__False.vti} (66%) create mode 100644 python/tests/reference/Grid/clean_1.0__True.vti rename python/tests/reference/Grid/{clean_3_1+2+3_False.vti => clean_1.7320508075688772_1+2+3_False.vti} (87%) create mode 100644 python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_True.vti rename python/tests/reference/Grid/{clean_4_1_False.vti => clean_1.7320508075688772_1_False.vti} (87%) rename python/tests/reference/Grid/{clean_2_1_False.vti => clean_1.7320508075688772_1_True.vti} (87%) rename python/tests/reference/Grid/{clean_2_None_True.vti => clean_1.7320508075688772__False.vti} (75%) rename python/tests/reference/Grid/{clean_2_None_False.vti => clean_1.7320508075688772__True.vti} (73%) delete mode 100644 python/tests/reference/Grid/clean_3_1+2+3_True.vti delete mode 100644 python/tests/reference/Grid/clean_3_None_False.vti delete mode 100644 python/tests/reference/Grid/clean_3_None_True.vti delete mode 100644 python/tests/reference/Grid/clean_4_1+2+3_False.vti delete mode 100644 python/tests/reference/Grid/clean_4_1+2+3_True.vti delete mode 100644 python/tests/reference/Grid/clean_4_1_True.vti delete mode 100644 python/tests/reference/Grid/clean_4_None_False.vti delete mode 100644 python/tests/reference/Grid/clean_4_None_True.vti diff --git a/python/damask/_grid.py b/python/damask/_grid.py index d4dc456a2..0292cd6cc 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -18,7 +18,7 @@ from . import grid_filters from . import Rotation from . import Table from . import Colormap -from ._typehints import FloatSequence, IntSequence, IntCollection +from ._typehints import FloatSequence, IntSequence, IntCollection, NumpyRngSeed class Grid: """ @@ -92,10 +92,10 @@ class Grid: """ if not isinstance(other, Grid): return NotImplemented - return bool(np.allclose(other.size,self.size) - and np.allclose(other.origin,self.origin) - and np.all(other.cells == self.cells) - and np.all(other.material == self.material)) + return bool( np.allclose(other.size,self.size) + and np.allclose(other.origin,self.origin) + and np.all(other.cells == self.cells) + and np.all(other.material == self.material)) @property @@ -191,8 +191,8 @@ class Grid: 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'), - size = bbox[1] - bbox[0], - origin = bbox[0], + size = bbox[1] - bbox[0], + origin = bbox[0], comments = comments, initial_conditions = ic) @@ -247,7 +247,7 @@ class Grid: else: comments.append(line.strip()) - material = np.empty(int(cells.prod())) # initialize as flat array + material = np.empty(cells.prod()) # initialize as flat array i = 0 for line in content[header_length:]: if len(items := line.split('#')[0].split()) == 3: @@ -265,7 +265,7 @@ class Grid: raise TypeError(f'mismatch between {cells.prod()} expected entries and {i} found') if not np.any(np.mod(material,1) != 0.0): # no float present - material = material.astype('int') - (1 if material.min() > 0 else 0) + material = material.astype(int) - (1 if material.min() > 0 else 0) return Grid(material.reshape(cells,order='F'),size,origin,comments) @@ -927,7 +927,7 @@ class Grid: cells/self.cells, output=self.material.dtype, order=0, - mode=('wrap' if periodic else 'nearest'), + mode='wrap' if periodic else 'nearest', prefilter=False ), size = self.size, @@ -937,45 +937,62 @@ class Grid: def clean(self, - stencil: int = 3, + distance: float = np.sqrt(3), selection: IntCollection = None, invert_selection: bool = False, - periodic: bool = True) -> 'Grid': + periodic: bool = True, + rng_seed: NumpyRngSeed = None) -> 'Grid': """ Smooth grid by selecting most frequent material ID within given stencil at each location. Parameters ---------- - stencil : int, optional - Size of smoothing stencil. Defaults to 3. + 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 mostFrequent(arr: np.ndarray, selection: List, invert: bool): - me = arr[arr.size//2] - if selection is None or np.isin(me,selection,invert=invert): - unique, inverse = np.unique(arr, return_inverse=True) - return unique[np.argmax(np.bincount(inverse))] + def most_frequent(stencil: np.ndarray, + selection: set, + rng: NumpyRngSeed): + 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 - extra_keywords = dict(selection=util.ensure_integer_list(selection),invert=invert_selection) + 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, - mostFrequent, - size=(stencil if selection is None else stencil//2*2+1,)*3, - mode=('wrap' if periodic else 'nearest'), - extra_keywords=extra_keywords, + 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, @@ -1007,14 +1024,15 @@ class Grid: R: Rotation, fill: int = None) -> 'Grid': """ - Rotate grid (pad if required). + Rotate grid (and pad if required). Parameters ---------- R : damask.Rotation Rotation to apply to the grid. fill : int, optional - Material ID to fill the corners. Defaults to material.max() + 1. + Material ID to fill enlarged bounding box. + Defaults to material.max() + 1. Returns ------- @@ -1054,9 +1072,11 @@ class Grid: 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 [0,0,0]. + 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. + Material ID to fill the background. + Defaults to material.max() + 1. Returns ------- @@ -1065,15 +1085,15 @@ class Grid: Examples -------- - Remove 1/2 of the microstructure in z-direction. + 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]) + >>> 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 0.0 m + origin: 0.0 0.0 5e-05 m # materials: 1 """ @@ -1150,29 +1170,31 @@ class Grid: def vicinity_offset(self, - vicinity: int = 1, + distance: float = np.sqrt(3), offset: int = None, selection: IntCollection = None, invert_selection: bool = False, periodic: bool = True) -> 'Grid': """ - Offset material ID of points in the vicinity of a trigger point. + Offset material ID of points in the vicinity of selected (or just other) material IDs. Trigger points are variations in material ID, i.e. grain/phase boundaries or explicitly given material IDs. Parameters ---------- - vicinity : int, optional + distance : float, optional Voxel distance checked for presence of other materials. - Defaults to 1. + Defaults to sqrt(3). offset : int, optional - Offset (positive or negative) to tag material indices, - defaults to material.max()+1. + Offset (positive or negative) to tag material IDs. + Defaults to material.max()+1. selection : int or collection of int, optional - Material IDs that triger the offset. + Material IDs that trigger an offset. + Defaults to any other than own material ID. invert_selection : bool, optional - Consider all material IDs except those in selection. Defaults to False. + Consider all material IDs except those in selection. + Defaults to False. periodic : bool, optional Assume grid to be periodic. Defaults to True. @@ -1182,20 +1204,24 @@ class Grid: Updated grid-based geometry. """ - def tainted_neighborhood(stencil: np.ndarray, selection): - me = stencil[stencil.shape[0]//2] - return np.any(stencil != me if selection is None else - np.in1d(stencil,np.array(list(set(selection) - {me})))) + def tainted_neighborhood(stencil: np.ndarray, selection: set): + me = stencil[stencil.size//2] + return np.any(stencil != me if not selection else + np.in1d(stencil,np.array(list(selection - {me})))) + 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 offset_ = np.nanmax(self.material)+1 if offset is None else offset - selection_ = util.ensure_integer_list(selection) - if selection_ is not None and invert_selection: - selection_ = list(set(self.material.flatten()) - set(selection_)) + selection_ = set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \ + set(util.aslist(selection)) mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, - size=1+2*vicinity, + footprint=footprint, mode='wrap' if periodic else 'nearest', - extra_keywords=dict(selection=selection_)) + extra_keywords=dict(selection=selection_), + ) return Grid(material = np.where(mask, self.material + offset_,self.material), size = self.size, diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 195394449..534a9548d 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -870,23 +870,23 @@ class Orientation(Rotation,Crystal): def related(self: MyType, model: str) -> MyType: """ - Orientations derived from the given relationship. + All orientations related to self by given relationship model. Parameters ---------- model : str - Model for orientation relationship. - Must be out of self.orientation_relationships. + Orientation relationship model selected from self.orientation_relationships. Returns ------- - Orientations with crystal structure according to - the selected model for the orienation relationship. + Orientations related to self following the selected + model for the orientation relationship. Examples -------- - Rotations of the Bain orientation relationship (cI -> cF) - of a crystal in "Cube" orientation. + Face-centered cubic orientations following from a + body-centered cubic crystal in "Cube" orientation according + to the Bain orientation relationship (cI -> cF). >>> import numpy as np >>> import damask diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 9f4df1ed1..a4ddfb418 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -134,9 +134,8 @@ def from_grid(grid, """ material = grid.material.reshape((-1,1),order='F') - selection_ = _util.ensure_integer_list(selection) - mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection_ is None else \ - _np.isin(material,selection_,invert=invert_selection).flatten() + mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \ + _np.isin(material,_util.aslist(selection),invert=invert_selection).flatten() coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') if not average: diff --git a/python/damask/util.py b/python/damask/util.py index 1ad17443d..285c5f682 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -767,14 +767,23 @@ def tail_repack(extended: Union[str, Sequence[str]], list(extended[len(existing):])) -def ensure_integer_list(arg: Union[IntCollection,int,None]) -> Union[List,None]: - """Convert to list of Integers.""" - if arg is None: - return None - elif isinstance(arg,(np.ndarray,Collection)): - return list(arg) - else: - return [arg] +def aslist(arg: Union[IntCollection,int,None]) -> List: + """ + Transform argument to list. + + Parameters + ---------- + arg : int or collection of int or None + Entity to transform into list. + + Returns + ------- + transformed : list + Entity transformed into list. + + """ + return [] if arg is None else list(arg) if isinstance(arg,(np.ndarray,Collection)) else [arg] + #################################################################################################### # Classes diff --git a/python/tests/reference/Grid/clean_3_1_True.vti b/python/tests/reference/Grid/clean_1.0_1+2+3_False.vti similarity index 87% rename from python/tests/reference/Grid/clean_3_1_True.vti rename to python/tests/reference/Grid/clean_1.0_1+2+3_False.vti index be670913c..e2a97c1af 100644 --- a/python/tests/reference/Grid/clean_3_1_True.vti +++ b/python/tests/reference/Grid/clean_1.0_1+2+3_False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_2_1+2+3_False.vti b/python/tests/reference/Grid/clean_1.0_1+2+3_True.vti similarity index 87% rename from python/tests/reference/Grid/clean_2_1+2+3_False.vti rename to python/tests/reference/Grid/clean_1.0_1+2+3_True.vti index 33dc58cae..7cac33a2a 100644 --- a/python/tests/reference/Grid/clean_2_1+2+3_False.vti +++ b/python/tests/reference/Grid/clean_1.0_1+2+3_True.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_2_1_True.vti b/python/tests/reference/Grid/clean_1.0_1_False.vti similarity index 87% rename from python/tests/reference/Grid/clean_2_1_True.vti rename to python/tests/reference/Grid/clean_1.0_1_False.vti index be670913c..e2a97c1af 100644 --- a/python/tests/reference/Grid/clean_2_1_True.vti +++ b/python/tests/reference/Grid/clean_1.0_1_False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_3_1_False.vti b/python/tests/reference/Grid/clean_1.0_1_True.vti similarity index 87% rename from python/tests/reference/Grid/clean_3_1_False.vti rename to python/tests/reference/Grid/clean_1.0_1_True.vti index d8ee724cc..561cb3245 100644 --- a/python/tests/reference/Grid/clean_3_1_False.vti +++ b/python/tests/reference/Grid/clean_1.0_1_True.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_2_1+2+3_True.vti b/python/tests/reference/Grid/clean_1.0__False.vti similarity index 66% rename from python/tests/reference/Grid/clean_2_1+2+3_True.vti rename to python/tests/reference/Grid/clean_1.0__False.vti index e73ebc444..70dbb7542 100644 --- a/python/tests/reference/Grid/clean_2_1+2+3_True.vti +++ b/python/tests/reference/Grid/clean_1.0__False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= @@ -11,7 +11,7 @@ - AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg== + AQAAAACAAAAABQAAhAAAAA==eF7t0jcOAjEURVGGnHOOQ4b9b5CC8xtLNAwlbk5hPUuWblZ6n+zvV5ZZYZU11tlgky22E+PdPnsccsARx+ww9jPOuWDOFddM/3Pljfvk/sgTz7ww3d/54JPlv4X8VYexj466jP6ix+gvekw7nHDKTx0umXa44ZY7Rn8H5iza4QtoVQaf diff --git a/python/tests/reference/Grid/clean_1.0__True.vti b/python/tests/reference/Grid/clean_1.0__True.vti new file mode 100644 index 000000000..654968e1f --- /dev/null +++ b/python/tests/reference/Grid/clean_1.0__True.vti @@ -0,0 +1,19 @@ + + + + + + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= + + + + + + + + AQAAAACAAAAABQAAkAAAAA==eF7t070OgkAQRWExKo0GDREMaNjCv/d/QgvPbU5CQw3Nl5nZZZPlUm3+T7W6yK3c4Un9rK/V9/youlN9wzO2ml/xobrHghfM+Xcc0edPWDTP/ie+5AHf+MEv+h5Wl+nvsVff+ZvLcfKUHHtdctegc9RK5zL7Cmb/IJPf5DLvT36Sx7n/MHnMPTh/8QfFJwU8 + + + + + diff --git a/python/tests/reference/Grid/clean_3_1+2+3_False.vti b/python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_False.vti similarity index 87% rename from python/tests/reference/Grid/clean_3_1+2+3_False.vti rename to python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_False.vti index 33dc58cae..7cac33a2a 100644 --- a/python/tests/reference/Grid/clean_3_1+2+3_False.vti +++ b/python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_True.vti b/python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_True.vti new file mode 100644 index 000000000..7cac33a2a --- /dev/null +++ b/python/tests/reference/Grid/clean_1.7320508075688772_1+2+3_True.vti @@ -0,0 +1,19 @@ + + + + + + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= + + + + + + + + AQAAAACAAAAABQAAZwAAAA==eF7t0rcOgmAAhVEgNmyo2AuoWN//BR04EwsJcfzvcvabL47qxcFOJg177HPAIUdMOeaEU844Z8YFl1wx55obbrnjngceeeKZFxYseeWNd1Z88MkX3/zwy+Z/wf8YOqzX1uEPlgwHCA== + + + + + diff --git a/python/tests/reference/Grid/clean_4_1_False.vti b/python/tests/reference/Grid/clean_1.7320508075688772_1_False.vti similarity index 87% rename from python/tests/reference/Grid/clean_4_1_False.vti rename to python/tests/reference/Grid/clean_1.7320508075688772_1_False.vti index d8ee724cc..561cb3245 100644 --- a/python/tests/reference/Grid/clean_4_1_False.vti +++ b/python/tests/reference/Grid/clean_1.7320508075688772_1_False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_2_1_False.vti b/python/tests/reference/Grid/clean_1.7320508075688772_1_True.vti similarity index 87% rename from python/tests/reference/Grid/clean_2_1_False.vti rename to python/tests/reference/Grid/clean_1.7320508075688772_1_True.vti index d8ee724cc..561cb3245 100644 --- a/python/tests/reference/Grid/clean_2_1_False.vti +++ b/python/tests/reference/Grid/clean_1.7320508075688772_1_True.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= diff --git a/python/tests/reference/Grid/clean_2_None_True.vti b/python/tests/reference/Grid/clean_1.7320508075688772__False.vti similarity index 75% rename from python/tests/reference/Grid/clean_2_None_True.vti rename to python/tests/reference/Grid/clean_1.7320508075688772__False.vti index cf91a6700..21cbfbb4a 100644 --- a/python/tests/reference/Grid/clean_2_None_True.vti +++ b/python/tests/reference/Grid/clean_1.7320508075688772__False.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= @@ -11,7 +11,7 @@ - AQAAAACAAAAABQAAGQAAAA==eF5jZIAAxlF6lB4AmmmUHqUHkAYA/M8A8Q== + AQAAAACAAAAABQAAKwAAAA==eF5jZIAAxlGaLJoJjcYlTqw6Qvpx2U+pu0iVJ8QnJD5Kj9KDgQYAUc4BDA== diff --git a/python/tests/reference/Grid/clean_2_None_False.vti b/python/tests/reference/Grid/clean_1.7320508075688772__True.vti similarity index 73% rename from python/tests/reference/Grid/clean_2_None_False.vti rename to python/tests/reference/Grid/clean_1.7320508075688772__True.vti index 9d0302a10..272f0ecf7 100644 --- a/python/tests/reference/Grid/clean_2_None_False.vti +++ b/python/tests/reference/Grid/clean_1.7320508075688772__True.vti @@ -3,7 +3,7 @@ - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= + AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ= @@ -11,7 +11,7 @@ - AQAAAACAAAAABQAAGwAAAA==eF5jZIAAxlF6lB4AmmmUpogeDUfKaAD7jwDw + AQAAAACAAAAABQAAPwAAAA==eF5jZIAAxlGaLJqJAE2pPlx8atG4zCXkXmLFaeXuURqVJhQfhNIhLj4h9YTil1h7COkn5D9C+nGJAwBKngD7 diff --git a/python/tests/reference/Grid/clean_3_1+2+3_True.vti b/python/tests/reference/Grid/clean_3_1+2+3_True.vti deleted file mode 100644 index e73ebc444..000000000 --- a/python/tests/reference/Grid/clean_3_1+2+3_True.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg== - - - - - diff --git a/python/tests/reference/Grid/clean_3_None_False.vti b/python/tests/reference/Grid/clean_3_None_False.vti deleted file mode 100644 index 80a3ce9d2..000000000 --- a/python/tests/reference/Grid/clean_3_None_False.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAIgAAAA==eF5jZIAAxlGaLJoJjSakntr6hzqN7v9RepSmJw0AC04A9Q== - - - - - diff --git a/python/tests/reference/Grid/clean_3_None_True.vti b/python/tests/reference/Grid/clean_3_None_True.vti deleted file mode 100644 index b1ffa6b5d..000000000 --- a/python/tests/reference/Grid/clean_3_None_True.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAALwAAAA==eF5jZIAAxlGaLJoJjSakHpc+cvUTUkdrmlL3j9KU0dROF5TqH2iaVPcDAALOANU= - - - - - diff --git a/python/tests/reference/Grid/clean_4_1+2+3_False.vti b/python/tests/reference/Grid/clean_4_1+2+3_False.vti deleted file mode 100644 index c02459176..000000000 --- a/python/tests/reference/Grid/clean_4_1+2+3_False.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAcQAAAA==eF7t0rkOglAUBFAxKu6igvsKrv//gxYcm9fQGEPBNKe6yc1kolaZqPEndthljzH7HHDIEceccMoZE8654JIpM6645oZb7rjngUeeeOaFV+YseOOdDz754pthf+3Aqr7rdv9vw3+/NjssU7XDD0/8BuQ= - - - - - diff --git a/python/tests/reference/Grid/clean_4_1+2+3_True.vti b/python/tests/reference/Grid/clean_4_1+2+3_True.vti deleted file mode 100644 index 37e026a0a..000000000 --- a/python/tests/reference/Grid/clean_4_1+2+3_True.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAYQAAAA==eF7t0scVglAAAEHgqZgBA2ZExdR/gx6YCpDj38s0sEnUlgR7ccAhR0w55oRTzjjngktmzFlwxTU33LLkjnseeOSJZ15Y8cqaN975YMMnX3zzwy/j4F+GD9u6fvgD+gwHCA== - - - - - diff --git a/python/tests/reference/Grid/clean_4_1_True.vti b/python/tests/reference/Grid/clean_4_1_True.vti deleted file mode 100644 index fb9aa04f7..000000000 --- a/python/tests/reference/Grid/clean_4_1_True.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAZAAAAA==eF7t0rcSglAARFEHE0bAgBkE8///oAWnF8b2bXP6nRv1mkXBv+xzwCFHHDPmhFPOOOeCSyZMmXHFNTfcMueOex545IlnXliw5JUVa95454NPvvjmh79+DXYzdNisbYdfSqMHMg== - - - - - diff --git a/python/tests/reference/Grid/clean_4_None_False.vti b/python/tests/reference/Grid/clean_4_None_False.vti deleted file mode 100644 index 121c43671..000000000 --- a/python/tests/reference/Grid/clean_4_None_False.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAIAAAAA==eF5jZIAAxlF6lB4AmokAPdj1DzRNyP2jNH4aAMufANU= - - - - - diff --git a/python/tests/reference/Grid/clean_4_None_True.vti b/python/tests/reference/Grid/clean_4_None_True.vti deleted file mode 100644 index 54fa77562..000000000 --- a/python/tests/reference/Grid/clean_4_None_True.vti +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= - - - - - - - - AQAAAACAAAAABQAAMAAAAA==eF5jYoAAJhw0IwEalz566aeUptT+oa6fUppS+4e6fkppSu0f6voppSm1HwBAngDh - - - - - diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 6e5953ff0..416559572 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -165,28 +165,26 @@ class TestGrid: default.flip(directions) - @pytest.mark.parametrize('stencil',[1,2,3,4]) - @pytest.mark.parametrize('selection',[None,[1],[1,2,3]]) + @pytest.mark.parametrize('distance',[1.,np.sqrt(3)]) + @pytest.mark.parametrize('selection',[None,1,[1],[1,2,3]]) @pytest.mark.parametrize('periodic',[True,False]) - def test_clean_reference(self,default,update,ref_path,stencil,selection,periodic): - current = default.clean(stencil,selection,periodic=periodic) - reference = ref_path/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}.vti' - if update and stencil > 1: + def test_clean_reference(self,default,update,ref_path,distance,selection,periodic): + current = default.clean(distance,selection,periodic=periodic,rng_seed=0) + 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) if stencil > 1 else default, - current - ) + assert grid_equal(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]) - def test_clean_invert(self,random,selection,invert): - selection_inverse = set(random.material.flatten()) - set(selection) - assert random.clean(selection=selection,invert_selection=invert) == \ - random.clean(selection=selection_inverse,invert_selection=not invert) + def test_clean_invert(self,default,selection,invert): + selection_inverse = set(default.material.flatten()) - set(selection) + assert default.clean(selection=selection,invert_selection=invert,rng_seed=0) == \ + default.clean(selection=selection_inverse,invert_selection=not invert,rng_seed=0) def test_clean_selection_empty(self,random): - assert random.clean(selection=[],invert_selection=False) == random and \ - random.clean(selection=[],invert_selection=True) == random.clean() + assert random.clean(selection=None,invert_selection=True,rng_seed=0) == random.clean(rng_seed=0) and \ + random.clean(selection=None,invert_selection=False,rng_seed=0) == random.clean(rng_seed=0) @pytest.mark.parametrize('cells',[ @@ -329,20 +327,20 @@ class TestGrid: @pytest.mark.parametrize('selection',[1,None]) def test_vicinity_offset(self,selection): offset = np.random.randint(2,4) - vicinity = np.random.randint(2,4) + distance = np.random.randint(2,4) g = np.random.randint(28,40,(3)) m = np.ones(g,'i') - x = (g*np.random.permutation(np.array([.5,1,1]))).astype('i') + x = (g*np.random.permutation(np.array([.5,1,1]))).astype(int) m[slice(0,x[0]),slice(0,x[1]),slice(0,x[2])] = 2 m2 = m.copy() for i in [0,1,2]: - m2[(np.roll(m,+vicinity,i)-m)!=0] += offset - m2[(np.roll(m,-vicinity,i)-m)!=0] += offset + m2[(np.roll(m,+distance,i)-m)!=0] += offset + m2[(np.roll(m,-distance,i)-m)!=0] += offset if selection == 1: m2[m==1] = 1 - grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,selection=selection) + grid = Grid(m,np.random.rand(3)).vicinity_offset(distance,offset,selection=selection) assert np.all(m2==grid.material) diff --git a/python/tests/test_util.py b/python/tests/test_util.py index ee345605f..671654ee0 100644 --- a/python/tests/test_util.py +++ b/python/tests/test_util.py @@ -117,6 +117,10 @@ class TestUtil: def test_decorate(self,style): assert 'DAMASK' in style('DAMASK') + @pytest.mark.parametrize('lst',[1,[1,2],set([1,2,3]),np.arange(4)]) + def test_aslist(self,lst): + assert len(util.aslist(lst)) > 0 + @pytest.mark.parametrize('complete',[True,False]) def test_D3D_base_group(self,tmp_path,complete): base_group = ''.join(random.choices('DAMASK', k=10)) From 4f6d9aa4b6ebd8df5e6c846dd00232b5aecf9244 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 9 Mar 2022 19:01:45 -0500 Subject: [PATCH 28/28] adjusted faulty test --- python/damask/_grid.py | 2 +- python/tests/test_Grid.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 0292cd6cc..14177417c 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -972,7 +972,7 @@ class Grid: """ def most_frequent(stencil: np.ndarray, selection: set, - rng: NumpyRngSeed): + rng): me = stencil[stencil.size//2] if not selection or me in selection: unique, counts = np.unique(stencil,return_counts=True) diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 416559572..2f9dc549e 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -352,8 +352,8 @@ class TestGrid: random.vicinity_offset(selection=selection_inverse,invert_selection=not invert) def test_vicinity_offset_selection_empty(self,random): - assert random.vicinity_offset(selection=[],invert_selection=False) == random and \ - random.vicinity_offset(selection=[],invert_selection=True) == random.vicinity_offset() + assert random.vicinity_offset(selection=None,invert_selection=False) == random.vicinity_offset() and \ + random.vicinity_offset(selection=None,invert_selection=True ) == random.vicinity_offset() @pytest.mark.parametrize('periodic',[True,False])