Note
Go to the end to download the full example code.
Relion Projection Interoperability¶
In this tutorial we compare projections generated by Relion
with projections generated by ASPIRE’s Simulation
class.
Both sets of projections are generated using a downsampled
volume map of a 70S Ribosome, absent of noise and CTF corruption.
import os
import numpy as np
from aspire.source import RelionSource, Simulation
from aspire.volume import Volume
Load Relion Projections¶
We load the Relion projections as a RelionSource
and view the images.
starfile = os.path.join(os.path.dirname(os.getcwd()), "data", "rln_proj_65.star")
rln_src = RelionSource(starfile)
rln_src.images[:].show(colorbar=False)
Note
The projections above were generated in Relion using the following command:
relion_project --i clean70SRibosome_vol_65p.mrc --nr_uniform 3000 --angpix 5
For this tutorial we take a subset of these projections consisting of the first 5 images.
Generate Projections using Simulation
¶
Using the metadata associated with the RelionSource
and the same volume
we generate an analogous set of projections with ASPIRE’s Simulation
class.
# Load the volume from file as a ``Volume`` object.
filepath = os.path.join(
os.path.dirname(os.getcwd()), "data", "clean70SRibosome_vol_65p.mrc"
)
vol = Volume.load(filepath, dtype=rln_src.dtype)
# Create a ``Simulation`` source using metadata from the RelionSource projections.
# Note, for odd resolution Relion projections are shifted from ASPIRE projections
# by 1 pixel in x and y.
sim_src = Simulation(
n=rln_src.n,
vols=vol,
offsets=-np.ones((rln_src.n, 2), dtype=rln_src.dtype),
amplitudes=rln_src.amplitudes,
angles=rln_src.angles,
dtype=rln_src.dtype,
)
sim_src.images[:].show(colorbar=False)
Comparing the Projections¶
We will take a few different approaches to comparing the two sets of projection images.
Visual Comparison¶
We’ll first look at a side-by-side of the two sets of images to confirm visually that the projections are taken from the same viewing angles.
rln_src.images[:].show(colorbar=False)
sim_src.images[:].show(colorbar=False)
Fourier Ring Correlation¶
Additionally, we can compare the two sets of images using the FRC. Note that the images are tightly correlated up to a high resolution of 2 pixels.
rln_src.images[:].frc(sim_src.images[:], cutoff=0.143, plot=True)
(array([2.03125, 2.03125, 2.03125, 2.03125, 2.03125]), array([[0.9999512 , 0.999759 , 0.99972236, 0.9997412 , 0.9998079 ,
0.9996844 , 0.9998557 , 0.9998626 , 0.9996015 , 0.99980164,
0.99976003, 0.9993758 , 0.99953103, 0.9995893 , 0.9993813 ,
0.9995789 , 0.9996112 , 0.99948025, 0.9995136 , 0.9994556 ,
0.9994089 , 0.99950975, 0.99942386, 0.9993721 , 0.9992845 ,
0.9991798 , 0.9993925 , 0.99923795, 0.9991501 , 0.99885595,
0.99914384, 0.6890403 ],
[0.99996096, 0.99965173, 0.9994138 , 0.9996295 , 0.9995364 ,
0.99973553, 0.99981254, 0.99972916, 0.99975425, 0.99976027,
0.9997864 , 0.9996998 , 0.99965954, 0.99939144, 0.9995732 ,
0.9993533 , 0.99950606, 0.9995502 , 0.999231 , 0.99947745,
0.9993991 , 0.9992753 , 0.9993047 , 0.9992678 , 0.99936014,
0.99925387, 0.99918777, 0.9992852 , 0.9992362 , 0.99918747,
0.9990527 , 0.65634775],
[0.99980867, 0.9999284 , 0.9996262 , 0.99976695, 0.99972284,
0.99960023, 0.99968237, 0.9997462 , 0.9998087 , 0.9996951 ,
0.9998498 , 0.99968654, 0.9996273 , 0.999716 , 0.99958813,
0.9995541 , 0.99949145, 0.9993192 , 0.9991363 , 0.9995127 ,
0.9994655 , 0.99959916, 0.99941707, 0.99944943, 0.99925214,
0.9989504 , 0.99913025, 0.9994102 , 0.99942446, 0.9992472 ,
0.9988977 , 0.6197825 ],
[0.9998406 , 0.99976444, 0.9996911 , 0.9998639 , 0.9996305 ,
0.9997982 , 0.9997752 , 0.999624 , 0.9997876 , 0.99984205,
0.9998592 , 0.9996771 , 0.99947655, 0.9992746 , 0.9995294 ,
0.999453 , 0.9995276 , 0.99958897, 0.99937934, 0.9994439 ,
0.9995143 , 0.99963874, 0.9994447 , 0.9992456 , 0.9992859 ,
0.99928594, 0.9989984 , 0.999283 , 0.99888486, 0.9988116 ,
0.9988935 , 0.71348727],
[0.9999206 , 0.99977803, 0.99962074, 0.9996264 , 0.9994459 ,
0.9997416 , 0.9997853 , 0.99961793, 0.9997695 , 0.9998145 ,
0.9997705 , 0.99975216, 0.9997678 , 0.99958897, 0.99926215,
0.99953574, 0.9994928 , 0.9995174 , 0.99969566, 0.99941885,
0.9994484 , 0.999326 , 0.9993586 , 0.9993657 , 0.99932224,
0.999234 , 0.99943435, 0.99917585, 0.9990706 , 0.99915725,
0.9991647 , 0.6540194 ]], dtype=float32))
Relative Error¶
As Relion and ASPIRE differ in methods of generating projections, the pixel intensity of the images may not correspond perfectly. So we begin by first normalizing the two sets of projections. We then check that the relative error with respect to the frobenius norm is less than 3%.
# Work with numpy arrays.
rln_np = rln_src.images[:].asnumpy()
sim_np = sim_src.images[:].asnumpy()
# Normalize images.
rln_np = (rln_np - np.mean(rln_np)) / np.std(rln_np)
sim_np = (sim_np - np.mean(sim_np)) / np.std(sim_np)
# Assert that error is less than 3%.
error = np.linalg.norm(rln_np - sim_np, axis=(1, 2)) / np.linalg.norm(
rln_np, axis=(1, 2)
)
assert all(error < 0.03)
print(f"Relative per-image error: {error}")
Relative per-image error: [0.02434896 0.02776876 0.02810044 0.02241788 0.02729609]
Total running time of the script: (0 minutes 1.451 seconds)