Skip to content

Conversation

@ycexiao
Copy link
Collaborator

@ycexiao ycexiao commented Sep 11, 2025

What problem does this PR address?

address issues mentioned in #243.
Refactor the code to throw extrapolation warnings and throw an extrapolation warning for morph_shift.

What should the reviewer(s) do?

In this PR,

  1. checkExtrapolation is implemented at morph.Morph to make it accessible to all derived classes.
  2. Interfaces of related functions are changed to adopt checkExtrapolation's output.

@codecov
Copy link

codecov bot commented Sep 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.92%. Comparing base (dce54cf) to head (2c9208a).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #255   +/-   ##
=======================================
  Coverage   99.92%   99.92%           
=======================================
  Files          23       23           
  Lines        1355     1355           
=======================================
  Hits         1354     1354           
  Misses          1        1           
Files with missing lines Coverage Δ
tests/test_morphsqueeze.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

extrap_index_low = morph.extrap_index_low
extrap_index_high = morph.extrap_index_high

extrap_low = np.where(x_morph < min(x_squeezed))[0]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The code to compute extrap_index_*_expected and extrap_index_*_actual is identical, so we can remove the check and keep only one of them. In this case, extrap_index_*_actual is removed, which makes the implementation in the main program simpler.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there an argument to be made that this work could be done in checkExtrapolation()?

@ycexiao ycexiao marked this pull request as ready for review September 11, 2025 19:29
@ycexiao
Copy link
Collaborator Author

ycexiao commented Sep 11, 2025

@sbillinge @Sparks29032, it's ready for review. Please check if this is okay, and then I will code the warnings for stretching and write the tests.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

pls see comment

cutoff_low = extrapolation_info["cutoff_low"]
cutoff_high = extrapolation_info["cutoff_high"]

if is_extrap_low or is_extrap_high:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is getting better, but I still think it would be more readable with something like:

if low and high:
    low|high flow
elif low:
   low flow
elif high:
   high flow

return rv

def checkExtrapolation(self, x_true, x_extrapolate):
import numpy
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason we are importing numpy locally? Put it at the top of the file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No. I will put it at the top of the file.

ylabel(self.youtlabel)
return rv

def checkExtrapolation(self, x_true, x_extrapolate):
Copy link
Contributor

Choose a reason for hiding this comment

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

make this a private function if it is only used within this module, or give it a docstring.

Also, just to chec before we put this in the base class, is this method called in multiple sub-classes?

Finally, the function name seems to be a bit off. It seems as if it is a setter, not checking anything. Something like set_extrapolation_info() or something like that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The method will be called in morphsqueeze, morphshift, and morphstretch. I will add its docstring.

Yes, set_extrapolation_info will be better.

extrap_index_low = morph.extrap_index_low
extrap_index_high = morph.extrap_index_high

extrap_low = np.where(x_morph < min(x_squeezed))[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there an argument to be made that this work could be done in checkExtrapolation()?

@ycexiao
Copy link
Collaborator Author

ycexiao commented Sep 12, 2025

@sbillinge Is there an argument to be made that this work could be done in checkExtrapolation()?

Yes. We can add this to that function.

if is_extrap_low or is_extrap_high:
if not is_extrap_high:
wmsg = (
"Warning: points with grid value below "
Copy link
Collaborator

Choose a reason for hiding this comment

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

Change "will be extrapolated" to "are extrapolated"

@ycexiao ycexiao changed the title feat: add checkExtrapolation function in morph.Morph feat: add set_extrapolation_info function in morph.Morph Sep 12, 2025
Copy link
Collaborator Author

@ycexiao ycexiao left a comment

Choose a reason for hiding this comment

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

@sbillinge @Sparks29032 it's ready for review.

cutoff_low = extrapolation_info["cutoff_low"]
cutoff_high = extrapolation_info["cutoff_high"]

if is_extrap_low and is_extrap_high:
Copy link
Collaborator Author

@ycexiao ycexiao Sep 12, 2025

Choose a reason for hiding this comment

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

Logic flow changed according to @sbillinge's comment.

"""

"""Morph -- base class for defining a morph."""
import numpy
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

import is moved to the top.

return rv

def set_extrapolation_info(self, x_true, x_extrapolate):
"""Set extrapolation information of the concerned morphing
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

docstring is added.

extrapolation_info = {
"is_extrap_low": is_extrap_low,
"cutoff_low": cutoff_low,
"extrap_index_low": extrap_index_low,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

extrap_index_* is added.

"cutoff_high": cutoff_high,
"extrap_index_high": extrap_index_high,
}
self.extrapolation_info = extrapolation_info
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The way the function works has changed from returning a dict to setting the object's attributes since now the name starts with set.

extrap_index_low_expected = extrap_low[-1] if extrap_low.size else 0
extrap_index_high_expected = extrap_high[0] if extrap_high.size else -1

extrapolation_info = morph.extrapolation_info
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Getting the index now can be done in the morph.

assert np.allclose(y_target_actual, y_target)
assert np.allclose(x_target_actual, x_target_expected)
assert np.allclose(y_target_actual, y_target_expected)
assert extrap_index_low_actual == extrap_index_low_expected
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

extrap_index_* assertions. are added

lambda x: (
"Warning: points with grid value below "
f"{x[0]} will be extrapolated."
f"{x[0]} are extrapolated."
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"will be" -> "are"

@sbillinge sbillinge merged commit 2e5391d into diffpy:main Sep 13, 2025
5 checks passed
@sbillinge
Copy link
Contributor

Nicely done, thanks @ycexiao !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants