<jupyter_start><jupyter_text>This notebook is part of the *orix* documentation https://orix.readthedocs.io. Links to the documentation won’t work from the notebook.  Crystal reference frameThis notebook describes the alignment of crystal reference frames and symmetryoperations in `orix`.<jupyter_code>%matplotlib inline

from diffpy.structure import Atom, Lattice, Structure
import matplotlib.pyplot as plt
import numpy as np

from orix.crystal_map import Phase
from orix.quaternion import Rotation
from orix.vector import Miller


plt.rcParams.update(
    {
        "figure.figsize": (10, 5),
        "font.size": 20,
        "axes.grid": True,
        "lines.markersize": 10,
        "lines.linewidth": 3,
    }
)<jupyter_output><empty_output><jupyter_text>Alignment and the structure matrix The direct Bravais lattice is characterized by basis vectors ($\mathbf{a},\mathbf{b}, \mathbf{c}$) with unit cell edge lengths ($a$, $b$, $c$) and angles($\alpha$, $\beta$, $\gamma$). The reciprocal lattice has basis vectors given by$$\mathbf{a^*} = \frac{\mathbf{b} \times \mathbf{c}}{\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})},\:\:\mathbf{b^*} = \frac{\mathbf{c} \times \mathbf{a}}{\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})},\:\:\mathbf{c^*} = \frac{\mathbf{a} \times \mathbf{b}}{\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})},$$with reciprocal lattice parameters ($a^*$, $b^*$, $c^*$) and angles ($\alpha^*$,$\beta^*$, $\gamma^*$).Using these two crystallographic lattices, we can define a standard Cartesian(orthonormal) reference frame by the unit vectors ($\mathbf{e_1}, \mathbf{e_2},\mathbf{e_3}$). In principle, the direct lattice reference frame can be orientedarbitrarily in the Cartesian reference frame. In `orix` we have chosen$$\mathbf{e_1} ||\: \frac{\mathbf{a}}{a},\:\:\mathbf{e_2} ||\: \mathbf{e_3} \times \mathbf{e_1},\:\:\mathbf{e_3} ||\: \frac{\mathbf{c^*}}{c^*}.$$This alignment is used for example inRowenhorst et al. (2015) andDe Graef (2003), the latterwhich was the basis for the *EMsoft* Fortran suite of programs. Another commonoption is $\mathbf{e_1} || \mathbf{a^*}/a^*$, $\mathbf{e_2} ||\mathbf{e_3} \times \mathbf{e_1}$, $\mathbf{e_3} || \mathbf{c}/c$, which is usedfor example inBritton et al. (2016) and the`diffpy.structure` Python package, which we'll come back to.In calculations, it is useful to describe the transformation of the Cartesianunit *row* vectors to the coordinates of the direct lattice vectors by thestructure *row* matrix $\mathbf{A}$ (also called the crystal *base*). Given thechosen alignment of basis vectors with the Cartesian reference frame,$\mathbf{A}$ is defined as\begin{equation}\mathbf{A} = \begin{pmatrix}a & 0 & 0\\b\cos\gamma & b\sin\gamma & 0\\c\cos\beta & -c\frac{(\cos\beta\cos\gamma - \cos\alpha)}{\sin\gamma} & \frac{\mathrm{V}}{ab\sin\gamma}\end{pmatrix},\end{equation}where $V$ is the volume of the unit cell.In `orix`, we use the[Lattice](https://www.diffpy.org/diffpy.structure/mod_lattice.htmldiffpy.structure.lattice.Lattice)class in `diffpy.structure` to keep track of these properties internally. Let'screate a trigonal crystal with lattice parameters $(a, b, c)$ = (1.7, 1.7, 1.4)nm and ($\alpha, \beta, \gamma$) = $(90^{\circ}, 90^{\circ}, 120^{\circ})$<jupyter_code>lattice = Lattice(1.7, 1.7, 1.4, 90, 90, 120)
lattice<jupyter_output><empty_output><jupyter_text>`diffpy.structure` stores the structure matrix in the `Lattice.base` property<jupyter_code>lattice.base<jupyter_output><empty_output><jupyter_text>and we see that `diffpy.structure` does not use the `orix` alignment mentionedabove, since $\mathbf{e1} \nparallel \mathbf{a} / a$. Instead, we see that$\mathbf{e3} \parallel \mathbf{c} / c$, which is in line with the alternativealignment mentioned above.Thus, the alignment is updated internally whenever a[Phase](reference.rstorix.crystal_map.Phase) is created, a class which bringstogether this crystal lattice and a point group[Symmetry](reference.rstorix.quaternion.Symmetry)<jupyter_code>phase = Phase(point_group="321", structure=Structure(lattice=lattice))
phase.structure.lattice.base<jupyter_output><empty_output><jupyter_text>WarningUsing another alignment than the one described above has undefined behaviour inorix. Therefore, it is important that the structure matrix of a `Phase` instanceis not changed. Note    The lattice is included in a[Structure](https://www.diffpy.org/diffpy.structure/package.htmldiffpy.structure.structure.Structure)because the latter class brings together a lattice and[atoms](https://www.diffpy.org/diffpy.structure/mod_atom.htmldiffpy.structure.atom.Atom),which is useful when simulating diffraction. We can visualize the alignment of the direct and reciprocal lattice basisvectors with the Cartesian reference frame using the stereographic projection<jupyter_code>abc = Miller(uvw=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], phase=phase)
abcr = Miller(hkl=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], phase=phase)
fig = abc.scatter(
    c=["r", "g", "b"],
    marker="o",
    return_figure=True,
    axes_labels=["e1", "e2"],
    hemisphere="both",
)
abcr.scatter(c=["r", "g", "b"], marker="x", s=300, figure=fig)<jupyter_output><empty_output><jupyter_text>Alignment of symmetry operations To see where the crystallographic axes about which the point group symmetryoperations rotate, we can add symmetry operations to the figure, like is donein the [Visualizing point groups](point_groups.ipynb) user guide for all pointgroups supported in `orix`<jupyter_code>ori = Rotation.from_axes_angles((0, 1, 0), np.deg2rad(65))
phase.point_group.plot(figure=fig, orientation=ori, fc="none", ec="C0", s=150)
fig<jupyter_output><empty_output><jupyter_text>Converting crystal vectors The reference frame of the stereographic projection above is the Cartesianreference frame ($\mathbf{e_1}, \mathbf{e_2}, \mathbf{e_3}$). The Cartesiancoordinates $(\mathbf{x}, \mathbf{y}, \mathbf{z})$ of$(\mathbf{a}, \mathbf{b}, \mathbf{c})$ and$(\mathbf{a^*}, \mathbf{b^*}, \mathbf{c^*})$ were found using $\mathbf{A}$ inthe following conversions\begin{align}(x, y, z) &= [uvw] \cdot \mathbf{A},\\(x, y, z) &= (hkl) \cdot (\mathbf{A}^{-1})^T.\end{align}Let's compute the internal conversions directly and check for equality<jupyter_code>np.allclose(abc.data, np.dot(abc.uvw, phase.structure.lattice.base))  # (x, y, z)
np.allclose(
    abcr.data,  # (x, y, z)
    np.dot(abcr.hkl, np.linalg.inv(phase.structure.lattice.base).T),
)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15562093527407866, 'fraction_numerical': 0.01610405698358625, 'mean_word_length': 5.504531722054381, 'pattern_counts': {'":': 5, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 4, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '357914', 'license': 'MIT', 'n_tokens_mistral': 2165, 'n_tokens_neox': 2047, 'n_words': 617, 'path': 'doc/crystal_reference_frame.ipynb', 'repo_name': 'bm424/texpy', 'size': '6458'}