Skip to content

Commit b5d2c6d

Browse files
committed
Add tutorial for resampling function
1 parent 47d53b8 commit b5d2c6d

File tree

4 files changed

+81
-1
lines changed

4 files changed

+81
-1
lines changed
40.8 KB
Binary file not shown.

doc/manual/source/examples/examples.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Landing page for diffpy.utils examples.
88

99
.. toctree::
1010
parsersexample
11+
resampleexample
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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``.

doc/manual/source/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ diffpy.utils - general purpose shared utilities for the diffpy libraries.
99
1010
The diffpy.utils package provides general functions for extracting data from variously formatted text files as well as
1111
some PDF-specific functionality. These include wx GUI utilities used by the PDFgui program and an interpolation function
12-
based on the Whittaker-Shannon formula for upsampling/downsampling a bandlimited PDF or other profile function.
12+
based on the Whittaker-Shannon formula for resampling a bandlimited PDF or other profile function.
1313

1414
========
1515
Examples
1616
========
1717
Illustrations of when and how one would use various diffpy.utils functions.
1818

1919
* :ref:`File Data Extraction<Parsers Example>`
20+
* :ref:`Resampling & Data Reconstruction<Resample Example>`
2021

2122
=======
2223
Authors

0 commit comments

Comments
 (0)