File: quaternions.py

package info (click to toggle)
python-ase 3.12.0-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 14,192 kB
  • ctags: 8,112
  • sloc: python: 93,375; sh: 99; makefile: 94
file content (60 lines) | stat: -rw-r--r-- 1,410 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import numpy as np
from ase.quaternions import Quaternion


def rand_rotm():
    """Axis & angle rotations."""
    u = np.random.random(3)
    u /= np.linalg.norm(u)
    theta = np.random.random() * np.pi * 2
    
    # Cross product matrix for u
    ucpm = np.array([[0, -u[2], u[1]], [u[2], 0, -u[0]], [-u[1], u[0], 0]])
    
    # Rotation matrix
    rotm = (np.cos(theta) * np.identity(3) + np.sin(theta) * ucpm +
            (1 - np.cos(theta)) * np.kron(u[:, None], u[None, :]))
    
    return rotm
    
# First: test that rotations DO work
for i in range(10):
    # 10 random tests
        
    rotm = rand_rotm()

    q = Quaternion.from_matrix(rotm)

    # Now test this with a vector
    v = np.random.random(3)

    vrotM = np.dot(rotm, v)
    vrotQ = q.rotate(v)

    assert np.allclose(vrotM, vrotQ)

# Second: test the special case of a PI rotation

rotm = np.identity(3)
rotm[:2, :2] *= -1               # Rotate PI around z axis

q = Quaternion.from_matrix(rotm)

assert not np.isnan(q.q).any()

# Third: test compound rotations and operator overload
for i in range(10):

    rotm1 = rand_rotm()
    rotm2 = rand_rotm()
    
    q1 = Quaternion.from_matrix(rotm1)
    q2 = Quaternion.from_matrix(rotm2)
    
    # Now test this with a vector
    v = np.random.random(3)
    
    vrotM = np.dot(rotm2, np.dot(rotm1, v))
    vrotQ = (q2 * q1).rotate(v)
    
    assert np.allclose(vrotM, vrotQ)