diff --git a/python/damask/ktv.py b/python/damask/ktv.py index de8392339..5cef8af21 100644 --- a/python/damask/ktv.py +++ b/python/damask/ktv.py @@ -8,27 +8,50 @@ from vtk.util import numpy_support as nps from . import table from . import version -class VTK: # capitals needed/preferred? +class VTK: """ - Manage vtk files. + Spatial visualization (and potentially manipulation). - tbd + High-level interface to VTK. """ def __init__(self,geom): - """tbd.""" + """ + Set geometry and topology. + + Parameters + ---------- + geom : subclass of vtk.vtkDataSet + Description of geometry and topology. Valid types are vtk.vtkRectilinearGrid, + vtk.vtkUnstructuredGrid, or vtk.vtkPolyData. + + """ self.geom = geom @staticmethod def from_rectilinearGrid(grid,size,origin=np.zeros(3)): - """Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data.""" + """ + Create VTK of type vtk.vtkRectilinearGrid. + + This is the common type for results from the grid solver. + + Parameters + ---------- + grid : numpy.ndarray of shape (3) of np.dtype = int + Number of cells. + size : numpy.ndarray of shape (3) + Physical length. + origin : numpy.ndarray of shape (3), optional + Spatial origin. + + """ coordArray = [vtk.vtkDoubleArray(),vtk.vtkDoubleArray(),vtk.vtkDoubleArray()] for dim in [0,1,2]: - for c in np.linspace(origin[dim],origin[dim]+size[dim],grid[dim]): + for c in np.linspace(origin[dim],origin[dim]+size[dim],grid[dim]+1): coordArray[dim].InsertNextValue(c) geom = vtk.vtkRectilinearGrid() - geom.SetDimensions(*grid) + geom.SetDimensions(*(grid+1)) geom.SetXCoordinates(coordArray[0]) geom.SetYCoordinates(coordArray[1]) geom.SetZCoordinates(coordArray[2]) @@ -39,10 +62,18 @@ class VTK: # capitals needed/preferred? @staticmethod def from_unstructuredGrid(nodes,connectivity,cell_type): """ - Create an unstructured grid (mesh). + Create VTK of type vtk.vtkUnstructuredGrid. - connectivity: 0 based at the moment, shape Ncell x N nodes - cell_type: TRIANGLE, 'QUAD', 'TETRA','HEXAHEDRON' + This is the common type for results from FEM solvers. + + Parameters + ---------- + 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_type : str + Name of the vtk.vtkCell subclass. Tested for TRIANGLE, QUAD, and HEXAHEDRON. """ vtk_nodes = vtk.vtkPoints() @@ -62,6 +93,17 @@ class VTK: # capitals needed/preferred? @staticmethod def from_polyData(points): + """ + Create VTK of type vtk.polyData. + + This is the common type for point-wise data. + + Parameters + ---------- + points : numpy.ndarray of shape (:,3) + Spatial position of the points. + + """ vtk_points= vtk.vtkPoints() vtk_points.SetData(nps.numpy_to_vtk(points)) @@ -79,16 +121,28 @@ class VTK: # capitals needed/preferred? @staticmethod def from_file(fname,ftype=None): + """ + Create VTK from file. + + Parameters + ---------- + fname : str + Filename for reading. Valid extensions are .vtk, .vtr, .vtu, and .vtp. + ftype : str, optional + Name of the vtk.vtkDataSet subclass when opening an .vtk file. Valid types are vtkRectilinearGrid, + vtkUnstructuredGrid, and vtkPolyData. + + """ ext = os.path.splitext(fname)[1] if ext == '.vtk': reader = vtk.vtkGenericDataObjectReader() reader.SetFileName(fname) reader.Update() - if ftype.lower() == 'rectilineargrid': + if 'rectilineargrid' in ftype.lower(): geom = reader.GetRectilinearGridOutput() - elif ftype.lower() == 'unstructuredgrid': + elif 'unstructuredgrid' in ftype.lower(): geom = reader.GetUnstructuredGridOutput() - elif ftype.lower() == 'polydata': + elif 'polydata' in ftype.lower(): geom = reader.GetPolyDataOutput() else: raise Exception @@ -109,8 +163,17 @@ class VTK: # capitals needed/preferred? return VTK(geom) + # ToDo: If extension is given, check for consistency. def write(self,fname): - """ToDo: Check if given fileextension makes sense.""" + """ + Write to file. + + Parameters + ---------- + fname : str + Filename for writing. + + """ if (isinstance(self.geom,vtk.vtkRectilinearGrid)): writer = vtk.vtkXMLRectilinearGridWriter() elif(isinstance(self.geom,vtk.vtkUnstructuredGrid)): @@ -127,18 +190,19 @@ class VTK: # capitals needed/preferred? writer.Write() + # Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data + # Needs support for pd.DataFrame and/or table def add(self,data,label=None): - - Npoints = self.geom.GetNumberOfPoints() - Ncells = self.geom.GetNumberOfCells() + """Add data to either cells or points.""" + N_points = self.geom.GetNumberOfPoints() + N_cells = self.geom.GetNumberOfCells() if isinstance(data,np.ndarray): - shape = [data.shape[0],np.product(data.shape[1:],dtype=np.int)] - d = nps.numpy_to_vtk(num_array=data.reshape(shape),deep=True) + d = nps.numpy_to_vtk(num_array=data.reshape(data.shape[0],-1),deep=True) d.SetName(label) - if shape[0] == Ncells: + if data.shape[0] == N_cells: self.geom.GetCellData().AddArray(d) - elif shape[0] == Npoints: + elif data.shape[0] == N_points: self.geom.GetPointData().AddArray(d) elif isinstance(data,pd.DataFrame): pass diff --git a/python/damask/result.py b/python/damask/result.py index 20ee803fd..37bd90b42 100644 --- a/python/damask/result.py +++ b/python/damask/result.py @@ -26,12 +26,12 @@ class Result: def __init__(self,fname): """ - Opens an existing DADF5 file. + Open an existing DADF5 file. Parameters ---------- fname : str - name of the DADF5 file to be openend. + name of the DADF5 file to be openend. """ with h5py.File(fname,'r') as f: @@ -1029,7 +1029,7 @@ class Result: if mode.lower()=='cell': if self.structured: - v = VTK.from_rectilinearGrid(self.grid+1,self.size,self.origin) + v = VTK.from_rectilinearGrid(self.grid,self.size,self.origin) else: with h5py.File(self.fname,'r') as f: v = VTK.from_unstructuredGrid(f['/geometry/x_n'][()],