## Fitting along slices

Here we demonstrate how to fit along slices. The idea is that the user defines the positions of vertical and horizontal lines crossing the detector plane in regions of most interest (Yoneda wings, Bragg peaks, etc.) and then finds the sample parameters which fits those regions best.

Such an approach uses much less CPU while still giving a chance to find the optimal sample parameters. In general, however, it is arguable whether fitting along slices makes more sense than fitting using the whole detector image.

Technically, the idea is to mask the whole detector except thin lines, one vertical and one horizontal, representing slices. This will make the simulation and the fitting procedure to calculate only along these indicated slices.

• In the given script we simulate a dilute random assembly of cylinders on a substrate. The fitting procedure looks for the cylinder’s height and radius.
• Function get_masked_simulation masks the entire detector except for a horizontal and a vertical stripe.
• The custom PlotObserver class, which plots the fit along the slices at every 10th fit iteration.
  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, angstrom, 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 create_real_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} # retrieving simulated data in the form of numpy array simulation = model.get_simulation(P) simulation.setBackground(ba.PoissonBackground()) result = simulation.simulate() return result.array() 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_real_data(data): """ Plot experimental data as heatmap with horizontal/vertical lines representing slices on top. """ plt.subplots_adjust(wspace=0.2, hspace=0.2) ba_plot.plot_histogram(data, title="Experimental 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() real_data = fit_objective.experimentalData().extracted_field() simul_data = fit_objective.simulationResult().extracted_field() # plot real data plt.subplot(2, 2, 1) self.plot_real_data(real_data) # horizontal slices slices = [("real", 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", 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 """ real_data = create_real_data() fit_objective = ba.FitObjective() fit_objective.addSimulationAndData(get_masked_simulation, real_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() 
auto/Examples/fit/scatter2d/fit_along_slices.py