From 4b80d15c267fc515d93d88a4f43997f2fc10a1dc Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 10:09:39 -0400 Subject: [PATCH 01/14] Remove Numpy 1 limitation --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 712eaa8f11..c4eabef52f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ dependencies = [ "joblib", "matplotlib >= 3.2.0", "mrcfile", - "numpy>=1.21.5, <2.0.0", + "numpy>=1.21.5", "packaging", "pooch>=1.7.0", "pillow", From af32d27f70b89dee75425bdc31e846c422451eee Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 10:14:07 -0400 Subject: [PATCH 02/14] latest np2, Inf to inf --- src/aspire/basis/basis.py | 4 ++-- src/aspire/basis/fb_2d.py | 4 ++-- src/aspire/basis/fb_3d.py | 4 ++-- src/aspire/basis/fle_2d.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/aspire/basis/basis.py b/src/aspire/basis/basis.py index 23c770674a..ee6aee2d02 100644 --- a/src/aspire/basis/basis.py +++ b/src/aspire/basis/basis.py @@ -373,9 +373,9 @@ def __init__(self, size, ell_max=None, dtype=np.float32): :param size: The size of the vectors for which to define the basis. Currently only square images and cubic volumes are supported. :param ell_max: The maximum order ell of the basis elements. If no input - (= None), it will be set to np.Inf and the basis includes all + (= None), it will be set to np.inf and the basis includes all ell such that the resulting basis vectors are concentrated - below the Nyquist frequency (default Inf). + below the Nyquist frequency (default inf). """ if ell_max is None: ell_max = np.inf diff --git a/src/aspire/basis/fb_2d.py b/src/aspire/basis/fb_2d.py index 2698e41ed6..18f7b83478 100644 --- a/src/aspire/basis/fb_2d.py +++ b/src/aspire/basis/fb_2d.py @@ -31,9 +31,9 @@ def __init__(self, size, ell_max=None, dtype=np.float32): May be a 2-tuple or an integer, in which case a square basis is assumed. Currently only square images are supported. :ell_max: The maximum order ell of the basis elements. If no input - (= None), it will be set to np.Inf and the basis includes all + (= None), it will be set to np.inf and the basis includes all ell such that the resulting basis vectors are concentrated - below the Nyquist frequency (default Inf). + below the Nyquist frequency (default inf). """ if isinstance(size, int): diff --git a/src/aspire/basis/fb_3d.py b/src/aspire/basis/fb_3d.py index b787ff618f..dedd52025c 100644 --- a/src/aspire/basis/fb_3d.py +++ b/src/aspire/basis/fb_3d.py @@ -26,9 +26,9 @@ def __init__(self, size, ell_max=None, dtype=np.float32): May be a 3-tuple or an integer, in which case a cubic basis is assumed. Currently only cubic images are supported. :param ell_max: The maximum order ell of the basis elements. If no input - (= None), it will be set to np.Inf and the basis includes all + (= None), it will be set to np.inf and the basis includes all ell such that the resulting basis vectors are concentrated - below the Nyquist frequency (default Inf). + below the Nyquist frequency (default inf). """ if isinstance(size, int): size = (size, size, size) diff --git a/src/aspire/basis/fle_2d.py b/src/aspire/basis/fle_2d.py index 76330e6fba..ffce0ea284 100644 --- a/src/aspire/basis/fle_2d.py +++ b/src/aspire/basis/fle_2d.py @@ -358,7 +358,7 @@ def _lap_eig_disk(self): num_ells = 1 + 2 * max_ell self._ells = np.zeros((num_ells, max_k), dtype=int) self._ks = np.zeros((num_ells, max_k), dtype=int) - self.bessel_zeros = np.ones((num_ells, max_k), dtype=np.float64) * np.Inf + self.bessel_zeros = np.ones((num_ells, max_k), dtype=np.float64) * np.inf # keep track of which order Bessel function we're on self._ells[0, :] = 0 From 03aceb8d1be7059c73906125c9797d8e36e19735 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 10:48:23 -0400 Subject: [PATCH 03/14] row_stack to vstack --- src/aspire/basis/fpswf_2d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspire/basis/fpswf_2d.py b/src/aspire/basis/fpswf_2d.py index 21be9270d2..6eac1a91db 100644 --- a/src/aspire/basis/fpswf_2d.py +++ b/src/aspire/basis/fpswf_2d.py @@ -87,7 +87,7 @@ def _precomp(self): self.quad_rule_radial_wts = e self.num_angular_pts = f - us_fft_pts = np.row_stack((self.quad_rule_pts_x, self.quad_rule_pts_y)) + us_fft_pts = np.vstack((self.quad_rule_pts_x, self.quad_rule_pts_y)) us_fft_pts = self.bandlimit / self.rcut * us_fft_pts ( blk_r, From 2d43bf300b366514c720b6afd06f192dab721c24 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 10:58:51 -0400 Subject: [PATCH 04/14] np2 copy False -> None --- src/aspire/abinitio/commonline_base.py | 2 +- src/aspire/abinitio/commonline_c3_c4.py | 2 +- src/aspire/abinitio/commonline_d2.py | 4 ++-- src/aspire/abinitio/commonline_sync3n.py | 18 +++++++++--------- src/aspire/apple/picking.py | 4 ++-- src/aspire/basis/basis.py | 2 +- src/aspire/basis/fle_2d.py | 8 +++----- src/aspire/basis/fpswf_2d.py | 2 +- src/aspire/classification/averager2d.py | 2 +- src/aspire/classification/rir_class2d.py | 2 +- src/aspire/ctf/ctf_estimator.py | 4 ++-- src/aspire/image/image.py | 6 +++--- src/aspire/nufft/cufinufft.py | 2 +- src/aspire/nufft/finufft.py | 4 ++-- src/aspire/numeric/complex_pca/validation.py | 10 +++++----- src/aspire/numeric/pyfftw_fft.py | 2 +- src/aspire/operators/blk_diag_matrix.py | 4 ++-- src/aspire/operators/diag_matrix.py | 2 +- src/aspire/reconstruction/mean.py | 2 +- src/aspire/sinogram/sinogram.py | 2 +- src/aspire/source/micrograph.py | 2 +- src/aspire/utils/bot_align.py | 8 ++++---- src/aspire/utils/matrix.py | 2 +- src/aspire/utils/misc.py | 6 +++--- src/aspire/utils/rotation.py | 6 +++--- src/aspire/volume/volume.py | 2 +- tests/test_FFBbasis3D.py | 4 ++-- tests/test_coef.py | 8 ++++---- tests/test_complexPCA.py | 2 +- tests/test_diag_matrix.py | 2 +- tests/test_downsample.py | 4 ++-- tests/test_matrix.py | 4 ++-- tests/test_mean_estimator.py | 4 ++-- tests/test_micrograph_source.py | 2 +- tests/test_orient_sdp.py | 2 +- tests/test_polar_ft.py | 2 +- tests/test_simulation.py | 2 +- tests/test_volume.py | 6 +++--- 38 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/aspire/abinitio/commonline_base.py b/src/aspire/abinitio/commonline_base.py index fe456c645e..2cd80b61fa 100644 --- a/src/aspire/abinitio/commonline_base.py +++ b/src/aspire/abinitio/commonline_base.py @@ -149,7 +149,7 @@ def _prepare_pf(self): # Apply mask in doubles (allow imgs to upcast as needed) imgs = imgs * fuzz_mask # Cast to desired type - imgs = Image(imgs.asnumpy().astype(self.dtype, copy=False)) + imgs = Image(imgs.asnumpy().astype(self.dtype, copy=None)) # Obtain coefficients of polar Fourier transform for input 2D images pft = PolarFT( diff --git a/src/aspire/abinitio/commonline_c3_c4.py b/src/aspire/abinitio/commonline_c3_c4.py index 242094b745..bc2956ec0d 100644 --- a/src/aspire/abinitio/commonline_c3_c4.py +++ b/src/aspire/abinitio/commonline_c3_c4.py @@ -693,7 +693,7 @@ def _J_sync_power_method(self, vijs): while itr < max_iters and residual > epsilon: itr += 1 # Note, this appears to need double precision for accuracy in the following division. - vec_new = self._signs_times_v(vijs, vec).astype(np.float64, copy=False) + vec_new = self._signs_times_v(vijs, vec).astype(np.float64, copy=None) vec_new = vec_new / norm(vec_new) residual = norm(vec_new - vec) vec = vec_new diff --git a/src/aspire/abinitio/commonline_d2.py b/src/aspire/abinitio/commonline_d2.py index a8e951c642..93b2e9bc0a 100644 --- a/src/aspire/abinitio/commonline_d2.py +++ b/src/aspire/abinitio/commonline_d2.py @@ -1149,12 +1149,12 @@ def _sync_colors(self, Rijs): # Seed eigs initial vector for iterative method. # scipy LinearOperator needs doubles for some architectures (arm). - v0 = randn(3 * n_pairs, seed=self.seed).astype(np.float64, copy=False) + v0 = randn(3 * n_pairs, seed=self.seed).astype(np.float64, copy=None) v0 = v0 / norm(v0) vals, colors = la.eigs(color_mat, k=3, which="LR", v0=v0) vals = np.real(vals) - colors = np.real(colors).astype(self.dtype, copy=False) + colors = np.real(colors).astype(self.dtype, copy=None) colors = np.sign(colors[0]) * colors # Stable eigs cp, _ = self._unmix_colors(colors[:, :2]) diff --git a/src/aspire/abinitio/commonline_sync3n.py b/src/aspire/abinitio/commonline_sync3n.py index 5afa771c69..aa11a2348a 100644 --- a/src/aspire/abinitio/commonline_sync3n.py +++ b/src/aspire/abinitio/commonline_sync3n.py @@ -197,7 +197,7 @@ def _sync3n_S_to_rot(self, S, W=None, n_eigs=4): """ # Critical this occurs in double precision - S = S.astype(np.float64, copy=False) + S = S.astype(np.float64, copy=None) if n_eigs < 3: raise ValueError( @@ -213,7 +213,7 @@ def _sync3n_S_to_rot(self, S, W=None, n_eigs=4): ) # Initialize D # Critical this occurs in double precision - W = W.astype(np.float64, copy=False) + W = W.astype(np.float64, copy=None) D = np.mean(W, axis=1) Dhalf = D @@ -664,8 +664,8 @@ def _pairs_probabilities_cupy(self, Rijs, P2, A, a, B, b, x0): ) # accumulate over thread results - ln_f_arb = ln_f_arb_dev.get().astype(self.dtype, copy=False) - ln_f_ind = ln_f_ind_dev.get().astype(self.dtype, copy=False) + ln_f_arb = ln_f_arb_dev.get().astype(self.dtype, copy=None) + ln_f_ind = ln_f_ind_dev.get().astype(self.dtype, copy=None) return ln_f_ind, ln_f_arb @@ -748,8 +748,8 @@ def fun(x, B, P, b, x0, A=A, a=a): popt, pcov = curve_fit( fun, - hist_x.astype(np.float64, copy=False), - scores_hist.astype(np.float64, copy=False), + hist_x.astype(np.float64, copy=None), + scores_hist.astype(np.float64, copy=None), p0=start_values, bounds=(lower_bounds, upper_bounds), method="trf", # MATLAB used method "LAR" with algo "Trust-Region" @@ -1043,7 +1043,7 @@ def _J_sync_power_method(self, Rijs): while itr < max_iters and residual > epsilon: itr += 1 # Todo, this code code actually needs double precision for accuracy... forcing. - vec_new = self._signs_times_v(Rijs, vec).astype(np.float64, copy=False) + vec_new = self._signs_times_v(Rijs, vec).astype(np.float64, copy=None) vec_new = vec_new / norm(vec_new) residual = norm(vec_new - vec) vec = vec_new @@ -1073,7 +1073,7 @@ def _signs_times_v(self, Rijs, vec): else: new_vec = self._signs_times_v_host(Rijs, vec) - return new_vec.astype(vec.dtype, copy=False) + return new_vec.astype(vec.dtype, copy=None) def _signs_times_v_host(self, Rijs, vec): """ @@ -1177,7 +1177,7 @@ def _signs_times_v_cupy(self, Rijs, vec): ) # dtoh - new_vec = new_vec_dev.get().astype(vec.dtype, copy=False) + new_vec = new_vec_dev.get().astype(vec.dtype, copy=None) return new_vec diff --git a/src/aspire/apple/picking.py b/src/aspire/apple/picking.py index d64d16c773..d54cf61f1d 100644 --- a/src/aspire/apple/picking.py +++ b/src/aspire/apple/picking.py @@ -149,7 +149,7 @@ def read_micrograph(self): self.original_im = ( DiskMicrographSource(self.filename) .asnumpy()[0] - .astype(np.float32, copy=False) + .astype(np.float32, copy=None) ) # Discard outer pixels @@ -167,7 +167,7 @@ def read_micrograph(self): # Note, float64 required for signal.correlate call accuracy. im = np.asarray( PILImage.fromarray(im).resize(size, PILImage.Resampling.BICUBIC) - ).astype(np.float64, copy=False) + ).astype(np.float64, copy=None) im = signal.correlate( im, diff --git a/src/aspire/basis/basis.py b/src/aspire/basis/basis.py index ee6aee2d02..6baf16f769 100644 --- a/src/aspire/basis/basis.py +++ b/src/aspire/basis/basis.py @@ -62,7 +62,7 @@ def __init__(self, basis, data, dtype=None): ) self.basis = basis - self._data = data.astype(self.dtype, copy=False) + self._data = data.astype(self.dtype, copy=None) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 1 diff --git a/src/aspire/basis/fle_2d.py b/src/aspire/basis/fle_2d.py index ffce0ea284..6499919110 100644 --- a/src/aspire/basis/fle_2d.py +++ b/src/aspire/basis/fle_2d.py @@ -314,7 +314,7 @@ def _compute_nufft_points(self): ) grid_xy[0] = xp.cos(phi) # x grid_xy[1] = xp.sin(phi) # y - grid_xy = grid_xy * nodes * h + grid_xy[:] = grid_xy * nodes * h self.grid_xy = grid_xy.reshape(2, -1) def _build_interpolation_matrix(self): @@ -643,7 +643,7 @@ def _step1(self, z): num_img = z.shape[0] z = z[:, :, : self.num_angular_nodes // 2].reshape(num_img, -1) im = anufft( - z.astype(complex_type(self.dtype), copy=False), + z.astype(complex_type(self.dtype), copy=None), self.grid_xy, (self.nres, self.nres), epsilon=self.epsilon, @@ -798,9 +798,7 @@ def filter_to_basis_mat(self, f, **kwargs): omega = 2 * xp.pi * xp.vstack((omegax.flatten("C"), omegay.flatten("C"))) h_vals2d = ( - xp.asarray(h_fun(omega)) - .reshape(n_k, n_theta) - .astype(self.dtype, copy=False) + xp.asarray(h_fun(omega)).reshape(n_k, n_theta).astype(self.dtype, copy=None) ) h_vals = xp.sum(h_vals2d, axis=1) / n_theta diff --git a/src/aspire/basis/fpswf_2d.py b/src/aspire/basis/fpswf_2d.py index 6eac1a91db..aa7b9913d9 100644 --- a/src/aspire/basis/fpswf_2d.py +++ b/src/aspire/basis/fpswf_2d.py @@ -99,7 +99,7 @@ def _precomp(self): ) = self._pswf_integration_sub_routine() self.us_fft_pts = us_fft_pts.astype( - self.dtype, copy=False + self.dtype, copy=None ) # TODO, debug where this is incorrect dtype self.blk_r = blk_r self.num_angular_pts = num_angular_pts diff --git a/src/aspire/classification/averager2d.py b/src/aspire/classification/averager2d.py index b447a6d91c..644359c9e7 100644 --- a/src/aspire/classification/averager2d.py +++ b/src/aspire/classification/averager2d.py @@ -82,7 +82,7 @@ def _cls_images(self, cls, src=None): source for a certain operation (ie alignment). """ src = src or self.src - return src.images[cls].asnumpy().astype(self.dtype, copy=False) + return src.images[cls].asnumpy().astype(self.dtype, copy=None) class AligningAverager2D(Averager2D): diff --git a/src/aspire/classification/rir_class2d.py b/src/aspire/classification/rir_class2d.py index 19a3479ffe..dde35ef050 100644 --- a/src/aspire/classification/rir_class2d.py +++ b/src/aspire/classification/rir_class2d.py @@ -390,7 +390,7 @@ def _sk_pca(self, M): # We use an extension of SK that is hacked to admit complex. pca = ComplexPCA( self.bispectrum_components, - copy=False, # careful, overwrites data matrix... we'll handle the copies. + copy=None, # careful, overwrites data matrix... we'll handle the copies. svd_solver="auto", # use randomized (Halko) for larger problems random_state=self.seed, ) diff --git a/src/aspire/ctf/ctf_estimator.py b/src/aspire/ctf/ctf_estimator.py index b6983cb071..39f2998a21 100644 --- a/src/aspire/ctf/ctf_estimator.py +++ b/src/aspire/ctf/ctf_estimator.py @@ -241,7 +241,7 @@ def estimate_psd(self, blocks, tapers_1d): """ num_1d_tapers = tapers_1d.shape[-1] - tapers_1d = tapers_1d.astype(complex_type(self.dtype), copy=False) + tapers_1d = tapers_1d.astype(complex_type(self.dtype), copy=None) blocks_mt = np.zeros(blocks[0, :, :].shape, dtype=self.dtype) @@ -768,7 +768,7 @@ def estimate_ctf( micrograph = mrc.data # Try to match dtype used in Basis instance - micrograph = micrograph.astype(dtype, copy=False) + micrograph = micrograph.astype(dtype, copy=None) micrograph_blocks = ctf_object.preprocess_micrograph(micrograph, psd_size) diff --git a/src/aspire/image/image.py b/src/aspire/image/image.py index 757362870d..6d0f3b8960 100644 --- a/src/aspire/image/image.py +++ b/src/aspire/image/image.py @@ -195,7 +195,7 @@ def __init__(self, data, pixel_size=None, dtype=None): if not data.shape[-1] == data.shape[-2]: raise ValueError("Only square ndarrays are supported.") - self._data = data.astype(self.dtype, copy=False) + self._data = data.astype(self.dtype, copy=None) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 2 @@ -543,7 +543,7 @@ def load(filepath, dtype=None): # Attempt casting when user provides dtype if dtype is not None: - im = im.astype(dtype, copy=False) + im = im.astype(dtype, copy=None) # Return as Image instance return Image(im, pixel_size=pixel_size) @@ -658,7 +658,7 @@ def backproject(self, rot_matrices, symmetry_group=None, zero_nyquist=True): # TODO: rotated_grids might as well give us correctly shaped array in the first place pts_rot = aspire.volume.rotated_grids(L, rotations).astype( - self.dtype, copy=False + self.dtype, copy=None ) pts_rot = pts_rot.reshape((3, -1)) diff --git a/src/aspire/nufft/cufinufft.py b/src/aspire/nufft/cufinufft.py index fd869aacfd..2660f4ea46 100644 --- a/src/aspire/nufft/cufinufft.py +++ b/src/aspire/nufft/cufinufft.py @@ -30,7 +30,7 @@ def __init__(self, sz, fourier_pts, epsilon=1e-8, ntransforms=1, **kwargs): # ASPIRE-Python/703 # Cast to doubles. self._original_dtype = fourier_pts.dtype - fourier_pts = fourier_pts.astype(np.float64, copy=False) + fourier_pts = fourier_pts.astype(np.float64, copy=None) # Basic dtype passthough. dtype = fourier_pts.dtype diff --git a/src/aspire/nufft/finufft.py b/src/aspire/nufft/finufft.py index efc1a062f2..e396d76124 100644 --- a/src/aspire/nufft/finufft.py +++ b/src/aspire/nufft/finufft.py @@ -99,7 +99,7 @@ def transform(self, signal): ), f"Signal frame to be transformed must have shape {self.sz}" # FINUFFT was designed for a complex input array - signal = np.array(signal, copy=False, dtype=self.complex_dtype, order="C") + signal = np.array(signal, copy=None, dtype=self.complex_dtype, order="C") result = self._transform_plan.execute(signal) @@ -130,7 +130,7 @@ def adjoint(self, signal): signal = signal.reshape(self.num_pts) # FINUFFT was designed for a complex input array - signal = np.array(signal, copy=False, dtype=self.complex_dtype, order="C") + signal = np.array(signal, copy=None, dtype=self.complex_dtype, order="C") result = self._adjoint_plan.execute(signal) diff --git a/src/aspire/numeric/complex_pca/validation.py b/src/aspire/numeric/complex_pca/validation.py index 7fafedfe18..11d7aaba9f 100644 --- a/src/aspire/numeric/complex_pca/validation.py +++ b/src/aspire/numeric/complex_pca/validation.py @@ -81,7 +81,7 @@ def _ensure_sparse_format( Data type of result. If None, the dtype of the input is preserved. copy : boolean - Whether a forced copy will be triggered. If copy=False, a copy might + Whether a forced copy will be triggered. If copy=None, a copy might be triggered by a conversion. force_all_finite : boolean or 'allow-nan', (default=True) @@ -173,7 +173,7 @@ def check_array( accept_large_sparse=True, dtype="numeric", order=None, - copy=False, + copy=None, force_all_finite=True, ensure_2d=True, allow_nd=False, @@ -216,13 +216,13 @@ def check_array( order : 'F', 'C' or None (default=None) Whether an array will be forced to be fortran or c-style. - When order is None (default), then if copy=False, nothing is ensured + When order is None (default), then if copy=None, nothing is ensured about the memory layout of the output array; otherwise (copy=True) the memory layout of the returned array is kept as close as possible to the original array. copy : boolean (default=False) - Whether a forced copy will be triggered. If copy=False, a copy might + Whether a forced copy will be triggered. If copy=None, a copy might be triggered by a conversion. force_all_finite : boolean or 'allow-nan', (default=True) @@ -365,7 +365,7 @@ def check_array( array = np.asarray(array, order=order) if array.dtype.kind == "f": _assert_all_finite(array, allow_nan=False, msg_dtype=dtype) - array = array.astype(dtype, casting="unsafe", copy=False) + array = array.astype(dtype, casting="unsafe", copy=None) else: array = np.asarray(array, order=order, dtype=dtype) except ComplexWarning: diff --git a/src/aspire/numeric/pyfftw_fft.py b/src/aspire/numeric/pyfftw_fft.py index 95a8ea80f7..4503b42b38 100644 --- a/src/aspire/numeric/pyfftw_fft.py +++ b/src/aspire/numeric/pyfftw_fft.py @@ -139,7 +139,7 @@ def ifftn(self, a, axes=None, workers=-1): # FFTW_BACKWARD requires complex input array, cast as needed. # See https://pyfftw.readthedocs.io/en/latest/source/pyfftw/pyfftw.html#scheme-table comp_type = complex_type(a.dtype) - a = a.astype(comp_type, copy=False) + a = a.astype(comp_type, copy=None) mutex.acquire() try: diff --git a/src/aspire/operators/blk_diag_matrix.py b/src/aspire/operators/blk_diag_matrix.py index 3e493f9525..af882ecc68 100644 --- a/src/aspire/operators/blk_diag_matrix.py +++ b/src/aspire/operators/blk_diag_matrix.py @@ -91,7 +91,7 @@ def append(self, blk): :param blk: Block to append (ndarray). """ - self.data.append(blk.astype(self.dtype, copy=False)) + self.data.append(blk.astype(self.dtype, copy=None)) self.nblocks += 1 self.reset_cache() @@ -130,7 +130,7 @@ def __setitem__(self, key, value): Convenience wrapper, setter on self.data. """ - self.data[key] = value.astype(self.dtype, copy=False) + self.data[key] = value.astype(self.dtype, copy=None) self.reset_cache() def __len__(self): diff --git a/src/aspire/operators/diag_matrix.py b/src/aspire/operators/diag_matrix.py index 4c94ab83d1..68d6a728ae 100644 --- a/src/aspire/operators/diag_matrix.py +++ b/src/aspire/operators/diag_matrix.py @@ -45,7 +45,7 @@ def __init__(self, data, dtype=None): self.dtype = np.dtype(dtype) # Assign the `data` - self._data = data.astype(self.dtype, copy=False) + self._data = data.astype(self.dtype, copy=None) # Assign shapes from `data` self.count = self._data.shape[-1] diff --git a/src/aspire/reconstruction/mean.py b/src/aspire/reconstruction/mean.py index d0cade9754..56f0624e8d 100644 --- a/src/aspire/reconstruction/mean.py +++ b/src/aspire/reconstruction/mean.py @@ -102,7 +102,7 @@ def _compute_kernel(self): _range = np.arange(i, min(self.src.n, i + self.batch_size), dtype=int) sq_filters_f = evaluate_src_filters_on_grid(self.src, _range) ** 2 amplitudes_sq = (self.src.amplitudes[_range] ** 2).astype( - self.dtype, copy=False + self.dtype, copy=None ) for k in range(self.r): diff --git a/src/aspire/sinogram/sinogram.py b/src/aspire/sinogram/sinogram.py index 7c7bb43662..0f82b0c479 100644 --- a/src/aspire/sinogram/sinogram.py +++ b/src/aspire/sinogram/sinogram.py @@ -37,7 +37,7 @@ def __init__(self, data, dtype=None): f"Invalid data shape: {data.shape}. Expected shape: (..., angles, radial_points), where '...' is the stack number." ) - self._data = data.astype(self.dtype, copy=False) + self._data = data.astype(self.dtype, copy=None) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_shape = self._data.shape[:-2] diff --git a/src/aspire/source/micrograph.py b/src/aspire/source/micrograph.py index 5aa35e389c..86b161d822 100644 --- a/src/aspire/source/micrograph.py +++ b/src/aspire/source/micrograph.py @@ -155,7 +155,7 @@ def __init__(self, micrographs, dtype=None, pixel_size=None): ) # We're already backed by an array, access it directly. - self._data = micrographs.astype(self.dtype, copy=False) + self._data = micrographs.astype(self.dtype, copy=None) def _images(self, indices): """ diff --git a/src/aspire/utils/bot_align.py b/src/aspire/utils/bot_align.py index fc8fbe4fdc..e94888d92e 100644 --- a/src/aspire/utils/bot_align.py +++ b/src/aspire/utils/bot_align.py @@ -139,7 +139,7 @@ def cost(new, t=t, q=q): Loss function for surrogate problems. """ kx = np.array( - [cov_fun(new.astype(dtype, copy=False), R[j]) for j in range(t)] + [cov_fun(new.astype(dtype, copy=None), R[j]) for j in range(t)] ) mu = kx @ q return mu @@ -151,7 +151,7 @@ def euclidean_grad(new, t=t, q=q): """ # Corresponds to equation 11 in the paper. kx_grad = np.array( - [cov_fun_grad(new.astype(dtype, copy=False), R[j]) for j in range(t)] + [cov_fun_grad(new.astype(dtype, copy=None), R[j]) for j in range(t)] ) kx_grad = kx_grad.reshape((t, 9)) @@ -168,7 +168,7 @@ def euclidean_grad(new, t=t, q=q): verbosity=verbosity, ) result = optimizer.run(problem) - R_new = result.point.astype(dtype, copy=False) + R_new = result.point.astype(dtype, copy=None) loss[t] = loss_fun(R_new) R[t] = R_new @@ -190,7 +190,7 @@ def loss_u(u): """ Convert the alignment loss function over SO(3) to be over R^3. """ - u = u.astype(dtype, copy=False) + u = u.astype(dtype, copy=None) R = sign * Rotation.from_rotvec(u).matrices[0] v_rot = vol_given_ds.rotate(Rotation(R)).asnumpy()[0] return norm(vol_ref_ds - v_rot) diff --git a/src/aspire/utils/matrix.py b/src/aspire/utils/matrix.py index 71c709608b..bc802f87f8 100644 --- a/src/aspire/utils/matrix.py +++ b/src/aspire/utils/matrix.py @@ -462,7 +462,7 @@ def nearest_rotations(A, allow_reflection=False): # If det(U)*det(V) = -1, we negate the third singular value to # ensure we have a rotation. neg_det_idx = np.linalg.det(U) * np.linalg.det(V) < 0 - U[neg_det_idx] = U[neg_det_idx] @ np.diag((1, 1, -1)).astype(dtype, copy=False) + U[neg_det_idx] = U[neg_det_idx] @ np.diag((1, 1, -1)).astype(dtype, copy=None) rots = U @ V diff --git a/src/aspire/utils/misc.py b/src/aspire/utils/misc.py index a3f9917024..087454de5e 100644 --- a/src/aspire/utils/misc.py +++ b/src/aspire/utils/misc.py @@ -135,7 +135,7 @@ def gaussian_1d(size, mu=0, sigma=1, dtype=np.float64): p = (g["x"] - mu) ** 2 / (2 * sigma**2) - return np.exp(-p).astype(dtype, copy=False) + return np.exp(-p).astype(dtype, copy=None) def gaussian_2d(size, mu=(0, 0), sigma=(1, 1), indexing="yx", dtype=np.float64): @@ -180,7 +180,7 @@ def gaussian_2d(size, mu=(0, 0), sigma=(1, 1), indexing="yx", dtype=np.float64): 2 * sigma[1] ** 2 ) - return np.exp(-p).astype(dtype, copy=False) + return np.exp(-p).astype(dtype, copy=None) def gaussian_3d(size, mu=(0, 0, 0), sigma=(1, 1, 1), indexing="zyx", dtype=np.float64): @@ -228,7 +228,7 @@ def gaussian_3d(size, mu=(0, 0, 0), sigma=(1, 1, 1), indexing="zyx", dtype=np.fl + (g["z"] - mu[2]) ** 2 / (2 * sigma[2] ** 2) ) - return np.exp(-p).astype(dtype, copy=False) + return np.exp(-p).astype(dtype, copy=None) def bump_3d(size, spread=1, dtype=np.float64): diff --git a/src/aspire/utils/rotation.py b/src/aspire/utils/rotation.py index 07a31df9df..fb643914bf 100644 --- a/src/aspire/utils/rotation.py +++ b/src/aspire/utils/rotation.py @@ -256,7 +256,7 @@ def from_euler(values, dtype=None): """ dtype = dtype or getattr(values, "dtype", np.float32) rotations = sp_rot.from_euler("ZYZ", values, degrees=False) - matrices = rotations.as_matrix().astype(dtype, copy=False) + matrices = rotations.as_matrix().astype(dtype, copy=None) return Rotation(matrices) @staticmethod @@ -324,7 +324,7 @@ def from_rotvec(vec, dtype=None): """ dtype = dtype or vec.dtype rots = sp_rot.from_rotvec(vec) - matrices = rots.as_matrix().astype(dtype, copy=False) + matrices = rots.as_matrix().astype(dtype, copy=None) return Rotation(matrices) @staticmethod @@ -337,7 +337,7 @@ def from_matrix(values, dtype=None): :return: new Rotation object """ dtype = dtype or values.dtype - return Rotation(values.astype(dtype, copy=False)) + return Rotation(values.astype(dtype, copy=None)) @staticmethod def generate_random_rotations( diff --git a/src/aspire/volume/volume.py b/src/aspire/volume/volume.py index eae985a794..1954a1cbd5 100644 --- a/src/aspire/volume/volume.py +++ b/src/aspire/volume/volume.py @@ -105,7 +105,7 @@ def __init__(self, data, dtype=None, pixel_size=None, symmetry_group=None): if not (data.shape[-1] == data.shape[-2] == data.shape[-3]): raise ValueError("Only cubed ndarrays are supported.") - self._data = data.astype(self.dtype, copy=False) + self._data = data.astype(self.dtype, copy=None) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 3 diff --git a/tests/test_FFBbasis3D.py b/tests/test_FFBbasis3D.py index 03bdfdd21b..3992f5d374 100644 --- a/tests/test_FFBbasis3D.py +++ b/tests/test_FFBbasis3D.py @@ -470,7 +470,7 @@ def testFFBBasis3DEvaluate(self, basis): def testFFBBasis3DEvaluate_t(self, basis): x = np.load(os.path.join(DATA_DIR, "ffbbasis3d_xcoef_in_8_8_8.npy")).T # RCOPT - x = x.astype(basis.dtype, copy=False) + x = x.astype(basis.dtype, copy=None) result = basis.evaluate_t(Volume(x)) ref = np.load(os.path.join(DATA_DIR, "ffbbasis3d_vcoef_out_8_8_8.npy"))[..., 0] @@ -479,7 +479,7 @@ def testFFBBasis3DEvaluate_t(self, basis): def testFFBBasis3DExpand(self, basis): x = np.load(os.path.join(DATA_DIR, "ffbbasis3d_xcoef_in_8_8_8.npy")).T # RCOPT - x = x.astype(basis.dtype, copy=False) + x = x.astype(basis.dtype, copy=None) result = basis.expand(x) ref = np.load(os.path.join(DATA_DIR, "ffbbasis3d_vcoef_out_exp_8_8_8.npy"))[ diff --git a/tests/test_coef.py b/tests/test_coef.py index 3ace0ddec5..2a283d16e4 100644 --- a/tests/test_coef.py +++ b/tests/test_coef.py @@ -90,7 +90,7 @@ def coef_fixture(basis, stack, dtype): # shape. size = stack + (basis.count,) - coef_np = np.random.random(size=size).astype(dtype, copy=False) + coef_np = np.random.random(size=size).astype(dtype, copy=None) return Coef(basis, coef_np, dtype=dtype) @@ -212,7 +212,7 @@ def test_add(basis, coef_fixture): Tests addition operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) # Construct Coef c = Coef(basis, x) @@ -231,7 +231,7 @@ def test_sub(basis, coef_fixture): Tests subtraction operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) # Construct Coef c = Coef(basis, x) @@ -264,7 +264,7 @@ def test_mul(basis, coef_fixture): Tests multiplication operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) # Construct Coef c = Coef(basis, x) diff --git a/tests/test_complexPCA.py b/tests/test_complexPCA.py index 509b0b84a5..1c224324d7 100644 --- a/tests/test_complexPCA.py +++ b/tests/test_complexPCA.py @@ -53,7 +53,7 @@ def testLargeFitTransform(self): """ pca = ComplexPCA( - n_components=self.components_large, copy=False, svd_solver="full" + n_components=self.components_large, copy=None, svd_solver="full" ) # Input data matrix X should be (n_samples, m_features) diff --git a/tests/test_diag_matrix.py b/tests/test_diag_matrix.py index 05805912c9..30f2b76faa 100644 --- a/tests/test_diag_matrix.py +++ b/tests/test_diag_matrix.py @@ -65,7 +65,7 @@ def diag_matrix_fixture(stack, matrix_size, dtype): """ shape = (2,) + stack + (matrix_size,) # Internally convert dtype. Passthrough will be checked explicitly in `test_dtype_passthrough` and `test_dtype_cast` - d_np = np.random.random(shape).astype(dtype, copy=False) + d_np = np.random.random(shape).astype(dtype, copy=None) d1 = DiagMatrix(d_np[0]) d2 = DiagMatrix(d_np[1]) diff --git a/tests/test_downsample.py b/tests/test_downsample.py index 6c1cac82dd..1af37d7281 100644 --- a/tests/test_downsample.py +++ b/tests/test_downsample.py @@ -148,7 +148,7 @@ def emdb_vol(): @pytest.fixture(scope="module") def volume(emdb_vol, res, dtype): - vol = emdb_vol.astype(dtype, copy=False) + vol = emdb_vol.astype(dtype, copy=None) vol = vol.downsample(res) return vol @@ -266,7 +266,7 @@ def test_pixel_size(): dsL = 5 # downsampled # Construct a small test Image - img = Image(np.random.random((1, L, L)).astype(DTYPE, copy=False), pixel_size=1.23) + img = Image(np.random.random((1, L, L)).astype(DTYPE, copy=None), pixel_size=1.23) # Downsample the image result = img.downsample(dsL) diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 728200b9b3..be6829d3fa 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -356,7 +356,7 @@ def test_nearest_rotations(dtype): rots = Rotation.generate_random_rotations(n_rots, seed=0, dtype=dtype).matrices # Add some noise to the rotations. - noise = 1e-3 * randn(n_rots * 9, seed=0).astype(dtype, copy=False).reshape( + noise = 1e-3 * randn(n_rots * 9, seed=0).astype(dtype, copy=None).reshape( n_rots, 3, 3 ) noisy_rots = rots + noise @@ -381,7 +381,7 @@ def test_nearest_rotations_reflection(dtype): # Add a reflection and some noise to the rotation. refl = rot @ np.diag((1, -1, 1)).astype(dtype) - noise = 1e-3 * randn(9, seed=0).astype(dtype, copy=False).reshape(3, 3) + noise = 1e-3 * randn(9, seed=0).astype(dtype, copy=None).reshape(3, 3) noisy_refl = refl + noise # Find nearest rotation. diff --git a/tests/test_mean_estimator.py b/tests/test_mean_estimator.py index e6b2a2f837..3e7f915193 100644 --- a/tests/test_mean_estimator.py +++ b/tests/test_mean_estimator.py @@ -115,8 +115,8 @@ def test_adjoint(sim, basis, estimator): L = sim.L n = sim.n - u = np.random.rand(n, L, L).astype(sim.dtype, copy=False) - v = np.random.rand(L, L, L).astype(sim.dtype, copy=False) + u = np.random.rand(n, L, L).astype(sim.dtype, copy=None) + v = np.random.rand(L, L, L).astype(sim.dtype, copy=None) proj = Volume(v).project(rots) backproj = Image(u).backproject(rots) diff --git a/tests/test_micrograph_source.py b/tests/test_micrograph_source.py index d4793cf61f..c44e703cbb 100644 --- a/tests/test_micrograph_source.py +++ b/tests/test_micrograph_source.py @@ -56,7 +56,7 @@ def image_data_fixture(micrograph_count, micrograph_size, dtype): This generates a Numpy array with prescribed shape and dtype. """ img_np = np.random.rand(micrograph_count, micrograph_size, micrograph_size) - return img_np.astype(dtype, copy=False) + return img_np.astype(dtype, copy=None) # ===== diff --git a/tests/test_orient_sdp.py b/tests/test_orient_sdp.py index 22658ee06a..aa215d1766 100644 --- a/tests/test_orient_sdp.py +++ b/tests/test_orient_sdp.py @@ -152,7 +152,7 @@ def test_ATA_solver(): rots = Rotation.generate_random_rotations(n=n_rots, seed=seed, dtype=dtype).matrices # Create a simple reference linear transformation A that is rank-3. - A_ref = np.diag([1, 2, 3]).astype(dtype, copy=False) + A_ref = np.diag([1, 2, 3]).astype(dtype, copy=None) # Create v1 and v2 such that A_ref*v1=R1 and A_ref*v2=R2, R1 and R2 are the first # and second columns of all rotations. diff --git a/tests/test_polar_ft.py b/tests/test_polar_ft.py index 425d5e14bb..4ec69b67e4 100644 --- a/tests/test_polar_ft.py +++ b/tests/test_polar_ft.py @@ -203,7 +203,7 @@ def test_half_to_full_transform(stack_shape): """ img_size = 32 image = Image( - np.random.rand(*stack_shape, img_size, img_size).astype(np.float32, copy=False) + np.random.rand(*stack_shape, img_size, img_size).astype(np.float32, copy=None) ) pft = PolarFT(size=img_size) pf = pft.transform(image) diff --git a/tests/test_simulation.py b/tests/test_simulation.py index 944e2e7c06..46b00d2ce9 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -82,7 +82,7 @@ def testPassthroughFromVol(self): without an explcit Simulation dtype. """ for dtype in (np.float32, np.float64): - sim = Simulation(vols=self.vol.astype(dtype, copy=False)) + sim = Simulation(vols=self.vol.astype(dtype, copy=None)) # Did we assign the right type? self.assertTrue(sim.dtype == dtype) diff --git a/tests/test_volume.py b/tests/test_volume.py index d220860784..74c77c5cc5 100644 --- a/tests/test_volume.py +++ b/tests/test_volume.py @@ -163,10 +163,10 @@ def test_astype(vols_1, dtype): def test_astype_copy(vols_1): """ - `astype(copy=False)` is an optimization partially mimicked from numpy. + `astype(copy=None)` is an optimization partially mimicked from numpy. """ - # Same dtype, copy=False - v2 = vols_1.astype(vols_1.dtype, copy=False) + # Same dtype, copy=None + v2 = vols_1.astype(vols_1.dtype, copy=None) # Details should match, assert isinstance(v2, Volume) assert np.allclose(v2.asnumpy(), vols_1.asnumpy()) From 54d7a508cd1dc775f05e7fe86791a96c34a35369 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 14:19:48 -0400 Subject: [PATCH 05/14] np2 breaks np.sign for complex --- src/aspire/utils/matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspire/utils/matrix.py b/src/aspire/utils/matrix.py index bc802f87f8..534c027b30 100644 --- a/src/aspire/utils/matrix.py +++ b/src/aspire/utils/matrix.py @@ -493,7 +493,7 @@ def fix_signs(u): # Now we only care about the sign +1/-1. # The following corrects for any numerical division noise, # and also remaps 0 to +1. - signs = np.sign(signs * 2 + 1) + signs = np.sign(signs.real * 2 + 1) # Apply signs elementwise to matrix return u * signs From 4f13006b5e0ffe2f96958b7f7b5fa64dcf10a1cf Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 15:06:13 -0400 Subject: [PATCH 06/14] np2 multiply xform dtype cast --- src/aspire/image/xform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aspire/image/xform.py b/src/aspire/image/xform.py index 0759c819e8..38f65d9bee 100644 --- a/src/aspire/image/xform.py +++ b/src/aspire/image/xform.py @@ -144,8 +144,9 @@ def __init__(self, factor): self.multipliers = np.array(factor) def _forward(self, im, indices): + if self.multipliers.size == 1: # if we have a scalar multiplier - im_new = im * self.multipliers + im_new = im * self.multipliers.astype(im.dtype) else: im_new = im * self.multipliers[indices] From 71a5e05449d13fee336778289b9d17bc65940887 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 15:11:03 -0400 Subject: [PATCH 07/14] sk pca copy False --- src/aspire/classification/rir_class2d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspire/classification/rir_class2d.py b/src/aspire/classification/rir_class2d.py index dde35ef050..19a3479ffe 100644 --- a/src/aspire/classification/rir_class2d.py +++ b/src/aspire/classification/rir_class2d.py @@ -390,7 +390,7 @@ def _sk_pca(self, M): # We use an extension of SK that is hacked to admit complex. pca = ComplexPCA( self.bispectrum_components, - copy=None, # careful, overwrites data matrix... we'll handle the copies. + copy=False, # careful, overwrites data matrix... we'll handle the copies. svd_solver="auto", # use randomized (Halko) for larger problems random_state=self.seed, ) From c151f9df6a724d06bfc38e97c94ac85eaf0d415c Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 15:11:51 -0400 Subject: [PATCH 08/14] sk pca copy False --- tests/test_complexPCA.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_complexPCA.py b/tests/test_complexPCA.py index 1c224324d7..509b0b84a5 100644 --- a/tests/test_complexPCA.py +++ b/tests/test_complexPCA.py @@ -53,7 +53,7 @@ def testLargeFitTransform(self): """ pca = ComplexPCA( - n_components=self.components_large, copy=None, svd_solver="full" + n_components=self.components_large, copy=False, svd_solver="full" ) # Input data matrix X should be (n_samples, m_features) From 680a426d19a248dae5f5bc0600120b43762beba6 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 15:28:01 -0400 Subject: [PATCH 09/14] another great np2 improvement --- src/aspire/image/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspire/image/image.py b/src/aspire/image/image.py index 6d0f3b8960..bd9dfa22a1 100644 --- a/src/aspire/image/image.py +++ b/src/aspire/image/image.py @@ -72,7 +72,7 @@ def normalize_bg(imgs, bg_radius=1.0, do_ramp=True): # Apply mask images and calculate mean and std values of background imgs_masked = imgs * mask - denominator = np.sum(mask) + denominator = np.count_nonzero(mask) # scalar int first_moment = np.sum(imgs_masked, axis=(1, 2)) / denominator second_moment = np.sum(imgs_masked**2, axis=(1, 2)) / denominator mean = first_moment.reshape(-1, 1, 1) From 3585686cc34e74938cc7335c7022a5834c18feab Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 15:39:22 -0400 Subject: [PATCH 10/14] sqrt(weight) dtype not same as weight --- src/aspire/__init__.py | 15 +++++++++++++++ src/aspire/abinitio/commonline_base.py | 2 +- src/aspire/abinitio/commonline_c3_c4.py | 2 +- src/aspire/abinitio/commonline_d2.py | 4 ++-- src/aspire/abinitio/commonline_sync3n.py | 20 ++++++++++---------- src/aspire/apple/picking.py | 4 ++-- src/aspire/basis/basis.py | 2 +- src/aspire/basis/fle_2d.py | 6 ++++-- src/aspire/basis/fpswf_2d.py | 2 +- src/aspire/classification/averager2d.py | 2 +- src/aspire/covariance/covar2d.py | 2 +- src/aspire/ctf/ctf_estimator.py | 4 ++-- src/aspire/image/image.py | 6 +++--- src/aspire/nufft/cufinufft.py | 2 +- src/aspire/nufft/finufft.py | 4 ++-- src/aspire/numeric/complex_pca/validation.py | 10 +++++----- src/aspire/numeric/pyfftw_fft.py | 2 +- src/aspire/operators/blk_diag_matrix.py | 4 ++-- src/aspire/operators/diag_matrix.py | 2 +- src/aspire/reconstruction/estimator.py | 1 - src/aspire/reconstruction/kernel.py | 4 ++-- src/aspire/reconstruction/mean.py | 19 ++++++++++--------- src/aspire/sinogram/sinogram.py | 2 +- src/aspire/source/micrograph.py | 2 +- src/aspire/utils/bot_align.py | 8 ++++---- src/aspire/utils/matrix.py | 4 ++-- src/aspire/utils/misc.py | 8 ++++---- src/aspire/utils/rotation.py | 6 +++--- src/aspire/volume/volume.py | 2 +- tests/test_FFBbasis3D.py | 4 ++-- tests/test_coef.py | 8 ++++---- tests/test_diag_matrix.py | 2 +- tests/test_downsample.py | 4 ++-- tests/test_matrix.py | 4 ++-- tests/test_mean_estimator.py | 4 ++-- tests/test_micrograph_source.py | 2 +- tests/test_orient_sdp.py | 2 +- tests/test_polar_ft.py | 2 +- tests/test_simulation.py | 2 +- tests/test_volume.py | 6 +++--- 40 files changed, 104 insertions(+), 87 deletions(-) diff --git a/src/aspire/__init__.py b/src/aspire/__init__.py index 9c80750c9c..8273099c75 100644 --- a/src/aspire/__init__.py +++ b/src/aspire/__init__.py @@ -2,11 +2,14 @@ import logging.config import os import pkgutil +import warnings from datetime import datetime from pathlib import Path import confuse +import numpy as np import pooch +from packaging.version import parse as parse_version import aspire from aspire.exceptions import handle_exception @@ -84,3 +87,15 @@ def __getattr__(attr): return importlib.import_module(f"aspire.{attr}") else: raise AttributeError(f"module `{__name__}` has no attribute `{attr}`.") + + +if parse_version(np.version.version) >= parse_version("2.0.0"): + # ImportWarnings are generally filtered, but raise this one for now. + with warnings.catch_warnings(): + warnings.simplefilter("default") + warnings.warn( + "ASPIRE's Numpy 2 support is in beta. If you experience a runtime" + "crash relating to mismatched dtypes or a Numpy call please try" + ' `pip install "numpy<2"` and report to ASPIRE developers.', + ImportWarning, + ) diff --git a/src/aspire/abinitio/commonline_base.py b/src/aspire/abinitio/commonline_base.py index 2cd80b61fa..fe456c645e 100644 --- a/src/aspire/abinitio/commonline_base.py +++ b/src/aspire/abinitio/commonline_base.py @@ -149,7 +149,7 @@ def _prepare_pf(self): # Apply mask in doubles (allow imgs to upcast as needed) imgs = imgs * fuzz_mask # Cast to desired type - imgs = Image(imgs.asnumpy().astype(self.dtype, copy=None)) + imgs = Image(imgs.asnumpy().astype(self.dtype, copy=False)) # Obtain coefficients of polar Fourier transform for input 2D images pft = PolarFT( diff --git a/src/aspire/abinitio/commonline_c3_c4.py b/src/aspire/abinitio/commonline_c3_c4.py index bc2956ec0d..242094b745 100644 --- a/src/aspire/abinitio/commonline_c3_c4.py +++ b/src/aspire/abinitio/commonline_c3_c4.py @@ -693,7 +693,7 @@ def _J_sync_power_method(self, vijs): while itr < max_iters and residual > epsilon: itr += 1 # Note, this appears to need double precision for accuracy in the following division. - vec_new = self._signs_times_v(vijs, vec).astype(np.float64, copy=None) + vec_new = self._signs_times_v(vijs, vec).astype(np.float64, copy=False) vec_new = vec_new / norm(vec_new) residual = norm(vec_new - vec) vec = vec_new diff --git a/src/aspire/abinitio/commonline_d2.py b/src/aspire/abinitio/commonline_d2.py index 93b2e9bc0a..a8e951c642 100644 --- a/src/aspire/abinitio/commonline_d2.py +++ b/src/aspire/abinitio/commonline_d2.py @@ -1149,12 +1149,12 @@ def _sync_colors(self, Rijs): # Seed eigs initial vector for iterative method. # scipy LinearOperator needs doubles for some architectures (arm). - v0 = randn(3 * n_pairs, seed=self.seed).astype(np.float64, copy=None) + v0 = randn(3 * n_pairs, seed=self.seed).astype(np.float64, copy=False) v0 = v0 / norm(v0) vals, colors = la.eigs(color_mat, k=3, which="LR", v0=v0) vals = np.real(vals) - colors = np.real(colors).astype(self.dtype, copy=None) + colors = np.real(colors).astype(self.dtype, copy=False) colors = np.sign(colors[0]) * colors # Stable eigs cp, _ = self._unmix_colors(colors[:, :2]) diff --git a/src/aspire/abinitio/commonline_sync3n.py b/src/aspire/abinitio/commonline_sync3n.py index aa11a2348a..a0db2263ec 100644 --- a/src/aspire/abinitio/commonline_sync3n.py +++ b/src/aspire/abinitio/commonline_sync3n.py @@ -197,7 +197,7 @@ def _sync3n_S_to_rot(self, S, W=None, n_eigs=4): """ # Critical this occurs in double precision - S = S.astype(np.float64, copy=None) + S = S.astype(np.float64, copy=False) if n_eigs < 3: raise ValueError( @@ -213,7 +213,7 @@ def _sync3n_S_to_rot(self, S, W=None, n_eigs=4): ) # Initialize D # Critical this occurs in double precision - W = W.astype(np.float64, copy=None) + W = W.astype(np.float64, copy=False) D = np.mean(W, axis=1) Dhalf = D @@ -266,7 +266,7 @@ def _sync3n_S_to_rot(self, S, W=None, n_eigs=4): # Enforce we are returning actual rotations rotations = nearest_rotations(rotations, allow_reflection=True) - return rotations.astype(self.dtype) + return rotations.astype(self.dtype, copy=False) def _construct_sync3n_matrix(self, Rij): """ @@ -664,8 +664,8 @@ def _pairs_probabilities_cupy(self, Rijs, P2, A, a, B, b, x0): ) # accumulate over thread results - ln_f_arb = ln_f_arb_dev.get().astype(self.dtype, copy=None) - ln_f_ind = ln_f_ind_dev.get().astype(self.dtype, copy=None) + ln_f_arb = ln_f_arb_dev.get().astype(self.dtype, copy=False) + ln_f_ind = ln_f_ind_dev.get().astype(self.dtype, copy=False) return ln_f_ind, ln_f_arb @@ -748,8 +748,8 @@ def fun(x, B, P, b, x0, A=A, a=a): popt, pcov = curve_fit( fun, - hist_x.astype(np.float64, copy=None), - scores_hist.astype(np.float64, copy=None), + hist_x.astype(np.float64, copy=False), + scores_hist.astype(np.float64, copy=False), p0=start_values, bounds=(lower_bounds, upper_bounds), method="trf", # MATLAB used method "LAR" with algo "Trust-Region" @@ -1043,7 +1043,7 @@ def _J_sync_power_method(self, Rijs): while itr < max_iters and residual > epsilon: itr += 1 # Todo, this code code actually needs double precision for accuracy... forcing. - vec_new = self._signs_times_v(Rijs, vec).astype(np.float64, copy=None) + vec_new = self._signs_times_v(Rijs, vec).astype(np.float64, copy=False) vec_new = vec_new / norm(vec_new) residual = norm(vec_new - vec) vec = vec_new @@ -1073,7 +1073,7 @@ def _signs_times_v(self, Rijs, vec): else: new_vec = self._signs_times_v_host(Rijs, vec) - return new_vec.astype(vec.dtype, copy=None) + return new_vec.astype(vec.dtype, copy=False) def _signs_times_v_host(self, Rijs, vec): """ @@ -1177,7 +1177,7 @@ def _signs_times_v_cupy(self, Rijs, vec): ) # dtoh - new_vec = new_vec_dev.get().astype(vec.dtype, copy=None) + new_vec = new_vec_dev.get().astype(vec.dtype, copy=False) return new_vec diff --git a/src/aspire/apple/picking.py b/src/aspire/apple/picking.py index d54cf61f1d..d64d16c773 100644 --- a/src/aspire/apple/picking.py +++ b/src/aspire/apple/picking.py @@ -149,7 +149,7 @@ def read_micrograph(self): self.original_im = ( DiskMicrographSource(self.filename) .asnumpy()[0] - .astype(np.float32, copy=None) + .astype(np.float32, copy=False) ) # Discard outer pixels @@ -167,7 +167,7 @@ def read_micrograph(self): # Note, float64 required for signal.correlate call accuracy. im = np.asarray( PILImage.fromarray(im).resize(size, PILImage.Resampling.BICUBIC) - ).astype(np.float64, copy=None) + ).astype(np.float64, copy=False) im = signal.correlate( im, diff --git a/src/aspire/basis/basis.py b/src/aspire/basis/basis.py index 6baf16f769..ee6aee2d02 100644 --- a/src/aspire/basis/basis.py +++ b/src/aspire/basis/basis.py @@ -62,7 +62,7 @@ def __init__(self, basis, data, dtype=None): ) self.basis = basis - self._data = data.astype(self.dtype, copy=None) + self._data = data.astype(self.dtype, copy=False) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 1 diff --git a/src/aspire/basis/fle_2d.py b/src/aspire/basis/fle_2d.py index 6499919110..fc22352c18 100644 --- a/src/aspire/basis/fle_2d.py +++ b/src/aspire/basis/fle_2d.py @@ -643,7 +643,7 @@ def _step1(self, z): num_img = z.shape[0] z = z[:, :, : self.num_angular_nodes // 2].reshape(num_img, -1) im = anufft( - z.astype(complex_type(self.dtype), copy=None), + z.astype(complex_type(self.dtype), copy=False), self.grid_xy, (self.nres, self.nres), epsilon=self.epsilon, @@ -798,7 +798,9 @@ def filter_to_basis_mat(self, f, **kwargs): omega = 2 * xp.pi * xp.vstack((omegax.flatten("C"), omegay.flatten("C"))) h_vals2d = ( - xp.asarray(h_fun(omega)).reshape(n_k, n_theta).astype(self.dtype, copy=None) + xp.asarray(h_fun(omega)) + .reshape(n_k, n_theta) + .astype(self.dtype, copy=False) ) h_vals = xp.sum(h_vals2d, axis=1) / n_theta diff --git a/src/aspire/basis/fpswf_2d.py b/src/aspire/basis/fpswf_2d.py index aa7b9913d9..6eac1a91db 100644 --- a/src/aspire/basis/fpswf_2d.py +++ b/src/aspire/basis/fpswf_2d.py @@ -99,7 +99,7 @@ def _precomp(self): ) = self._pswf_integration_sub_routine() self.us_fft_pts = us_fft_pts.astype( - self.dtype, copy=None + self.dtype, copy=False ) # TODO, debug where this is incorrect dtype self.blk_r = blk_r self.num_angular_pts = num_angular_pts diff --git a/src/aspire/classification/averager2d.py b/src/aspire/classification/averager2d.py index 644359c9e7..b447a6d91c 100644 --- a/src/aspire/classification/averager2d.py +++ b/src/aspire/classification/averager2d.py @@ -82,7 +82,7 @@ def _cls_images(self, cls, src=None): source for a certain operation (ie alignment). """ src = src or self.src - return src.images[cls].asnumpy().astype(self.dtype, copy=None) + return src.images[cls].asnumpy().astype(self.dtype, copy=False) class AligningAverager2D(Averager2D): diff --git a/src/aspire/covariance/covar2d.py b/src/aspire/covariance/covar2d.py index a4f1971b78..d2e7dafe43 100644 --- a/src/aspire/covariance/covar2d.py +++ b/src/aspire/covariance/covar2d.py @@ -607,7 +607,7 @@ def _calc_op(self): ctf_basis_k_sq = ctf_basis_k_t @ ctf_basis_k A_mean_k = weight * ctf_basis_k_sq A_mean += A_mean_k - A_covar_k = np.sqrt(weight) * ctf_basis_k_sq + A_covar_k = np.sqrt(weight).astype(self.dtype) * ctf_basis_k_sq A_covar[k] = A_covar_k M_covar += A_covar_k diff --git a/src/aspire/ctf/ctf_estimator.py b/src/aspire/ctf/ctf_estimator.py index 39f2998a21..b6983cb071 100644 --- a/src/aspire/ctf/ctf_estimator.py +++ b/src/aspire/ctf/ctf_estimator.py @@ -241,7 +241,7 @@ def estimate_psd(self, blocks, tapers_1d): """ num_1d_tapers = tapers_1d.shape[-1] - tapers_1d = tapers_1d.astype(complex_type(self.dtype), copy=None) + tapers_1d = tapers_1d.astype(complex_type(self.dtype), copy=False) blocks_mt = np.zeros(blocks[0, :, :].shape, dtype=self.dtype) @@ -768,7 +768,7 @@ def estimate_ctf( micrograph = mrc.data # Try to match dtype used in Basis instance - micrograph = micrograph.astype(dtype, copy=None) + micrograph = micrograph.astype(dtype, copy=False) micrograph_blocks = ctf_object.preprocess_micrograph(micrograph, psd_size) diff --git a/src/aspire/image/image.py b/src/aspire/image/image.py index bd9dfa22a1..1e980e88dd 100644 --- a/src/aspire/image/image.py +++ b/src/aspire/image/image.py @@ -195,7 +195,7 @@ def __init__(self, data, pixel_size=None, dtype=None): if not data.shape[-1] == data.shape[-2]: raise ValueError("Only square ndarrays are supported.") - self._data = data.astype(self.dtype, copy=None) + self._data = data.astype(self.dtype, copy=False) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 2 @@ -543,7 +543,7 @@ def load(filepath, dtype=None): # Attempt casting when user provides dtype if dtype is not None: - im = im.astype(dtype, copy=None) + im = im.astype(dtype, copy=False) # Return as Image instance return Image(im, pixel_size=pixel_size) @@ -658,7 +658,7 @@ def backproject(self, rot_matrices, symmetry_group=None, zero_nyquist=True): # TODO: rotated_grids might as well give us correctly shaped array in the first place pts_rot = aspire.volume.rotated_grids(L, rotations).astype( - self.dtype, copy=None + self.dtype, copy=False ) pts_rot = pts_rot.reshape((3, -1)) diff --git a/src/aspire/nufft/cufinufft.py b/src/aspire/nufft/cufinufft.py index 2660f4ea46..fd869aacfd 100644 --- a/src/aspire/nufft/cufinufft.py +++ b/src/aspire/nufft/cufinufft.py @@ -30,7 +30,7 @@ def __init__(self, sz, fourier_pts, epsilon=1e-8, ntransforms=1, **kwargs): # ASPIRE-Python/703 # Cast to doubles. self._original_dtype = fourier_pts.dtype - fourier_pts = fourier_pts.astype(np.float64, copy=None) + fourier_pts = fourier_pts.astype(np.float64, copy=False) # Basic dtype passthough. dtype = fourier_pts.dtype diff --git a/src/aspire/nufft/finufft.py b/src/aspire/nufft/finufft.py index e396d76124..a955ab20d0 100644 --- a/src/aspire/nufft/finufft.py +++ b/src/aspire/nufft/finufft.py @@ -99,7 +99,7 @@ def transform(self, signal): ), f"Signal frame to be transformed must have shape {self.sz}" # FINUFFT was designed for a complex input array - signal = np.array(signal, copy=None, dtype=self.complex_dtype, order="C") + signal = np.asarray(signal, dtype=self.complex_dtype, order="C") result = self._transform_plan.execute(signal) @@ -130,7 +130,7 @@ def adjoint(self, signal): signal = signal.reshape(self.num_pts) # FINUFFT was designed for a complex input array - signal = np.array(signal, copy=None, dtype=self.complex_dtype, order="C") + signal = np.asarray(signal, dtype=self.complex_dtype, order="C") result = self._adjoint_plan.execute(signal) diff --git a/src/aspire/numeric/complex_pca/validation.py b/src/aspire/numeric/complex_pca/validation.py index 11d7aaba9f..7fafedfe18 100644 --- a/src/aspire/numeric/complex_pca/validation.py +++ b/src/aspire/numeric/complex_pca/validation.py @@ -81,7 +81,7 @@ def _ensure_sparse_format( Data type of result. If None, the dtype of the input is preserved. copy : boolean - Whether a forced copy will be triggered. If copy=None, a copy might + Whether a forced copy will be triggered. If copy=False, a copy might be triggered by a conversion. force_all_finite : boolean or 'allow-nan', (default=True) @@ -173,7 +173,7 @@ def check_array( accept_large_sparse=True, dtype="numeric", order=None, - copy=None, + copy=False, force_all_finite=True, ensure_2d=True, allow_nd=False, @@ -216,13 +216,13 @@ def check_array( order : 'F', 'C' or None (default=None) Whether an array will be forced to be fortran or c-style. - When order is None (default), then if copy=None, nothing is ensured + When order is None (default), then if copy=False, nothing is ensured about the memory layout of the output array; otherwise (copy=True) the memory layout of the returned array is kept as close as possible to the original array. copy : boolean (default=False) - Whether a forced copy will be triggered. If copy=None, a copy might + Whether a forced copy will be triggered. If copy=False, a copy might be triggered by a conversion. force_all_finite : boolean or 'allow-nan', (default=True) @@ -365,7 +365,7 @@ def check_array( array = np.asarray(array, order=order) if array.dtype.kind == "f": _assert_all_finite(array, allow_nan=False, msg_dtype=dtype) - array = array.astype(dtype, casting="unsafe", copy=None) + array = array.astype(dtype, casting="unsafe", copy=False) else: array = np.asarray(array, order=order, dtype=dtype) except ComplexWarning: diff --git a/src/aspire/numeric/pyfftw_fft.py b/src/aspire/numeric/pyfftw_fft.py index 4503b42b38..95a8ea80f7 100644 --- a/src/aspire/numeric/pyfftw_fft.py +++ b/src/aspire/numeric/pyfftw_fft.py @@ -139,7 +139,7 @@ def ifftn(self, a, axes=None, workers=-1): # FFTW_BACKWARD requires complex input array, cast as needed. # See https://pyfftw.readthedocs.io/en/latest/source/pyfftw/pyfftw.html#scheme-table comp_type = complex_type(a.dtype) - a = a.astype(comp_type, copy=None) + a = a.astype(comp_type, copy=False) mutex.acquire() try: diff --git a/src/aspire/operators/blk_diag_matrix.py b/src/aspire/operators/blk_diag_matrix.py index af882ecc68..3e493f9525 100644 --- a/src/aspire/operators/blk_diag_matrix.py +++ b/src/aspire/operators/blk_diag_matrix.py @@ -91,7 +91,7 @@ def append(self, blk): :param blk: Block to append (ndarray). """ - self.data.append(blk.astype(self.dtype, copy=None)) + self.data.append(blk.astype(self.dtype, copy=False)) self.nblocks += 1 self.reset_cache() @@ -130,7 +130,7 @@ def __setitem__(self, key, value): Convenience wrapper, setter on self.data. """ - self.data[key] = value.astype(self.dtype, copy=None) + self.data[key] = value.astype(self.dtype, copy=False) self.reset_cache() def __len__(self): diff --git a/src/aspire/operators/diag_matrix.py b/src/aspire/operators/diag_matrix.py index 68d6a728ae..4c94ab83d1 100644 --- a/src/aspire/operators/diag_matrix.py +++ b/src/aspire/operators/diag_matrix.py @@ -45,7 +45,7 @@ def __init__(self, data, dtype=None): self.dtype = np.dtype(dtype) # Assign the `data` - self._data = data.astype(self.dtype, copy=None) + self._data = data.astype(self.dtype, copy=False) # Assign shapes from `data` self.count = self._data.shape[-1] diff --git a/src/aspire/reconstruction/estimator.py b/src/aspire/reconstruction/estimator.py index 2bf0ec3366..ac5e9caeca 100644 --- a/src/aspire/reconstruction/estimator.py +++ b/src/aspire/reconstruction/estimator.py @@ -159,7 +159,6 @@ def apply_kernel(self, vol_coef, kernel=None): if kernel is None: kernel = self.kernel - vol = Coef(self.basis, vol_coef).evaluate() # returns a Volume vol = kernel.convolve_volume(vol) # returns a Volume vol_coef = self.basis.evaluate_t(vol) diff --git a/src/aspire/reconstruction/kernel.py b/src/aspire/reconstruction/kernel.py index 84d4e61409..9a86a244f2 100644 --- a/src/aspire/reconstruction/kernel.py +++ b/src/aspire/reconstruction/kernel.py @@ -32,7 +32,7 @@ def __add__(self, delta): to be able to use it within optimization loops. This operator allows one to use the FourierKernel object with the underlying 'kernel' attribute tweaked with a regularization parameter. """ - new_kernel = self.kernel + delta + new_kernel = self.kernel + float(delta) return FourierKernel(new_kernel) def circularize(self): @@ -191,7 +191,7 @@ def __add__(self, delta): def circularize(self): _L = self.M // 2 - xx = np.empty((self.r, self.r, _L, _L, _L)) + xx = np.empty((self.r, self.r, _L, _L, _L), self.dtype) for k in range(self.r): for j in range(self.r): xx[k, j] = FourierKernel(self.kermat[k, j]).circularize().real diff --git a/src/aspire/reconstruction/mean.py b/src/aspire/reconstruction/mean.py index 56f0624e8d..b380c8788c 100644 --- a/src/aspire/reconstruction/mean.py +++ b/src/aspire/reconstruction/mean.py @@ -5,10 +5,9 @@ from scipy.linalg import norm from scipy.sparse.linalg import LinearOperator -from aspire import config from aspire.basis import Coef from aspire.nufft import anufft -from aspire.numeric import fft +from aspire.numeric import config, fft from aspire.numeric.scipy import cg from aspire.operators import evaluate_src_filters_on_grid from aspire.reconstruction import Estimator, FourierKernel, FourierKernelMatrix @@ -102,7 +101,7 @@ def _compute_kernel(self): _range = np.arange(i, min(self.src.n, i + self.batch_size), dtype=int) sq_filters_f = evaluate_src_filters_on_grid(self.src, _range) ** 2 amplitudes_sq = (self.src.amplitudes[_range] ** 2).astype( - self.dtype, copy=None + self.dtype, copy=False ) for k in range(self.r): @@ -139,7 +138,7 @@ def _compute_kernel(self): if j != k: kernel[j, k] += batch_kernel - kermat_f = np.zeros((self.r, self.r, _2L, _2L, _2L)) + kermat_f = np.zeros((self.r, self.r, _2L, _2L, _2L), dtype=self.dtype) logger.info("Computing non-centered Fourier Transform Kernel Mat") for k in range(self.r): for j in range(self.r): @@ -184,10 +183,12 @@ def src_backward(self): i, self.weights[:, k], symmetry_group=symmetry_group, - ) / (self.src.n * sym_order) + ) / float(self.src.n * sym_order) vol_rhs[k] += batch_vol_rhs.astype(self.dtype) - res = np.sqrt(self.src.n * sym_order) * self.basis.evaluate_t(vol_rhs) + res = np.sqrt(self.src.n * sym_order, dtype=self.dtype) * self.basis.evaluate_t( + vol_rhs + ) logger.info(f"Determined weighted adjoint mappings. Shape = {res.shape}") return res @@ -210,6 +211,7 @@ def conj_grad(self, b_coef, x0=None, tol=1e-5, regularizer=0): precond_kernel = self.precond_kernel if regularizer > 0: precond_kernel += regularizer + M = LinearOperator( (self.r * count, self.r * count), matvec=partial(self.apply_kernel, kernel=precond_kernel), @@ -262,7 +264,7 @@ def cb(xk): f"Conjugate gradient unable to converge after {info} iterations." ) - return x.reshape(self.r, self.basis.count) + return x.reshape(self.r, self.basis.count).astype(self.dtype, copy=False) def apply_kernel(self, vol_coef, kernel=None): """ @@ -283,8 +285,7 @@ def apply_kernel(self, vol_coef, kernel=None): vols_out = Volume( np.zeros((self.r, self.src.L, self.src.L, self.src.L), dtype=self.dtype) ) - - vol = Coef(self.basis, vol_coef).evaluate() + vol = Coef(self.basis, vol_coef.astype(self.dtype, copy=False)).evaluate() for k in range(self.r): for j in range(self.r): diff --git a/src/aspire/sinogram/sinogram.py b/src/aspire/sinogram/sinogram.py index 0f82b0c479..7c7bb43662 100644 --- a/src/aspire/sinogram/sinogram.py +++ b/src/aspire/sinogram/sinogram.py @@ -37,7 +37,7 @@ def __init__(self, data, dtype=None): f"Invalid data shape: {data.shape}. Expected shape: (..., angles, radial_points), where '...' is the stack number." ) - self._data = data.astype(self.dtype, copy=None) + self._data = data.astype(self.dtype, copy=False) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_shape = self._data.shape[:-2] diff --git a/src/aspire/source/micrograph.py b/src/aspire/source/micrograph.py index 86b161d822..5aa35e389c 100644 --- a/src/aspire/source/micrograph.py +++ b/src/aspire/source/micrograph.py @@ -155,7 +155,7 @@ def __init__(self, micrographs, dtype=None, pixel_size=None): ) # We're already backed by an array, access it directly. - self._data = micrographs.astype(self.dtype, copy=None) + self._data = micrographs.astype(self.dtype, copy=False) def _images(self, indices): """ diff --git a/src/aspire/utils/bot_align.py b/src/aspire/utils/bot_align.py index e94888d92e..fc8fbe4fdc 100644 --- a/src/aspire/utils/bot_align.py +++ b/src/aspire/utils/bot_align.py @@ -139,7 +139,7 @@ def cost(new, t=t, q=q): Loss function for surrogate problems. """ kx = np.array( - [cov_fun(new.astype(dtype, copy=None), R[j]) for j in range(t)] + [cov_fun(new.astype(dtype, copy=False), R[j]) for j in range(t)] ) mu = kx @ q return mu @@ -151,7 +151,7 @@ def euclidean_grad(new, t=t, q=q): """ # Corresponds to equation 11 in the paper. kx_grad = np.array( - [cov_fun_grad(new.astype(dtype, copy=None), R[j]) for j in range(t)] + [cov_fun_grad(new.astype(dtype, copy=False), R[j]) for j in range(t)] ) kx_grad = kx_grad.reshape((t, 9)) @@ -168,7 +168,7 @@ def euclidean_grad(new, t=t, q=q): verbosity=verbosity, ) result = optimizer.run(problem) - R_new = result.point.astype(dtype, copy=None) + R_new = result.point.astype(dtype, copy=False) loss[t] = loss_fun(R_new) R[t] = R_new @@ -190,7 +190,7 @@ def loss_u(u): """ Convert the alignment loss function over SO(3) to be over R^3. """ - u = u.astype(dtype, copy=None) + u = u.astype(dtype, copy=False) R = sign * Rotation.from_rotvec(u).matrices[0] v_rot = vol_given_ds.rotate(Rotation(R)).asnumpy()[0] return norm(vol_ref_ds - v_rot) diff --git a/src/aspire/utils/matrix.py b/src/aspire/utils/matrix.py index 534c027b30..f33aa47b23 100644 --- a/src/aspire/utils/matrix.py +++ b/src/aspire/utils/matrix.py @@ -1,5 +1,5 @@ """ -Utilties for arrays/n-dimensional matrices. +Utilities for arrays/n-dimensional matrices. """ import numpy as np @@ -462,7 +462,7 @@ def nearest_rotations(A, allow_reflection=False): # If det(U)*det(V) = -1, we negate the third singular value to # ensure we have a rotation. neg_det_idx = np.linalg.det(U) * np.linalg.det(V) < 0 - U[neg_det_idx] = U[neg_det_idx] @ np.diag((1, 1, -1)).astype(dtype, copy=None) + U[neg_det_idx] = U[neg_det_idx] @ np.diag((1, 1, -1)).astype(dtype, copy=False) rots = U @ V diff --git a/src/aspire/utils/misc.py b/src/aspire/utils/misc.py index 087454de5e..5485c42788 100644 --- a/src/aspire/utils/misc.py +++ b/src/aspire/utils/misc.py @@ -1,5 +1,5 @@ """ -Miscellaneous Utilities that have no better place (yet). +Miscellaneous utilities that have no better place (yet). """ import hashlib @@ -135,7 +135,7 @@ def gaussian_1d(size, mu=0, sigma=1, dtype=np.float64): p = (g["x"] - mu) ** 2 / (2 * sigma**2) - return np.exp(-p).astype(dtype, copy=None) + return np.exp(-p).astype(dtype, copy=False) def gaussian_2d(size, mu=(0, 0), sigma=(1, 1), indexing="yx", dtype=np.float64): @@ -180,7 +180,7 @@ def gaussian_2d(size, mu=(0, 0), sigma=(1, 1), indexing="yx", dtype=np.float64): 2 * sigma[1] ** 2 ) - return np.exp(-p).astype(dtype, copy=None) + return np.exp(-p).astype(dtype, copy=False) def gaussian_3d(size, mu=(0, 0, 0), sigma=(1, 1, 1), indexing="zyx", dtype=np.float64): @@ -228,7 +228,7 @@ def gaussian_3d(size, mu=(0, 0, 0), sigma=(1, 1, 1), indexing="zyx", dtype=np.fl + (g["z"] - mu[2]) ** 2 / (2 * sigma[2] ** 2) ) - return np.exp(-p).astype(dtype, copy=None) + return np.exp(-p).astype(dtype, copy=False) def bump_3d(size, spread=1, dtype=np.float64): diff --git a/src/aspire/utils/rotation.py b/src/aspire/utils/rotation.py index fb643914bf..07a31df9df 100644 --- a/src/aspire/utils/rotation.py +++ b/src/aspire/utils/rotation.py @@ -256,7 +256,7 @@ def from_euler(values, dtype=None): """ dtype = dtype or getattr(values, "dtype", np.float32) rotations = sp_rot.from_euler("ZYZ", values, degrees=False) - matrices = rotations.as_matrix().astype(dtype, copy=None) + matrices = rotations.as_matrix().astype(dtype, copy=False) return Rotation(matrices) @staticmethod @@ -324,7 +324,7 @@ def from_rotvec(vec, dtype=None): """ dtype = dtype or vec.dtype rots = sp_rot.from_rotvec(vec) - matrices = rots.as_matrix().astype(dtype, copy=None) + matrices = rots.as_matrix().astype(dtype, copy=False) return Rotation(matrices) @staticmethod @@ -337,7 +337,7 @@ def from_matrix(values, dtype=None): :return: new Rotation object """ dtype = dtype or values.dtype - return Rotation(values.astype(dtype, copy=None)) + return Rotation(values.astype(dtype, copy=False)) @staticmethod def generate_random_rotations( diff --git a/src/aspire/volume/volume.py b/src/aspire/volume/volume.py index 1954a1cbd5..eae985a794 100644 --- a/src/aspire/volume/volume.py +++ b/src/aspire/volume/volume.py @@ -105,7 +105,7 @@ def __init__(self, data, dtype=None, pixel_size=None, symmetry_group=None): if not (data.shape[-1] == data.shape[-2] == data.shape[-3]): raise ValueError("Only cubed ndarrays are supported.") - self._data = data.astype(self.dtype, copy=None) + self._data = data.astype(self.dtype, copy=False) self.ndim = self._data.ndim self.shape = self._data.shape self.stack_ndim = self._data.ndim - 3 diff --git a/tests/test_FFBbasis3D.py b/tests/test_FFBbasis3D.py index 3992f5d374..03bdfdd21b 100644 --- a/tests/test_FFBbasis3D.py +++ b/tests/test_FFBbasis3D.py @@ -470,7 +470,7 @@ def testFFBBasis3DEvaluate(self, basis): def testFFBBasis3DEvaluate_t(self, basis): x = np.load(os.path.join(DATA_DIR, "ffbbasis3d_xcoef_in_8_8_8.npy")).T # RCOPT - x = x.astype(basis.dtype, copy=None) + x = x.astype(basis.dtype, copy=False) result = basis.evaluate_t(Volume(x)) ref = np.load(os.path.join(DATA_DIR, "ffbbasis3d_vcoef_out_8_8_8.npy"))[..., 0] @@ -479,7 +479,7 @@ def testFFBBasis3DEvaluate_t(self, basis): def testFFBBasis3DExpand(self, basis): x = np.load(os.path.join(DATA_DIR, "ffbbasis3d_xcoef_in_8_8_8.npy")).T # RCOPT - x = x.astype(basis.dtype, copy=None) + x = x.astype(basis.dtype, copy=False) result = basis.expand(x) ref = np.load(os.path.join(DATA_DIR, "ffbbasis3d_vcoef_out_exp_8_8_8.npy"))[ diff --git a/tests/test_coef.py b/tests/test_coef.py index 2a283d16e4..3ace0ddec5 100644 --- a/tests/test_coef.py +++ b/tests/test_coef.py @@ -90,7 +90,7 @@ def coef_fixture(basis, stack, dtype): # shape. size = stack + (basis.count,) - coef_np = np.random.random(size=size).astype(dtype, copy=None) + coef_np = np.random.random(size=size).astype(dtype, copy=False) return Coef(basis, coef_np, dtype=dtype) @@ -212,7 +212,7 @@ def test_add(basis, coef_fixture): Tests addition operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) # Construct Coef c = Coef(basis, x) @@ -231,7 +231,7 @@ def test_sub(basis, coef_fixture): Tests subtraction operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) # Construct Coef c = Coef(basis, x) @@ -264,7 +264,7 @@ def test_mul(basis, coef_fixture): Tests multiplication operation against pure Numpy. """ # Make array - x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=None) + x = np.random.random(size=coef_fixture.shape).astype(coef_fixture.dtype, copy=False) # Construct Coef c = Coef(basis, x) diff --git a/tests/test_diag_matrix.py b/tests/test_diag_matrix.py index 30f2b76faa..05805912c9 100644 --- a/tests/test_diag_matrix.py +++ b/tests/test_diag_matrix.py @@ -65,7 +65,7 @@ def diag_matrix_fixture(stack, matrix_size, dtype): """ shape = (2,) + stack + (matrix_size,) # Internally convert dtype. Passthrough will be checked explicitly in `test_dtype_passthrough` and `test_dtype_cast` - d_np = np.random.random(shape).astype(dtype, copy=None) + d_np = np.random.random(shape).astype(dtype, copy=False) d1 = DiagMatrix(d_np[0]) d2 = DiagMatrix(d_np[1]) diff --git a/tests/test_downsample.py b/tests/test_downsample.py index 1af37d7281..6c1cac82dd 100644 --- a/tests/test_downsample.py +++ b/tests/test_downsample.py @@ -148,7 +148,7 @@ def emdb_vol(): @pytest.fixture(scope="module") def volume(emdb_vol, res, dtype): - vol = emdb_vol.astype(dtype, copy=None) + vol = emdb_vol.astype(dtype, copy=False) vol = vol.downsample(res) return vol @@ -266,7 +266,7 @@ def test_pixel_size(): dsL = 5 # downsampled # Construct a small test Image - img = Image(np.random.random((1, L, L)).astype(DTYPE, copy=None), pixel_size=1.23) + img = Image(np.random.random((1, L, L)).astype(DTYPE, copy=False), pixel_size=1.23) # Downsample the image result = img.downsample(dsL) diff --git a/tests/test_matrix.py b/tests/test_matrix.py index be6829d3fa..728200b9b3 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -356,7 +356,7 @@ def test_nearest_rotations(dtype): rots = Rotation.generate_random_rotations(n_rots, seed=0, dtype=dtype).matrices # Add some noise to the rotations. - noise = 1e-3 * randn(n_rots * 9, seed=0).astype(dtype, copy=None).reshape( + noise = 1e-3 * randn(n_rots * 9, seed=0).astype(dtype, copy=False).reshape( n_rots, 3, 3 ) noisy_rots = rots + noise @@ -381,7 +381,7 @@ def test_nearest_rotations_reflection(dtype): # Add a reflection and some noise to the rotation. refl = rot @ np.diag((1, -1, 1)).astype(dtype) - noise = 1e-3 * randn(9, seed=0).astype(dtype, copy=None).reshape(3, 3) + noise = 1e-3 * randn(9, seed=0).astype(dtype, copy=False).reshape(3, 3) noisy_refl = refl + noise # Find nearest rotation. diff --git a/tests/test_mean_estimator.py b/tests/test_mean_estimator.py index 3e7f915193..e6b2a2f837 100644 --- a/tests/test_mean_estimator.py +++ b/tests/test_mean_estimator.py @@ -115,8 +115,8 @@ def test_adjoint(sim, basis, estimator): L = sim.L n = sim.n - u = np.random.rand(n, L, L).astype(sim.dtype, copy=None) - v = np.random.rand(L, L, L).astype(sim.dtype, copy=None) + u = np.random.rand(n, L, L).astype(sim.dtype, copy=False) + v = np.random.rand(L, L, L).astype(sim.dtype, copy=False) proj = Volume(v).project(rots) backproj = Image(u).backproject(rots) diff --git a/tests/test_micrograph_source.py b/tests/test_micrograph_source.py index c44e703cbb..d4793cf61f 100644 --- a/tests/test_micrograph_source.py +++ b/tests/test_micrograph_source.py @@ -56,7 +56,7 @@ def image_data_fixture(micrograph_count, micrograph_size, dtype): This generates a Numpy array with prescribed shape and dtype. """ img_np = np.random.rand(micrograph_count, micrograph_size, micrograph_size) - return img_np.astype(dtype, copy=None) + return img_np.astype(dtype, copy=False) # ===== diff --git a/tests/test_orient_sdp.py b/tests/test_orient_sdp.py index aa215d1766..22658ee06a 100644 --- a/tests/test_orient_sdp.py +++ b/tests/test_orient_sdp.py @@ -152,7 +152,7 @@ def test_ATA_solver(): rots = Rotation.generate_random_rotations(n=n_rots, seed=seed, dtype=dtype).matrices # Create a simple reference linear transformation A that is rank-3. - A_ref = np.diag([1, 2, 3]).astype(dtype, copy=None) + A_ref = np.diag([1, 2, 3]).astype(dtype, copy=False) # Create v1 and v2 such that A_ref*v1=R1 and A_ref*v2=R2, R1 and R2 are the first # and second columns of all rotations. diff --git a/tests/test_polar_ft.py b/tests/test_polar_ft.py index 4ec69b67e4..425d5e14bb 100644 --- a/tests/test_polar_ft.py +++ b/tests/test_polar_ft.py @@ -203,7 +203,7 @@ def test_half_to_full_transform(stack_shape): """ img_size = 32 image = Image( - np.random.rand(*stack_shape, img_size, img_size).astype(np.float32, copy=None) + np.random.rand(*stack_shape, img_size, img_size).astype(np.float32, copy=False) ) pft = PolarFT(size=img_size) pf = pft.transform(image) diff --git a/tests/test_simulation.py b/tests/test_simulation.py index 46b00d2ce9..944e2e7c06 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -82,7 +82,7 @@ def testPassthroughFromVol(self): without an explcit Simulation dtype. """ for dtype in (np.float32, np.float64): - sim = Simulation(vols=self.vol.astype(dtype, copy=None)) + sim = Simulation(vols=self.vol.astype(dtype, copy=False)) # Did we assign the right type? self.assertTrue(sim.dtype == dtype) diff --git a/tests/test_volume.py b/tests/test_volume.py index 74c77c5cc5..d220860784 100644 --- a/tests/test_volume.py +++ b/tests/test_volume.py @@ -163,10 +163,10 @@ def test_astype(vols_1, dtype): def test_astype_copy(vols_1): """ - `astype(copy=None)` is an optimization partially mimicked from numpy. + `astype(copy=False)` is an optimization partially mimicked from numpy. """ - # Same dtype, copy=None - v2 = vols_1.astype(vols_1.dtype, copy=None) + # Same dtype, copy=False + v2 = vols_1.astype(vols_1.dtype, copy=False) # Details should match, assert isinstance(v2, Volume) assert np.allclose(v2.asnumpy(), vols_1.asnumpy()) From 4d5b3a050bb3d22f8504eb365c63c5934f4340d5 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Wed, 9 Oct 2024 16:19:09 -0400 Subject: [PATCH 11/14] looks like np2 impacted mrcfile as well --- tests/test_mrc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_mrc.py b/tests/test_mrc.py index 363db73a6c..723a45464c 100644 --- a/tests/test_mrc.py +++ b/tests/test_mrc.py @@ -81,15 +81,13 @@ def testUpdate(self): with mrcfile.new_mmap( files[1], shape=(self.n, self.n), mrc_mode=2, overwrite=True ) as mrc: - mrc.set_data(self.a.astype(np.float32)) + mrc.set_data(self.a) + self.stats.update_header(mrc) mrc.header.time = epoch mrc.header.label[0] = label # Our homebrew and mrcfile files should now match to the bit. comparison = sha256sum(files[0]) == sha256sum(files[1]) - # Expected hash: - # 71355fa0bcd5b989ff88166962ea5d2b78ea032933bd6fda41fbdcc1c6d1a009 logging.debug(f"sha256(file0): {sha256sum(files[0])}") logging.debug(f"sha256(file1): {sha256sum(files[1])}") - self.assertTrue(comparison) From 2e03ac4d771a2e87a82db4e053c1527dd0317e38 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Mon, 21 Oct 2024 12:46:55 -0400 Subject: [PATCH 12/14] Tox wants explicit stack level --- src/aspire/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aspire/__init__.py b/src/aspire/__init__.py index 8273099c75..a5145dcd5f 100644 --- a/src/aspire/__init__.py +++ b/src/aspire/__init__.py @@ -98,4 +98,5 @@ def __getattr__(attr): "crash relating to mismatched dtypes or a Numpy call please try" ' `pip install "numpy<2"` and report to ASPIRE developers.', ImportWarning, + stacklevel=1, ) From 4f7a9d48563c2424835e4d5d3b8792c75d364214 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Tue, 22 Oct 2024 08:29:17 -0400 Subject: [PATCH 13/14] missing space in warning message --- src/aspire/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspire/__init__.py b/src/aspire/__init__.py index a5145dcd5f..686280e8e9 100644 --- a/src/aspire/__init__.py +++ b/src/aspire/__init__.py @@ -95,7 +95,7 @@ def __getattr__(attr): warnings.simplefilter("default") warnings.warn( "ASPIRE's Numpy 2 support is in beta. If you experience a runtime" - "crash relating to mismatched dtypes or a Numpy call please try" + " crash relating to mismatched dtypes or a Numpy call please try" ' `pip install "numpy<2"` and report to ASPIRE developers.', ImportWarning, stacklevel=1, From 5e75e20c4c7e4baf4c00cbbaafa6d433bc212264 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Tue, 22 Oct 2024 08:31:25 -0400 Subject: [PATCH 14/14] misc cleanup, reducing pr delta from draft work --- src/aspire/image/xform.py | 1 - src/aspire/reconstruction/estimator.py | 1 + src/aspire/reconstruction/mean.py | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/aspire/image/xform.py b/src/aspire/image/xform.py index 38f65d9bee..8003b4a1c5 100644 --- a/src/aspire/image/xform.py +++ b/src/aspire/image/xform.py @@ -144,7 +144,6 @@ def __init__(self, factor): self.multipliers = np.array(factor) def _forward(self, im, indices): - if self.multipliers.size == 1: # if we have a scalar multiplier im_new = im * self.multipliers.astype(im.dtype) else: diff --git a/src/aspire/reconstruction/estimator.py b/src/aspire/reconstruction/estimator.py index ac5e9caeca..2bf0ec3366 100644 --- a/src/aspire/reconstruction/estimator.py +++ b/src/aspire/reconstruction/estimator.py @@ -159,6 +159,7 @@ def apply_kernel(self, vol_coef, kernel=None): if kernel is None: kernel = self.kernel + vol = Coef(self.basis, vol_coef).evaluate() # returns a Volume vol = kernel.convolve_volume(vol) # returns a Volume vol_coef = self.basis.evaluate_t(vol) diff --git a/src/aspire/reconstruction/mean.py b/src/aspire/reconstruction/mean.py index b380c8788c..e3888ee200 100644 --- a/src/aspire/reconstruction/mean.py +++ b/src/aspire/reconstruction/mean.py @@ -5,9 +5,10 @@ from scipy.linalg import norm from scipy.sparse.linalg import LinearOperator +from aspire import config from aspire.basis import Coef from aspire.nufft import anufft -from aspire.numeric import config, fft +from aspire.numeric import fft from aspire.numeric.scipy import cg from aspire.operators import evaluate_src_filters_on_grid from aspire.reconstruction import Estimator, FourierKernel, FourierKernelMatrix @@ -211,7 +212,6 @@ def conj_grad(self, b_coef, x0=None, tol=1e-5, regularizer=0): precond_kernel = self.precond_kernel if regularizer > 0: precond_kernel += regularizer - M = LinearOperator( (self.r * count, self.r * count), matvec=partial(self.apply_kernel, kernel=precond_kernel),