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
|
#!/usr/bin/env python3
"""
Fitting example: looking for background and scale factors.
Real data contains some "unknown" background and scale factor.
In the fit we are trying to find cylinder radius and height,
scale and background factors.
"""
import numpy as np
from matplotlib import pyplot as plt
import bornagain as ba
from bornagain import deg, angstrom, nm
def get_sample(params):
"""
Build the sample representing cylinders on top of substrate without interference.
"""
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):
"""
Create and return GISAXS simulation with beam and detector defined
"""
background = params["background"]
scale = params["scale"]
simulation = ba.GISASSimulation()
simulation.setDetectorParameters(100, -1*deg, 1*deg, 100, 0, 2*deg)
simulation.setBeamParameters(1*angstrom, 0.2*deg, 0)
simulation.beam().setIntensity(1e12*scale)
simulation.setBackground(ba.ConstantBackground(background))
simulation.setSample(get_sample(params))
return simulation
def create_real_data():
"""
Generating "real" data by adding noise, background and scale
to the simulated data.
Cylinder radius is set to 5nm, cylinder height to 10nm.
During the fit we will try to find cylinder height and radius and
scale, background factors.
"""
params = {
'radius': 5*nm,
'height': 10*nm,
'scale': 2,
'background': 1000
}
simulation = get_simulation(params)
simulation.runSimulation()
# retrieving simulated data in the form of numpy array
return simulation.result().array()
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)
params = ba.Parameters()
params.add("radius", 5.*nm, vary=False)
params.add("height", 9.*nm, min=8.*nm, max=12.*nm)
params.add("scale", 1.5, min=1, max=3)
params.add("background", 200, min=100, max=2000, step=100)
minimizer = ba.Minimizer()
result = minimizer.minimize(fit_objective.evaluate, params)
fit_objective.finalize(result)
if __name__ == '__main__':
run_fitting()
plt.show()
|