Merge branch 'lattice-into-orientation' into 'development'

keep Orientation object clean

See merge request damask/DAMASK!377
This commit is contained in:
Philip Eisenlohr 2021-05-10 22:28:25 +00:00
commit 4ba4ca1337
10 changed files with 102 additions and 98 deletions

@ -1 +1 @@
Subproject commit 95f7faea920dd6956884e4a55f72e5d5b1ffcdc8 Subproject commit 5e104e75bbfb9d0d1969658aaf10999590956e3e

View File

@ -14,7 +14,6 @@ from . import tensor # noqa
from . import mechanics # noqa from . import mechanics # noqa
from . import solver # noqa from . import solver # noqa
from . import grid_filters # noqa from . import grid_filters # noqa
from . import lattice # noqa
#Modules that contain only one class (of the same name), are prefixed by a '_'. #Modules that contain only one class (of the same name), are prefixed by a '_'.
#For example, '_colormap' containsa class called 'Colormap' which is imported as 'damask.Colormap'. #For example, '_colormap' containsa class called 'Colormap' which is imported as 'damask.Colormap'.
from ._rotation import Rotation # noqa from ._rotation import Rotation # noqa

View File

@ -110,13 +110,13 @@ class Colormap(mpl.colors.ListedColormap):
low_,high_ = map(Colormap._rgb2msh,low_high) low_,high_ = map(Colormap._rgb2msh,low_high)
elif model.lower() == 'hsv': elif model.lower() == 'hsv':
if np.any(low_high<0) or np.any(low_high[:,1:3]>1) or np.any(low_high[:,0]>360): if np.any(low_high<0) or np.any(low_high>[360,1,1]):
raise ValueError(f'HSV color {low} | {high} are out of range.') raise ValueError(f'HSV color {low} | {high} are out of range.')
low_,high_ = map(Colormap._hsv2msh,low_high) low_,high_ = map(Colormap._hsv2msh,low_high)
elif model.lower() == 'hsl': elif model.lower() == 'hsl':
if np.any(low_high<0) or np.any(low_high[:,1:3]>1) or np.any(low_high[:,0]>360): if np.any(low_high<0) or np.any(low_high>[360,1,1]):
raise ValueError(f'HSL color {low} | {high} are out of range.') raise ValueError(f'HSL color {low} | {high} are out of range.')
low_,high_ = map(Colormap._hsl2msh,low_high) low_,high_ = map(Colormap._hsl2msh,low_high)

View File

@ -5,6 +5,35 @@ import numpy as np
from . import Rotation from . import Rotation
from . import util from . import util
from . import tensor from . import tensor
from . import _lattice
_crystal_families = ['triclinic',
'monoclinic',
'orthorhombic',
'tetragonal',
'hexagonal',
'cubic']
_lattice_symmetries = {
'aP': 'triclinic',
'mP': 'monoclinic',
'mS': 'monoclinic',
'oP': 'orthorhombic',
'oS': 'orthorhombic',
'oI': 'orthorhombic',
'oF': 'orthorhombic',
'tP': 'tetragonal',
'tI': 'tetragonal',
'hP': 'hexagonal',
'cP': 'cubic',
'cI': 'cubic',
'cF': 'cubic',
}
_parameter_doc = \ _parameter_doc = \
"""lattice : str """lattice : str
@ -33,7 +62,7 @@ class Orientation(Rotation):
""" """
Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice. Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice.
The crystal family is one of Orientation.crystal_families: The crystal family is one of:
- triclinic - triclinic
- monoclinic - monoclinic
@ -45,7 +74,7 @@ class Orientation(Rotation):
and enables symmetry-related operations such as and enables symmetry-related operations such as
"equivalent", "reduced", "disorientation", "IPF_color", or "to_SST". "equivalent", "reduced", "disorientation", "IPF_color", or "to_SST".
The Bravais lattice is one of Orientation.lattice_symmetries: The Bravais lattice is given in the Pearson notation:
- triclinic - triclinic
- aP : primitive - aP : primitive
@ -85,35 +114,6 @@ class Orientation(Rotation):
""" """
crystal_families = ['triclinic',
'monoclinic',
'orthorhombic',
'tetragonal',
'hexagonal',
'cubic']
lattice_symmetries = {
'aP': 'triclinic',
'mP': 'monoclinic',
'mS': 'monoclinic',
'oP': 'orthorhombic',
'oS': 'orthorhombic',
'oI': 'orthorhombic',
'oF': 'orthorhombic',
'tP': 'tetragonal',
'tI': 'tetragonal',
'hP': 'hexagonal',
'cP': 'cubic',
'cI': 'cubic',
'cF': 'cubic',
}
@util.extend_docstring(_parameter_doc) @util.extend_docstring(_parameter_doc)
def __init__(self, def __init__(self,
rotation = None, rotation = None,
@ -132,34 +132,17 @@ class Orientation(Rotation):
Defaults to no rotation. Defaults to no rotation.
""" """
from damask.lattice import kinematics
Rotation.__init__(self) if rotation is None else Rotation.__init__(self,rotation=rotation) Rotation.__init__(self) if rotation is None else Rotation.__init__(self,rotation=rotation)
if ( lattice not in self.lattice_symmetries
and lattice not in self.crystal_families):
raise KeyError(f'Lattice "{lattice}" is unknown')
self.family = None
self.lattice = None
self.a = None
self.b = None
self.c = None
self.alpha = None
self.beta = None
self.gamma = None
self.kinematics = None self.kinematics = None
if lattice in self.lattice_symmetries: if lattice in _lattice_symmetries:
self.family = self.lattice_symmetries[lattice] self.family = _lattice_symmetries[lattice]
self.lattice = lattice self.lattice = lattice
self.a = 1 if a is None else a self.a = 1 if a is None else a
self.b = b self.b = b
self.c = c self.c = c
self.alpha = (np.radians(alpha) if degrees else alpha) if alpha is not None else None
self.beta = (np.radians(beta) if degrees else beta) if beta is not None else None
self.gamma = (np.radians(gamma) if degrees else gamma) if gamma is not None else None
self.a = float(self.a) if self.a is not None else \ self.a = float(self.a) if self.a is not None else \
(self.b / self.ratio['b'] if self.b is not None and self.ratio['b'] is not None else (self.b / self.ratio['b'] if self.b is not None and self.ratio['b'] is not None else
self.c / self.ratio['c'] if self.c is not None and self.ratio['c'] is not None else None) self.c / self.ratio['c'] if self.c is not None and self.ratio['c'] is not None else None)
@ -171,9 +154,13 @@ class Orientation(Rotation):
(self.a * self.ratio['c'] if self.a is not None and self.ratio['c'] is not None else (self.a * self.ratio['c'] if self.a is not None and self.ratio['c'] is not None else
self.b / self.ratio['b'] * self.ratio['c'] self.b / self.ratio['b'] * self.ratio['c']
if self.c is not None and self.ratio['b'] is not None and self.ratio['c'] is not None else None) if self.c is not None and self.ratio['b'] is not None and self.ratio['c'] is not None else None)
self.alpha = self.alpha if self.alpha is not None else self.immutable['alpha'] if 'alpha' in self.immutable else None
self.beta = self.beta if self.beta is not None else self.immutable['beta'] if 'beta' in self.immutable else None self.alpha = np.radians(alpha) if degrees and alpha is not None else alpha
self.gamma = self.gamma if self.gamma is not None else self.immutable['gamma'] if 'gamma' in self.immutable else None self.beta = np.radians(beta) if degrees and beta is not None else beta
self.gamma = np.radians(gamma) if degrees and gamma is not None else gamma
if self.alpha is None and 'alpha' in self.immutable: self.alpha = self.immutable['alpha']
if self.beta is None and 'beta' in self.immutable: self.beta = self.immutable['beta']
if self.gamma is None and 'gamma' in self.immutable: self.gamma = self.immutable['gamma']
if \ if \
(self.a is None) \ (self.a is None) \
@ -190,16 +177,22 @@ class Orientation(Rotation):
> np.sum(np.roll([self.alpha,self.beta,self.gamma],r)[1:]) for r in range(3)]): > np.sum(np.roll([self.alpha,self.beta,self.gamma],r)[1:]) for r in range(3)]):
raise ValueError ('Each lattice angle must be less than sum of others') raise ValueError ('Each lattice angle must be less than sum of others')
if self.lattice in kinematics: if self.lattice in _lattice.kinematics:
master = kinematics[self.lattice] master = _lattice.kinematics[self.lattice]
self.kinematics = {} self.kinematics = {}
for m in master: for m in master:
self.kinematics[m] = {'direction':master[m][:,0:3],'plane':master[m][:,3:6]} \ self.kinematics[m] = {'direction':master[m][:,0:3],'plane':master[m][:,3:6]} \
if master[m].shape[-1] == 6 else \ if master[m].shape[-1] == 6 else \
{'direction':self.Bravais_to_Miller(uvtw=master[m][:,0:4]), {'direction':self.Bravais_to_Miller(uvtw=master[m][:,0:4]),
'plane': self.Bravais_to_Miller(hkil=master[m][:,4:8])} 'plane': self.Bravais_to_Miller(hkil=master[m][:,4:8])}
elif lattice in self.crystal_families: elif lattice in _crystal_families:
self.family = lattice self.family = lattice
self.lattice = None
self.a = self.b = self.c = None
self.alpha = self.beta = self.gamma = None
else:
raise KeyError(f'Lattice "{lattice}" is unknown')
def __repr__(self): def __repr__(self):
@ -676,11 +669,9 @@ class Orientation(Rotation):
https://doi.org/10.1016/j.actamat.2004.11.021 https://doi.org/10.1016/j.actamat.2004.11.021
""" """
from damask.lattice import relations if model not in _lattice.relations:
if model not in relations:
raise KeyError(f'Orientation relationship "{model}" is unknown') raise KeyError(f'Orientation relationship "{model}" is unknown')
r = relations[model] r = _lattice.relations[model]
if self.lattice not in r: if self.lattice not in r:
raise KeyError(f'Relationship "{model}" not supported for lattice "{self.lattice}"') raise KeyError(f'Relationship "{model}" not supported for lattice "{self.lattice}"')

View File

@ -150,9 +150,8 @@ class VTK:
---------- ----------
fname : str or pathlib.Path fname : str or pathlib.Path
Filename for reading. Valid extensions are .vtr, .vtu, .vtp, and .vtk. Filename for reading. Valid extensions are .vtr, .vtu, .vtp, and .vtk.
dataset_type : str, optional dataset_type : {'vtkRectilinearGrid', 'vtkUnstructuredGrid', 'vtkPolyData'}, optional
Name of the vtk.vtkDataSet subclass when opening a .vtk file. Name of the vtk.vtkDataSet subclass when opening a .vtk file.
Valid types are vtkRectilinearGrid, vtkUnstructuredGrid, and vtkPolyData.
Returns Returns
------- -------

View File

@ -124,9 +124,6 @@ def strain(F,t,m):
""" """
Calculate strain tensor (SethHill family). Calculate strain tensor (SethHill family).
For details refer to https://en.wikipedia.org/wiki/Finite_strain_theory and
https://de.wikipedia.org/wiki/Verzerrungstensor
Parameters Parameters
---------- ----------
F : numpy.ndarray of shape (...,3,3) F : numpy.ndarray of shape (...,3,3)
@ -142,6 +139,11 @@ def strain(F,t,m):
epsilon : numpy.ndarray of shape (...,3,3) epsilon : numpy.ndarray of shape (...,3,3)
Strain of F. Strain of F.
References
----------
https://en.wikipedia.org/wiki/Finite_strain_theory
https://de.wikipedia.org/wiki/Verzerrungstensor
""" """
if t == 'V': if t == 'V':
w,n = _np.linalg.eigh(deformation_Cauchy_Green_left(F)) w,n = _np.linalg.eigh(deformation_Cauchy_Green_left(F))
@ -150,7 +152,6 @@ def strain(F,t,m):
if m > 0.0: if m > 0.0:
eps = 1.0/(2.0*abs(m)) * (+ _np.einsum('...j,...kj,...lj',w**m,n,n) - _np.eye(3)) eps = 1.0/(2.0*abs(m)) * (+ _np.einsum('...j,...kj,...lj',w**m,n,n) - _np.eye(3))
elif m < 0.0: elif m < 0.0:
eps = 1.0/(2.0*abs(m)) * (- _np.einsum('...j,...kj,...lj',w**m,n,n) + _np.eye(3)) eps = 1.0/(2.0*abs(m)) * (- _np.einsum('...j,...kj,...lj',w**m,n,n) + _np.eye(3))
else: else:

View File

@ -1,3 +1,5 @@
"""Miscellaneous helper functionality."""
import sys import sys
import datetime import datetime
import os import os
@ -177,26 +179,36 @@ def execute(cmd,wd='./',env=None):
def natural_sort(key): def natural_sort(key):
"""
Natural sort.
For use in python's 'sorted'.
References
----------
https://en.wikipedia.org/wiki/Natural_sort_order
"""
convert = lambda text: int(text) if text.isdigit() else text convert = lambda text: int(text) if text.isdigit() else text
return [ convert(c) for c in re.split('([0-9]+)', key) ] return [ convert(c) for c in re.split('([0-9]+)', key) ]
def show_progress(iterable,N_iter=None,prefix='',bar_length=50): def show_progress(iterable,N_iter=None,prefix='',bar_length=50):
""" """
Decorate a loop with a status bar. Decorate a loop with a progress bar.
Use similar like enumerate. Use similar like enumerate.
Parameters Parameters
---------- ----------
iterable : iterable/function with yield statement iterable : iterable or function with yield statement
Iterable (or function with yield statement) to be decorated. Iterable (or function with yield statement) to be decorated.
N_iter : int N_iter : int, optional
Total # of iterations. Needed if number of iterations can not be obtained as len(iterable). Total number of iterations. Required unless obtainable as len(iterable).
prefix : str, optional. prefix : str, optional
Prefix string. Prefix string.
bar_length : int, optional bar_length : int, optional
Character length of bar. Defaults to 50. Length of progress bar in characters. Defaults to 50.
""" """
if N_iter in [0,1] or (hasattr(iterable,'__len__') and len(iterable) <= 1): if N_iter in [0,1] or (hasattr(iterable,'__len__') and len(iterable) <= 1):
@ -509,6 +521,7 @@ def dict_prune(d):
v = dict_prune(v) v = dict_prune(v)
if not isinstance(v,dict) or v != {}: if not isinstance(v,dict) or v != {}:
new[k] = v new[k] = v
return new return new

View File

@ -12,7 +12,7 @@ setuptools.setup(
author='The DAMASK team', author='The DAMASK team',
author_email='damask@mpie.de', author_email='damask@mpie.de',
description='DAMASK library', description='DAMASK library',
long_description='Python library for pre and post processing of DAMASK simulations', long_description='Python library for managing DAMASK simulations',
url='https://damask.mpie.de', url='https://damask.mpie.de',
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
include_package_data=True, include_package_data=True,

View File

@ -5,9 +5,10 @@ from itertools import permutations
from damask import Rotation from damask import Rotation
from damask import Orientation from damask import Orientation
from damask import Table from damask import Table
from damask import lattice
from damask import util from damask import util
from damask import grid_filters from damask import grid_filters
from damask import _lattice as lattice
from damask._orientation import _crystal_families as crystal_families
@pytest.fixture @pytest.fixture
@ -22,7 +23,7 @@ def set_of_rodrigues(set_of_quaternions):
class TestOrientation: class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[None,5,(4,6)]) @pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_equal(self,lattice,shape): def test_equal(self,lattice,shape):
R = Rotation.from_random(shape) R = Rotation.from_random(shape)
@ -30,14 +31,14 @@ class TestOrientation:
(Orientation(R,lattice) == Orientation(R,lattice)).all() (Orientation(R,lattice) == Orientation(R,lattice)).all()
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[None,5,(4,6)]) @pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_unequal(self,lattice,shape): def test_unequal(self,lattice,shape):
R = Rotation.from_random(shape) R = Rotation.from_random(shape)
assert not ( Orientation(R,lattice) != Orientation(R,lattice) if shape is None else \ assert not ( Orientation(R,lattice) != Orientation(R,lattice) if shape is None else \
(Orientation(R,lattice) != Orientation(R,lattice)).any()) (Orientation(R,lattice) != Orientation(R,lattice)).any())
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[None,5,(4,6)]) @pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_close(self,lattice,shape): def test_close(self,lattice,shape):
R = Orientation.from_random(lattice=lattice,shape=shape) R = Orientation.from_random(lattice=lattice,shape=shape)
@ -182,14 +183,14 @@ class TestOrientation:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Orientation(lattice='aP',a=1,b=2,c=3,alpha=45,beta=45,gamma=90.0001,degrees=True) # noqa Orientation(lattice='aP',a=1,b=2,c=3,alpha=45,beta=45,gamma=90.0001,degrees=True) # noqa
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('angle',[10,20,30,40]) @pytest.mark.parametrize('angle',[10,20,30,40])
def test_average(self,angle,lattice): def test_average(self,angle,lattice):
o = Orientation.from_axis_angle(lattice=lattice,axis_angle=[[0,0,1,10],[0,0,1,angle]],degrees=True) o = Orientation.from_axis_angle(lattice=lattice,axis_angle=[[0,0,1,10],[0,0,1,angle]],degrees=True)
avg_angle = o.average().as_axis_angle(degrees=True,pair=True)[1] avg_angle = o.average().as_axis_angle(degrees=True,pair=True)[1]
assert np.isclose(avg_angle,10+(angle-10)/2.) assert np.isclose(avg_angle,10+(angle-10)/2.)
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_reduced_equivalent(self,lattice): def test_reduced_equivalent(self,lattice):
i = Orientation(lattice=lattice) i = Orientation(lattice=lattice)
o = Orientation.from_random(lattice=lattice) o = Orientation.from_random(lattice=lattice)
@ -197,7 +198,7 @@ class TestOrientation:
FZ = np.argmin(abs(eq.misorientation(i.broadcast_to(len(eq))).as_axis_angle(pair=True)[1])) FZ = np.argmin(abs(eq.misorientation(i.broadcast_to(len(eq))).as_axis_angle(pair=True)[1]))
assert o.reduced == eq[FZ] assert o.reduced == eq[FZ]
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('N',[1,8,32]) @pytest.mark.parametrize('N',[1,8,32])
def test_disorientation(self,lattice,N): def test_disorientation(self,lattice,N):
o = Orientation.from_random(lattice=lattice,shape=N) o = Orientation.from_random(lattice=lattice,shape=N)
@ -215,7 +216,7 @@ class TestOrientation:
.misorientation(p[n].equivalent[ops[n][1]]) .misorientation(p[n].equivalent[ops[n][1]])
.as_quaternion()) .as_quaternion())
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('a,b',[ @pytest.mark.parametrize('a,b',[
((2,3,2),(2,3,2)), ((2,3,2),(2,3,2)),
((2,2),(4,4)), ((2,2),(4,4)),
@ -230,20 +231,20 @@ class TestOrientation:
assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \ assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \
.isclose(o.disorientation(p)[tuple(loc)]) .isclose(o.disorientation(p)[tuple(loc)])
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_disorientation360(self,lattice): def test_disorientation360(self,lattice):
o_1 = Orientation(Rotation(),lattice) o_1 = Orientation(Rotation(),lattice)
o_2 = Orientation.from_Euler_angles(lattice=lattice,phi=[360,0,0],degrees=True) o_2 = Orientation.from_Euler_angles(lattice=lattice,phi=[360,0,0],degrees=True)
assert np.allclose((o_1.disorientation(o_2)).as_matrix(),np.eye(3)) assert np.allclose((o_1.disorientation(o_2)).as_matrix(),np.eye(3))
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)]) @pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
def test_reduced_vectorization(self,lattice,shape): def test_reduced_vectorization(self,lattice,shape):
o = Orientation.from_random(lattice=lattice,shape=shape) o = Orientation.from_random(lattice=lattice,shape=shape)
for r, theO in zip(o.reduced.flatten(),o.flatten()): for r, theO in zip(o.reduced.flatten(),o.flatten()):
assert r == theO.reduced assert r == theO.reduced
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_reduced_corner_cases(self,lattice): def test_reduced_corner_cases(self,lattice):
# test whether there is always a sym-eq rotation that falls into the FZ # test whether there is always a sym-eq rotation that falls into the FZ
N = np.random.randint(10,40) N = np.random.randint(10,40)
@ -253,7 +254,7 @@ class TestOrientation:
assert evenly_distributed.shape == evenly_distributed.reduced.shape assert evenly_distributed.shape == evenly_distributed.reduced.shape
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)]) @pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
@ -262,7 +263,7 @@ class TestOrientation:
for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.to_SST(vector=vector,proper=proper)) assert np.allclose(r,theO.to_SST(vector=vector,proper=proper))
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)]) @pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
@ -272,7 +273,7 @@ class TestOrientation:
for r, theO in zip(o.IPF_color(vector,in_SST=in_SST,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.IPF_color(vector,in_SST=in_SST,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.IPF_color(vector,in_SST=in_SST,proper=proper)) assert np.allclose(r,theO.IPF_color(vector,in_SST=in_SST,proper=proper))
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('a,b',[ @pytest.mark.parametrize('a,b',[
((2,3,2),(2,3,2)), ((2,3,2),(2,3,2)),
((2,2),(4,4)), ((2,2),(4,4)),
@ -300,7 +301,7 @@ class TestOrientation:
assert np.allclose(np.array(color['RGB']), assert np.allclose(np.array(color['RGB']),
cube.IPF_color(vector=np.array(direction),proper=proper)) cube.IPF_color(vector=np.array(direction),proper=proper))
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_IPF_equivalent(self,set_of_quaternions,lattice,proper): def test_IPF_equivalent(self,set_of_quaternions,lattice,proper):
direction = np.random.random(3)*2.0-1.0 direction = np.random.random(3)*2.0-1.0
@ -308,13 +309,13 @@ class TestOrientation:
color = o.IPF_color(vector=direction,proper=proper) color = o.IPF_color(vector=direction,proper=proper)
assert np.allclose(np.broadcast_to(color[0,...],color.shape),color) assert np.allclose(np.broadcast_to(color[0,...],color.shape),color)
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_in_FZ_vectorization(self,set_of_rodrigues,lattice): def test_in_FZ_vectorization(self,set_of_rodrigues,lattice):
result = Orientation.from_Rodrigues_vector(rho=set_of_rodrigues.reshape((-1,4,4)),lattice=lattice).in_FZ.reshape(-1) result = Orientation.from_Rodrigues_vector(rho=set_of_rodrigues.reshape((-1,4,4)),lattice=lattice).in_FZ.reshape(-1)
for r,rho in zip(result,set_of_rodrigues[:len(result)]): for r,rho in zip(result,set_of_rodrigues[:len(result)]):
assert r == Orientation.from_Rodrigues_vector(rho=rho,lattice=lattice).in_FZ assert r == Orientation.from_Rodrigues_vector(rho=rho,lattice=lattice).in_FZ
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_in_disorientation_FZ_vectorization(self,set_of_rodrigues,lattice): def test_in_disorientation_FZ_vectorization(self,set_of_rodrigues,lattice):
result = Orientation.from_Rodrigues_vector(rho=set_of_rodrigues.reshape((-1,4,4)), result = Orientation.from_Rodrigues_vector(rho=set_of_rodrigues.reshape((-1,4,4)),
lattice=lattice).in_disorientation_FZ.reshape(-1) lattice=lattice).in_disorientation_FZ.reshape(-1)
@ -322,7 +323,7 @@ class TestOrientation:
assert r == Orientation.from_Rodrigues_vector(rho=rho,lattice=lattice).in_disorientation_FZ assert r == Orientation.from_Rodrigues_vector(rho=rho,lattice=lattice).in_disorientation_FZ
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
def test_in_SST_vectorization(self,lattice,proper): def test_in_SST_vectorization(self,lattice,proper):
vecs = np.random.rand(20,4,3) vecs = np.random.rand(20,4,3)
result = Orientation(lattice=lattice).in_SST(vecs,proper).flatten() result = Orientation(lattice=lattice).in_SST(vecs,proper).flatten()
@ -393,7 +394,7 @@ class TestOrientation:
a=a,b=b,c=c, a=a,b=b,c=c,
alpha=alpha,beta=beta,gamma=gamma).related(relation) # noqa alpha=alpha,beta=beta,gamma=gamma).related(relation) # noqa
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',crystal_families)
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_in_SST(self,lattice,proper): def test_in_SST(self,lattice,proper):
assert Orientation(lattice=lattice).in_SST(np.zeros(3),proper) assert Orientation(lattice=lattice).in_SST(np.zeros(3),proper)