more tests
Hotfix needed for axis angle to matrix (not used in DAMASK, needs further investigation)
This commit is contained in:
parent
de79a5af43
commit
a6b0aaffba
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
|
|
Loading…
Reference in New Issue