encapsulating all lattice(-family) related data
This commit is contained in:
parent
4701eea10f
commit
3c8d06b6f1
|
@ -1,4 +1,5 @@
|
||||||
import inspect
|
import inspect
|
||||||
|
import copy
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
@ -135,37 +136,11 @@ class Orientation(Rotation):
|
||||||
if family in set(lattice_symmetries.values()) and lattice is None:
|
if family in set(lattice_symmetries.values()) and lattice is None:
|
||||||
self.family = family
|
self.family = family
|
||||||
self.lattice = None
|
self.lattice = None
|
||||||
|
self.structure = LatticeFamily(self.family)
|
||||||
self.structure = l = LatticeFamily(self.family) # noqa
|
|
||||||
self.immutable = l.immutable
|
|
||||||
self.basis = l.basis
|
|
||||||
|
|
||||||
self.a = self.b = self.c = None
|
|
||||||
self.alpha = self.beta = self.gamma = None
|
|
||||||
|
|
||||||
elif lattice in lattice_symmetries:
|
elif lattice in lattice_symmetries:
|
||||||
|
|
||||||
self.family = lattice_symmetries[lattice]
|
self.family = lattice_symmetries[lattice]
|
||||||
self.lattice = lattice
|
self.lattice = lattice
|
||||||
|
self.structure = l = Lattice(self.lattice, a,b,c, alpha,beta,gamma, degrees)
|
||||||
self.structure = l = Lattice(self.lattice, a,b,c, alpha,beta,gamma, degrees) # noqa
|
|
||||||
self.immutable = l.immutable
|
|
||||||
self.basis = l.basis
|
|
||||||
|
|
||||||
self.a = l.a
|
|
||||||
self.b = l.b
|
|
||||||
self.c = l.c
|
|
||||||
|
|
||||||
self.alpha = l.alpha
|
|
||||||
self.beta = l.beta
|
|
||||||
self.gamma = l.gamma
|
|
||||||
|
|
||||||
self.ratio = l.ratio
|
|
||||||
|
|
||||||
self.to_frame = l.to_frame
|
|
||||||
|
|
||||||
self.kinematics = l.kinematics
|
|
||||||
self.relation_operations = l.relation_operations
|
|
||||||
else:
|
else:
|
||||||
raise KeyError(f'no valid family or lattice')
|
raise KeyError(f'no valid family or lattice')
|
||||||
|
|
||||||
|
@ -177,18 +152,12 @@ class Orientation(Rotation):
|
||||||
+ [super().__repr__()])
|
+ [super().__repr__()])
|
||||||
|
|
||||||
|
|
||||||
def __copy__(self,**kwargs):
|
def __copy__(self,rotation=None):
|
||||||
"""Create deep copy."""
|
"""Create deep copy."""
|
||||||
return self.__class__(rotation= kwargs['rotation'] if 'rotation' in kwargs else self.quaternion,
|
dup = copy.deepcopy(self)
|
||||||
family = kwargs['family'] if 'family' in kwargs else self.family,
|
if rotation is not None:
|
||||||
lattice = kwargs['lattice'] if 'lattice' in kwargs else self.lattice,
|
dup.quaternion = Orientation(rotation,family='cubic').quaternion
|
||||||
a = kwargs['a'] if 'a' in kwargs else self.a,
|
return dup
|
||||||
b = kwargs['b'] if 'b' in kwargs else self.b,
|
|
||||||
c = kwargs['c'] if 'c' in kwargs else self.c,
|
|
||||||
alpha = kwargs['alpha'] if 'alpha' in kwargs else self.alpha,
|
|
||||||
beta = kwargs['beta'] if 'beta' in kwargs else self.beta,
|
|
||||||
gamma = kwargs['gamma'] if 'gamma' in kwargs else self.gamma,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy = __copy__
|
copy = __copy__
|
||||||
|
|
||||||
|
@ -415,8 +384,8 @@ class Orientation(Rotation):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
o = cls(**kwargs)
|
o = cls(**kwargs)
|
||||||
x = o.to_frame(uvw=uvw)
|
x = o.structure.to_frame(uvw=uvw)
|
||||||
z = o.to_frame(hkl=hkl)
|
z = o.structure.to_frame(hkl=hkl)
|
||||||
om = np.stack([x,np.cross(z,x),z],axis=-2)
|
om = np.stack([x,np.cross(z,x),z],axis=-2)
|
||||||
return o.copy(rotation=Rotation.from_matrix(tensor.transpose(om/np.linalg.norm(om,axis=-1,keepdims=True))))
|
return o.copy(rotation=Rotation.from_matrix(tensor.transpose(om/np.linalg.norm(om,axis=-1,keepdims=True))))
|
||||||
|
|
||||||
|
@ -707,21 +676,21 @@ class Orientation(Rotation):
|
||||||
if not isinstance(vector,np.ndarray) or vector.shape[-1] != 3:
|
if not isinstance(vector,np.ndarray) or vector.shape[-1] != 3:
|
||||||
raise ValueError('input is not a field of three-dimensional vectors')
|
raise ValueError('input is not a field of three-dimensional vectors')
|
||||||
|
|
||||||
if self.basis is None: # direct exit for no symmetry
|
if self.structure.basis is None: # direct exit for no symmetry
|
||||||
return np.ones_like(vector[...,0],bool)
|
return np.ones_like(vector[...,0],bool)
|
||||||
|
|
||||||
if proper:
|
if proper:
|
||||||
components_proper = np.around(np.einsum('...ji,...i',
|
components_proper = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['proper'], vector.shape+(3,)),
|
np.broadcast_to(self.structure.basis['proper'], vector.shape+(3,)),
|
||||||
vector), 12)
|
vector), 12)
|
||||||
components_improper = np.around(np.einsum('...ji,...i',
|
components_improper = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['improper'], vector.shape+(3,)),
|
np.broadcast_to(self.structure.basis['improper'], vector.shape+(3,)),
|
||||||
vector), 12)
|
vector), 12)
|
||||||
return np.all(components_proper >= 0.0,axis=-1) \
|
return np.all(components_proper >= 0.0,axis=-1) \
|
||||||
| np.all(components_improper >= 0.0,axis=-1)
|
| np.all(components_improper >= 0.0,axis=-1)
|
||||||
else:
|
else:
|
||||||
components = np.around(np.einsum('...ji,...i',
|
components = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['improper'], vector.shape+(3,)),
|
np.broadcast_to(self.structure.basis['improper'], vector.shape+(3,)),
|
||||||
np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12)
|
np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12)
|
||||||
|
|
||||||
return np.all(components >= 0.0,axis=-1)
|
return np.all(components >= 0.0,axis=-1)
|
||||||
|
@ -762,15 +731,15 @@ class Orientation(Rotation):
|
||||||
vector_ = self.to_SST(vector,proper) if in_SST else \
|
vector_ = self.to_SST(vector,proper) if in_SST else \
|
||||||
self @ np.broadcast_to(vector,self.shape+(3,))
|
self @ np.broadcast_to(vector,self.shape+(3,))
|
||||||
|
|
||||||
if self.basis is None: # direct exit for no symmetry
|
if self.structure.basis is None: # direct exit for no symmetry
|
||||||
return np.zeros_like(vector_)
|
return np.zeros_like(vector_)
|
||||||
|
|
||||||
if proper:
|
if proper:
|
||||||
components_proper = np.around(np.einsum('...ji,...i',
|
components_proper = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['proper'], vector_.shape+(3,)),
|
np.broadcast_to(self.structure.basis['proper'], vector_.shape+(3,)),
|
||||||
vector_), 12)
|
vector_), 12)
|
||||||
components_improper = np.around(np.einsum('...ji,...i',
|
components_improper = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['improper'], vector_.shape+(3,)),
|
np.broadcast_to(self.structure.basis['improper'], vector_.shape+(3,)),
|
||||||
vector_), 12)
|
vector_), 12)
|
||||||
in_SST = np.all(components_proper >= 0.0,axis=-1) \
|
in_SST = np.all(components_proper >= 0.0,axis=-1) \
|
||||||
| np.all(components_improper >= 0.0,axis=-1)
|
| np.all(components_improper >= 0.0,axis=-1)
|
||||||
|
@ -778,7 +747,7 @@ class Orientation(Rotation):
|
||||||
components_proper,components_improper)
|
components_proper,components_improper)
|
||||||
else:
|
else:
|
||||||
components = np.around(np.einsum('...ji,...i',
|
components = np.around(np.einsum('...ji,...i',
|
||||||
np.broadcast_to(self.basis['improper'], vector_.shape+(3,)),
|
np.broadcast_to(self.structure.basis['improper'], vector_.shape+(3,)),
|
||||||
np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12)
|
np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12)
|
||||||
|
|
||||||
in_SST = np.all(components >= 0.0,axis=-1)
|
in_SST = np.all(components >= 0.0,axis=-1)
|
||||||
|
@ -813,7 +782,7 @@ class Orientation(Rotation):
|
||||||
"""
|
"""
|
||||||
sym_ops = self.structure.symmetry_operations
|
sym_ops = self.structure.symmetry_operations
|
||||||
# ToDo: simplify 'with_symmetry'
|
# ToDo: simplify 'with_symmetry'
|
||||||
v = self.to_frame(uvw=uvw,hkl=hkl)
|
v = self.structure.to_frame(uvw=uvw,hkl=hkl)
|
||||||
if with_symmetry:
|
if with_symmetry:
|
||||||
v = sym_ops.broadcast_to(sym_ops.shape+v.shape[:-1],mode='right') \
|
v = sym_ops.broadcast_to(sym_ops.shape+v.shape[:-1],mode='right') \
|
||||||
@ np.broadcast_to(v,sym_ops.shape+v.shape)
|
@ np.broadcast_to(v,sym_ops.shape+v.shape)
|
||||||
|
@ -850,8 +819,8 @@ class Orientation(Rotation):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
d = self.to_frame(uvw=self.kinematics(mode)['direction'])
|
d = self.structure.to_frame(uvw=self.structure.kinematics(mode)['direction'])
|
||||||
p = self.to_frame(hkl=self.kinematics(mode)['plane'])
|
p = self.structure.to_frame(hkl=self.structure.kinematics(mode)['plane'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise (f'"{mode}" not defined for lattice "{self.lattice}"')
|
raise (f'"{mode}" not defined for lattice "{self.lattice}"')
|
||||||
P = np.einsum('...i,...j',d/np.linalg.norm(d,axis=-1,keepdims=True),
|
P = np.einsum('...i,...j',d/np.linalg.norm(d,axis=-1,keepdims=True),
|
||||||
|
@ -869,14 +838,15 @@ class Orientation(Rotation):
|
||||||
is added to the left of the Rotation array.
|
is added to the left of the Rotation array.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
lattice,o = self.relation_operations(model)
|
lattice,o = self.structure.relation_operations(model)
|
||||||
target = Orientation(lattice=lattice)
|
target = Lattice(lattice=lattice)
|
||||||
|
struct = self.structure
|
||||||
o = o.broadcast_to(o.shape+self.shape,mode='right')
|
o = o.broadcast_to(o.shape+self.shape,mode='right')
|
||||||
return self.copy(rotation=o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'),
|
return Orientation(rotation=o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'),
|
||||||
lattice=lattice,
|
lattice=lattice,
|
||||||
b = self.b if target.ratio['b'] is None else self.a*target.ratio['b'],
|
b = struct.b if target.ratio['b'] is None else struct.a*target.ratio['b'],
|
||||||
c = self.c if target.ratio['c'] is None else self.a*target.ratio['c'],
|
c = struct.c if target.ratio['c'] is None else struct.a*target.ratio['c'],
|
||||||
alpha = None if 'alpha' in target.immutable else self.alpha,
|
alpha = None if 'alpha' in target.immutable else struct.alpha,
|
||||||
beta = None if 'beta' in target.immutable else self.beta,
|
beta = None if 'beta' in target.immutable else struct.beta,
|
||||||
gamma = None if 'gamma' in target.immutable else self.gamma,
|
gamma = None if 'gamma' in target.immutable else struct.gamma,
|
||||||
)
|
)
|
||||||
|
|
|
@ -409,7 +409,7 @@ class TestOrientation:
|
||||||
**dict(zip(['a','b','c'],lengths)),
|
**dict(zip(['a','b','c'],lengths)),
|
||||||
**dict(zip(['alpha','beta','gamma'],np.arccos(cosines))),
|
**dict(zip(['alpha','beta','gamma'],np.arccos(cosines))),
|
||||||
)
|
)
|
||||||
assert np.allclose(o.to_frame(uvw=np.eye(3)),basis), 'Lattice basis disagrees with initialization'
|
assert np.allclose(o.structure.to_frame(uvw=np.eye(3)),basis), 'Lattice basis disagrees with initialization'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice,a,b,c,alpha,beta,gamma',
|
@pytest.mark.parametrize('lattice,a,b,c,alpha,beta,gamma',
|
||||||
|
|
Loading…
Reference in New Issue