From c880052250f2f2d0fe50def3a90f60185d3db5a0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 2 Dec 2020 14:37:44 +0100 Subject: [PATCH 1/9] avoid evil eval --- python/damask/_vtk.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index 2f4d63791..a1a48f38e 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -76,7 +76,8 @@ class VTK: nodes : numpy.ndarray of shape (:,3) Spatial position of the nodes. connectivity : numpy.ndarray of np.dtype = int - Cell connectivity (0-based), first dimension determines #Cells, second dimension determines #Nodes/Cell. + Cell connectivity (0-based), first dimension determines #Cells, + second dimension determines #Nodes/Cell. cell_type : str Name of the vtk.vtkCell subclass. Tested for TRIANGLE, QUAD, TETRA, and HEXAHEDRON. @@ -91,7 +92,9 @@ class VTK: vtk_data = vtk.vtkUnstructuredGrid() vtk_data.SetPoints(vtk_nodes) - vtk_data.SetCells(eval(f'vtk.VTK_{cell_type.split("_",1)[-1].upper()}'),cells) + cell_types = {'TRIANGLE':vtk.VTK_TRIANGLE, 'QUAD':vtk.VTK_QUAD, + 'TETRA' :vtk.VTK_TETRA, 'HEXAHEDRON':vtk.VTK_HEXAHEDRON} + vtk_data.SetCells(cell_types[cell_type.split("_",1)[-1].upper()],cells) return VTK(vtk_data) From d3a5979d25b312058f5015cfc209d6dece1f3a83 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 2 Dec 2020 14:45:47 +0100 Subject: [PATCH 2/9] meaningful result --- python/damask/_result.py | 9 +++++---- python/tests/test_Result.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 0e74f86df..bdc1b6d14 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -780,7 +780,7 @@ class Result: @staticmethod - def _add_IPF_color(q,l): + def _add_IPF_color(l,q): m = util.scale_to_coprime(np.array(l)) try: lattice = {'fcc':'cF','bcc':'cI','hex':'hP'}[q['meta']['Lattice']] @@ -798,16 +798,17 @@ class Result: 'Creator': 'add_IPF_color' } } - def add_IPF_color(self,q,l): + def add_IPF_color(self,l,q='O'): """ Add RGB color tuple of inverse pole figure (IPF) color. Parameters ---------- - q : str - Label of the dataset containing the crystallographic orientation as quaternions. l : numpy.array of shape (3) Lab frame direction for inverse pole figure. + q : str + Label of the dataset containing the crystallographic orientation as quaternions. + Defaults to 'O'. """ self._add_generic_pointwise(self._add_IPF_color,{'q':q},{'l':l}) diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 1e014216e..015265456 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -169,7 +169,7 @@ class TestResult: @pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]]) def test_add_IPF_color(self,default,d): - default.add_IPF_color('O',np.array(d)) + default.add_IPF_color(d,'O') loc = {'O': default.get_dataset_location('O'), 'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))} qu = default.read_dataset(loc['O']).view(np.double).squeeze() From c80e1c5420ef80ef5fa435dafe28207a93a01798 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Dec 2020 10:47:42 +0100 Subject: [PATCH 3/9] less confusing in the standard case, more helpful in the special case --- python/damask/_grid.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 2bd5a5f9e..0440dc7d0 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -43,12 +43,15 @@ class Grid: def __repr__(self): """Basic information on grid definition.""" + mat_min = np.nanmin(self.material) + mat_max = np.nanmax(self.material) + mat_N = self.N_materials return util.srepr([ - f'cells a b c: {util.srepr(self.cells, " x ")}', - f'size x y z: {util.srepr(self.size, " x ")}', - f'origin x y z: {util.srepr(self.origin," ")}', - f'# materials: {self.N_materials}', - f'max material: {np.nanmax(self.material)}', + f'cells a b c: {util.srepr(self.cells, " x ")}', + f'size x y z: {util.srepr(self.size, " x ")}', + f'origin x y z: {util.srepr(self.origin," ")}', + f'# materials: {mat_N}' + ('' if mat_min == 0 and mat_max+1 == mat_N else + f' (min: {mat_min}, max: {mat_max})') ]) From 42eb8021268a60a31203f021ae7860e8cc4e24d0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Dec 2020 11:29:23 +0100 Subject: [PATCH 4/9] not needed anymore --- src/grid/discretization_grid.f90 | 162 ------------------------------- 1 file changed, 162 deletions(-) diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index e4b64c9c0..93fd4d82b 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -149,168 +149,6 @@ subroutine discretization_grid_init(restart) end subroutine discretization_grid_init -!-------------------------------------------------------------------------------------------------- -!> @brief Parses geometry file -!> @details important variables have an implicit "save" attribute. Therefore, this function is -! supposed to be called only once! -!-------------------------------------------------------------------------------------------------- -subroutine readGeom(grid,geomSize,origin,material) - - integer, dimension(3), intent(out) :: & - grid ! grid (across all processes!) - real(pReal), dimension(3), intent(out) :: & - geomSize, & ! size (across all processes!) - origin ! origin (across all processes!) - integer, dimension(:), intent(out), allocatable :: & - material - - character(len=:), allocatable :: rawData - character(len=65536) :: line - integer, allocatable, dimension(:) :: chunkPos - integer :: & - headerLength = -1, & !< length of header (in lines) - fileLength, & !< length of the geom file (in characters) - fileUnit, & - startPos, endPos, & - myStat, & - l, & !< line counter - c, & !< counter for # materials in line - o, & !< order of "to" packing - e, & !< "element", i.e. spectral collocation point - i, j - - grid = -1 - geomSize = -1.0_pReal - -!-------------------------------------------------------------------------------------------------- -! read raw data as stream - inquire(file = trim(interface_geomFile), size=fileLength) - open(newunit=fileUnit, file=trim(interface_geomFile), access='stream',& - status='old', position='rewind', action='read',iostat=myStat) - if(myStat /= 0) call IO_error(100,ext_msg=trim(interface_geomFile)) - allocate(character(len=fileLength)::rawData) - read(fileUnit) rawData - close(fileUnit) - -!-------------------------------------------------------------------------------------------------- -! get header length - endPos = index(rawData,IO_EOL) - if(endPos <= index(rawData,'head')) then ! ToDo: Should be 'header' - startPos = len(rawData) - call IO_error(error_ID=841, ext_msg='readGeom') - else - chunkPos = IO_stringPos(rawData(1:endPos)) - if (chunkPos(1) < 2) call IO_error(error_ID=841, ext_msg='readGeom') - headerLength = IO_intValue(rawData(1:endPos),chunkPos,1) - startPos = endPos + 1 - endif - -!-------------------------------------------------------------------------------------------------- -! read and interpret header - origin = 0.0_pReal - l = 0 - do while (l < headerLength .and. startPos < len(rawData)) - endPos = startPos + index(rawData(startPos:),IO_EOL) - 1 - if (endPos < startPos) endPos = len(rawData) ! end of file without new line - line = rawData(startPos:endPos) - startPos = endPos + 1 - l = l + 1 - - chunkPos = IO_stringPos(trim(line)) - if (chunkPos(1) < 2) cycle ! need at least one keyword value pair - - select case (IO_lc(IO_StringValue(trim(line),chunkPos,1)) ) - case ('grid') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('a') - grid(1) = IO_intValue(line,chunkPos,j+1) - case('b') - grid(2) = IO_intValue(line,chunkPos,j+1) - case('c') - grid(3) = IO_intValue(line,chunkPos,j+1) - end select - enddo - endif - - case ('size') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('x') - geomSize(1) = IO_floatValue(line,chunkPos,j+1) - case('y') - geomSize(2) = IO_floatValue(line,chunkPos,j+1) - case('z') - geomSize(3) = IO_floatValue(line,chunkPos,j+1) - end select - enddo - endif - - case ('origin') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('x') - origin(1) = IO_floatValue(line,chunkPos,j+1) - case('y') - origin(2) = IO_floatValue(line,chunkPos,j+1) - case('z') - origin(3) = IO_floatValue(line,chunkPos,j+1) - end select - enddo - endif - - end select - - enddo - -!-------------------------------------------------------------------------------------------------- -! sanity checks - if(any(grid < 1)) & - call IO_error(error_ID = 842, ext_msg='grid (readGeom)') - if(any(geomSize < 0.0_pReal)) & - call IO_error(error_ID = 842, ext_msg='size (readGeom)') - - allocate(material(product(grid)), source = -1) ! too large in case of MPI (shrink later, not very elegant) - -!-------------------------------------------------------------------------------------------------- -! read and interpret content - e = 1 - do while (startPos < len(rawData)) - endPos = startPos + index(rawData(startPos:),IO_EOL) - 1 - if (endPos < startPos) endPos = len(rawData) ! end of file without new line - line = rawData(startPos:endPos) - startPos = endPos + 1 - l = l + 1 - chunkPos = IO_stringPos(trim(line)) - - noCompression: if (chunkPos(1) /= 3) then - c = chunkPos(1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,i+1), i=0, c-1)] - else noCompression - compression: if (IO_lc(IO_stringValue(line,chunkPos,2)) == 'of') then - c = IO_intValue(line,chunkPos,1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,3),i = 1,IO_intValue(line,chunkPos,1))] - else if (IO_lc(IO_stringValue(line,chunkPos,2)) == 'to') then compression - c = abs(IO_intValue(line,chunkPos,3) - IO_intValue(line,chunkPos,1)) + 1 - o = merge(+1, -1, IO_intValue(line,chunkPos,3) > IO_intValue(line,chunkPos,1)) - material(e:e+c-1) = [(i, i = IO_intValue(line,chunkPos,1),IO_intValue(line,chunkPos,3),o)] - else compression - c = chunkPos(1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,i+1), i=0, c-1)] - endif compression - endif noCompression - - e = e+c - end do - - if (e-1 /= product(grid)) call IO_error(error_ID = 843, el=e) - -end subroutine readGeom - - !-------------------------------------------------------------------------------------------------- !> @brief Parse vtk rectilinear grid (.vtr) !> @details https://vtk.org/Wiki/VTK_XML_Formats From 78a246b44ac78276d5586e52c413925ec5a033b4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Dec 2020 12:46:48 +0100 Subject: [PATCH 5/9] avoid constant reallocation, it is slow for large vtr files --- src/grid/discretization_grid.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index 93fd4d82b..1b3700c14 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -404,12 +404,12 @@ subroutine readVTR(grid,geomSize,origin,material) size_deflated = temp(4:) bytes_inflated = base64_to_bytes(base64_str(base64_nChar(headerLen)+1_pI64:)) - allocate(bytes(0)) + allocate(bytes(sum(size_inflated))) e = 0_pI64 do b = 1, nBlock s = e + 1_pI64 e = s + size_deflated(b) - 1_pI64 - bytes = [bytes,zlib_inflate(bytes_inflated(s:e),size_inflated(b))] + bytes(sum(size_inflated(:b-1))+1_pI64:sum(size_inflated(:b))) = zlib_inflate(bytes_inflated(s:e),size_inflated(b)) enddo end function asBytes_compressed From 32c2de6b91739b3b2e24e9616d15ed5b1ccbfa90 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 10 Dec 2020 20:53:11 +0100 Subject: [PATCH 6/9] Ensuring regular spacing for grid --- python/damask/_grid.py | 29 +++++++++++++++++------------ python/tests/test_Grid.py | 13 +++++++++++-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 584a34b51..8380bbc5b 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -7,7 +7,8 @@ import warnings import numpy as np import pandas as pd import h5py -from scipy import ndimage,spatial +from scipy import ndimage, spatial +from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np from . import environment from . import VTK @@ -50,8 +51,8 @@ class Grid: f'cells a b c: {util.srepr(self.cells, " x ")}', f'size x y z: {util.srepr(self.size, " x ")}', f'origin x y z: {util.srepr(self.origin," ")}', - f'# materials: {mat_N}' + ('' if mat_min == 0 and mat_max+1 == mat_N else - f' (min: {mat_min}, max: {mat_max})') + f'# materials: {mat_N}' + ('' if mat_min == 0 and mat_max+1 == mat_N else + f' (min: {mat_min}, max: {mat_max})') ]) @@ -107,9 +108,9 @@ class Grid: @material.setter def material(self,material): if len(material.shape) != 3: - raise ValueError(f'Invalid material shape {material.shape}.') + raise ValueError(f'invalid material shape {material.shape}') elif material.dtype not in np.sctypes['float'] + np.sctypes['int']: - raise TypeError(f'Invalid material data type {material.dtype}.') + raise TypeError(f'invalid material data type {material.dtype}') else: self._material = np.copy(material) @@ -126,7 +127,7 @@ class Grid: @size.setter def size(self,size): if len(size) != 3 or any(np.array(size) <= 0): - raise ValueError(f'Invalid size {size}.') + raise ValueError(f'invalid size {size}') else: self._size = np.array(size) @@ -138,7 +139,7 @@ class Grid: @origin.setter def origin(self,origin): if len(origin) != 3: - raise ValueError(f'Invalid origin {origin}.') + raise ValueError(f'invalid origin {origin}') else: self._origin = np.array(origin) @@ -181,6 +182,10 @@ class Grid: cells = np.array(v.vtk_data.GetDimensions())-1 bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T + for i,c in enumerate([v.vtk_data.GetXCoordinates(),v.vtk_data.GetYCoordinates(),v.vtk_data.GetZCoordinates()]): + if not np.allclose(vtk_to_np(c),np.linspace(bbox[0][i],bbox[1][i],cells[i]+1)): + raise ValueError('regular grid spacing violated') + return Grid(material = v.get('material').reshape(cells,order='F'), size = bbox[1] - bbox[0], origin = bbox[0], @@ -214,7 +219,7 @@ class Grid: except ValueError: header_length,keyword = (-1, 'invalid') if not keyword.startswith('head') or header_length < 3: - raise TypeError('Header length information missing or invalid') + raise TypeError('header length information missing or invalid') comments = [] content = f.readlines() @@ -246,7 +251,7 @@ class Grid: i += len(items) if i != cells.prod(): - raise TypeError(f'Invalid file: expected {cells.prod()} entries, found {i}') + raise TypeError(f'invalid file: expected {cells.prod()} entries, found {i}') if not np.any(np.mod(material,1) != 0.0): # no float present material = material.astype('int') - (1 if material.min() > 0 else 0) @@ -631,7 +636,7 @@ class Grid: """ valid = ['x','y','z'] if not set(directions).issubset(valid): - raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.') + raise ValueError(f'invalid direction {set(directions).difference(valid)} specified') limits = [None,None] if reflect else [-2,0] mat = self.material.copy() @@ -663,7 +668,7 @@ class Grid: """ valid = ['x','y','z'] if not set(directions).issubset(valid): - raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.') + raise ValueError(f'invalid direction {set(directions).difference(valid)} specified') mat = np.flip(self.material, (valid.index(d) for d in directions if d in valid)) @@ -916,7 +921,7 @@ class Grid: """ valid = ['x','y','z'] if not set(directions).issubset(valid): - raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.') + raise ValueError(f'invalid direction {set(directions).difference(valid)} specified') o = [[0, self.cells[0]+1, np.prod(self.cells[:2]+1)+self.cells[0]+1, np.prod(self.cells[:2]+1)], [0, np.prod(self.cells[:2]+1), np.prod(self.cells[:2]+1)+1, 1], diff --git a/python/tests/test_Grid.py b/python/tests/test_Grid.py index 37f011676..48831f917 100644 --- a/python/tests/test_Grid.py +++ b/python/tests/test_Grid.py @@ -1,5 +1,6 @@ import pytest import numpy as np +from vtk.util.numpy_support import numpy_to_vtk as np_to_vtk from damask import VTK from damask import Grid @@ -57,13 +58,21 @@ class TestGrid: new = Grid.load(tmp_path/'default.vtr') assert grid_equal(new,default) - def test_invalid_vtr(self,tmp_path): + def test_invalid_no_material(self,tmp_path): v = VTK.from_rectilinear_grid(np.random.randint(5,10,3)*2,np.random.random(3) + 1.0) v.save(tmp_path/'no_materialpoint.vtr',parallel=False) with pytest.raises(ValueError): Grid.load(tmp_path/'no_materialpoint.vtr') - def test_invalid_material(self): + def test_invalid_spacing(self,tmp_path,default): + default.save(tmp_path/'spacing_ok.vtr') + vtk = VTK.load(tmp_path/'spacing_ok.vtr') + vtk.vtk_data.SetXCoordinates(np_to_vtk(np.sort(np.random.random(default.cells[0])))) + vtk.save(tmp_path/'invalid_spacing.vtr',parallel=False) + with pytest.raises(ValueError): + Grid.load(tmp_path/'invalid_spacing.vtr') + + def test_invalid_material_type(self): with pytest.raises(TypeError): Grid(np.zeros((3,3,3),dtype='complex'),np.ones(3)) From b0c8024e017ee85fd16c648cdf5d995e9f697c28 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 10 Dec 2020 22:50:23 +0100 Subject: [PATCH 7/9] include updates to release scripts --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index fd99d76d1..08f8aea46 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit fd99d76d1eaa42fd36971ff2f79a59d98534fc27 +Subproject commit 08f8aea465a1b5e476b584bcae7927d113919b1d From 2e28bc127acae295a288a4d3ff9f21c596e2326a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 10 Dec 2020 23:44:54 +0100 Subject: [PATCH 8/9] better message in case that GUI is not possible --- python/damask/_colormap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index 7deaf4ca4..5a22f049b 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -57,7 +57,7 @@ class Colormap(mpl.colors.ListedColormap): ax1.imshow(np.linspace(0,1,self.N).reshape(1,-1), aspect='auto', cmap=self, interpolation='nearest') plt.show(block = False) - return self.name + return 'Colormap: '+self.name @staticmethod From 8c8dd9ba0aac858b0bbbfeafaf975cac81c8d72d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 11 Dec 2020 00:14:59 +0100 Subject: [PATCH 9/9] simplified --- Makefile | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 418d70507..102b954bd 100644 --- a/Makefile +++ b/Makefile @@ -2,27 +2,20 @@ SHELL = /bin/sh ######################################################################################## # Makefile for the installation of DAMASK ######################################################################################## -DAMASK_ROOT = $(shell python3 -c "import os,sys; print(os.path.normpath(os.path.realpath(os.path.expanduser('$(pwd)'))))") .PHONY: all all: grid mesh processing .PHONY: grid -grid: build/grid - @(cd build/grid;make -j${DAMASK_NUM_THREADS} all install;) +grid: + @cmake -B build/grid -DDAMASK_SOLVER=GRID -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} + @cmake --build build/grid --parallel ${DAMASK_NUM_THRADS} + @cmake --install build/grid .PHONY: mesh -mesh: build/mesh - @(cd build/mesh; make -j${DAMASK_NUM_THREADS} all install;) - -.PHONY: build/grid -build/grid: - @mkdir -p build/grid - @(cd build/grid; cmake -Wno-dev -DDAMASK_SOLVER=GRID -DCMAKE_INSTALL_PREFIX=${DAMASK_ROOT} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) - -.PHONY: build/mesh -build/mesh: - @mkdir -p build/mesh - @(cd build/mesh; cmake -Wno-dev -DDAMASK_SOLVER=MESH -DCMAKE_INSTALL_PREFIX=${DAMASK_ROOT} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) +mesh: + @cmake -B build/mesh -DDAMASK_SOLVER=MESH -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} + @cmake --build build/mesh --parallel ${DAMASK_NUM_THRADS} + @cmake --install build/mesh .PHONY: clean clean: