Merge branch 'python-vtk-improvements' into 'development'
Resolve issues in #149 See merge request damask/DAMASK!535
This commit is contained in:
commit
3bc1a5eda4
|
@ -328,7 +328,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
if fname is None:
|
if fname is None:
|
||||||
return open(self.name.replace(' ','_')+suffix, 'w', newline='\n')
|
return open(self.name.replace(' ','_')+suffix, 'w', newline='\n')
|
||||||
elif isinstance(fname, (str, Path)):
|
elif isinstance(fname, (str, Path)):
|
||||||
return open(fname, 'w', newline='\n')
|
return open(Path(fname).expanduser(), 'w', newline='\n')
|
||||||
else:
|
else:
|
||||||
return fname
|
return fname
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ class Crystal():
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Represent."""
|
"""Give short human-readable summary."""
|
||||||
family = f'Crystal family: {self.family}'
|
family = f'Crystal family: {self.family}'
|
||||||
return family if self.lattice is None else \
|
return family if self.lattice is None else \
|
||||||
util.srepr([family,
|
util.srepr([family,
|
||||||
|
|
|
@ -17,6 +17,7 @@ from . import util
|
||||||
from . import grid_filters
|
from . import grid_filters
|
||||||
from . import Rotation
|
from . import Rotation
|
||||||
from . import Table
|
from . import Table
|
||||||
|
from . import Colormap
|
||||||
from ._typehints import FloatSequence, IntSequence
|
from ._typehints import FloatSequence, IntSequence
|
||||||
|
|
||||||
class Grid:
|
class Grid:
|
||||||
|
@ -57,7 +58,7 @@ class Grid:
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""Basic information on grid definition."""
|
"""Give short human-readable summary."""
|
||||||
mat_min = np.nanmin(self.material)
|
mat_min = np.nanmin(self.material)
|
||||||
mat_max = np.nanmax(self.material)
|
mat_max = np.nanmax(self.material)
|
||||||
mat_N = self.N_materials
|
mat_N = self.N_materials
|
||||||
|
@ -173,8 +174,8 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Grid file to read. Valid extension is .vti, which will be appended
|
Grid file to read.
|
||||||
if not given.
|
Valid extension is .vti, which will be appended if not given.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -183,14 +184,14 @@ class Grid:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
v = VTK.load(fname if str(fname).endswith('.vti') else str(fname)+'.vti')
|
v = VTK.load(fname if str(fname).endswith('.vti') else str(fname)+'.vti')
|
||||||
comments = v.get_comments()
|
|
||||||
cells = np.array(v.vtk_data.GetDimensions())-1
|
cells = np.array(v.vtk_data.GetDimensions())-1
|
||||||
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
||||||
|
comments = v.comments
|
||||||
|
|
||||||
return Grid(material = v.get('material').reshape(cells,order='F'),
|
return Grid(material = v.get('material').reshape(cells,order='F'),
|
||||||
size = bbox[1] - bbox[0],
|
size = bbox[1] - bbox[0],
|
||||||
origin = bbox[0],
|
origin = bbox[0],
|
||||||
comments=comments)
|
comments = comments)
|
||||||
|
|
||||||
|
|
||||||
@typing. no_type_check
|
@typing. no_type_check
|
||||||
|
@ -643,9 +644,9 @@ class Grid:
|
||||||
Compress with zlib algorithm. Defaults to True.
|
Compress with zlib algorithm. Defaults to True.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
v = VTK.from_image_data(self.cells,self.size,self.origin)
|
v = VTK.from_image_data(self.cells,self.size,self.origin)\
|
||||||
v.add(self.material.flatten(order='F'),'material')
|
.add(self.material.flatten(order='F'),'material')
|
||||||
v.add_comments(self.comments)
|
v.comments += self.comments
|
||||||
|
|
||||||
v.save(fname,parallel=False,compress=compress)
|
v.save(fname,parallel=False,compress=compress)
|
||||||
|
|
||||||
|
@ -681,9 +682,20 @@ class Grid:
|
||||||
header='\n'.join(header), fmt=format_string, comments='')
|
header='\n'.join(header), fmt=format_string, comments='')
|
||||||
|
|
||||||
|
|
||||||
def show(self) -> None:
|
def show(self,
|
||||||
"""Show on screen."""
|
colormap: Colormap = Colormap.from_predefined('cividis')) -> None:
|
||||||
VTK.from_image_data(self.cells,self.size,self.origin).show()
|
"""
|
||||||
|
Show on screen.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
colormap : damask.Colormap, optional
|
||||||
|
Colors used to map material IDs. Defaults to 'cividis'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
VTK.from_image_data(self.cells,self.size,self.origin) \
|
||||||
|
.add(self.material.flatten('F'),'material') \
|
||||||
|
.show('material',colormap)
|
||||||
|
|
||||||
|
|
||||||
def add_primitive(self,
|
def add_primitive(self,
|
||||||
|
|
|
@ -120,10 +120,11 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""Represent."""
|
"""Give short human-readable summary."""
|
||||||
return '\n'.join([Crystal.__repr__(self),
|
return util.srepr([Crystal.__repr__(self),
|
||||||
Rotation.__repr__(self)])
|
Rotation.__repr__(self)])
|
||||||
|
|
||||||
|
|
||||||
def __copy__(self: MyType,
|
def __copy__(self: MyType,
|
||||||
rotation: Union[FloatSequence, Rotation] = None) -> MyType:
|
rotation: Union[FloatSequence, Rotation] = None) -> MyType:
|
||||||
"""Create deep copy."""
|
"""Create deep copy."""
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Result:
|
||||||
'fields': self.fields,
|
'fields': self.fields,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fname = Path(fname).absolute()
|
self.fname = Path(fname).expanduser().absolute()
|
||||||
|
|
||||||
self._protected = True
|
self._protected = True
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ class Result:
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Show summary of file content."""
|
"""Give short human-readable summary."""
|
||||||
with h5py.File(self.fname,'r') as f:
|
with h5py.File(self.fname,'r') as f:
|
||||||
header = [f'Created by {f.attrs["creator"]}',
|
header = [f'Created by {f.attrs["creator"]}',
|
||||||
f' on {f.attrs["created"]}',
|
f' on {f.attrs["created"]}',
|
||||||
|
@ -1635,7 +1635,7 @@ class Result:
|
||||||
else:
|
else:
|
||||||
raise ValueError(f'invalid mode "{mode}"')
|
raise ValueError(f'invalid mode "{mode}"')
|
||||||
|
|
||||||
v.set_comments(util.execution_stamp('Result','export_VTK'))
|
v.comments = util.execution_stamp('Result','export_VTK')
|
||||||
|
|
||||||
N_digits = int(np.floor(np.log10(max(1,int(self.increments[-1][10:])))))+1
|
N_digits = int(np.floor(np.log10(max(1,int(self.increments[-1][10:])))))+1
|
||||||
|
|
||||||
|
@ -1651,12 +1651,12 @@ class Result:
|
||||||
if self.version_minor >= 13:
|
if self.version_minor >= 13:
|
||||||
creator = f.attrs['creator'] if h5py3 else f.attrs['creator'].decode()
|
creator = f.attrs['creator'] if h5py3 else f.attrs['creator'].decode()
|
||||||
created = f.attrs['created'] if h5py3 else f.attrs['created'].decode()
|
created = f.attrs['created'] if h5py3 else f.attrs['created'].decode()
|
||||||
v.add_comments(f'{creator} ({created})')
|
v.comments += f'{creator} ({created})'
|
||||||
|
|
||||||
for inc in util.show_progress(self.visible['increments']):
|
for inc in util.show_progress(self.visible['increments']):
|
||||||
|
|
||||||
u = _read(f['/'.join([inc,'geometry','u_n' if mode.lower() == 'cell' else 'u_p'])])
|
u = _read(f['/'.join([inc,'geometry','u_n' if mode.lower() == 'cell' else 'u_p'])])
|
||||||
v.add(u,'u')
|
v = v.add(u,'u')
|
||||||
|
|
||||||
for ty in ['phase','homogenization']:
|
for ty in ['phase','homogenization']:
|
||||||
for field in self.visible['fields']:
|
for field in self.visible['fields']:
|
||||||
|
@ -1683,7 +1683,7 @@ class Result:
|
||||||
outs[out][at_cell_ho[label]] = data[in_data_ho[label]]
|
outs[out][at_cell_ho[label]] = data[in_data_ho[label]]
|
||||||
|
|
||||||
for label,dataset in outs.items():
|
for label,dataset in outs.items():
|
||||||
v.add(dataset,' / '.join(['/'.join([ty,field,label]),dataset.dtype.metadata['unit']]))
|
v = v.add(dataset,' / '.join(['/'.join([ty,field,label]),dataset.dtype.metadata['unit']]))
|
||||||
|
|
||||||
v.save(f'{self.fname.stem}_inc{inc[10:].zfill(N_digits)}',parallel=parallel)
|
v.save(f'{self.fname.stem}_inc{inc[10:].zfill(N_digits)}',parallel=parallel)
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ class Rotation:
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""Represent rotation as unit quaternion(s)."""
|
"""Give short human-readable summary."""
|
||||||
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
||||||
+ str(self.quaternion)
|
+ str(self.quaternion)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Table:
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""Brief overview."""
|
"""Give short human-readable summary."""
|
||||||
self._relabel('shapes')
|
self._relabel('shapes')
|
||||||
data_repr = self.data.__repr__()
|
data_repr = self.data.__repr__()
|
||||||
self._relabel('uniform')
|
self._relabel('uniform')
|
||||||
|
@ -259,7 +259,7 @@ class Table:
|
||||||
Table data from file.
|
Table data from file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
f = open(fname) if isinstance(fname, (str, Path)) else fname
|
f = open(Path(fname).expanduser()) if isinstance(fname, (str, Path)) else fname
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
|
||||||
comments = []
|
comments = []
|
||||||
|
@ -333,7 +333,7 @@ class Table:
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def labels(self) -> List[Tuple[int, ...]]:
|
def labels(self) -> List[str]:
|
||||||
return list(self.shapes)
|
return list(self.shapes)
|
||||||
|
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@ class Table:
|
||||||
labels += [f'{util.srepr(self.shapes[l],"x")}:{i+1}_{l}' \
|
labels += [f'{util.srepr(self.shapes[l],"x")}:{i+1}_{l}' \
|
||||||
for i in range(np.prod(self.shapes[l]))]
|
for i in range(np.prod(self.shapes[l]))]
|
||||||
|
|
||||||
f = open(fname,'w',newline='\n') if isinstance(fname, (str, Path)) else fname
|
f = open(Path(fname).expanduser(),'w',newline='\n') if isinstance(fname, (str, Path)) else fname
|
||||||
|
|
||||||
f.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+'\n')
|
f.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+'\n')
|
||||||
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False)
|
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import warnings
|
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union, Literal, List
|
from typing import Union, Literal, List, Sequence
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import vtk
|
import vtk
|
||||||
|
@ -13,6 +12,7 @@ from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np
|
||||||
from ._typehints import FloatSequence, IntSequence
|
from ._typehints import FloatSequence, IntSequence
|
||||||
from . import util
|
from . import util
|
||||||
from . import Table
|
from . import Table
|
||||||
|
from . import Colormap
|
||||||
|
|
||||||
|
|
||||||
class VTK:
|
class VTK:
|
||||||
|
@ -38,6 +38,110 @@ class VTK:
|
||||||
self.vtk_data = vtk_data
|
self.vtk_data = vtk_data
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""Give short human-readable summary."""
|
||||||
|
info = [self.vtk_data.__vtkname__]
|
||||||
|
|
||||||
|
for data in ['Cell Data', 'Point Data']:
|
||||||
|
if data == 'Cell Data': info.append(f'\n# cells: {self.N_cells}')
|
||||||
|
if data == 'Point Data': info.append(f'\n# points: {self.N_points}')
|
||||||
|
if data in self.labels:
|
||||||
|
info += [f' - {l}' for l in self.labels[data]]
|
||||||
|
|
||||||
|
return util.srepr(info)
|
||||||
|
|
||||||
|
|
||||||
|
def __eq__(self,
|
||||||
|
other: object) -> bool:
|
||||||
|
"""
|
||||||
|
Equal to other.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
other : damask.VTK
|
||||||
|
VTK to check for equality.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not isinstance(other, VTK):
|
||||||
|
return NotImplemented
|
||||||
|
return self.as_ASCII() == other.as_ASCII()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
if isinstance(self.vtk_data,vtk.vtkImageData):
|
||||||
|
dup = vtk.vtkImageData()
|
||||||
|
elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
|
||||||
|
dup = vtk.vtkUnstructuredGrid()
|
||||||
|
elif isinstance(self.vtk_data,vtk.vtkPolyData):
|
||||||
|
dup = vtk.vtkPolyData()
|
||||||
|
elif isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
|
||||||
|
dup = vtk.vtkRectilinearGrid()
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
dup.DeepCopy(self.vtk_data)
|
||||||
|
|
||||||
|
return VTK(dup)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comments(self) -> List[str]:
|
||||||
|
"""Return the comments."""
|
||||||
|
fielddata = self.vtk_data.GetFieldData()
|
||||||
|
for a in range(fielddata.GetNumberOfArrays()):
|
||||||
|
if fielddata.GetArrayName(a) == 'comments':
|
||||||
|
comments = fielddata.GetAbstractArray(a)
|
||||||
|
return [comments.GetValue(i) for i in range(comments.GetNumberOfValues())]
|
||||||
|
return []
|
||||||
|
|
||||||
|
@comments.setter
|
||||||
|
def comments(self,
|
||||||
|
comments: Union[str, Sequence[str]]):
|
||||||
|
"""
|
||||||
|
Set comments.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
comments : str or list of str
|
||||||
|
Comments.
|
||||||
|
|
||||||
|
"""
|
||||||
|
s = vtk.vtkStringArray()
|
||||||
|
s.SetName('comments')
|
||||||
|
for c in util.tail_repack(comments,self.comments):
|
||||||
|
s.InsertNextValue(c)
|
||||||
|
self.vtk_data.GetFieldData().AddArray(s)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def N_points(self) -> int:
|
||||||
|
"""Number of points in vtkdata."""
|
||||||
|
return self.vtk_data.GetNumberOfPoints()
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def N_cells(self) -> int:
|
||||||
|
"""Number of cells in vtkdata."""
|
||||||
|
return self.vtk_data.GetNumberOfCells()
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def labels(self):
|
||||||
|
"""Labels of datasets."""
|
||||||
|
labels = {}
|
||||||
|
|
||||||
|
cell_data = self.vtk_data.GetCellData()
|
||||||
|
if c := [cell_data.GetArrayName(a) for a in range(cell_data.GetNumberOfArrays())]:
|
||||||
|
labels['Cell Data'] = c
|
||||||
|
|
||||||
|
point_data = self.vtk_data.GetPointData()
|
||||||
|
if p := [point_data.GetArrayName(a) for a in range(point_data.GetNumberOfArrays())]:
|
||||||
|
labels['Point Data'] = p
|
||||||
|
|
||||||
|
return labels
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_image_data(cells: IntSequence,
|
def from_image_data(cells: IntSequence,
|
||||||
size: FloatSequence,
|
size: FloatSequence,
|
||||||
|
@ -70,40 +174,6 @@ class VTK:
|
||||||
return VTK(vtk_data)
|
return VTK(vtk_data)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_rectilinear_grid(grid: np.ndarray,
|
|
||||||
size: FloatSequence,
|
|
||||||
origin: FloatSequence = np.zeros(3)) -> 'VTK':
|
|
||||||
"""
|
|
||||||
Create VTK of type vtk.vtkRectilinearGrid.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
grid : iterable of int, len (3)
|
|
||||||
Number of cells along each dimension.
|
|
||||||
size : iterable of float, len (3)
|
|
||||||
Physical length along each dimension.
|
|
||||||
origin : iterable of float, len (3), optional
|
|
||||||
Coordinates of grid origin.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
new : damask.VTK
|
|
||||||
VTK-based geometry without nodal or cell data.
|
|
||||||
|
|
||||||
"""
|
|
||||||
warnings.warn('Support for vtr files will be removed in DAMASK 3.1.0', DeprecationWarning,2)
|
|
||||||
vtk_data = vtk.vtkRectilinearGrid()
|
|
||||||
vtk_data.SetDimensions(*(np.array(grid)+1))
|
|
||||||
coord = [np_to_vtk(np.linspace(origin[i],origin[i]+size[i],grid[i]+1),deep=True) for i in [0,1,2]]
|
|
||||||
[coord[i].SetName(n) for i,n in enumerate(['x','y','z'])]
|
|
||||||
vtk_data.SetXCoordinates(coord[0])
|
|
||||||
vtk_data.SetYCoordinates(coord[1])
|
|
||||||
vtk_data.SetZCoordinates(coord[2])
|
|
||||||
|
|
||||||
return VTK(vtk_data)
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_unstructured_grid(nodes: np.ndarray,
|
def from_unstructured_grid(nodes: np.ndarray,
|
||||||
connectivity: np.ndarray,
|
connectivity: np.ndarray,
|
||||||
|
@ -115,7 +185,7 @@ class VTK:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
nodes : numpy.ndarray of shape (:,3)
|
nodes : numpy.ndarray, shape (:,3)
|
||||||
Spatial position of the nodes.
|
Spatial position of the nodes.
|
||||||
connectivity : numpy.ndarray of np.dtype = int
|
connectivity : numpy.ndarray of np.dtype = int
|
||||||
Cell connectivity (0-based), first dimension determines #Cells,
|
Cell connectivity (0-based), first dimension determines #Cells,
|
||||||
|
@ -155,7 +225,7 @@ class VTK:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
points : numpy.ndarray of shape (:,3)
|
points : numpy.ndarray, shape (:,3)
|
||||||
Spatial position of the points.
|
Spatial position of the points.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -180,9 +250,36 @@ class VTK:
|
||||||
return VTK(vtk_data)
|
return VTK(vtk_data)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_rectilinear_grid(grid: FloatSequence) -> 'VTK':
|
||||||
|
"""
|
||||||
|
Create VTK of type vtk.vtkRectilinearGrid.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
grid : iterables of floats, len (3)
|
||||||
|
Grid coordinates along x, y, and z directions.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
new : damask.VTK
|
||||||
|
VTK-based geometry without nodal or cell data.
|
||||||
|
|
||||||
|
"""
|
||||||
|
vtk_data = vtk.vtkRectilinearGrid()
|
||||||
|
vtk_data.SetDimensions(*map(len,grid))
|
||||||
|
coord = [np_to_vtk(np.array(grid[i]),deep=True) for i in [0,1,2]]
|
||||||
|
[coord[i].SetName(n) for i,n in enumerate(['x','y','z'])]
|
||||||
|
vtk_data.SetXCoordinates(coord[0])
|
||||||
|
vtk_data.SetYCoordinates(coord[1])
|
||||||
|
vtk_data.SetZCoordinates(coord[2])
|
||||||
|
|
||||||
|
return VTK(vtk_data)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(fname: Union[str, Path],
|
def load(fname: Union[str, Path],
|
||||||
dataset_type: Literal['ImageData', 'UnstructuredGrid', 'PolyData'] = None) -> 'VTK':
|
dataset_type: Literal['ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'] = None) -> 'VTK':
|
||||||
"""
|
"""
|
||||||
Load from VTK file.
|
Load from VTK file.
|
||||||
|
|
||||||
|
@ -190,8 +287,8 @@ class VTK:
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename for reading.
|
Filename for reading.
|
||||||
Valid extensions are .vti, .vtr, .vtu, .vtp, and .vtk.
|
Valid extensions are .vti, .vtu, .vtp, .vtr, and .vtk.
|
||||||
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData'}, optional
|
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'}, optional
|
||||||
Name of the vtk.vtkDataSet subclass when opening a .vtk file.
|
Name of the vtk.vtkDataSet subclass when opening a .vtk file.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -200,40 +297,40 @@ class VTK:
|
||||||
VTK-based geometry from file.
|
VTK-based geometry from file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(fname): # vtk has a strange error handling
|
if not Path(fname).expanduser().is_file(): # vtk has a strange error handling
|
||||||
raise FileNotFoundError(f'file "{fname}" not found')
|
raise FileNotFoundError(f'file "{fname}" not found')
|
||||||
if (ext := Path(fname).suffix) == '.vtk' or dataset_type is not None:
|
if (ext := Path(fname).suffix) == '.vtk' or dataset_type is not None:
|
||||||
reader = vtk.vtkGenericDataObjectReader()
|
reader = vtk.vtkGenericDataObjectReader()
|
||||||
reader.SetFileName(str(fname))
|
reader.SetFileName(str(Path(fname).expanduser()))
|
||||||
if dataset_type is None:
|
if dataset_type is None:
|
||||||
raise TypeError('dataset type for *.vtk file not given')
|
raise TypeError('dataset type for *.vtk file not given')
|
||||||
elif dataset_type.lower().endswith(('imagedata','image_data')):
|
elif dataset_type.lower().endswith(('imagedata','image_data')):
|
||||||
reader.Update()
|
reader.Update()
|
||||||
vtk_data = reader.GetStructuredPointsOutput()
|
vtk_data = reader.GetStructuredPointsOutput()
|
||||||
elif dataset_type.lower().endswith(('rectilineargrid','rectilinear_grid')):
|
|
||||||
reader.Update()
|
|
||||||
vtk_data = reader.GetRectilinearGridOutput()
|
|
||||||
elif dataset_type.lower().endswith(('unstructuredgrid','unstructured_grid')):
|
elif dataset_type.lower().endswith(('unstructuredgrid','unstructured_grid')):
|
||||||
reader.Update()
|
reader.Update()
|
||||||
vtk_data = reader.GetUnstructuredGridOutput()
|
vtk_data = reader.GetUnstructuredGridOutput()
|
||||||
elif dataset_type.lower().endswith(('polydata','poly_data')):
|
elif dataset_type.lower().endswith(('polydata','poly_data')):
|
||||||
reader.Update()
|
reader.Update()
|
||||||
vtk_data = reader.GetPolyDataOutput()
|
vtk_data = reader.GetPolyDataOutput()
|
||||||
|
elif dataset_type.lower().endswith(('rectilineargrid','rectilinear_grid')):
|
||||||
|
reader.Update()
|
||||||
|
vtk_data = reader.GetRectilinearGridOutput()
|
||||||
else:
|
else:
|
||||||
raise TypeError(f'unknown dataset type "{dataset_type}" for vtk file')
|
raise TypeError(f'unknown dataset type "{dataset_type}" for vtk file')
|
||||||
else:
|
else:
|
||||||
if ext == '.vti':
|
if ext == '.vti':
|
||||||
reader = vtk.vtkXMLImageDataReader()
|
reader = vtk.vtkXMLImageDataReader()
|
||||||
elif ext == '.vtr':
|
|
||||||
reader = vtk.vtkXMLRectilinearGridReader()
|
|
||||||
elif ext == '.vtu':
|
elif ext == '.vtu':
|
||||||
reader = vtk.vtkXMLUnstructuredGridReader()
|
reader = vtk.vtkXMLUnstructuredGridReader()
|
||||||
elif ext == '.vtp':
|
elif ext == '.vtp':
|
||||||
reader = vtk.vtkXMLPolyDataReader()
|
reader = vtk.vtkXMLPolyDataReader()
|
||||||
|
elif ext == '.vtr':
|
||||||
|
reader = vtk.vtkXMLRectilinearGridReader()
|
||||||
else:
|
else:
|
||||||
raise TypeError(f'unknown file extension "{ext}"')
|
raise TypeError(f'unknown file extension "{ext}"')
|
||||||
|
|
||||||
reader.SetFileName(str(fname))
|
reader.SetFileName(str(Path(fname).expanduser()))
|
||||||
reader.Update()
|
reader.Update()
|
||||||
vtk_data = reader.GetOutput()
|
vtk_data = reader.GetOutput()
|
||||||
|
|
||||||
|
@ -245,6 +342,17 @@ class VTK:
|
||||||
"""Wrapper for parallel writing."""
|
"""Wrapper for parallel writing."""
|
||||||
writer.Write()
|
writer.Write()
|
||||||
|
|
||||||
|
|
||||||
|
def as_ASCII(self) -> str:
|
||||||
|
"""ASCII representation of the VTK data."""
|
||||||
|
writer = vtk.vtkDataSetWriter()
|
||||||
|
writer.SetHeader(f'# {util.execution_stamp("VTK")}')
|
||||||
|
writer.WriteToOutputStringOn()
|
||||||
|
writer.SetInputData(self.vtk_data)
|
||||||
|
writer.Write()
|
||||||
|
return writer.GetOutputString()
|
||||||
|
|
||||||
|
|
||||||
def save(self,
|
def save(self,
|
||||||
fname: Union[str, Path],
|
fname: Union[str, Path],
|
||||||
parallel: bool = True,
|
parallel: bool = True,
|
||||||
|
@ -264,16 +372,16 @@ class VTK:
|
||||||
"""
|
"""
|
||||||
if isinstance(self.vtk_data,vtk.vtkImageData):
|
if isinstance(self.vtk_data,vtk.vtkImageData):
|
||||||
writer = vtk.vtkXMLImageDataWriter()
|
writer = vtk.vtkXMLImageDataWriter()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
|
|
||||||
writer = vtk.vtkXMLRectilinearGridWriter()
|
|
||||||
elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
|
elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
|
||||||
writer = vtk.vtkXMLUnstructuredGridWriter()
|
writer = vtk.vtkXMLUnstructuredGridWriter()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkPolyData):
|
elif isinstance(self.vtk_data,vtk.vtkPolyData):
|
||||||
writer = vtk.vtkXMLPolyDataWriter()
|
writer = vtk.vtkXMLPolyDataWriter()
|
||||||
|
elif isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
|
||||||
|
writer = vtk.vtkXMLRectilinearGridWriter()
|
||||||
|
|
||||||
default_ext = '.'+writer.GetDefaultFileExtension()
|
default_ext = '.'+writer.GetDefaultFileExtension()
|
||||||
ext = Path(fname).suffix
|
ext = Path(fname).suffix
|
||||||
writer.SetFileName(str(fname)+(default_ext if default_ext != ext else ''))
|
writer.SetFileName(str(Path(fname).expanduser())+(default_ext if default_ext != ext else ''))
|
||||||
|
|
||||||
if compress:
|
if compress:
|
||||||
writer.SetCompressorTypeToZLib()
|
writer.SetCompressorTypeToZLib()
|
||||||
|
@ -293,36 +401,31 @@ class VTK:
|
||||||
|
|
||||||
|
|
||||||
# Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data
|
# Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data
|
||||||
# Needs support for damask.Table
|
|
||||||
def add(self,
|
def add(self,
|
||||||
data: Union[np.ndarray, np.ma.MaskedArray],
|
data: Union[np.ndarray, np.ma.MaskedArray, 'Table'],
|
||||||
label: str = None):
|
label: str = None):
|
||||||
"""
|
"""
|
||||||
Add data to either cells or points.
|
Add data to either cells or points.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
data : numpy.ndarray or numpy.ma.MaskedArray
|
data : numpy.ndarray, numpy.ma.MaskedArray, or damask.Table
|
||||||
Data to add. First dimension needs to match either
|
Data to add. First dimension needs to match either
|
||||||
number of cells or number of points.
|
number of cells or number of points.
|
||||||
label : str
|
label : str, optional if data is damask.Table
|
||||||
Data label.
|
Data label.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
N_points = self.vtk_data.GetNumberOfPoints()
|
|
||||||
N_cells = self.vtk_data.GetNumberOfCells()
|
|
||||||
|
|
||||||
if isinstance(data,np.ndarray):
|
def _add_array(vtk_data,
|
||||||
if label is None:
|
data: np.ndarray,
|
||||||
raise ValueError('no label defined for numpy.ndarray')
|
label: str):
|
||||||
|
|
||||||
N_data = data.shape[0]
|
N_data = data.shape[0]
|
||||||
data_ = (data if not isinstance(data,np.ma.MaskedArray) else
|
data_ = data.reshape(N_data,-1) \
|
||||||
np.where(data.mask,data.fill_value,data)).reshape(N_data,-1)
|
.astype(np.single if data.dtype in [np.double,np.longdouble] else data.dtype)
|
||||||
|
|
||||||
if data_.dtype in [np.double,np.longdouble]:
|
if data.dtype.type is np.str_:
|
||||||
d = np_to_vtk(data_.astype(np.single),deep=True) # avoid large files
|
|
||||||
elif data_.dtype.type is np.str_:
|
|
||||||
d = vtk.vtkStringArray()
|
d = vtk.vtkStringArray()
|
||||||
for s in np.squeeze(data_):
|
for s in np.squeeze(data_):
|
||||||
d.InsertNextValue(s)
|
d.InsertNextValue(s)
|
||||||
|
@ -331,17 +434,29 @@ class VTK:
|
||||||
|
|
||||||
d.SetName(label)
|
d.SetName(label)
|
||||||
|
|
||||||
if N_data == N_points:
|
if N_data == vtk_data.GetNumberOfPoints():
|
||||||
self.vtk_data.GetPointData().AddArray(d)
|
vtk_data.GetPointData().AddArray(d)
|
||||||
elif N_data == N_cells:
|
elif N_data == vtk_data.GetNumberOfCells():
|
||||||
self.vtk_data.GetCellData().AddArray(d)
|
vtk_data.GetCellData().AddArray(d)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f'cell / point count ({N_cells} / {N_points}) differs from data ({N_data})')
|
raise ValueError(f'data count mismatch ({N_data} ≠ {self.N_points} & {self.N_cells})')
|
||||||
|
|
||||||
|
dup = self.copy()
|
||||||
|
if isinstance(data,np.ndarray):
|
||||||
|
if label is not None:
|
||||||
|
_add_array(dup.vtk_data,
|
||||||
|
np.where(data.mask,data.fill_value,data) if isinstance(data,np.ma.MaskedArray) else data,
|
||||||
|
label)
|
||||||
|
else:
|
||||||
|
raise ValueError('no label defined for numpy.ndarray')
|
||||||
elif isinstance(data,Table):
|
elif isinstance(data,Table):
|
||||||
raise NotImplementedError('damask.Table')
|
for l in data.labels:
|
||||||
|
_add_array(dup.vtk_data,data.get(l),l)
|
||||||
else:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
|
return dup
|
||||||
|
|
||||||
|
|
||||||
def get(self,
|
def get(self,
|
||||||
label: str) -> np.ndarray:
|
label: str) -> np.ndarray:
|
||||||
|
@ -386,59 +501,9 @@ class VTK:
|
||||||
raise ValueError(f'array "{label}" not found')
|
raise ValueError(f'array "{label}" not found')
|
||||||
|
|
||||||
|
|
||||||
def get_comments(self) -> List[str]:
|
def show(self,
|
||||||
"""Return the comments."""
|
label: str = None,
|
||||||
fielddata = self.vtk_data.GetFieldData()
|
colormap: Colormap = Colormap.from_predefined('cividis')):
|
||||||
for a in range(fielddata.GetNumberOfArrays()):
|
|
||||||
if fielddata.GetArrayName(a) == 'comments':
|
|
||||||
comments = fielddata.GetAbstractArray(a)
|
|
||||||
return [comments.GetValue(i) for i in range(comments.GetNumberOfValues())]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def set_comments(self,
|
|
||||||
comments: Union[str, List[str]]):
|
|
||||||
"""
|
|
||||||
Set comments.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
comments : str or list of str
|
|
||||||
Comments.
|
|
||||||
|
|
||||||
"""
|
|
||||||
s = vtk.vtkStringArray()
|
|
||||||
s.SetName('comments')
|
|
||||||
for c in [comments] if isinstance(comments,str) else comments:
|
|
||||||
s.InsertNextValue(c)
|
|
||||||
self.vtk_data.GetFieldData().AddArray(s)
|
|
||||||
|
|
||||||
|
|
||||||
def add_comments(self,
|
|
||||||
comments: Union[str, List[str]]):
|
|
||||||
"""
|
|
||||||
Add comments.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
comments : str or list of str
|
|
||||||
Comments to add.
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.set_comments(self.get_comments() + ([comments] if isinstance(comments,str) else comments))
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
"""ASCII representation of the VTK data."""
|
|
||||||
writer = vtk.vtkDataSetWriter()
|
|
||||||
writer.SetHeader(f'# {util.execution_stamp("VTK")}')
|
|
||||||
writer.WriteToOutputStringOn()
|
|
||||||
writer.SetInputData(self.vtk_data)
|
|
||||||
writer.Write()
|
|
||||||
return writer.GetOutputString()
|
|
||||||
|
|
||||||
|
|
||||||
def show(self):
|
|
||||||
"""
|
"""
|
||||||
Render.
|
Render.
|
||||||
|
|
||||||
|
@ -459,8 +524,17 @@ class VTK:
|
||||||
width = 1024
|
width = 1024
|
||||||
height = 768
|
height = 768
|
||||||
|
|
||||||
|
lut = vtk.vtkLookupTable()
|
||||||
|
lut.SetNumberOfTableValues(len(colormap.colors))
|
||||||
|
for i,c in enumerate(colormap.colors):
|
||||||
|
lut.SetTableValue(i,c if len(c)==4 else np.append(c,1.0))
|
||||||
|
lut.Build()
|
||||||
|
|
||||||
|
self.vtk_data.GetCellData().SetActiveScalars(label)
|
||||||
mapper = vtk.vtkDataSetMapper()
|
mapper = vtk.vtkDataSetMapper()
|
||||||
mapper.SetInputData(self.vtk_data)
|
mapper.SetInputData(self.vtk_data)
|
||||||
|
mapper.SetLookupTable(lut)
|
||||||
|
mapper.SetScalarRange(self.vtk_data.GetScalarRange())
|
||||||
|
|
||||||
actor = vtk.vtkActor()
|
actor = vtk.vtkActor()
|
||||||
actor.SetMapper(mapper)
|
actor.SetMapper(mapper)
|
||||||
|
@ -468,7 +542,15 @@ class VTK:
|
||||||
|
|
||||||
ren = vtk.vtkRenderer()
|
ren = vtk.vtkRenderer()
|
||||||
ren.AddActor(actor)
|
ren.AddActor(actor)
|
||||||
|
if label is None:
|
||||||
ren.SetBackground(67/255,128/255,208/255)
|
ren.SetBackground(67/255,128/255,208/255)
|
||||||
|
else:
|
||||||
|
colormap = vtk.vtkScalarBarActor()
|
||||||
|
colormap.SetLookupTable(lut)
|
||||||
|
colormap.SetTitle(label)
|
||||||
|
colormap.SetMaximumWidthInPixels(width//100)
|
||||||
|
ren.AddActor2D(colormap)
|
||||||
|
ren.SetBackground(0.3,0.3,0.3)
|
||||||
|
|
||||||
window = vtk.vtkRenderWindow()
|
window = vtk.vtkRenderWindow()
|
||||||
window.AddRenderer(ren)
|
window.AddRenderer(ren)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import re
|
||||||
import fractions
|
import fractions
|
||||||
from collections import abc
|
from collections import abc
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal
|
from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -33,7 +33,8 @@ __all__=[
|
||||||
'extend_docstring', 'extended_docstring',
|
'extend_docstring', 'extended_docstring',
|
||||||
'Bravais_to_Miller', 'Miller_to_Bravais',
|
'Bravais_to_Miller', 'Miller_to_Bravais',
|
||||||
'DREAM3D_base_group', 'DREAM3D_cell_data_group',
|
'DREAM3D_base_group', 'DREAM3D_cell_data_group',
|
||||||
'dict_prune', 'dict_flatten'
|
'dict_prune', 'dict_flatten',
|
||||||
|
'tail_repack',
|
||||||
]
|
]
|
||||||
|
|
||||||
# https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py
|
# https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py
|
||||||
|
@ -722,6 +723,36 @@ def dict_flatten(d: Dict) -> Dict:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def tail_repack(extended: Union[str, Sequence[str]],
|
||||||
|
existing: List[str] = []) -> List[str]:
|
||||||
|
"""
|
||||||
|
Repack tailing characters into single string if all are new.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
extended : str or list of str
|
||||||
|
Extended string list with potentially autosplitted tailing string relative to `existing`.
|
||||||
|
existing : list of str
|
||||||
|
Base string list.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
repacked : list of str
|
||||||
|
Repacked version of `extended`.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
>>> tail_repack(['a','new','e','n','t','r','y'],['a','new'])
|
||||||
|
['a','new','entry']
|
||||||
|
>>> tail_repack(['a','new','shiny','e','n','t','r','y'],['a','new'])
|
||||||
|
['a','new','shiny','e','n','t','r','y']
|
||||||
|
|
||||||
|
"""
|
||||||
|
return [extended] if isinstance(extended,str) else existing + \
|
||||||
|
([''.join(extended[len(existing):])] if np.prod([len(i) for i in extended[len(existing):]]) == 1 else
|
||||||
|
list(extended[len(existing):]))
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Classes
|
# Classes
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<VTKFile type="RectilinearGrid" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
|
<VTKFile type="RectilinearGrid" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
|
||||||
<RectilinearGrid WholeExtent="0 5 0 6 0 7">
|
<RectilinearGrid WholeExtent="0 3 0 4 0 5">
|
||||||
<Piece Extent="0 5 0 6 0 7">
|
<Piece Extent="0 3 0 4 0 5">
|
||||||
<PointData>
|
<PointData>
|
||||||
<DataArray type="Float32" Name="node" NumberOfComponents="3" format="binary" RangeMin="0" RangeMax="1.268857765318962">
|
<DataArray type="Float32" Name="node" NumberOfComponents="3" format="binary" RangeMin="0" RangeMax="31.016124838541646">
|
||||||
AQAAAACAAADADwAAFQMAAA==eF5Vl7GtFEEQBTeG8wgAhxxux8bEOIsYwDu/M0A6D0JofMAmjU0BF5+d7anXjzP+L6NV4l3pj8S29efL77/35ucO//nwS3zeiL99fTM2+3zPd/u6uTc/d3h67EY8PXB50jxpnjRPmifNk/Kcn4Gn+do18NiNeO3StvPfJk/ztUseuxGvXfI8Hg95mp87PD12I54euD5hu0IeuHbpRly74r9mb9+/7nQvru6T6b5uxHSfPH/PdniaqzseuxHTvT1pnjRPmifNk+ZJec7PsF3Ddg3bxY2Y7rZLnubqbrvkgemOZ7bD01zd8diNmO69K2xXyAPTvXeF7QrzzHa3vbtPpvtt7+7Xjbi73/b1/ex4muleHrsRd3c8aZ40T5onzZPmSXm2q512Dds1bBc34u6uXfI001275IG7e3mqXXma6V4euxF3d3aF7Qp54O7OrrBdYZ5t+/npo7oXV/fJdF83YrpPXt/Pjqe5uuOxGzHd25PmSfOkedI8aZ6U5/wM2zVs17Bd3Ijpbrvkaa7utksemO54Zjs8zdUdj92I6d67wnaFPDDde1fYrjDP9Vare7Heeft7f6n7ZHvn7e/9pe54YHvn1R0PXJ40T5onzZPmSfOkPFu91epuu4bt4kZs77z9vWuXPLC98+puu+RZb7W644HtnVd3PHDNCtsV8sD2zqt77wrzbNvn44e6F1f3yXRfN2K6T17fz46nubrjsRsx3duT5knzpHnSPGmelOf8DNs1bNewXdyI6W675Gmu7rZLHpjueGY7PM3VHY/diOneu8J2hTww3XtX2K4wz3yrD3Uv5p0/7J0/1H1yv/OHuuNp5p0/7J0/1B0PXJ40T5onzZPmSfOkPNv1VmvXsF3DdnEj7ndeu+Rp5p3XLnngfucPdcfTzDt/2Dt/qDseuGaF7Qp54H7n2RW2K8xT3xHdi5/67ui+bsR0nzx/zHZ4mqs7HrsR0709aZ40T5onzZPmSXnWb3YNPDDd8cB0t13yNFd32yUPTHc8sx2eZv0/btAdD0z33hW2K+SB6d67wnYV/wMyiXC6
|
AQAAAACAAACgBQAA+QAAAA==eF5tkoENwjAMBDsCG/XZzON1LJSIf58Dlaoc4mr7k1wXn7rBan69hxZvrWE1L/9fre2b1bx9te9+yw+rea2cqeAX/IJf8OMyh5rZn+541ey8514MT83Oe+7XqKVm5019+AW/4Bd8zhRWM/d4r0c+zs65zrMcLt7k/frMz//Myev68At+wS/46cH9RW/eo13/OMNzPp7D9gVf8DVnZ5+fs4TLd9eHH1az89r3N+N+aNYy75X3hnvKfjd8wTdrzmRej+cbd1FzbnPmRc/Uh2/283z9sJqd93H9u/2wmp03vuALvuCr/fXbfljNzpv68MNqdt7n/QEgMrwB
|
||||||
<InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
|
<InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
|
||||||
<Value index="0">
|
<Value index="0">
|
||||||
0
|
0
|
||||||
</Value>
|
</Value>
|
||||||
<Value index="1">
|
<Value index="1">
|
||||||
1.2688577653
|
31.016124839
|
||||||
</Value>
|
</Value>
|
||||||
</InformationKey>
|
</InformationKey>
|
||||||
</DataArray>
|
</DataArray>
|
||||||
</PointData>
|
</PointData>
|
||||||
<CellData>
|
<CellData>
|
||||||
<DataArray type="Float32" Name="cell" NumberOfComponents="3" format="binary" RangeMin="0.10871961651677305" RangeMax="1.1607924233069467">
|
<DataArray type="Float32" Name="cell" NumberOfComponents="3" format="binary" RangeMin="0" RangeMax="18.788294228055936">
|
||||||
AQAAAACAAADYCQAA8QEAAA==eF5N0CGOFlEQAOHVK0nmBnAFgnn/PLsSsZd4CSQIPDfYZN2iUbMePI4DEMR/BbgDNJ2ve1yZSir18P3jeD6O8eruxfj99s0Ff356Kh63v4o/jNsdP/xzb24+Xbg4XBwuDheHe3//s1wcLg4Xh4vT3fZ2k9NNTjc53eRsnuXibJ7l4mye5T4fq1ycr1a5OF+tk3uMb++u9TnY52Cfg30O9pmLfeZin7nxjYt95mKf2932dpN9bjfZ526e5WKfu3mWi33uV6tc7HO/Wif3GO+vry8+B/sc7HOwz8E+c7HPXOwzN75xsc9c7HO7295uss/tJvvczbNc7HM3z3Kxz/1qlYt97lfr5B7/f/kc7HOwz8E+B/vMxT5zsc/c+MbFPnOxz+1ue7vJPreb7HM3z3Kxz908y8U+96tVLva5X62Te4y7xy/1OdjnYJ+DfQ72mYt95mKfufGNi33mYp/b3fZ2k31uN9nnbp7lYp+7eZaLfe5Xq1zsc79aJ/cYjy9/1Odgn4N9DvY52Gcu9pmLfebGNy72mYt9bnfb2032ud1kn7t5lot97uZZLva5X61ysc/9ap3cY1y//qnPwT4H+xzsc7DPXOwzF/vMjW9c7DMX+9zutreb7HO7yT538ywX+9zNs1zsc79a5WKf+1XyX6K10A4=
|
AQAAAACAAADQAgAAigAAAA==eF5tkQEOgDAIA32CP7L+bE83oMBVJVnWhGMt2bax1gEta3Uv7tb6n0mmtPyt/RymtUZXmQ/fe+Wwo/981pPnDt9iWmt0FWe403tn89NozlkfJyp9hTxCnodpjjtgPsr2Ob7vJiMw8OB/xF1Ma42uWsizkGchTzGtNToZgREYDZP+yFPMrS+Grlfp
|
||||||
<InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
|
<InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
|
||||||
<Value index="0">
|
<Value index="0">
|
||||||
0.10871961652
|
0
|
||||||
</Value>
|
</Value>
|
||||||
<Value index="1">
|
<Value index="1">
|
||||||
1.1607924233
|
18.788294228
|
||||||
</Value>
|
</Value>
|
||||||
</InformationKey>
|
</InformationKey>
|
||||||
</DataArray>
|
</DataArray>
|
||||||
</CellData>
|
</CellData>
|
||||||
<Coordinates>
|
<Coordinates>
|
||||||
<DataArray type="Float64" Name="x" format="binary" RangeMin="0" RangeMax="0.6">
|
<DataArray type="Float64" Name="x" format="binary" RangeMin="0" RangeMax="9">
|
||||||
AQAAAACAAAAwAAAAJwAAAA==eF5jYICAHXKtrwN37LOH0Ofsua4vLrDlug7l37M3BoPH9gCdQxK6
|
AQAAAACAAAAgAAAAFQAAAA==eF5jYEAGH+whtIADhFZyAAAYkwHi
|
||||||
</DataArray>
|
</DataArray>
|
||||||
<DataArray type="Float64" Name="y" format="binary" RangeMin="0" RangeMax="1">
|
<DataArray type="Float64" Name="y" format="binary" RangeMin="0" RangeMax="16">
|
||||||
AQAAAACAAAA4AAAAIgAAAA==eF5jYICAUDA4ag+hr9pDRB9A+U/tV4HBK6j4B3sAk7wQqg==
|
AQAAAACAAAAoAAAAFwAAAA==eF5jYEAGH+whtIADhFaC0gYOAChDAlI=
|
||||||
</DataArray>
|
</DataArray>
|
||||||
<DataArray type="Float64" Name="z" format="binary" RangeMin="0" RangeMax="0.5">
|
<DataArray type="Float64" Name="z" format="binary" RangeMin="0" RangeMax="25">
|
||||||
AQAAAACAAABAAAAALAAAAA==eF5jYICASSqeQLTJHkIfsr+9LReITkP5l+zB3NvXoOK37SG6HtgDANusGUo=
|
AQAAAACAAAAwAAAAGgAAAA==eF5jYEAGH+whtIADhFaC0gZQ2tIBADuFAss=
|
||||||
</DataArray>
|
</DataArray>
|
||||||
</Coordinates>
|
</Coordinates>
|
||||||
</Piece>
|
</Piece>
|
||||||
|
|
|
@ -42,6 +42,10 @@ class TestGrid:
|
||||||
print('patched datetime.datetime.now')
|
print('patched datetime.datetime.now')
|
||||||
|
|
||||||
|
|
||||||
|
def test_show(sef,default,monkeypatch):
|
||||||
|
monkeypatch.delenv('DISPLAY',raising=False)
|
||||||
|
default.show()
|
||||||
|
|
||||||
def test_equal(self,default):
|
def test_equal(self,default):
|
||||||
assert default == default
|
assert default == default
|
||||||
assert not default == 42
|
assert not default == 42
|
||||||
|
|
|
@ -385,7 +385,7 @@ class TestResult:
|
||||||
result.export_VTK(output,parallel=False)
|
result.export_VTK(output,parallel=False)
|
||||||
fname = fname.split('.')[0]+f'_inc{(inc if type(inc) == int else inc[0]):0>2}.vti'
|
fname = fname.split('.')[0]+f'_inc{(inc if type(inc) == int else inc[0]):0>2}.vti'
|
||||||
v = VTK.load(tmp_path/fname)
|
v = VTK.load(tmp_path/fname)
|
||||||
v.set_comments('n/a')
|
v.comments = 'n/a'
|
||||||
v.save(tmp_path/fname,parallel=False)
|
v.save(tmp_path/fname,parallel=False)
|
||||||
with open(fname) as f:
|
with open(fname) as f:
|
||||||
cur = hashlib.md5(f.read().encode()).hexdigest()
|
cur = hashlib.md5(f.read().encode()).hexdigest()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import filecmp
|
import filecmp
|
||||||
import time
|
import time
|
||||||
|
import string
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -8,7 +9,7 @@ import numpy.ma as ma
|
||||||
import vtk
|
import vtk
|
||||||
|
|
||||||
from damask import VTK
|
from damask import VTK
|
||||||
from damask import grid_filters
|
from damask import Table
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def ref_path(ref_path_base):
|
def ref_path(ref_path_base):
|
||||||
|
@ -32,29 +33,44 @@ class TestVTK:
|
||||||
monkeypatch.delenv('DISPLAY',raising=False)
|
monkeypatch.delenv('DISPLAY',raising=False)
|
||||||
default.show()
|
default.show()
|
||||||
|
|
||||||
|
|
||||||
|
def test_imageData(self,tmp_path):
|
||||||
|
cells = np.random.randint(5,10,3)
|
||||||
|
size = np.random.random(3) + 0.1
|
||||||
|
origin = np.random.random(3) - 0.5
|
||||||
|
v = VTK.from_image_data(cells,size,origin)
|
||||||
|
string = str(v)
|
||||||
|
string = v.as_ASCII()
|
||||||
|
v.save(tmp_path/'imageData',False)
|
||||||
|
vtr = VTK.load(tmp_path/'imageData.vti')
|
||||||
|
with open(tmp_path/'imageData.vtk','w') as f:
|
||||||
|
f.write(string)
|
||||||
|
vtk = VTK.load(tmp_path/'imageData.vtk','VTK_imageData')
|
||||||
|
assert (string == vtr.as_ASCII() == vtk.as_ASCII())
|
||||||
|
|
||||||
def test_rectilinearGrid(self,tmp_path):
|
def test_rectilinearGrid(self,tmp_path):
|
||||||
cells = np.random.randint(5,10,3)*2
|
grid = np.sort(np.random.random((3,10)))
|
||||||
size = np.random.random(3) + 1.0
|
v = VTK.from_rectilinear_grid(grid)
|
||||||
origin = np.random.random(3)
|
string = str(v)
|
||||||
v = VTK.from_rectilinear_grid(cells,size,origin)
|
string = v.as_ASCII()
|
||||||
string = v.__repr__()
|
|
||||||
v.save(tmp_path/'rectilinearGrid',False)
|
v.save(tmp_path/'rectilinearGrid',False)
|
||||||
vtr = VTK.load(tmp_path/'rectilinearGrid.vtr')
|
vtr = VTK.load(tmp_path/'rectilinearGrid.vtr')
|
||||||
with open(tmp_path/'rectilinearGrid.vtk','w') as f:
|
with open(tmp_path/'rectilinearGrid.vtk','w') as f:
|
||||||
f.write(string)
|
f.write(string)
|
||||||
vtk = VTK.load(tmp_path/'rectilinearGrid.vtk','VTK_rectilinearGrid')
|
vtk = VTK.load(tmp_path/'rectilinearGrid.vtk','VTK_rectilinearGrid')
|
||||||
assert(string == vtr.__repr__() == vtk.__repr__())
|
assert (string == vtr.as_ASCII() == vtk.as_ASCII())
|
||||||
|
|
||||||
def test_polyData(self,tmp_path):
|
def test_polyData(self,tmp_path):
|
||||||
points = np.random.rand(100,3)
|
points = np.random.rand(100,3)
|
||||||
v = VTK.from_poly_data(points)
|
v = VTK.from_poly_data(points)
|
||||||
string = v.__repr__()
|
string = str(v)
|
||||||
|
string = v.as_ASCII()
|
||||||
v.save(tmp_path/'polyData',False)
|
v.save(tmp_path/'polyData',False)
|
||||||
vtp = VTK.load(tmp_path/'polyData.vtp')
|
vtp = VTK.load(tmp_path/'polyData.vtp')
|
||||||
with open(tmp_path/'polyData.vtk','w') as f:
|
with open(tmp_path/'polyData.vtk','w') as f:
|
||||||
f.write(string)
|
f.write(string)
|
||||||
vtk = VTK.load(tmp_path/'polyData.vtk','polyData')
|
vtk = VTK.load(tmp_path/'polyData.vtk','polyData')
|
||||||
assert(string == vtp.__repr__() == vtk.__repr__())
|
assert(string == vtp.as_ASCII() == vtk.as_ASCII())
|
||||||
|
|
||||||
@pytest.mark.parametrize('cell_type,n',[
|
@pytest.mark.parametrize('cell_type,n',[
|
||||||
('VTK_hexahedron',8),
|
('VTK_hexahedron',8),
|
||||||
|
@ -67,13 +83,14 @@ class TestVTK:
|
||||||
nodes = np.random.rand(n,3)
|
nodes = np.random.rand(n,3)
|
||||||
connectivity = np.random.choice(np.arange(n),n,False).reshape(-1,n)
|
connectivity = np.random.choice(np.arange(n),n,False).reshape(-1,n)
|
||||||
v = VTK.from_unstructured_grid(nodes,connectivity,cell_type)
|
v = VTK.from_unstructured_grid(nodes,connectivity,cell_type)
|
||||||
string = v.__repr__()
|
string = str(v)
|
||||||
|
string = v.as_ASCII()
|
||||||
v.save(tmp_path/'unstructuredGrid',False)
|
v.save(tmp_path/'unstructuredGrid',False)
|
||||||
vtu = VTK.load(tmp_path/'unstructuredGrid.vtu')
|
vtu = VTK.load(tmp_path/'unstructuredGrid.vtu')
|
||||||
with open(tmp_path/'unstructuredGrid.vtk','w') as f:
|
with open(tmp_path/'unstructuredGrid.vtk','w') as f:
|
||||||
f.write(string)
|
f.write(string)
|
||||||
vtk = VTK.load(tmp_path/'unstructuredGrid.vtk','unstructuredgrid')
|
vtk = VTK.load(tmp_path/'unstructuredGrid.vtk','unstructuredgrid')
|
||||||
assert(string == vtu.__repr__() == vtk.__repr__())
|
assert(string == vtu.as_ASCII() == vtk.as_ASCII())
|
||||||
|
|
||||||
|
|
||||||
def test_parallel_out(self,tmp_path):
|
def test_parallel_out(self,tmp_path):
|
||||||
|
@ -97,7 +114,7 @@ class TestVTK:
|
||||||
fname_p = tmp_path/'plain.vtp'
|
fname_p = tmp_path/'plain.vtp'
|
||||||
v.save(fname_c,parallel=False,compress=False)
|
v.save(fname_c,parallel=False,compress=False)
|
||||||
v.save(fname_p,parallel=False,compress=True)
|
v.save(fname_p,parallel=False,compress=True)
|
||||||
assert(VTK.load(fname_c).__repr__() == VTK.load(fname_p).__repr__())
|
assert(VTK.load(fname_c).as_ASCII() == VTK.load(fname_p).as_ASCII())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('fname',['a','a.vtp','a.b','a.b.vtp'])
|
@pytest.mark.parametrize('fname',['a','a.vtp','a.b','a.b.vtp'])
|
||||||
|
@ -148,49 +165,79 @@ class TestVTK:
|
||||||
@pytest.mark.parametrize('N_values',[5*6*7,6*7*8])
|
@pytest.mark.parametrize('N_values',[5*6*7,6*7*8])
|
||||||
def test_add_get(self,default,data_type,shape,N_values):
|
def test_add_get(self,default,data_type,shape,N_values):
|
||||||
data = np.squeeze(np.random.randint(0,100,(N_values,)+shape)).astype(data_type)
|
data = np.squeeze(np.random.randint(0,100,(N_values,)+shape)).astype(data_type)
|
||||||
default.add(data,'data')
|
new = default.add(data,'data')
|
||||||
assert (np.squeeze(data.reshape(N_values,-1)) == default.get('data')).all()
|
assert (np.squeeze(data.reshape(N_values,-1)) == new.get('data')).all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shapes',[{'scalar':(1,),'vector':(3,),'tensor':(3,3)},
|
||||||
|
{'vector':(6,),'tensor':(3,3)},
|
||||||
|
{'tensor':(3,3),'scalar':(1,)}])
|
||||||
|
def test_add_table(self,default,shapes):
|
||||||
|
N = np.random.choice([default.N_points,default.N_cells])
|
||||||
|
d = dict()
|
||||||
|
for k,s in shapes.items():
|
||||||
|
d[k] = dict(shape = s,
|
||||||
|
data = np.random.random(N*np.prod(s)).reshape((N,-1)))
|
||||||
|
new = default.add(Table(np.column_stack([d[k]['data'] for k in shapes.keys()]),shapes))
|
||||||
|
for k,s in shapes.items():
|
||||||
|
assert np.allclose(np.squeeze(d[k]['data']),new.get(k),rtol=1e-7)
|
||||||
|
|
||||||
|
|
||||||
def test_add_masked(self,default):
|
def test_add_masked(self,default):
|
||||||
data = np.random.rand(5*6*7,3)
|
data = np.random.rand(5*6*7,3)
|
||||||
masked = ma.MaskedArray(data,mask=data<.4,fill_value=42.)
|
masked = ma.MaskedArray(data,mask=data<.4,fill_value=42.)
|
||||||
default.add(masked,'D')
|
mask_auto = default.add(masked,'D')
|
||||||
result_masked = str(default)
|
mask_manual = default.add(np.where(masked.mask,masked.fill_value,masked),'D')
|
||||||
default.add(np.where(masked.mask,masked.fill_value,masked),'D')
|
assert mask_manual == mask_auto
|
||||||
assert result_masked == str(default)
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('data_type,shape',[(float,(3,)),
|
||||||
|
(float,(3,3)),
|
||||||
|
(float,(1,)),
|
||||||
|
(int,(4,)),
|
||||||
|
(str,(1,))])
|
||||||
|
@pytest.mark.parametrize('N_values',[5*6*7,6*7*8])
|
||||||
|
def test_labels(self,default,data_type,shape,N_values):
|
||||||
|
data = np.squeeze(np.random.randint(0,100,(N_values,)+shape)).astype(data_type)
|
||||||
|
ALPHABET = np.array(list(string.ascii_lowercase + ' '))
|
||||||
|
label = ''.join(np.random.choice(ALPHABET, size=10))
|
||||||
|
new = default.add(data,label)
|
||||||
|
if N_values == default.N_points: assert label in new.labels['Point Data']
|
||||||
|
if N_values == default.N_cells: assert label in new.labels['Cell Data']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_comments(self,tmp_path,default):
|
def test_comments(self,tmp_path,default):
|
||||||
default.add_comments(['this is a comment'])
|
default.comments += 'this is a comment'
|
||||||
default.save(tmp_path/'with_comments',parallel=False)
|
default.save(tmp_path/'with_comments',parallel=False)
|
||||||
new = VTK.load(tmp_path/'with_comments.vti')
|
new = VTK.load(tmp_path/'with_comments.vti')
|
||||||
assert new.get_comments() == ['this is a comment']
|
assert new.comments == ['this is a comment']
|
||||||
|
|
||||||
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
||||||
def test_compare_reference_polyData(self,update,ref_path,tmp_path):
|
def test_compare_reference_polyData(self,update,ref_path,tmp_path):
|
||||||
points=np.dstack((np.linspace(0.,1.,10),np.linspace(0.,2.,10),np.linspace(-1.,1.,10))).squeeze()
|
points=np.dstack((np.linspace(0.,1.,10),np.linspace(0.,2.,10),np.linspace(-1.,1.,10))).squeeze()
|
||||||
polyData = VTK.from_poly_data(points)
|
polyData = VTK.from_poly_data(points).add(points,'coordinates')
|
||||||
polyData.add(points,'coordinates')
|
|
||||||
if update:
|
if update:
|
||||||
polyData.save(ref_path/'polyData')
|
polyData.save(ref_path/'polyData')
|
||||||
else:
|
else:
|
||||||
reference = VTK.load(ref_path/'polyData.vtp')
|
reference = VTK.load(ref_path/'polyData.vtp')
|
||||||
assert polyData.__repr__() == reference.__repr__() and \
|
assert polyData.as_ASCII() == reference.as_ASCII() and \
|
||||||
np.allclose(polyData.get('coordinates'),points)
|
np.allclose(polyData.get('coordinates'),points)
|
||||||
|
|
||||||
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
||||||
def test_compare_reference_rectilinearGrid(self,update,ref_path,tmp_path):
|
def test_compare_reference_rectilinearGrid(self,update,ref_path,tmp_path):
|
||||||
cells = np.array([5,6,7],int)
|
grid = [np.arange(4)**2.,
|
||||||
size = np.array([.6,1.,.5])
|
np.arange(5)**2.,
|
||||||
rectilinearGrid = VTK.from_rectilinear_grid(cells,size)
|
np.arange(6)**2.] # ParaView renders tetrahedral meshing unless using float coordinates!
|
||||||
c = grid_filters.coordinates0_point(cells,size).reshape(-1,3,order='F')
|
coords = np.stack(np.meshgrid(*grid,indexing='ij'),axis=-1)
|
||||||
n = grid_filters.coordinates0_node(cells,size).reshape(-1,3,order='F')
|
c = coords[:-1,:-1,:-1,:].reshape(-1,3,order='F')
|
||||||
rectilinearGrid.add(np.ascontiguousarray(c),'cell')
|
n = coords[:,:,:,:].reshape(-1,3,order='F')
|
||||||
rectilinearGrid.add(np.ascontiguousarray(n),'node')
|
rectilinearGrid = VTK.from_rectilinear_grid(grid) \
|
||||||
|
.add(np.ascontiguousarray(c),'cell') \
|
||||||
|
.add(np.ascontiguousarray(n),'node')
|
||||||
if update:
|
if update:
|
||||||
rectilinearGrid.save(ref_path/'rectilinearGrid')
|
rectilinearGrid.save(ref_path/'rectilinearGrid')
|
||||||
else:
|
else:
|
||||||
reference = VTK.load(ref_path/'rectilinearGrid.vtr')
|
reference = VTK.load(ref_path/'rectilinearGrid.vtr')
|
||||||
assert rectilinearGrid.__repr__() == reference.__repr__() and \
|
assert rectilinearGrid.as_ASCII() == reference.as_ASCII() and \
|
||||||
np.allclose(rectilinearGrid.get('cell'),c)
|
np.allclose(rectilinearGrid.get('cell'),c)
|
||||||
|
|
Loading…
Reference in New Issue