Skip to content

Commit 1f197eb

Browse files
committed
improve test coverage
1 parent f7a813f commit 1f197eb

7 files changed

Lines changed: 88 additions & 3 deletions

File tree

src/aspire/covariance/covar2d.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ def _noise_correct_covar_rhs(self, b_covar, b_noise, noise_var, shrinker):
736736

737737
def _solve_covar(self, A_covar, b_covar, M, covar_est_opt):
738738
method = self._solve_covar_cg
739-
if all(isinstance(a, DiagMatrix) for a in A_covar):
739+
if all(isinstance(a, DiagMatrix) or a is None for a in A_covar):
740740
method = self._solve_covar_direct
741741

742742
return method(A_covar, b_covar, M, covar_est_opt)

src/aspire/numeric/cupy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ def atleast_1d(x):
1717
Returns same type as input.
1818
"""
1919
_fn = np.atleast_1d
20-
if cp and isinstance(x, cp.ndarray):
20+
if isinstance(x, cp.ndarray):
2121
_fn = cp.atleast_1d
2222
return _fn(x)

tests/test_FFBbasis2D.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ def testShift(self, basis):
128128
# Check pixel_size passthrough
129129
np.testing.assert_array_equal(f_imgs.pixel_size, f_shifted_imgs.pixel_size)
130130

131+
def testBadFilterLength(self, basis):
132+
filt = RadialCTFFilter(defocus=np.linspace(1000, 10000, 3)) # len 3
133+
with pytest.raises(RuntimeError, match=r".*Unexpected filter length.*"):
134+
# filter_to_basis_mat should enforce len 1
135+
_ = basis.filter_to_basis_mat(filt)
136+
131137

132138
params = [pytest.param(512, np.float32, marks=pytest.mark.expensive)]
133139

tests/test_FLEbasis2D.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from aspire.image import Image
1010
from aspire.nufft import backend_available
1111
from aspire.numeric import fft
12+
from aspire.operators import RadialCTFFilter
1213
from aspire.source import Simulation
1314
from aspire.volume import Volume
1415

@@ -122,6 +123,12 @@ def testEvaluateExpand(self, basis):
122123

123124
assert relerr(expand.asnumpy(), evaluate_t.asnumpy()) < basis.epsilon
124125

126+
def testBadFilterLength(self, basis):
127+
filt = RadialCTFFilter(defocus=np.linspace(1000, 10000, 3)) # len 3
128+
with pytest.raises(RuntimeError, match=r".*Unexpected filter length.*"):
129+
# filter_to_basis_mat should enforce len 1
130+
_ = basis.filter_to_basis_mat(filt)
131+
125132

126133
@pytest.mark.parametrize("basis", test_bases_match_fb, ids=show_fle_params)
127134
def testMatchFBEvaluate(basis):

tests/test_large_covar.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
from aspire.basis import FFBBasis2D, FLEBasis2D
1717
from aspire.covariance import BatchedRotCov2D
18-
from aspire.source import RelionSource
18+
from aspire.operators import RadialCTFFilter
19+
from aspire.source import RelionSource, Simulation
1920

2021
DTYPES = [
2122
np.float32,
@@ -139,3 +140,30 @@ def test_covar2d(preprocessed_src, basis, force_radial):
139140
cov2d = BatchedRotCov2D(preprocessed_src, basis, expand_method=expand_method)
140141
# smoke test
141142
_ = cov2d.get_covar()
143+
144+
145+
def test_covar2d_many_ctf():
146+
"""
147+
Smoke test for many CTF case using optimized radial expansion code path.
148+
"""
149+
# N must be >= 2048 to enable auto GPU filter eval branch
150+
# in covar2d _radial_filter_stack_to_basis_mats
151+
N = 2500
152+
L = 33
153+
dt = np.float32
154+
src = Simulation(
155+
C=1,
156+
n=N,
157+
L=L,
158+
filter_stack=RadialCTFFilter(defocus=np.linspace(10000, 20000, N)),
159+
offsets=0,
160+
amplitudes=1,
161+
dtype=dt,
162+
).cache()
163+
164+
basis = FLEBasis2D(L, dtype=dt)
165+
166+
cov2d = BatchedRotCov2D(src, basis, expand_method="radial")
167+
168+
# smoke test
169+
_ = cov2d.get_covar()

tests/test_preprocess_pipeline.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,28 @@ def testWhiten2(dtype):
192192
np.testing.assert_allclose(np.eye(2), corr_coef, atol=2e-1)
193193

194194

195+
@pytest.mark.parametrize("dtype", [np.float32, np.float64])
196+
def testWhitenNoCTF(dtype):
197+
"""
198+
Test operation with `filter_stack=None`.
199+
"""
200+
# Note this atol holds only for L even. Odd tested in testWhiten2.
201+
L = 64
202+
sim = get_sim_object(L, dtype)
203+
sim.filter_stack = None
204+
noise_estimator = AnisotropicNoiseEstimator(sim)
205+
sim = sim.whiten(noise_estimator)
206+
imgs_wt = sim.images[:num_images].asnumpy()
207+
208+
# calculate correlation between two neighboring pixels from background
209+
corr_coef = np.corrcoef(imgs_wt[:, L - 1, L - 1], imgs_wt[:, L - 2, L - 1])
210+
211+
# correlation matrix should be close to identity
212+
np.testing.assert_allclose(np.eye(2), corr_coef, atol=1e-1)
213+
# dtype of returned images should be the same
214+
assert dtype == imgs_wt.dtype
215+
216+
195217
@pytest.mark.parametrize("dtype", [np.float32, np.float64])
196218
def test_whiten_safeguard(dtype):
197219
"""Test that whitening safeguard works as expected."""

tests/test_utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import aspire
1515
from aspire import __version__
16+
from aspire.numeric import xp
1617
from aspire.utils import (
1718
LogFilterByCount,
1819
all_pairs,
@@ -498,3 +499,24 @@ def wrapper(*args, **kwargs):
498499
return func(*args, **kwargs)
499500

500501
return wrapper
502+
503+
504+
def test_atleast1d():
505+
"""
506+
Test xp.atleast_1d is agnostic to inputs.
507+
"""
508+
x = 1.0
509+
y = xp.asnumpy(xp.atleast_1d(x))
510+
ref = np.atleast_1d(x)
511+
np.testing.assert_allclose(y, ref)
512+
513+
x = np.arange(9)
514+
# x is host input
515+
y = xp.atleast_1d(x)
516+
# cp input when in GPU mode
517+
# xp functions should pass through as np otherwise
518+
y2 = xp.atleast_1d(xp.asarray(x))
519+
520+
ref = np.atleast_1d(x)
521+
np.testing.assert_allclose(xp.asnumpy(y), ref)
522+
np.testing.assert_allclose(xp.asnumpy(y2), ref)

0 commit comments

Comments
 (0)