@@ -213,31 +213,39 @@ def test_find_subpixel_peak_position():
213213 find_subpixel_peak_position (corr_gauss , subpixel_method = "invalid_method" )
214214
215215def test_vectorized_sig2noise_ratio ():
216- """Test vectorized_sig2noise_ratio function"""
217- # Create a simple correlation map with a clear peak
218- corr = np .zeros ((3 , 5 , 5 ))
216+ """Test vectorized_sig2noise_ratio function
219217
220- # First correlation map: clear peak
221- corr [0 , 2 , 2 ] = 1.0
222- corr [0 , :2 , :] = 0.1
223- corr [0 , 3 :, :] = 0.1
218+ The correlation maps are 16 x 16 with all peaks away from the map
219+ borders, so no window trips the validity flag (weak or border peaks)
220+ and every ratio stays positive.
221+ """
222+ corr = np .full ((3 , 16 , 16 ), 0.05 )
224223
225- # Second correlation map: two peaks
226- corr [1 , 2 , 2 ] = 1.0
227- corr [1 , 0 , 0 ] = 0.5
224+ # First correlation map: clear peak, faint interior second peak
225+ corr [0 , 8 , 8 ] = 1.0
226+ corr [0 , 4 , 4 ] = 0.1
228227
229- # Third correlation map: noisy
230- corr [2 , 2 , 2 ] = 0.3
231- corr [2 ] = corr [2 ] + 0.1
228+ # Second correlation map: two interior peaks; the secondary one at
229+ # (8, 10) sits inside the width=2 exclusion box but outside the
230+ # width=1 box, so the ratio must depend on the chosen width
231+ corr [1 , 8 , 8 ] = 1.0
232+ corr [1 , 8 , 10 ] = 0.5
233+ corr [1 , 4 , 4 ] = 0.3
234+
235+ # Third correlation map: noisy, two interior peaks of similar height
236+ corr [2 , 8 , 8 ] = 0.4
237+ corr [2 , 4 , 12 ] = 0.35
232238
233239 # Test peak2peak method
234240 s2n_p2p = vectorized_sig2noise_ratio (corr , sig2noise_method = 'peak2peak' , width = 1 )
235241 assert s2n_p2p .shape == (3 ,)
242+ assert np .all (s2n_p2p > 0 ) # no window is flagged
236243 assert s2n_p2p [0 ] > s2n_p2p [2 ] # Clear peak should have higher S2N than noisy
237244
238245 # Test peak2mean method
239246 s2n_p2m = vectorized_sig2noise_ratio (corr , sig2noise_method = 'peak2mean' )
240247 assert s2n_p2m .shape == (3 ,)
248+ assert np .all (s2n_p2m > 0 ) # no window is flagged
241249 assert s2n_p2m [0 ] > s2n_p2m [2 ] # Clear peak should have higher S2N than noisy
242250
243251 # Test with different width
@@ -249,6 +257,45 @@ def test_vectorized_sig2noise_ratio():
249257 with pytest .raises (Exception ):
250258 vectorized_sig2noise_ratio (corr , sig2noise_method = 'invalid_method' )
251259
260+ def test_vectorized_sig2noise_ratio_flags_invalid_windows ():
261+ """Windows failing the validity checks must return a zero ratio.
262+
263+ Regression test: ``peak2peak[flag is True] = 0`` indexed with the
264+ Python expression ``flag is True`` (a constant ``False``), which numpy
265+ treats as an empty boolean mask, so the flag was silently never
266+ applied and invalid windows leaked raw ratios.
267+ """
268+ corr = np .full ((4 , 16 , 16 ), 0.05 )
269+
270+ # Window 0: healthy interior peaks -> must stay positive
271+ corr [0 , 8 , 8 ] = 1.0
272+ corr [0 , 4 , 4 ] = 0.5
273+
274+ # Window 1: first peak on the map border
275+ corr [1 , 0 , 5 ] = 1.0
276+ corr [1 , 8 , 8 ] = 0.5
277+
278+ # Window 2: no signal (first peak below the 1e-3 threshold)
279+ corr [2 ] = 1e-5
280+ corr [2 , 8 , 8 ] = 5e-4
281+
282+ # Window 3: healthy first peak but second peak on the map border
283+ corr [3 , 8 , 8 ] = 1.0
284+ corr [3 , 0 , 3 ] = 0.9
285+
286+ s2n_p2p = vectorized_sig2noise_ratio (corr , sig2noise_method = 'peak2peak' , width = 1 )
287+ assert s2n_p2p [0 ] > 0
288+ assert s2n_p2p [1 ] == 0 # border first peak
289+ assert s2n_p2p [2 ] == 0 # no signal
290+ assert s2n_p2p [3 ] == 0 # border second peak
291+
292+ # peak2mean only checks the first peak
293+ s2n_p2m = vectorized_sig2noise_ratio (corr , sig2noise_method = 'peak2mean' )
294+ assert s2n_p2m [0 ] > 0
295+ assert s2n_p2m [1 ] == 0 # border first peak
296+ assert s2n_p2m [2 ] == 0 # no signal
297+ assert s2n_p2m [3 ] > 0 # second peak is irrelevant for peak2mean
298+
252299def test_fft_correlate_images ():
253300 """Test fft_correlate_images function"""
254301 # Create simple test images
0 commit comments