Skip to content

Commit 4910a65

Browse files
committed
chore: resolve merge conflicts
2 parents bfc9186 + f5fc9ac commit 4910a65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+857
-334
lines changed

CITATION.cff

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
cff-version: 1.2.0
2+
title: diffpy.morph
3+
message: >-
4+
If you use this software, please cite the manuscript
5+
associated with this repository (will be included here
6+
when published).
7+
type: software
8+
authors:
9+
- given-names: Andrew
10+
family-names: Yang
11+
email: ayang2@caltech.edu
12+
affiliation: Caltech
13+
orcid: "https://orcid.org/0000-0003-0553-715X"
14+
- given-names: Christopher
15+
family-names: Farrow
16+
orcid: "https://orcid.org/0000-0001-5768-6654"
17+
- given-names: Chia-Hao
18+
family-names: Liu
19+
affiliation: Columbia University
20+
orcid: "https://orcid.org/0000-0002-3216-0354"
21+
- given-names: Luis
22+
family-names: Kitsu
23+
orcid: "https://orcid.org/0000-0002-9292-4416"
24+
affiliation: University of Colorado Boulder
25+
email: Luis.Kitsu@echemes.ethz.ch
26+
- given-names: Simon
27+
family-names: Billinge
28+
email: sb2896@columbia.edu
29+
affiliation: Columbia University
30+
orcid: "https://orcid.org/0000-0002-9734-4998"
31+
abstract: >-
32+
diffpy.morph is an open-source and free-to-use Python
33+
package that increases the insight researchers can obtain
34+
when comparing experimentally measured 1D functions such
35+
as diffraction patterns and atomic distribution functions
36+
(PDFs). For example, it is often difficult to identify
37+
whether or not structural changes have occurred between
38+
two diffraction patterns or PDFs of the same material
39+
measured at different temperatures due to the presence of
40+
benign thermal effects such as lattice expansion and
41+
increased atomic motion. These contribute large signals in
42+
the difference curves and Rw factors when comparing two
43+
curves, which can hide small but significant structural
44+
changes. diffpy.morph does its best to correct for these
45+
benign effects by applying simple transformations, or
46+
“morphs”, to a diffraction pattern or PDF prior to
47+
comparison. Other morphs are also possible such as
48+
corrections for nanoparticle shape effects on the PDF.
49+
diffpy.morph is model-independent and also could be used
50+
on other non-diffraction spectra, though it has not been
51+
extensively tested beyond powder diffraction patterns
52+
and the PDF.
53+
keywords:
54+
- diffpy
55+
- pdf
56+
- data interpretation
57+
license: BSD-3-Clause

README.rst

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,35 @@
3535
.. |Tracking| image:: https://img.shields.io/badge/issue_tracking-github-blue
3636
:target: https://github.com/diffpy/diffpy.morph/issues
3737

38-
Python package for manipulating and comparing PDF profiles
38+
Python package for manipulating and comparing diffraction data
3939

4040
``diffpy.morph`` is a Python software package designed to increase the insight
41-
researchers can obtain from measured atomic pair distribution functions
41+
researchers can obtain from measured diffraction data
42+
and atomic pair distribution functions
4243
(PDFs) in a model-independent way. The program was designed to help a
4344
researcher answer the question: "Has my material undergone a phase
4445
transition between these two measurements?"
4546

46-
One approach is to compare the two PDFs in a plot and view the difference
47-
curve underneath. However, significant signal can be seen in the
48-
difference curve from benign effects such as thermal expansion (peak
49-
shifts) and increased thermal motion (peak broadening) or a change in
47+
One approach is to compare the two diffraction patterns in a plot
48+
and view the difference curve underneath. However, significant signal can
49+
be seen in the difference curve from benign effects such as thermal expansion
50+
(peak shifts) and increased thermal motion (peak broadening) or a change in
5051
scale due to differences in incident flux, for example. ``diffpy.morph`` will
5152
do its best to correct for these benign effects before computing and
52-
plotting the difference curve. One measured PDF (typically that collected
53-
at higher temperature) is identified as the target PDF and the second
54-
PDF is then morphed by "stretching" (changing the r-axis to simulate a
53+
plotting the difference curve. One measured function (typically that collected
54+
at higher temperature) is identified as the target function and the second
55+
function is then morphed by "stretching" (changing the r-axis to simulate a
5556
uniform lattice expansion), "smearing" (broadening peaks through a
5657
uniform convolution to simulate increased thermal motion), and "scaling"
5758
(self-explanatory). ``diffpy.morph`` will vary the amplitude of the morphing
5859
transformations to obtain the best fit between the morphed and the target
59-
PDFs, then plot them on top of each other with the difference plotted
60+
functions, then plot them on top of each other with the difference plotted
6061
below.
6162

6263
There are also a few other morphing transformations in the program.
6364

64-
Finally, we note that ``diffpy.morph`` should work on other spectra that are not
65-
PDFs, though it has not been extensively tested beyond the PDF.
65+
Finally, we note that ``diffpy.morph`` should work on other spectra,
66+
though it has not been extensively tested beyond spectral data and the PDF.
6667

6768

6869
For more information about the diffpy.morph library, please consult our `online documentation <https://diffpy.github.io/diffpy.morph>`_.
@@ -153,9 +154,9 @@ If installed correctly, this last command should return the version
153154
of ``diffpy.morph`` that you have installed on your system. To begin using
154155
``diffpy.morph``, run a command like ::
155156

156-
diffpy.morph <target PDF file> <morphed PDF file>
157+
diffpy.morph <morph file> <target file>
157158

158-
where both PDFs file are text files which contain PDF data, such as ``.gr``
159+
where both files are text files which contain two-column data, such as ``.gr``
159160
or ``.cgr`` files that are produced by ``PDFgetX2``, ``PDFgetX3``,
160161
or ``PDFgui``. File extensions other than ``.gr`` or ``.cgr``,
161162
but with the same content structure, also work with ``diffpy.morph``.

TUTORIAL.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ Basic diffpy.morph Workflow
132132
superficial and in most cases can be ignored.
133133

134134
We see that this has had hardly any effect on our PDF. To see
135-
an effect, we restrict the ``rmin`` and ``rmax`` values to
135+
an effect, we restrict the ``xmin`` and ``xmax`` values to
136136
reflect relevant data range by typing ::
137137

138-
diffpy.morph --scale=0.8 --smear=0.5 --rmin=1.5 --rmax=30 darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
138+
diffpy.morph --scale=0.8 --smear=0.5 --xmin=1.5 --xmax=30 darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
139139

140140
Now, we see that the difference Rw = 0.204 and that the optimized
141141
``smear=-0.084138``.
@@ -151,7 +151,7 @@ Basic diffpy.morph Workflow
151151
8. Finally, we will examine the stretch factor. Provide an initial
152152
guess by typing ::
153153

154-
diffpy.morph --scale=0.8 --smear=-0.08 --stretch=0.5 --rmin=1.5 --rmax=30 -a darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
154+
diffpy.morph --scale=0.8 --smear=-0.08 --stretch=0.5 --xmin=1.5 --xmax=30 -a darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
155155

156156
And noting that the difference has increased. Before continuing,
157157
see if you can see which direction (higher or lower) our initial
@@ -160,7 +160,7 @@ Basic diffpy.morph Workflow
160160

161161
If you cannot, type ::
162162

163-
diffpy.morph --scale=0.8 --smear=-0.08 --stretch=0.005 --rmin=1.5 --rmax=30 -a darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
163+
diffpy.morph --scale=0.8 --smear=-0.08 --stretch=0.005 --xmin=1.5 --xmax=30 -a darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
164164

165165
to observe decreased difference and then remove ``-a`` to see
166166
the optimized ``--stretch=0.001762``. We have now reached

docs/source/funcxy.rst

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
.. _funcxy:
2+
3+
Using funcxy with Commonly-Used Diffraction Software
4+
####################################################
5+
6+
The general xy morph ``funcxy`` can be used to tune parameters
7+
of many popular diffraction software functions.
8+
9+
Below, we give templates for how one can use ``funcxy``
10+
with `PDFgetx3 <https://www.diffpy.org/products/pdfgetx.html>`_
11+
and `PyFai <https://pyfai.readthedocs.io/en/stable/>`_.
12+
13+
Getting a Better PDF with PDFgetx3
14+
==================================
15+
16+
In PDFgetx3, the ``PDFGetter`` takes in a 1D diffraction
17+
pattern I(Q) and returns a PDF G(r).
18+
19+
There are many parameters you can specify, such as
20+
- ``qmin``: Lower Q-cutoff for the Fourier transform giving the PDF
21+
- ``qmax``: Upper Q-cutoff for the Fourier transform giving the PDF
22+
- ``qmaxinst``: Upper Q-boundary for meaningful signal
23+
- ``rpoly``: Approximately the low-r bound of meaningful G(r) values
24+
25+
Furthermore, you can supply a background file ``backgroundfile``
26+
and subtract a scaled version of the background file by the
27+
scaling factor ``bgscale``.
28+
29+
We will showcase an example of how one would refine over the
30+
``PDFGetter`` parameters using ``funcxy`` to obtain a PDF.
31+
32+
Let's say you have a measured I(Q) with Q in angstroms of
33+
glass (composition SiO2) named ``sample.chi`` taken on a
34+
kapton background. We want to match a target calculated PDF G(r)
35+
stored in a file named ``target.cgr``.
36+
Let's also say we have a measured I(Q) of the
37+
kapton background ``background.chi``.
38+
39+
.. code-block:: python
40+
41+
from diffpy.pdfgetx.pdfgetter import PDFGetter
42+
from diffpy.morph.morphpy import morph_arrays
43+
from diffpy.utils.parsers.loaddata import loadData
44+
45+
pg = PDFGetter()
46+
47+
backgroundfile = "background.chi"
48+
composition = "SiO2"
49+
50+
51+
def wrap(x, y, **kwargs):
52+
xy_out = pg.__call__(
53+
x=x, y=y, dataformat="QA",
54+
composition=composition,
55+
backgroundfile=backgroundfile,
56+
**kwargs
57+
)
58+
r = xy_out[0]
59+
gr = xy_out[1]
60+
return (r, gr)
61+
62+
63+
sample_iq = loadData("sample.chi")
64+
target_gr = loadData("target.cgr")
65+
params_to_morph = {
66+
"bgscale": 1.0,
67+
"qmin": 0.0, "qmax": 25.0,
68+
"qmaxinst": 25.0, "rpoly": 0.9
69+
}
70+
71+
morph_info, morphed_gr = morph_arrays(
72+
sample_iq, target_gr,
73+
funcxy=(wrap, params_to_morph)
74+
)
75+
76+
You can now plot ``morphed_gr`` against your ``target_gr`` to see
77+
how well your morphing refinement of the PDF-getting parameters
78+
as done!
79+
To see what the refined values of the parameters are,
80+
print out ``morph_info``.
81+
You can freely add and remove entries in
82+
``params_to_morph`` to include or not include them as
83+
parameters to refine over.
84+
85+
If you expect to see thermal effect differences between your
86+
measured PDF and ``target_gr``, you can also include
87+
the ``stretch``, ``scale``, and ``smear`` morphs in your
88+
call to ``morph_arrays``.
89+
90+
91+
Performing Detector Calibration with PyFai
92+
==========================================
93+
94+
When performing azimuthal integration, it is important to
95+
ensure your beam center and detector distances are calibrated.
96+
However, it is possible that they have shifted
97+
across measurements. Here, we will use morphing to the rescue!
98+
99+
Let's say we just measured a diffraction pattern stored
100+
as a NumPy object in ``diffraction_image.npy``, but some
101+
of the detector geometries are off.
102+
Our azimuthally integrated ``sample.chi`` looks a bit off.
103+
Before this measurement, you measured an amazing
104+
I(Q) pattern ``target.chi`` with a perfectly calibrated
105+
sample-to-detector distance and beam center.
106+
We will use morphing to try to match the integration of
107+
the 2D pattern to the target 1D function.
108+
109+
For the integration, we will need some information, such as
110+
the wavelength of the beam,
111+
the size of each pixel in the 2D image
112+
(``pixel1`` is the horizontal length in meters and
113+
``pixel2`` is the vertical length in meters),
114+
and a guess of the beam center.
115+
This information can be found on the
116+
`PyFai documentation <https://pyfai.readthedocs.io/en/stable/usage/cookbook/integration_with_python.html>`_.
117+
For our example, let's say we have a ``1024``x``1024`` pixel image
118+
where each pixel is a ``100`` micron by ``100`` micron region, and
119+
our wavelength was ``1.11`` angstroms.
120+
121+
.. code-block:: python
122+
123+
import numpy as np
124+
import pyFAI.integrator.azimuthal as pyfai
125+
import pyFAI.detectors as pfd
126+
from diffpy.morph.morphpy import morph_arrays
127+
from diffpy.utils.parsers.loaddata import loadData
128+
129+
pattern_2d = np.load("diffraction_image.npy")
130+
wavelength = 0.1110e-9 # in m
131+
pixel1 = 1e-4 # in m
132+
pixel2 = 1e-4 # in m
133+
cent_x = 511 # in number of pixels
134+
cent_y = 511 # in number of pixels
135+
136+
ai = pyfai.AzimuthalIntegrator()
137+
ai.wavelength = wavelength
138+
detector = pfd.Detector()
139+
detector.max_shape = pattern_2d.shape
140+
141+
142+
def wrap(x, y, sample_to_detector_dist, cent_offset_x, cent_offset_y):
143+
detector.pixel1 = pixel1
144+
detector.pixel2 = pixel2
145+
ai.detector = detector
146+
147+
ai.setFit2D(
148+
directDist=sample_to_detector_dist,
149+
centerX=cent_x+cent_offset_x,
150+
centerY=cent_y+cent_offset_y
151+
)
152+
153+
return ai.integrate1d_ng(
154+
pattern_2d,
155+
npt=1000, unit="q_A^-1",
156+
method="mean"
157+
)
158+
159+
160+
params_to_morph = {
161+
"sample_to_detector_dist": 60, # in mm
162+
"cent_offset_x": 0, # in number of pixels
163+
"cent_offset_y": 0 # in number of pixels
164+
}
165+
166+
sample_chi = loadData("sample.chi")
167+
target_chi = loadData("target.chi")
168+
169+
morph_info, morphed_chi = morph_arrays(
170+
sample_chi, target_chi,
171+
funcxy=(wrap, params_to_morph)
172+
)
173+
174+
You can now plot ``morphed_chi`` against your ``target_chi``
175+
to see if the refinement has helped in the calibration!
176+
To see the calibrated values, you can print out ``morph_info``.
177+
178+
If you would like to morph over other PyFai parameters
179+
(e.g. ``rot1``, ``tilt``, ``wavelength``),
180+
you can adjust the wrapper function ``wrap`` to take in
181+
these parameters.

docs/source/index.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ plotted below.
3434

3535
There are also a few other morphing transformations in the program.
3636
If no morphing transformation is specified, ``diffpy.morph`` will return just
37-
the plotted PDFs.
37+
the plotted functions.
3838

3939
Finally, we note that though ``diffpy.morph`` should work on other spectra
40-
that are not PDFs, it has not been extensively tested beyond the PDF.
40+
that are not from diffraction, it has not been extensively tested beyond 1D
41+
diffraction patterns and PDFs.
4142

4243
To get started, please visit the `quickstart tutorial <quickstart.html>`__.
4344
For those looking to see more advanced features, you can read our

0 commit comments

Comments
 (0)