more tests

Hotfix needed for axis angle to matrix (not used in DAMASK, needs
further investigation)
This commit is contained in:
Martin Diehl 2020-05-19 19:41:50 +02:00
parent de79a5af43
commit a6b0aaffba
3 changed files with 39 additions and 21 deletions

View File

@ -669,7 +669,7 @@ class Rotation:
"""Rotation matrix to Bunge-Euler angles."""
with np.errstate(invalid='ignore',divide='ignore'):
zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2)
eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.0,1e-4),
eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.0,1e-9),
np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]),
np.pi*0.5*(1-om[...,2,2:3]),
np.zeros(om.shape[:-2]+(1,)),
@ -679,30 +679,30 @@ class Rotation:
np.arctan2(om[...,0,2:3]*zeta,+om[...,1,2:3]*zeta)
])
)
eu[np.abs(eu)<1.e-6] = 0.0
eu[np.abs(eu)<1.e-8] = 0.0
eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu)
return eu
@staticmethod
def om2ax(om):
"""Rotation matrix to axis angle pair."""
return Rotation.qu2ax(Rotation.om2qu(om)) # HOTFIX
diag_delta = -_P*np.block([om[...,1,2:3]-om[...,2,1:2],
om[...,2,0:1]-om[...,0,2:3],
om[...,0,1:2]-om[...,1,0:1]
])
diag_delta[np.abs(diag_delta)<1.e-6] = 1.0
t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.0).reshape(om.shape[:-2]+(1,))
w,vr = np.linalg.eig(om)
# mask duplicated real eigenvalues
w[np.isclose(w[...,0],1.0+0.0j),1:] = 0.
w[np.isclose(w[...,1],1.0+0.0j),2:] = 0.
vr = np.swapaxes(vr,-1,-2)
ax = np.where(np.abs(diag_delta)<0,
ax = np.where(np.abs(diag_delta)<1e-12,
np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)),
np.abs(np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,))) \
*np.sign(diag_delta))
ax = np.block([ax,np.arccos(np.clip(t,-1.0,1.0))])
ax[np.abs(ax[...,3])<1.e-6] = [ 0.0, 0.0, 1.0, 0.0]
ax[np.abs(ax[...,3])<1.e-8] = [ 0.0, 0.0, 1.0, 0.0]
return ax
@staticmethod
@ -804,6 +804,7 @@ class Rotation:
@staticmethod
def ax2om(ax):
"""Axis angle pair to rotation matrix."""
return Rotation.qu2om(Rotation.ax2qu(ax)) # HOTFIX
c = np.cos(ax[...,3:4])
s = np.sin(ax[...,3:4])
omc = 1. -c

View File

@ -134,25 +134,26 @@ def om2qu(a):
def om2eu(om):
"""Rotation matrix to Bunge-Euler angles."""
if not np.isclose(np.abs(om[2,2]),1.0,1.e-4):
if not np.isclose(np.abs(om[2,2]),1.0,1.e-9):
zeta = 1.0/np.sqrt(1.0-om[2,2]**2)
eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta),
np.arccos(om[2,2]),
np.arctan2(om[0,2]*zeta, om[1,2]*zeta)])
else:
eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation
eu[np.abs(eu)<1.e-6] = 0.0
eu[np.abs(eu)<1.e-8] = 0.0
eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu)
return eu
def om2ax(om):
"""Rotation matrix to axis angle pair."""
return qu2ax(om2qu(om)) # HOTFIX
ax=np.empty(4)
# first get the rotation angle
t = 0.5*(om.trace() -1.0)
ax[3] = np.arccos(np.clip(t,-1.0,1.0))
if np.abs(ax[3])<1.e-6:
if np.abs(ax[3])<1.e-8:
ax = np.array([ 0.0, 0.0, 1.0, 0.0])
else:
w,vr = np.linalg.eig(om)
@ -160,8 +161,7 @@ def om2ax(om):
i = np.where(np.isclose(w,1.0+0.0j))[0][0]
ax[0:3] = np.real(vr[0:3,i])
diagDelta = -_P*np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]])
diagDelta[np.abs(diagDelta)<1.e-6] = 1.0
ax[0:3] = np.where(np.abs(diagDelta)<0, ax[0:3],np.abs(ax[0:3])*np.sign(diagDelta))
ax[0:3] = np.where(np.abs(diagDelta)<1e-12, ax[0:3],np.abs(ax[0:3])*np.sign(diagDelta))
return ax
#---------- Bunge-Euler angles ----------
@ -229,6 +229,7 @@ def ax2qu(ax):
def ax2om(ax):
"""Axis angle pair to rotation matrix."""
return qu2om(ax2qu(ax)) # HOTFIX
c = np.cos(ax[3])
s = np.sin(ax[3])
omc = 1.0-c

View File

@ -107,10 +107,10 @@ class TestRotation:
print(m,o,rot.as_quaternion())
assert ok and np.isclose(np.linalg.norm(o),1.0)
@pytest.mark.parametrize('forward,backward',[(Rotation.om2qu,Rotation.qu2om)])
#(Rotation.om2eu,Rotation.eu2om),
#(Rotation.om2ax,Rotation.ax2om),
#(Rotation.om2ro,Rotation.ro2om),
@pytest.mark.parametrize('forward,backward',[(Rotation.om2qu,Rotation.qu2om),
(Rotation.om2eu,Rotation.eu2om),
(Rotation.om2ax,Rotation.ax2om),
(Rotation.om2ro,Rotation.ro2om)])
#(Rotation.om2ho,Rotation.ho2om),
#(Rotation.om2cu,Rotation.cu2om)])
def test_matrix_internal(self,default,forward,backward):
@ -121,12 +121,12 @@ class TestRotation:
print(m,o,rot.as_quaternion())
assert ok and np.isclose(np.linalg.det(o),1.0)
@pytest.mark.parametrize('forward,backward',[(Rotation.eu2qu,Rotation.qu2eu)])
#(Rotation.eu2om,Rotation.om2eu),
#(Rotation.eu2ax,Rotation.ax2eu),
#(Rotation.eu2ro,Rotation.ro2eu),
#(Rotation.eu2ho,Rotation.ho2eu),
#(Rotation.eu2cu,Rotation.cu2eu)])
@pytest.mark.parametrize('forward,backward',[(Rotation.eu2qu,Rotation.qu2eu),
(Rotation.eu2om,Rotation.om2eu),
(Rotation.eu2ax,Rotation.ax2eu),
(Rotation.eu2ro,Rotation.ro2eu),
(Rotation.eu2ho,Rotation.ho2eu),
(Rotation.eu2cu,Rotation.cu2eu)])
def test_Eulers_internal(self,default,forward,backward):
for rot in default:
m = rot.as_Eulers()
@ -140,6 +140,22 @@ class TestRotation:
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()
@pytest.mark.parametrize('forward,backward',[(Rotation.ax2qu,Rotation.qu2ax),
(Rotation.ax2om,Rotation.om2ax),
(Rotation.ax2eu,Rotation.eu2ax),
(Rotation.ax2ro,Rotation.ro2ax),
(Rotation.ax2ho,Rotation.ho2ax),
(Rotation.ax2cu,Rotation.cu2ax)])
def test_axis_angle_internal(self,default,forward,backward):
for rot in default:
m = rot.as_axis_angle()
o = backward(forward(m))
ok = np.allclose(m,o,atol=atol)
if np.isclose(m[3],np.pi,atol=atol):
ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol)
print(m,o,rot.as_quaternion())
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi+1.e-7
@pytest.mark.parametrize('degrees',[True,False])
def test_Eulers(self,default,degrees):
@ -177,7 +193,7 @@ class TestRotation:
if np.isclose(m[3],np.pi,atol=atol):
ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol)
print(m,o,rot.as_quaternion())
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi++1.e-9
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi+1.e-7
@pytest.mark.parametrize('P',[1,-1])
@pytest.mark.parametrize('normalise',[True,False])