141 lines
4.3 KiB
Python
141 lines
4.3 KiB
Python
import numpy as np
|
|
from scipy.constants import golden as phi
|
|
|
|
|
|
def icosahedral(cls):
|
|
g1 = tetrahedral(cls).as_quat()
|
|
a = 0.5
|
|
b = 0.5 / phi
|
|
c = phi / 2
|
|
g2 = np.array([[+a, +b, +c, 0],
|
|
[+a, +b, -c, 0],
|
|
[+a, +c, 0, +b],
|
|
[+a, +c, 0, -b],
|
|
[+a, -b, +c, 0],
|
|
[+a, -b, -c, 0],
|
|
[+a, -c, 0, +b],
|
|
[+a, -c, 0, -b],
|
|
[+a, 0, +b, +c],
|
|
[+a, 0, +b, -c],
|
|
[+a, 0, -b, +c],
|
|
[+a, 0, -b, -c],
|
|
[+b, +a, 0, +c],
|
|
[+b, +a, 0, -c],
|
|
[+b, +c, +a, 0],
|
|
[+b, +c, -a, 0],
|
|
[+b, -a, 0, +c],
|
|
[+b, -a, 0, -c],
|
|
[+b, -c, +a, 0],
|
|
[+b, -c, -a, 0],
|
|
[+b, 0, +c, +a],
|
|
[+b, 0, +c, -a],
|
|
[+b, 0, -c, +a],
|
|
[+b, 0, -c, -a],
|
|
[+c, +a, +b, 0],
|
|
[+c, +a, -b, 0],
|
|
[+c, +b, 0, +a],
|
|
[+c, +b, 0, -a],
|
|
[+c, -a, +b, 0],
|
|
[+c, -a, -b, 0],
|
|
[+c, -b, 0, +a],
|
|
[+c, -b, 0, -a],
|
|
[+c, 0, +a, +b],
|
|
[+c, 0, +a, -b],
|
|
[+c, 0, -a, +b],
|
|
[+c, 0, -a, -b],
|
|
[0, +a, +c, +b],
|
|
[0, +a, +c, -b],
|
|
[0, +a, -c, +b],
|
|
[0, +a, -c, -b],
|
|
[0, +b, +a, +c],
|
|
[0, +b, +a, -c],
|
|
[0, +b, -a, +c],
|
|
[0, +b, -a, -c],
|
|
[0, +c, +b, +a],
|
|
[0, +c, +b, -a],
|
|
[0, +c, -b, +a],
|
|
[0, +c, -b, -a]])
|
|
return cls.from_quat(np.concatenate((g1, g2)))
|
|
|
|
|
|
def octahedral(cls):
|
|
g1 = tetrahedral(cls).as_quat()
|
|
c = np.sqrt(2) / 2
|
|
g2 = np.array([[+c, 0, 0, +c],
|
|
[0, +c, 0, +c],
|
|
[0, 0, +c, +c],
|
|
[0, 0, -c, +c],
|
|
[0, -c, 0, +c],
|
|
[-c, 0, 0, +c],
|
|
[0, +c, +c, 0],
|
|
[0, -c, +c, 0],
|
|
[+c, 0, +c, 0],
|
|
[-c, 0, +c, 0],
|
|
[+c, +c, 0, 0],
|
|
[-c, +c, 0, 0]])
|
|
return cls.from_quat(np.concatenate((g1, g2)))
|
|
|
|
|
|
def tetrahedral(cls):
|
|
g1 = np.eye(4)
|
|
c = 0.5
|
|
g2 = np.array([[c, -c, -c, +c],
|
|
[c, -c, +c, +c],
|
|
[c, +c, -c, +c],
|
|
[c, +c, +c, +c],
|
|
[c, -c, -c, -c],
|
|
[c, -c, +c, -c],
|
|
[c, +c, -c, -c],
|
|
[c, +c, +c, -c]])
|
|
return cls.from_quat(np.concatenate((g1, g2)))
|
|
|
|
|
|
def dicyclic(cls, n, axis=2):
|
|
g1 = cyclic(cls, n, axis).as_rotvec()
|
|
|
|
thetas = np.linspace(0, np.pi, n, endpoint=False)
|
|
rv = np.pi * np.vstack([np.zeros(n), np.cos(thetas), np.sin(thetas)]).T
|
|
g2 = np.roll(rv, axis, axis=1)
|
|
return cls.from_rotvec(np.concatenate((g1, g2)))
|
|
|
|
|
|
def cyclic(cls, n, axis=2):
|
|
thetas = np.linspace(0, 2 * np.pi, n, endpoint=False)
|
|
rv = np.vstack([thetas, np.zeros(n), np.zeros(n)]).T
|
|
return cls.from_rotvec(np.roll(rv, axis, axis=1))
|
|
|
|
|
|
def create_group(cls, group, axis='Z'):
|
|
if not isinstance(group, str):
|
|
raise ValueError("`group` argument must be a string")
|
|
|
|
permitted_axes = ['x', 'y', 'z', 'X', 'Y', 'Z']
|
|
if axis not in permitted_axes:
|
|
raise ValueError("`axis` must be one of " + ", ".join(permitted_axes))
|
|
|
|
if group in ['I', 'O', 'T']:
|
|
symbol = group
|
|
order = 1
|
|
elif group[:1] in ['C', 'D'] and group[1:].isdigit():
|
|
symbol = group[:1]
|
|
order = int(group[1:])
|
|
else:
|
|
raise ValueError("`group` must be one of 'I', 'O', 'T', 'Dn', 'Cn'")
|
|
|
|
if order < 1:
|
|
raise ValueError("Group order must be positive")
|
|
|
|
axis = 'xyz'.index(axis.lower())
|
|
if symbol == 'I':
|
|
return icosahedral(cls)
|
|
elif symbol == 'O':
|
|
return octahedral(cls)
|
|
elif symbol == 'T':
|
|
return tetrahedral(cls)
|
|
elif symbol == 'D':
|
|
return dicyclic(cls, order, axis=axis)
|
|
elif symbol == 'C':
|
|
return cyclic(cls, order, axis=axis)
|
|
else:
|
|
assert False
|