check for invalid materialpoint configuration

This commit is contained in:
Martin Diehl 2023-02-01 20:31:04 +01:00
parent fd84406903
commit 46ad436d76
2 changed files with 58 additions and 32 deletions

View File

@ -8,6 +8,7 @@ from . import Config
from . import Rotation from . import Rotation
from . import Orientation from . import Orientation
from . import util from . import util
from . import tensor
from . import Table from . import Table
@ -443,7 +444,7 @@ class ConfigMaterial(Config):
Phase label (per constituent). Phase label (per constituent).
v: (array-like) of float, optional v: (array-like) of float, optional
Constituent volume fraction (per constituent). Constituent volume fraction (per constituent).
Defaults to 1/N_constituents Defaults to 1/N_constituent.
O: (array-like) of damask.Rotation or np.array/list of shape(4), optional O: (array-like) of damask.Rotation or np.array/list of shape(4), optional
Orientation as unit quaternion (per constituent). Orientation as unit quaternion (per constituent).
V_e: (array-like) of np.array/list of shape(3,3), optional V_e: (array-like) of np.array/list of shape(3,3), optional
@ -536,48 +537,44 @@ class ConfigMaterial(Config):
phase: {Austenite: null, Ferrite: null} phase: {Austenite: null, Ferrite: null}
""" """
kwargs = {} dim = {'O':(4,),'V_e':(3,3,)}
for keyword,value in zip(['homogenization','phase','v','O','V_e'],[homogenization,phase,v,O,V_e]): ex = dict((keyword, -len(val)) for keyword,val in dim.items())
if value is not None: kwargs[keyword] = value
_constituent_properties = ['phase','O','v','V_e']
_dim = {'O':(4,),'V_e':(3,3,)}
_ex = dict((k, -len(v)) for k, v in _dim.items())
N_materials,N_constituents = 1,1 N_materials,N_constituents = 1,1
shaped : Dict[str, Union[None,np.ndarray]] = \ shaped = {}
{'v': None, for arg,val in zip(['homogenization','phase','v','O','V_e'],[homogenization,phase,v,O,V_e]):
'phase': None, if val is None: continue
'homogenization': None, shaped[arg] = np.array(val)
} s = shaped[arg].shape[:ex.get(arg,None)] # type: ignore
for arg,value in kwargs.items():
shaped[arg] = np.array(value)
s = shaped[arg].shape[:_ex.get(arg,None)] # type: ignore
N_materials = max(N_materials,s[0]) if len(s)>0 else N_materials N_materials = max(N_materials,s[0]) if len(s)>0 else N_materials
N_constituents = max(N_constituents,s[1]) if len(s)>1 else N_constituents N_constituents = max(N_constituents,s[1]) if len(s)>1 else N_constituents
shaped['v'] = np.array(1./N_constituents) if shaped['v'] is None else shaped['v'] shaped['v'] = np.array(shaped.get('v',1./N_constituents),float)
mat: Sequence[dict] = [{'constituents':[{} for _ in range(N_constituents)]} for _ in range(N_materials)] mat: Sequence[dict] = [{'constituents':[{} for _ in range(N_constituents)]} for _ in range(N_materials)]
for k,v in shaped.items(): for k,v in shaped.items():
target = (N_materials,N_constituents) + _dim.get(k,()) target = (N_materials,N_constituents) + dim.get(k,())
obj = np.broadcast_to(np.array(v).reshape(util.shapeshifter(() if v is None else v.shape, obj = np.broadcast_to(np.array(v).reshape(util.shapeshifter(np.array(v).shape,target,'right')),target)
target, if k == 'v':
mode = 'right')), total = obj if len(np.atleast_1d(obj)) == 1 else np.sum(obj,axis=-1)
target) if np.min(obj) < 0 or np.min(total) < 0 or np.max(total) > 1:
raise ValueError('volume fraction "v" out of range')
if k == 'O' and not np.allclose(1.0,np.linalg.norm(obj,axis=-1)):
raise ValueError('orientation "O" is not a unit quaterion')
elif k == 'V_e' and not np.allclose(obj,tensor.symmetric(obj)):
raise ValueError('elastic stretch "V_e" is not symmetric')
for i in range(N_materials): for i in range(N_materials):
if k in _constituent_properties: if k == 'homogenization':
for j in range(N_constituents): mat[i][k] = obj[i,0]
mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j]
else: else:
mat[i][k] = obj[i,0].item() if isinstance(obj[i,0],np.generic) else obj[i,0] for j in range(N_constituents):
mat[i]['constituents'][j][k] = obj[i,j]
dup = self.copy() dup = self.copy()
dup['material'] = dup['material'] + mat if 'material' in dup else mat dup['material'] = dup['material'] + mat if 'material' in dup else mat
for what in [item for item in ['phase','homogenization'] if shaped[item] is not None]: for what in [item for item in ['phase','homogenization'] if item in shaped]:
for k in np.unique(shaped[what]): # type: ignore for k in np.unique(shaped[what]): # type: ignore
if k not in dup[what]: dup[what][str(k)] = None if k not in dup[what]: dup[what][str(k)] = None

View File

@ -16,6 +16,27 @@ def ref_path(ref_path_base):
class TestConfigMaterial: class TestConfigMaterial:
def test_init_empty(self):
c = ConfigMaterial()
assert len(c) == 3
assert c['homogenization'] == {}
assert c['phase'] == {}
assert c['material'] == []
def test_init_d(self):
c = ConfigMaterial(config={'phase':4})
assert len(c) == 1
assert c['phase'] == 4
@pytest.mark.parametrize('kwargs',[{'homogenization':{'SX':{}}},
{'phase':{'Aluminum':{}}},
{'material':[{'A':1},{'B':2}]}])
def test_init_some(self,kwargs):
c = ConfigMaterial(**kwargs)
assert len(c) == 3
for k,v in kwargs.items():
if k in kwargs: assert v == kwargs[k]
@pytest.mark.parametrize('fname',[None,'test.yaml']) @pytest.mark.parametrize('fname',[None,'test.yaml'])
def test_load_save(self,ref_path,tmp_path,fname): def test_load_save(self,ref_path,tmp_path,fname):
reference = ConfigMaterial.load(ref_path/'material.yaml') reference = ConfigMaterial.load(ref_path/'material.yaml')
@ -88,14 +109,14 @@ class TestConfigMaterial:
def test_from_table(self): def test_from_table(self):
N = np.random.randint(3,10) N = np.random.randint(3,10)
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),
np.ones(N*2),np.zeros(N*2),np.ones(N*2),np.ones(N*2), np.zeros(N*2),np.ones(N*2),np.zeros(N*2),np.zeros(N*2),
np.ones(N*2), np.ones(N*2),
)).T )).T
t = Table({'varying':1,'constant':4,'ones':1},a) t = Table({'varying':1,'constant':4,'ones':1},a)
c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':'ones'}) c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':'ones'})
assert len(c['material']) == N assert len(c['material']) == N
for i,m in enumerate(c['material']): for i,m in enumerate(c['material']):
assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all() assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [0,1,0,0]).all()
def test_updated_dicts(self,ref_path): def test_updated_dicts(self,ref_path):
m1 = ConfigMaterial().material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX') m1 = ConfigMaterial().material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX')
@ -109,14 +130,14 @@ class TestConfigMaterial:
def test_from_table_with_constant(self): def test_from_table_with_constant(self):
N = np.random.randint(3,10) N = np.random.randint(3,10)
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),
np.ones(N*2),np.zeros(N*2),np.ones(N*2),np.ones(N*2), np.zeros(N*2),np.ones(N*2),np.zeros(N*2),np.zeros(N*2),
np.ones(N*2), np.ones(N*2),
)).T )).T
t = Table({'varying':1,'constant':4,'ones':1},a) t = Table({'varying':1,'constant':4,'ones':1},a)
c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':1}) c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':1})
assert len(c['material']) == N assert len(c['material']) == N
for i,m in enumerate(c['material']): for i,m in enumerate(c['material']):
assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all() assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [0,1,0,0]).all()
@pytest.mark.parametrize('N,n,kw',[ @pytest.mark.parametrize('N,n,kw',[
(1,1,{'phase':'Gold', (1,1,{'phase':'Gold',
@ -137,6 +158,14 @@ class TestConfigMaterial:
assert len(m['material']) == N assert len(m['material']) == N
assert len(m['material'][0]['constituents']) == n assert len(m['material'][0]['constituents']) == n
@pytest.mark.parametrize('shape',[(),(4,),(5,2)])
@pytest.mark.parametrize('kw',[{'V_e':np.random.rand(3,3)},
{'O':np.random.rand(4)},
{'v':np.array(2)}])
def test_material_add_invalid(self,kw,shape):
kw = {arg:np.broadcast_to(val,shape+val.shape) for arg,val in kw.items()}
with pytest.raises(ValueError):
ConfigMaterial().material_add(**kw)
@pytest.mark.parametrize('cell_ensemble_data',[None,'CellEnsembleData']) @pytest.mark.parametrize('cell_ensemble_data',[None,'CellEnsembleData'])
def test_load_DREAM3D(self,ref_path,cell_ensemble_data): def test_load_DREAM3D(self,ref_path,cell_ensemble_data):