## Consecutive fitting

This example demonstrates how to run two fits one after the other using different minimizer settings and starting values of the fit parameters.

• In this example we are looking for the radius and height of cylindrical nano particles randomly distributed on a surface.
• During the first (started at line 101) fit we are setting the initial values of the fit parameters to be quite far from the expected values and use a genetic minimizer to explore a large parameter space.
• The second fit at line 112 starts from the best parameter values found in the previous step and uses one of the gradient descent algorithms to find the precise location of the minimum.
  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  #!/usr/bin/env python3 """ Fitting example: running one fit after another using different minimizers. During the first fit Genetic minimizer will be used to scan large parameter space and roughly find local minimum. The second Minuit2 minimizer will continue after that to find precise minimum location. """ import numpy as np from matplotlib import pyplot as plt import bornagain as ba from bornagain import deg, angstrom, nm def get_sample(params): """ Returns a sample with uncorrelated cylinders and pyramids on a substrate. """ radius = params["radius"] height = params["height"] m_vacuum = ba.HomogeneousMaterial("Vacuum", 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) layout = ba.ParticleLayout() layout.addParticle(cylinder) vacuum_layer = ba.Layer(m_vacuum) vacuum_layer.addLayout(layout) substrate_layer = ba.Layer(m_substrate, 0) multi_layer = ba.MultiLayer() multi_layer.addLayer(vacuum_layer) multi_layer.addLayer(substrate_layer) return multi_layer def get_simulation(params): """ Returns a GISAXS simulation with beam and detector defined. """ simulation = ba.GISASSimulation() simulation.setDetectorParameters(100, 0, 2*deg, 100, 0, 2*deg) simulation.setBeamParameters(1*angstrom, 0.2*deg, 0) simulation.beam().setIntensity(1e+08) simulation.setSample(get_sample(params)) return simulation def create_real_data(): """ Generating "real" data by adding noise to the simulated data. """ params = {'radius': 5*nm, 'height': 5*nm} simulation = get_simulation(params) simulation.runSimulation() # retrieving simulated data in the form of numpy array real_data = simulation.result().array() # spoiling simulated data with the noise to produce "real" data noise_factor = 0.1 noisy = np.random.normal(real_data, noise_factor*np.sqrt(real_data)) noisy[noisy < 0.1] = 0.1 return noisy def run_fitting(): """ main function to run fitting """ real_data = create_real_data() fit_objective = ba.FitObjective() fit_objective.addSimulationAndData(get_simulation, real_data, 1) fit_objective.initPrint(10) fit_objective.initPlot(10) """ Setting fitting parameters with starting values. Here we select starting values being quite far from true values to puzzle our minimizer's as much as possible. """ params = ba.Parameters() params.add("height", 1.*nm, min=0.01, max=30, step=0.05*nm) params.add("radius", 20.*nm, min=0.01, max=30, step=0.05*nm) """ Now we run first minimization round using the Genetic minimizer. The Genetic minimizer is able to explore large parameter space without being trapped by some local minimum. """ minimizer = ba.Minimizer() minimizer.setMinimizer("Genetic", "", "MaxIterations=2;RandomSeed=1") result = minimizer.minimize(fit_objective.evaluate, params) fit_objective.finalize(result) best_params_so_far = result.parameters() """ Second fit will use another minimizer. It starts from best parameters found in previous minimization and then continues until fit converges. """ minimizer.setMinimizer("Minuit2", "Migrad") result = minimizer.minimize(fit_objective.evaluate, best_params_so_far) fit_objective.finalize(result) if __name__ == '__main__': run_fitting() plt.show() 
consecutive_fitting.py