### Beam divergence in specular simulations

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

In application to specular simulation, the observed intensity picture can be affected by divergence either in beam wavelength or incident angle.

In this example the following parameters related to the beam divergence 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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122  """ Example of taking into account beam divergence effects in specular simulations with BornAgain. """ 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, 0.0) m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0.0) m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0.0) m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0.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(divergent_beam): """ Defines and returns a specular simulation. """ # simulation parameters definition wavelength = 1.54 * angstrom n_bins = 500 alpha_min = 0.0 * deg alpha_max = 2.0 * deg simulation = ba.SpecularSimulation() simulation.setBeamParameters( wavelength, n_bins, alpha_min, alpha_max) # adding beam divergence if divergent_beam is True: add_beam_divergence(simulation, wavelength) return simulation def add_beam_divergence(simulation, wavelength): """ Adds beam divergence to the simulation """ # beam divergence 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 standard deviations to take into account n_points = 25 # number of points to take in parameter distribution # creating beam parameter distributions alpha_distr = ba.DistributionGaussian(0.0, d_ang) wavelength_distr = ba.DistributionGaussian(wavelength, d_wl) # adding distributions to the simulation simulation.addParameterDistribution("*/Beam/InclinationAngle", alpha_distr, n_points, n_sig) simulation.addParameterDistribution("*/Beam/Wavelength", wavelength_distr, n_points, n_sig) def run_simulation(divergent_beam): """ Runs simulation and returns its result. """ sample = get_sample() simulation = get_simulation(divergent_beam) simulation.setSample(sample) simulation.runSimulation() return simulation.result() def get_plot_data(sim_result): data = sim_result.data() intensity = data.getArray() x_axis = data.getAxis(0).getBinCenters() return x_axis, intensity def plot(sim_result_1, sim_result_2): """ Plots results from two different simulations """ plt.semilogy(*get_plot_data(sim_result_1), *get_plot_data(sim_result_2)) plt.xlabel(r'$\alpha_i \; (deg)$', fontsize=16) plt.ylabel(r'Intensity', fontsize=16) plt.legend(['Divergent beam', 'Ideal beam'], loc='upper right') plt.show() if __name__ == '__main__': result_div_beam = run_simulation(divergent_beam=True) result_ideal_beam = run_simulation(divergent_beam=False) plot(result_div_beam, result_ideal_beam) 
BeamDivergence.py