Vs GenX

This example applies a Gaussian incident-angle spread to a specular reflectometry calculation and compares the BornAgain result with reference data generated by GenX. It isolates angular divergence as the instrument correction under test while keeping the multilayer model common to both calculations.

Result

Vs GenX result

Sample

Vs GenX sample

Data files

Place these files next to the Python script.

Python script

 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
87
88
89
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = ["bornagain>=25,<26"]
# ///
"""
Reflectivity of a multilayer, taking into account beam angular divergence
and beam footprint correction, simulated with BornAgain and GenX.
"""
from pathlib import Path
import numpy as np, sys
import bornagain as ba
ba.require_versions("bornagain>=25,<26")
from bornagain import angstrom, deg, nm

# input parameters
wavelength = 1.54*angstrom
beam_sample_ratio = 0.01  # beam-to-sample size ratio

def reference_data(filename):
    """
    Loads and returns reference data from GenX simulation
    """
    # Data files are next to this script.
    data_dir = Path(__file__).resolve().parent
    filepath = data_dir / filename
    print(f"Loading GenX reference data from {filepath}")
    ax_values, data = np.loadtxt(filepath,
                                      usecols=(0, 1),
                                      skiprows=3,
                                      unpack=True)

    # translate axis values from double incident angle to incident angle
    ax_values *= 0.5

    return ax_values, data


def get_sample():
    """
    Twenty alternating Ti and Ni layers on a silicon substrate.
    """
    ambient_mat = ba.Vacuum()
    ti_mat = ba.SLDMaterial("Ti", (0.05, 0.62, 0.55), -1.9493e-6, 0)
    ni_mat = ba.SLDMaterial("Ni", (0.93, 0.48, 0.14), 9.4245e-6, 0)
    substrate_mat = ba.SLDMaterial(
        "SiSubstrate", (0.28, 0.57, 0.82), 2.0704e-6, 0)

    stack = ba.LayerStack(10)
    stack.addLayer(ba.Layer(ti_mat, 3*nm))
    stack.addLayer(ba.Layer(ni_mat, 7*nm))

    sample = ba.Sample()
    sample.addLayer(ba.Layer(ambient_mat))
    sample.addStack(stack)
    sample.addLayer(ba.Layer(substrate_mat))
    return sample


def get_simulation(sample):
    """
    A specular simulation with beam and detector defined.
    """
    n = 500
    footprint = ba.FootprintSquare(beam_sample_ratio)
    alpha_distr = ba.DistributionGaussian(0, 0.01 * deg, 25, 3.)

    # scan starts high enough that all divergence samples stay above the horizon
    scan = ba.AlphaScan(n, 0.04*deg, 2*deg)
    scan.setWavelength(1.54*angstrom)
    scan.setFootprint(footprint)
    scan.setGrazingAngleDistribution(alpha_distr)

    return ba.SpecularSimulation(scan, sample)


if __name__ == '__main__':
    genx_axis, genx_values = reference_data("genx_angular_divergence.dat.gz")

    ba.plt.yscale('log')
    ba.plt.plot(genx_axis, genx_values, 'ko', markevery=300)

    sample = get_sample()
    ba.showSample3D(sample, sample_size=120*nm, seed=0)
    simulation = get_simulation(sample)
    result = simulation.simulate()
    ba.plot_datafield(result)
    ba.plt.legend(['GenX', 'BornAgain'], loc='upper right')
    ba.plt.show()
auto/Examples/specular/instrument/VsGenx.py