Skip to content

1) Capture no wavelength UserWarning for test_q_to_thh method 2) discuss passing variables to @pytest.mark.parametrize #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 14, 2024
10 changes: 4 additions & 6 deletions src/diffpy/utils/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
import numpy as np

wavelength_warning_emsg = (
"INFO: no wavelength has been specified. You can continue "
"to use the DiffractionObject but some of its powerful features "
"will not be available. To specify a wavelength, set "
"diffraction_object.wavelength = [number], "
"where diffraction_object is the variable name of you Diffraction Object, "
"and number is the wavelength in angstroms."
"No wavelength has been specified. You can continue to use the DiffractionObject, but "
"some of its powerful features will not be available. "
"To specify a wavelength, if you have do = DiffractionObject(xarray, yarray, 'tth'), "
"you may set do.wavelength = 1.54 with the unit in angstroms."
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it is clearer to say than 1.54 here, it add "for a wavelength of 1.54 angstroms". Which would someone like Fillipo find clearer?

)
invalid_tth_emsg = "Two theta exceeds 180 degrees. Please check the input values for errors."
invalid_q_or_d_or_wavelength_emsg = (
Expand Down
42 changes: 21 additions & 21 deletions tests/test_diffraction_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,11 @@ def test_diffraction_objects_equality(inputs1, inputs2, expected):


def test_on_xtype():
test = DiffractionObject(wavelength=2 * np.pi, xarray=np.array([30, 60]), yarray=np.array([1, 2]), xtype="tth")
assert np.allclose(test.on_xtype("tth"), [np.array([30, 60]), np.array([1, 2])])
assert np.allclose(test.on_xtype("2theta"), [np.array([30, 60]), np.array([1, 2])])
assert np.allclose(test.on_xtype("q"), [np.array([0.51764, 1]), np.array([1, 2])])
assert np.allclose(test.on_xtype("d"), [np.array([12.13818, 6.28319]), np.array([1, 2])])
do = DiffractionObject(wavelength=2 * np.pi, xarray=np.array([30, 60]), yarray=np.array([1, 2]), xtype="tth")
assert np.allclose(do.on_xtype("tth"), [np.array([30, 60]), np.array([1, 2])])
assert np.allclose(do.on_xtype("2theta"), [np.array([30, 60]), np.array([1, 2])])
assert np.allclose(do.on_xtype("q"), [np.array([0.51764, 1]), np.array([1, 2])])
assert np.allclose(do.on_xtype("d"), [np.array([12.13818, 6.28319]), np.array([1, 2])])


def test_init_invalid_xtype():
Expand All @@ -184,34 +184,34 @@ def test_init_invalid_xtype():

params_index = [
# UC1: exact match
([4 * np.pi, np.array([30.005, 60]), np.array([1, 2]), "tth", "tth", 30.005], [0]),
(4 * np.pi, np.array([30.005, 60]), np.array([1, 2]), "tth", "tth", 30.005, [0]),
# UC2: target value lies in the array, returns the (first) closest index
([4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "tth", 45], [0]),
([4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "q", 0.25], [0]),
(4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "tth", 45, [0]),
(4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "q", 0.25, [0]),
# UC3: target value out of the range, returns the closest index
([4 * np.pi, np.array([0.25, 0.5, 0.71]), np.array([1, 2, 3]), "q", "q", 0.1], [0]),
([4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "tth", 63], [1]),
(4 * np.pi, np.array([0.25, 0.5, 0.71]), np.array([1, 2, 3]), "q", "q", 0.1, [0]),
(4 * np.pi, np.array([30, 60]), np.array([1, 2]), "tth", "tth", 63, [1]),
]


@pytest.mark.parametrize("inputs, expected", params_index)
def test_get_array_index(inputs, expected):
test = DiffractionObject(wavelength=inputs[0], xarray=inputs[1], yarray=inputs[2], xtype=inputs[3])
actual = test.get_array_index(value=inputs[5], xtype=inputs[4])
assert actual == expected[0]
@pytest.mark.parametrize("wavelength, xarray, yarray, xtype_1, xtype_2, value, expected_index", params_index)
def test_get_array_index(wavelength, xarray, yarray, xtype_1, xtype_2, value, expected_index):
do = DiffractionObject(wavelength=wavelength, xarray=xarray, yarray=yarray, xtype=xtype_1)
actual_index = do.get_array_index(value=value, xtype=xtype_2)
assert actual_index == expected_index


def test_get_array_index_bad():
test = DiffractionObject(wavelength=2 * np.pi, xarray=np.array([]), yarray=np.array([]), xtype="tth")
do = DiffractionObject(wavelength=2 * np.pi, xarray=np.array([]), yarray=np.array([]), xtype="tth")
with pytest.raises(ValueError, match=re.escape("The 'tth' array is empty. Please ensure it is initialized.")):
test.get_array_index(value=30)
do.get_array_index(value=30)


def test_dump(tmp_path, mocker):
x, y = np.linspace(0, 5, 6), np.linspace(0, 5, 6)
directory = Path(tmp_path)
file = directory / "testfile"
test = DiffractionObject(
do = DiffractionObject(
wavelength=1.54,
name="test",
scat_quantity="x-ray",
Expand All @@ -222,7 +222,7 @@ def test_dump(tmp_path, mocker):
)
mocker.patch("importlib.metadata.version", return_value="3.3.0")
with freeze_time("2012-01-14"):
test.dump(file, "q")
do.dump(file, "q")
with open(file, "r") as f:
actual = f.read()
expected = (
Expand Down Expand Up @@ -360,15 +360,15 @@ def test_all_array_getter():


def test_all_array_setter():
actual_do = DiffractionObject()
do = DiffractionObject()

# Attempt to directly modify the property
with pytest.raises(
AttributeError,
match="Direct modification of attribute 'all_arrays' is not allowed. "
"Please use 'input_data' to modify 'all_arrays'.",
):
actual_do.all_arrays = np.empty((4, 4))
do.all_arrays = np.empty((4, 4))


def test_id_getter():
Expand Down
80 changes: 48 additions & 32 deletions tests/test_transforms.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,97 @@
import re

import numpy as np
import pytest

from diffpy.utils.transforms import d_to_q, d_to_tth, q_to_d, q_to_tth, tth_to_d, tth_to_q

params_q_to_tth = [
# UC1: Empty q values, no wavelength, return empty arrays
([None, np.empty((0))], np.empty((0))),
(None, np.empty((0)), np.empty((0))),
# UC2: Empty q values, wavelength specified, return empty arrays
([4 * np.pi, np.empty((0))], np.empty(0)),
(4 * np.pi, np.empty((0)), np.empty(0)),
# UC3: User specified valid q values, no wavelength, return empty arrays
(
[None, np.array([0, 0.2, 0.4, 0.6, 0.8, 1])],
None,
np.array([0, 0.2, 0.4, 0.6, 0.8, 1]),
np.array([0, 1, 2, 3, 4, 5]),
),
# UC4: User specified valid q values (with wavelength)
# expected tth values are 2*arcsin(q) in degrees
([4 * np.pi, np.array([0, 1 / np.sqrt(2), 1.0])], np.array([0, 90.0, 180.0])),
(4 * np.pi, np.array([0, 1 / np.sqrt(2), 1.0]), np.array([0, 90.0, 180.0])),
]


@pytest.mark.parametrize("inputs, expected", params_q_to_tth)
def test_q_to_tth(inputs, expected):
actual = q_to_tth(inputs[1], inputs[0])
assert np.allclose(expected, actual)
@pytest.mark.parametrize("wavelength, q, expected_tth", params_q_to_tth)
def test_q_to_tth(wavelength, q, expected_tth):

wavelength_warning_emsg = (
"No wavelength has been specified. You can continue to use the DiffractionObject, but "
"some of its powerful features will not be available. "
"To specify a wavelength, if you have do = DiffractionObject(xarray, yarray, 'tth'), "
"you may set do.wavelength = 1.54 with the unit in angstroms."
Copy link
Contributor

Choose a reason for hiding this comment

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

Please see the small tweak above

)
if wavelength is None:
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_emsg)):
actual_tth = q_to_tth(q, wavelength)
actual_tth = q_to_tth(q, wavelength)
else:
actual_tth = q_to_tth(q, wavelength)

assert np.allclose(expected_tth, actual_tth)


params_q_to_tth_bad = [
# UC1: user specified invalid q values that result in tth > 180 degrees
(
[4 * np.pi, np.array([0.2, 0.4, 0.6, 0.8, 1, 1.2])],
[
ValueError,
"The supplied input array and wavelength will result in an impossible two-theta. "
"Please check these values and re-instantiate the DiffractionObject with correct values.",
],
4 * np.pi,
np.array([0.2, 0.4, 0.6, 0.8, 1, 1.2]),
ValueError,
"The supplied input array and wavelength will result in an impossible two-theta. "
"Please check these values and re-instantiate the DiffractionObject with correct values.",
),
# UC2: user specified a wrong wavelength that result in tth > 180 degrees
(
[100, np.array([0, 0.2, 0.4, 0.6, 0.8, 1])],
[
ValueError,
"The supplied input array and wavelength will result in an impossible two-theta. "
"Please check these values and re-instantiate the DiffractionObject with correct values.",
],
100,
np.array([0, 0.2, 0.4, 0.6, 0.8, 1]),
ValueError,
"The supplied input array and wavelength will result in an impossible two-theta. "
"Please check these values and re-instantiate the DiffractionObject with correct values.",
),
]


@pytest.mark.parametrize("inputs, expected", params_q_to_tth_bad)
def test_q_to_tth_bad(inputs, expected):
with pytest.raises(expected[0], match=expected[1]):
q_to_tth(inputs[1], inputs[0])
@pytest.mark.parametrize("q, wavelength, expected_error_type, expected_error_msg", params_q_to_tth_bad)
def test_q_to_tth_bad(q, wavelength, expected_error_type, expected_error_msg):
with pytest.raises(expected_error_type, match=expected_error_msg):
q_to_tth(wavelength, q)


params_tth_to_q = [
# UC0: User specified empty tth values (without wavelength)
([None, np.array([])], np.array([])),
(None, np.array([]), np.array([])),
# UC1: User specified empty tth values (with wavelength)
([4 * np.pi, np.array([])], np.array([])),
(4 * np.pi, np.array([]), np.array([])),
# UC2: User specified valid tth values between 0-180 degrees (without wavelength)
(
[None, np.array([0, 30, 60, 90, 120, 180])],
None,
np.array([0, 30, 60, 90, 120, 180]),
np.array([0, 1, 2, 3, 4, 5]),
),
# UC3: User specified valid tth values between 0-180 degrees (with wavelength)
# expected q values are sin15, sin30, sin45, sin60, sin90
(
[4 * np.pi, np.array([0, 30.0, 60.0, 90.0, 120.0, 180.0])],
4 * np.pi,
np.array([0, 30.0, 60.0, 90.0, 120.0, 180.0]),
np.array([0, 0.258819, 0.5, 0.707107, 0.866025, 1]),
),
]


@pytest.mark.parametrize("inputs, expected", params_tth_to_q)
def test_tth_to_q(inputs, expected):
actual = tth_to_q(inputs[1], inputs[0])
assert np.allclose(actual, expected)
@pytest.mark.parametrize("wavelength, tth, expected_q", params_tth_to_q)
def test_tth_to_q(wavelength, tth, expected_q):
actual_q = tth_to_q(tth, wavelength)
assert np.allclose(actual_q, expected_q)


params_tth_to_q_bad = [
Expand Down
Loading