Note
Go to the end to download the full example code.
Bragg’s law: indexing powder XRD peaks#
Each line of a diffraction pattern is a family of \((hkl)\) planes
that satisfies Bragg’s law \(n\lambda=2d\sin\theta\).
powder_xrd_peaks() computes each
reflection’s structure factor
(structure_factor()) directly
from atomic positions and Miller indices, so BCC’s and FCC’s systematic
absences (reflections with zero intensity by symmetry) fall out
automatically rather than being hardcoded as a rule.
import matplotlib.pyplot as plt
import numpy as np
from chemistrykit.crystal.systems.xrd import powder_xrd_peaks
from chemistrykit.crystal.visualizers.crystal_plots import plot_xrd_pattern
wavelength = 154.18 # Cu-Kalpha, pm
iron_bcc = powder_xrd_peaks("BCC", a=286.65, wavelength=wavelength, hkl_max=3)
copper_fcc = powder_xrd_peaks("FCC", a=361.5, wavelength=wavelength, hkl_max=3)
polonium_sc = powder_xrd_peaks("SC", a=336.0, wavelength=wavelength, hkl_max=2)
print("Fe (BCC) allowed reflections (h+k+l even only):")
for peak in iron_bcc:
print(f" {peak.hkl} 2theta={peak.two_theta:6.2f} deg d={peak.d_spacing:6.2f} pm")
print("\nCu (FCC) allowed reflections (unmixed parity only):")
for peak in copper_fcc:
print(f" {peak.hkl} 2theta={peak.two_theta:6.2f} deg d={peak.d_spacing:6.2f} pm")
print("\nalpha-Po (SC) allowed reflections (no absences):")
for peak in polonium_sc:
print(f" {peak.hkl} 2theta={peak.two_theta:6.2f} deg d={peak.d_spacing:6.2f} pm")
Fe (BCC) allowed reflections (h+k+l even only):
(1, 1, 0) 2theta= 44.71 deg d=202.69 pm
(1, 0, 1) 2theta= 44.71 deg d=202.69 pm
(0, 1, 1) 2theta= 44.71 deg d=202.69 pm
(2, 0, 0) 2theta= 65.08 deg d=143.32 pm
(0, 2, 0) 2theta= 65.08 deg d=143.32 pm
(0, 0, 2) 2theta= 65.08 deg d=143.32 pm
(2, 1, 1) 2theta= 82.41 deg d=117.02 pm
(1, 2, 1) 2theta= 82.41 deg d=117.02 pm
(1, 1, 2) 2theta= 82.41 deg d=117.02 pm
(2, 2, 0) 2theta= 99.04 deg d=101.35 pm
(2, 0, 2) 2theta= 99.04 deg d=101.35 pm
(0, 2, 2) 2theta= 99.04 deg d=101.35 pm
(3, 1, 0) 2theta=116.52 deg d= 90.65 pm
(3, 0, 1) 2theta=116.52 deg d= 90.65 pm
(1, 3, 0) 2theta=116.52 deg d= 90.65 pm
(1, 0, 3) 2theta=116.52 deg d= 90.65 pm
(0, 3, 1) 2theta=116.52 deg d= 90.65 pm
(0, 1, 3) 2theta=116.52 deg d= 90.65 pm
(2, 2, 2) 2theta=137.38 deg d= 82.75 pm
Cu (FCC) allowed reflections (unmixed parity only):
(1, 1, 1) 2theta= 43.35 deg d=208.71 pm
(2, 0, 0) 2theta= 50.49 deg d=180.75 pm
(0, 2, 0) 2theta= 50.49 deg d=180.75 pm
(0, 0, 2) 2theta= 50.49 deg d=180.75 pm
(2, 2, 0) 2theta= 74.19 deg d=127.81 pm
(2, 0, 2) 2theta= 74.19 deg d=127.81 pm
(0, 2, 2) 2theta= 74.19 deg d=127.81 pm
(3, 1, 1) 2theta= 90.03 deg d=109.00 pm
(1, 3, 1) 2theta= 90.03 deg d=109.00 pm
(1, 1, 3) 2theta= 90.03 deg d=109.00 pm
(2, 2, 2) 2theta= 95.25 deg d=104.36 pm
(3, 3, 1) 2theta=136.73 deg d= 82.93 pm
(3, 1, 3) 2theta=136.73 deg d= 82.93 pm
(1, 3, 3) 2theta=136.73 deg d= 82.93 pm
alpha-Po (SC) allowed reflections (no absences):
(1, 0, 0) 2theta= 26.53 deg d=336.00 pm
(0, 1, 0) 2theta= 26.53 deg d=336.00 pm
(0, 0, 1) 2theta= 26.53 deg d=336.00 pm
(1, 1, 0) 2theta= 37.87 deg d=237.59 pm
(1, 0, 1) 2theta= 37.87 deg d=237.59 pm
(0, 1, 1) 2theta= 37.87 deg d=237.59 pm
(1, 1, 1) 2theta= 46.83 deg d=193.99 pm
(2, 0, 0) 2theta= 54.63 deg d=168.00 pm
(0, 2, 0) 2theta= 54.63 deg d=168.00 pm
(0, 0, 2) 2theta= 54.63 deg d=168.00 pm
(2, 1, 0) 2theta= 61.73 deg d=150.26 pm
(2, 0, 1) 2theta= 61.73 deg d=150.26 pm
(1, 2, 0) 2theta= 61.73 deg d=150.26 pm
(1, 0, 2) 2theta= 61.73 deg d=150.26 pm
(0, 2, 1) 2theta= 61.73 deg d=150.26 pm
(0, 1, 2) 2theta= 61.73 deg d=150.26 pm
(2, 1, 1) 2theta= 68.39 deg d=137.17 pm
(1, 2, 1) 2theta= 68.39 deg d=137.17 pm
(1, 1, 2) 2theta= 68.39 deg d=137.17 pm
(2, 2, 0) 2theta= 80.92 deg d=118.79 pm
(2, 0, 2) 2theta= 80.92 deg d=118.79 pm
(0, 2, 2) 2theta= 80.92 deg d=118.79 pm
(2, 2, 1) 2theta= 86.99 deg d=112.00 pm
(2, 1, 2) 2theta= 86.99 deg d=112.00 pm
(1, 2, 2) 2theta= 86.99 deg d=112.00 pm
(2, 2, 2) 2theta=105.27 deg d= 96.99 pm
BCC’s (100) reflection (h+k+l=1, odd) is absent – the first line is (110) instead. FCC’s (100) and (110) are both absent (mixed parity) – the first line is (111).
bcc_hkls = {p.hkl for p in iron_bcc}
fcc_hkls = {p.hkl for p in copper_fcc}
print(f"\n(100) present for BCC? {(1, 0, 0) in bcc_hkls}")
print(f"(110) present for BCC? {(1, 1, 0) in bcc_hkls}")
print(f"(100) present for FCC? {(1, 0, 0) in fcc_hkls}")
print(f"(111) present for FCC? {(1, 1, 1) in fcc_hkls}")
(100) present for BCC? False
(110) present for BCC? True
(100) present for FCC? False
(111) present for FCC? True
Every listed peak obeys Bragg’s law exactly – recover the wavelength from each peak’s d-spacing and angle, and the NaCl-style inverse problem (lattice constant from a measured angle) that the Braggs solved:
for peak in copper_fcc:
lam = 2.0 * peak.d_spacing * np.sin(np.radians(peak.two_theta / 2.0))
assert abs(lam - wavelength) < 1e-9
first = copper_fcc[0]
h, k, l = first.hkl
a_recovered = wavelength / (2.0 * np.sin(np.radians(first.two_theta / 2.0))) * np.sqrt(h * h + k * k + l * l)
print(f"\nCu lattice constant recovered from the (111) angle via Bragg's law: {a_recovered:.2f} pm")
Cu lattice constant recovered from the (111) angle via Bragg's law: 361.50 pm
fig, axes = plt.subplots(3, 1, figsize=(8, 8), sharex=True)
plot_xrd_pattern(iron_bcc, ax=axes[0])
axes[0].set_title("Fe (BCC)")
plot_xrd_pattern(copper_fcc, ax=axes[1])
axes[1].set_title("Cu (FCC)")
plot_xrd_pattern(polonium_sc, ax=axes[2])
axes[2].set_title("alpha-Po (SC)")
plt.tight_layout()
plt.show()

Total running time of the script: (0 minutes 0.126 seconds)