1D lattice

In this example we simulate the scattering from a one-dimensional repetition of rectangular patches. This is done by using Crystal1D together with very long boxes.

  • By default, the axis of the one-dimensional lattice coincides with the $x$-axis of the reference Cartesian frame.
  • Long boxes are placed along a one-dimensional lattice on top of a substrate; the lattice length corresponds to the grating period.
  • length, width, height in the Box(length, width, height) constructor correspond to the $x$, $y$, $z$ axes, in that order.
  • The grating can be rotated by rotating both the Crystal1D lattice direction and the particle.
  • To avoid rapidly oscillating form factors of long boxes, the simulation is performed in Monte Carlo integration mode.

Scattering intensity

 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
#!/usr/bin/env python3
"""
Simulation of grating using very long boxes and 1D lattice.
Monte-carlo integration is used to get rid of
large-particle form factor oscillations.
"""
import bornagain as ba
from bornagain import ba_plot as bp, deg, micrometer, nm


def get_sample(lattice_rotation_angle=0*deg):
    """
    A sample with a grating on a substrate.
    lattice_rotation_angle = 0 - beam parallel to grating lines
    lattice_rotation_angle = 90*deg - beam perpendicular to grating lines
    """
    # Materials
    vacuum = ba.Vacuum()
    si_color = (0.30, 0.62, 0.86)
    si_mat = ba.RefractiveMaterial("Si", si_color, 5.7816e-6, 1.0229e-7)

    box_length, box_width, box_height = 50*micrometer, 70*nm, 50*nm
    lattice_length = 150*nm

    box_ff = ba.LongBoxLorentz(box_length, box_width, box_height)
    box = ba.Particle(si_mat, box_ff)
    box.rotate(ba.RotationZ(lattice_rotation_angle))

    # Particle layout
    layout = ba.Crystal1D(box, lattice_length,
                          90*deg - lattice_rotation_angle,
                          1/box_length)
    profile = ba.Profile1DGauss(450)
    layout.setDecayFunction(profile)

    sigma, hurst, corrLength = 5*nm, 0.5, 10*nm
    autocorr = ba.SelfAffineFractalModel(sigma, hurst, corrLength)
    transient = ba.TanhTransient()
    roughness = ba.Roughness(autocorr, transient)

    # Sample
    vacuum_layer = ba.Layer(vacuum)
    vacuum_layer.deposit2D(layout)
    substrate_layer = ba.Layer(si_mat, roughness)

    sample = ba.Sample()
    sample.addLayer(vacuum_layer)
    sample.addLayer(substrate_layer)
    return sample


def get_simulation(sample):
    beam = ba.Beam(1e8, 0.134*nm, 0.4*deg)
    n = 200
    detector = ba.SphericalDetector(n, -0.5*deg, 0.5*deg, n, 0, 0.5*deg)
    simulation = ba.ScatteringSimulation(beam, sample, detector)
    simulation.options().setMonteCarloIntegration(True, 100)
    return simulation


if __name__ == '__main__':
    sample = get_sample()
    ba.showSample3D(sample, sample_size=1500*nm, seed=0)
    simulation = get_simulation(sample)
    result = simulation.simulate()
    bp.plot_datafield(result, unit_aspect=1)
    bp.plt.show()
auto/Examples/scatter2d/RectangularGrating.py

Explanation

A one-dimensional lattice can be viewed as a chain of particles placed at regular intervals on a single axis. One use case is a grating, where very long boxes are placed at nodes of a 1D lattice.

See the BornAgain user manual (Chapter 3.4.1, One Dimensional Lattice) for details about the theory.

Crystal1D constructor

The structure is created with

structure = ba.Crystal1D(particle, length, xi, linear_density)

Arguments:

particle        # particle or Mixture placed at lattice sites
length          # lattice constant, in nanometers
xi              # rotation of the lattice with respect to x-axis, in radians
linear_density  # number of lattice lines per nanometer in the transverse axis

When the beam azimuthal angle $\varphi_f$ is zero, the beam direction coincides with x-axis. In this case, $\xi$ can be considered as the lattice rotation with respect to the beam.

Position variance

The position variance parameter allows uncertainty for each particle position around the lattice point by applying a corresponding Debye-Waller factor.

It can be set using the setLateralPositionVariance(value) method, where value is given in nm$^2$.

structure = ba.Crystal1D(particle, 100*nm, 0*deg, 1/box_length)
structure.setLateralPositionVariance(0.1)

By default the variance is set to zero.

Decay function

To account for finite size effects of the lattice, assign a decay function to the structure. This function encodes the loss of coherent scattering from lattice points with increasing distance between them. The origin of this loss of coherence could be attributed to the coherence length of the beam or to the domain structure of the lattice.

In the picture below a one-dimensional lattice is represented in real space as a probability density function for finding a particle at a given coordinate on the x-axis. In the presence of a decay function, this density can be given as $\sum F_{decay}(x)\cdot\delta(x-na)$.

The Fourier transform of this distribution $P(x)$ provides the scattering amplitude in reciprocal space. An exponential decay law in real space with the decay length $\lambda$ will give a Cauchy distribution with characteristic width $1/\lambda$ in reciprocal space, as shown below.

The decay function is assigned with setDecayFunction(decay):

structure = ba.Crystal1D(particle, 10*nm, 0*deg, 1/box_length)
structure.setDecayFunction(ba.Profile1DCauchy(1000*nm))

List of decay functions

BornAgain supports four types of one-dimensional decay functions.

  • Profile1DCauchy(decay_length): one-dimensional Cauchy decay function in reciprocal space, corresponding to $exp(-|x|/\lambda)$ in real space.
  • Profile1DGauss(decay_length): one-dimensional Gauss decay function in reciprocal space, corresponding to $exp(-x^2/(2*\lambda^2))$ in real space.
  • Profile1DTriangle(decay_length): one-dimensional triangle decay function in reciprocal space, corresponding to $1-|x|/\lambda$ if $|x|<\lambda$ in real space.
  • Profile1DVoigt(decay_length, eta): one-dimensional pseudo-Voigt decay function in reciprocal space, corresponding to $eta*Gauss + (1-eta)*Cauchy$.

The parameter $\lambda$ is given in nanometers and sets the characteristic length scale at which loss of coherence takes place. In the case of the pseudo-Voigt distribution, an additional dimensionless parameter eta balances between the Gaussian and Cauchy profiles.

Particle density

The linear_density constructor argument gives the number of lattice lines per nanometer in the direction transverse to the 1D lattice. For a grating made of long boxes, use the inverse box length.

Lattice rotation in detail

The rotation of the lattice does not change the orientation of the particles with respect to the beam direction. To rotate a grating as a physical object, rotate both the particle and the lattice direction.

For example:

box = ba.Particle(material, ba.Box(10*nm, 1000*nm, 10*nm))
box.rotate(ba.RotationZ(30*deg))

structure = ba.Crystal1D(box, 40*nm, 30*deg, 1/(1000*nm))
layer.deposit2D(structure)