From c4ed0e6436d2c3c29a6a1db5dee6d3b1ee906bb5 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Thu, 10 Apr 2025 16:51:28 -0600 Subject: [PATCH 1/9] test: adding test and empty function --- src/diffpy/morph/morphs/morphsqueeze.py | 0 tests/test_morphsqueeze.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/diffpy/morph/morphs/morphsqueeze.py create mode 100644 tests/test_morphsqueeze.py diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py new file mode 100644 index 00000000..e69de29b From c59b09e5d252209ff264ed4b6b1b6186c02ccf2e Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Thu, 10 Apr 2025 16:53:45 -0600 Subject: [PATCH 2/9] test: adding test and empty function --- src/diffpy/morph/morphs/morphsqueeze.py | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index e69de29b..637adbb3 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -0,0 +1,36 @@ +from diffpy.morph.morphs.morph import LABEL_GR, LABEL_RA, Morph + + +class MorphSqueeze(Morph): + """Squeeze the morph function. + + This applies a polynomial to squeeze the morph non-linearly. The resulting + squeezed morph is interpolated to the (trimmed) target grid. + Only the overlapping region between the squeezed morph and the target + grid is used. The target is trimmed (or not) accordingly, and the final + outputs (morph and target) are returned on the same grid, defined by this + trimmed target range. + + Configuration Variables + ----------------------- + squeeze + list or array-like + Polynomial coefficients [a0, a1, ..., an] for the squeeze function. + """ + + # Define input output types + summary = "Squeeze morph by polynomial shift" + xinlabel = LABEL_RA + yinlabel = LABEL_GR + xoutlabel = LABEL_RA + youtlabel = LABEL_GR + parnames = ["squeeze"] + + def morph(self, x_morph, y_morph, x_target, y_target): + Morph.morph(self, x_morph, y_morph, x_target, y_target) + if self.squeeze is None: + self.x_morph_out = self.x_morph_in + self.y_morph_out = self.y_morph_in + return self.xyallout + + return self.xyallout From 2320b82e5e401358690592eab43fed473749028a Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Fri, 11 Apr 2025 12:07:59 -0600 Subject: [PATCH 3/9] test: adding different UCs tests while keeping function empty --- news/morphsqueeze.rst | 23 ++++++++++ src/diffpy/morph/morphs/morphsqueeze.py | 12 +---- tests/test_morphsqueeze.py | 60 +++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 news/morphsqueeze.rst diff --git a/news/morphsqueeze.rst b/news/morphsqueeze.rst new file mode 100644 index 00000000..750fbcf1 --- /dev/null +++ b/news/morphsqueeze.rst @@ -0,0 +1,23 @@ +**Added:** + +* Polynomial squeeze of x-axis of morphed data + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index 637adbb3..e4f0e3c3 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -4,12 +4,8 @@ class MorphSqueeze(Morph): """Squeeze the morph function. - This applies a polynomial to squeeze the morph non-linearly. The resulting - squeezed morph is interpolated to the (trimmed) target grid. - Only the overlapping region between the squeezed morph and the target - grid is used. The target is trimmed (or not) accordingly, and the final - outputs (morph and target) are returned on the same grid, defined by this - trimmed target range. + This applies a polynomial to squeeze the morph non-linearly. The morphed + data is returned on the same grid as the unmorphed data. Configuration Variables ----------------------- @@ -28,9 +24,5 @@ class MorphSqueeze(Morph): def morph(self, x_morph, y_morph, x_target, y_target): Morph.morph(self, x_morph, y_morph, x_target, y_target) - if self.squeeze is None: - self.x_morph_out = self.x_morph_in - self.y_morph_out = self.y_morph_in - return self.xyallout return self.xyallout diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index e69de29b..6102390a 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -0,0 +1,60 @@ +import numpy as np +import pytest +from numpy.polynomial import Polynomial + +from diffpy.morph.morphs.morphsqueeze import MorphSqueeze + +squeeze_coeffs_list = [ + # The order of coefficients is [a0, a1, a2, ..., an] + # Negative cubic squeeze coefficients + [-0.2, -0.01, -0.001, -0.001], + # Positive cubic squeeze coefficients + [0.2, 0.01, 0.001, 0.001], + # Positive and negative cubic squeeze coefficients + [0.2, -0.01, 0.002, -0.001], + # Quadratic squeeze coefficients + [-0.2, 0.005, -0.007], + # Linear squeeze coefficients + [0.1, 0.3], + # 4th order squeeze coefficients + [0.2, -0.01, 0.001, -0.001, 0.0004], + # Zeros and non-zeros, the full polynomial is applied + [0, 0.03, 0, -0.001], + # Testing zeros, expect no squeezing + [0, 0, 0, 0, 0, 0], +] +morph_target_grids = [ + # UCs from issue 181: https://github.com/diffpy/diffpy.morph/issues/181 + # UC2: Same grid + (np.linspace(0, 10, 101), np.linspace(0, 10, 101)), + # UC4: Target extends beyond morph + (np.linspace(0, 10, 101), np.linspace(-2, 20, 221)), + # UC6: Target extends beyond morph; morph coarser + (np.linspace(0, 10, 101), np.linspace(-2, 20, 421)), + # UC8: Target extends beyond morph; target coarser + (np.linspace(0, 10, 401), np.linspace(-2, 20, 200)), + # UC10: morph starts earlier than target + (np.linspace(-2, 10, 121), np.linspace(0, 20, 201)), + # UC12: morph extends beyond target + (np.linspace(-2, 20, 221), np.linspace(0, 10, 101)), +] + + +@pytest.mark.parametrize("x_morph, x_target", morph_target_grids) +@pytest.mark.parametrize("squeeze_coeffs", squeeze_coeffs_list) +def test_morphsqueeze(x_morph, x_target, squeeze_coeffs): + y_target = np.sin(x_target) + squeeze_polynomial = Polynomial(squeeze_coeffs) + x_squeezed = x_morph + squeeze_polynomial(x_morph) + y_morph = np.sin(x_squeezed) + x_morph_expected = x_morph + y_morph_expected = np.sin(x_morph) + morph = MorphSqueeze() + morph.squeeze = squeeze_coeffs + x_morph_actual, y_morph_actual, x_target_actual, y_target_actual = morph( + x_morph, y_morph, x_target, y_target + ) + assert np.allclose(y_morph_actual, y_morph_expected) + assert np.allclose(x_morph_actual, x_morph_expected) + assert np.allclose(x_target_actual, x_target) + assert np.allclose(y_target_actual, y_target) From ead324881156de78908e20e0adf601244c5e6a44 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Fri, 11 Apr 2025 14:24:17 -0600 Subject: [PATCH 4/9] test: writting better docstrings and comments --- src/diffpy/morph/morphs/morphsqueeze.py | 27 ++++++++++++++++++++++--- tests/test_morphsqueeze.py | 12 +++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index e4f0e3c3..81d8728a 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -9,9 +9,29 @@ class MorphSqueeze(Morph): Configuration Variables ----------------------- - squeeze - list or array-like - Polynomial coefficients [a0, a1, ..., an] for the squeeze function. + squeeze : list + The polynomial coefficients [a0, a1, ..., an] for the squeeze function + where the polynomial would be of the form a0 + a1*x + a2*x^2 and so + on. The order of the polynomial is determined by the length of the + list. + + Example + ------- + >>> import numpy as np + >>> from numpy.polynomial import Polynomial + >>> from diffpy.morph.morphs.morphsqueeze import MorphSqueeze + + >>> x_morph = np.linspace(0, 10, 101) + >>> x_target = np.linspace(0, 10, 101) + >>> squeeze_coeff = [0.1, -0.01, 0.005] + >>> poly = Polynomial(squeeze_coeff) + >>> y_morph = np.sin(x_morph + poly(x_morph)) + >>> y_target = np.sin(x_target) + + >>> morph = MorphSqueeze() + >>> morph.squeeze = squeeze_coeff + >>> x_morph_out, y_morph_out, x_target_out, y_target_out = morph( + ... x_morph, y_morph, x_target, y_target) """ # Define input output types @@ -23,6 +43,7 @@ class MorphSqueeze(Morph): parnames = ["squeeze"] def morph(self, x_morph, y_morph, x_target, y_target): + """Apply a polynomial to squeeze the morph function""" Morph.morph(self, x_morph, y_morph, x_target, y_target) return self.xyallout diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index 6102390a..7087e91f 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -25,17 +25,17 @@ ] morph_target_grids = [ # UCs from issue 181: https://github.com/diffpy/diffpy.morph/issues/181 - # UC2: Same grid + # UC2: Same range and same grid density (np.linspace(0, 10, 101), np.linspace(0, 10, 101)), - # UC4: Target extends beyond morph + # UC4: Target range wider than morph, same grid density (np.linspace(0, 10, 101), np.linspace(-2, 20, 221)), - # UC6: Target extends beyond morph; morph coarser + # UC6: Target range wider than morph, finer target grid density (np.linspace(0, 10, 101), np.linspace(-2, 20, 421)), - # UC8: Target extends beyond morph; target coarser + # UC8: Target range wider than morph, finer morph grid density (np.linspace(0, 10, 401), np.linspace(-2, 20, 200)), - # UC10: morph starts earlier than target + # UC10: Morph range starts and ends earlier than target, same grid density (np.linspace(-2, 10, 121), np.linspace(0, 20, 201)), - # UC12: morph extends beyond target + # UC12: Morph range wider than target, same grid density (np.linspace(-2, 20, 221), np.linspace(0, 10, 101)), ] From 924872edc7b0ed581dd912dfd5f2464c22b67870 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Fri, 11 Apr 2025 16:23:31 -0600 Subject: [PATCH 5/9] test: writting better docstrings and comments --- src/diffpy/morph/morphs/morphsqueeze.py | 4 ++-- tests/test_morphsqueeze.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index 81d8728a..d8843685 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -21,12 +21,12 @@ class MorphSqueeze(Morph): >>> from numpy.polynomial import Polynomial >>> from diffpy.morph.morphs.morphsqueeze import MorphSqueeze - >>> x_morph = np.linspace(0, 10, 101) >>> x_target = np.linspace(0, 10, 101) + >>> y_target = np.sin(x_target) + >>> x_morph = np.linspace(0, 10, 101) >>> squeeze_coeff = [0.1, -0.01, 0.005] >>> poly = Polynomial(squeeze_coeff) >>> y_morph = np.sin(x_morph + poly(x_morph)) - >>> y_target = np.sin(x_target) >>> morph = MorphSqueeze() >>> morph.squeeze = squeeze_coeff diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index 7087e91f..a1ece051 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -29,9 +29,9 @@ (np.linspace(0, 10, 101), np.linspace(0, 10, 101)), # UC4: Target range wider than morph, same grid density (np.linspace(0, 10, 101), np.linspace(-2, 20, 221)), - # UC6: Target range wider than morph, finer target grid density + # UC6: Target range wider than morph, target grid density finer than morph (np.linspace(0, 10, 101), np.linspace(-2, 20, 421)), - # UC8: Target range wider than morph, finer morph grid density + # UC8: Target range wider than morph, morph grid density finer than target (np.linspace(0, 10, 401), np.linspace(-2, 20, 200)), # UC10: Morph range starts and ends earlier than target, same grid density (np.linspace(-2, 10, 121), np.linspace(0, 20, 201)), From 3538e4db5f414464c35dfe3c27281b024fe6efc3 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Sun, 13 Apr 2025 12:16:03 -0600 Subject: [PATCH 6/9] test: modified docstrings --- src/diffpy/morph/morphs/morphsqueeze.py | 72 ++++++++++++++----------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index d8843685..0aeb63c8 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -2,37 +2,8 @@ class MorphSqueeze(Morph): - """Squeeze the morph function. - - This applies a polynomial to squeeze the morph non-linearly. The morphed - data is returned on the same grid as the unmorphed data. - - Configuration Variables - ----------------------- - squeeze : list - The polynomial coefficients [a0, a1, ..., an] for the squeeze function - where the polynomial would be of the form a0 + a1*x + a2*x^2 and so - on. The order of the polynomial is determined by the length of the - list. - - Example - ------- - >>> import numpy as np - >>> from numpy.polynomial import Polynomial - >>> from diffpy.morph.morphs.morphsqueeze import MorphSqueeze - - >>> x_target = np.linspace(0, 10, 101) - >>> y_target = np.sin(x_target) - >>> x_morph = np.linspace(0, 10, 101) - >>> squeeze_coeff = [0.1, -0.01, 0.005] - >>> poly = Polynomial(squeeze_coeff) - >>> y_morph = np.sin(x_morph + poly(x_morph)) - - >>> morph = MorphSqueeze() - >>> morph.squeeze = squeeze_coeff - >>> x_morph_out, y_morph_out, x_target_out, y_target_out = morph( - ... x_morph, y_morph, x_target, y_target) - """ + """Apply a polynomial to squeeze the morph function. The morphed + data is returned on the same grid as the unmorphed data.""" # Define input output types summary = "Squeeze morph by polynomial shift" @@ -43,7 +14,44 @@ class MorphSqueeze(Morph): parnames = ["squeeze"] def morph(self, x_morph, y_morph, x_target, y_target): - """Apply a polynomial to squeeze the morph function""" + """Squeeze the morph function. + + This applies a polynomial to squeeze the morph non-linearly. + + Configuration Variables + ----------------------- + squeeze : list + The polynomial coefficients [a0, a1, ..., an] for the squeeze + function where the polynomial would be of the form + a0 + a1*x + a2*x^2 and so on. The order of the polynomial is + determined by the length of the list. + + Returns + ------- + A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out) + where the target values remain the same and the morph data + is shifted according to the squeeze. The morphed data is + returned on the same grid as the unmorphed data. + + Example + ------- + Import the squeeze morph function: + >>> from diffpy.morph.morphs.morphsqueeze import MorphSqueeze + Provide initial guess for squeezing coefficients: + >>> squeeze_coeff = [0.1, -0.01, 0.005] + Run the squeeze morph given input morph array (x_morph, y_morph) + and target array (x_target, y_target): + >>> morph = MorphSqueeze() + >>> morph.squeeze = squeeze_coeff + >>> x_morph_out, y_morph_out, x_target_out, y_target_out = morph( + ... x_morph, y_morph, x_target, y_target) + To access parameters from the morph instance: + >>> x_morph_in = morph.x_morph_in + >>> y_morph_in = morph.y_morph_in + >>> x_target_in = morph.x_target_in + >>> y_target_in = morph.y_target_in + >>> squeeze_coeff_out = morph.squeeze + """ Morph.morph(self, x_morph, y_morph, x_target, y_target) return self.xyallout From 234b387cb7b5993e90b5067845b7a2a4870e2ee1 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Tue, 15 Apr 2025 16:13:30 -0600 Subject: [PATCH 7/9] func: adding squeeze functionallity and extrapolation indices --- src/diffpy/morph/morphs/morphsqueeze.py | 26 +++++++++++++++---- tests/test_morphsqueeze.py | 34 +++++++++++++++++++------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index 0aeb63c8..cd7cb86b 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -1,3 +1,7 @@ +import numpy as np +from numpy.polynomial import Polynomial +from scipy.interpolate import CubicSpline + from diffpy.morph.morphs.morph import LABEL_GR, LABEL_RA, Morph @@ -28,10 +32,13 @@ def morph(self, x_morph, y_morph, x_target, y_target): Returns ------- - A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out) - where the target values remain the same and the morph data - is shifted according to the squeeze. The morphed data is - returned on the same grid as the unmorphed data. + A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out, + min_index, max_index) where the target values remain the same and + the morph data is shifted according to the squeeze. The morphed + data is returned on the same grid as the unmorphed data. + The min_index and max_index are the last index before the + interpolated region and the first index after the interpolated + region, respectively. If there is no extrapolation it returns None. Example ------- @@ -54,4 +61,13 @@ def morph(self, x_morph, y_morph, x_target, y_target): """ Morph.morph(self, x_morph, y_morph, x_target, y_target) - return self.xyallout + squeeze_polynomial = Polynomial(self.squeeze) + x_squeezed = self.x_morph_in + squeeze_polynomial(self.x_morph_in) + self.y_morph_out = CubicSpline(x_squeezed, self.y_morph_in)( + self.x_morph_in + ) + left_extrap = np.where(self.x_morph_in < x_squeezed[0])[0] + right_extrap = np.where(self.x_morph_in > x_squeezed[-1])[0] + min_index = left_extrap[-1] if left_extrap.size else None + max_index = right_extrap[0] if right_extrap.size else None + return self.xyallout + (min_index, max_index) diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index a1ece051..9ba0afdc 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -7,11 +7,11 @@ squeeze_coeffs_list = [ # The order of coefficients is [a0, a1, a2, ..., an] # Negative cubic squeeze coefficients - [-0.2, -0.01, -0.001, -0.001], + [-0.2, -0.01, -0.001, -0.0001], # Positive cubic squeeze coefficients - [0.2, 0.01, 0.001, 0.001], + [0.2, 0.01, 0.001, 0.0001], # Positive and negative cubic squeeze coefficients - [0.2, -0.01, 0.002, -0.001], + [0.2, -0.01, 0.002, -0.0001], # Quadratic squeeze coefficients [-0.2, 0.005, -0.007], # Linear squeeze coefficients @@ -19,7 +19,7 @@ # 4th order squeeze coefficients [0.2, -0.01, 0.001, -0.001, 0.0004], # Zeros and non-zeros, the full polynomial is applied - [0, 0.03, 0, -0.001], + [0, 0.03, 0, -0.0001], # Testing zeros, expect no squeezing [0, 0, 0, 0, 0, 0], ] @@ -51,10 +51,28 @@ def test_morphsqueeze(x_morph, x_target, squeeze_coeffs): y_morph_expected = np.sin(x_morph) morph = MorphSqueeze() morph.squeeze = squeeze_coeffs - x_morph_actual, y_morph_actual, x_target_actual, y_target_actual = morph( - x_morph, y_morph, x_target, y_target - ) - assert np.allclose(y_morph_actual, y_morph_expected) + ( + x_morph_actual, + y_morph_actual, + x_target_actual, + y_target_actual, + low_extrap_idx, + high_extrap_idx, + ) = morph(x_morph, y_morph, x_target, y_target) + if low_extrap_idx is None and high_extrap_idx is None: + assert np.allclose(y_morph_actual, y_morph_expected, atol=1e-6) + else: + interp_start = low_extrap_idx + 1 if low_extrap_idx is not None else 0 + interp_end = ( + high_extrap_idx + if high_extrap_idx is not None + else len(y_morph_actual) + ) + assert np.allclose( + y_morph_actual[interp_start:interp_end], + y_morph_expected[interp_start:interp_end], + atol=1e-6, + ) assert np.allclose(x_morph_actual, x_morph_expected) assert np.allclose(x_target_actual, x_target) assert np.allclose(y_target_actual, y_target) From 4c6d9936af5dabe88ddde4fc573180ae8eb14926 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Wed, 16 Apr 2025 14:19:58 -0600 Subject: [PATCH 8/9] func: not returning extrapolation indices --- src/diffpy/morph/morphs/morphsqueeze.py | 25 ++++++------ tests/test_morphsqueeze.py | 52 ++++++++++++++----------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/diffpy/morph/morphs/morphsqueeze.py b/src/diffpy/morph/morphs/morphsqueeze.py index cd7cb86b..e63adc8b 100644 --- a/src/diffpy/morph/morphs/morphsqueeze.py +++ b/src/diffpy/morph/morphs/morphsqueeze.py @@ -16,6 +16,10 @@ class MorphSqueeze(Morph): xoutlabel = LABEL_RA youtlabel = LABEL_GR parnames = ["squeeze"] + # extrap_index_low: last index before interpolation region + # extrap_index_high: first index after interpolation region + extrap_index_low = None + extrap_index_high = None def morph(self, x_morph, y_morph, x_target, y_target): """Squeeze the morph function. @@ -32,13 +36,10 @@ def morph(self, x_morph, y_morph, x_target, y_target): Returns ------- - A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out, - min_index, max_index) where the target values remain the same and - the morph data is shifted according to the squeeze. The morphed - data is returned on the same grid as the unmorphed data. - The min_index and max_index are the last index before the - interpolated region and the first index after the interpolated - region, respectively. If there is no extrapolation it returns None. + A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out) + where the target values remain the same and the morph data is + shifted according to the squeeze. The morphed data is returned on + the same grid as the unmorphed data. Example ------- @@ -66,8 +67,8 @@ def morph(self, x_morph, y_morph, x_target, y_target): self.y_morph_out = CubicSpline(x_squeezed, self.y_morph_in)( self.x_morph_in ) - left_extrap = np.where(self.x_morph_in < x_squeezed[0])[0] - right_extrap = np.where(self.x_morph_in > x_squeezed[-1])[0] - min_index = left_extrap[-1] if left_extrap.size else None - max_index = right_extrap[0] if right_extrap.size else None - return self.xyallout + (min_index, max_index) + low_extrap = np.where(self.x_morph_in < x_squeezed[0])[0] + high_extrap = np.where(self.x_morph_in > x_squeezed[-1])[0] + self.extrap_index_low = low_extrap[-1] if low_extrap.size else None + self.extrap_index_high = high_extrap[0] if high_extrap.size else None + return self.xyallout diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index 9ba0afdc..b589dc71 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -47,32 +47,40 @@ def test_morphsqueeze(x_morph, x_target, squeeze_coeffs): squeeze_polynomial = Polynomial(squeeze_coeffs) x_squeezed = x_morph + squeeze_polynomial(x_morph) y_morph = np.sin(x_squeezed) + low_extrap = np.where(x_morph < x_squeezed[0])[0] + high_extrap = np.where(x_morph > x_squeezed[-1])[0] + extrap_index_low_expected = low_extrap[-1] if low_extrap.size else None + extrap_index_high_expected = high_extrap[0] if high_extrap.size else None x_morph_expected = x_morph y_morph_expected = np.sin(x_morph) morph = MorphSqueeze() morph.squeeze = squeeze_coeffs - ( - x_morph_actual, - y_morph_actual, - x_target_actual, - y_target_actual, - low_extrap_idx, - high_extrap_idx, - ) = morph(x_morph, y_morph, x_target, y_target) - if low_extrap_idx is None and high_extrap_idx is None: - assert np.allclose(y_morph_actual, y_morph_expected, atol=1e-6) - else: - interp_start = low_extrap_idx + 1 if low_extrap_idx is not None else 0 - interp_end = ( - high_extrap_idx - if high_extrap_idx is not None - else len(y_morph_actual) - ) - assert np.allclose( - y_morph_actual[interp_start:interp_end], - y_morph_expected[interp_start:interp_end], - atol=1e-6, - ) + x_morph_actual, y_morph_actual, x_target_actual, y_target_actual = morph( + x_morph, y_morph, x_target, y_target + ) + extrap_index_low = morph.extrap_index_low + extrap_index_high = morph.extrap_index_high + if extrap_index_low is None: + extrap_index_low = 0 + elif extrap_index_high is None: + extrap_index_high = -1 + assert np.allclose( + y_morph_actual[extrap_index_low + 1 : extrap_index_high], + y_morph_expected[extrap_index_low + 1 : extrap_index_high], + atol=1e-6, + ) + assert np.allclose( + y_morph_actual[:extrap_index_low], + y_morph_expected[:extrap_index_low], + atol=1e-3, + ) + assert np.allclose( + y_morph_actual[extrap_index_high:], + y_morph_expected[extrap_index_high:], + atol=1e-3, + ) + assert morph.extrap_index_low == extrap_index_low_expected + assert morph.extrap_index_high == extrap_index_high_expected assert np.allclose(x_morph_actual, x_morph_expected) assert np.allclose(x_target_actual, x_target) assert np.allclose(y_target_actual, y_target) From fcee8207cfe7b08d8ac2247a6a3e7ff205d15ac0 Mon Sep 17 00:00:00 2001 From: Luis Kitsu Iglesias Date: Fri, 18 Apr 2025 16:10:06 -0600 Subject: [PATCH 9/9] test: made some coefficients smaller to pass tolerance --- tests/test_morphsqueeze.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_morphsqueeze.py b/tests/test_morphsqueeze.py index b589dc71..0de38e81 100644 --- a/tests/test_morphsqueeze.py +++ b/tests/test_morphsqueeze.py @@ -7,17 +7,17 @@ squeeze_coeffs_list = [ # The order of coefficients is [a0, a1, a2, ..., an] # Negative cubic squeeze coefficients - [-0.2, -0.01, -0.001, -0.0001], + [-0.01, -0.0005, -0.0005, -1e-6], # Positive cubic squeeze coefficients [0.2, 0.01, 0.001, 0.0001], # Positive and negative cubic squeeze coefficients [0.2, -0.01, 0.002, -0.0001], # Quadratic squeeze coefficients - [-0.2, 0.005, -0.007], + [-0.2, 0.005, -0.0004], # Linear squeeze coefficients [0.1, 0.3], # 4th order squeeze coefficients - [0.2, -0.01, 0.001, -0.001, 0.0004], + [0.2, -0.01, 0.001, -0.001, 0.0001], # Zeros and non-zeros, the full polynomial is applied [0, 0.03, 0, -0.0001], # Testing zeros, expect no squeezing @@ -36,7 +36,7 @@ # UC10: Morph range starts and ends earlier than target, same grid density (np.linspace(-2, 10, 121), np.linspace(0, 20, 201)), # UC12: Morph range wider than target, same grid density - (np.linspace(-2, 20, 221), np.linspace(0, 10, 101)), + (np.linspace(-2, 20, 201), np.linspace(0, 10, 101)), ]