root / ase / lattice / spacegroup / cell.py @ 14
Historique | Voir | Annoter | Télécharger (3,36 ko)
| 1 |
# Copyright (C) 2010, Jesper Friis
|
|---|---|
| 2 |
# (see accompanying license files for details).
|
| 3 |
|
| 4 |
import numpy as np |
| 5 |
from numpy import pi, sin, cos, tan, arcsin, arccos, arctan, sqrt |
| 6 |
from numpy import dot |
| 7 |
from numpy.linalg import norm |
| 8 |
|
| 9 |
import ase |
| 10 |
|
| 11 |
|
| 12 |
__ALL__ = ['cell_to_cellpar', 'cellpar_to_cell', 'metric_from_cell'] |
| 13 |
|
| 14 |
|
| 15 |
def unit_vector(x): |
| 16 |
"""Return a unit vector in the same direction as x."""
|
| 17 |
y = np.array(x, dtype='float')
|
| 18 |
return y/norm(y)
|
| 19 |
|
| 20 |
|
| 21 |
def angle(x, y): |
| 22 |
"""Return the angle between vectors a and b in degrees."""
|
| 23 |
return arccos(dot(x, y)/(norm(x)*norm(y)))*180./pi |
| 24 |
|
| 25 |
|
| 26 |
def cell_to_cellpar(cell): |
| 27 |
"""Returns the cell parameters [a, b, c, alpha, beta, gamma] as a
|
| 28 |
numpy array."""
|
| 29 |
va, vb, vc = cell |
| 30 |
a = np.linalg.norm(va) |
| 31 |
b = np.linalg.norm(vb) |
| 32 |
c = np.linalg.norm(vc) |
| 33 |
alpha = 180.0/pi*arccos(dot(vb, vc)/(b*c))
|
| 34 |
beta = 180.0/pi*arccos(dot(vc, va)/(c*a))
|
| 35 |
gamma = 180.0/pi*arccos(dot(va, vb)/(a*b))
|
| 36 |
return np.array([a, b, c, alpha, beta, gamma])
|
| 37 |
|
| 38 |
|
| 39 |
def cellpar_to_cell(cellpar, ab_normal=(0,0,1), a_direction=None): |
| 40 |
"""Return a 3x3 cell matrix from `cellpar` = [a, b, c, alpha,
|
| 41 |
beta, gamma]. The returned cell is orientated such that a and b
|
| 42 |
are normal to `ab_normal` and a is parallel to the projection of
|
| 43 |
`a_direction` in the a-b plane.
|
| 44 |
|
| 45 |
Default `a_direction` is (1,0,0), unless this is parallel to
|
| 46 |
`ab_normal`, in which case default `a_direction` is (0,0,1).
|
| 47 |
|
| 48 |
The returned cell has the vectors va, vb and vc along the rows. The
|
| 49 |
cell will be oriented such that va and vb are normal to `ab_normal`
|
| 50 |
and va will be along the projection of `a_direction` onto the a-b
|
| 51 |
plane.
|
| 52 |
|
| 53 |
Example:
|
| 54 |
|
| 55 |
>>> cell = cellpar_to_cell([1, 2, 4, 10, 20, 30], (0,1,1), (1,2,3))
|
| 56 |
>>> np.round(cell, 3)
|
| 57 |
array([[ 0.816, -0.408, 0.408],
|
| 58 |
[ 1.992, -0.13 , 0.13 ],
|
| 59 |
[ 3.859, -0.745, 0.745]])
|
| 60 |
|
| 61 |
"""
|
| 62 |
if a_direction is None: |
| 63 |
if np.linalg.norm(np.cross(ab_normal, (1,0,0))) < 1e-5: |
| 64 |
a_direction = (0,0,1) |
| 65 |
else:
|
| 66 |
a_direction = (1,0,0) |
| 67 |
|
| 68 |
# Define rotated X,Y,Z-system, with Z along ab_normal and X along
|
| 69 |
# the projection of a_direction onto the normal plane of Z.
|
| 70 |
ad = np.array(a_direction) |
| 71 |
Z = unit_vector(ab_normal) |
| 72 |
X = unit_vector(ad - dot(ad, Z)*Z) |
| 73 |
Y = np.cross(Z, X) |
| 74 |
|
| 75 |
# Express va, vb and vc in the X,Y,Z-system
|
| 76 |
alpha, beta, gamma = 90., 90., 90. |
| 77 |
if isinstance(cellpar, (int, long, float)): |
| 78 |
a = b = c = cellpar |
| 79 |
elif len(cellpar) == 1: |
| 80 |
a = b = c = cellpar[0]
|
| 81 |
elif len(cellpar) == 3: |
| 82 |
a, b, c = cellpar |
| 83 |
alpha, beta, gamma = 90., 90., 90. |
| 84 |
else:
|
| 85 |
a, b, c, alpha, beta, gamma = cellpar |
| 86 |
alpha *= pi/180.0
|
| 87 |
beta *= pi/180.0
|
| 88 |
gamma *= pi/180.0
|
| 89 |
va = a * np.array([1, 0, 0]) |
| 90 |
vb = b * np.array([cos(gamma), sin(gamma), 0])
|
| 91 |
cx = cos(beta) |
| 92 |
cy = (cos(alpha) - cos(beta)*cos(gamma))/sin(gamma) |
| 93 |
cz = sqrt(1. - cx*cx - cy*cy)
|
| 94 |
vc = c * np.array([cx, cy, cz]) |
| 95 |
|
| 96 |
# Convert to the Cartesian x,y,z-system
|
| 97 |
abc = np.vstack((va, vb, vc)) |
| 98 |
T = np.vstack((X, Y, Z)) |
| 99 |
cell = dot(abc, T) |
| 100 |
return cell
|
| 101 |
|
| 102 |
|
| 103 |
def metric_from_cell(cell): |
| 104 |
"""Calculates the metric matrix from cell, which is given in the
|
| 105 |
Cartesian system."""
|
| 106 |
cell = np.asarray(cell, dtype=float)
|
| 107 |
return np.dot(cell, cell.T)
|
| 108 |
|
| 109 |
|
| 110 |
|
| 111 |
|
| 112 |
if __name__ == '__main__': |
| 113 |
import doctest |
| 114 |
print 'doctest: ', doctest.testmod() |
| 115 |
|