object oriented approach

Orientation (of special lattice) should not have generic attributes
Also, import at the beginning of the file
This commit is contained in:
Martin Diehl 2021-04-29 19:44:21 +02:00
parent 59961a71ac
commit b1ad8197f2
5 changed files with 61 additions and 65 deletions

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

@ -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,12 +132,10 @@ 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 if ( lattice not in _lattice_symmetries
and lattice not in self.crystal_families): and lattice not in _crystal_families):
raise KeyError(f'Lattice "{lattice}" is unknown') raise KeyError(f'Lattice "{lattice}" is unknown')
self.family = None self.family = None
@ -150,8 +148,8 @@ class Orientation(Rotation):
self.gamma = 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
@ -190,15 +188,15 @@ 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
@ -676,11 +674,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

@ -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)