import numpy as np
import escape as esc
esc.require("0.9.7")
from escape.utils.widgets import show
Loading material database from /home/dkor/Data/Development/workspace_escape/escape/python/src/escape/scattering/../data/mdb/materials.db
High Resolution X-ray Diffraction¶
Implementation of High Resolution X-ray diffraction (HRXRD) module in ESCAPE is based fully on a series of works of Stepanov et al. This notebook demonstrates an application of the 2x2 reduced matrix formalism to the calculation of HRXRD intensity from the multilayer GaAs/(100A)AlAs(70A)x20 times on GaAs subtrate. A simulation generated by Stepanov's X-ray server has been used as experimental data, resulting in good matching between curve generated by ESCAPE and by Stepanov's server.
The script can simulate the following profiles of structure parameters and defects in multilayers:
Normal lattice strains, da(z)/a;
Crystal susceptibilities x0(z), xh(z), [chi0, chih]
Interface roughness sigma in multilayers.
The examples for lateral strains are not demonstrated or discussed in this notebook. The reflection from the whole multilayer in this notebook is calculated by terms of (2x2) reduced recursive matix fomalism, but (4x4) formalism which is useful for grazing incidence case is also available.
References:
S.A.Stepanov, E.A.Kondrashkina, R.Koehler, D.V.Novikov, G.Materlik, and S.M.Durbin, "Dynamical x-ray diffraction of multilayers and superlattices: Recursion matrix extension to grazing angles", Phys. Rev. B, 57, (1998) 4829-4841.
First we create all independent parameters relevant for our model. For the description of material in ESCAPE one have to provide scattering length densities as parameters. In Stepanov's software susceptibility is used as a fit parameter. For convinience we will use in this notebook susceptibilities too, but later multiply them by conversion coefficient coeff to convert to SLDs.
from escape.scattering.material import default_mdb as mdb
src = esc.xrays(1.540562)
gaas_strain = esc.par("Strain: GaAs", 0.0, userlim=[0.0, 0.03], units="A", fixed=True)
alas_strain = esc.par("Strain: AlAs", 0.298, scale=1e-2, units="A")
gaas_thkn = esc.par("GaAs Thkn", 100.0, units="A")
alas_thkn = esc.par("AlAs Thkn", 70.0, units="A")
gaas_rough = esc.par("GaAs RMS", 2.0, units="A")
alas_rough = esc.par("AlAs RMS", 2.0, units="A")
Next we can create unitcell objects and materials
sub_ucell = esc.unitcell("GaAs unitcell", 5.6532, 5.6532, 5.6532, 90.0, 90.0, 90.0)
#strained unitcell. substrate unitcell is a basis
gaas_ucell = esc.strained_unitcell("GaAs unitcell", gaas_strain, sub_ucell)
alas_ucell = esc.strained_unitcell("AlAs unitcell", alas_strain, sub_ucell)
gaas_material = esc.crystal("GaAs", density="mdb", ucell=gaas_ucell)
alas_material = esc.crystal("AlAs", density="mdb", ucell=alas_ucell)
sub_material = esc.crystal("GaAs", density="mdb", ucell=sub_ucell)
gaas_layer = esc.layer("Layer: GaAs", material=gaas_material, thkn=gaas_thkn, rough=gaas_rough)
alas_layer = esc.layer("Layer: AlAs", material=alas_material, thkn=alas_thkn, rough=alas_rough)
gaas_substr = esc.substrate("Substrate: GaAs", material=sub_material, rough=1.0)
sample = esc.multilayer("GaAs/AlAs:20", frgr=esc.air("Air"), bkgr=gaas_substr)
stack = esc.layer_stack("GaAs/AlAs", repeat=20)
stack.add(gaas_layer)
stack.add(alas_layer)
sample.add(stack)
show(sample, source=src, profile="sld0re")
#show(sample, source=src, profile="sld0im")
Below we create data object. As experimental data we take simulated curve from the Stepanov's X-ray server and add some poisson noise to it. Intensity of the substrate peak is very sensitive to angle values and a small correction value is necessary to get a better match between curves.
theta, y = np.loadtxt("data/g1743010.dat", unpack=True)
I0 = 1e8
K0 = 2.0 * np.pi / src.wavelength;
#z-component of incident wave vector
p0 = K0 * np.sin(np.deg2rad(theta))
y = np.random.poisson(y*I0)/I0
err = np.sqrt(y)/np.sqrt(I0)
dobj = esc.data("g1743010", p0, y, err, copy=True)
show(dobj, ylog=True, xlabel="Kz[1/A]", ylabel="Intensity")
#creating calculation kernels
p0=esc.var("p0")
src = esc.xrays(1.54056)
khrxrd2x2 = esc.kernel("", esc.spechrxrd("HRXRD 2x2", p0, sample, 0, 0, 4, 1.0, "2x2", source=src), multithreaded=True)
mobj = esc.model("Model", khrxrd2x2, dobj, residuals_scale="q4", weight_type="data")
opt = esc.diffevol("DiffEvol", mobj, maxiter=150, polish_final_maxiter=50,
polish_candidate_maxiter=50, minconv=1e-3, nupdate=1)
opt.shake()
#opt()
show(opt, ylog=True, xlog=False, xlabel="Kz[1/A]", ylabel="R")
Using the same sample object one can also calculate specular reflectivity. This is useful if specular reflectivity has been measured together with HRXRD. One can easily fit both curves with shared parameters.
qz = esc.var("Qz")
refl = esc.specrefl("Spec. Refl.", qz, sample, "parratt", source=src)
show(refl, coordinates=np.linspace(0, 0.1, 2000), ylog=True, xlabel="Qz[1/a]", ylabel="R")