Live notebook

You can run this notebook in a live session Binder or view it on Github.

Kinematical EBSD simulations#

In this tutorial, we will perform kinematical Kikuchi pattern simulations of nickel, a variant of the \(\sigma\)-phase (Fe, Cr) in steels, and silicon carbide 6H.

We can obtain kinematical master patterns using KikuchiPatternSimulator.calculate_master_pattern(), provided that the simulator is created from a ReciprocalLatticeVector instance that satisfy these conditions:

  1. The unit cell, i.e. the structure used to create the phase used in ReciprocalLatticeVector, must have all asymmetric atom positions filled, which can either be done by creating a Phase instance from a valid CIF file with Phase.from_cif() or calling ReciprocalLatticeVector.sanitise_phase()

  2. The atoms in the structure have their elements described by the symbol (Ni), not by the atomic number (28)

  3. The lattice parameters are in given in Ångström.

  4. Kinematical structure factors \(F_{hkl}\) have been calculated with ReciprocalLatticeVector.calculate_structure_factor()

  5. Bragg angles \(\theta_B\) have been calculated with ReciprocalLatticeVector.calculate_theta()

Let’s import the necessary libraries

[1]:
# Exchange inline for notebook or qt5 (from pyqt) for interactive plotting
%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np
import pyvista

from diffpy.structure import Atom, Lattice, Structure
from diffsims.crystallography import ReciprocalLatticeVector
import hyperspy.api as hs
import kikuchipy as kp
from orix.crystal_map import Phase


# Plotting parameters
plt.rcParams.update(
    {"figure.figsize": (10, 10), "font.size": 20, "lines.markersize": 10}
)
# See https://docs.pyvista.org/user-guide/jupyter/index.html
pyvista.set_jupyter_backend("panel")
2023-07-24 16:15:44,133 - numexpr.utils - INFO - NumExpr defaulting to 2 threads.
/tmp/ipykernel_3685/2172114549.py:20: PyVistaDeprecationWarning: `panel` backend is deprecated and is planned for future removal.
  pyvista.set_jupyter_backend("panel")

Nickel#

We’ll compare our kinematical simulations to dynamical simulations performed with EMsoft (see [Callahan and De Graef, 2013]), since we have a Ni master pattern available in the kikuchipy.data module

[2]:
mp_ni_dyn = kp.data.nickel_ebsd_master_pattern_small(
    projection="stereographic"
)

Inspect phase

[3]:
phase_ni = mp_ni_dyn.phase.deepcopy()

print(phase_ni)
print(phase_ni.structure.lattice)
<name: ni. space group: Fm-3m. point group: m-3m. proper point group: 432. color: tab:blue>
Lattice(a=0.35236, b=0.35236, c=0.35236, alpha=90, beta=90, gamma=90)

Change lattice parameters from nm to Ångström

[4]:
lat_ni = phase_ni.structure.lattice  # Shallow copy
lat_ni.setLatPar(lat_ni.a * 10, lat_ni.b * 10, lat_ni.c * 10)

print(phase_ni.structure.lattice)
Lattice(a=3.5236, b=3.5236, c=3.5236, alpha=90, beta=90, gamma=90)

We’ll build up the reflector list by:

  1. Finding all reflectors with a minimal interplanar spacing \(d\)

  2. Keeping those that have a structure factor above 0.5% of the reflector with the highest structure factor

[5]:
rlv_ni = ReciprocalLatticeVector.from_min_dspacing(phase_ni, 0.5)

# Exclude non-allowed reflectors (not available for hexagonal or trigonal
# phases!)
rlv_ni = rlv_ni[rlv_ni.allowed]
rlv_ni = rlv_ni.unique(use_symmetry=True).symmetrise()

Sanitise phase by completing the unit cell

[6]:
rlv_ni.phase.structure
[6]:
[28   0.000000 0.000000 0.000000 1.0000]
[7]:
rlv_ni.sanitise_phase()
rlv_ni.phase.structure
[7]:
[Ni   0.000000 0.000000 0.000000 1.0000,
 Ni   0.000000 0.500000 0.500000 1.0000,
 Ni   0.500000 0.000000 0.500000 1.0000,
 Ni   0.500000 0.500000 0.000000 1.0000]

We can now calculate the structure factors. Two parametrizations are available, from [Kirkland, 1998] ("xtables", the default) or [Lobato and Van Dyck, 2014] ("lobato")

[8]:
rlv_ni.calculate_structure_factor()
[9]:
structure_factor_ni = abs(rlv_ni.structure_factor)
rlv_ni = rlv_ni[structure_factor_ni > 0.05 * structure_factor_ni.max()]

rlv_ni.print_table()
 h k l      d     |F|_hkl   |F|^2   |F|^2_rel   Mult
 1 1 1    2.034    11.8     140.0     100.0      8
 2 0 0    1.762    10.4     108.2      77.3      6
 2 2 0    1.246     7.4     55.0       39.3      12
 3 1 1    1.062     6.2     38.6       27.6      24
 2 2 2    1.017     5.9     34.7       24.8      8
 4 0 0    0.881     4.9     23.9       17.1      6
 3 3 1    0.808     4.3     18.8       13.4      24
 4 2 0    0.788     4.2     17.4       12.5      24
 4 2 2    0.719     3.6     13.3       9.5       24
 5 1 1    0.678     3.3     11.1       8.0       24
 3 3 3    0.678     3.3     11.1       8.0       8
 4 4 0    0.623     2.9      8.6       6.1       12
 5 3 1    0.596     2.7      7.4       5.3       48
 6 0 0    0.587     2.7      7.1       5.1       6
 4 4 2    0.587     2.7      7.1       5.1       24
 6 2 0    0.557     2.4      6.0       4.3       24
 5 3 3    0.537     2.3      5.3       3.8       24
 6 2 2    0.531     2.3      5.1       3.7       24
 4 4 4    0.509     2.1      4.4       3.2       8
[10]:
rlv_ni.calculate_theta(20e3)

We can now create our simulator and plot the simulation

[11]:
simulator_ni = kp.simulations.KikuchiPatternSimulator(rlv_ni)
simulator_ni.reflectors.size
[11]:
338

Plotting the band centers with intensities scaled by the structure factor

[12]:
simulator_ni.plot()
../_images/tutorials_kinematical_ebsd_simulations_21_0.png

Or no scaling (scaling="square" for the structure factor squared)

[13]:
simulator_ni.plot(scaling=None)
../_images/tutorials_kinematical_ebsd_simulations_23_0.png

We can also plot the Kikuchi bands, showing both hemispheres, also adding the crystal axes alignment

[14]:
fig = simulator_ni.plot(hemisphere="both", mode="bands", return_figure=True)

ax = fig.axes[0]
ax.scatter(simulator_ni.phase.a_axis, c="r")
ax.scatter(simulator_ni.phase.b_axis, c="g")
ax.scatter(simulator_ni.phase.c_axis, c="b")
../_images/tutorials_kinematical_ebsd_simulations_25_0.png

The simulation can be plotted in spherical projection as well using Matplotlib, or PyVista provided that it is installed

[15]:
simulator_ni.plot("spherical", mode="bands")
../_images/tutorials_kinematical_ebsd_simulations_27_0.png
[16]:
# Interactive!
simulator_ni.plot("spherical", mode="bands", backend="pyvista")