Beam Wavelength Spread in Specular Simulations

This example demonstrates beam wavelength spread effects in reflectivity computations. All simulation parameters (except for those related to beam spread itself) coincide with those defined in reflectometry simulation tutorial.

In real specular experiments the observed reflectivity is always affected by the beam spread in both wavelength and incident angle.

Intensity image

In this example the following parameters related to the spread of the beam were set to the simulation:

  • Gaussian distributions both in wavelength and incident angle
  • The mean value for beam wavelength $\lambda_0 = 1.54 \, \unicode{x212B}$
  • Standard deviation in the wavelength $\sigma_{\lambda} = 0.01 \cdot \lambda_0$
  • Standard deviation in the incident angle $\sigma_{\alpha} = 0.01^{\circ}$

As one can see from the python script, the definitions of beam parameter distributions match ones described in similar example for GISAS simulations. However, in the case of the incident angle one should always use a distribution with zero mean, since the actual mean value is substituted by SpecularSimulation in dependence on the defined inclination angle range. If the distribution of the incident angle has non-zero mean value, an exception is thrown:

terminate called after throwing an instance of 'std::runtime_error'
  what():  Error in SpecularSimulation: parameter distribution of beam inclination angle should have zero mean.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""
An example of taking into account beam angular and wavelength
divergence in reflectometry calculations with BornAgain.

"""
import bornagain as ba

# input parameters
wavelength = 1.54 * ba.angstrom
alpha_i_min = 0.0 * ba.deg  # min incident angle, deg
alpha_i_max = 2.0 * ba.deg  # max incident angle, rad

# convolution parameters
d_wl = 0.01 * wavelength  # spread width for wavelength
d_ang = 0.01 * ba.deg  # spread width for incident angle
n_sig = 3  # number of sigmas to convolve over
n_points = 25  # number of points to convolve over

# substrate (Si)
si_sld_real = 2.0704e-06  # \AA^{-2}
# layer parameters
n_repetitions = 10
# Ni
ni_sld_real = 9.4245e-06  # \AA^{-2}
d_ni = 70 * ba.angstrom  # ni layer thickness (nm)
# Ti
ti_sld_real = -1.9493e-06  # \AA^{-2}
d_ti = 30 * ba.angstrom  # ti layer thickness (nm)


def get_sample():
    # defining materials
    # this example implies beam divergence in the wavelength,
    # thus MaterialBySLD must be used to provide correct result
    m_air = ba.MaterialBySLD("Air", 0.0, 0.0)
    m_ni = ba.MaterialBySLD("Ni", ni_sld_real, 0.0)
    m_ti = ba.MaterialBySLD("Ti", ti_sld_real, 0.0)
    m_substrate = ba.MaterialBySLD("SiSubstrate", si_sld_real, 0.0)

    air_layer = ba.Layer(m_air)
    ni_layer = ba.Layer(m_ni, d_ni)
    ti_layer = ba.Layer(m_ti, d_ti)
    substrate_layer = ba.Layer(m_substrate)
    multi_layer = ba.MultiLayer()
    multi_layer.addLayer(air_layer)
    for i in range(n_repetitions):
        multi_layer.addLayer(ti_layer)
        multi_layer.addLayer(ni_layer)
    multi_layer.addLayer(substrate_layer)
    return multi_layer


def get_simulation(scan_size=500):
    """
    Returns a specular simulation with beam and detector defined.
    """

    alpha_distr = ba.RangedDistributionGaussian(n_points, n_sig)
    wavelength_distr = ba.RangedDistributionGaussian(n_points, n_sig)

    scan = ba.AngularSpecScan(wavelength, scan_size, alpha_i_min, alpha_i_max)
    scan.setAbsoluteAngularResolution(alpha_distr, d_ang)
    scan.setAbsoluteWavelengthResolution(wavelength_distr, d_wl)

    simulation = ba.SpecularSimulation()
    simulation.setScan(scan)

    return simulation


def run_simulation():
    """
    Runs simulation and returns it.
    """
    sample = get_sample()
    simulation = get_simulation()
    simulation.setSample(sample)
    simulation.runSimulation()
    return simulation.result()


if __name__ == '__main__':
    results = run_simulation()
    ba.plot_simulation_result(results)
BeamFullDivergence.py