Basic notation#

Vectors#

Vectors are represented as a columns of numbers. In Wulfric vectors are stored and manipulated as (3,) NumPy arrays:

\[\begin{split}\boldsymbol{v} = (v_x,v_y,v_z)^T = \begin{pmatrix} v_x \\ v_y \\ v_z \end{pmatrix}\end{split}\]
vector = np.array([vx, vy, vz])

Note

One-dimensional NumPy arrays do not distinguish between row and column vectors.

Cell#

Cell of the lattice is defined by the three lattice vectors \(\boldsymbol{a}_i = (a_i^x, a_i^y, a_i^z)^T\). In Wulfric those vectors are stored as a matrix with vectors as rows (hence the transposition symbol):

\[\begin{split}(\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)^T = \begin{pmatrix} a_1^x & a_1^y & a_1^z \\ a_2^x & a_2^y & a_2^z \\ a_3^x & a_3^y & a_3^z \end{pmatrix}\end{split}\]
cell = [
    [a1_x, a1_y, a1_z],
    [a2_x, a2_y, a2_z],
    [a3_x, a3_y, a3_z],
]

Note

That definition of the cell is the same as in the spglib's python interface and is a transpose of the definition of the C spglib.

Atom's positions#

Atoms positions are stored as vectors of the relative coordinates with respect to the cell vectors.

\[\begin{split}\boldsymbol{r} = (r_1,r_2,r_3)^T = \begin{pmatrix} r_1 \\ r_2 \\ r_3 \end{pmatrix}\end{split}\]
position = np.array([r1, r2, r3])

Cartesian (absolute) coordinates of the atoms can be calculated by the following formula:

\[\begin{split}\boldsymbol{x}^T &= \boldsymbol{r}^T(\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)^T\\ \boldsymbol{x} &= (\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3) \boldsymbol{r}\end{split}\]
x = r @ cell
# or
x = cell.T @ r

Note

Remember, that one-dimensional NumPy arrays do not distinguish between row and column vectors and cell store transposed cell matrix in our notation: cell \(\rightarrow (\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)^T\). In the documentation analytical formulas are written for the \((\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)\) matrix, while code snippets are written for \((\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)^T\) matrix.

Reciprocal cell#

Reciprocal cell is defined by the three reciprocal lattice vectors \(\boldsymbol{b}_i = (b_i^x, b_i^y, b_i^z)^T\). In Wulfric those vectors are stored as a matrix with vectors as rows (hence the transposition symbol):

\[\begin{split}(\boldsymbol{b}_1, \boldsymbol{b}_2, \boldsymbol{b}_3)^T = \begin{pmatrix} b_1^x & b_1^y & b_1^z \\ b_2^x & b_2^y & b_2^z \\ b_3^x & b_3^y & b_3^z \end{pmatrix}\end{split}\]
reciprocal_cell = [
    [b1_x, b1_y, b1_z],
    [b2_x, b2_y, b2_z],
    [b3_x, b3_y, b3_z],
]

Reciprocal cell is connected with the cell of the lattice as follows:

\[(\boldsymbol{b}_1, \boldsymbol{b}_2, \boldsymbol{b}_3)^T = 2\pi(\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)^{-1}\]
reciprocal_cell = 2 * np.pi * np.linalg.inv(cell.T)

K-points#

K-points are stored as vectors of the fractional coordinates with respect to the reciprocal cell vectors.

\[\begin{split}\boldsymbol{g} = (g_1,g_2,g_3)^T = \begin{pmatrix} g_1 \\ g_2 \\ g_3 \end{pmatrix}\end{split}\]
kpoint = np.array([g1, g2, g3])

Cartesian (absolute) coordinates of the k-points can be calculated by the following formula:

\[\begin{split}\boldsymbol{k}^T &= \boldsymbol{g}^T(\boldsymbol{b}_1, \boldsymbol{b}_2, \boldsymbol{b}_3)^T\\ \boldsymbol{k} &= (\boldsymbol{b}_1, \boldsymbol{b}_2, \boldsymbol{b}_3) \boldsymbol{g}\end{split}\]
k = g @ reciprocal_cell
# or
k = reciprocal_cell.T @ g

Transformation of the cell#

The choice of the cell of the lattice is not unique. Transformation between two different cells of the same lattice might be expressed by the transformation matrix \(\boldsymbol{P}\):

\[(\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3) = (\boldsymbol{\tilde{a}}_1, \boldsymbol{\tilde{a}}_2, \boldsymbol{\tilde{a}}_3) \boldsymbol{P}\]
tcell = np.linalg.inv(P.T) @ cell

Crystal is not affected by the change of the cell, i.e. the atom's Cartesian coordinates are not changed (\(\boldsymbol{x} = \boldsymbol{\tilde{x}}\)). Therefore, the atom's relative positions are transformed as

\[\boldsymbol{\tilde{r}} = \boldsymbol{P}\boldsymbol{r}\]
tr = P @ r

Hint

\[\boldsymbol{x} = (\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3)\boldsymbol{r} = (\boldsymbol{\tilde{a}}_1, \boldsymbol{\tilde{a}}_2, \boldsymbol{\tilde{a}}_3)\boldsymbol{P}\boldsymbol{r} = \boldsymbol{\tilde{x}} = (\boldsymbol{\tilde{a}}_1, \boldsymbol{\tilde{a}}_2, \boldsymbol{\tilde{a}}_3)\boldsymbol{\tilde{r}}\]

Reciprocal cell is changed by the transformation as follows:

\[(\boldsymbol{b}_1, \boldsymbol{b}_2, \boldsymbol{b}_3) = (\boldsymbol{\tilde{b}}_1, \boldsymbol{\tilde{b}}_2, \boldsymbol{\tilde{b}}_3) (\boldsymbol{P}^{-1})^T\]
reciprocal_tcell = np.linalg.inv(P) @ reciprocal_cell

Relative positions of the k-points are transformed as follows:

\[\boldsymbol{\tilde{g}} = (\boldsymbol{P}^{-1})^T\boldsymbol{g}\]
tg = np.linalg.inv(P).T @ g

Standardization of the cell#

When standardization of the cell is required, it can be expressed by the transformation matrix \(\boldsymbol{S}\) with \((\boldsymbol{a}_1^s, \boldsymbol{a}_2^s, \boldsymbol{a}_3^s)\) being the standardized primitive cell:

\[(\boldsymbol{a}_1, \boldsymbol{a}_2, \boldsymbol{a}_3) = (\boldsymbol{a}_1^s, \boldsymbol{a}_2^s, \boldsymbol{a}_3^s) \boldsymbol{S}\]

Note

Matrix \(\boldsymbol{S}\) is orthonormal for all Bravais lattices, except for the Base-centred monoclinic (MCLC). All matrices satisfy \(\det(\boldsymbol{S}) = 1\).

Details on how the standardization matrix is constructed are provided in the individual pages for each of the 14 Bravais lattices.

Conventional vs primitive cell (Setyawan and Curtarolo)#

In the reference paper [1] conventional (>=1 lattice point per cell) and primitive (1 lattice point per cell) standardized cells are defined. Transformation from primitive to conventional cell is expressed by the transformation matrix \(\boldsymbol{C}\):

\[(\boldsymbol{a}_1^s, \boldsymbol{a}_2^s, \boldsymbol{a}_3^s) = (\boldsymbol{a}_1^{cs}, \boldsymbol{a}_2^{cs}, \boldsymbol{a}_3^{cs}) \boldsymbol{C}\]

Transformation matrices \(\boldsymbol{C}\) and its inverse are provided in the individual pages for each of the 14 Bravais lattices.

Important

Given cell is always interpreted as primitive.

References#