Skip to content

tests for scale_to #211

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
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/diffpy/utils/diffraction_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def on_d(self):

def scale_to(self, target_diff_object, xtype=None, xvalue=None):
f"""
returns a new diffraction object which is the current object but recaled in y to the target
returns a new diffraction object which is the current object but rescaled in y to the target

Parameters
----------
Expand All @@ -390,14 +390,15 @@ def scale_to(self, target_diff_object, xtype=None, xvalue=None):

data = self.on_xtype(xtype)
target = target_diff_object.on_xtype(xtype)
if len(data[0]) == 0 or len(target[0]) == 0 or len(data[0]) != len(target[0]):
raise ValueError("I cannot scale two diffraction objects with empty or different lengths.")
Copy link
Contributor Author

@yucongalicechen yucongalicechen Dec 8, 2024

Choose a reason for hiding this comment

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

@sbillinge I added this error message here but I'm not sure if this is appropriate. Does it make more sense that we find xindex for each diffraction object? (see comment below)

Copy link
Contributor

Choose a reason for hiding this comment

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

if the arrays are empty I think it will blow up anyway, right? so we don't need to blow it up?

If they are different lengths, I think we can still handle it maybe? If the xvalue given is outside one of the two different array lengths it will blow up. But in general I think it would be handy to be able to do this on different length arrays.

It does make it more complicated because we would have to interpolate one on to the other before doing the comparison. we could move that more awkward case to an issue on a later release, or just go for it. We can check. I think it kept adding and subtracting etc. to only between arrays on the same grids. But we often wan to compare data on different grids...that is kind of the point of these diffraction objects....makinng those tricky things easy. For example, I may have a diffraction pattern I got from a paper from my sample, and then I am at the synchrotron and I measure something and I want to know if it is what I am expecting and I just want to scale them and plot them on top of each other but it is a super hassle because they are on different length arrays and one is on tth and the other on q and so on on. The DO's are supposed to make those hassles all go away.

if xvalue is None:
xvalue = data[0][0] + (data[0][-1] - data[0][0]) / 2.0

xindex = (np.abs(data[0] - xvalue)).argmin()
ytarget = target[1][xindex]
yself = data[1][xindex]
scaled.on_tth[1] = data[1] * ytarget / yself
scaled.on_q[1] = data[1] * ytarget / yself
scaled._all_arrays[:, 0] = data[1] * ytarget / yself
return scaled

def on_xtype(self, xtype):
Expand Down
93 changes: 93 additions & 0 deletions tests/test_diffraction_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,99 @@ def test_on_xtype_bad():
test.on_xtype("invalid")


params_scale_to = [
# UC1: xvalue exact match
(
[
np.array([10, 15, 25, 30, 60, 140]),
np.array([10, 20, 25, 30, 60, 100]),
"tth",
2 * np.pi,
np.array([10, 15, 25, 30, 60, 140]),
np.array([2, 3, 4, 5, 6, 7]),
"tth",
2 * np.pi,
"tth",
60,
],
[np.array([1, 2, 2.5, 3, 6, 10])],
),
# UC2: xvalue approximate match
(
[
np.array([0.11, 0.24, 0.31, 0.4]),
np.array([10, 20, 40, 60]),
"q",
2 * np.pi,
np.array([0.11, 0.24, 0.31, 0.4]),
np.array([1, 3, 4, 5]),
"q",
2 * np.pi,
"q",
0.1,
],
[np.array([1, 2, 4, 6])],
),
]


@pytest.mark.parametrize("inputs, expected", params_scale_to)
def test_scale_to(inputs, expected):
orig_diff_object = DiffractionObject(xarray=inputs[0], yarray=inputs[1], xtype=inputs[2], wavelength=inputs[3])
target_diff_object = DiffractionObject(
xarray=inputs[4], yarray=inputs[5], xtype=inputs[6], wavelength=inputs[7]
)
scaled_diff_object = orig_diff_object.scale_to(target_diff_object, xtype=inputs[8], xvalue=inputs[9])
# Check the intensity data is same as expected
assert np.allclose(scaled_diff_object.on_xtype(inputs[8])[1], expected[0])


params_scale_to_bad = [
# UC1: at least one of the y-arrays is empty
(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A test example for scaling DOs with different array lengths. Here I think it makes more sense to scale them on q=61 (for self) & q=62 (for target).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

add the bad test case for specifying nothing

[
np.array([]),
np.array([]),
"tth",
2 * np.pi,
np.array([11, 14, 16, 20, 25, 30]),
np.array([2, 3, 4, 5, 6, 7]),
"tth",
2 * np.pi,
"tth",
60,
]
),
# UC2: diffraction objects with different array lengths
(
[
np.array([0.11, 0.24, 0.31, 0.4, 0.5]),
np.array([10, 20, 40, 50, 60]),
"q",
2 * np.pi,
np.array([0.1, 0.15, 0.3, 0.4]),
np.array([1, 3, 4, 5]),
"q",
2 * np.pi,
"q",
0.1,
]
),
]


@pytest.mark.parametrize("inputs", params_scale_to_bad)
def test_scale_to_bad(inputs):
orig_diff_object = DiffractionObject(xarray=inputs[0], yarray=inputs[1], xtype=inputs[2], wavelength=inputs[3])
target_diff_object = DiffractionObject(
xarray=inputs[4], yarray=inputs[5], xtype=inputs[6], wavelength=inputs[7]
)
with pytest.raises(
ValueError, match="I cannot scale two diffraction objects with empty or different lengths."
):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added a test for error message

orig_diff_object.scale_to(target_diff_object, xtype=inputs[8], xvalue=inputs[9])


params_index = [
# UC1: exact match
([4 * np.pi, np.array([30.005, 60]), np.array([1, 2]), "tth", "tth", 30.005], [0]),
Expand Down
Loading