Skip to content

Commit 71ecf4c

Browse files
committed
Merge branch '408-bravais-to-miller-accept-dot-undefined' into 'development'
flexible Miller-Bravais indices Closes #408 See merge request damask/DAMASK!1012
2 parents f49abef + e5319d7 commit 71ecf4c

File tree

2 files changed

+84
-26
lines changed

2 files changed

+84
-26
lines changed

python/damask/util.py

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ def _docstringer(docstring: _Union[str, _Callable],
594594
docstring : str or callable, optional
595595
Docstring (of callable) to extend.
596596
adopted_* : str or callable, optional
597-
Additional information to insert into/append to respective section.
597+
Additional information to insert into or append to respective section.
598598
599599
Notes
600600
-----
@@ -680,7 +680,7 @@ def extend_docstring(docstring: _Union[None, str, _Callable] = None,
680680
docstring : str or callable, optional
681681
Docstring to extend. Defaults to that of decorated function.
682682
adopted_* : str or callable, optional
683-
Additional information to insert into/append to respective section.
683+
Additional information to insert into or append to respective section.
684684
685685
Notes
686686
-----
@@ -804,6 +804,49 @@ def get_cell_data_group(f: _h5py.File) -> str:
804804
return get_cell_data_group(f)
805805

806806

807+
def _standardize_MillerBravais(idx: _IntSequence) -> _np.ndarray:
808+
"""
809+
Convert Miller-Bravais indices with missing component to standard (full) form.
810+
811+
Parameters
812+
----------
813+
idx : numpy.ndarray, shape (...,4) or (...,3)
814+
Miller–Bravais indices of crystallographic direction [uvtw] or plane normal (hkil).
815+
The third index (t or i) can be omitted completely or given as "..." (Ellipsis).
816+
817+
Returns
818+
-------
819+
uvtw|hkil : numpy.ndarray, shape (...,4)
820+
Miller-Bravais indices of [uvtw] direction or (hkil) plane normal.
821+
822+
"""
823+
def expand(v: _np.ndarray) -> _np.ndarray:
824+
"""Expand from 3 to 4 indices."""
825+
return _np.block([v[...,:2], -_np.sum(v[...,:2],axis=-1,keepdims=True), v[...,2:]])
826+
827+
a = _np.asarray(idx)
828+
if _np.issubdtype(a.dtype,_np.signedinteger):
829+
if a.shape[-1] == 4:
830+
if (_np.sum(a[...,:3],axis=-1) != 0).any(): raise ValueError(rf'u+v+t≠0 | h+k+i≠0: {a}')
831+
return a
832+
elif a.shape[-1] == 3:
833+
return expand(a)
834+
else:
835+
if a.shape[-1] == 4:
836+
b = (_np.block([a[...,:2],
837+
_np.where(a[...,2:3] == ..., -_np.sum(a[...,:2],axis=-1,keepdims=True),a[...,2:3]),
838+
a[...,3:]]))
839+
if (_np.sum(b[...,:3].astype(int),axis=-1) != 0).any(): raise ValueError(rf'u+v+t≠0 | h+k+i≠0: {b}')
840+
elif a.shape[-1] == 3:
841+
b = expand(a)
842+
843+
if (b != (c := b.astype(int))).any():
844+
raise ValueError(f'"uvtw" | "hkil" are not (castable to) signed integers: {a}')
845+
return c
846+
847+
raise ValueError(f'invalid Miller-Bravais indices {a}')
848+
849+
807850
def Bravais_to_Miller(*,
808851
uvtw: _Optional[_IntSequence] = None,
809852
hkil: _Optional[_IntSequence] = None) -> _np.ndarray:
@@ -812,8 +855,9 @@ def Bravais_to_Miller(*,
812855
813856
Parameters
814857
----------
815-
uvtw|hkil : numpy.ndarray, shape (...,4)
858+
uvtw|hkil : numpy.ndarray, shape (...,4) or (...,3)
816859
Miller–Bravais indices of crystallographic direction [uvtw] or plane normal (hkil).
860+
The third index (t or i) can be omitted completely or given as "..." (Ellipsis).
817861
818862
Returns
819863
-------
@@ -823,23 +867,22 @@ def Bravais_to_Miller(*,
823867
"""
824868
if (uvtw is not None) ^ (hkil is None):
825869
raise KeyError('specify either "uvtw" or "hkil"')
826-
if uvtw is not None and (_np.sum(_np.asarray(uvtw)[...,:3],axis=-1) != 0).any():
827-
raise ValueError(rf'u+v+t≠0: {uvtw}')
828-
if hkil is not None and (_np.sum(_np.asarray(hkil)[...,:3],axis=-1) != 0).any():
829-
raise ValueError(rf'h+k+i≠0: {hkil}')
830-
831-
axis,basis = (_np.array(uvtw),_np.array([[2,1,0,0],
832-
[1,2,0,0],
833-
[0,0,0,1]])) \
834-
if hkil is None else \
835-
(_np.array(hkil),_np.array([[1,0,0,0],
836-
[0,1,0,0],
837-
[0,0,0,1]]))
870+
elif uvtw is not None:
871+
axis,basis = _standardize_MillerBravais(uvtw),_np.array([[2,1,0,0],
872+
[1,2,0,0],
873+
[0,0,0,1]])
874+
elif hkil is not None:
875+
axis,basis = _standardize_MillerBravais(hkil),_np.array([[1,0,0,0],
876+
[0,1,0,0],
877+
[0,0,0,1]])
838878
uvw_hkl = _np.einsum('il,...l',basis,axis)
839-
if not _np.issubdtype(uvw_hkl.dtype,_np.signedinteger):
840-
raise TypeError('"uvtw"/"hkil" are not (signed) integers')
879+
841880
return uvw_hkl//_np.gcd.reduce(uvw_hkl,axis=-1,keepdims=True)
842881

882+
883+
MillerBravais_to_Miller = Bravais_to_Miller
884+
885+
843886
def Miller_to_Bravais(*,
844887
uvw: _Optional[_IntSequence] = None,
845888
hkl: _Optional[_IntSequence] = None) -> _np.ndarray:
@@ -868,12 +911,16 @@ def Miller_to_Bravais(*,
868911
[ 0, 1, 0],
869912
[-1,-1, 0],
870913
[ 0, 0, 1]]))
871-
uvtw_hkil = _np.einsum('il,...l',basis,axis)
872-
if not _np.issubdtype(uvtw_hkil.dtype,_np.signedinteger):
873-
raise TypeError('"uvw"/"hkl" are not (signed) integers')
914+
if (axis != axis.astype(int)).any():
915+
raise ValueError(f'"uvt" | "hki" are not (castable to) signed integers: {axis}')
916+
uvtw_hkil = _np.einsum('il,...l',basis,axis.astype(int))
917+
874918
return uvtw_hkil//_np.gcd.reduce(uvtw_hkil,axis=-1,keepdims=True)
875919

876920

921+
Miller_to_MillerBravais = Miller_to_Bravais
922+
923+
877924
def dict_prune(d: _Dict) -> _Dict:
878925
"""
879926
Recursively remove empty dictionaries.

python/tests/test_util.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,16 @@ def test_double_Miller_to_Bravais(self):
221221
with pytest.raises(KeyError):
222222
util.Miller_to_Bravais(uvw=np.ones(4),hkl=np.ones(4))
223223

224-
@pytest.mark.parametrize('key_value',[{'uvtw':[1.,0.,-1.,0.]},
225-
{'hkil':[1.,0.,-1.,0.]}])
224+
@pytest.mark.parametrize('key_value',[{'uvtw':[1.,0.,-1.,1.1]},
225+
{'hkil':[1.,0.,-1.,1.1]}])
226226
def test_float_Bravais_to_Miller(self,key_value):
227-
with pytest.raises(TypeError):
227+
with pytest.raises(ValueError):
228228
util.Bravais_to_Miller(**key_value)
229229

230-
@pytest.mark.parametrize('key_value',[{'uvw':[1.,0.,-1.]},
231-
{'hkl':[1.,0.,-1.]}])
230+
@pytest.mark.parametrize('key_value',[{'uvw':[1.,0.,-1.1]},
231+
{'hkl':[1.,0.,-9.4]}])
232232
def test_float_Miller_to_Bravais(self,key_value):
233-
with pytest.raises(TypeError):
233+
with pytest.raises(ValueError):
234234
util.Miller_to_Bravais(**key_value)
235235

236236

@@ -267,6 +267,17 @@ def test_Miller_Bravais_Miller_random(self,kw_Miller,kw_Bravais):
267267
def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais):
268268
assert np.all(vector == util.Miller_to_Bravais(**{kw_Miller:util.Bravais_to_Miller(**{kw_Bravais:vector})}))
269269

270+
@pytest.mark.parametrize('dim',(None,1,4))
271+
def test_standardize_MillerBravais(self,dim):
272+
shape = tuple(np.random.randint(1,6,dim))+(3,) if dim is not None else (3,)
273+
idx_red = np.random.randint(-10,11,shape)
274+
idx_full = np.block([idx_red[...,:2], -np.sum(idx_red[...,:2],axis=-1,keepdims=True), idx_red[...,2:]])
275+
idx_missing = idx_full.astype(object)
276+
idx_missing[...,2][idx_full[...,3]>0] = ...
277+
assert np.equal(idx_full,util._standardize_MillerBravais(idx_red)).all() and \
278+
np.equal(idx_full,util._standardize_MillerBravais(idx_missing)).all()
279+
280+
270281
@pytest.mark.parametrize('adopted_parameters',[
271282
pytest.param("""
272283
p2 : str, optional

0 commit comments

Comments
 (0)