|
| 1 | +.. _Resample Example: |
| 2 | + |
| 3 | +:tocdepth: 2 |
| 4 | + |
| 5 | +Resampling Example |
| 6 | +################## |
| 7 | + |
| 8 | +This example will demonstrate how we can use diffpy.utils functions to resample a function on a denser grid. |
| 9 | +Specifically, we will resample the grid of one function to match another for us to easily compare the two. |
| 10 | +Then we will show how this resampling method lets us create a perfect reconstruction of certain functions |
| 11 | +given enough datapoints. |
| 12 | + |
| 13 | +1) To start, unzip :download:`parserdata<./exampledata/parserdata.zip>`. Then, load the data table from ``Nickel.gr`` |
| 14 | + and ``NiTarget.gr``. These datasets are based on data from `Atomic Pair Distribution Function Analysis: A Primer |
| 15 | + <https://global.oup.com/academic/product/atomic-pair-distribution-function-analysis-9780198885801?cc=us&lang=en&>`_. |
| 16 | + :: |
| 17 | + |
| 18 | + from diffpy.utils.parsers import loadData |
| 19 | + nickel_datatable = loadData('<PATH to Nickel.gr>') |
| 20 | + nitarget_datatable = loadData('<PATH to NiTarget.gr>') |
| 21 | + |
| 22 | + Each data table has two columns: first is the grid and second is the function value. |
| 23 | + To extract the columns, we can utilize the serialize function ... :: |
| 24 | + |
| 25 | + from diffpy.utils.parsers import serialize_data |
| 26 | + nickel_data = serialize_data('Nickel.gr', {}, nickel_datatable, dt_colnames=['grid', 'func']) |
| 27 | + nickel_grid = nickel_data['Nickel.gr']['grid'] |
| 28 | + nickel_func = nickel_data['Nickel.gr']['func'] |
| 29 | + target_data = serialize_data('NiTarget.gr', {}, nitarget_datatable, dt_colnames=['grid', 'function']) |
| 30 | + target_grid = nickel_data['Nickel.gr']['grid'] |
| 31 | + target_func = nickel_data['Nickel.gr']['func'] |
| 32 | + |
| 33 | + ... or you can use any other column extracting method you prefer. |
| 34 | + |
| 35 | +2) If we plot the two on top of each other :: |
| 36 | + |
| 37 | + import matplotlib.pyplot as plt |
| 38 | + plt.plot(target_grid, target_func, linewidth=3) |
| 39 | + plt.plot(nickel_grid, nickel_func, linewidth=1) |
| 40 | + |
| 41 | + they look pretty similar, but to truly see the difference, we should plot the difference between the two. |
| 42 | + We may want to run something like ... :: |
| 43 | + |
| 44 | + import numpy as np |
| 45 | + difference = np.subtract(target_func, nickel_func) |
| 46 | + |
| 47 | + ... but this will only produce the right result if the ``target_func`` and ``nickel_func`` are on the same grid. |
| 48 | + Checking the lengths of ``target_grid`` and ``nickel_grid`` shows that these grids are clearly distinct. |
| 49 | + |
| 50 | +3) However, we can resample the two functions to be on the same grid. Since both functions have grids spanning |
| 51 | + ``[0, 60]``, let us define a new grid ... :: |
| 52 | + |
| 53 | + grid = np.linspace(0, 60, 6001) |
| 54 | + |
| 55 | + ... and use the diffpy.utils ``wsinterp`` function to resample on this grid.:: |
| 56 | + |
| 57 | + from diffpy.utils.parsers import wsinterp |
| 58 | + nickel_resample = wsinterp(grid, nickel_grid, nickel_func) |
| 59 | + target_resample = wsinterp(grid, target_grid, target_func) |
| 60 | + |
| 61 | + We can now plot the difference to see that these two functions are in fact equal.: |
| 62 | + |
| 63 | + plt.plot(grid, target_resample - nickel_resample) |
| 64 | + |
| 65 | + This is the desired result as the data in ``Nickel.gr`` is every tenth data point in ``NiTarget.gr``. |
| 66 | + This also shows us that ``wsinterp`` can help us reconstruct a function from incomplete data. |
| 67 | + |
| 68 | +4) In order for our function reconstruction to be perfect, we require that (a) the function is a Fourier transform of a |
| 69 | + band-limited dataset and (b) the original grid has enough equally-spaced datapoints based on the Nyquist sampling |
| 70 | + theorem. |
| 71 | + |
| 72 | + * If our function :math:`F(r)` is of the form :math:`F(r) = \int_0^{qmax} f(q)e^{-iqr}dq` where :math:`qmax` is |
| 73 | + the bandlimit, then for a grid spanning :math:`r \in [rmin, rmax]`, the Nyquist sampling theorem tells us we |
| 74 | + require at least :math:`qmax * (rmin - rmax) / \pi` equally-spaced datapoints. |
| 75 | + |
| 76 | + In the case of our dataset, our band-limit is ``qmax=25.0`` and our function spans :math:`r \in (0.0, 60.0)`. |
| 77 | + Thus, our original grid requires :math:`25.0 * 60.0 / \pi < 478`. Since our grid has :math:`601` datapoints, our |
| 78 | + reconstruction was perfect as shown from the comparison between ``Nickel.gr`` and ``NiTarget.gr``. |
0 commit comments