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