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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
#!/usr/bin/env python3
"""
Fitting example: fit along slices
"""
from matplotlib import pyplot as plt
import bornagain as ba
from bornagain import deg, nm, ba_plot
import model1_cylinders as model
phi_slice_value = 0.0 # position of vertical slice in deg
alpha_slice_value = 0.2 # position of horizontal slice in deg
def get_masked_simulation(P):
"""
Create and return GISAXS simulation with beam and detector defined
"""
simulation = model.get_simulation(P)
"""
At this point we mask all the detector and then unmask two areas
corresponding to the vertical and horizontal lines. This will make
simulation/fitting to be performed along slices only.
"""
simulation.detector().maskAll()
simulation.detector().addMask(ba.HorizontalLine(alpha_slice_value*deg), False)
simulation.detector().addMask(ba.VerticalLine(phi_slice_value*deg), False)
return simulation
def fake_data():
"""
Generating "real" data by adding noise to the simulated data.
"""
# initial values which we will have to find later during the fit
P = {'radius': 5*nm, 'height': 10*nm}
simulation = model.get_simulation(P)
simulation.setBackground(ba.PoissonBackground())
result = simulation.simulate()
return result.noisy(0.1, 0.1)
class PlotObserver:
"""
Draws fit progress every nth iteration. Here we plot slices along real
and simulated images to see fit progress.
"""
def __init__(self):
self.fig = plt.figure(figsize=(10.25, 7.69))
self.fig.canvas.draw()
def __call__(self, fit_objective):
self.update(fit_objective)
@staticmethod
def plot_data(data):
"""
Plot experimental data as heatmap with horizontal/vertical lines
representing slices on top.
"""
plt.subplots_adjust(wspace=0.2, hspace=0.2)
data.setTitle("Experimental data")
ba_plot.plot_simulation_result(data)
# line representing vertical slice
plt.plot([phi_slice_value, phi_slice_value],
[data.yAxis().min(), data.yAxis().max()],
color='gray',
linestyle='-',
linewidth=1)
# line representing horizontal slice
plt.plot([data.xAxis().min(), data.xAxis().max()],
[alpha_slice_value, alpha_slice_value],
color='gray',
linestyle='-',
linewidth=1)
@staticmethod
def plot_slices(slices, title):
"""
Plots vertical and horizontal projections.
"""
plt.subplots_adjust(wspace=0.2, hspace=0.3)
plt.yscale('log')
for label, slice in slices:
plt.plot(slice.xAxis().binCenters(), slice.flatVector(), label=label)
plt.xlim(slice.xAxis().min(), slice.xAxis().max())
plt.ylim(1, slice.maxVal()*10)
plt.legend(loc='upper right')
plt.title(title)
@staticmethod
def display_fit_parameters(fit_objective):
"""
Displays fit parameters, chi and iteration number.
"""
plt.title('Parameters')
plt.axis('off')
iteration_info = fit_objective.iterationInfo()
plt.text(
0.01, 0.85, "Iterations " +
'{:d}'.format(iteration_info.iterationCount()))
plt.text(0.01, 0.75,
"Chi2 " + '{:8.4f}'.format(iteration_info.chi2()))
for index, P in enumerate(iteration_info.parameters()):
plt.text(
0.01, 0.55 - index*0.1,
'{:30.30s}: {:6.3f}'.format(P.name(), P.value))
plt.tight_layout()
plt.draw()
plt.pause(0.01)
def update(self, fit_objective):
"""
Callback to access fit_objective on every n'th iteration.
"""
self.fig.clf()
data = fit_objective.experimentalData()
simul_data = fit_objective.simulationResult()
# plot real data
plt.subplot(2, 2, 1)
self.plot_data(data)
# horizontal slices
slices = [("real", data.xProjection(alpha_slice_value)),
("simul", simul_data.xProjection(alpha_slice_value))]
title = ("Horizontal slice at alpha =" +
'{:3.1f}'.format(alpha_slice_value))
plt.subplot(2, 2, 2)
self.plot_slices(slices, title)
# vertical slices
slices = [("real", data.yProjection(phi_slice_value)),
("simul", simul_data.yProjection(phi_slice_value))]
title = "Vertical slice at phi =" + '{:3.1f}'.format(
phi_slice_value)
plt.subplot(2, 2, 3)
self.plot_slices(slices, title)
# display fit parameters
plt.subplot(2, 2, 4)
self.display_fit_parameters(fit_objective)
def run_fitting():
"""
main function to run fitting
"""
data = fake_data()
fit_objective = ba.FitObjective()
fit_objective.addFitPair(get_masked_simulation, data, 1)
fit_objective.initPrint(10)
# creating custom observer which will draw fit progress
plotter = PlotObserver()
fit_objective.initPlot(10, plotter)
P = ba.Parameters()
P.add("radius", 6.*nm, min=4, max=8)
P.add("height", 9.*nm, min=8, max=12)
minimizer = ba.Minimizer()
result = minimizer.minimize(fit_objective.evaluate, P)
fit_objective.finalize(result)
if __name__ == '__main__':
run_fitting()
plt.show()
|