In [1]:
import numpy as np
import escape as esc

esc.require("0.9.8")
Loading material database from C:\dev\escape-core\python\src\escape\scattering\..\data\mdb\materials.db

Specular reflectivity. (Ta/Cu/Nb/Gd/Nb/Al2O3). Example with mass density fit.¶

This notebook shows a multilayer X-ray reflectivity fit for a Nb/Gd/Nb structure on Al2O3. The example is useful for understanding how density-based parameters and layer interfaces shape the measured reflectivity curve.

In this notebook we are going to fit the data published in the following article [https://doi.org/10.1103/PhysRevB.97.144511]. The given sample is a Nb(25nm)/Gd(7nm)/Nb(25nm) trilayer on a Al2O3 substrate and covered with Ta/Cu thin films. In the previous notebook about specular reflectivity we have demonstarted how the module works, where as an experimental data we took the curve generated with Parratt32 program. The idea of this notebook is to demonstrate how to work with real experimental data in terms of ESCAPE. The result obtained here could be slightly different from what is published, because we do not have all details about published model.

We first define our parameters, which we are going to fit. The names of these parameters are self-explanatory.

In [2]:
thknTa = esc.par("Ta Thkn", 3.0, units="nm", userlim=[1, 5])
roughTa = esc.par("Ta Roughness", 0.1, units="nm", userlim=[0, 3])

thknCu = esc.par("Cu Thkn", 4.0, units="nm", userlim=[3, 7])
roughCu = esc.par("Cu Roughness", 0.5, units="nm", userlim=[0, 4])

thknGd = esc.par("Gd Thkn", 7.6, units="nm", userlim=[0, 10])
roughGd = esc.par("Gd Roughness", 0.5, units="nm", userlim=[0, 5])

thknNb1 = esc.par("Nb1 Thkn", 25.0, units="nm", userlim=[20, 30])
roughNb1 = esc.par("Nb1 Roughness", 1.0, units="nm", userlim=[0, 5])

thknNb2 = esc.par("Nb2 Thkn", 25.0, units="nm", userlim=[20, 30])
roughNb2 = esc.par("Nb2 Roughness", 1.0, units="nm", userlim=[0, 5])

roughAl2O3 = esc.par("Al2O3 Roughness", 1.0, units="nm", userlim=[0, 1])

Next we create materials, layers and finally the sample objects.

In [3]:
Al2O3 = esc.amorphous(
    "Al2O3", formula="Al2O3", density=esc.par(value="3.95g/cm^3", fixed=True)
)

ta_layer = esc.layer("Ta", thknTa, roughTa, bydensity=True)
cu_layer = esc.layer("Cu", thknCu, roughCu, bydensity=True)
gd_layer = esc.layer("Gd", thknGd, roughGd, bydensity=True)

nb1_layer = esc.layer("Nb", thknNb1, roughNb1, bydensity=True)
nb2_layer = esc.layer("Nb", thknNb2, roughNb2, bydensity=True)

sub = esc.substrate(Al2O3, roughAl2O3, bydensity=True)

sample = esc.multilayer(name="Ta/Cu/Nb1/Gd/Nb2/Al2O3", frgr=esc.air("Air"), bkgr=sub)

sample.add(ta_layer)
sample.add(cu_layer)
sample.add(nb1_layer)
sample.add(gd_layer)
sample.add(nb2_layer)

wl = 0.229  # we use it later
src = esc.xrays(wavelength=wl, units="nm")

sample.show(source=src)
Out[3]:

The contribution of resolution function is negligible, but as a demonstration we will take it into account. The beam FWHM can be also defined as a parameter. This can help, if resolution function cannot be estimated properly. Normally this paramater is fixed.

In [4]:
Qz = esc.var("qz")
fwhm = esc.par("FWHM", 2.0e-2, userlim=[0.001, 0.02], fixed=True)
R = esc.specrefl(Qz, sample, "matrix", source=src)
# we integrate over the variable Qz, thus intensity is a function of I(Qz0)
R = esc.average_normal(R, fwhm, Qz)

Below we take into account sample size. At low angles the X-rays or neutrons beam doesn't cover the whole sample leading to the reduction of intensity. Usually this correction is done for the data, but can be also added to the model as a fit parameter in the case if some characteristics are not known.

In [5]:
I0 = esc.par("I0", 1, scale=1e7, userlim=[0.1, 10], units="Cnt")
B = esc.par("Bgr", 10, userlim=[0, 30], units="Cnt")

h = 0.05  # size of a beam
L = 5  # size of a sample

Qmax = esc.par(
    "Qmax", 4 * np.pi / wl * h / L, fixed=True, userlim=[0, 1.5], units="1/nm"
)

I0f = esc.conditional(Qz > Qmax, esc.func(Qz, I0), I0 / (Qmax / Qz))

I = I0f * R + B
In [6]:
# Opening the experimental data and creating the data object
theta, y = np.loadtxt("data/GdNb/TriLayer/XRR/xrr2.dat", unpack=True)
qz = 4 * np.pi / wl * np.sin((theta / 2) * np.pi / 180.0)

qz_r = qz[(qz >= 0.15) & (qz <= 3)]
y_r = y[(qz >= 0.15) & (qz <= 3)]
print(qz_r.size, y_r.size)
dobj = esc.data(qz_r, y_r, copy=True)
596 596
In [7]:
# Creating the model
mobj = esc.model(I, dobj, residuals_scale="log", weight_type="none")
In [8]:
# Now we can perform optimization with DE algorithm
opt = esc.diffevol(
    mobj,
    popsize=6,
    maxiter=150,
    ftol=1e-5,
    nupdate=5,
    crossover=0.7,
    maxfev=10000,
    #strategy="best1bin",
    polish_final_maxiter=50,
    polish_candidate_maxiter=0,
)

opt()

opt.show().config_model(ylog=True, xlog=False, xlabel="Q[1/nm]", ylabel="R")
Out[8]:
In [9]:
sample.show(source=src)
Out[9]:
In [10]:
opt
Out[10]:
Name: Differential Evolution	Parameters number:         21
Parameter           	Value          	+-	Error     	Units     	Fixed
Qmax                	        0.54875	+-	0         	1/nm      	    1
I0                  	         1.3557	+-	0.00019993	x1e+07	Cnt	    0
FWHM                	           0.02	+-	0         	          	    1
Ta Density          	         16.663	+-	0.0083433 	          	    0
Ta Thkn             	         3.9509	+-	0.0046787 	nm        	    0
Ta Roughness        	         2.3442	+-	0.0018266 	nm        	    0
Cu Density          	         4.8391	+-	0.0044598 	          	    0
Cu Thkn             	         4.9888	+-	0.01838   	nm        	    0
Cu Roughness        	        0.83511	+-	0.00068212	nm        	    0
Nb Density          	          4.285	+-	0         	          	    0
Nb1 Thkn            	         25.903	+-	0.019642  	nm        	    0
Nb1 Roughness       	          1.689	+-	0.021744  	nm        	    0
Gd Density          	         7.5076	+-	0.0017482 	          	    0
Gd Thkn             	         9.6568	+-	0.0024783 	nm        	    0
Gd Roughness        	         1.0817	+-	0.00242   	nm        	    0
Nb Density          	         8.6878	+-	0.0018635 	          	    0
Nb2 Thkn            	         26.746	+-	0.0024649 	nm        	    0
Nb2 Roughness       	        0.87448	+-	0.0021615 	nm        	    0
Parameter           	           3.95	+-	0         	g/cm^3    	    1
Al2O3 Roughness     	        0.69889	+-	0.001659  	nm        	    0
Bgr                 	         6.3855	+-	0.4075    	Cnt       	    0
In [ ]: