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
|
#!/usr/bin/env python3
"""
Fitting example: looking for background.
Real data contains some "unknown" background.
In the fit we are trying to find cylinder radius and height and background.
"""
from matplotlib import pyplot as plt
import bornagain as ba
from bornagain import deg, nm, nm2
import lmfit
def get_sample(P):
"""
Uncorrelated cylinders on a substrate, parameterized for fitting.
"""
substrate_mat = ba.RefractiveMaterial(
"Substrate", (0.28, 0.57, 0.82), 6e-6, 2e-8)
particle_mat = ba.RefractiveMaterial(
"Particle", (0.86, 0.24, 0.18), 6e-4, 2e-8)
particle = ba.Particle(
particle_mat, ba.Cylinder(P["radius"], P["height"]))
particle_layer = ba.Layer(ba.Vacuum())
particle_layer.deposit2D(ba.Dilute2D(0.01/nm2, particle))
sample = ba.Sample()
sample.addLayer(particle_layer)
sample.addLayer(ba.Layer(substrate_mat))
return sample
def get_simulation(P):
"""
GISAS simulation for the parameterized cylinder sample.
"""
n = 100
beam = ba.Beam(1e8, 0.1*nm, 0.2*deg)
detector = ba.SphericalDetector(n, -1*deg, 1*deg, n, 0, 2*deg)
simulation = ba.ScatteringSimulation(beam, get_sample(P), detector)
simulation.options().setUseAvgMaterials(False)
return simulation
def get_background_simulation(P):
"""
GISAS simulation with a fitted constant background.
"""
background = P["background"]
simulation = get_simulation(P)
simulation.setBackground(ba.ConstantBackground(background))
return simulation
def fake_data():
"""
Generate synthetic data with known cylinder dimensions and background.
"""
P = {
'radius': 5*nm,
'height': 10*nm,
'background': 1000
}
simulation = get_background_simulation(P)
result = simulation.simulate()
return result
if __name__ == '__main__':
data = fake_data()
flat_exp_values = data.intensities().ravel()
def residuals(P):
"""
Runs a simulation for given parameters P, and returns residuals
vector.
"""
sim_values = get_background_simulation(
P.valuesdict()).simulate().intensities()
flat_sim_values = sim_values.ravel()
return flat_exp_values - flat_sim_values
P = lmfit.Parameters()
P.add("radius", 5.*nm, vary=False)
P.add("height", 9.*nm, min=8.*nm, max=12.*nm)
P.add("background", 200, min=100, max=2000)
result = lmfit.minimize(residuals, P)
print(lmfit.fit_report(result))
finalP = result.params.valuesdict()
ba.showSample3D(get_sample(finalP), sample_size=120*nm, seed=0)
plt.show()
|