Skip to content

Commit 49bb353

Browse files
authored
Merge pull request diffpy#184 from sbillinge/private_f
refactor the transforms out of DiffractionObjects
2 parents d3f83b2 + e55e44d commit 49bb353

File tree

5 files changed

+269
-355
lines changed

5 files changed

+269
-355
lines changed

news/private_f.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
**Added:**
2+
3+
* <news item>
4+
5+
**Changed:**
6+
7+
* refactor `q_to_tth()` and `tth_to_q()` into `diffpy.utils.transforms` to make them available outside
8+
DiffractionObject
9+
10+
**Deprecated:**
11+
12+
* <news item>
13+
14+
**Removed:**
15+
16+
* <news item>
17+
18+
**Fixed:**
19+
20+
* <news item>
21+
22+
**Security:**
23+
24+
* <news item>

src/diffpy/utils/scattering_objects/diffraction_objects.py

Lines changed: 20 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import numpy as np
66

77
from diffpy.utils.tools import get_package_info
8+
from diffpy.utils.transforms import q_to_tth, tth_to_q
89

910
QQUANTITIES = ["q"]
1011
ANGLEQUANTITIES = ["angle", "tth", "twotheta", "2theta"]
@@ -17,23 +18,6 @@
1718
"and specifying how to handle the mismatch."
1819
)
1920

20-
wavelength_warning_emsg = (
21-
"INFO: no wavelength has been specified. You can continue "
22-
"to use the DiffractionObject but some of its powerful features "
23-
"will not be available. To specify a wavelength, set "
24-
"diffraction_object.wavelength = [number], "
25-
"where diffraction_object is the variable name of you Diffraction Object, "
26-
"and number is the wavelength in angstroms."
27-
)
28-
29-
length_mismatch_emsg = "Please ensure {array_name} array and intensity array are of the same length."
30-
non_numeric_value_emsg = "Invalid value found in {array_name} array. Please ensure all values are numeric."
31-
invalid_tth_emsg = "Two theta exceeds 180 degrees. Please check the input values for errors."
32-
invalid_q_or_wavelength_emsg = (
33-
"The supplied q-array and wavelength will result in an impossible two-theta. "
34-
"Please check these values and re-instantiate the DiffractionObject with correct values."
35-
)
36-
3721

3822
class Diffraction_object:
3923
"""A class to represent and manipulate data associated with diffraction experiments.
@@ -54,9 +38,9 @@ def __init__(self, name="", wavelength=None):
5438
self.name = name
5539
self.wavelength = wavelength
5640
self.scat_quantity = ""
57-
self.on_q = [np.empty(0), np.empty(0)]
58-
self.on_tth = [np.empty(0), np.empty(0)]
59-
self.on_d = [np.empty(0), np.empty(0)]
41+
self.on_q = np.array([np.empty(0), np.empty(0)])
42+
self.on_tth = np.array([np.empty(0), np.empty(0)])
43+
self.on_d = np.array([np.empty(0), np.empty(0)])
6044
self._all_arrays = [self.on_q, self.on_tth]
6145
self.metadata = {}
6246

@@ -311,97 +295,19 @@ def insert_scattering_quantity(
311295
if wavelength is not None:
312296
self.wavelength = wavelength
313297
if xtype.lower() in QQUANTITIES:
314-
self.on_q = [np.array(xarray), np.array(yarray)]
298+
self.on_q = np.array([xarray, yarray])
315299
elif xtype.lower() in ANGLEQUANTITIES:
316-
self.on_tth = [np.array(xarray), np.array(yarray)]
300+
self.on_tth = np.array([xarray, yarray])
317301
elif xtype.lower() in DQUANTITIES:
318-
self.on_tth = [np.array(xarray), np.array(yarray)]
302+
self.on_tth = np.array([xarray, yarray])
319303
self.set_all_arrays()
320304

321-
def q_to_tth(self):
322-
r"""
323-
Helper function to convert q to two-theta.
324-
325-
By definition the relationship is:
326-
327-
.. math::
328-
329-
\sin\left(\frac{2\theta}{2}\right) = \frac{\lambda q}{4 \pi}
330-
331-
thus
332-
333-
.. math::
334-
335-
2\theta_n = 2 \arcsin\left(\frac{\lambda q}{4 \pi}\right)
336-
337-
Parameters
338-
----------
339-
q : array
340-
An array of :math:`q` values
341-
342-
wavelength : float
343-
Wavelength of the incoming x-rays
344-
345-
Function adapted from scikit-beam. Thanks to those developers
346-
347-
Returns
348-
-------
349-
two_theta : array
350-
An array of :math:`2\theta` values in radians
351-
"""
352-
q = self.on_q[0]
353-
q = np.asarray(q)
354-
wavelength = float(self.wavelength)
355-
pre_factor = wavelength / (4 * np.pi)
356-
return np.rad2deg(2.0 * np.arcsin(q * pre_factor))
357-
358-
def tth_to_q(self):
359-
r"""
360-
Helper function to convert two-theta to q
361-
362-
By definition the relationship is
363-
364-
.. math::
365-
366-
\sin\left(\frac{2\theta}{2}\right) = \frac{\lambda q}{4 \pi}
367-
368-
thus
369-
370-
.. math::
371-
372-
q = \frac{4 \pi \sin\left(\frac{2\theta}{2}\right)}{\lambda}
373-
374-
375-
376-
Parameters
377-
----------
378-
two_theta : array
379-
An array of :math:`2\theta` values in units of degrees
380-
381-
wavelength : float
382-
Wavelength of the incoming x-rays
383-
384-
Function adapted from scikit-beam. Thanks to those developers.
385-
386-
Returns
387-
-------
388-
q : array
389-
An array of :math:`q` values in the inverse of the units
390-
of ``wavelength``
391-
"""
392-
two_theta = np.asarray(np.deg2rad(self.on_tth[0]))
393-
wavelength = float(self.wavelength)
394-
pre_factor = (4 * np.pi) / wavelength
395-
return pre_factor * np.sin(two_theta / 2)
396-
397305
def set_all_arrays(self):
398306
master_array, xtype = self._get_original_array()
399307
if xtype == "q":
400-
self.on_tth[0] = self.q_to_tth()
401-
self.on_tth[1] = master_array[1]
402-
if xtype == "tth":
403-
self.on_q[0] = self.tth_to_q()
404-
self.on_q[1] = master_array[1]
308+
self.on_tth = q_to_tth(self.on_q, self.wavelength)
309+
elif xtype == "tth":
310+
self.on_q = tth_to_q(self.on_tth, self.wavelength)
405311
self.tthmin = self.on_tth[0][0]
406312
self.tthmax = self.on_tth[0][-1]
407313
self.qmin = self.on_q[0][0]
@@ -500,9 +406,9 @@ def __init__(self, name="", wavelength=None):
500406
self.name = name
501407
self.wavelength = wavelength
502408
self.scat_quantity = ""
503-
self.on_q = [np.empty(0), np.empty(0)]
504-
self.on_tth = [np.empty(0), np.empty(0)]
505-
self.on_d = [np.empty(0), np.empty(0)]
409+
self.on_q = np.empty((2, 0), dtype=np.float64)
410+
self.on_tth = np.empty((2, 0), dtype=np.float64)
411+
self.on_d = np.empty((2, 0), dtype=np.float64)
506412
self._all_arrays = [self.on_q, self.on_tth]
507413
self.metadata = {}
508414

@@ -757,115 +663,19 @@ def insert_scattering_quantity(
757663
if wavelength is not None:
758664
self.wavelength = wavelength
759665
if xtype.lower() in QQUANTITIES:
760-
self.on_q = [np.array(xarray), np.array(yarray)]
666+
self.on_q = np.array([xarray, yarray])
761667
elif xtype.lower() in ANGLEQUANTITIES:
762-
self.on_tth = [np.array(xarray), np.array(yarray)]
763-
elif xtype.lower() in DQUANTITIES:
764-
self.on_tth = [np.array(xarray), np.array(yarray)]
668+
self.on_tth = np.array([xarray, yarray])
669+
elif xtype.lower() in DQUANTITIES: # Fixme when d is implemented. This here as a placeholder
670+
self.on_tth = np.array([xarray, yarray])
765671
self.set_all_arrays()
766672

767-
def q_to_tth(self):
768-
r"""
769-
Helper function to convert q to two-theta.
770-
771-
By definition the relationship is:
772-
773-
.. math::
774-
775-
\sin\left(\frac{2\theta}{2}\right) = \frac{\lambda q}{4 \pi}
776-
777-
thus
778-
779-
.. math::
780-
781-
2\theta_n = 2 \arcsin\left(\frac{\lambda q}{4 \pi}\right)
782-
783-
Function adapted from scikit-beam. Thanks to those developers
784-
785-
Parameters
786-
----------
787-
q : array
788-
The array of :math:`q` values
789-
790-
wavelength : float
791-
Wavelength of the incoming x-rays
792-
793-
Returns
794-
-------
795-
two_theta : array
796-
The array of :math:`2\theta` values in radians
797-
"""
798-
for i, value in enumerate(self.on_q[0]):
799-
if not isinstance(value, (int, float)):
800-
raise TypeError(non_numeric_value_emsg.format(array_name="q"))
801-
if len(self.on_q[0]) != len(self.on_q[1]):
802-
raise RuntimeError(length_mismatch_emsg.format(array_name="q"))
803-
if self.wavelength is None:
804-
warnings.warn(wavelength_warning_emsg, UserWarning)
805-
return np.empty(0)
806-
q = self.on_q[0]
807-
q = np.asarray(q)
808-
wavelength = float(self.wavelength)
809-
pre_factor = wavelength / (4 * np.pi)
810-
if np.any(np.abs(q * pre_factor) > 1):
811-
raise ValueError(invalid_q_or_wavelength_emsg)
812-
return np.rad2deg(2.0 * np.arcsin(q * pre_factor))
813-
814-
def tth_to_q(self):
815-
r"""
816-
Helper function to convert two-theta to q
817-
818-
By definition the relationship is
819-
820-
.. math::
821-
822-
\sin\left(\frac{2\theta}{2}\right) = \frac{\lambda q}{4 \pi}
823-
824-
thus
825-
826-
.. math::
827-
828-
q = \frac{4 \pi \sin\left(\frac{2\theta}{2}\right)}{\lambda}
829-
830-
Function adapted from scikit-beam. Thanks to those developers.
831-
832-
Parameters
833-
----------
834-
two_theta : array
835-
The array of :math:`2\theta` values in units of degrees
836-
837-
wavelength : float
838-
Wavelength of the incoming x-rays
839-
840-
Returns
841-
-------
842-
q : array
843-
The array of :math:`q` values in the inverse of the units
844-
of ``wavelength``
845-
"""
846-
for i, value in enumerate(self.on_tth[0]):
847-
if not isinstance(value, (int, float)):
848-
raise TypeError(non_numeric_value_emsg.format(array_name="two theta"))
849-
if len(self.on_tth[0]) != len(self.on_tth[1]):
850-
raise RuntimeError(length_mismatch_emsg.format(array_name="two theta"))
851-
two_theta = np.asarray(np.deg2rad(self.on_tth[0]))
852-
if np.any(two_theta > np.pi):
853-
raise ValueError(invalid_tth_emsg)
854-
if self.wavelength is None:
855-
warnings.warn(wavelength_warning_emsg, UserWarning)
856-
return np.empty(0)
857-
wavelength = float(self.wavelength)
858-
pre_factor = (4 * np.pi) / wavelength
859-
return pre_factor * np.sin(two_theta / 2)
860-
861673
def set_all_arrays(self):
862674
master_array, xtype = self._get_original_array()
863675
if xtype == "q":
864-
self.on_tth[0] = self.q_to_tth()
865-
self.on_tth[1] = master_array[1]
866-
if xtype == "tth":
867-
self.on_q[0] = self.tth_to_q()
868-
self.on_q[1] = master_array[1]
676+
self.on_tth = q_to_tth(self.on_q, self.wavelength)
677+
elif xtype == "tth":
678+
self.on_q = tth_to_q(self.on_tth, self.wavelength)
869679
self.tthmin = self.on_tth[0][0]
870680
self.tthmax = self.on_tth[0][-1]
871681
self.qmin = self.on_q[0][0]

0 commit comments

Comments
 (0)