Associating particle CTF parameters with micrographs

Hi,

Let’s say I have refined per-group CTF parameters using one particle set (using Global CTF refinement, which modifies the particle CTF blob).

Is there a way (perhaps using cryosparc-tools?) to copy those parameters back to the micrograph CTF slot?

This would be useful for heterogeneous samples, e.g. from native extracts, as it would allow for the refinement of beam tilt/trefoil etc for the best behaving (highest resolution) species in the sample, and transfer of those parameters to other particle sets of different species extracted from the same set of micrographs.

Cheers
Oli

1 Like

Hi @olibclarke, some of the particle CTF fields modified by Global CTF Refinement (tilt, trefoil and others) are not available in micrograph CTFs. You can instead copy those parameters to new particle datasets based on their exposure groups.

Here’s a partial script that could do this with cryosparc-tools:

from cryosparc.tools import CryoSPARC

cs = CryoSPARC(...)  # Substitute instance details and credentials here

# Substitute with project and job details:
puid = "P#"
wuid = "W#"
ref_particles_juid = "JX"
ref_particles_output = "particles"
new_particles_juid = "JY"
new_particles_output = "particles"

# Setup job
job = cs.create_external_job(puid, wuid, title="New CTF Refined Particles")
job.connect("ref_particles", ref_particles_juid, ref_particles_output, slots=["ctf"])
job.connect("new_particles", new_particles_juid, new_particles_output, slots=["ctf"])
job.add_output("particle", "particles", slots=["ctf"], passthrough="new_particles")

# Run job
with job.run():
    ref_particles = job.load_input("ref_particles", slots=["ctf"])
    new_particles = job.load_input("new_particles", slots=["ctf"])

    for exp_group, ref_parts in ref_particles.split_by("ctf/exp_group_id").items():
        mask = new_particles['ctf/exp_group_id'] == exp_group
        for field in [  # add/remove fields here as needed
            'ctf/accel_kv',
            'ctf/cs_mm',
            'ctf/df_angle_rad',
            'ctf/df1_A',
            'ctf/df2_A',
            'ctf/phase_shift_rad',
            'ctf/anisomag',
            'ctf/shift_A',
            'ctf/tilt_A',
            'ctf/trefoil_A',
            'ctf/tetra_A'
        ]:
            new_particles[field][mask] = ref_parts[field][0]

    job.save_output("particles", new_particles)

Be sure to make the noted substitutions.

This script does the following:

  1. Create a new External job with the CTF refined particles (ref_particles) and newly-picked unrefined particles (new_particles) as input.
  2. Load the ctf slot for both inputs
  3. Split the refined particles by their exposure group
  4. For each exposure group, update the new particles with the relevant fields from the first refined particle in the matching group

I may have flagged fields that shouldn’t change in the new particles dataset, you can take those out if they’re not needed. Hope that helps! Let me know if you run into any trouble with it.

2 Likes

Thank you @nfrasser this is very helpful, I will give it a go!

Cheers
Oli

1 Like