Optimizer - cavity
[1]:
import nexus as nx
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
# ------------------------- layers --------------------------
lay_Fe = nx.Layer(id = "Fe",
material = nx.Material.Template(nx.lib.material.Fe_enriched),
thickness = 2)
lay_B4C = nx.Layer(id = "B4C",
material = nx.Material.Template(nx.lib.material.B4C),
thickness = 15)
lay_Pt_bottom = nx.Layer(id = "Pt bottom",
material = nx.Material.Template(nx.lib.material.Pt),
thickness = 15)
# the inital guess for the top layer is 3nm here
# set it to a Var object
lay_Pt_top = nx.Layer(id = "Pt top",
material = nx.Material.Template(nx.lib.material.Pt),
thickness = nx.Var(3, min = 0, max = 10, fit = True, id = "Pt top thickness"))
lay_substrate = nx.Layer(id = "substrate",
material = nx.Material.Template(nx.lib.material.Si),
thickness = nx.inf)
sample = nx.Sample(id = "cavity",
geometry = "r",
layers = [lay_Pt_top,
lay_B4C,
lay_Fe,
lay_B4C,
lay_Pt_bottom,
lay_substrate])
beam = nx.Beam()
beam.LinearSigma()
exp = nx.Experiment(beam = beam,
objects = sample,
id = "my exp")
# initialize a reflectivity object used for the optimization
angles = np.linspace(0.01, 0.4, 1001)
reflectivity = nx.Reflectivity(experiment = exp,
sample = sample,
energy = nx.lib.energy.Fe57,
angles = angles)
intensity = reflectivity()
plt.semilogy(angles, intensity)
plt.xlabel('angle (deg)')
plt.ylabel('reflectivity')
plt.show()
[2]:
# setup the optimizer
class NexusOptimizer(nx.Optimizer):
def __init__(self, measurements, id):
super().__init__(measurements, id)
def Residual(self):
# calculate the reflectivity
intensity = reflectivity()
# get the index of the first minimum
if (len(find_peaks(-intensity)[0]) < 1):
return 1e30 # return large punish value
min_index = find_peaks(-intensity)[0][0]
# optimize for the intensity at the first minimum position
# actually this is intensity[min_index] - 0 again because the intensity should be minimal
residual = intensity[min_index]
return residual
# pass the reflectivity object to the optimizer
opt = NexusOptimizer(measurements = [reflectivity],
id = "opt id")
# we use a local gradient-free algorithm here
opt.options.method = "Subplex"
# run the optimization
opt()
plt.semilogy(angles, reflectivity.result)
plt.xlabel('angle (deg)')
plt.ylabel('reflectivity')
plt.show()
Run Optimizer instance with id: opt id
Starting optimizer with 1 provided measurement dependencies and 1 fit parameter(s):
no. | id | initial value | min | max
0 | Pt top thickness | 3 | 0 | 10
Using 0 equality constraint(s) on parameter(s):
Using 0 inequality constraint(s).
Residual start value: 0.143937
Calling NLopt solver with fit method Subplex
Termination: parameter tolerance reached.
cost = 2.922241e-04
iterations: 50
Optimizer finished with 1 fit parameter(s):
no. | id | fit value | initial value | min | max
0 | Pt top thickness | 2.06487 | 3 | 0 | 10
and 0 equality constraint(s) on parameter(s):
and 0 inequality constraint(s).
Optimized residual from 0.143937 to 0.0241754
Optimizer instance finished. id:opt id