## Minimizer settings

This example demonstrates how to change the minimizer algorithm and some of its settings. For example, the following lines

minimizer = ba.Minimizer()

print(ba.MinimizerFactory().catalogueDetailsToString())

  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 123 124 125 126 127 128 129  #!/usr/bin/env python3 """ Fitting example: running same fit using various minimizer and their settings. """ import bornagain as ba from bornagain import deg, angstrom, nm def get_sample(P): """ A sample with uncorrelated cylinders and prisms on a substrate. """ cylinder_height = P["cylinder_height"] cylinder_radius = P["cylinder_radius"] prism_height = P["prism_height"] prism_base_edge = P["prism_base_edge"] # defining materials vacuum = ba.RefractiveMaterial("Vacuum", 0, 0) material_substrate = ba.RefractiveMaterial("Substrate", 6e-6, 2e-8) material_particle = ba.RefractiveMaterial("Particle", 6e-4, 2e-8) # collection of particles cylinder_ff = ba.Cylinder(cylinder_radius, cylinder_height) cylinder = ba.Particle(material_particle, cylinder_ff) prism_ff = ba.Prism3(prism_base_edge, prism_height) prism = ba.Particle(material_particle, prism_ff) layout = ba.ParticleLayout() layout.addParticle(cylinder, 0.5) layout.addParticle(prism, 0.5) interference = ba.InterferenceNone() layout.setInterference(interference) # vacuum layer with particles and substrate form multilayer vacuum_layer = ba.Layer(vacuum) vacuum_layer.addLayout(layout) substrate_layer = ba.Layer(material_substrate, 0) sample = ba.MultiLayer() sample.addLayer(vacuum_layer) sample.addLayer(substrate_layer) return sample def get_simulation(P): """ A GISAXS simulation with beam and detector defined """ beam = ba.Beam(1e8, 1*angstrom, 0.2*deg) n = 100 # bp.simargs['n'] detector = ba.SphericalDetector(n, -1*deg, 1*deg, n, 0, 2*deg) return ba.ScatteringSimulation(beam, get_sample(P), detector) def fake_data(): """ Generating "real" data from simulated image with default parameters. """ P = { 'cylinder_height': 5*nm, 'cylinder_radius': 5*nm, 'prism_height': 5*nm, 'prism_base_edge': 5*nm } simulation = get_simulation(P) result = simulation.simulate() return result def run_fitting(): """ main function to run fitting """ data = fake_data() # prints info about available minimizers print(ba.MinimizerFactory().catalogToString()) # prints detailed info about available minimizers and their options print(ba.MinimizerFactory().catalogDetailsToString()) fit_objective = ba.FitObjective() fit_objective.addFitPair(get_simulation, data, 1) fit_objective.initPrint(10) P = ba.Parameters() P.add("cylinder_height", 4.*nm, min=0.01) P.add("cylinder_radius", 6.*nm, min=0.01) P.add("prism_height", 4.*nm, min=0.01) P.add("prism_base_edge", 12.*nm, min=0.01) minimizer = ba.Minimizer() # Uncomment one of the line below to adjust minimizer settings """ Setting Minuit2 minimizer with Migrad algorithm, limiting number of iterations. Minimization will try to respect MaxFunctionCalls value. """ # minimizer.setMinimizer("Minuit2", "Migrad", "MaxFunctionCalls=50") """ Setting two options at once. Strategy=2 promises more accurate fit. """ # minimizer.setMinimizer("Minuit2", "Migrad", "MaxFunctionCalls=500;Strategy=2") """ Setting Minuit2 minimizer with Fumili algorithm. """ # minimizer.setMinimizer("Minuit2", "Fumili") """ Setting Levenberg-Marquardt algorithm. """ # minimizer.setMinimizer("GSLLMA") result = minimizer.minimize(fit_objective.evaluate_residuals, P) fit_objective.finalize(result) print("Fitting completed.") print("chi2:", result.minValue()) for fitPar in result.parameters(): print(fitPar.name(), fitPar.value, fitPar.error) if __name__ == '__main__': run_fitting()