diff --git a/src/diffpy/utils/transforms.py b/src/diffpy/utils/transforms.py index c150b2a4..fa3e8747 100644 --- a/src/diffpy/utils/transforms.py +++ b/src/diffpy/utils/transforms.py @@ -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 for a wavelength of 1.54 angstroms." ) invalid_tth_emsg = "Two theta exceeds 180 degrees. Please check the input values for errors." invalid_q_or_d_or_wavelength_emsg = ( diff --git a/tests/test_diffraction_objects.py b/tests/test_diffraction_objects.py index 50080550..5a5d9805 100644 --- a/tests/test_diffraction_objects.py +++ b/tests/test_diffraction_objects.py @@ -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(): @@ -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", @@ -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 = ( @@ -360,7 +360,7 @@ def test_all_array_getter(): def test_all_array_setter(): - actual_do = DiffractionObject() + do = DiffractionObject() # Attempt to directly modify the property with pytest.raises( @@ -368,7 +368,7 @@ def test_all_array_setter(): 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(): diff --git a/tests/test_transforms.py b/tests/test_transforms.py index f1c940b7..909026e6 100644 --- a/tests/test_transforms.py +++ b/tests/test_transforms.py @@ -1,3 +1,5 @@ +import re + import numpy as np import pytest @@ -5,77 +7,90 @@ 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 for a wavelength of 1.54 angstroms." + ) + if wavelength is None: + with pytest.warns(UserWarning, match=re.escape(wavelength_warning_emsg)): + 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 = [