Specular simulation with a footprint correction

This example demonstrates taking into account the beam footprint correction in specular simulations.

Footprint effect originates from non-infinite sizes of beam and sample. Then at small incident angles $\alpha_i$ the beam irradiates an area bigger than the area of the sample. Exact footprint impact depends on the ratio between the widths of beam and sample as well as on the shape of the beam.

Footprint scene

Intensity image

When taking into account footprint correction, there are two possible options for the beam shape in BornAgain:

  • Square beam — the beam has sharp edges and square cross-section, its intensity is uniformly distributed.
  • Gaussian beam — the beam is infinite in space, while its intensity has Gaussian distribution along the radius of the beam.

The footprint correction for square beam is defined by FootprintSquare command, which has the signature

<footprint_object> = FootprintSquare(beam_to_sample_width_ratio)

Here <footprint_object> is an object later passed to the simulation, while beam_to_sample_width_ratio defines the ratio between the widths of beam and sample.

In the case of the Gaussian beam the footprint object is created with

<footprint_object> = FootprintGauss(beam_to_sample_width_ratio)

The command signature is exactly the same as in the case with the square beam, but the beam width required for beam_to_sample_width_ratio is now defined as the beam diameter associated with the intensity level equal to $I_0 \cdot e^{-\frac{1}{2}}$, where $I_0$ is the on-axis (maximal) intensity.

In this example a square beam is considered, with beam_to_sample_width_ratio being equal to $0.01$. The incident angle range was made rather small in this example (from $0.0$ to $0.6$ degrees) in order to emphasize the footprint impact at small incident angles. In other respects this example exactly matches the reflectometry simulation tutorial.

 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
86
#!/usr/bin/env python3
"""
Specular simulation with a footprint correction
for a square beam

"""
from matplotlib import pyplot as plt
import bornagain as ba
from bornagain import deg, angstrom


def get_sample():
    """
    Defines sample and returns it
    """

    # creating materials
    m_ambient = ba.MaterialBySLD("Ambient", 0, 0)
    m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
    m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
    m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)

    # creating layers
    ambient_layer = ba.Layer(m_ambient)
    ti_layer = ba.Layer(m_ti, 30*angstrom)
    ni_layer = ba.Layer(m_ni, 70*angstrom)
    substrate_layer = ba.Layer(m_substrate)

    # creating multilayer
    multi_layer = ba.MultiLayer()
    multi_layer.addLayer(ambient_layer)
    for i in range(10):
        multi_layer.addLayer(ti_layer)
        multi_layer.addLayer(ni_layer)
    multi_layer.addLayer(substrate_layer)

    return multi_layer


def get_simulation(footprint):
    """
    Defines and returns a specular simulation.
    """
    simulation = ba.SpecularSimulation()
    scan = ba.AngularSpecScan(1.54*angstrom, 500, 0, 0.6*deg)
    scan.setFootprintFactor(footprint)
    simulation.setScan(scan)
    return simulation


def run_simulation(simulation):
    """
    Runs simulation and returns its result.
    """
    simulation.setSample(get_sample())
    simulation.runSimulation()
    return simulation.result()


def get_plot_data(sim_result):
    return sim_result.axis(), sim_result.array()


def plot(sim_result_1, sim_result_2):
    """
    Plots results from two different simulations
    """

    x1, y1 = get_plot_data(sim_result_1)
    x2, y2 = get_plot_data(sim_result_2)
    plt.semilogy(x1, y1, x2, y2)

    plt.xlabel(r'$\alpha_i \; (deg)$', fontsize=16)
    plt.ylabel(r'Intensity', fontsize=16)

    plt.legend(['With footprint', 'Without footprint'], loc='upper right')

    plt.show()


if __name__ == '__main__':
    beam_sample_ratio = 0.01  # beam-to-sample size ratio
    result_with_fp = run_simulation(
        get_simulation(footprint=ba.FootprintSquare(beam_sample_ratio)))
    result_without_fp = run_simulation(get_simulation(footprint=None))
    plot(result_with_fp, result_without_fp)
FootprintCorrection.py