DAMASK_EICMD/python/tests/test_Result.py

696 lines
31 KiB
Python
Raw Normal View History

2021-04-01 17:17:27 +05:30
import bz2
import pickle
2020-05-26 02:35:31 +05:30
import time
import shutil
import os
import sys
2021-04-03 11:01:31 +05:30
import hashlib
2022-11-07 03:46:30 +05:30
import fnmatch
import random
2020-05-26 02:35:31 +05:30
from datetime import datetime
import pytest
from vtkmodules.vtkIOXML import vtkXMLImageDataReader
from vtkmodules.vtkCommonCore import vtkVersion
try:
from vtkmodules.vtkIOXdmf2 import vtkXdmfReader
except ImportError:
vtkXdmfReader=None # noqa type: ignore
2022-11-07 03:46:30 +05:30
import h5py
import numpy as np
from damask import Result
from damask import Orientation
2021-08-18 13:39:47 +05:30
from damask import VTK
from damask import tensor
from damask import mechanics
2020-07-31 20:20:01 +05:30
from damask import grid_filters
2021-09-02 11:34:09 +05:30
@pytest.fixture
def default(tmp_path,res_path):
"""Small Result file in temp location for modification."""
fname = '12grains6x7x8_tensionY.hdf5'
shutil.copy(res_path/fname,tmp_path)
return Result(tmp_path/fname).view(times=20.0)
@pytest.fixture
def single_phase(tmp_path,res_path):
"""Single phase Result file in temp location for modification."""
fname = '6grains6x7x8_single_phase_tensionY.hdf5'
shutil.copy(res_path/fname,tmp_path)
2020-07-31 20:20:01 +05:30
return Result(tmp_path/fname)
@pytest.fixture
def res_path(res_path_base):
"""Directory containing testing resources."""
return res_path_base/'Result'
2021-04-01 17:17:27 +05:30
def dict_equal(d1, d2):
for k in d1:
if (k not in d2):
return False
else:
if type(d1[k]) is dict:
return dict_equal(d1[k],d2[k])
else:
if not np.allclose(d1[k],d2[k]):
return False
return True
2023-12-05 11:44:14 +05:30
@pytest.fixture
def h5py_dataset_iterator():
"""Iterate over all datasets in an HDF5 file."""
def _h5py_dataset_iterator(g, prefix=''):
for key,item in g.items():
path = '/'.join([prefix, key])
2023-12-05 11:44:14 +05:30
if isinstance(item, h5py.Dataset): # test for dataset
yield (path, item)
elif isinstance(item, h5py.Group): # test for group (go down)
yield from _h5py_dataset_iterator(item, path)
return _h5py_dataset_iterator
class TestResult:
2019-12-04 10:29:52 +05:30
2020-04-21 14:47:15 +05:30
def test_self_report(self,default):
print(default)
2021-01-13 19:27:58 +05:30
def test_view_all(self,default):
default = Result(default.fname)
2023-12-18 21:13:41 +05:30
a = default.view_all().get('F')
2021-04-03 16:41:20 +05:30
assert dict_equal(a,default.view(increments='*').get('F'))
assert dict_equal(a,default.view(increments=default.increments_in_range(0,np.iinfo(int).max)).get('F'))
2020-05-23 14:08:25 +05:30
assert dict_equal(a,default.view(times=True).get('F'))
assert dict_equal(a,default.view(times='*').get('F'))
assert dict_equal(a,default.view(times=default.times_in_range(0.0,np.inf)).get('F'))
2020-05-23 14:08:25 +05:30
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
2021-01-13 19:27:58 +05:30
def test_view_none(self,default,what):
2022-03-05 00:30:33 +05:30
n0 = default.view(**{what:False})
n1 = default.view(**{what:[]})
2020-05-23 14:08:25 +05:30
label = 'increments' if what == 'times' else what
2020-05-23 14:08:25 +05:30
assert n0.get('F') is n1.get('F') is None and \
len(n0._visible[label]) == len(n1._visible[label]) == 0
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
2021-01-13 19:27:58 +05:30
def test_view_more(self,default,what):
2022-03-05 00:30:33 +05:30
empty = default.view(**{what:False})
2020-05-23 14:08:25 +05:30
2022-03-05 00:30:33 +05:30
a = empty.view_more(**{what:'*'}).get('F')
b = empty.view_more(**{what:True}).get('F')
2020-05-23 14:08:25 +05:30
2021-04-03 16:41:20 +05:30
assert dict_equal(a,b)
2020-05-23 14:08:25 +05:30
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
2021-01-13 19:27:58 +05:30
def test_view_less(self,default,what):
2022-03-05 00:30:33 +05:30
full = default.view(**{what:True})
2020-05-23 14:08:25 +05:30
2022-03-05 00:30:33 +05:30
n0 = full.view_less(**{what:'*'})
n1 = full.view_less(**{what:True})
label = 'increments' if what == 'times' else what
2020-05-23 14:08:25 +05:30
assert n0.get('F') is n1.get('F') is None and \
len(n0._visible[label]) == len(n1._visible[label]) == 0
2020-05-23 14:08:25 +05:30
2022-11-11 11:33:14 +05:30
def test_view_invalid_incstimes(self,default):
with pytest.raises(ValueError):
default.view(increments=0,times=0)
@pytest.mark.parametrize('inc',[0,10])
@pytest.mark.parametrize('sign',[+1,-1])
def test_view_approxtimes(self,default,inc,sign):
eps = sign*1e-3
times = list(default._times.values())
assert [default._increments[inc]] == default.view(times=times[inc]+eps)._visible['increments']
2022-11-11 11:33:14 +05:30
2023-12-18 21:13:41 +05:30
def test_getters(self,default):
file_layout = default.get('non-existing',prune=False,flatten=False)
for i in default.increments:
increment = file_layout[f'increment_{i}']
fields = []
for p in default.phases:
phase = increment['phase'][p]
for f in default.fields:
fields.append(phase[f])
for h in default.homogenizations:
homogenization = increment['homogenization'][h]
for f in default.fields:
fields.append(homogenization[f])
assert len(fields) > 0
def test_add_invalid(self,default):
default.add_absolute('xxxx')
2019-12-04 10:45:32 +05:30
def test_add_absolute(self,default):
2020-11-06 02:44:49 +05:30
default.add_absolute('F_e')
2021-04-03 16:41:20 +05:30
in_memory = np.abs(default.place('F_e'))
in_file = default.place('|F_e|')
assert np.allclose(in_memory,in_file)
2020-02-01 14:12:04 +05:30
2021-08-18 14:52:16 +05:30
@pytest.mark.parametrize('mode',
2022-03-27 02:43:54 +05:30
['direct',pytest.param('function',marks=pytest.mark.xfail(sys.platform in ['darwin','win32'], reason='n/a'))])
def test_add_calculation(self,default,tmp_path,mode):
2020-07-31 20:20:01 +05:30
if mode == 'direct':
2021-04-25 11:17:00 +05:30
default.add_calculation('2.0*np.abs(#F#)-1.0','x','-','my notes')
2020-07-31 20:20:01 +05:30
else:
with open(tmp_path/'f.py','w') as f:
f.write("import numpy as np\ndef my_func(field):\n return 2.0*np.abs(field)-1.0\n")
sys.path.insert(0,str(tmp_path))
import f
default.enable_user_function(f.my_func)
2021-04-25 11:17:00 +05:30
default.add_calculation('my_func(#F#)','x','-','my notes')
2020-07-31 20:20:01 +05:30
2021-04-03 16:41:20 +05:30
in_memory = 2.0*np.abs(default.place('F'))-1.0
in_file = default.place('x')
2020-02-01 14:12:04 +05:30
assert np.allclose(in_memory,in_file)
2021-08-17 01:01:17 +05:30
def test_add_calculation_invalid(self,default):
default.add_calculation('np.linalg.norm(#F#,axis=0)','wrong_dim')
assert default.get('wrong_dim') is None
2020-11-18 03:26:22 +05:30
def test_add_stress_Cauchy(self,default):
default.add_stress_Cauchy('P','F')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.stress_Cauchy(default.place('P'), default.place('F'))
in_file = default.place('sigma')
assert np.allclose(in_memory,in_file)
2019-12-04 10:19:43 +05:30
def test_add_determinant(self,default):
default.add_determinant('P')
2021-04-03 16:41:20 +05:30
in_memory = np.linalg.det(default.place('P'))
in_file = default.place('det(P)')
2019-12-04 10:19:43 +05:30
assert np.allclose(in_memory,in_file)
2019-12-04 10:45:32 +05:30
def test_add_deviator(self,default):
default.add_deviator('P')
2021-04-03 16:41:20 +05:30
in_memory = tensor.deviatoric(default.place('P'))
in_file = default.place('s_P')
2019-12-04 10:45:32 +05:30
assert np.allclose(in_memory,in_file)
@pytest.mark.parametrize('eigenvalue,function',[('max',np.amax),('min',np.amin)])
def test_add_eigenvalue(self,default,eigenvalue,function):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
default.add_eigenvalue('sigma',eigenvalue)
2021-04-03 16:41:20 +05:30
in_memory = function(tensor.eigenvalues(default.place('sigma')),axis=1)
in_file = default.place(f'lambda_{eigenvalue}(sigma)')
2020-02-15 21:25:12 +05:30
assert np.allclose(in_memory,in_file)
@pytest.mark.parametrize('eigenvalue,idx',[('max',2),('mid',1),('min',0)])
def test_add_eigenvector(self,default,eigenvalue,idx):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
default.add_eigenvector('sigma',eigenvalue)
2021-04-03 16:41:20 +05:30
in_memory = tensor.eigenvectors(default.place('sigma'))[:,idx]
in_file = default.place(f'v_{eigenvalue}(sigma)')
2020-02-15 21:25:12 +05:30
assert np.allclose(in_memory,in_file)
2020-05-23 12:43:45 +05:30
@pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]])
2020-07-01 01:13:57 +05:30
def test_add_IPF_color(self,default,d):
2020-12-02 19:15:47 +05:30
default.add_IPF_color(d,'O')
qu = default.place('O')
crystal_structure = qu.dtype.metadata['lattice']
c = Orientation(rotation=qu,lattice=crystal_structure)
in_memory = np.uint8(c.IPF_color(np.array(d))*255)
in_file = default.place('IPFcolor_({} {} {})'.format(*d))
2020-05-23 12:43:45 +05:30
assert np.allclose(in_memory,in_file)
2020-02-15 21:25:12 +05:30
def test_add_maximum_shear(self,default):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
2020-02-15 21:25:12 +05:30
default.add_maximum_shear('sigma')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.maximum_shear(default.place('sigma'))
in_file = default.place('max_shear(sigma)')
2020-02-15 21:25:12 +05:30
assert np.allclose(in_memory,in_file)
2020-02-16 14:34:33 +05:30
def test_add_Mises_strain(self,default):
t = ['V','U'][np.random.randint(0,2)]
m = np.random.random()*2.0 - 1.0
2020-11-16 05:42:23 +05:30
default.add_strain('F',t,m)
2020-06-25 01:04:51 +05:30
label = f'epsilon_{t}^{m}(F)'
2020-11-18 03:26:22 +05:30
default.add_equivalent_Mises(label)
2021-04-03 16:41:20 +05:30
in_memory = mechanics.equivalent_strain_Mises(default.place(label))
in_file = default.place(label+'_vM')
2020-02-16 14:34:33 +05:30
assert np.allclose(in_memory,in_file)
def test_add_Mises_stress(self,default):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
default.add_equivalent_Mises('sigma')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.equivalent_stress_Mises(default.place('sigma'))
in_file = default.place('sigma_vM')
2020-02-16 14:34:33 +05:30
assert np.allclose(in_memory,in_file)
2020-11-06 04:17:37 +05:30
def test_add_Mises_invalid(self,default):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
2021-04-25 11:17:00 +05:30
default.add_calculation('#sigma#','sigma_y',unit='y')
2020-11-18 03:26:22 +05:30
default.add_equivalent_Mises('sigma_y')
assert default.get('sigma_y_vM') is None
2020-11-06 04:17:37 +05:30
def test_add_Mises_stress_strain(self,default):
2020-11-18 03:26:22 +05:30
default.add_stress_Cauchy('P','F')
2021-04-25 11:17:00 +05:30
default.add_calculation('#sigma#','sigma_y',unit='y')
default.add_calculation('#sigma#','sigma_x',unit='x')
2020-11-18 03:26:22 +05:30
default.add_equivalent_Mises('sigma_y',kind='strain')
default.add_equivalent_Mises('sigma_x',kind='stress')
2021-04-03 16:41:20 +05:30
assert not np.allclose(default.place('sigma_y_vM'),default.place('sigma_x_vM'))
@pytest.mark.parametrize('ord',[1,2])
@pytest.mark.parametrize('dataset,axis',[('F',(1,2)),('xi_sl',(1,))])
def test_add_norm(self,default,ord,dataset,axis):
default.add_norm(dataset,ord)
in_memory = np.linalg.norm(default.place(dataset),ord=ord,axis=axis,keepdims=True)
in_file = default.place(f'|{dataset}|_{ord}')
2019-12-04 10:19:43 +05:30
assert np.allclose(in_memory,in_file)
2020-11-18 03:26:22 +05:30
def test_add_stress_second_Piola_Kirchhoff(self,default):
default.add_stress_second_Piola_Kirchhoff('P','F')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.stress_second_Piola_Kirchhoff(default.place('P'),default.place('F'))
in_file = default.place('S')
assert np.allclose(in_memory,in_file)
@pytest.mark.parametrize('options',[{'uvw':[1,0,0],'with_symmetry':False},
{'uvw':[1,1,0],'with_symmetry':True},
{'hkl':[0,1,1],'with_symmetry':True},
{'hkl':[1,1,1],'with_symmetry':False},
])
2021-07-18 21:33:36 +05:30
def test_add_pole(self,default,options):
default.add_pole(**options)
rot = default.place('O')
in_memory = Orientation(rot,lattice=rot.dtype.metadata['lattice']).to_pole(**options)
2022-05-11 10:32:20 +05:30
brackets = [['[[]','[]]'],'()','⟨⟩','{}'][('hkl' in options)*1+(options['with_symmetry'])*2] # escape fnmatch
label = 'p^{}{} {} {}{}'.format(brackets[0],
*(list(options.values())[0]),
brackets[-1])
in_file = default.place(label)
2020-05-23 11:49:08 +05:30
assert np.allclose(in_memory,in_file)
2020-11-20 03:16:52 +05:30
def test_add_rotation(self,default):
default.add_rotation('F')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.rotation(default.place('F')).as_matrix()
in_file = default.place('R(F)')
assert np.allclose(in_memory,in_file)
def test_add_spherical(self,default):
default.add_spherical('P')
2021-04-03 16:41:20 +05:30
in_memory = tensor.spherical(default.place('P'),False)
in_file = default.place('p_P')
assert np.allclose(in_memory,in_file)
2020-02-16 14:34:33 +05:30
def test_add_strain(self,default):
t = ['V','U'][np.random.randint(0,2)]
m = np.random.random()*2.0 - 1.0
2020-11-16 05:42:23 +05:30
default.add_strain('F',t,m)
2020-06-25 01:04:51 +05:30
label = f'epsilon_{t}^{m}(F)'
2021-04-03 16:41:20 +05:30
in_memory = mechanics.strain(default.place('F'),t,m)
in_file = default.place(label)
2020-02-16 14:34:33 +05:30
assert np.allclose(in_memory,in_file)
def test_add_stretch_right(self,default):
default.add_stretch_tensor('F','U')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.stretch_right(default.place('F'))
in_file = default.place('U(F)')
assert np.allclose(in_memory,in_file)
def test_add_stretch_left(self,default):
default.add_stretch_tensor('F','V')
2021-04-03 16:41:20 +05:30
in_memory = mechanics.stretch_left(default.place('F'))
in_file = default.place('V(F)')
assert np.allclose(in_memory,in_file)
2020-05-22 22:34:02 +05:30
2021-08-18 14:14:04 +05:30
def test_add_invalid_dataset(self,default):
with pytest.raises(TypeError):
default.add_calculation('#invalid#*2')
def test_add_generic_grid_invalid(self,res_path):
result = Result(res_path/'4grains2x4x3_compressionY.hdf5')
2021-08-18 14:14:04 +05:30
with pytest.raises(NotImplementedError):
result.add_curl('F')
@pytest.mark.parametrize('shape',['vector','tensor'])
def test_add_curl(self,default,shape):
if shape == 'vector': default.add_calculation('#F#[:,:,0]','x','1','just a vector')
if shape == 'tensor': default.add_calculation('#F#[:,:,:]','x','1','just a tensor')
x = default.place('x')
default.add_curl('x')
in_file = default.place('curl(x)')
in_memory = grid_filters.curl(default.size,x.reshape(tuple(default.cells)+x.shape[1:])).reshape(in_file.shape)
assert (in_file == in_memory).all()
@pytest.mark.parametrize('shape',['vector','tensor'])
def test_add_divergence(self,default,shape):
if shape == 'vector': default.add_calculation('#F#[:,:,0]','x','1','just a vector')
if shape == 'tensor': default.add_calculation('#F#[:,:,:]','x','1','just a tensor')
x = default.place('x')
default.add_divergence('x')
in_file = default.place('divergence(x)')
in_memory = grid_filters.divergence(default.size,x.reshape(tuple(default.cells)+x.shape[1:])).reshape(in_file.shape)
assert (in_file == in_memory).all()
@pytest.mark.parametrize('shape',['scalar','pseudo_scalar','vector'])
def test_add_gradient(self,default,shape):
if shape == 'pseudo_scalar': default.add_calculation('#F#[:,0,0:1]','x','1','a pseudo scalar')
if shape == 'scalar': default.add_calculation('#F#[:,0,0]','x','1','just a scalar')
if shape == 'vector': default.add_calculation('#F#[:,:,1]','x','1','just a vector')
x = default.place('x').reshape((np.prod(default.cells),-1))
default.add_gradient('x')
in_file = default.place('gradient(x)')
in_memory = grid_filters.gradient(default.size,x.reshape(tuple(default.cells)+x.shape[1:])).reshape(in_file.shape)
assert (in_file == in_memory).all()
@pytest.mark.parametrize('overwrite',['off','on'])
def test_add_overwrite(self,default,overwrite):
last = default.view(increments=-1)
2021-04-05 11:23:19 +05:30
last.add_stress_Cauchy()
created_first = last.place('sigma').dtype.metadata['created']
created_first = datetime.strptime(created_first,'%Y-%m-%d %H:%M:%S%z')
last = last.view(protected=overwrite != 'on')
time.sleep(2)
try:
2021-04-25 11:17:00 +05:30
last.add_calculation('#sigma#*0.0+311.','sigma','not the Cauchy stress')
except ValueError:
pass
created_second = last.place('sigma').dtype.metadata['created']
created_second = datetime.strptime(created_second,'%Y-%m-%d %H:%M:%S%z')
2021-04-04 22:02:17 +05:30
if overwrite == 'on':
assert created_first < created_second and np.allclose(last.place('sigma'),311.)
else:
2021-04-05 11:23:19 +05:30
assert created_first == created_second and not np.allclose(last.place('sigma'),311.)
2020-06-01 15:03:22 +05:30
@pytest.mark.parametrize('allowed',['off','on'])
def test_rename(self,default,allowed):
if allowed == 'on':
2021-04-03 16:41:20 +05:30
F = default.place('F')
2021-12-17 15:01:41 +05:30
default = default.view(protected=False)
2020-06-01 15:03:22 +05:30
default.rename('F','new_name')
2021-04-03 16:41:20 +05:30
assert np.all(F == default.place('new_name'))
2021-12-17 15:01:41 +05:30
default = default.view(protected=True)
2020-06-01 15:03:22 +05:30
with pytest.raises(PermissionError):
default.rename('P','another_new_name')
@pytest.mark.parametrize('allowed',['off','on'])
def test_remove(self,default,allowed):
if allowed == 'on':
2021-12-17 15:01:41 +05:30
unsafe = default.view(protected=False)
unsafe.remove('F')
assert unsafe.get('F') is None
else:
with pytest.raises(PermissionError):
default.remove('F')
2020-07-31 20:20:01 +05:30
@pytest.mark.parametrize('mode',['cell','node'])
def test_coordinates(self,default,mode):
2022-02-02 13:40:24 +05:30
if mode == 'cell':
a = grid_filters.coordinates0_point(default.cells,default.size,default.origin)
b = default.coordinates0_point.reshape(tuple(default.cells)+(3,),order='F')
elif mode == 'node':
a = grid_filters.coordinates0_node(default.cells,default.size,default.origin)
b = default.coordinates0_node.reshape(tuple(default.cells+1)+(3,),order='F')
assert np.allclose(a,b)
2020-07-31 20:20:01 +05:30
2021-08-18 14:47:13 +05:30
@pytest.mark.parametrize('output',['F','*',['P'],['P','F']],ids=range(4))
2023-02-04 16:17:54 +05:30
@pytest.mark.parametrize('fname',['12grains6x7x8_tensionY.hdf5',
'4grains2x4x3_compressionY.hdf5',
'6grains6x7x8_single_phase_tensionY.hdf5'],ids=range(3))
2021-04-03 11:01:31 +05:30
@pytest.mark.parametrize('inc',[4,0],ids=range(2))
@pytest.mark.xfail(vtkVersion.GetVTKMajorVersion()<9, reason='missing "Direction" attribute')
def test_export_vtk(self,request,tmp_path,res_path,update,patch_execution_stamp,patch_datetime_now,output,fname,inc):
result = Result(res_path/fname).view(increments=inc)
result.export_VTK(output,target_dir=tmp_path,parallel=False)
fname = fname.split('.')[0]+f'_inc{(inc if type(inc) == int else inc[0]):0>2}.vti'
2021-08-18 13:39:47 +05:30
v = VTK.load(tmp_path/fname)
v.comments = ['n/a']
2021-08-18 13:39:47 +05:30
v.save(tmp_path/fname,parallel=False)
with open(tmp_path/fname,'rb') as f:
cur = hashlib.md5(f.read()).hexdigest()
2021-04-03 11:01:31 +05:30
if update:
with open((res_path/'export_VTK'/request.node.name).with_suffix('.md5'),'w') as f:
f.write(cur+'\n')
with open((res_path/'export_VTK'/request.node.name).with_suffix('.md5')) as f:
assert cur == f.read().strip('\n')
2021-04-26 03:52:37 +05:30
@pytest.mark.parametrize('mode',['point','cell'])
@pytest.mark.parametrize('output',[False,True])
def test_export_vtk_marc(self,tmp_path,res_path,mode,output):
2021-04-26 03:52:37 +05:30
os.chdir(tmp_path)
result = Result(res_path/'check_compile_job1.hdf5')
2021-06-17 21:56:37 +05:30
result.export_VTK(output,mode)
2021-04-26 03:52:37 +05:30
def test_marc_coordinates(self,res_path):
result = Result(res_path/'check_compile_job1.hdf5').view(increments=-1)
2021-04-26 03:52:37 +05:30
c_n = result.coordinates0_node + result.get('u_n')
c_p = result.coordinates0_point + result.get('u_p')
assert len(c_n) > len(c_p)
2020-10-27 21:16:08 +05:30
@pytest.mark.parametrize('mode',['point','cell'])
def test_vtk_mode(self,tmp_path,single_phase,mode):
os.chdir(tmp_path)
2021-06-17 21:56:37 +05:30
single_phase.export_VTK(mode=mode)
2020-10-27 21:16:08 +05:30
2021-08-18 13:06:28 +05:30
def test_vtk_invalid_mode(self,single_phase):
with pytest.raises(ValueError):
single_phase.export_VTK(mode='invalid')
def test_vtk_custom_path(self,tmp_path,single_phase):
export_dir = tmp_path/'export_dir'
single_phase.export_VTK(mode='point',target_dir=export_dir,parallel=False)
assert set(os.listdir(export_dir)) == set([f'{single_phase.fname.stem}_inc{i:02}.vtp' for i in range(0,40+1,4)])
2021-08-18 13:06:28 +05:30
def test_export_DREAM3D(self,tmp_path,res_path,h5py_dataset_iterator):
result = Result(res_path/'2phase_irregularGrid_tensionX_material.hdf5').view(increments=0) # compare the initial data only
2023-05-04 14:19:52 +05:30
result.export_DREAM3D(target_dir=tmp_path)
2023-04-26 16:31:18 +05:30
def ignore(path):
# features present in reference but not in exported file
for i in ['Pipeline','StatsGeneratorDataContainer','Grain Data',
'BoundaryCells','FeatureIds','IPFColor','NumFeatures']:
if path.find(i) >= 0: return True
return False
with h5py.File(res_path/'2phase_irregularGrid.dream3d','r') as ref, \
h5py.File(tmp_path/'2phase_irregularGrid_tensionX_material_inc0.dream3d','r') as cur:
for (path,dset) in h5py_dataset_iterator(ref):
if ignore(path): continue
if path.find('PhaseName') < 0:
assert np.array_equal(dset,cur[path])
else:
c = [_.decode() for _ in cur[path]]
r = ['Unknown Phase Type'] + result._phases
assert c == r
grp = str(path).rpartition('/')[0]
for attr in ref[grp].attrs:
assert np.array_equal(ref[grp].attrs[attr],cur[grp].attrs[attr])
for attr in dset.attrs:
assert np.array_equal(dset.attrs[attr],cur[path].attrs[attr])
def test_export_DREAM3D_invalid(self,res_path):
with pytest.raises(NotImplementedError):
Result(res_path/'4grains2x4x3_compressionY.hdf5').export_DREAM3D()
2023-04-26 16:31:18 +05:30
def test_XDMF_datatypes(self,tmp_path,single_phase,update,res_path):
for what,shape in {'scalar':(),'vector':(3,),'tensor':(3,3),'matrix':(12,)}.items():
for dtype in ['f4','f8','i1','i2','i4','i8','u1','u2','u4','u8']:
single_phase.add_calculation(f"np.ones(np.shape(#F#)[0:1]+{shape},'{dtype}')",f'{what}_{dtype}')
xdmf_path = tmp_path/single_phase.fname.with_suffix('.xdmf').name
single_phase.export_XDMF(target_dir=tmp_path)
if update:
shutil.copy(xdmf_path,res_path/xdmf_path.name)
assert sorted(open(xdmf_path).read()) == sorted(open(res_path/xdmf_path.name).read())
@pytest.mark.skipif(not hasattr(vtkXdmfReader,'GetOutput'),reason='https://discourse.vtk.org/t/2450')
def test_XDMF_shape(self,tmp_path,single_phase):
single_phase.export_XDMF(target_dir=single_phase.fname.parent)
fname = single_phase.fname.with_suffix('.xdmf')
reader_xdmf = vtkXdmfReader()
2021-06-19 00:41:01 +05:30
reader_xdmf.SetFileName(fname)
reader_xdmf.Update()
dim_xdmf = reader_xdmf.GetOutput().GetDimensions()
bounds_xdmf = reader_xdmf.GetOutput().GetBounds()
single_phase.view(increments=0).export_VTK(target_dir=single_phase.fname.parent,parallel=False)
fname = single_phase.fname.with_name(single_phase.fname.stem+'_inc00.vti')
reader_vti = vtkXMLImageDataReader()
2021-09-02 11:34:09 +05:30
reader_vti.SetFileName(fname)
reader_vti.Update()
dim_vti = reader_vti.GetOutput().GetDimensions()
bounds_vti = reader_vti.GetOutput().GetBounds()
assert dim_vti == dim_xdmf and bounds_vti == bounds_xdmf
def test_XDMF_invalid(self,default):
with pytest.raises(NotImplementedError):
2021-06-17 21:56:37 +05:30
default.export_XDMF()
2021-04-01 17:17:27 +05:30
def test_XDMF_custom_path(self,single_phase,tmp_path):
os.chdir(tmp_path)
single_phase.export_XDMF()
assert single_phase.fname.with_suffix('.xdmf').name in os.listdir(tmp_path)
export_dir = tmp_path/'export_dir'
single_phase.export_XDMF(target_dir=export_dir)
assert single_phase.fname.with_suffix('.xdmf').name in os.listdir(export_dir)
@pytest.mark.skipif(not hasattr(vtkXdmfReader,'GetOutput'),reason='https://discourse.vtk.org/t/2450')
def test_XDMF_relabs_path(self,single_phase,tmp_path):
def dims(xdmf):
reader_xdmf = vtkXdmfReader()
reader_xdmf.SetFileName(xdmf)
reader_xdmf.Update()
return reader_xdmf.GetOutput().GetDimensions()
single_phase.export_XDMF(target_dir=tmp_path)
xdmfname = single_phase.fname.with_suffix('.xdmf').name
ref_dims = dims(tmp_path/xdmfname)
for (d,info) in {
'A': dict(absolute_path=True,
mv='..',
),
'B': dict(absolute_path=False,
mv='../A',
),
}.items():
sub = tmp_path/d; sub.mkdir(exist_ok=True)
single_phase.export_XDMF(target_dir=sub,absolute_path=info['absolute_path'])
os.replace(sub/xdmfname,sub/info['mv']/xdmfname)
assert ref_dims == dims(sub/info['mv']/xdmfname)
@pytest.mark.parametrize('view,output,flatten,prune',
2021-04-01 17:17:27 +05:30
[({},['F','P','F','L_p','F_e','F_p'],True,True),
({'increments':3},'F',True,True),
({'increments':[1,8,3,4,5,6,7]},['F','P'],True,True),
({'phases':['A','B']},['F','P'],True,True),
({'phases':['A','C'],'homogenizations':False},['F','P','O'],True,True),
({'phases':False,'homogenizations':False},['F','P','O'],True,True),
({'phases':False},['Delta_V'],True,True),
({},['u_p','u_n'],False,False)],
ids=list(range(8)))
def test_get(self,update,request,res_path,view,output,flatten,prune):
result = Result(res_path/'4grains2x4x3_compressionY.hdf5')
2021-04-01 17:17:27 +05:30
for key,value in view.items():
2022-03-05 00:30:33 +05:30
result = result.view(**{key:value})
2021-04-01 17:17:27 +05:30
2021-04-03 11:01:31 +05:30
fname = request.node.name
cur = result.get(output,flatten,prune)
2021-04-01 17:17:27 +05:30
if update:
with bz2.BZ2File((res_path/'get'/fname).with_suffix('.pbz2'),'w') as f:
2021-04-01 17:17:27 +05:30
pickle.dump(cur,f)
2021-04-01 19:22:43 +05:30
with bz2.BZ2File((res_path/'get'/fname).with_suffix('.pbz2')) as f:
ref = pickle.load(f)
assert cur is None if ref is None else dict_equal(cur,ref)
2021-04-01 19:22:43 +05:30
@pytest.mark.parametrize('view,output,flatten,constituents,prune',
2021-04-01 19:22:43 +05:30
[({},['F','P','F','L_p','F_e','F_p'],True,True,None),
({'increments':3},'F',True,True,[0,1,2,3,4,5,6,7]),
({'increments':[1,8,3,4,5,6,7]},['F','P'],True,True,1),
({'phases':['A','B']},['F','P'],True,True,[1,2]),
({'phases':['A','C'],'homogenizations':False},['F','P','O'],True,True,[0,7]),
({'phases':False,'homogenizations':False},['F','P','O'],True,True,[1,2,3,4]),
({'phases':False},['Delta_V'],True,True,[1,2,4]),
({},['u_p','u_n'],False,False,None)],
ids=list(range(8)))
def test_place(self,update,request,res_path,view,output,flatten,prune,constituents):
result = Result(res_path/'4grains2x4x3_compressionY.hdf5')
2021-04-01 19:22:43 +05:30
for key,value in view.items():
2022-03-05 00:30:33 +05:30
result = result.view(**{key:value})
2021-04-01 19:22:43 +05:30
2021-04-03 11:01:31 +05:30
fname = request.node.name
cur = result.place(output,flatten,prune,constituents)
2021-04-01 19:22:43 +05:30
if update:
with bz2.BZ2File((res_path/'place'/fname).with_suffix('.pbz2'),'w') as f:
2021-04-01 19:22:43 +05:30
pickle.dump(cur,f)
with bz2.BZ2File((res_path/'place'/fname).with_suffix('.pbz2')) as f:
ref = pickle.load(f)
assert cur is None if ref is None else dict_equal(cur,ref)
2021-08-18 13:06:28 +05:30
2022-11-10 04:01:25 +05:30
def test_simulation_setup_files(self,default):
assert set(default.simulation_setup_files) == set(['12grains6x7x8.vti',
'material.yaml',
'tensionY.yaml',
'previous/12grains6x7x8.vti',
'previous/material.yaml',
'previous/tensionY.yaml'])
def test_export_simulation_setup_files(self,tmp_path,default):
sub = 'deep/down'
default.export_simulation_setup(target_dir=tmp_path/sub,overwrite=True)
for f in default.simulation_setup_files:
assert (tmp_path/sub/f).exists()
def test_export_simulation_setup_overwrite(self,tmp_path,default):
os.chdir(tmp_path)
default.export_simulation_setup('material.yaml',overwrite=True)
with pytest.raises(PermissionError):
default.export_simulation_setup('material.yaml',overwrite=False)
@pytest.mark.parametrize('output',['12grains6x7x8.vti',
'tensionY.yaml',
])
def test_export_simulation_setup_content(self,res_path,tmp_path,default,output):
2022-11-10 04:01:25 +05:30
default.export_simulation_setup(output,target_dir=tmp_path,overwrite=True)
assert open(tmp_path/output).read() == open(res_path/output).read()
2021-08-18 13:06:28 +05:30
@pytest.mark.parametrize('fname',['4grains2x4x3_compressionY.hdf5',
'6grains6x7x8_single_phase_tensionY.hdf5'])
2021-08-18 14:14:04 +05:30
@pytest.mark.parametrize('output',['material.yaml','*'])
def test_export_simulation_setup_consistency(self,res_path,tmp_path,fname,output):
r = Result(res_path/fname)
r.export_simulation_setup(output,target_dir=tmp_path)
with h5py.File(res_path/fname,'r') as f_hdf5:
2022-11-07 03:46:30 +05:30
for file in fnmatch.filter(f_hdf5['setup'].keys(),output):
with open(tmp_path/file) as f:
assert f_hdf5[f'setup/{file}'][()][0].decode() == f.read()
def test_export_simulation_setup_custom_path(self,res_path,tmp_path):
subdir = 'export_dir'
absdir = tmp_path/subdir
absdir.mkdir(exist_ok=True)
r = Result(res_path/'4grains2x4x3_compressionY.hdf5')
for t,cwd in zip([absdir,subdir,None],[tmp_path,tmp_path,absdir]):
os.chdir(cwd)
r.export_simulation_setup('material.yaml',target_dir=t)
assert 'material.yaml' in os.listdir(absdir); (absdir/'material.yaml').unlink()
@pytest.mark.parametrize('fname',['4grains2x4x3_compressionY.hdf5',
2023-03-22 04:18:37 +05:30
'6grains6x7x8_single_phase_tensionY.hdf5',
'12grains6x7x8_tensionY.hdf5',
'check_compile_job1.hdf5',])
def test_export_DADF5(self,res_path,tmp_path,fname):
r = Result(res_path/fname)
r = r.view(phases = random.sample(r._phases,1))
r = r.view(increments = random.sample(r._increments,np.random.randint(1,len(r._increments))))
r.export_DADF5(tmp_path/fname)
r_exp = Result(tmp_path/fname)
assert str(r.get()) == str(r_exp.get())
assert str(r.place()) == str(r_exp.place())
@pytest.mark.parametrize('fname',['4grains2x4x3_compressionY.hdf5',
'6grains6x7x8_single_phase_tensionY.hdf5'])
def test_export_DADF5_name_clash(self,res_path,tmp_path,fname):
r = Result(res_path/fname)
with pytest.raises(PermissionError):
r.export_DADF5(r.fname)
2023-03-22 04:18:37 +05:30
@pytest.mark.parametrize('fname',['4grains2x4x3_compressionY.hdf5',
'6grains6x7x8_single_phase_tensionY.hdf5',
'12grains6x7x8_tensionY.hdf5'])
def test_export_DADF5_regrid(self,res_path,tmp_path,fname):
r = Result(res_path/fname)
2023-03-22 04:18:37 +05:30
m = grid_filters.regrid(r.size,np.broadcast_to(np.eye(3),tuple(r.cells)+(3,3)),r.cells*2)
r.export_DADF5(tmp_path/'regridded.hdf5',mapping=m)
assert np.all(Result(tmp_path/'regridded.hdf5').cells == r.cells*2)