Fitting along slices
Here we demonstrate how to fit along slices. The idea is that the user defines positions of vertical and horizontal lines crossing the detector plane in regions of most interest (Yoneda wings, Bragg peaks, etc) and then finds sample parameters which fits those regions best.
Such approach uses much less CPU while still giving a chance to find optimal sample parameters. In general, however, it is arguable, whether fitting along slices makes more sence than fitting using the whole detector image. Without going into this discussion we just provide such possibility.
Technically, the idea is to mask the whole detector except thin lines, one vertical and one horizontal, representing slices. This will make the simulation and fitting to calculate only along the indicated slices.
- In the given example we simulate cylinders on top of substrate without interference. The fitting procedure looks for the cylinder's height and radius.
- Lines 187, 188, 189 demonstrate the whole code you need to mask the whole detector and then unmask two slices: vertical line at phi=0.0, and horizontal line at alpha=0.2deg.
- The majority of the code is located in custom DrawObserver class (defined at Line 77, and invoked at Lines 195,196), which plots the fit progress along slices every 5th iteration.
""" Fitting example: fit along slices """ from __future__ import print_function import matplotlib from matplotlib import pyplot as plt import math import random import bornagain as ba from bornagain import deg, angstrom, nm import numpy phi_slice_value = 0.0*deg # position of vertical slice alpha_slice_value = 0.2*deg # position of horizontal slice def get_sample(radius=5*nm, height=10*nm): """ Returns a sample with uncorrelated cylinders on a substrate. """ m_air = ba.HomogeneousMaterial("Air", 0.0, 0.0) m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) cylinder_ff = ba.FormFactorCylinder(radius, height) cylinder = ba.Particle(m_particle, cylinder_ff) particle_layout = ba.ParticleLayout() particle_layout.addParticle(cylinder) air_layer = ba.Layer(m_air) air_layer.addLayout(particle_layout) substrate_layer = ba.Layer(m_substrate, 0) multi_layer = ba.MultiLayer() multi_layer.addLayer(air_layer) multi_layer.addLayer(substrate_layer) return multi_layer def get_simulation(): """ Create and return GISAXS simulation with beam and detector defined """ simulation = ba.GISASSimulation() simulation.setDetectorParameters(100, -1.0*deg, 1.0*deg, 100, 0.0*deg, 2.0*deg) simulation.setBeamParameters(1.0*angstrom, 0.2*deg, 0.0*deg) return simulation def create_real_data(): """ Generating "real" data by adding noise to the simulated data. """ sample = get_sample(5.0*nm, 10.0*nm) simulation = get_simulation() simulation.setSample(sample) simulation.runSimulation() real_data = simulation.getIntensityData() # spoiling simulated data with the noise to produce "real" data noise_factor = 1.0 for i in range(0, real_data.getTotalNumberOfBins()): amplitude = real_data.getBinContent(i) sigma = noise_factor*math.sqrt(amplitude) noisy_amplitude = random.gauss(amplitude, sigma) if noisy_amplitude