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
|
#!/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.
"""
from matplotlib import pyplot as plt
import bornagain as ba
from bornagain import ba_fitmonitor, deg, angstrom, nm
def get_sample(P):
"""
A sample with uncorrelated cylinders and pyramids on a substrate.
"""
radius = P["radius"]
height = P["height"]
vacuum = ba.RefractiveMaterial("Vacuum", 0, 0)
material_substrate = ba.RefractiveMaterial("Substrate", 6e-6, 2e-8)
material_particle = ba.RefractiveMaterial("Particle", 6e-4, 2e-8)
cylinder_ff = ba.Cylinder(radius, height)
cylinder = ba.Particle(material_particle, cylinder_ff)
layout = ba.ParticleLayout()
layout.addParticle(cylinder)
vacuum_layer = ba.Layer(vacuum)
vacuum_layer.addLayout(layout)
substrate_layer = ba.Layer(material_substrate, 0)
sample = ba.Sample()
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, 0., 2*deg, n, 0., 2*deg)
return ba.ScatteringSimulation(beam, get_sample(P), detector)
def fake_data():
"""
Generating "real" data by adding noise to the simulated data.
"""
P = {'radius': 5*nm, 'height': 5*nm}
simulation = get_simulation(P)
result = simulation.simulate()
return result.noisy(0.3, 0.5)
def run_fitting():
"""
main function to run fitting
"""
data = fake_data()
fit_objective = ba.FitObjective()
fit_objective.addFitPair(get_simulation, data, 1)
fit_objective.initPrint(30)
observer = ba_fitmonitor.PlotterGISAS()
fit_objective.initPlot(30, observer)
"""
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.
"""
P = ba.Parameters()
P.add("height", 1.*nm, min=0.01, max=30)
P.add("radius", 20.*nm, min=0.01, max=30)
"""
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=3;PopSize=500")
result = minimizer.minimize(fit_objective.evaluate, P)
fit_objective.finalize(result)
best_P_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",
"MaxFunctionCalls=0")
result = minimizer.minimize(fit_objective.evaluate, best_P_so_far)
fit_objective.finalize(result)
if __name__ == '__main__':
run_fitting()
plt.show()
|