Chapter 2: Diffraction


2.2. The Electron#

Download

OpenInColab

part of

MSE672: Introduction to Transmission Electron Microscopy

Spring 2024

Gerd Duscher Khalid Hattar
Microscopy Facilities Tennessee Ion Beam Materials Laboratory
Materials Science & Engineering Nuclear Engineering
Institute of Advanced Materials & Manufacturing
The University of Tennessee, Knoxville

Background and methods to analysis and quantification of data acquired with transmission electron microscopes.

First we load the code to make figures from pyTEMlib

2.2.1. Import packages for figures and#

2.2.1.1. Check Installed Packages#

import sys
import importlib.metadata
def test_package(package_name):
    """Test if package exists and returns version or -1"""
    try:
        version = importlib.metadata.version(package_name)
    except importlib.metadata.PackageNotFoundError:
        version = '-1'
    return version

if test_package('pyTEMlib') < '0.2024.1.0':
    print('installing pyTEMlib')
    !{sys.executable} -m pip install  --upgrade pyTEMlib -q
if 'google.colab' in sys.modules:
    !{sys.executable} -m pip install numpy==1.24.4
print('done')
done

Please restart the session (in Runtime menu) in Google Colab.

2.2.1.2. Load the plotting and figure packages#

%matplotlib widget
import matplotlib.pylab as plt
import numpy as np
import sys
if 'google.colab' in sys.modules:
    from google.colab import output
    output.enable_custom_widget_manager()

import scipy  # we will use the constants part only

2.2.2. Interaction of Common Particles with Matter#

We generally use electron, photons, and neutrons for diffraction/scattering experiments.

These particles interact with differently with matter:

X-rays $\leftrightarrow$ electron density
neutrons $\leftrightarrow$ mass of nucleus
neutrons $\leftrightarrow$ magnetic moment
electrons $\leftrightarrow$ screened charge of nucleus

We will deal with the nature of electrons more closely in the following

2.2.3. Non-relativistic de Broglie Wavelength#

The electron is a elementary particle with spin \(\frac{1}{2}\) (lepton).

Non–relativistic De Broglie wavelength of electron:

\(\lambda = \frac{h}{p} = \frac{h}{\sqrt{2m_0E_{kin}}} \approx \frac{1.22}{\sqrt{E_{kin}}}\)

E is the kinetic energy of the electron: \(E_{kin} = eU \) [eV].

The wave length in a TEM is usually a couple of picometers . This is a factor of 100 smaller than your XRD-source.

Obvioulsy, we are in the wave picture right now.

# --------- input  ---------------------------
acceleration_voltage_V = U = 300.0 * 1000.0 #V   
# --------------------------------------------
## energy
E_kin = acceleration_voltage_V * scipy.constants.elementary_charge
h = scipy.constants.Planck
m0 = scipy.constants.electron_mass
c = scipy.constants.speed_of_light

wave_length_m = h/np.sqrt(2*m0*E_kin) # non-relativistic wavelength in m

# # please note that we will keep all length units in Angstrom if possible.
# # otherwise we use only SI units!!!
wave_length_A = wave_length_m *1e10 # now in Angstrom

print(f'Classic wave length is {wave_length_A*100.:.2f} pm for acceleration voltage {acceleration_voltage_V/1000.:.1f} kV')
# Notice that we change units in the output to make them most readable.

print(f' which is a velocity of {np.sqrt(2/m0*E_kin):.2f} m/s or {np.sqrt(2/m0*E_kin)/c*100:.2f}% of the speed of light')
Classic wave length is 2.24 pm for acceleration voltage 300.0 kV
 which is a velocity of 324852582.95 m/s or 108.36% of the speed of light

2.2.4. Relativistic Correction#

In the table below we see that the speeds of the electron is rather close to the speed of light \(c\)

The formula for relativistic corrected wavelength is: \(\lambda = \frac{h}{\sqrt{2m_e E_{kin} *(1+\frac{E_{kin}}{2 m_e c^2})}}\)

Please note: All units are internally in SI units: kg, s, V, J, except the length wihich is in nm!

We multiply with the appropriate factors for the output

# ---------Input: Acceleration Voltage --
E0 = acceleration_voltage_V = 300.0 *1000.0 # V
# ---------------------------------------
E_kin = acceleration_voltage_V * scipy.constants.elementary_charge
h = scipy.constants.Planck
m0 = scipy.constants.electron_mass
c = scipy.constants.speed_of_light

#relativisitic wavelength
wave_length = h/np.sqrt(2* m0 * E_kin * (1 + E_kin / (2 * m0 * c**2))) #in m

print(f'The relativistically corrected wave length is {wave_length*1e12:.2f} pm for acceleration voltage {acceleration_voltage_V/1000:.1f} kV')
The relativistically corrected wave length is 1.97 pm for acceleration voltage 300.0 kV

100kV : \(\lambda\) = 4 pm \(<\) than diameter of an atom

The relativistic parameters are:

E (keV)

\(\lambda\) (pm)

M/m\(_0\)

v/c

10

12.2

1.0796

0.1950

30

6.98

1.129

0.3284

100

3.70

1.1957

0.5482

200

2.51

1.3914

0.6953

400

1.64

1.7828

0.8275

1000

0.87

2.9569

0.9411

The same functionality (and code) is used in the kinematic_scattering library and we can test the values of above table.

Please change the acceleration voltage (acceleration_voltage_V) above.

2.2.4.1. Relativistic velocity#

\[\frac{v^2}{c^2} = \frac{E_{kin}(E_{kin}+2m_e c^2)}{(E_{kin}+m_e c^2)^2}\]
v = np.sqrt(E_kin * (E_kin + 2 * m0 * c**2)/(E_kin + m0 * c**2) **2)*c

print(f'For an acceleration voltage of {acceleration_voltage_V/1000:.0f}keV: ')
print(f'The classic velocity of the electron  is {np.sqrt(2/m0 * E_kin):.2f} m/s or {np.sqrt(2 / m0 * E_kin)/c * 100:.2f}% of the speed of light')
print(f'The relativistic velocity of the electron  is {v:.2f} m/s or {v/c*100:.2f}% of the speed of light')
For an acceleration voltage of 300keV: 
The classic velocity of the electron  is 324852582.95 m/s or 108.36% of the speed of light
The relativistic velocity of the electron  is 232796486.28 m/s or 77.65% of the speed of light

2.2.5. That means that the resolution is not limited by the wavelength!#

# Import Kinematic Scattering Library
import pyTEMlib.kinematic_scattering as ks         # Kinematic scattering Library

acceleration_voltage= 30*1e3
wave_length = ks.get_wavelength(acceleration_voltage)
print(f'The relativistically corrected wave length is {wave_length*1e2:.2f} pm for acceleration voltage {acceleration_voltage/1000:.1f} kV')

# Wavelength in Angstrom
def get_wavelength(acceleration_voltage):
    """
    Calculates the relativistic corrected de Broglie wave length of an electron

    Input:
    ------
        acceleration voltage in volt
    Output:
    -------
        wave length in Angstrom
    """
    E = acceleration_voltage * scipy.constants.elementary_charge
    h = scipy.constants.Planck
    m0 = scipy.constants.electron_mass
    c = scipy.constants.speed_of_light
    
    wavelength = h / np.sqrt(2 * m0 * E * (1 + (E / (2 * m0 * c ** 2))))
    return wavelength * 10**10
The relativistically corrected wave length is 6.98 pm for acceleration voltage 30.0 kV
help(ks.get_wavelength)
Help on function get_wavelength in module pyTEMlib.kinematic_scattering:

get_wavelength(acceleration_voltage)
    Calculates the relativistic corrected de Broglie wavelength of an electron in Angstrom
    
    Parameter:
    ---------
    acceleration_voltage: float
        acceleration voltage in volt
    Returns:
    -------
    wavelength: float
        wave length in Angstrom
help(ks)
Help on module pyTEMlib.kinematic_scattering in pyTEMlib:

NAME
    pyTEMlib.kinematic_scattering

DESCRIPTION
    kinematic_scattering
    Copyright by Gerd Duscher
    
    The University of Tennessee, Knoxville
    Department of Materials Science & Engineering
    
    Sources:
       Scattering Theory:
       Zuo and Spence, "Advanced TEM", 2017
    
       Spence and Zuo, Electron Microdiffraction, Plenum 1992
    
       Atomic Form Factor:
           Kirkland: Advanced Computing in Electron Microscopy 2nd edition
           Appendix C
    
    Units:
        everything is in SI units, except length which is given in Angstrom.
    
    Usage:
        See the notebooks for examples of these routines
    
    All the input and output is done through a ase.Atoms object and the dictionary in the info attribute

FUNCTIONS
    Zuo_fig_3_18(verbose=True)
        Input for Figure 3.18 in Zuo and Spence "Advanced TEM", 2017
        
        This input acts as an example as well as a reference
        
        Parameters:
        -----------
        verbose: boolean:
            optional to see output
        Returns:
        -------
            atoms: ase.Atoms
                Silicon crystal structure
            e
            dictionary: tags is the dictionary of all input and output parameter needed to reproduce that figure.
    
    check_sanity(atoms, verbose_level=0)
        Check sanity of input parameters
    
    example(verbose=True)
        same as Zuo_fig_3_18
    
    feq(element, q)
        Atomic form factor parametrized in 1/Angstrom but converted to 1/Angstrom
        
        The atomic form factor is from Kirkland: Advanced Computing in Electron Microscopy 2nd edition, Appendix C.
        From Appendix C of Kirkland, "Advanced Computing in Electron Microscopy", 3Ard ed.
        Calculation of electron form factor for specific q:
        Using equation Kirkland C.15
        
        Parameters
        ----------
        element: string
            element name
        q: float
            magnitude of scattering vector in 1/Angstrom -- (=> exp(-i*g.r), physics negative convention)
        
        Returns
        -------
        fL+fG: float
            atomic scattering vector
    
    find_angles(zone)
        Microscope stage coordinates of zone
    
    find_nearest_zone_axis(tags)
        Test all zone axis up to a maximum of hkl_max
    
    get_dynamically_allowed(atoms, verbose=False)
    
    get_metric_tensor(matrix)
        The metric tensor of the lattice.
    
    get_rotation_matrix(tags)
        zone axis in global coordinate system
    
    get_wavelength(acceleration_voltage)
        Calculates the relativistic corrected de Broglie wavelength of an electron in Angstrom
        
        Parameter:
        ---------
        acceleration_voltage: float
            acceleration voltage in volt
        Returns:
        -------
        wavelength: float
            wave length in Angstrom
    
    kinematic_scattering(atoms, verbose=False)
        All kinematic scattering calculation
        
        Calculates Bragg spots, Kikuchi lines, excess, and deficient HOLZ lines
        
        Parameters
        ----------
        atoms: ase.Atoms
            object with crystal structure:
            and with experimental parameters in info attribute:
            'acceleration_voltage_V', 'zone_hkl', 'Sg_max', 'hkl_max'
            Optional parameters are:
            'mistilt', convergence_angle_mrad', and 'crystal_name'
            verbose = True will give extended output of the calculation
        verbose: boolean
            default is False
        
        Returns
        -------
        atoms:
            There are three sub_dictionaries in info attribute:
            ['allowed'], ['forbidden'], and ['HOLZ']
            ['allowed'] and ['forbidden'] dictionaries contain:
                ['Sg'], ['hkl'], ['g'], ['structure factor'], ['intensities'],
                ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], ['HHOLZ'], ['label'], and ['Laue_zone']
            the ['HOLZ'] dictionary contains:
                ['slope'], ['distance'], ['theta'], ['g_deficient'], ['g_excess'], ['hkl'], ['intensities'],
                ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], and  ['HHOLZ']
            Please note that the Kikuchi lines are the HOLZ lines of ZOLZ
        
            There are also a few parameters stored in the main dictionary:
                ['wave_length_nm'], ['reciprocal_unit_cell'], ['inner_potential_V'], ['incident_wave_vector'],
                ['volume'], ['theta'], ['phi'], and ['incident_wave_vector_vacuum']
    
    kinematic_scattering2(atoms, verbose=False)
        All kinematic scattering calculation
        
        Calculates Bragg spots, Kikuchi lines, excess, and deficient HOLZ lines
        
        Parameters
        ----------
        atoms: ase.Atoms
            object with crystal structure:
            and with experimental parameters in info attribute:
            'acceleration_voltage_V', 'zone_hkl', 'Sg_max', 'hkl_max'
            Optional parameters are:
            'mistilt', convergence_angle_mrad', and 'crystal_name'
            verbose = True will give extended output of the calculation
        verbose: boolean
            default is False
        
        Returns
        -------
        ato,s:
            There are three sub_dictionaries in info attribute:
            ['allowed'], ['forbidden'], and ['HOLZ']
            ['allowed'] and ['forbidden'] dictionaries contain:
                ['Sg'], ['hkl'], ['g'], ['structure factor'], ['intensities'],
                ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], ['HHOLZ'], ['label'], and ['Laue_zone']
            the ['HOLZ'] dictionary contains:
                ['slope'], ['distance'], ['theta'], ['g_deficient'], ['g_excess'], ['hkl'], ['intensities'],
                ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], and  ['HHOLZ']
            Please note that the Kikuchi lines are the HOLZ lines of ZOLZ
        
            There are also a few parameters stored in the main dictionary:
                ['wave_length_nm'], ['reciprocal_unit_cell'], ['inner_potential_V'], ['incident_wave_vector'],
                ['volume'], ['theta'], ['phi'], and ['incident_wave_vector_vacuum']
    
    make_pretty_labels(hkls, hex_label=False)
        Make pretty labels
        
        Parameters
        ----------
        hkls: np.ndarray
            a numpy array with all the Miller indices to be labeled
        hex_label: boolean - optional
            if True this will make for Miller indices.
        
        Returns
        -------
        hkl_label: list
            list of labels in Latex format
    
    read_poscar(filename)
    
    ring_pattern_calculation(atoms, verbose=False)
        Calculate the ring diffraction pattern of a crystal structure
        
        Parameters
        ----------
        atoms: Crystal
            crystal structure
        verbose: verbose print-outs
            set to False
        Returns
        -------
        tags: dict
            dictionary with diffraction information added
    
    scattering_matrix(tags, verbose_level=1)
        Scattering matrix
    
    stage_rotation_matrix(alpha, beta)
        Microscope stage coordinate system
    
    vector_norm(g)
        Length of vector
        
        depreciated - use np.linalg.norm
    
    zone_mistilt(zone, angles)
        Rotation of zone axis by mistilt
        
        Parameters
        ----------
        zone: list or numpy array of int
            zone axis in Miller indices
        angles: ist or numpy array of float
            list of mistilt angles in degree
        
        Returns
        -------
        new_zone_axis: np.ndarray (3)
            new tilted zone axis

DATA
    a_l = 0.3336
    base_l = [(0.6666666666666666, 0.3333333333333333, 0.5), (0.3333333333...
    c_l = 0.4754
    cdb = {'ag': {'a': 4.0853, 'crystal_name': 'silver', 'elements': 'Ag',...
    crystal_data_base = {'ag': {'a': 4.0853, 'crystal_name': 'silver', 'el...
    electronFF = {'Ac': {'Z': 89, 'bond_length': [2.09, 1.88, 1.7, 0], 'ch...
    inputKeys = ['acceleration_voltage_V', 'zone_hkl', 'Sg_max', 'hkl_max'...
    jmol_colors = array([[1.   , 0.   , 0.   ],
           [1.   , 1. ...02, 0...
    optional_inputKeys = ['crystal', 'lattice_parameter_nm', 'convergence_...

FILE
    c:\users\gduscher\appdata\local\anaconda3\lib\site-packages\pytemlib\kinematic_scattering.py

2.2.6. Particle Flux and Current#

It is important todetermine the order of magitude of how many electrons are hitting the sample.

The electron sources deliver in the order of \(\mu\)A current, but most of these electrons are not used.

In a modern electron microscope, we talk about a range of 1pA to 1nA in the electron beam.

We start with the defition of an Ampere: $\(A = \frac{C}{s}\)$

That definition is enough to calculate the number ofelectron per time unit (flux).

print(f" elementary charge: {scipy.constants.physical_constants['elementary charge'][0]:.5g} {scipy.constants.physical_constants['elementary charge'][1]}")
print(f'\n  1pA is {1e-12/scipy.constants.elementary_charge:.3} electrons/s or {1e-12/scipy.constants.elementary_charge/1000:.0f} electrons/ms')
print(f' 10pA is {10e-12/scipy.constants.elementary_charge:.3} electrons/s')
print(f'100pA is {100e-12/scipy.constants.elementary_charge*1 :.3} electrons/s')

print(f'\n at 10pA an electron will hit the sample every {scipy.constants.elementary_charge/10e-12 * 1e9:.2f} ns ')
 elementary charge: 1.6022e-19 C

  1pA is 6.24e+06 electrons/s or 6242 electrons/ms
 10pA is 6.24e+07 electrons/s
100pA is 6.24e+08 electrons/s

 at 10pA an electron will hit the sample every 16.02 ns 

We see that we have much lower fluence in the TEM than in a laser (how could they do femtosecond pulses otherwise).

2.2.6.1. Question#

How long does one have to integrate a detector to register 1 electron with an electron beam of 1.6pA?