root / ase / lattice / spacegroup / cell.py @ 14
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() |