Skip to content

Commit ae3f699

Browse files
committed
improve tests for the peak position error; fine-tune the major peak-detecting function
1 parent 6ac077b commit ae3f699

2 files changed

Lines changed: 32 additions & 18 deletions

File tree

src/fairmd/lipids/analib/formfactor.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
import numpy as np
44
import scipy.interpolate
55
import scipy.signal
6-
from scipy.optimize import curve_fit
76

87

98
def get_mins_from_ffdata(ffdata: np.ndarray) -> list[float]:
109
"""Find the positions of minimums in form factor data."""
11-
sg_window_q = 0.03 # Savitsky-Golay window (in Q)
10+
sg_window_q = 0.05 # Savitsky-Golay window (in Q)
1211
delta_q = ffdata[1, 0] - ffdata[0, 0] # Q step in FF data
1312
sg_window_n = int(np.ceil(sg_window_q / delta_q)) # S-G window (in num frames)
1413
try:
@@ -19,7 +18,8 @@ def get_mins_from_ffdata(ffdata: np.ndarray) -> list[float]:
1918

2019
min_q_distance = 0.01 # Min distance btw peaks (in Q)
2120
mqd_n = int(np.ceil(min_q_distance / delta_q)) # same in num frames
22-
peak_ind = scipy.signal.find_peaks(-filtered, distance=mqd_n)
21+
peak_prominence = (filtered.max() - filtered.min()) * 0.1
22+
peak_ind = scipy.signal.find_peaks(-filtered, distance=mqd_n, prominence=peak_prominence)
2323
min_peak_q = 0.1
2424

2525
return [ffdata[i, 0] for i in peak_ind[0] if ffdata[i, 0] > min_peak_q]
@@ -77,5 +77,9 @@ def calc_minpos_with_error(ffdata: np.ndarray) -> (float, float):
7777
)
7878
a, b, _c = popt
7979
min_x = -b / 2 / a
80-
delta_minx = (-1/2/a)**2*pcov[0, 0] + (b/2/a**2)**2*pcov[1, 1] + 2*(-1/2/a)*(b/2/a**2)*pcov[0, 1]
80+
delta_minx = (
81+
(-1 / 2 / a) ** 2 * pcov[0, 0]
82+
+ (b / 2 / a**2) ** 2 * pcov[1, 1]
83+
+ 2 * (-1 / 2 / a) * (b / 2 / a**2) * pcov[0, 1]
84+
)
8185
return min_x, np.sqrt(delta_minx)

tests/test_formfactor.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,32 @@ def test_estimate_error_of_min():
5757
abs=1e-3,
5858
msg="Error of minimum with no error is not estimated as err=0.1 [const]",
5959
)
60-
# Case 1: constant error
61-
# sin(8x) = 0
62-
# 8x = pi*n => x = pi*n/8
63-
#
64-
# Error must be estimated as following: we down the curve by the value of error and find intersections
65-
# with x axis. The error is the mean distance between the minimum and these intersections. In this
66-
# case, the intersections are defined by the equation:
67-
#
68-
# |sin(8x)|-0.1 = 0 =>> |sin(8x)| = 0.1 =>> sin(8x) = 0.1 or sin(8x) = -0.1, i.e.,
69-
#
70-
# x = +-arcsin(0.1)/8 + pi*n/8; so error should be arcsin(0.1)/8
71-
#
60+
# Case 1: 2 constant errors
7261
pos_comp, err_comp = calc_minpos_with_error(synt_data)
62+
synt_data[:, 2] = 0.2
63+
pos_berr, err_berr = calc_minpos_with_error(synt_data)
64+
check.less(
65+
err_comp,
66+
err_berr,
67+
msg="Error of minimum with constant error 0.2 must be > than with err 0.1",
68+
)
7369
check.almost_equal(
70+
pos_comp,
71+
pos_berr,
72+
abs=1e-5,
73+
msg="Minimum position with constant error 0.2 must be close to minimum position with constant error 0.1",
74+
)
75+
# Case 2: noise
76+
synt_data[:, 1] += 0.05 * np.random.rand(1000) - 0.025
77+
pos_noised, err_noised = calc_minpos_with_error(synt_data)
78+
check.less(
7479
err_comp,
75-
np.arcsin(0.1) / 8,
80+
err_noised,
81+
msg="Error of minimum with noise is not greater than error of minimum with constant error",
82+
)
83+
check.almost_equal(
84+
pos_comp,
85+
pos_noised,
7686
abs=1e-3,
77-
msg="Error of minimum with constant error is not estimated correctly",
87+
msg="Minimum position with and w/o noise should be similar",
7888
)

0 commit comments

Comments
 (0)