diff --git a/processing/pre/geom_grainGrowth.py b/processing/pre/geom_grainGrowth.py
index bdf8d8efe..6d1985ee3 100755
--- a/processing/pre/geom_grainGrowth.py
+++ b/processing/pre/geom_grainGrowth.py
@@ -169,7 +169,7 @@ for name in filenames:
# undo any changes involving immutable microstructures
microstructure = np.where(immutable, microstructure_original,microstructure)
- damask.util.croak(geom.update(microstructure[0:grid_original[0],0:grid_original[1],0:grid_original[2]]))
+ geom=geom.duplicate(microstructure[0:grid_original[0],0:grid_original[1],0:grid_original[2]])
geom.add_comments(scriptID + ' ' + ' '.join(sys.argv[1:]))
geom.to_file(sys.stdout if name is None else name,pack=False)
diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py
index e2b317d63..59f3b749d 100644
--- a/python/damask/_colormap.py
+++ b/python/damask/_colormap.py
@@ -280,7 +280,7 @@ class Colormap(mpl.colors.ListedColormap):
colors+=[i]+c
out = [{
- 'Creator':util.version_date('Colormap'),
+ 'Creator':util.execution_stamp('Colormap'),
'ColorSpace':'RGB',
'Name':colormap.name,
'DefaultMap':True,
@@ -296,7 +296,7 @@ class Colormap(mpl.colors.ListedColormap):
def _export_ASCII(colormap,fhandle=None):
"""Write colormap to ASCII table."""
labels = {'RGBA':4} if colormap.colors.shape[1] == 4 else {'RGB': 3}
- t = Table(colormap.colors,labels,f'Creator: {util.version_date("Colormap")}')
+ t = Table(colormap.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
if fhandle is None:
with open(colormap.name.replace(' ','_')+'.txt', 'w') as f:
diff --git a/python/damask/_geom.py b/python/damask/_geom.py
index 6632eb5ed..8a5dfcdc9 100644
--- a/python/damask/_geom.py
+++ b/python/damask/_geom.py
@@ -24,15 +24,15 @@ class Geom:
Parameters
----------
microstructure : numpy.ndarray
- microstructure array (3D)
+ Microstructure array (3D)
size : list or numpy.ndarray
- physical size of the microstructure in meter.
+ Physical size of the microstructure in meter.
origin : list or numpy.ndarray, optional
- physical origin of the microstructure in meter.
+ Physical origin of the microstructure in meter.
homogenization : int, optional
- homogenization index.
+ Homogenization index.
comments : list of str, optional
- comments lines.
+ Comment lines.
"""
self.set_microstructure(microstructure)
@@ -63,63 +63,73 @@ class Geom:
return self.__copy__()
- def update(self,microstructure=None,size=None,origin=None,rescale=False):
+ def duplicate(self,microstructure=None,size=None,origin=None,comments=None,autosize=False):
"""
- Update microstructure and size.
+ Create a duplicate having updated microstructure, size, and origin.
Parameters
----------
microstructure : numpy.ndarray, optional
- microstructure array (3D).
+ Microstructure array (3D).
size : list or numpy.ndarray, optional
- physical size of the microstructure in meter.
+ Physical size of the microstructure in meter.
origin : list or numpy.ndarray, optional
- physical origin of the microstructure in meter.
- rescale : bool, optional
- ignore size parameter and rescale according to change of grid points.
+ Physical origin of the microstructure in meter.
+ comments : list of str, optional
+ Comment lines.
+ autosize : bool, optional
+ Ignore size parameter and rescale according to change of grid points.
"""
- grid_old = self.get_grid()
- size_old = self.get_size()
- origin_old = self.get_origin()
- unique_old = self.N_microstructure
- max_old = np.nanmax(self.microstructure)
+ if size is not None and autosize:
+ raise ValueError('Auto-sizing conflicts with explicit size parameter.')
- if size is not None and rescale:
- raise ValueError('Either set size explicitly or rescale automatically')
+ grid_old = self.get_grid()
+ dup = self.copy()
+ dup.set_microstructure(microstructure)
+ dup.set_origin(origin)
- self.set_microstructure(microstructure)
- self.set_origin(origin)
+ if comments is not None:
+ dup.set_comments(comments)
if size is not None:
- self.set_size(size)
- elif rescale:
- self.set_size(self.get_grid()/grid_old*self.size)
+ dup.set_size(size)
+ elif autosize:
+ dup.set_size(dup.get_grid()/grid_old*self.get_size())
- message = [f'grid a b c: {util.srepr(grid_old," x ")}']
- if np.any(grid_old != self.get_grid()):
- message[-1] = util.delete(message[-1])
- message.append(util.emph(f'grid a b c: {util.srepr(self.get_grid()," x ")}'))
+ return dup
- message.append(f'size x y z: {util.srepr(size_old," x ")}')
- if np.any(size_old != self.get_size()):
- message[-1] = util.delete(message[-1])
- message.append(util.emph(f'size x y z: {util.srepr(self.get_size()," x ")}'))
- message.append(f'origin x y z: {util.srepr(origin_old," ")}')
- if np.any(origin_old != self.get_origin()):
- message[-1] = util.delete(message[-1])
- message.append(util.emph(f'origin x y z: {util.srepr(self.get_origin()," ")}'))
+ def diff(self,other):
+ """
+ Report property differences of self relative to other.
- message.append(f'# microstructures: {unique_old}')
- if unique_old != self.N_microstructure:
- message[-1] = util.delete(message[-1])
- message.append(util.emph(f'# microstructures: {self.N_microstructure}'))
+ Parameters
+ ----------
+ other : Geom
+ Geometry to compare self against.
- message.append(f'max microstructure: {max_old}')
- if max_old != np.nanmax(self.microstructure):
- message[-1] = util.delete(message[-1])
- message.append(util.emph(f'max microstructure: {np.nanmax(self.microstructure)}'))
+ """
+ message = []
+ if np.any(other.get_grid() != self.get_grid()):
+ message.append(util.delete(f'grid a b c: {util.srepr(other.get_grid()," x ")}'))
+ message.append(util.emph( f'grid a b c: {util.srepr( self.get_grid()," x ")}'))
+
+ if np.any(other.get_size() != self.get_size()):
+ message.append(util.delete(f'size x y z: {util.srepr(other.get_size()," x ")}'))
+ message.append(util.emph( f'size x y z: {util.srepr( self.get_size()," x ")}'))
+
+ if np.any(other.get_origin() != self.get_origin()):
+ message.append(util.delete(f'origin x y z: {util.srepr(other.get_origin()," ")}'))
+ message.append(util.emph( f'origin x y z: {util.srepr( self.get_origin()," ")}'))
+
+ if other.N_microstructure != self.N_microstructure:
+ message.append(util.delete(f'# materialpoints: {other.N_microstructure}'))
+ message.append(util.emph( f'# materialpoints: { self.N_microstructure}'))
+
+ if np.nanmax(other.microstructure) != np.nanmax(self.microstructure):
+ message.append(util.delete(f'max materialpoint: {np.nanmax(other.microstructure)}'))
+ message.append(util.emph( f'max materialpoint: {np.nanmax( self.microstructure)}'))
return util.return_message(message)
@@ -131,7 +141,7 @@ class Geom:
Parameters
----------
comments : list of str
- new comments.
+ All comments.
"""
self.comments = []
@@ -145,7 +155,7 @@ class Geom:
Parameters
----------
comments : list of str
- new comments.
+ New comments.
"""
self.comments += [str(c) for c in comments] if isinstance(comments,list) else [str(comments)]
@@ -172,6 +182,10 @@ class Geom:
else:
self.microstructure = np.copy(microstructure)
+ if self.microstructure.dtype in np.sctypes['float'] and \
+ np.all(self.microstructure == self.microstructure.astype(int).astype(float)):
+ self.microstructure = self.microstructure.astype(int)
+
if len(self.microstructure.shape) != 3:
raise ValueError(f'Invalid microstructure shape {microstructure.shape}')
elif self.microstructure.dtype not in np.sctypes['float'] + np.sctypes['int']:
@@ -185,7 +199,7 @@ class Geom:
Parameters
----------
size : list or numpy.ndarray
- physical size of the microstructure in meter.
+ Physical size of the microstructure in meter.
"""
if size is not None:
@@ -202,7 +216,7 @@ class Geom:
Parameters
----------
origin : list or numpy.ndarray
- physical origin of the microstructure in meter
+ Physical origin of the microstructure in meter.
"""
if origin is not None:
@@ -219,12 +233,12 @@ class Geom:
Parameters
----------
homogenization : int
- homogenization index
+ Homogenization index.
"""
if homogenization is not None:
if not isinstance(homogenization,int) or homogenization < 1:
- raise TypeError(f'Invalid homogenization {homogenization}')
+ raise TypeError(f'Invalid homogenization {homogenization}.')
else:
self.homogenization = homogenization
@@ -286,13 +300,16 @@ class Geom:
f = fname
f.seek(0)
- header_length,keyword = f.readline().split()[:2]
- header_length = int(header_length)
- content = f.readlines()
-
+ try:
+ header_length,keyword = f.readline().split()[:2]
+ header_length = int(header_length)
+ except ValueError:
+ header_length,keyword = (-1, 'invalid')
if not keyword.startswith('head') or header_length < 3:
raise TypeError('Header length information missing or invalid')
+ content = f.readlines()
+
comments = []
for i,line in enumerate(content[:header_length]):
items = line.split('#')[0].lower().strip().split()
@@ -345,11 +362,12 @@ class Geom:
"""
v = VTK.from_file(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr')
- grid = np.array(v.geom.GetDimensions())-1
- bbox = np.array(v.geom.GetBounds()).reshape(3,2).T
+ comments = v.get_comments()
+ grid = np.array(v.vtk_data.GetDimensions())-1
+ bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
size = bbox[1] - bbox[0]
- return Geom(v.get('materialpoint').reshape(grid,order='F'),size,bbox[0])
+ return Geom(v.get('materialpoint').reshape(grid,order='F'),size,bbox[0],comments=comments)
@staticmethod
@@ -398,8 +416,9 @@ class Geom:
else:
microstructure = microstructure.reshape(grid)
- creator = util.version_date('Geom','from_Laguerre_tessellation')
- return Geom(microstructure+1,size,homogenization=1,comments=creator)
+ return Geom(microstructure+1,size,homogenization=1,
+ comments=util.execution_stamp('Geom','from_Laguerre_tessellation'),
+ )
@staticmethod
@@ -423,8 +442,9 @@ class Geom:
KDTree = spatial.cKDTree(seeds,boxsize=size) if periodic else spatial.cKDTree(seeds)
devNull,microstructure = KDTree.query(coords)
- creator = util.version_date('Geom','from_Voronoi_tessellation')
- return Geom(microstructure.reshape(grid)+1,size,homogenization=1,comments=creator)
+ return Geom(microstructure.reshape(grid)+1,size,homogenization=1,
+ comments=util.execution_stamp('Geom','from_Voronoi_tessellation'),
+ )
def to_file(self,fname,pack=None):
@@ -511,6 +531,7 @@ class Geom:
"""
v = VTK.from_rectilinearGrid(self.grid,self.size,self.origin)
v.add(self.microstructure.flatten(order='F'),'materialpoint')
+ v.add_comments(self.comments)
if fname:
v.write(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr')
@@ -518,9 +539,9 @@ class Geom:
sys.stdout.write(v.__repr__())
- def show(self):
- """Show raw content (as in file)."""
- f=StringIO()
+ def as_ASCII(self):
+ """Format geometry as human-readable ASCII."""
+ f = StringIO()
self.to_file(f)
f.seek(0)
return ''.join(f.readlines())
@@ -550,10 +571,10 @@ class Geom:
R : damask.Rotation, optional
Rotation of primitive. Defaults to no rotation.
inverse : Boolean, optional
- Retain original microstructure within primitive and fill
- outside. Defaults to False.
+ Retain original microstructure within primitive and fill outside.
+ Defaults to False.
periodic : Boolean, optional
- Repeat primitive over boundaries. Defaults to False.
+ Repeat primitive over boundaries. Defaults to True.
"""
# normalized 'radius' and center
@@ -563,11 +584,11 @@ class Geom:
(np.array(center) - self.origin)/self.size
coords = grid_filters.cell_coord0(self.grid,np.ones(3)) \
- - (np.ones(3)*0.5 if periodic else c) # center if periodic
+ - ((np.ones(3)-(1./self.grid if np.array(center).dtype in np.sctypes['int'] else 0))*0.5 if periodic else c) # periodic center is always at CoG
coords_rot = R.broadcast_to(tuple(self.grid))@coords
- with np.errstate(over='ignore',under='ignore'):
- mask = np.where(np.sum(np.abs(coords_rot/r)**(2.0**exponent),axis=-1) < 1,True,False)
+ with np.errstate(all='ignore'):
+ mask = np.where(np.sum(np.power(coords_rot/r,2.0**exponent),axis=-1) > 1.0,True,False)
if periodic: # translate back to center
mask = np.roll(mask,((c-np.ones(3)*.5)*self.grid).astype(int),(0,1,2))
@@ -575,8 +596,9 @@ class Geom:
fill_ = np.full_like(self.microstructure,np.nanmax(self.microstructure)+1 if fill is None else fill)
ms = np.ma.MaskedArray(fill_,np.logical_not(mask) if inverse else mask)
- self.add_comments(util.version_date('Geom','add_primitive'))
- return self.update(ms)
+ return self.duplicate(ms,
+ comments=self.get_comments()+[util.execution_stamp('Geom','add_primitive')],
+ )
def mirror(self,directions,reflect=False):
@@ -589,10 +611,10 @@ class Geom:
Direction(s) along which the microstructure is mirrored.
Valid entries are 'x', 'y', 'z'.
reflect : bool, optional
- Reflect (include) outermost layers.
+ Reflect (include) outermost layers. Defaults to False.
"""
- valid = {'x','y','z'}
+ valid = ['x','y','z']
if not set(directions).issubset(valid):
raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.')
@@ -606,8 +628,31 @@ class Geom:
if 'x' in directions:
ms = np.concatenate([ms,ms[limits[0]:limits[1]:-1,:,:]],0)
- self.add_comments(util.version_date('Geom','mirror'))
- return self.update(ms,rescale=True)
+ return self.duplicate(ms,
+ comments=self.get_comments()+[util.execution_stamp('Geom','mirror')],
+ autosize=True)
+
+
+ def flip(self,directions):
+ """
+ Flip microstructure along given directions.
+
+ Parameters
+ ----------
+ directions : iterable containing str
+ Direction(s) along which the microstructure is flipped.
+ Valid entries are 'x', 'y', 'z'.
+
+ """
+ valid = ['x','y','z']
+ if not set(directions).issubset(valid):
+ raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.')
+
+ ms = np.flip(self.microstructure, (valid.index(d) for d in directions if d in valid))
+
+ return self.duplicate(ms,
+ comments=self.get_comments()+[util.execution_stamp('Geom','flip')],
+ )
def scale(self,grid,periodic=True):
@@ -622,17 +667,16 @@ class Geom:
Assume geometry to be periodic. Defaults to True.
"""
- self.add_comments(util.version_date('Geom','scale'))
- return self.update(
- ndimage.interpolation.zoom(
- self.microstructure,
- grid/self.get_grid(),
- output=self.microstructure.dtype,
- order=0,
- mode=('wrap' if periodic else 'nearest'),
- prefilter=False
- )
- )
+ return self.duplicate(ndimage.interpolation.zoom(
+ self.microstructure,
+ grid/self.get_grid(),
+ output=self.microstructure.dtype,
+ order=0,
+ mode=('wrap' if periodic else 'nearest'),
+ prefilter=False
+ ),
+ comments=self.get_comments()+[util.execution_stamp('Geom','scale')],
+ )
def clean(self,stencil=3,selection=None,periodic=True):
@@ -657,15 +701,15 @@ class Geom:
else:
return me
- self.add_comments(util.version_date('Geom','clean'))
- return self.update(ndimage.filters.generic_filter(
- self.microstructure,
- mostFrequent,
- size=(stencil if selection is None else stencil//2*2+1,)*3,
- mode=('wrap' if periodic else 'nearest'),
- extra_keywords=dict(selection=selection),
- ).astype(self.microstructure.dtype)
- )
+ return self.duplicate(ndimage.filters.generic_filter(
+ self.microstructure,
+ mostFrequent,
+ size=(stencil if selection is None else stencil//2*2+1,)*3,
+ mode=('wrap' if periodic else 'nearest'),
+ extra_keywords=dict(selection=selection),
+ ).astype(self.microstructure.dtype),
+ comments=self.get_comments()+[util.execution_stamp('Geom','clean')],
+ )
def renumber(self):
@@ -674,8 +718,9 @@ class Geom:
for i, oldID in enumerate(np.unique(self.microstructure)):
renumbered = np.where(self.microstructure == oldID, i+1, renumbered)
- self.add_comments(util.version_date('Geom','renumber'))
- return self.update(renumbered)
+ return self.duplicate(renumbered,
+ comments=self.get_comments()+[util.execution_stamp('Geom','renumber')],
+ )
def rotate(self,R,fill=None):
@@ -709,8 +754,11 @@ class Geom:
origin = self.origin-(np.asarray(microstructure_in.shape)-self.grid)*.5 * self.size/self.grid
- self.add_comments(util.version_date('Geom','rotate'))
- return self.update(microstructure_in,origin=origin,rescale=True)
+ return self.duplicate(microstructure_in,
+ origin=origin,
+ comments=self.get_comments()+[util.execution_stamp('Geom','rotate')],
+ autosize=True,
+ )
def canvas(self,grid=None,offset=None,fill=None):
@@ -724,16 +772,14 @@ class Geom:
offset : numpy.ndarray of shape (3)
Offset (measured in grid points) from old to new microstructure[0,0,0].
fill : int or float, optional
- Microstructure index to fill the corners. Defaults to microstructure.max() + 1.
+ Microstructure index to fill the background. Defaults to microstructure.max() + 1.
"""
- if fill is None: fill = np.nanmax(self.microstructure) + 1
if offset is None: offset = 0
- dtype = float if int(fill) != fill or self.microstructure.dtype==np.float else int
+ if fill is None: fill = np.nanmax(self.microstructure) + 1
+ dtype = float if int(fill) != fill or self.microstructure.dtype in np.sctypes['float'] else int
- canvas = np.full(self.grid if grid is None else grid,
- np.nanmax(self.microstructure)+1 if fill is None else fill,
- dtype)
+ canvas = np.full(self.grid if grid is None else grid,fill,dtype)
LL = np.clip( offset, 0,np.minimum(self.grid, grid+offset))
UR = np.clip( offset+grid, 0,np.minimum(self.grid, grid+offset))
@@ -742,8 +788,11 @@ class Geom:
canvas[ll[0]:ur[0],ll[1]:ur[1],ll[2]:ur[2]] = self.microstructure[LL[0]:UR[0],LL[1]:UR[1],LL[2]:UR[2]]
- self.add_comments(util.version_date('Geom','canvas'))
- return self.update(canvas,origin=self.origin+offset*self.size/self.grid,rescale=True)
+ return self.duplicate(canvas,
+ origin=self.origin+offset*self.size/self.grid,
+ comments=self.get_comments()+[util.execution_stamp('Geom','canvas')],
+ autosize=True,
+ )
def substitute(self,from_microstructure,to_microstructure):
@@ -762,8 +811,9 @@ class Geom:
for from_ms,to_ms in zip(from_microstructure,to_microstructure):
substituted[self.microstructure==from_ms] = to_ms
- self.add_comments(util.version_date('Geom','substitute'))
- return self.update(substituted)
+ return self.duplicate(substituted,
+ comments=self.get_comments()+[util.execution_stamp('Geom','substitute')],
+ )
def vicinity_offset(self,vicinity=1,offset=None,trigger=[],periodic=True):
@@ -804,9 +854,10 @@ class Geom:
mask = ndimage.filters.generic_filter(self.microstructure,
tainted_neighborhood,
size=1+2*vicinity,
- mode=('wrap' if periodic else 'nearest'),
+ mode='wrap' if periodic else 'nearest',
extra_keywords={'trigger':trigger})
microstructure = np.ma.MaskedArray(self.microstructure + offset_, np.logical_not(mask))
- self.add_comments(util.version_date('Geom','vicinity_offset'))
- return self.update(microstructure)
+ return self.duplicate(microstructure,
+ comments=self.get_comments()+[util.execution_stamp('Geom','vicinity_offset')],
+ )
diff --git a/python/damask/_result.py b/python/damask/_result.py
index d739db8f5..1af403ab1 100644
--- a/python/damask/_result.py
+++ b/python/damask/_result.py
@@ -1,6 +1,5 @@
import multiprocessing as mp
import re
-import inspect
import glob
import os
import datetime
@@ -537,7 +536,7 @@ class Result:
'meta': {
'Unit': x['meta']['Unit'],
'Description': f"Absolute value of {x['label']} ({x['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_absolute'
}
}
def add_absolute(self,x):
@@ -565,7 +564,7 @@ class Result:
'meta': {
'Unit': kwargs['unit'],
'Description': f"{kwargs['description']} (formula: {kwargs['formula']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_calculation'
}
}
def add_calculation(self,label,formula,unit='n/a',description=None):
@@ -599,7 +598,7 @@ class Result:
'Description': "Cauchy stress calculated "
f"from {P['label']} ({P['meta']['Description']})"
f" and {F['label']} ({F['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_Cauchy'
}
}
def add_Cauchy(self,P='P',F='F'):
@@ -625,7 +624,7 @@ class Result:
'meta': {
'Unit': T['meta']['Unit'],
'Description': f"Determinant of tensor {T['label']} ({T['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_determinant'
}
}
def add_determinant(self,T):
@@ -649,7 +648,7 @@ class Result:
'meta': {
'Unit': T['meta']['Unit'],
'Description': f"Deviator of tensor {T['label']} ({T['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_deviator'
}
}
def add_deviator(self,T):
@@ -680,7 +679,7 @@ class Result:
'meta' : {
'Unit': T_sym['meta']['Unit'],
'Description': f"{label} eigenvalue of {T_sym['label']} ({T_sym['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_eigenvalue'
}
}
def add_eigenvalue(self,T_sym,eigenvalue='max'):
@@ -713,7 +712,7 @@ class Result:
'Unit': '1',
'Description': f"Eigenvector corresponding to {label} eigenvalue"
f" of {T_sym['label']} ({T_sym['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_eigenvector'
}
}
def add_eigenvector(self,T_sym,eigenvalue='max'):
@@ -746,7 +745,7 @@ class Result:
'Unit': '8-bit RGB',
'Lattice': q['meta']['Lattice'],
'Description': 'Inverse Pole Figure (IPF) colors along sample direction [{} {} {}]'.format(*m),
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_IPF_color'
}
}
def add_IPF_color(self,q,l):
@@ -772,7 +771,7 @@ class Result:
'meta': {
'Unit': T_sym['meta']['Unit'],
'Description': f"Maximum shear component of {T_sym['label']} ({T_sym['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_maximum_shear'
}
}
def add_maximum_shear(self,T_sym):
@@ -799,7 +798,7 @@ class Result:
'meta': {
'Unit': T_sym['meta']['Unit'],
'Description': f"Mises equivalent {t} of {T_sym['label']} ({T_sym['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_Mises'
}
}
def add_Mises(self,T_sym):
@@ -835,7 +834,7 @@ class Result:
'meta': {
'Unit': x['meta']['Unit'],
'Description': f"{o}-norm of {t} {x['label']} ({x['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_norm'
}
}
def add_norm(self,x,ord=None):
@@ -863,7 +862,7 @@ class Result:
'Description': "2. Piola-Kirchhoff stress calculated "
f"from {P['label']} ({P['meta']['Description']})"
f" and {F['label']} ({F['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_PK2'
}
}
def add_PK2(self,P='P',F='F'):
@@ -899,7 +898,7 @@ class Result:
'Unit': '1',
'Description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\
.format('Polar' if polar else 'Cartesian'),
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_pole'
}
}
def add_pole(self,q,p,polar=False):
@@ -927,7 +926,7 @@ class Result:
'meta': {
'Unit': F['meta']['Unit'],
'Description': f"Rotational part of {F['label']} ({F['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_rotational_part'
}
}
def add_rotational_part(self,F):
@@ -951,7 +950,7 @@ class Result:
'meta': {
'Unit': T['meta']['Unit'],
'Description': f"Spherical component of tensor {T['label']} ({T['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_spherical'
}
}
def add_spherical(self,T):
@@ -975,7 +974,7 @@ class Result:
'meta': {
'Unit': F['meta']['Unit'],
'Description': f"Strain tensor of {F['label']} ({F['meta']['Description']})",
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_strain_tensor'
}
}
def add_strain_tensor(self,F='F',t='V',m=0.0):
@@ -1007,7 +1006,7 @@ class Result:
'Unit': F['meta']['Unit'],
'Description': '{} stretch tensor of {} ({})'.format('Left' if t.upper() == 'V' else 'Right',
F['label'],F['meta']['Description']),
- 'Creator': inspect.stack()[0][3][1:]
+ 'Creator': 'add_stretch_tensor'
}
}
def add_stretch_tensor(self,F='F',t='V'):
diff --git a/python/damask/_table.py b/python/damask/_table.py
index b4822bea9..fd8cf0fe3 100644
--- a/python/damask/_table.py
+++ b/python/damask/_table.py
@@ -49,7 +49,7 @@ class Table:
def _add_comment(self,label,shape,info):
if info is not None:
specific = f'{label}{" "+str(shape) if np.prod(shape,dtype=int) > 1 else ""}: {info}'
- general = util.version_date('Table')
+ general = util.execution_stamp('Table')
self.comments.append(f'{specific} / {general}')
@@ -136,7 +136,7 @@ class Table:
content = f.readlines()
- comments = [util.version_date('Table','from_ang')]
+ comments = [util.execution_stamp('Table','from_ang')]
for line in content:
if line.startswith('#'):
comments.append(line.strip())
diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py
index 349e158ca..bbc2d2e69 100644
--- a/python/damask/_vtk.py
+++ b/python/damask/_vtk.py
@@ -20,18 +20,19 @@ class VTK:
High-level interface to VTK.
"""
- def __init__(self,geom):
+ def __init__(self,vtk_data):
"""
- Set geometry and topology.
+ Initialize from vtk dataset.
Parameters
----------
- geom : subclass of vtk.vtkDataSet
- Description of geometry and topology. Valid types are vtk.vtkRectilinearGrid,
- vtk.vtkUnstructuredGrid, or vtk.vtkPolyData.
+ vtk_data : subclass of vtk.vtkDataSet
+ Description of geometry and topology, optionally with attached data.
+ Valid types are vtk.vtkRectilinearGrid, vtk.vtkUnstructuredGrid,
+ or vtk.vtkPolyData.
"""
- self.geom = geom
+ self.vtk_data = vtk_data
@staticmethod
@@ -51,15 +52,15 @@ class VTK:
Spatial origin.
"""
- geom = vtk.vtkRectilinearGrid()
- geom.SetDimensions(*(grid+1))
+ vtk_data = vtk.vtkRectilinearGrid()
+ vtk_data.SetDimensions(*(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'])]
- geom.SetXCoordinates(coord[0])
- geom.SetYCoordinates(coord[1])
- geom.SetZCoordinates(coord[2])
+ vtk_data.SetXCoordinates(coord[0])
+ vtk_data.SetYCoordinates(coord[1])
+ vtk_data.SetZCoordinates(coord[2])
- return VTK(geom)
+ return VTK(vtk_data)
@staticmethod
@@ -87,11 +88,11 @@ class VTK:
connectivity),axis=1).ravel()
cells.SetCells(connectivity.shape[0],np_to_vtkIdTypeArray(T,deep=True))
- geom = vtk.vtkUnstructuredGrid()
- geom.SetPoints(vtk_nodes)
- geom.SetCells(eval(f'vtk.VTK_{cell_type.split("_",1)[-1].upper()}'),cells)
+ vtk_data = vtk.vtkUnstructuredGrid()
+ vtk_data.SetPoints(vtk_nodes)
+ vtk_data.SetCells(eval(f'vtk.VTK_{cell_type.split("_",1)[-1].upper()}'),cells)
- return VTK(geom)
+ return VTK(vtk_data)
@staticmethod
@@ -110,10 +111,10 @@ class VTK:
vtk_points = vtk.vtkPoints()
vtk_points.SetData(np_to_vtk(points))
- geom = vtk.vtkPolyData()
- geom.SetPoints(vtk_points)
+ vtk_data = vtk.vtkPolyData()
+ vtk_data.SetPoints(vtk_points)
- return VTK(geom)
+ return VTK(vtk_data)
@staticmethod
@@ -131,18 +132,20 @@ class VTK:
"""
ext = Path(fname).suffix
- if ext == '.vtk' or dataset_type:
+ if ext == '.vtk' or dataset_type is not None:
reader = vtk.vtkGenericDataObjectReader()
reader.SetFileName(str(fname))
- reader.Update()
if dataset_type is None:
raise TypeError('Dataset type for *.vtk file not given.')
elif dataset_type.lower().endswith('rectilineargrid'):
- geom = reader.GetRectilinearGridOutput()
+ reader.Update()
+ vtk_data = reader.GetRectilinearGridOutput()
elif dataset_type.lower().endswith('unstructuredgrid'):
- geom = reader.GetUnstructuredGridOutput()
+ reader.Update()
+ vtk_data = reader.GetUnstructuredGridOutput()
elif dataset_type.lower().endswith('polydata'):
- geom = reader.GetPolyDataOutput()
+ reader.Update()
+ vtk_data = reader.GetPolyDataOutput()
else:
raise TypeError(f'Unknown dataset type {dataset_type} for vtk file')
else:
@@ -157,9 +160,9 @@ class VTK:
reader.SetFileName(str(fname))
reader.Update()
- geom = reader.GetOutput()
+ vtk_data = reader.GetOutput()
- return VTK(geom)
+ return VTK(vtk_data)
@staticmethod
def _write(writer):
@@ -177,11 +180,11 @@ class VTK:
Write data in parallel background process. Defaults to True.
"""
- if isinstance(self.geom,vtk.vtkRectilinearGrid):
+ if isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
writer = vtk.vtkXMLRectilinearGridWriter()
- elif isinstance(self.geom,vtk.vtkUnstructuredGrid):
+ elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
writer = vtk.vtkXMLUnstructuredGridWriter()
- elif isinstance(self.geom,vtk.vtkPolyData):
+ elif isinstance(self.vtk_data,vtk.vtkPolyData):
writer = vtk.vtkXMLPolyDataWriter()
default_ext = writer.GetDefaultFileExtension()
@@ -191,7 +194,7 @@ class VTK:
writer.SetFileName(str(Path(fname).with_suffix('.'+default_ext)))
writer.SetCompressorTypeToZLib()
writer.SetDataModeToBinary()
- writer.SetInputData(self.geom)
+ writer.SetInputData(self.vtk_data)
if parallel:
try:
@@ -218,8 +221,8 @@ class VTK:
Data label.
"""
- N_points = self.geom.GetNumberOfPoints()
- N_cells = self.geom.GetNumberOfCells()
+ N_points = self.vtk_data.GetNumberOfPoints()
+ N_cells = self.vtk_data.GetNumberOfCells()
if isinstance(data,np.ndarray):
if label is None:
@@ -232,9 +235,9 @@ class VTK:
d.SetName(label)
if data.shape[0] == N_cells:
- self.geom.GetCellData().AddArray(d)
+ self.vtk_data.GetCellData().AddArray(d)
elif data.shape[0] == N_points:
- self.geom.GetPointData().AddArray(d)
+ self.vtk_data.GetPointData().AddArray(d)
else:
raise ValueError(f'Invalid shape {data.shape[0]}')
elif isinstance(data,pd.DataFrame):
@@ -259,22 +262,22 @@ class VTK:
Data label.
"""
- celldata = self.geom.GetCellData()
- for a in range(celldata.GetNumberOfArrays()):
- if celldata.GetArrayName(a) == label:
- return vtk_to_np(celldata.GetArray(a))
+ cell_data = self.vtk_data.GetCellData()
+ for a in range(cell_data.GetNumberOfArrays()):
+ if cell_data.GetArrayName(a) == label:
+ return vtk_to_np(cell_data.GetArray(a))
- pointdata = self.geom.GetPointData()
- for a in range(celldata.GetNumberOfArrays()):
- if pointdata.GetArrayName(a) == label:
- return vtk_to_np(pointdata.GetArray(a))
+ point_data = self.vtk_data.GetPointData()
+ for a in range(point_data.GetNumberOfArrays()):
+ if point_data.GetArrayName(a) == label:
+ return vtk_to_np(point_data.GetArray(a))
raise ValueError(f'array "{label}" not found')
def get_comments(self):
"""Return the comments."""
- fielddata = self.geom.GetFieldData()
+ fielddata = self.vtk_data.GetFieldData()
for a in range(fielddata.GetNumberOfArrays()):
if fielddata.GetArrayName(a) == 'comments':
comments = fielddata.GetAbstractArray(a)
@@ -284,7 +287,7 @@ class VTK:
def set_comments(self,comments):
"""
- Set Comments.
+ Set comments.
Parameters
----------
@@ -296,12 +299,12 @@ class VTK:
s.SetName('comments')
for c in [comments] if isinstance(comments,str) else comments:
s.InsertNextValue(c)
- self.geom.GetFieldData().AddArray(s)
+ self.vtk_data.GetFieldData().AddArray(s)
def add_comments(self,comments):
"""
- Add Comments.
+ Add comments.
Parameters
----------
@@ -309,15 +312,15 @@ class VTK:
Comments to add.
"""
- self.set_comments(self.get_comments + ([comments] if isinstance(comments,str) else comments))
+ self.set_comments(self.get_comments() + ([comments] if isinstance(comments,str) else comments))
def __repr__(self):
"""ASCII representation of the VTK data."""
writer = vtk.vtkDataSetWriter()
- writer.SetHeader(f'# {util.version_date("VTK")}')
+ writer.SetHeader(f'# {util.execution_stamp("VTK")}')
writer.WriteToOutputStringOn()
- writer.SetInputData(self.geom)
+ writer.SetInputData(self.vtk_data)
writer.Write()
return writer.GetOutputString()
@@ -329,7 +332,7 @@ class VTK:
See http://compilatrix.com/article/vtk-1 for further ideas.
"""
mapper = vtk.vtkDataSetMapper()
- mapper.SetInputData(self.geom)
+ mapper.SetInputData(self.vtk_data)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
diff --git a/python/damask/util.py b/python/damask/util.py
index f7c40416e..a04ee47de 100644
--- a/python/damask/util.py
+++ b/python/damask/util.py
@@ -22,7 +22,7 @@ __all__=[
'scale_to_coprime',
'return_message',
'extendableOption',
- 'version_date'
+ 'execution_stamp'
]
####################################################################################################
@@ -178,10 +178,10 @@ def scale_to_coprime(v):
return m
-def version_date(class_name,function_name=None):
- """tbd."""
- _function_name = '' if function_name is None else f'.{function_name}'
+def execution_stamp(class_name,function_name=None):
+ """Timestamp the execution of a (function within a) class."""
now = datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
+ _function_name = '' if function_name is None else f'.{function_name}'
return f'damask.{class_name}{_function_name} v{version} ({now})'
diff --git a/python/tests/conftest.py b/python/tests/conftest.py
index 51da90671..9c58eedd9 100644
--- a/python/tests/conftest.py
+++ b/python/tests/conftest.py
@@ -26,13 +26,13 @@ def patch_datetime_now(monkeypatch):
monkeypatch.setattr(datetime, 'datetime', mydatetime)
@pytest.fixture
-def version_date(monkeypatch):
- """Set damask.util.version_date for reproducible tests results."""
- def version_date(class_name,function_name=None):
+def execution_stamp(monkeypatch):
+ """Set damask.util.execution_stamp for reproducible tests results."""
+ def execution_stamp(class_name,function_name=None):
_function_name = '' if function_name is None else f'.{function_name}'
return f'damask.{class_name}{_function_name} v{patched_version} ({patched_date})'
- monkeypatch.setattr(damask.util, 'version_date', version_date)
+ monkeypatch.setattr(damask.util, 'execution_stamp', execution_stamp)
def pytest_addoption(parser):
diff --git a/python/tests/reference/Geom/clean.vtr b/python/tests/reference/Geom/clean.vtr
deleted file mode 100644
index c76ce3988..000000000
--- a/python/tests/reference/Geom/clean.vtr
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
-
-
-
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
-
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
-
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
-
-
-
-
-
diff --git a/python/tests/reference/Geom/clean_1_1+2+3_False.vtr b/python/tests/reference/Geom/clean_1_1+2+3_False.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_1+2+3_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_1_1+2+3_True.vtr b/python/tests/reference/Geom/clean_1_1+2+3_True.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_1+2+3_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_1_1_False.vtr b/python/tests/reference/Geom/clean_1_1_False.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_1_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_1_1_True.vtr b/python/tests/reference/Geom/clean_1_1_True.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_1_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_1_None_False.vtr b/python/tests/reference/Geom/clean_1_None_False.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_None_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_1_None_True.vtr b/python/tests/reference/Geom/clean_1_None_True.vtr
new file mode 100644
index 000000000..d8a3d4169
--- /dev/null
+++ b/python/tests/reference/Geom/clean_1_None_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_2_1+2+3_False.vtr b/python/tests/reference/Geom/clean_2_1+2+3_False.vtr
new file mode 100644
index 000000000..5400fcdb6
--- /dev/null
+++ b/python/tests/reference/Geom/clean_2_1+2+3_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAZwAAAA==eF7t0rcOgmAAhVEgNmyo2AuoWN//BR04EwsJcfzvcvabL47qxcFOJg177HPAIUdMOeaEU844Z8YFl1wx55obbrnjngceeeKZFxYseeWNd1Z88MkX3/zwy+Z/wf8YOqzX1uEPlgwHCA==
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_2_1+2+3_True.vtr b/python/tests/reference/Geom/clean_2_1+2+3_True.vtr
new file mode 100644
index 000000000..eb2d1b64a
--- /dev/null
+++ b/python/tests/reference/Geom/clean_2_1+2+3_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg==
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_2_1_False.vtr b/python/tests/reference/Geom/clean_2_1_False.vtr
index c76ce3988..e77743025 100644
--- a/python/tests/reference/Geom/clean_2_1_False.vtr
+++ b/python/tests/reference/Geom/clean_2_1_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAZAAAAA==eF7t0scRglAAQEEBAyZUMCuomPtv0ANbgMNw/O+yDbyo1xQFWxkzYZ8DDjliyjEnnHLGOTMuuOSKOQuuueGWO+554JEnnlmy4oVX3ljzzgeffPHND7+Mg50aPmz698MfmvQHCg==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_2_1_True.vtr b/python/tests/reference/Geom/clean_2_1_True.vtr
index c76ce3988..d8a3d4169 100644
--- a/python/tests/reference/Geom/clean_2_1_True.vtr
+++ b/python/tests/reference/Geom/clean_2_1_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_2_None_False.vtr b/python/tests/reference/Geom/clean_2_None_False.vtr
index c76ce3988..068186206 100644
--- a/python/tests/reference/Geom/clean_2_None_False.vtr
+++ b/python/tests/reference/Geom/clean_2_None_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAGwAAAA==eF5jZIAAxlF6lB4AmmmUpogeDUfKaAD7jwDw
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_2_None_True.vtr b/python/tests/reference/Geom/clean_2_None_True.vtr
index fe04087d2..e72fa97e1 100644
--- a/python/tests/reference/Geom/clean_2_None_True.vtr
+++ b/python/tests/reference/Geom/clean_2_None_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAAMQAAAA==eF7tzCEOADAMxLDr/v/o8pLSaTMwi1JJCoAvnGHrN7f/AAAAAAAAAAAAeE8DQvkLTQ==
+
+ AQAAAACAAAAABQAAGQAAAA==eF5jZIAAxlF6lB4AmmmUHqUHkAYA/M8A8Q==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_3_1+2+3_False.vtr b/python/tests/reference/Geom/clean_3_1+2+3_False.vtr
new file mode 100644
index 000000000..5400fcdb6
--- /dev/null
+++ b/python/tests/reference/Geom/clean_3_1+2+3_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAZwAAAA==eF7t0rcOgmAAhVEgNmyo2AuoWN//BR04EwsJcfzvcvabL47qxcFOJg177HPAIUdMOeaEU844Z8YFl1wx55obbrnjngceeeKZFxYseeWNd1Z88MkX3/zwy+Z/wf8YOqzX1uEPlgwHCA==
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_3_1+2+3_True.vtr b/python/tests/reference/Geom/clean_3_1+2+3_True.vtr
new file mode 100644
index 000000000..eb2d1b64a
--- /dev/null
+++ b/python/tests/reference/Geom/clean_3_1+2+3_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg==
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_3_1_False.vtr b/python/tests/reference/Geom/clean_3_1_False.vtr
index c76ce3988..e77743025 100644
--- a/python/tests/reference/Geom/clean_3_1_False.vtr
+++ b/python/tests/reference/Geom/clean_3_1_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAZAAAAA==eF7t0scRglAAQEEBAyZUMCuomPtv0ANbgMNw/O+yDbyo1xQFWxkzYZ8DDjliyjEnnHLGOTMuuOSKOQuuueGWO+554JEnnlmy4oVX3ljzzgeffPHND7+Mg50aPmz698MfmvQHCg==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_3_1_True.vtr b/python/tests/reference/Geom/clean_3_1_True.vtr
index c76ce3988..d8a3d4169 100644
--- a/python/tests/reference/Geom/clean_3_1_True.vtr
+++ b/python/tests/reference/Geom/clean_3_1_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAYwAAAA==eF7t0scBgkAAAEHBgBEwgDmBsf8GfTANCN/bzzSwUa8pCrYyZp8DDjliwjEnnHLGORdMmTHnkiuuuWHBklvuuOeBR5545oVX3nhnxZoPPvnimx9+GQc7GT5sqvjvhz+ZtAcJ
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_3_None_False.vtr b/python/tests/reference/Geom/clean_3_None_False.vtr
index c2ad86f43..f7cd54cc0 100644
--- a/python/tests/reference/Geom/clean_3_None_False.vtr
+++ b/python/tests/reference/Geom/clean_3_None_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAAOgAAAA==eF7t1CEOACAMBMHS/z8aXwNJSagYMe6y8jIislgNtTW9d9oD/PL6r6b3AAAAAAAAAAAA4MYGlRYLYA==
+
+ AQAAAACAAAAABQAAIgAAAA==eF5jZIAAxlGaLJoJjSakntr6hzqN7v9RepSmJw0AC04A9Q==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_3_None_True.vtr b/python/tests/reference/Geom/clean_3_None_True.vtr
index b4d19ebcf..2ebca1695 100644
--- a/python/tests/reference/Geom/clean_3_None_True.vtr
+++ b/python/tests/reference/Geom/clean_3_None_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANwAAAA==eF7t1KERADAMA7Gk+w9dWpYCswiI+R66q6rDzmPa/kj3ALZK/2m6BwAAAAAAAAAAAJMLZrELTQ==
+
+ AQAAAACAAAAABQAALwAAAA==eF5jZIAAxlGaLJoJjSakHpc+cvUTUkdrmlL3j9KU0dROF5TqH2iaVPcDAALOANU=
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_4_1+2+3_False.vtr b/python/tests/reference/Geom/clean_4_1+2+3_False.vtr
new file mode 100644
index 000000000..20f83428f
--- /dev/null
+++ b/python/tests/reference/Geom/clean_4_1+2+3_False.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAcQAAAA==eF7t0rkOglAUBFAxKu6igvsKrv//gxYcm9fQGEPBNKe6yc1kolaZqPEndthljzH7HHDIEceccMoZE8654JIpM6645oZb7rjngUeeeOaFV+YseOOdDz754pthf+3Aqr7rdv9vw3+/NjssU7XDD0/8BuQ=
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_4_1+2+3_True.vtr b/python/tests/reference/Geom/clean_4_1+2+3_True.vtr
new file mode 100644
index 000000000..ae1490bce
--- /dev/null
+++ b/python/tests/reference/Geom/clean_4_1+2+3_True.vtr
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ AQAAAACAAAAABQAAYQAAAA==eF7t0scVglAAAEHgqZgBA2ZExdR/gx6YCpDj38s0sEnUlgR7ccAhR0w55oRTzjjngktmzFlwxTU33LLkjnseeOSJZ15Y8cqaN975YMMnX3zzwy/j4F+GD9u6fvgD+gwHCA==
+
+
+
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
+
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
+
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
+
+
+
+
+
diff --git a/python/tests/reference/Geom/clean_4_1_False.vtr b/python/tests/reference/Geom/clean_4_1_False.vtr
index c76ce3988..e77743025 100644
--- a/python/tests/reference/Geom/clean_4_1_False.vtr
+++ b/python/tests/reference/Geom/clean_4_1_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAZAAAAA==eF7t0scRglAAQEEBAyZUMCuomPtv0ANbgMNw/O+yDbyo1xQFWxkzYZ8DDjliyjEnnHLGOTMuuOSKOQuuueGWO+554JEnnlmy4oVX3ljzzgeffPHND7+Mg50aPmz698MfmvQHCg==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_4_1_True.vtr b/python/tests/reference/Geom/clean_4_1_True.vtr
index c76ce3988..d042cf7b4 100644
--- a/python/tests/reference/Geom/clean_4_1_True.vtr
+++ b/python/tests/reference/Geom/clean_4_1_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAANQAAAA==eF7t1CECACAMxLBj/380fhYwIyK2spWkmnWgt6b3AF65/avfegAAAAAAAAAAAMy0AfYtC2k=
+
+ AQAAAACAAAAABQAAZAAAAA==eF7t0rcSglAARFEHE0bAgBkE8///oAWnF8b2bXP6nRv1mkXBv+xzwCFHHDPmhFPOOOeCSyZMmXHFNTfcMueOex545IlnXliw5JUVa95454NPvvjmh79+DXYzdNisbYdfSqMHMg==
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_4_None_False.vtr b/python/tests/reference/Geom/clean_4_None_False.vtr
index 811d7dc8f..686f5a190 100644
--- a/python/tests/reference/Geom/clean_4_None_False.vtr
+++ b/python/tests/reference/Geom/clean_4_None_False.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAAOQAAAA==eF7t1CESACAMA8HS/z8aX4OgCGDFuszJZERkMTbU1us9gFO6/+q23moPAAAAAAAAAADAnybPzQto
+
+ AQAAAACAAAAABQAAIAAAAA==eF5jZIAAxlF6lB4AmokAPdj1DzRNyP2jNH4aAMufANU=
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/clean_4_None_True.vtr b/python/tests/reference/Geom/clean_4_None_True.vtr
index 88a8643d9..66109b418 100644
--- a/python/tests/reference/Geom/clean_4_None_True.vtr
+++ b/python/tests/reference/Geom/clean_4_None_True.vtr
@@ -1,23 +1,23 @@
-
-
+
+
-
- AQAAAACAAAAALQAAJAAAAA==eF7twwEJAAAMBKH7/qWXY6DgqqmqqqqqqqqqqqqqPnhyUwtB
+
+ AQAAAACAAAAABQAAMAAAAA==eF5jYoAAJhw0IwEalz566aeUptT+oa6fUppS+4e6fkppSu0f6voppSm1HwBAngDh
-
- AQAAAACAAACoAAAAVQAAAA==eF5jYICAWTNBYKU9hN5pb2IMAoeh/JP2EFUXoOKX7dPTQOAaVP6m/dkzIHAHqu4BVPwhVP1jqPwTqL5nUHUvoOpeQtW9hqp7A1X3Dqrugz0ASSZF3Q==
+
+ AQAAAACAAABIAAAAOgAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2D3IeNxx9YfV6DiN+22x9tFGsbchco/sAMA/fQl6g==
-
- AQAAAACAAACYAAAAVgAAAA==eF5jYIAAmeOFQLTGHkLvsQ8Fg6NQ/hn7IjDjIlT8qr1F32MgugGVv2MPMeUBVN1D+8cQBVD1T+3BymSeQ/W9sF8FBq+g+t/Yg4Ut3kHN+WAPAAVdQE4=
+
+ AQAAAACAAAAwAAAAKwAAAA==eF5jYICAvrdbF3w/tsEOQh+wC30iUFisdRLKv2D3MeNxx9YfV+wAD5wZgw==
-
- AQAAAACAAABIAAAAIgAAAA==eF5jYEAGB+wh9AUofQNKP4DST6D0Cyj9Bkp/sAcAAU8I6Q==
+
+ AQAAAACAAAAoAAAAIwAAAA==eF5jYICA3rdbF3w/tsEOQh+wC3kiUFisdRLKv2AHAFVBE/w=
diff --git a/python/tests/reference/Geom/flip_directions=x-y-z.geom b/python/tests/reference/Geom/flip_directions=x-y-z.geom
new file mode 100644
index 000000000..99e55ad7f
--- /dev/null
+++ b/python/tests/reference/Geom/flip_directions=x-y-z.geom
@@ -0,0 +1,25 @@
+4 header
+grid a 8 b 5 c 4
+size x 8e-06 y 5e-06 z 4e-06
+origin x 0.0 y 0.0 z 0.0
+homogenization 1
+40 39 38 37 36 35 34 33
+32 31 30 29 28 27 26 25
+24 23 22 21 20 19 18 17
+16 15 14 13 12 11 10 9
+ 8 7 6 5 4 3 2 1
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+41 40 39 38 37 36 35 34
+33 32 31 30 29 28 27 26
+25 24 23 22 21 20 19 18
+17 16 15 14 13 12 11 10
+ 9 8 7 6 5 4 3 2
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
diff --git a/python/tests/reference/Geom/flip_directions=x.geom b/python/tests/reference/Geom/flip_directions=x.geom
new file mode 100644
index 000000000..9d4ee74a9
--- /dev/null
+++ b/python/tests/reference/Geom/flip_directions=x.geom
@@ -0,0 +1,25 @@
+4 header
+grid a 8 b 5 c 4
+size x 8e-06 y 5e-06 z 4e-06
+origin x 0.0 y 0.0 z 0.0
+homogenization 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 9 8 7 6 5 4 3 2
+17 16 15 14 13 12 11 10
+25 24 23 22 21 20 19 18
+33 32 31 30 29 28 27 26
+41 40 39 38 37 36 35 34
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 8 7 6 5 4 3 2 1
+16 15 14 13 12 11 10 9
+24 23 22 21 20 19 18 17
+32 31 30 29 28 27 26 25
+40 39 38 37 36 35 34 33
diff --git a/python/tests/reference/Geom/flip_directions=y-z.geom b/python/tests/reference/Geom/flip_directions=y-z.geom
new file mode 100644
index 000000000..ecd22f902
--- /dev/null
+++ b/python/tests/reference/Geom/flip_directions=y-z.geom
@@ -0,0 +1,25 @@
+4 header
+grid a 8 b 5 c 4
+size x 8e-06 y 5e-06 z 4e-06
+origin x 0.0 y 0.0 z 0.0
+homogenization 1
+33 34 35 36 37 38 39 40
+25 26 27 28 29 30 31 32
+17 18 19 20 21 22 23 24
+ 9 10 11 12 13 14 15 16
+ 1 2 3 4 5 6 7 8
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+34 35 36 37 38 39 40 41
+26 27 28 29 30 31 32 33
+18 19 20 21 22 23 24 25
+10 11 12 13 14 15 16 17
+ 2 3 4 5 6 7 8 9
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
diff --git a/python/tests/reference/Geom/flip_directions=z-x-y.geom b/python/tests/reference/Geom/flip_directions=z-x-y.geom
new file mode 100644
index 000000000..99e55ad7f
--- /dev/null
+++ b/python/tests/reference/Geom/flip_directions=z-x-y.geom
@@ -0,0 +1,25 @@
+4 header
+grid a 8 b 5 c 4
+size x 8e-06 y 5e-06 z 4e-06
+origin x 0.0 y 0.0 z 0.0
+homogenization 1
+40 39 38 37 36 35 34 33
+32 31 30 29 28 27 26 25
+24 23 22 21 20 19 18 17
+16 15 14 13 12 11 10 9
+ 8 7 6 5 4 3 2 1
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2
+41 40 39 38 37 36 35 34
+33 32 31 30 29 28 27 26
+25 24 23 22 21 20 19 18
+17 16 15 14 13 12 11 10
+ 9 8 7 6 5 4 3 2
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1
diff --git a/python/tests/test_Colormap.py b/python/tests/test_Colormap.py
index 870ff9761..22c208551 100644
--- a/python/tests/test_Colormap.py
+++ b/python/tests/test_Colormap.py
@@ -17,8 +17,8 @@ def reference_dir(reference_dir_base):
class TestColormap:
@pytest.fixture(autouse=True)
- def _version_date(self, version_date):
- print('patched damask.util.version_date')
+ def _execution_stamp(self, execution_stamp):
+ print('patched damask.util.execution_stamp')
def test_conversion(self):
specials = np.array([[0.,0.,0.],
diff --git a/python/tests/test_Geom.py b/python/tests/test_Geom.py
index 479dd43fc..91cb61591 100644
--- a/python/tests/test_Geom.py
+++ b/python/tests/test_Geom.py
@@ -13,7 +13,8 @@ from damask import util
def geom_equal(a,b):
return np.all(a.get_microstructure() == b.get_microstructure()) and \
np.all(a.get_grid() == b.get_grid()) and \
- np.allclose(a.get_size(), b.get_size())
+ np.allclose(a.get_size(), b.get_size()) and \
+ str(a.diff(b)) == str(b.diff(a))
@pytest.fixture
def default():
@@ -32,15 +33,26 @@ def reference_dir(reference_dir_base):
class TestGeom:
- def test_update(self,default):
- modified = default.copy()
- modified.update(
- default.get_microstructure(),
- default.get_size(),
- default.get_origin()
- )
+ @pytest.mark.parametrize('flavor',['plain','explicit'])
+ def test_duplicate(self,default,flavor):
+ if flavor == 'plain':
+ modified = default.duplicate()
+ elif flavor == 'explicit':
+ modified = default.duplicate(
+ default.get_microstructure(),
+ default.get_size(),
+ default.get_origin()
+ )
print(modified)
- assert geom_equal(modified,default)
+ assert geom_equal(default,modified)
+
+ def test_diff_equal(self,default):
+ assert str(default.diff(default)) == ''
+
+ def test_diff_not_equal(self,default):
+ new = Geom(default.microstructure[1:,1:,1:]+1,default.size*.9,np.ones(3)-default.origin,comments=['modified'])
+ assert str(default.diff(new)) != ''
+
@pytest.mark.parametrize('masked',[True,False])
def test_set_microstructure(self,default,masked):
@@ -53,24 +65,25 @@ class TestGeom:
def test_write_read_str(self,default,tmpdir):
default.to_file(str(tmpdir/'default.geom'))
new = Geom.from_file(str(tmpdir/'default.geom'))
- assert geom_equal(new,default)
+ assert geom_equal(default,new)
def test_write_read_file(self,default,tmpdir):
with open(tmpdir/'default.geom','w') as f:
- default.to_file(f)
+ default.to_file(f,pack=True)
with open(tmpdir/'default.geom') as f:
new = Geom.from_file(f)
- assert geom_equal(new,default)
+ assert geom_equal(default,new)
- def test_write_show(self,default,tmpdir):
+ def test_write_as_ASCII(self,default,tmpdir):
with open(tmpdir/'str.geom','w') as f:
- f.write(default.show())
+ f.write(default.as_ASCII())
with open(tmpdir/'str.geom') as f:
new = Geom.from_file(f)
- assert geom_equal(new,default)
+ assert geom_equal(default,new)
def test_read_write_vtr(self,default,tmpdir):
default.to_vtr(tmpdir/'default')
+ print(default.to_vtr())
for _ in range(10):
time.sleep(.2)
if os.path.exists(tmpdir/'default.vtr'): break
@@ -78,6 +91,13 @@ class TestGeom:
new = Geom.from_vtr(tmpdir/'default.vtr')
assert geom_equal(new,default)
+ def test_invalid_geom(self,tmpdir):
+ with open('invalid_file','w') as f:
+ f.write('this is not a valid header')
+ with open('invalid_file','r') as f:
+ with pytest.raises(TypeError):
+ Geom.from_file(f)
+
def test_invalid_vtr(self,tmpdir):
v = VTK.from_rectilinearGrid(np.random.randint(5,10,3)*2,np.random.random(3) + 1.0)
v.write(tmpdir/'no_materialpoint.vtr')
@@ -96,25 +116,25 @@ class TestGeom:
def test_invalid_combination(self,default):
with pytest.raises(ValueError):
- default.update(default.microstructure[1:,1:,1:],size=np.ones(3), rescale=True)
+ default.duplicate(default.microstructure[1:,1:,1:],size=np.ones(3), autosize=True)
def test_invalid_size(self,default):
with pytest.raises(ValueError):
- default.update(default.microstructure[1:,1:,1:],size=np.ones(2))
+ default.duplicate(default.microstructure[1:,1:,1:],size=np.ones(2))
def test_invalid_origin(self,default):
with pytest.raises(ValueError):
- default.update(default.microstructure[1:,1:,1:],origin=np.ones(4))
+ default.duplicate(default.microstructure[1:,1:,1:],origin=np.ones(4))
def test_invalid_microstructure_size(self,default):
microstructure = np.ones((3,3))
with pytest.raises(ValueError):
- default.update(microstructure)
+ default.duplicate(microstructure)
def test_invalid_microstructure_type(self,default):
microstructure = np.random.randint(1,300,(3,4,5))==1
with pytest.raises(TypeError):
- default.update(microstructure)
+ default.duplicate(microstructure)
def test_invalid_homogenization(self,default):
with pytest.raises(TypeError):
@@ -128,31 +148,61 @@ class TestGeom:
]
)
def test_mirror(self,default,update,reference_dir,directions,reflect):
- modified = default.copy()
- modified.mirror(directions,reflect)
+ modified = default.mirror(directions,reflect)
tag = f'directions={"-".join(directions)}_reflect={reflect}'
reference = reference_dir/f'mirror_{tag}.geom'
if update: modified.to_file(reference)
- assert geom_equal(modified,Geom.from_file(reference))
+ assert geom_equal(Geom.from_file(reference),
+ modified)
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
def test_mirror_invalid(self,default,directions):
with pytest.raises(ValueError):
default.mirror(directions)
+
+ @pytest.mark.parametrize('directions',[
+ ['x'],
+ ['x','y','z'],
+ ['z','x','y'],
+ ['y','z'],
+ ]
+ )
+ def test_flip(self,default,update,reference_dir,directions):
+ modified = default.flip(directions)
+ tag = f'directions={"-".join(directions)}'
+ reference = reference_dir/f'flip_{tag}.geom'
+ if update: modified.to_file(reference)
+ assert geom_equal(Geom.from_file(reference),
+ modified)
+
+ def test_flip_invariant(self,default):
+ assert geom_equal(default,default.flip([]))
+
+ @pytest.mark.parametrize('direction',[['x'],['x','y']])
+ def test_flip_double(self,default,direction):
+ assert geom_equal(default,default.flip(direction).flip(direction))
+
+ @pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
+ def test_flip_invalid(self,default,directions):
+ with pytest.raises(ValueError):
+ default.flip(directions)
+
+
@pytest.mark.parametrize('stencil',[1,2,3,4])
- @pytest.mark.parametrize('selection',[None,1,2])
+ @pytest.mark.parametrize('selection',[None,[1],[1,2,3]])
@pytest.mark.parametrize('periodic',[True,False])
- def test_clean(self,update,reference_dir,stencil,selection,periodic):
- current = Geom.from_vtr((reference_dir/'clean').with_suffix('.vtr'))
- current.clean(stencil,None if selection is None else [selection],periodic)
- reference = reference_dir/f'clean_{stencil}_{selection}_{periodic}'
- if update and stencil !=1:
+ def test_clean(self,default,update,reference_dir,stencil,selection,periodic):
+ current = default.clean(stencil,selection,periodic)
+ reference = reference_dir/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}'
+ if update and stencil > 1:
current.to_vtr(reference)
for _ in range(10):
time.sleep(.2)
if os.path.exists(reference.with_suffix('.vtr')): break
- assert geom_equal(current,Geom.from_vtr(reference if stencil !=1 else reference_dir/'clean'))
+ assert geom_equal(Geom.from_vtr(reference) if stencil > 1 else default,
+ current
+ )
@pytest.mark.parametrize('grid',[
(10,11,10),
@@ -164,33 +214,29 @@ class TestGeom:
]
)
def test_scale(self,default,update,reference_dir,grid):
- modified = default.copy()
- modified.scale(grid)
+ modified = default.scale(grid)
tag = f'grid={util.srepr(grid,"-")}'
reference = reference_dir/f'scale_{tag}.geom'
if update: modified.to_file(reference)
- assert geom_equal(modified,Geom.from_file(reference))
+ assert geom_equal(Geom.from_file(reference),
+ modified)
def test_renumber(self,default):
- modified = default.copy()
- microstructure = modified.get_microstructure()
+ microstructure = default.get_microstructure()
for m in np.unique(microstructure):
microstructure[microstructure==m] = microstructure.max() + np.random.randint(1,30)
- modified.update(microstructure)
+ modified = default.duplicate(microstructure)
assert not geom_equal(modified,default)
- modified.renumber()
- assert geom_equal(modified,default)
+ assert geom_equal(default,
+ modified.renumber())
def test_substitute(self,default):
- modified = default.copy()
- microstructure = modified.get_microstructure()
offset = np.random.randint(1,500)
- microstructure += offset
- modified.update(microstructure)
+ modified = default.duplicate(default.get_microstructure() + offset)
assert not geom_equal(modified,default)
- modified.substitute(np.arange(default.microstructure.max())+1+offset,
- np.arange(default.microstructure.max())+1)
- assert geom_equal(modified,default)
+ assert geom_equal(default,
+ modified.substitute(np.arange(default.microstructure.max())+1+offset,
+ np.arange(default.microstructure.max())+1))
@pytest.mark.parametrize('axis_angle',[np.array([1,0,0,86.7]), np.array([0,1,0,90.4]), np.array([0,0,1,90]),
np.array([1,0,0,175]),np.array([0,-1,0,178]),np.array([0,0,1,180])])
@@ -198,40 +244,58 @@ class TestGeom:
modified = default.copy()
for i in range(np.rint(360/axis_angle[3]).astype(int)):
modified.rotate(Rotation.from_axis_angle(axis_angle,degrees=True))
- assert geom_equal(modified,default)
+ assert geom_equal(default,modified)
@pytest.mark.parametrize('Eulers',[[32.0,68.0,21.0],
[0.0,32.0,240.0]])
def test_rotate(self,default,update,reference_dir,Eulers):
- modified = default.copy()
- modified.rotate(Rotation.from_Eulers(Eulers,degrees=True))
+ modified = default.rotate(Rotation.from_Eulers(Eulers,degrees=True))
tag = f'Eulers={util.srepr(Eulers,"-")}'
reference = reference_dir/f'rotate_{tag}.geom'
if update: modified.to_file(reference)
- assert geom_equal(modified,Geom.from_file(reference))
+ assert geom_equal(Geom.from_file(reference),
+ modified)
def test_canvas(self,default):
+ grid = default.grid
grid_add = np.random.randint(0,30,(3))
- modified = default.copy()
- modified.canvas(modified.grid + grid_add)
- e = default.grid
- assert np.all(modified.microstructure[:e[0],:e[1],:e[2]] == default.microstructure)
+ modified = default.canvas(grid + grid_add)
+ assert np.all(modified.microstructure[:grid[0],:grid[1],:grid[2]] == default.microstructure)
- @pytest.mark.parametrize('center1,center2',[(np.random.random(3)*.5,np.random.random(3)),
+ @pytest.mark.parametrize('center1,center2',[(np.random.random(3)*.5,np.random.random()*8),
(np.random.randint(4,8,(3)),np.random.randint(9,12,(3)))])
@pytest.mark.parametrize('diameter',[np.random.random(3)*.5,
- np.random.randint(4,10,(3))])
- def test_add_primitive(self,diameter,center1,center2):
+ np.random.randint(4,10,(3)),
+ np.random.rand(),
+ np.random.randint(30)])
+ @pytest.mark.parametrize('exponent',[np.random.random(3)*.5,
+ np.random.randint(4,10,(3)),
+ np.random.rand()*4,
+ np.random.randint(20)])
+ def test_add_primitive_shift(self,center1,center2,diameter,exponent):
"""Same volume fraction for periodic microstructures and different center."""
o = np.random.random(3)-.5
g = np.random.randint(8,32,(3))
s = np.random.random(3)+.5
- G_1 = Geom(np.ones(g,'i'),s,o)
- G_2 = Geom(np.ones(g,'i'),s,o)
- G_1.add_primitive(diameter,center1,1)
- G_2.add_primitive(diameter,center2,1)
+ G_1 = Geom(np.ones(g,'i'),s,o).add_primitive(diameter,center1,exponent)
+ G_2 = Geom(np.ones(g,'i'),s,o).add_primitive(diameter,center2,exponent)
assert np.count_nonzero(G_1.microstructure!=2) == np.count_nonzero(G_2.microstructure!=2)
+ @pytest.mark.parametrize('center',[np.random.randint(4,10,(3)),
+ np.random.randint(2,10),
+ np.random.rand()*4,
+ np.random.rand(3)*10])
+ @pytest.mark.parametrize('inverse',[True,False])
+ @pytest.mark.parametrize('periodic',[True,False])
+ def test_add_primitive_rotation(self,center,inverse,periodic):
+ """Rotation should not change result for sphere (except for discretization errors)."""
+ g = np.array([32,32,32])
+ fill = np.random.randint(10)+2
+ eu=np.array([np.random.randint(4),np.random.randint(2),np.random.randint(4)])*.5*np.pi
+ G_1 = Geom(np.ones(g,'i'),[1.,1.,1.]).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic)
+ G_2 = Geom(np.ones(g,'i'),[1.,1.,1.]).add_primitive(.3,center,1,fill,Rotation.from_Eulers(eu),inverse,periodic=periodic)
+ assert geom_equal(G_1,G_2)
+
@pytest.mark.parametrize('trigger',[[1],[]])
def test_vicinity_offset(self,trigger):
offset = np.random.randint(2,4)
@@ -248,8 +312,7 @@ class TestGeom:
if len(trigger) > 0:
m2[m==1] = 1
- geom = Geom(m,np.random.rand(3))
- geom.vicinity_offset(vicinity,offset,trigger=trigger)
+ geom = Geom(m,np.random.rand(3)).vicinity_offset(vicinity,offset,trigger=trigger)
assert np.all(m2==geom.microstructure)
diff --git a/python/tests/test_VTK.py b/python/tests/test_VTK.py
index 91ff4033c..ab9c4fa8b 100644
--- a/python/tests/test_VTK.py
+++ b/python/tests/test_VTK.py
@@ -13,8 +13,19 @@ def reference_dir(reference_dir_base):
"""Directory containing reference results."""
return reference_dir_base/'VTK'
+@pytest.fixture
+def default():
+ """Simple VTK."""
+ grid = np.array([5,6,7],int)
+ size = np.array([.6,1.,.5])
+ return VTK.from_rectilinearGrid(grid,size)
+
class TestVTK:
+ @pytest.fixture(autouse=True)
+ def _execution_stamp(self, execution_stamp):
+ print('patched damask.util.execution_stamp')
+
def test_rectilinearGrid(self,tmp_path):
grid = np.random.randint(5,10,3)*2
size = np.random.random(3) + 1.0
@@ -77,10 +88,36 @@ class TestVTK:
@pytest.mark.parametrize('name,dataset_type',[('this_file_does_not_exist.vtk', None),
('this_file_does_not_exist.vtk','vtk'),
('this_file_does_not_exist.vtx', None)])
- def test_invalid_dataset_type(self,dataset_type,name):
+ def test_invalid_dataset_type(self,name,dataset_type):
with pytest.raises(TypeError):
- VTK.from_file('this_file_does_not_exist.vtk',dataset_type)
+ VTK.from_file(name,dataset_type)
+ def test_invalid_extension_write(self,default):
+ with pytest.raises(ValueError):
+ default.write('default.txt')
+
+ def test_invalid_get(self,default):
+ with pytest.raises(ValueError):
+ default.get('does_not_exist')
+
+ def test_invalid_add_shape(self,default):
+ with pytest.raises(ValueError):
+ default.add(np.ones(3),'valid')
+
+ def test_invalid_add_missing_label(self,default):
+ data = np.random.randint(9,size=np.prod(np.array(default.vtk_data.GetDimensions())-1))
+ with pytest.raises(ValueError):
+ default.add(data)
+
+ def test_invalid_add_type(self,default):
+ with pytest.raises(TypeError):
+ default.add('invalid_type','valid')
+
+ def test_comments(self,tmp_path,default):
+ default.add_comments(['this is a comment'])
+ default.write(tmp_path/'with_comments',parallel=False)
+ new = VTK.from_file(tmp_path/'with_comments.vtr')
+ assert new.get_comments() == ['this is a comment']
def test_compare_reference_polyData(self,update,reference_dir,tmp_path):
points=np.dstack((np.linspace(0.,1.,10),np.linspace(0.,2.,10),np.linspace(-1.,1.,10))).squeeze()
@@ -90,7 +127,8 @@ class TestVTK:
polyData.write(reference_dir/'polyData')
else:
reference = VTK.from_file(reference_dir/'polyData.vtp')
- assert polyData.__repr__() == reference.__repr__()
+ assert polyData.__repr__() == reference.__repr__() and \
+ np.allclose(polyData.get('coordinates'),points)
def test_compare_reference_rectilinearGrid(self,update,reference_dir,tmp_path):
grid = np.array([5,6,7],int)
@@ -104,5 +142,5 @@ class TestVTK:
rectilinearGrid.write(reference_dir/'rectilinearGrid')
else:
reference = VTK.from_file(reference_dir/'rectilinearGrid.vtr')
- assert rectilinearGrid.__repr__() == reference.__repr__()
-
+ assert rectilinearGrid.__repr__() == reference.__repr__() and \
+ np.allclose(rectilinearGrid.get('cell'),c)