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)
relion projection interop

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)
relion projection interop

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)
  • relion projection interop
  • relion projection interop

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)
Fourier Ring Correlation
(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)

Gallery generated by Sphinx-Gallery