Skip to content
23 changes: 14 additions & 9 deletions src/diffpy/utils/scattering_objects/diffraction_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,25 +763,27 @@ def q_to_tth(self):

2\theta_n = 2 \arcsin\left(\frac{\lambda q}{4 \pi}\right)

Function adapted from scikit-beam. Thanks to those developers

Parameters
----------
q : array
An array of :math:`q` values
The array of :math:`q` values

wavelength : float
Wavelength of the incoming x-rays

Function adapted from scikit-beam. Thanks to those developers

Returns
-------
two_theta : array
An array of :math:`2\theta` values in radians
The array of :math:`2\theta` values in radians
"""
q = self.on_q[0]
q = np.asarray(q)
wavelength = float(self.wavelength)
pre_factor = wavelength / (4 * np.pi)
if np.any(np.abs(q * pre_factor) > 1):
raise ValueError("Please check if you entered an incorrect wavelength or q value.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we would want to raise a value error here because otherwise the code proceeds with tth = nan.

return np.rad2deg(2.0 * np.arcsin(q * pre_factor))

def tth_to_q(self):
Expand All @@ -800,25 +802,28 @@ def tth_to_q(self):

q = \frac{4 \pi \sin\left(\frac{2\theta}{2}\right)}{\lambda}


Function adapted from scikit-beam. Thanks to those developers.

Parameters
----------
two_theta : array
An array of :math:`2\theta` values in units of degrees
The array of :math:`2\theta` values in units of degrees

wavelength : float
Wavelength of the incoming x-rays

Function adapted from scikit-beam. Thanks to those developers.

Returns
-------
q : array
An array of :math:`q` values in the inverse of the units
The array of :math:`q` values in the inverse of the units
of ``wavelength``
"""
two_theta = np.asarray(np.deg2rad(self.on_tth[0]))
if np.any(two_theta > np.pi):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above, I think this isn't doing quite what we want.

raise ValueError(
"Two theta exceeds 180 degrees. Please check if invalid values were entered "
"or if degrees were incorrectly specified as radians."
)
wavelength = float(self.wavelength)
pre_factor = (4 * np.pi) / wavelength
return pre_factor * np.sin(two_theta / 2)
Expand Down
36 changes: 36 additions & 0 deletions tests/diffpy/utils/scattering_objects/test_diffraction_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,42 @@ def test_diffraction_objects_equality(inputs1, inputs2, expected):
assert (diffraction_object1 == diffraction_object2) == expected


def test_q_to_tth():
# valid q values including edge cases when q=0 or tth=180 after converting
# expected tth values are 2*arcsin(q)
actual = DiffractionObject(wavelength=4 * np.pi)
setattr(actual, "on_q", [[0, 0.2, 0.4, 0.6, 0.8, 1], [1, 2, 3, 4, 5, 6]])
actual_tth = actual.q_to_tth()
expected_tth = [0, 23.07392, 47.15636, 73.73980, 106.26020, 180]
assert np.allclose(actual_tth, expected_tth)


def test_q_to_tth_bad():
# invalid wavelength or q values when arcsin value is not in the range of [-1, 1]
actual = DiffractionObject(wavelength=4 * np.pi)
setattr(actual, "on_q", [[0.6, 0.8, 1, 1.2], [1, 2, 3, 4]])
with pytest.raises(ValueError):
actual.q_to_tth()


def test_tth_to_q():
# valid tth values including edge cases when tth=0 or 180 degree
# expected q vales are sin15, sin30, sin45, sin60, sin90
actual = DiffractionObject(wavelength=4 * np.pi)
setattr(actual, "on_tth", [[0, 30, 60, 90, 120, 180], [1, 2, 3, 4, 5, 6]])
actual_q = actual.tth_to_q()
expected_q = [0, 0.258819, 0.5, 0.707107, 0.866025, 1]
assert np.allclose(actual_q, expected_q)


def test_tth_to_q_bad():
# invalid tth value of > 180 degree
actual = DiffractionObject(wavelength=4 * np.pi)
setattr(actual, "on_tth", [[0, 30, 60, 90, 120, 181], [1, 2, 3, 4, 5, 6]])
with pytest.raises(ValueError):
actual.tth_to_q()


def test_dump(tmp_path, mocker):
x, y = np.linspace(0, 5, 6), np.linspace(0, 5, 6)
directory = Path(tmp_path)
Expand Down
Loading