{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Analysis of multiple cakes\n", "\n", "## 2.1. Averaging cakes for a better fit\n", "\n", "#### Import required libraries" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "from xrdfit.spectrum_fitting import PeakParams, FitSpectrum" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Sometimes setting the figsize in the first cell doesn't work so this call is in a second cell.\n", "import matplotlib\n", "matplotlib.rcParams['figure.figsize'] = [8, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it may be desirable or necessary to average the data from multiple cakes to improve the signal to noise ratio. `xrdfit` has a simple interface to achieve this.\n", "\n", "To start, we load a data file in the same way as before:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data = FitSpectrum('../example_data/adc_041_7Nb_NDload_700C_15mms_00001.dat', 90)\n", "spectral_data.plot_polar()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.1 Adding together cake intensities\n", "\n", "We can plot the spectrum of multiple cakes on the same plot by providing a list of the desired cake numbers." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data.plot([36, 1, 2], x_range=(2, 8))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to improve the quality of the analysed dataset we may want to sum multiple adjacent cakes to smooth the signal. This will increase the peak height but will also increase the noise floor.\n", "\n", "We can do this by specifying the `merge_cakes` parameter and the intensities of the specified cakes will be summed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data.plot([36, 1, 2], merge_cakes=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice how the intensity compares to the unmerged cakes above - it is the sum of all of the cakes.\n", "\n", "Since it is not always easy to visualise which cake number refers to which cake, there is a helper method `highlight_cakes` which will plot a schematic of the diffraction pattern, highlighting which cakes have been selected." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data.highlight_cakes([36, 1, 2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that it is not necessary to only fit adjacent cakes, any combination may be chosen. Which cakes you choose to fit wil depend on having an understanding of the underlying mechanism of the scattering and the experimental setup.\n", "\n", "Fitting peaks in merged cakes requires specifying multiple cakes in the fit method but otherwise is the same syntax as fitting a single cake ." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "peak_params = [PeakParams((2.75, 2.95), '1'), \n", " PeakParams((3.02, 3.15), '2'), \n", " PeakParams((3.15, 3.30), ['3', '4'], [(3.19, 3.22,), (3.24, 3.26)]),\n", " PeakParams((4.13, 4.30), '5')]\n", "\n", "spectral_data.fit_peaks(peak_params, [36, 1, 2], merge_cakes=True)\n", "\n", "for fit in spectral_data.fitted_peaks:\n", " fit.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.2 Fitting multiple unmerged cakes\n", "\n", "If we select multiple cakes but choose not to merge the cakes then the fit will use all of the individual data points to weight the fit. This means that all of the cakes are plotted separately and the fit attempts to find a middle ground between them. It is not clear whether this produces equivalent fits to merging the cakes. However, this feature may give better results for data sets containing sharp peaks that are poorly resolved by the 2-theta spacing, where the peak shape is defined only by a couple of points." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data.fit_peaks(peak_params, [36, 1, 2], merge_cakes=False)\n", "\n", "for fit in spectral_data.fitted_peaks:\n", " fit.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Whether averaging is useful will depend on the nature of your data. If you have a spherically symmetric diffraction pattern or a pattern with large homogeneous regions then averaging can reduce the effect of noise. However, if the underlying diffraction pattern is not spherically symmetric and is relatively well resolved than averaging can result in a blurring of the signal.\n", "\n", "## 2.2. Fitting multiple cakes separately\n", "\n", "\n", "It may be the case that you want to fit multiple cakes in the same spectrum separately. `xrdfit` does not have a method to do this directly but it is easy to do with a Python loop." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spectral_data = FitSpectrum('../example_data/adc_041_7Nb_NDload_700C_15mms_00001.dat', 90)\n", "\n", "peak_params = [PeakParams((2.75, 2.95), '1'), \n", " PeakParams((3.02, 3.15), '2'), \n", " PeakParams((3.15, 3.30), ['3', '4'], [(3.19, 3.22,), (3.24, 3.26)]),\n", " PeakParams((4.13, 4.30), '5')]\n", "\n", "fitted_cakes = []\n", "cakes_to_fit = [1, 2, 3, 4, 5]\n", "\n", "for cake_number in cakes_to_fit:\n", " spectral_data.fit_peaks(peak_params, cake_number)\n", " fitted_cakes.append(spectral_data.fitted_peaks)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have to extract the fitted peaks from the `FitSpectrum` object each fit because the default behaviour is to overwrite `FitSpectrum.fitted_peaks` each time the `fit_peaks` method is run. This is done so that when the user is iterating the `PeakParams` to get the best fit, there isn't a large number of similar but different fits.\n", "\n", "The above code has generated the list *fitted_cakes* which is a list of list of PeakFits, the first list dimension is cake number, the second is the peak number.\n", "\n", "To plot the first peak in each cake would then be:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for cake_spectrum in fitted_cakes:\n", " cake_spectrum[0].plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the cake number is given in the legend but this doesnt do much to distinguish the plots. We can supply the optional *title* parameter to the plot method to override the default title:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for cake_number, cake_spectrum in enumerate(fitted_cakes):\n", " cake_spectrum[0].plot(title=f\"Peak 1 for cake {cake_number + 1}\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" }, "pycharm": { "stem_cell": { "cell_type": "raw", "metadata": { "collapsed": false }, "source": [] } } }, "nbformat": 4, "nbformat_minor": 2 }