diff --git a/python/damask/_result.py b/python/damask/_result.py index a12ee467a..bf3ee67b9 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -466,6 +466,11 @@ class Result: return f[self.get_dataset_location('orientation')[0]].attrs['Lattice'].astype('str') # np.bytes_ to string + def enable_user_function(self,func): + globals()[func.__name__]=func + print(f'Function {func.__name__} enabled in add_calculation.') + + def read_dataset(self,path,c=0,plain=False): """ Dataset for all points/cells. @@ -504,7 +509,7 @@ class Result: else: return dataset - + @property def cell_coordinates(self): """Return initial coordinates of the cell centers.""" if self.structured: @@ -513,6 +518,7 @@ class Result: with h5py.File(self.fname,'r') as f: return f['geometry/x_c'][()] + @property def node_coordinates(self): """Return initial coordinates of the cell centers.""" if self.structured: @@ -561,7 +567,7 @@ class Result: 'Creator': inspect.stack()[0][3][1:] } } - def add_calculation(self,label,formula,unit='n/a',description=None,vectorized=True): + def add_calculation(self,label,formula,unit='n/a',description=None): """ Add result of a general formula. @@ -575,13 +581,8 @@ class Result: Physical unit of the result. description : str, optional Human-readable description of the result. - vectorized : bool, optional - Indicate whether the formula can be used in vectorized form. Defaults to ‘True’. """ - if not vectorized: - raise NotImplementedError - dataset_mapping = {d:d for d in set(re.findall(r'#(.*?)#',formula))} # datasets used in the formula args = {'formula':formula,'label':label,'unit':unit,'description':description} self._add_generic_pointwise(self._add_calculation,dataset_mapping,args) diff --git a/python/tests/test_Geom.py b/python/tests/test_Geom.py index 28c9d14b0..155178322 100644 --- a/python/tests/test_Geom.py +++ b/python/tests/test_Geom.py @@ -1,5 +1,4 @@ import copy -import os import pytest import numpy as np @@ -26,7 +25,7 @@ def default(): @pytest.fixture def reference_dir(reference_dir_base): """Directory containing reference results.""" - return os.path.join(reference_dir_base,'Geom') + return reference_dir_base/'Geom' class TestGeom: @@ -87,7 +86,7 @@ class TestGeom: modified = copy.deepcopy(default) modified.mirror(directions,reflect) tag = f'directions={"-".join(directions)}_reflect={reflect}' - reference = os.path.join(reference_dir,f'mirror_{tag}.geom') + reference = reference_dir/f'mirror_{tag}.geom' if update: modified.to_file(reference) assert geom_equal(modified,Geom.from_file(reference)) @@ -96,7 +95,7 @@ class TestGeom: modified = copy.deepcopy(default) modified.clean(stencil) tag = f'stencil={stencil}' - reference = os.path.join(reference_dir,f'clean_{tag}.geom') + reference = reference_dir/f'clean_{tag}.geom' if update: modified.to_file(reference) assert geom_equal(modified,Geom.from_file(reference)) @@ -113,7 +112,7 @@ class TestGeom: modified = copy.deepcopy(default) modified.scale(grid) tag = f'grid={util.srepr(grid,"-")}' - reference = os.path.join(reference_dir,f'scale_{tag}.geom') + reference = reference_dir/f'scale_{tag}.geom' if update: modified.to_file(reference) assert geom_equal(modified,Geom.from_file(reference)) @@ -152,7 +151,7 @@ class TestGeom: modified = copy.deepcopy(default) modified.rotate(Rotation.from_Eulers(Eulers,degrees=True)) tag = f'Eulers={util.srepr(Eulers,"-")}' - reference = os.path.join(reference_dir,f'rotate_{tag}.geom') + reference = reference_dir/f'rotate_{tag}.geom' if update: modified.to_file(reference) assert geom_equal(modified,Geom.from_file(reference)) diff --git a/python/tests/test_Orientation.py b/python/tests/test_Orientation.py index 84414a343..4987f1f1f 100644 --- a/python/tests/test_Orientation.py +++ b/python/tests/test_Orientation.py @@ -33,7 +33,7 @@ def inverse_pole(orientation,axis,proper=False,SST=True): @pytest.fixture def reference_dir(reference_dir_base): """Directory containing reference results.""" - return os.path.join(reference_dir_base,'Rotation') + return reference_dir_base/'Rotation' class TestOrientation: diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 20c27649b..53bcdda9d 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -1,6 +1,7 @@ import time import shutil import os +import sys from datetime import datetime import pytest @@ -10,13 +11,14 @@ import h5py import damask from damask import Result from damask import mechanics +from damask import grid_filters @pytest.fixture def default(tmp_path,reference_dir): """Small Result file in temp location for modification.""" fname = '12grains6x7x8_tensionY.hdf5' - shutil.copy(os.path.join(reference_dir,fname),tmp_path) - f = Result(os.path.join(tmp_path,fname)) + shutil.copy(reference_dir/fname,tmp_path) + f = Result(tmp_path/fname) f.pick('times',20.0) return f @@ -24,13 +26,13 @@ def default(tmp_path,reference_dir): def single_phase(tmp_path,reference_dir): """Single phase Result file in temp location for modification.""" fname = '6grains6x7x8_single_phase_tensionY.hdf5' - shutil.copy(os.path.join(reference_dir,fname),tmp_path) - return Result(os.path.join(tmp_path,fname)) + shutil.copy(reference_dir/fname,tmp_path) + return Result(tmp_path/fname) @pytest.fixture def reference_dir(reference_dir_base): """Directory containing reference results.""" - return os.path.join(reference_dir_base,'Result') + return reference_dir_base/'Result' class TestResult: @@ -98,8 +100,19 @@ class TestResult: in_file = default.read_dataset(loc['|Fe|'],0) assert np.allclose(in_memory,in_file) - def test_add_calculation(self,default): - default.add_calculation('x','2.0*np.abs(#F#)-1.0','-','my notes') + @pytest.mark.parametrize('mode',['direct','function']) + def test_add_calculation(self,default,tmp_path,mode): + + if mode == 'direct': + default.add_calculation('x','2.0*np.abs(#F#)-1.0','-','my notes') + 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) + default.add_calculation('x','my_func(#F#)','-','my notes') + loc = {'F': default.get_dataset_location('F'), 'x': default.get_dataset_location('x')} in_memory = 2.0*np.abs(default.read_dataset(loc['F'],0))-1.0 @@ -312,6 +325,16 @@ class TestResult: with pytest.raises(PermissionError): default.rename('P','another_new_name') + @pytest.mark.parametrize('mode',['cell','node']) + def test_coordinates(self,default,mode): + if mode == 'cell': + a = grid_filters.cell_coord0(default.grid,default.size,default.origin) + b = default.cell_coordinates.reshape(tuple(default.grid)+(3,),order='F') + elif mode == 'node': + a = grid_filters.node_coord0(default.grid,default.size,default.origin) + b = default.node_coordinates.reshape(tuple(default.grid+1)+(3,),order='F') + assert np.allclose(a,b) + @pytest.mark.parametrize('output',['F',[],['F','P']]) def test_vtk(self,tmp_path,default,output): os.chdir(tmp_path) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 49f57f67f..8b26a7472 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -6,7 +6,7 @@ import numpy as np from damask import Rotation from damask import _rotation -n = 1100 +n = 1000 atol=1.e-4 @pytest.fixture diff --git a/python/tests/test_Table.py b/python/tests/test_Table.py index ac7444808..f23d2f842 100644 --- a/python/tests/test_Table.py +++ b/python/tests/test_Table.py @@ -1,5 +1,3 @@ -import os - import pytest import numpy as np @@ -15,7 +13,7 @@ def default(): @pytest.fixture def reference_dir(reference_dir_base): """Directory containing reference results.""" - return os.path.join(reference_dir_base,'Table') + return reference_dir_base/'Table' class TestTable: @@ -35,9 +33,13 @@ class TestTable: d = default.get('5_F') assert np.allclose(d,1.0) and d.shape[1:] == (1,) - def test_write_read_str(self,default,tmpdir): - default.to_ASCII(str(tmpdir.join('default.txt'))) - new = Table.from_ASCII(str(tmpdir.join('default.txt'))) + @pytest.mark.parametrize('mode',['str','path']) + def test_write_read(self,default,tmpdir,mode): + default.to_ASCII(tmpdir/'default.txt') + if mode == 'path': + new = Table.from_ASCII(tmpdir/'default.txt') + elif mode == 'str': + new = Table.from_ASCII(str(tmpdir/'default.txt')) assert all(default.data==new.data) and default.shapes == new.shapes def test_write_read_file(self,default,tmpdir): @@ -54,20 +56,25 @@ class TestTable: new = Table.from_ASCII(f) assert all(default.data==new.data) and default.shapes == new.shapes - def test_read_ang_str(self,reference_dir): - new = Table.from_ang(os.path.join(reference_dir,'simple.ang')) + + @pytest.mark.parametrize('mode',['str','path']) + def test_read_ang(self,reference_dir,mode): + if mode == 'path': + new = Table.from_ang(reference_dir/'simple.ang') + elif mode == 'str': + new = Table.from_ang(str(reference_dir/'simple.ang')) assert new.data.shape == (4,10) and \ new.labels == ['eu', 'pos', 'IQ', 'CI', 'ID', 'intensity', 'fit'] def test_read_ang_file(self,reference_dir): - f = open(os.path.join(reference_dir,'simple.ang')) + f = open(reference_dir/'simple.ang') new = Table.from_ang(f) assert new.data.shape == (4,10) and \ new.labels == ['eu', 'pos', 'IQ', 'CI', 'ID', 'intensity', 'fit'] @pytest.mark.parametrize('fname',['datatype-mix.txt','whitespace-mix.txt']) def test_read_strange(self,reference_dir,fname): - with open(os.path.join(reference_dir,fname)) as f: + with open(reference_dir/fname) as f: Table.from_ASCII(f) def test_set(self,default):