From 796f088fbf968f862cd0053fe04701f4ca4dfd03 Mon Sep 17 00:00:00 2001
From: Cammille Carinan <cammille.carinan@xfel.eu>
Date: Fri, 21 May 2021 19:54:39 +0200
Subject: [PATCH] Try adding more tests

---
 src/toolbox_scs/base/knife_edge.py            | 15 ++++--------
 src/toolbox_scs/base/tests/test_knife_edge.py | 24 +++++++++++++++----
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/toolbox_scs/base/knife_edge.py b/src/toolbox_scs/base/knife_edge.py
index 0b64fee..e46cf6c 100644
--- a/src/toolbox_scs/base/knife_edge.py
+++ b/src/toolbox_scs/base/knife_edge.py
@@ -1,5 +1,5 @@
 import numpy as np
-from scipy.special import erfc
+from scipy import special
 from scipy.optimize import curve_fit
 
 
@@ -19,15 +19,13 @@ def knife_edge_base(positions, intensities, axisRange=None, p0=None):
     # Prepare arrays
     positions, intensities = prepare_arrays(positions, intensities, axisRange)
 
-    # Estimate a linear slope fitting the data to determine the erfc to use
-    slope = covariance(positions, intensities) / np.var(positions)
-    func = generate_erfc(sign=np.sign(slope) * -1)
+    # Estimate initial fitting params
     if p0 is None:
         p0 = [np.mean(positions), 0.1, np.max(intensities) / 2, 0]
 
     # Fit
     try:
-        popt, pcov = curve_fit(func, positions, intensities, p0=p0)
+        popt, pcov = curve_fit(erfc, positions, intensities, p0=p0)
     except (TypeError, RuntimeError):
         print("Fit did not converge.")
         popt, pcov = (None, None)
@@ -76,8 +74,5 @@ def covariance(a: np.ndarray, b: np.ndarray):
     return np.cov(a, b)[0][1]
 
 
-def generate_erfc(sign):
-    def func(x, x0, w0, a, b):
-        return a * erfc(sign * np.sqrt(2) * (x - x0) / w0) + b
-
-    return func
+def erfc(x, x0, w0, a, b):
+    return a * special.erfc(np.sqrt(2) * (x - x0) / w0) + b
diff --git a/src/toolbox_scs/base/tests/test_knife_edge.py b/src/toolbox_scs/base/tests/test_knife_edge.py
index a1cd9ae..1f06990 100644
--- a/src/toolbox_scs/base/tests/test_knife_edge.py
+++ b/src/toolbox_scs/base/tests/test_knife_edge.py
@@ -1,7 +1,7 @@
 import numpy as np
 import pytest
 
-from ..knife_edge import prepare_arrays, range_mask
+from ..knife_edge import erfc, knife_edge_base, prepare_arrays, range_mask
 
 
 def test_range_mask():
@@ -58,7 +58,7 @@ def test_prepare_arrays_nans():
     assert intensities.shape == (size,)
 
     # Test finite motors and signals with NaNs
-    signal_nan = with_values(signal, value=np.nan, num=20)
+    signal_nan = _with_values(signal, value=np.nan, num=20)
     positions, intensities = prepare_arrays(motor, signal_nan)
     assert positions.shape == (size-20,)
     assert np.isfinite(positions).all()
@@ -66,7 +66,7 @@ def test_prepare_arrays_nans():
     assert np.isfinite(intensities).all()
 
     # Test finite signals and motors with NaNs
-    motor_nan = with_values(motor, value=np.nan, num=3)
+    motor_nan = _with_values(motor, value=np.nan, num=3)
     positions, intensities = prepare_arrays(motor_nan, signal)
     assert positions.shape == ((trains-3) * pulses,)
     assert np.isfinite(positions).all()
@@ -91,7 +91,23 @@ def test_prepare_arrays_size():
     assert intensities.shape == (size,)
 
 
-def with_values(array, value, num=5):
+def test_knife_edge_base():
+    p0 = [0, -1.5, 1, 0]
+    x = np.linspace(-3, 3)
+    y = erfc(x, *p0)
+    noise = y * np.random.normal(0, .02, y.shape)  # 2% error
+    eff_y = (y + noise).reshape(1, -1)
+
+    # Test noisy data
+    popt, _ = knife_edge_base(x, eff_y)
+    np.testing.assert_allclose(p0, popt, atol=1e-1)
+
+    # Test flipped data
+    popt, _ = knife_edge_base(x, eff_y[::-1])
+    np.testing.assert_allclose(p0, popt, atol=1e-1)
+
+
+def _with_values(array, value, num=5):
     copy = array.astype(np.float)
     copy.ravel()[np.random.choice(copy.size, num, replace=False)] = value
     return copy
-- 
GitLab