Fit cylinders and prisms

In this example we use a simple geometry: cylinders and prisms in air layer, deposited on a substrate layer, with no interference. There are 4 fitting parameters:

  1. radius of cylinders
  2. height of cylinders
  3. side length of prisms
  4. height of prisms

Our reference data are a “noisy” two-dimensional intensity map obtained from the simulation of the same geometry with a fixed value of 5nm for the height and radius of cylinders and for the height of prisms which have a 10-nanometer-long side length. Then we run our fitting using default minimizer settings starting with a cylinder’s height of 4nm, a cylinder’s radius of 6nm, a prism’s half side of 6nm and a height equal to 4nm. As a result, the fitting procedure is able to find the correct value of 5nm for all four parameters.

Intensity Image: 
Python Script: 
Fitting example: 4 parameters fit with simple output
import bornagain as ba
from bornagain import deg, angstrom, nm

def get_sample():
    Returns a sample with uncorrelated cylinders and prisms on a substrate.
    # defining materials
    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)

    # collection of particles
    cylinder_ff = ba.FormFactorCylinder(1.0*nm, 1.0*nm)
    cylinder = ba.Particle(m_particle, cylinder_ff)
    prism_ff = ba.FormFactorPrism3(1.0*nm, 1.0*nm)
    prism = ba.Particle(m_particle, prism_ff)
    particle_layout = ba.ParticleLayout()
    particle_layout.addParticle(cylinder, 0.5)
    particle_layout.addParticle(prism, 0.5)
    interference = ba.InterferenceFunctionNone()

    # air layer with particles and substrate form multi layer
    air_layer = ba.Layer(m_air)
    substrate_layer = ba.Layer(m_substrate, 0)
    multi_layer = ba.MultiLayer()
    return multi_layer

def get_simulation():
    Returns a 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 run_fitting():
    run fitting
    sample = get_sample()
    simulation = get_simulation()

    real_data = ba.IntensityDataIOFactory.readIntensityData(

    fit_suite = ba.FitSuite()
    fit_suite.addSimulationAndRealData(simulation, real_data)

    # setting fitting parameters with starting values
    fit_suite.addFitParameter("*Cylinder/Height", 4.*nm).setLowerLimited(0.01)
    fit_suite.addFitParameter("*Cylinder/Radius", 6.*nm).setLowerLimited(0.01)
    fit_suite.addFitParameter("*Prism3/Height", 4.*nm).setLowerLimited(0.01)
    fit_suite.addFitParameter("*Prism3/BaseEdge", 12.*nm).setLowerLimited(0.01)

    # running fit

    print("Fitting completed.")
    print("chi2:", fit_suite.getChi2())
    for par in fit_suite.fitParameters():
        print(, par.value(), par.error())

if __name__ == '__main__':