polishing

This commit is contained in:
Martin Diehl 2020-05-20 16:19:12 +02:00
parent b59d773689
commit bb419d49df
2 changed files with 114 additions and 87 deletions

View File

@ -9,7 +9,6 @@ _sc = np.pi**(1./6.)/6.**(1./6.)
_beta = np.pi**(5./6.)/6.**(1./6.)/2. _beta = np.pi**(5./6.)/6.**(1./6.)/2.
_R1 = (3.*np.pi/4.)**(1./3.) _R1 = (3.*np.pi/4.)**(1./3.)
class Rotation: class Rotation:
u""" u"""
Orientation stored with functionality for conversion to different representations. Orientation stored with functionality for conversion to different representations.
@ -427,7 +426,7 @@ class Rotation:
if P > 0: ho *= -1 # convert from P=1 to P=-1 if P > 0: ho *= -1 # convert from P=1 to P=-1
if np.any(np.linalg.norm(ho,axis=-1) > (3.*np.pi/4.)**(1./3.)+1e-9): if np.any(np.linalg.norm(ho,axis=-1) >_R1+1e-9):
raise ValueError('Homochoric coordinate outside of the sphere.') raise ValueError('Homochoric coordinate outside of the sphere.')
return Rotation(Rotation._ho2qu(ho)) return Rotation(Rotation._ho2qu(ho))

View File

@ -520,6 +520,7 @@ class TestRotation:
(Rotation._qu2ho,Rotation._ho2qu), (Rotation._qu2ho,Rotation._ho2qu),
(Rotation._qu2cu,Rotation._cu2qu)]) (Rotation._qu2cu,Rotation._cu2qu)])
def test_quaternion_internal(self,default,forward,backward): def test_quaternion_internal(self,default,forward,backward):
"""Ensure invariance of conversion from quaternion and back."""
for rot in default: for rot in default:
m = rot.as_quaternion() m = rot.as_quaternion()
o = backward(forward(m)) o = backward(forward(m))
@ -536,6 +537,7 @@ class TestRotation:
(Rotation._om2ho,Rotation._ho2om), (Rotation._om2ho,Rotation._ho2om),
(Rotation._om2cu,Rotation._cu2om)]) (Rotation._om2cu,Rotation._cu2om)])
def test_matrix_internal(self,default,forward,backward): def test_matrix_internal(self,default,forward,backward):
"""Ensure invariance of conversion from rotation matrix and back."""
for rot in default: for rot in default:
m = rot.as_matrix() m = rot.as_matrix()
o = backward(forward(m)) o = backward(forward(m))
@ -550,6 +552,7 @@ class TestRotation:
(Rotation._eu2ho,Rotation._ho2eu), (Rotation._eu2ho,Rotation._ho2eu),
(Rotation._eu2cu,Rotation._cu2eu)]) (Rotation._eu2cu,Rotation._cu2eu)])
def test_Eulers_internal(self,default,forward,backward): def test_Eulers_internal(self,default,forward,backward):
"""Ensure invariance of conversion from Euler angles and back."""
for rot in default: for rot in default:
m = rot.as_Eulers() m = rot.as_Eulers()
o = backward(forward(m)) o = backward(forward(m))
@ -569,6 +572,7 @@ class TestRotation:
(Rotation._ax2ho,Rotation._ho2ax), (Rotation._ax2ho,Rotation._ho2ax),
(Rotation._ax2cu,Rotation._cu2ax)]) (Rotation._ax2cu,Rotation._cu2ax)])
def test_axis_angle_internal(self,default,forward,backward): def test_axis_angle_internal(self,default,forward,backward):
"""Ensure invariance of conversion from axis angle angles pair and back."""
for rot in default: for rot in default:
m = rot.as_axis_angle() m = rot.as_axis_angle()
o = backward(forward(m)) o = backward(forward(m))
@ -585,6 +589,7 @@ class TestRotation:
(Rotation._ro2ho,Rotation._ho2ro), (Rotation._ro2ho,Rotation._ho2ro),
(Rotation._ro2cu,Rotation._cu2ro)]) (Rotation._ro2cu,Rotation._cu2ro)])
def test_Rodrigues_internal(self,default,forward,backward): def test_Rodrigues_internal(self,default,forward,backward):
"""Ensure invariance of conversion from Rodrigues-Frank vector and back."""
cutoff = np.tan(np.pi*.5*(1.-1e-4)) cutoff = np.tan(np.pi*.5*(1.-1e-4))
for rot in default: for rot in default:
m = rot.as_Rodrigues() m = rot.as_Rodrigues()
@ -601,12 +606,114 @@ class TestRotation:
(Rotation._ho2ro,Rotation._ro2ho), (Rotation._ho2ro,Rotation._ro2ho),
(Rotation._ho2cu,Rotation._cu2ho)]) (Rotation._ho2cu,Rotation._cu2ho)])
def test_homochoric_internal(self,default,forward,backward): def test_homochoric_internal(self,default,forward,backward):
"""Ensure invariance of conversion from homochoric vector and back."""
for rot in default: for rot in default:
m = rot.as_homochoric() m = rot.as_homochoric()
o = backward(forward(m)) o = backward(forward(m))
ok = np.allclose(m,o,atol=atol) ok = np.allclose(m,o,atol=atol)
print(m,o,rot.as_quaternion()) print(m,o,rot.as_quaternion())
assert ok and np.linalg.norm(o) < (3.*np.pi/4.)**(1./3.) + 1.e-9 assert ok and np.linalg.norm(o) < _R1 + 1.e-9
@pytest.mark.parametrize('forward,backward',[(Rotation._cu2qu,Rotation._qu2cu),
(Rotation._cu2om,Rotation._om2cu),
#(Rotation._cu2eu,Rotation._eu2cu),
(Rotation._cu2ax,Rotation._ax2cu),
(Rotation._cu2ro,Rotation._ro2cu),
(Rotation._cu2ho,Rotation._ho2cu)])
def test_cubochoric_internal(self,default,forward,backward):
"""Ensure invariance of conversion from cubochoric vector and back."""
for rot in default:
m = rot.as_cubochoric()
o = backward(forward(m))
ok = np.allclose(m,o,atol=atol)
print(m,o,rot.as_quaternion())
assert ok and np.max(np.abs(o)) < np.pi**(2./3.) * 0.5 + 1.e-9
@pytest.mark.parametrize('vectorized, single',[(Rotation._qu2om,qu2om),
(Rotation._qu2eu,qu2eu),
(Rotation._qu2ax,qu2ax),
(Rotation._qu2ro,qu2ro),
(Rotation._qu2ho,qu2ho)])
def test_quaternion_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for quaternion against single point calculation."""
qu = np.array([rot.as_quaternion() for rot in default])
vectorized(qu.reshape(qu.shape[0]//2,-1,4))
co = vectorized(qu)
for q,c in zip(qu,co):
print(q,c)
assert np.allclose(single(q),c) and np.allclose(single(q),vectorized(q))
@pytest.mark.parametrize('vectorized, single',[(Rotation._om2qu,om2qu),
(Rotation._om2eu,om2eu),
(Rotation._om2ax,om2ax)])
def test_matrix_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for rotation matrix against single point calculation."""
om = np.array([rot.as_matrix() for rot in default])
vectorized(om.reshape(om.shape[0]//2,-1,3,3))
co = vectorized(om)
for o,c in zip(om,co):
print(o,c)
assert np.allclose(single(o),c) and np.allclose(single(o),vectorized(o))
@pytest.mark.parametrize('vectorized, single',[(Rotation._eu2qu,eu2qu),
(Rotation._eu2om,eu2om),
(Rotation._eu2ax,eu2ax),
(Rotation._eu2ro,eu2ro)])
def test_Eulers_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for Euler angles against single point calculation."""
eu = np.array([rot.as_Eulers() for rot in default])
vectorized(eu.reshape(eu.shape[0]//2,-1,3))
co = vectorized(eu)
for e,c in zip(eu,co):
print(e,c)
assert np.allclose(single(e),c) and np.allclose(single(e),vectorized(e))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ax2qu,ax2qu),
(Rotation._ax2om,ax2om),
(Rotation._ax2ro,ax2ro),
(Rotation._ax2ho,ax2ho)])
def test_axis_angle_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for axis angle pair against single point calculation."""
ax = np.array([rot.as_axis_angle() for rot in default])
vectorized(ax.reshape(ax.shape[0]//2,-1,4))
co = vectorized(ax)
for a,c in zip(ax,co):
print(a,c)
assert np.allclose(single(a),c) and np.allclose(single(a),vectorized(a))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ro2ax,ro2ax),
(Rotation._ro2ho,ro2ho)])
def test_Rodrigues_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for Rodrigues-Frank vector against single point calculation."""
ro = np.array([rot.as_Rodrigues() for rot in default])
vectorized(ro.reshape(ro.shape[0]//2,-1,4))
co = vectorized(ro)
for r,c in zip(ro,co):
print(r,c)
assert np.allclose(single(r),c) and np.allclose(single(r),vectorized(r))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ho2ax,ho2ax),
(Rotation._ho2cu,ho2cu)])
def test_homochoric_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for homochoric vector against single point calculation."""
ho = np.array([rot.as_homochoric() for rot in default])
vectorized(ho.reshape(ho.shape[0]//2,-1,3))
co = vectorized(ho)
for h,c in zip(ho,co):
print(h,c)
assert np.allclose(single(h),c) and np.allclose(single(h),vectorized(h))
@pytest.mark.parametrize('vectorized, single',[(Rotation._cu2ho,cu2ho)])
def test_cubochoric_vectorization(self,default,vectorized,single):
"""Check vectorized implementation for cubochoric vector against single point calculation."""
cu = np.array([rot.as_cubochoric() for rot in default])
vectorized(cu.reshape(cu.shape[0]//2,-1,3))
co = vectorized(cu)
for u,c in zip(cu,co):
print(u,c)
assert np.allclose(single(u),c) and np.allclose(single(u),vectorized(u))
@pytest.mark.parametrize('degrees',[True,False]) @pytest.mark.parametrize('degrees',[True,False])
def test_Eulers(self,default,degrees): def test_Eulers(self,default,degrees):
@ -622,7 +729,7 @@ class TestRotation:
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
@pytest.mark.parametrize('normalise',[True,False]) @pytest.mark.parametrize('normalise',[True,False])
@pytest.mark.parametrize('degrees',[True,False]) @pytest.mark.parametrize('degrees',[True,False])
def test_AxisAngle(self,default,degrees,normalise,P): def test_axis_angle(self,default,degrees,normalise,P):
c = np.array([P*-1,P*-1,P*-1,1.]) c = np.array([P*-1,P*-1,P*-1,1.])
for rot in default: for rot in default:
m = rot.as_Eulers() m = rot.as_Eulers()
@ -636,7 +743,7 @@ class TestRotation:
print(m,o,rot.as_quaternion()) print(m,o,rot.as_quaternion())
assert ok and (np.zeros(3)-1.e-9 <= o).all() and (o <= np.array([np.pi*2.,np.pi,np.pi*2.])+1.e-9).all() assert ok and (np.zeros(3)-1.e-9 <= o).all() and (o <= np.array([np.pi*2.,np.pi,np.pi*2.])+1.e-9).all()
def test_Matrix(self,default): def test_matrix(self,default):
for rot in default: for rot in default:
m = rot.as_axis_angle() m = rot.as_axis_angle()
o = Rotation.from_axis_angle(rot.as_axis_angle()).as_axis_angle() o = Rotation.from_axis_angle(rot.as_axis_angle()).as_axis_angle()
@ -658,7 +765,7 @@ class TestRotation:
assert ok and np.isclose(np.linalg.det(o),1.0) assert ok and np.isclose(np.linalg.det(o),1.0)
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
def test_Homochoric(self,default,P): def test_homochoric(self,default,P):
cutoff = np.tan(np.pi*.5*(1.-1e-4)) cutoff = np.tan(np.pi*.5*(1.-1e-4))
for rot in default: for rot in default:
m = rot.as_Rodrigues() m = rot.as_Rodrigues()
@ -669,7 +776,7 @@ class TestRotation:
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) assert ok and np.isclose(np.linalg.norm(o[:3]),1.0)
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
def test_Cubochoric(self,default,P): def test_cubochoric(self,default,P):
for rot in default: for rot in default:
m = rot.as_homochoric() m = rot.as_homochoric()
o = Rotation.from_cubochoric(rot.as_cubochoric()*P*-1,P).as_homochoric() o = Rotation.from_cubochoric(rot.as_cubochoric()*P*-1,P).as_homochoric()
@ -678,7 +785,7 @@ class TestRotation:
assert ok and np.linalg.norm(o) < (3.*np.pi/4.)**(1./3.) + 1.e-9 assert ok and np.linalg.norm(o) < (3.*np.pi/4.)**(1./3.) + 1.e-9
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
def test_Quaternion(self,default,P): def test_quaternion(self,default,P):
c = np.array([1,P*-1,P*-1,P*-1]) c = np.array([1,P*-1,P*-1,P*-1])
for rot in default: for rot in default:
m = rot.as_cubochoric() m = rot.as_cubochoric()
@ -711,85 +818,6 @@ class TestRotation:
with pytest.raises(ValueError): with pytest.raises(ValueError):
function(invalid) function(invalid)
@pytest.mark.parametrize('vectorized, single',[(Rotation._qu2om,qu2om),
(Rotation._qu2eu,qu2eu),
(Rotation._qu2ax,qu2ax),
(Rotation._qu2ro,qu2ro),
(Rotation._qu2ho,qu2ho)])
def test_quaternion_vectorization(self,default,vectorized,single):
qu = np.array([rot.as_quaternion() for rot in default])
vectorized(qu.reshape(qu.shape[0]//2,-1,4))
co = vectorized(qu)
for q,c in zip(qu,co):
print(q,c)
assert np.allclose(single(q),c) and np.allclose(single(q),vectorized(q))
@pytest.mark.parametrize('vectorized, single',[(Rotation._om2qu,om2qu),
(Rotation._om2eu,om2eu),
(Rotation._om2ax,om2ax)])
def test_matrix_vectorization(self,default,vectorized,single):
om = np.array([rot.as_matrix() for rot in default])
vectorized(om.reshape(om.shape[0]//2,-1,3,3))
co = vectorized(om)
for o,c in zip(om,co):
print(o,c)
assert np.allclose(single(o),c) and np.allclose(single(o),vectorized(o))
@pytest.mark.parametrize('vectorized, single',[(Rotation._eu2qu,eu2qu),
(Rotation._eu2om,eu2om),
(Rotation._eu2ax,eu2ax),
(Rotation._eu2ro,eu2ro)])
def test_Euler_vectorization(self,default,vectorized,single):
eu = np.array([rot.as_Eulers() for rot in default])
vectorized(eu.reshape(eu.shape[0]//2,-1,3))
co = vectorized(eu)
for e,c in zip(eu,co):
print(e,c)
assert np.allclose(single(e),c) and np.allclose(single(e),vectorized(e))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ax2qu,ax2qu),
(Rotation._ax2om,ax2om),
(Rotation._ax2ro,ax2ro),
(Rotation._ax2ho,ax2ho)])
def test_axisAngle_vectorization(self,default,vectorized,single):
ax = np.array([rot.as_axis_angle() for rot in default])
vectorized(ax.reshape(ax.shape[0]//2,-1,4))
co = vectorized(ax)
for a,c in zip(ax,co):
print(a,c)
assert np.allclose(single(a),c) and np.allclose(single(a),vectorized(a))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ro2ax,ro2ax),
(Rotation._ro2ho,ro2ho)])
def test_Rodrigues_vectorization(self,default,vectorized,single):
ro = np.array([rot.as_Rodrigues() for rot in default])
vectorized(ro.reshape(ro.shape[0]//2,-1,4))
co = vectorized(ro)
for r,c in zip(ro,co):
print(r,c)
assert np.allclose(single(r),c) and np.allclose(single(r),vectorized(r))
@pytest.mark.parametrize('vectorized, single',[(Rotation._ho2ax,ho2ax),
(Rotation._ho2cu,ho2cu)])
def test_homochoric_vectorization(self,default,vectorized,single):
ho = np.array([rot.as_homochoric() for rot in default])
vectorized(ho.reshape(ho.shape[0]//2,-1,3))
co = vectorized(ho)
for h,c in zip(ho,co):
print(h,c)
assert np.allclose(single(h),c) and np.allclose(single(h),vectorized(h))
@pytest.mark.parametrize('vectorized, single',[(Rotation._cu2ho,cu2ho)])
def test_cubochoric_vectorization(self,default,vectorized,single):
cu = np.array([rot.as_cubochoric() for rot in default])
vectorized(cu.reshape(cu.shape[0]//2,-1,3))
co = vectorized(cu)
for u,c in zip(cu,co):
print(u,c)
assert np.allclose(single(u),c) and np.allclose(single(u),vectorized(u))
@pytest.mark.parametrize('direction',['forward', @pytest.mark.parametrize('direction',['forward',
'backward']) 'backward'])
def test_pyramid_vectorization(self,direction): def test_pyramid_vectorization(self,direction):