Skip to content
2 changes: 1 addition & 1 deletion gallery/tutorials/aspire_introduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ def noise_function(x, y):

# Generate several CTFs.
ctf_filters = [
RadialCTFFilter(pixel_size=vol_ds.pixel_size, defocus=d)
RadialCTFFilter(defocus=d)
for d in np.linspace(defocus_min, defocus_max, defocus_ct)
]

Expand Down
2 changes: 1 addition & 1 deletion gallery/tutorials/pipeline_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
defocus_ct = 7

ctf_filters = [
RadialCTFFilter(pixel_size=original_vol.pixel_size, defocus=d)
RadialCTFFilter(defocus=d)
for d in np.linspace(defocus_min, defocus_max, defocus_ct)
]

Expand Down
7 changes: 5 additions & 2 deletions gallery/tutorials/tutorials/cov2d_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
print("Initialize simulation object and CTF filters.")
# Create filters
ctf_filters = [
RadialCTFFilter(pixel_size, voltage, defocus=d, Cs=2.0, alpha=0.1)
RadialCTFFilter(voltage, defocus=d, Cs=2.0, alpha=0.1)
for d in np.linspace(defocus_min, defocus_max, defocus_ct)
]

Expand All @@ -94,6 +94,7 @@
amplitudes=1.0,
dtype=dtype,
noise_adder=noise_adder,
pixel_size=pixel_size,
)


Expand All @@ -108,7 +109,9 @@
h_idx = sim.filter_indices

# Evaluate CTF in the 8X8 FB basis
h_ctf_fb = [ffbbasis.filter_to_basis_mat(filt) for filt in ctf_filters]
h_ctf_fb = [
ffbbasis.filter_to_basis_mat(filt, pixel_size=pixel_size) for filt in ctf_filters
]

# Get clean images from projections of 3D map.
print("Apply CTF filters to clean images.")
Expand Down
7 changes: 3 additions & 4 deletions gallery/tutorials/tutorials/cov3d_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,15 @@
L=img_size,
C=3,
dtype=dtype,
pixel_size=10,
).generate()

# Create a simulation object with specified filters
sim = Simulation(
L=img_size,
n=num_imgs,
vols=vols,
unique_filters=[
RadialCTFFilter(pixel_size=10, defocus=d) for d in np.linspace(1.5e4, 2.5e4, 7)
],
unique_filters=[RadialCTFFilter(defocus=d) for d in np.linspace(1.5e4, 2.5e4, 7)],
dtype=dtype,
)

Expand Down Expand Up @@ -89,7 +88,7 @@
eigs_est, lambdas_est = eigs(covar_est, num_eigs)

# Eigs returns column-major, so we transpose and construct a volume.
eigs_est = Volume(np.transpose(eigs_est, (3, 0, 1, 2)))
eigs_est = Volume(np.transpose(eigs_est, (3, 0, 1, 2)), pixel_size=vols.pixel_size)

# Truncate the eigendecomposition. Since we know the true rank of the
# covariance matrix, we enforce it here.
Expand Down
51 changes: 19 additions & 32 deletions gallery/tutorials/tutorials/ctf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
# Image size to use throughout the demo.
IMG_SIZE = 512


# %%
# Visualizing the CTF
# -------------------
Expand All @@ -40,7 +41,6 @@
from aspire.operators import CTFFilter, RadialCTFFilter

radial_ctf_filter = RadialCTFFilter(
pixel_size=1, # angstrom
voltage=200, # kV
defocus=10000, # angstrom, 10000 A = 1 um
Cs=2.26, # Spherical aberration constant
Expand All @@ -51,7 +51,7 @@
# The CTF filter can be visualized as an image once it is evaluated at a specific resolution.
# More specifically the following code will return a transfer function as an array,
# which is then plotted.
rctf_fn = radial_ctf_filter.evaluate_grid(IMG_SIZE)
rctf_fn = radial_ctf_filter.evaluate_grid(IMG_SIZE, pixel_size=1)
plt.imshow(rctf_fn)
plt.colorbar()
plt.show()
Expand All @@ -66,7 +66,6 @@
# and the values more typically differ by a few percent.

ctf_filter = CTFFilter(
pixel_size=1, # angstrom
voltage=200, # kV
defocus_u=15000, # angstrom, 10000 A = 1 um
defocus_v=10000,
Expand All @@ -77,7 +76,7 @@
)

# Again, we plot it, and note the difference from the RadialCTFFilter.
plt.imshow(ctf_filter.evaluate_grid(IMG_SIZE))
plt.imshow(ctf_filter.evaluate_grid(IMG_SIZE, pixel_size=1))
plt.colorbar()
plt.show()

Expand All @@ -90,7 +89,7 @@
# array returned by ASPIRE's ``CTFFilter.evaluate_grid``.


ctf_sign = np.sign(radial_ctf_filter.evaluate_grid(IMG_SIZE))
ctf_sign = np.sign(radial_ctf_filter.evaluate_grid(IMG_SIZE, pixel_size=1))
plt.imshow(ctf_sign)
plt.colorbar()
plt.show()
Expand Down Expand Up @@ -140,10 +139,9 @@ def generate_example_image(L, noise_variance=0.1):
return img


img = generate_example_image(IMG_SIZE)
plt.imshow(img)
plt.colorbar()
plt.show()
img = Image(generate_example_image(IMG_SIZE), pixel_size=1)
img.show()


# %%
# Apply CTF and Phase Flipping
Expand All @@ -157,26 +155,19 @@ def generate_example_image(L, noise_variance=0.1):
# Construct a range of CTF filters.
defoci = [2500, 5000, 10000, 20000]
ctf_filters = [
RadialCTFFilter(pixel_size=1 / 2, voltage=200, defocus=d, Cs=2.26, alpha=0.07, B=0)
for d in defoci
RadialCTFFilter(voltage=200, defocus=d, Cs=2.26, alpha=0.07, B=0) for d in defoci
]

# %%
# .. note::
# Pixel size was chosen to demonstrate effects similar to lecture notes,
# but at a higher resolution.


# %%
# Generate CTF corrupted Images
# """""""""""""""""""""""""""""
# Generate images corrupted by progressively increasing defocus.

# For each defocus, apply filter to the base image.
imgs = np.empty((len(defoci), IMG_SIZE, IMG_SIZE))
imgs = Image(np.empty((len(defoci), IMG_SIZE, IMG_SIZE)), pixel_size=1)
for i, ctf in enumerate(ctf_filters):
imgs[i] = Image(img).filter(ctf)[0]
Image(imgs).show()
imgs[i] = img.filter(ctf)[0]
imgs.show()

# %%
# Generate Phase Flipped Images
Expand All @@ -191,13 +182,13 @@ def generate_example_image(L, noise_variance=0.1):
# Compute the signs of this CTF
# In practice, this would be an estimated CTF,
# but in the demo we have the luxury of using the model CTF that was applied.
signs = np.sign(ctf.evaluate_grid(IMG_SIZE))
signs = np.sign(ctf.evaluate_grid(IMG_SIZE, pixel_size=1))
# Apply to the image in Fourier space.
phase_flipped_imgs_f[i] = signs * imgs_f[i]

# Construct the centered 2D FFT of the images.
phase_flipped_imgs = aspire.numeric.fft.centered_ifft2(phase_flipped_imgs_f).real
Image(phase_flipped_imgs).show()
Image(phase_flipped_imgs, pixel_size=1).show()

# %%
# .. warning::
Expand All @@ -218,15 +209,14 @@ def generate_example_image(L, noise_variance=0.1):
# along with an erroneous CTF filter.

bad_est_ctf_filter = RadialCTFFilter(
pixel_size=1,
voltage=200,
defocus=14000, # Modeled CTF was 10000
Cs=2.26,
alpha=0.07,
B=0,
)
# Evaluate Filter, returning a Numpy array.
bad_ctf_fn = bad_est_ctf_filter.evaluate_grid(IMG_SIZE)
bad_ctf_fn = bad_est_ctf_filter.evaluate_grid(IMG_SIZE, pixel_size=1)

c = IMG_SIZE // 2 + 1
plt.plot(rctf_fn[c, c:], label="Model CTF") # radial_ctf_filter
Expand Down Expand Up @@ -257,18 +247,16 @@ def generate_example_image(L, noise_variance=0.1):
from aspire.ctf import estimate_ctf

# Using our radial_ctf_filter from earlier, corrupt an image.
test_img = Image(img).filter(radial_ctf_filter)
plt.imshow(test_img.asnumpy()[0])
plt.colorbar()
plt.show()
test_img = img.filter(radial_ctf_filter)
test_img.show()

# Create the image file in a tmp dir
with TemporaryDirectory() as d:
test_img.save(os.path.join(d, "test_img.mrc"))

radial_ctf_est = estimate_ctf(
data_folder=d,
pixel_size=radial_ctf_filter.pixel_size,
pixel_size=1,
cs=radial_ctf_filter.Cs,
amplitude_contrast=radial_ctf_filter.alpha,
voltage=radial_ctf_filter.voltage,
Expand Down Expand Up @@ -296,14 +284,13 @@ def generate_example_image(L, noise_variance=0.1):

# Create a filter and evaluate.
est_ctf = RadialCTFFilter(
pixel_size=est["pixel_size"],
voltage=est["voltage"],
defocus=defocus, # Modeled CTF was 10000
Cs=est["cs"],
alpha=est["amplitude_contrast"],
B=0,
)
est_ctf_fn = est_ctf.evaluate_grid(IMG_SIZE)
est_ctf_fn = est_ctf.evaluate_grid(IMG_SIZE, pixel_size=1)

# Compare the model CTF with the estimated CTF.
c = IMG_SIZE // 2 + 1
Expand Down Expand Up @@ -347,7 +334,7 @@ def generate_example_image(L, noise_variance=0.1):
from aspire.source import Simulation

# Create the Source. ``ctf_filters`` are re-used from earlier section.
src = Simulation(L=64, n=4, unique_filters=ctf_filters)
src = Simulation(L=64, n=4, unique_filters=ctf_filters, pixel_size=1)
src.images[:4].show()

# %%
Expand Down
8 changes: 5 additions & 3 deletions gallery/tutorials/tutorials/image_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

# Create an ASPIRE Image instance from the data
# We'll tell it to convert to floating point data as well.
im = Image(img_data, dtype=np.float64)
# Adding a `pixel_size` will pass through to subsequent codes like
# filtering which may require it.
im = Image(img_data, pixel_size=1, dtype=np.float64)

# %%
# Plot the Image Stack
Expand Down Expand Up @@ -57,6 +59,6 @@
# CTF Filter
# ----------

# pixel_size/defous_u/defocus_v in angstrom, voltage in kV
filter = CTFFilter(pixel_size=1, voltage=100, defocus_u=1500, defocus_v=2000)
# defous_u/defocus_v in angstrom, voltage in kV
filter = CTFFilter(voltage=100, defocus_u=1500, defocus_v=2000)
im.filter(filter).show()
3 changes: 2 additions & 1 deletion gallery/tutorials/tutorials/micrograph_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
vol = AsymmetricVolume(
L=100,
C=1,
pixel_size=4,
seed=1234,
dtype=np.float32,
).generate()
Expand Down Expand Up @@ -181,7 +182,7 @@
# Create our CTF Filter and add it to a list.
# This configuration will apply the same CTF to all particles.
ctfs = [
RadialCTFFilter(pixel_size=4, voltage=200, defocus=15000, Cs=2.26, alpha=0.07, B=0),
RadialCTFFilter(voltage=200, defocus=15000, Cs=2.26, alpha=0.07, B=0),
]

src = MicrographSimulation(
Expand Down
7 changes: 4 additions & 3 deletions gallery/tutorials/tutorials/orient3d_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@

# Specify the CTF parameters not used for this example
# but necessary for initializing the simulation object
pixel_size = 5 # Pixel size of the images (in angstroms)
voltage = 200 # Voltage (in KV)
defocus_min = 1.5e4 # Minimum defocus value (in angstroms)
defocus_max = 2.5e4 # Maximum defocus value (in angstroms)
Expand All @@ -51,7 +50,7 @@
print("Initialize simulation object and CTF filters.")
# Create CTF filters
filters = [
RadialCTFFilter(pixel_size, voltage, defocus=d, Cs=2.0, alpha=0.1)
RadialCTFFilter(voltage, defocus=d, Cs=2.0, alpha=0.1)
for d in np.linspace(defocus_min, defocus_max, defocus_ct)
]

Expand All @@ -74,7 +73,9 @@

# Create a simulation object with specified filters and the downsampled 3D map
print("Use downsampled map to creat simulation object.")
sim = Simulation(L=img_size, n=num_imgs, vols=vols, unique_filters=filters, dtype=dtype)
sim = Simulation(
L=img_size, n=num_imgs, vols=vols, unique_filters=filters, pixel_size=5, dtype=dtype
)

print("Get true rotation angles generated randomly by the simulation object.")
rots_true = sim.rotations
Expand Down
3 changes: 2 additions & 1 deletion gallery/tutorials/tutorials/preprocess_imgs_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
print("Initialize simulation object and CTF filters.")
# Create CTF filters
ctf_filters = [
RadialCTFFilter(pixel_size, voltage, defocus=d, Cs=2.0, alpha=0.1)
RadialCTFFilter(voltage, defocus=d, Cs=2.0, alpha=0.1)
for d in np.linspace(defocus_min, defocus_max, defocus_ct)
]

Expand All @@ -75,6 +75,7 @@
vols=vols,
unique_filters=ctf_filters,
noise_adder=noise_adder,
pixel_size=pixel_size,
)

# %%
Expand Down
6 changes: 5 additions & 1 deletion src/aspire/basis/ffb_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ def filter_to_basis_mat(self, f, **kwargs):
" Use `method=None`."
)

pixel_size = kwargs.get("pixel_size", None)

# These form a circular dependence, import locally until time to clean up.
from aspire.basis.basis_utils import lgwt

Expand All @@ -269,7 +271,9 @@ def filter_to_basis_mat(self, f, **kwargs):
omegay = k * np.sin(theta)
omega = 2 * np.pi * np.vstack((omegax.flatten("C"), omegay.flatten("C")))

h_vals2d = h_fun(omega).reshape(n_k, n_theta).astype(self.dtype)
h_vals2d = (
h_fun(omega, pixel_size=pixel_size).reshape(n_k, n_theta).astype(self.dtype)
)
h_vals = np.sum(h_vals2d, axis=1) / n_theta

# Represent 1D function values in basis
Expand Down
3 changes: 2 additions & 1 deletion src/aspire/basis/fle_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ def filter_to_basis_mat(self, f, **kwargs):
"`FLEBasis2D.filter_to_basis_mat` method {method} not supported."
" Use `method=None`."
)
pixel_size = kwargs.get("pixel_size", None)

# Get the filter's evaluate function.
h_fun = f.evaluate
Expand All @@ -802,7 +803,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))
xp.asarray(h_fun(omega, pixel_size=pixel_size))
.reshape(n_k, n_theta)
.astype(self.dtype, copy=False)
)
Expand Down
2 changes: 1 addition & 1 deletion src/aspire/basis/fspca.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ def shift(self, coef, shifts):
self.evaluate_to_image_basis(coef).shift(shifts)
)

def filter_to_basis_mat(self, f):
def filter_to_basis_mat(self, f, **kwargs):
"""
Convert a filter into a basis representation.

Expand Down
Loading
Loading