Chapter 2: Diffraction
HOLZ Lines¶
part of
MSE672: Introduction to Transmission Electron Microscopy
Spring 2026
by Gerd Duscher
Microscopy Facilities
Institute of Advanced Materials & Manufacturing
Materials Science & Engineering
The University of Tennessee, Knoxville
Background and methods to analysis and quantification of data acquired with transmission electron microscopes
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.2026.1.2':
print('installing pyTEMlib')
!{sys.executable} -m pip install pyTEMlib -q --upgrade
print('done')done
Import numerical and plotting python packages¶
Import the python packages that we will use:
Beside the basic numerical (numpy) and plotting (pylab of matplotlib) libraries,
and some libraries from the book
kinematic scattering library.
%matplotlib widget
import matplotlib.pyplot 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 libraries from pyTEMlib
import pyTEMlib
__notebook_version__ = '2026.01.11'
print('pyTEM version: ', pyTEMlib.__version__)
print('notebook version: ', __notebook_version__)pyTEM version: 0.2026.1.2
notebook version: 2026.01.11
Define crystal¶
### Please choose another crystal like: Silicon, Aluminium, GaAs , ZnO
atoms = pyTEMlib.crystal_tools.structure_by_name('silicon')
atomsLattice(symbols='Si8', pbc=True, cell=[5.43088, 5.43088, 5.43088])Plot the unit cell¶
from ase.visualize.plot import plot_atoms
plot_atoms(atoms, radii=0.3, rotation=('0x,4y,0z'))<Axes: >Parameters for Diffraction Calculation¶
tags = {}
tags['acceleration_voltage_V'] = 99 *1000.0 #V
tags['convergence_angle_mrad'] = 0
tags['zone_hkl'] = np.array([2,2,1]) # incident neares zone axis: defines Laue Zones!!!!
tags['Sg_max'] = .01 # 1/Ang maximum allowed excitation error ; This parameter is related to the thickness
tags['hkl_max'] = 36 # Highest evaluated Miller indices
Kinematic Scattering Calculation¶
diff_dict = pyTEMlib.diffraction_tools.get_bragg_reflections(atoms, tags, verbose=True)Of the 724 possible reflection 152 are allowed.
Of those, there are 2 in ZOLZ and 150 in HOLZ
Of the 10 forbidden reflection in ZOLZ 0 can be dynamically activated.
Plot Selected Area Electron Diffraction Pattern¶
#####################
# Plot ZOLZ SAED Pattern #
#####################
#We plot only the allowed diffraction spots
g = diff_dict['allowed']['g']
# we sort them by order of Laue zone
ZOLZ = diff_dict['allowed']['ZOLZ']
HOLZ = diff_dict['allowed']['HOLZ']
rotation = 0
x = g[:, 0] * np.cos(g[:, 1]+np.pi+rotation)*10
y = g[:, 0] * np.sin(g[:, 1]+np.pi+rotation)*10
slope = np.tan(g[:, 1]+rotation-np.pi/2)
# Plot
fig = plt.figure()
ax = fig.add_subplot(111)
# We plot the x,y axis only; the z -direction is set to zero - this is our projection
ax.scatter(x[ZOLZ], y[ZOLZ], c='red', s=20)
ax.scatter(x[HOLZ], y[HOLZ], c='green', s=20)
# zero spot plotting
ax.scatter(0,0, c='red', s=100)
ax.scatter(0,0, c='white', s=40)
ax.set_aspect('equal')
FOV = 4
plt.ylim(-FOV,FOV); plt.xlim(-FOV,FOV); plt.show()import pyTEMlib.animation as animate
plt.figure()
animate.deficient_holz_line(exact_bragg=False, laue_zone=1)
animate.deficient_holz_line(exact_bragg='True', laue_zone=1, color='blue')
animate.deficient_holz_line(exact_bragg='True', laue_zone=1, color='red', shift=True)
HOLZ Line Construction¶
Position of deficient HOLZ line
What is :¶
For exact Bragg position in ZOLZ
then
with:
Because is the same as we can now calculate the deficient HOLZ lines
For exact Bragg position in ZOLZ then
This is our Kikuchi line equation
#Calculate angle between K0 and deficient cone vector
#For dynamic calculations K0 is replaced by Kg
K0 = diff_dict['K_0']
g_allowed = diff_dict['allowed']['g']
g_norm_allowed = g_allowed[:, 0]
dtheta = g_allowed[:,0]/2-np.arcsin(g_allowed[:,2]/g_allowed[:,3])
#calculate length of distance of deficient cone to K0 in ZOLZ plane
gd_length =2*np.sin((dtheta)/2 )*K0
#Calculate nearest point of HOLZ and Kikuchi lines
gd = g_allowed.copy()
gd[:,0] = -gd[:,0]*gd_length/g_norm_allowed
gd[:,1] = -gd[:,1]*gd_length/g_norm_allowed
gd[:,2] = 0.
###calculate and save line in Hough space coordinates (distance and theta)
slope = gd[:,0]/(gd[:,1]+1e-20)
distance = gd_length
theta = np.arctan(slope)
Now everything together in a single cell¶
We change the lattice parameter (Vegard’s law of alloys) by a few pm and observe the effect on the pattern.
# ----- Input -----------
unit_cell_change_pm = 0.0
# -----------------------
atoms = pyTEMlib.crystal_tools.structure_by_name('Silicon')
cell = atoms.cell.lengths()
atoms.set_cell(cell+unit_cell_change_pm/100, scale_atoms=True)
atoms
tags = {'crystal_name': 'silicon',
'acceleration_voltage_V': 100.8*1000.0, #V
'convergence_angle_mrad': 5.,
'Sg_max': .03, # 1/Ang maximum allowed excitation error ; This parameter is related to the thickness
'hkl_max': 9, # Highest evaluated Miller indices
'zone_hkl': np.array([1, 2, -2]),
'mistilt_alpha degree': 0., # -45#-35-0.28-1+2.42
'mistilt_beta degree': 0.,
'plot_FOV': .5}
diff_dict ={}
diff_dict = pyTEMlib.diffraction_tools.get_bragg_reflections(atoms, tags, verbose=True)
diff_dict['output']=pyTEMlib.diffraction_tools.plot_holz_parameter()
diff_dict['output']['plot_reflections']=False
diff_dict['output']['plot_Kikuchi']=False
diff_dict['output']['linewidth_HOLZ'] = 3
diff_dict['output']['plot_HOLZ']=True
pyTEMlib.diffraction_tools.plot_diffraction_pattern(diff_dict)
plt.gca().set_xlim(-20,20)
plt.gca().set_ylim(-20,20)Of the 156 possible reflection 28 are allowed.
Of those, there are 4 in ZOLZ and 24 in HOLZ
Of the 46 forbidden reflection in ZOLZ 0 can be dynamically activated.
(-20.0, 20.0)Now for graphite and low acceleration voltages.¶
Change the acceleration voltage and see what happens.
Tip: 60.29keV and 59.68 keV are especially interesting
### Please choose another crystal like: Silicon, Aluminium, GaAs , ZnO
# ----- Input -----------
crystal_name = 'graphite'
acceleration_voltage = 61.49 * 1000.0
# -----------------------
atoms = pyTEMlib.crystal_tools.structure_by_name(crystal_name)
tags = {'crystal_name': crystal_name,
'acceleration_voltage': acceleration_voltage, #V
'convergence_angle': 7.,
'Sg_max': .03, # 1/Ang maximum allowed excitation error ; This parameter is related to the thickness
'hkl_max': 9, # Highest evaluated Miller indices
'zone_hkl': np.array([0, 0, 1]),
'mistilt_alpha': .0, # -45#-35-0.28-1+2.42
'mistilt_beta': 0.,
'plot_FOV': .5}
diff_dict ={}
diff_dict = pyTEMlib.diffraction_tools.get_bragg_reflections(atoms, tags, verbose=True)
diff_dict['output']=pyTEMlib.diffraction_tools.plot_holz_parameter()
diff_dict['output']['plot_reflections']=True
diff_dict['output']['plot_Kikuchi']=False
diff_dict['output']['linewidth_HOLZ'] = 2
diff_dict['output']['plot_HOLZ']=True
pyTEMlib.diffraction_tools.plot_diffraction_pattern(diff_dict)
plt.title(crystal_name + ': ' + str(tags['zone_hkl']))
plt.gca().set_xlim(-1.7, 1.7)
plt.gca().set_ylim(-1.7, 1.7)
plt.gca().set_aspect('equal')
Of the 138 possible reflection 118 are allowed.
Of those, there are 18 in ZOLZ and 100 in HOLZ
Of the 0 forbidden reflection in ZOLZ 0 can be dynamically activated.
Navigation¶
Back: Kikuchi Lines
Chapter 2: Diffraction
List of Content: Front