Experimental support for Relion's Bayesian polishing in csparc2star.py

Hi Daniel,

I’ve been looking at all the availible .cs files in the MotionCorr and movie import jobs with the cryosparc icli to see the available fields. I’m not sure any of these contain the Z size unless this is stored in ‘shape’.

Either way I attach these incase you spot something I don’t…

From the motion corr job:

micrographs_rigid_aligned.cs

                         uid   <u8
                    micrograph_blob/path    |O
                     micrograph_blob/idx   <u4
                   micrograph_blob/shape   <u4       (2,)
                 micrograph_blob/psize_A   <f4
                  micrograph_blob/format    |O
micrograph_blob/is_background_subtracted   <u4
                    micrograph_blob/vmin   <f4
                    micrograph_blob/vmax   <f4
              micrograph_blob/import_sig   <u8
             micrograph_blob_non_dw/path    |O
              micrograph_blob_non_dw/idx   <u4
            micrograph_blob_non_dw/shape   <u4       (2,)
          micrograph_blob_non_dw/psize_A   <f4
           micrograph_blob_non_dw/format    |O
micrograph_blob_non_dw/is_background_subtracted   <u4
             micrograph_blob_non_dw/vmin   <f4
             micrograph_blob_non_dw/vmax   <f4
       micrograph_blob_non_dw/import_sig   <u8
       micrograph_thumbnail_blob_1x/path    |O
        micrograph_thumbnail_blob_1x/idx   <u4
      micrograph_thumbnail_blob_1x/shape   <u4       (2,)
     micrograph_thumbnail_blob_1x/format    |O
  micrograph_thumbnail_blob_1x/binfactor   <u4
micrograph_thumbnail_blob_1x/micrograph_path    |O
       micrograph_thumbnail_blob_1x/vmin   <f4
       micrograph_thumbnail_blob_1x/vmax   <f4
       micrograph_thumbnail_blob_2x/path    |O
        micrograph_thumbnail_blob_2x/idx   <u4
      micrograph_thumbnail_blob_2x/shape   <u4       (2,)
     micrograph_thumbnail_blob_2x/format    |O
  micrograph_thumbnail_blob_2x/binfactor   <u4
micrograph_thumbnail_blob_2x/micrograph_path    |O
       micrograph_thumbnail_blob_2x/vmin   <f4
       micrograph_thumbnail_blob_2x/vmax   <f4
                    background_blob/path    |O
                     background_blob/idx   <u4
               background_blob/binfactor   <u4
                   background_blob/shape   <u4       (2,)
                 background_blob/psize_A   <f4
                       rigid_motion/type    |O
                       rigid_motion/path    |O
                        rigid_motion/idx   <u4
                rigid_motion/frame_start   <u4
                  rigid_motion/frame_end   <u4
           rigid_motion/zero_shift_frame   <u4
                    rigid_motion/psize_A   <f4
                      spline_motion/type    |O
                      spline_motion/path    |O
                       spline_motion/idx   <u4
               spline_motion/frame_start   <u4
                 spline_motion/frame_end   <u4
          spline_motion/zero_shift_frame   <u4
                   spline_motion/psize_A   <f4

passthrough_micrographs.cs

uid   <u8
                         movie_blob/path    |O
                        movie_blob/shape   <u4       (3,)
                      movie_blob/psize_A   <f4
            movie_blob/is_gain_corrected   <u4
                       movie_blob/format    |O
              movie_blob/has_defect_file   <u4
                   movie_blob/import_sig   <u8
                      gain_ref_blob/path    |O
                       gain_ref_blob/idx   <u4
                     gain_ref_blob/shape   <u4       (2,)
                    gain_ref_blob/flip_x   <u4
                    gain_ref_blob/flip_y   <u4
                gain_ref_blob/rotate_num   <u4
                  mscope_params/accel_kv   <f4
                     mscope_params/cs_mm   <f4
       mscope_params/total_dose_e_per_A2   <f4
               mscope_params/phase_plate   <u4
                 mscope_params/neg_stain   <u4
              mscope_params/exp_group_id   <u4
               mscope_params/defect_path    |O

From the movies import job, imported_movies.cs

uid   <u8
                         movie_blob/path    |O
                        movie_blob/shape   <u4       (3,)
                      movie_blob/psize_A   <f4
            movie_blob/is_gain_corrected   <u4
                       movie_blob/format    |O
              movie_blob/has_defect_file   <u4
                   movie_blob/import_sig   <u8
                      gain_ref_blob/path    |O
                       gain_ref_blob/idx   <u4
                     gain_ref_blob/shape   <u4       (2,)
                    gain_ref_blob/flip_x   <u4
                    gain_ref_blob/flip_y   <u4
                gain_ref_blob/rotate_num   <u4
                  mscope_params/accel_kv   <f4
                     mscope_params/cs_mm   <f4
       mscope_params/total_dose_e_per_A2   <f4
               mscope_params/phase_plate   <u4
                 mscope_params/neg_stain   <u4
              mscope_params/exp_group_id   <u4
               mscope_params/defect_path    |O

Our Motion Corr job was run offline and the output with --loglevel=info is:

Writing per-movie star files into MovieExport/Movies/
Creating movie data_general tables
Copying micrograph size
Traceback (most recent call last):
  File "/xxx/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/indexes/base.py", line 3361, in get_loc
    return self._engine.get_loc(casted_key)
  File "pandas/_libs/index.pyx", line 76, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 5198, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 5206, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'rlnImageSizeZ'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/xxx/software/pyem/csparc2star.py", line 170, in <module>
    sys.exit(main(parser.parse_args()))
  File "/xxx/software/pyem/csparc2star.py", line 59, in main
    data_general = metadata.cryosparc_2_cs_movie_parameters(cs, passthrough=pt, trajdir=trajdir, path=args.micrograph_path)
  File "/xxx/software/pyem/pyem/metadata/cryosparc2.py", line 222, in cryosparc_2_cs_movie_parameters
    data_general[star.Relion.MICROGRAPHDOSERATE] /= data_general[star.Relion.IMAGESIZEZ]
  File "/xxx/software/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/frame.py", line 3458, in __getitem__
    indexer = self.columns.get_loc(key)
  File "/xxx/software/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/indexes/base.py", line 3363, in get_loc
    raise KeyError(key) from err
KeyError: 'rlnImageSizeZ'

Z size is is something cryosparc should automatically read from the input movies I’m guessing? Perhaps there is a way for me to modify the .cs file to include an extra field if this is missing? Or is it stored in ‘shape’?

Thanks so much for you help on all of this!

Max

@maxm that’s right, it comes from ‘movie_blob/shape’. You get the error even if the passthrough file is first on the csparc2star.py command?

@maxm I just made a commit that should let it get rlnImageSizeZ from the passthrough OR the main .cs file regardless of the order.

2 Likes

Hi Daniel,

Some progress! I just reinstalled and attempted the conversion with both potential orders.

The error persists when Passthrough is second:

Writing per-movie star files into MovieExport/Movies/
Creating movie data_general tables
Copying micrograph size
Copying micrograph size
Traceback (most recent call last):
  File "xxx/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/indexes/base.py", line 3361, in get_loc
    return self._engine.get_loc(casted_key)
  File "pandas/_libs/index.pyx", line 76, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 5198, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 5206, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'rlnImageSizeZ'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/xxx/pyem/csparc2star.py", line 177, in <module>
    sys.exit(main(parser.parse_args()))
  File "/xxx/pyem/csparc2star.py", line 59, in main
    data_general = metadata.cryosparc_2_cs_movie_parameters(cs, passthrough=pt, trajdir=trajdir, path=args.micrograph_path)
  File "/xxx/pyem/pyem/metadata/cryosparc2.py", line 223, in cryosparc_2_cs_movie_parameters
    data_general[star.Relion.MICROGRAPHDOSERATE] /= data_general[star.Relion.IMAGESIZEZ]
  File "/xxx/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/frame.py", line 3458, in __getitem__
    indexer = self.columns.get_loc(key)
  File "xxx/miniconda3/envs/pyem/lib/python3.9/site-packages/pandas/core/indexes/base.py", line 3363, in get_loc
    raise KeyError(key) from err
KeyError: 'rlnImageSizeZ'

However, with passthrough as the first argument there is a new error message…

Writing per-movie star files into MovieExport/Movies/
Creating movie data_general tables
Copying movie size
Copying movie size
Reading movie trajectory files
Traceback (most recent call last):
  File "/xxx/csparc2star.py", line 177, in <module>
    sys.exit(main(parser.parse_args()))
  File "/xxx/pyem/csparc2star.py", line 62, in main
    for mic in metadata.cryosparc_2_cs_motion_parameters(cs, data_general, trajdir=trajdir):
  File "/xxx/pyem/pyem/metadata/cryosparc2.py", line 249, in cryosparc_2_cs_motion_parameters
    trajfile = cs['rigid_motion/path'][i].decode('UTF-8')
ValueError: no field of name rigid_motion/path

Thanks again,
Max

Hi @DanielAsarnow,

pyem version: git cloned on 3 Dec.

Use case: csparc2star.py conversion of particles extracted from micrographs imported without connected source movies (i.e. motion-correction performed outside of cryoSPARC).

Error message:

Traceback (most recent call last):
  File "/lmb/home/ylee/software/pyem/csparc2star.py", line 177, in <module>
    sys.exit(main(parser.parse_args()))
  File "/lmb/home/ylee/software/pyem/csparc2star.py", line 93, in main
    if args.flipy and not args.inverty:
AttributeError: 'Namespace' object has no attribute 'flipy'

Temporary workaround: Commenting out lines 93-97.

Cheers,
Yang

I fixed the gain reference issue, added unlimited passthroughs / extra .cs files, and fixed the --flipy argument. Hopefully that fixes exporting the files for everyone - just give the main .cs file first and then all the other .cs files you want until all the required fields are found.

I also got my converted files to actually yield good Polishing output. The key was in this thread. We know that Relion is going to see our particles Y-flipped from how cryoSPARC saw them when we process the movies again. That means that the new extracted particle image will have a different shift and orientation than the one in the converted particles file. The transformation that corrects the particles to match the movies as Relion sees them is the diag(1,-1,-1) rotation described in the thread, plus multiplying Y shift by -1.

The map for polishing can then be made by relion_reconstruct, or the cryoSPARC map can be simply flipped itself (first on Z, then on Y).

--flipy applies rlnOriginYAnsgt = -rlnOriginYAngst and transforms by diag(1,-1,-1)

Under normal circumstances where you run Patch Motion in cryoSPARC, then export particles with --flipy and NOT --inverty and Polishing is correct for now, however the current convention for --inverty is an unfortunate choice. I would like to swap the meaning of the --inverty. The reason is that right now to get the same numerical coordinate in/out of cryoSPARC in repeat export/import cycles you need --inverty, but that should be the default. Instead --inverty should mean when you really need to flip the particles because you will extract using Relion.

But I don’t want to break old scripts that people may have…I will update the instructions on the github to reflect these points soon.

2 Likes

There is also an unexpected result caused by different patterns of local motion correction - this is important to understand for testing if things are working.

If you repeat motion correction via Relion/Motioncor2 and then run Relion Extract with the exported particles with --flipy, these particles will be bad, especially with recentering. It seems that different patterns of local motion correction scramble the aligned shifts. Thus running Extract to test the particles before Polishing won’t work. You have to just --flipy and then go directly to the movies using the original flipped map or a new reconstruction using the original particle images (but these transformed poses).

2 Likes

Has there been a fix for the duplicate axis error? I am running into the same now:

raise ValueError("cannot reindex on an axis with duplicate labels")

ValueError: cannot reindex on an axis with duplicate labels

Using pyem_20221207, input file is an ‘accepted exposures’ from cryoSPARC live.

Happy to send .cs file or full error logs if needed

2 Likes

Hello, I did the transformation between the cs file to star file in order to do Bayesian polishing in Relion, however, the global CTF refinement results: Beam tilt, beam trefoil and tetrafoil is not present in the output star file, among those CTF refinement parameters the only one passed to the star file is the refined spherical aberration.
How can I solve this? Is the only solution to repeat the global CTF refinement after bayesian polishing?

Hi Max,

I am encountering the same issues as you. Have you figured out a solution? Thanks.

Best,
Young

Hi @DanielAsarnow

Dabbling with this at the moment.

Just to check that we’re generating the appropriate motion data files. Our <individual_movie>.star files contain data_general and data_global_shift tables and nothing else. Is there meant to be more information, e.g. data_local_motion_model or data_local_shift, or are the global shifts all that is pertinent to Polishing anyway?

EDIT: source data comes from Patch Motion-corrected movies.

Cheers,
Yang

@leetleyang Relion can use either whole frame or patch trajectories to initialize the search in BPP. We’re doing the former, so motion model is 0 and we only need data_global_shift. In principle we could also set motion model to 1 and export patch trajectories to data_local_shift.

If you use Relion to run MotionCor2 then only global shifts are used as well. Local shifts are only available when using Relion’s own implementation of the MotionCor2 algorithm. Takanori has said multiple times he believes the initialization is not important (though personally I believe it does matter for some datasets). If you are interested you can compare values from a Relion job and cryoSPARC patch motion local trajectories and we may be able to add the local motion initialization.

1 Like

Hi @DanielAsarnow

Thanks for the clarification. That’s clear.

We’re attempting to compare several workflows now. Admittedly, our test dataset, with 3-10 coordinates to track per micrograph, isn’t ideal. I understand per particle tracking is more robust the more particles there are to track.

Scenario 1: CS to RELION to CS to RELION
  1. tif movies Patch Motion-corrected, (blob)-picked and processed in CS to obtain particle stack (3.1Å); tif movies motion-corrected with RelionCor in parallel.
    csparc2star.py particle conversion for re-extraction from rlnMicrographs.
    → rlnParticles re-refined in CS against original reference to regenerate ref->image relationship (3-3.2Å).
    csparc2star.py --inverty conversion for polishing with RelionCor outputs.
    half_maps and mask_fsc_auto used as is for postprocessing.
    shiny particles yield comparable/better results (~2.9Å; better FSC at medium resolution).
Scenario 2: CS to RELION
  1. tif movies Patch Motion-corrected and processed in CS to obtain particle stack (3.1Å).
    csparc2star.py --movie to generate csMicrograph list and motion star files.
    csparc2star.py --flipy particle conversion for polishing using csMicrograph and motion files.
    half_maps and mask_fsc_auto flipped in Z then in Y using relion_image_handler for postprocessing.*
    shiny particles yield worse results (4-5Å).
    (*although probably incorrect, also attempted polish against maps/masks that hadn’t been Z+Y-flipped with similar outcome.)
Scenario 3: CS to RELION (+rlnMotion)
  1. tif movies Patch Motion-corrected, (blob)-picked and processed in CS to obtain particle stack; tif movies motion-corrected with RelionCor in parallel.
    csparc2star.py --flipy particle conversion for polishing using RelionCor outputs.
    half_maps and mask_fsc_auto flipped in Z then in Y using relion_image_handler for postprocessing.*
    shiny particles yield worse results (4-5Å).
    (*although probably incorrect, also attempted to polish against maps/masks that hadn’t been Z+Y-flipped with similar outcome.)
(Caveats)

Scenario 1 (a.k.a. the safe way) was performed to establish a baseline. In general, the trajectories therein appear reasonable for the first half of the frames and then occasionally become a bit suspect in the latter half. Worth reiterating that this is not the best test case. The shape of the overall polishing B-factor plot looks reasonable, however. Smooth decline from 0 to -150. Polishing was initiated with the default parameters rather than a trained set. With EMPIAR and other data, we’ve rarely found the parameters to make a significant difference to the outcome, although this cannot be fully discounted as a factor in this case.

Question. Scenario 3 was attempted as a sanity check and also to test ±local motion initialization (compared to Scenario 2). From a workflow perspective, is there a reason why this might have tripped up? Comparing the data_global_shift tables from selected motion star files (RelionCor vs csparc2star), these seem to reflect similar shifts in magnitude and direction.

Also, after wrapping my head around the conventions in play, --inverty (or rather, UNinverty?) is indeed unfortunate, as you say. :slight_smile:

def cryosparc_2_cs_particle_locations(cs, df=None, swapxy=True, invertx=False, inverty=True):
...
  if inverty:
    # cryoSPARC coordinates have origin in "bottom left" so inverting Y is default for Relion correctness
    # (and therefore also for Import Particles). However, cryoSPARC Patch Motion flips images physically
    # vs. SerialEM, Motioncor2 doesn't, so "inverting twice" (not inverting) is required if switching.
    df[star.Relion.COORDY] = 1 - df[star.Relion.COORDY]
...

EDIT: I shall attempt the comparisons again on an EMPIAR dataset I have lying around.

Cheers,
Yang

My code comment is wrong actually - it is cryoSPARC that doesn’t flip the TIFs.

I think that differences in local motion patch interpolation between different motion correction is somehow scrambling the relationship with the refined particle shifts. So far I’ve only got a resolution enhancement from BPP if I re-extract and re-refine the particles based on the Relion or MotionCor2 motion correction. Going directly from csparc should work in principle but it seems something isn’t right. I’m reasonably sure the conversion convention I’m using is right, but none of the other options worked either.

Edit to clarify:
I’ve done Scenario 1 and 3 successfully, 3 also works if you add a re-extract and re-refine from the Relion MotionCorr job.

2 Likes

This makes sense. Insightful point. Thanks for clarifying your own experience as well.

Cheers,
Yang

Hi @DanielAsarnow

Wondering if there’s a quick way of getting around an apparent bug in the CS MC2 wrapper.

Looking in the .cs file, while 'movie_blob/psize_A' reflects 0.83, 'rigid_motion/psize_A' appears to be truncated to 0.. At least I think that’s why csparc2star.py --movie is returning divide_by_zero errors. micrograph_blob/vmin and micrograph_blob/vmax seem to be similarly truncated, so I think it’s a general parsing issue.

/home/ylee/software/pyem/pyem/metadata/cryosparc2.py:263: RuntimeWarning: divide by zero encountered in true_divide
  traj /= cs['rigid_motion/psize_A'][i]  # Looks right.
/home/ylee/software/pyem/pyem/metadata/cryosparc2.py:263: RuntimeWarning: invalid value encountered in true_divide
  traj /= cs['rigid_motion/psize_A'][i]  # Looks right.

Do you normally run MC2 outside of CS? The wrapper doesn’t support the -LogDir option in ≥1.4.6 leaving no convenient way of issuing -OutStar 1 from within CS.

EDIT:
Never mind. Easier to edit the .cs file itself.

EDIT2:
I see. csparc2star.py --movie attempts to correct for the axis inversion, which isn’t appropriate for MC2 inputs.

Cheers,
Yang

Hi @DanielAsarnow

Some further investigations. I repeated some tests with EMPIAR-11350 to see where things may be failing and which workflows are possible.

Scenario 1: RELION to CS to RELION (baseline)
  1. tif movies motion-corrected with RelionCor.
    → rlnMicrographs (blob)-picked and processed in CS to obtain particle stack (3.1-3.2Å).
    csparc2star.py --inverty particle conversion for polishing with RelionCor outputs.
    half_maps and mask_fsc_auto used as is for postprocessing.
    shiny particles yield better results (~2.8-2.9Å; better FSC at medium resolution).
Scenario 2: MC2(wrapper)/CS to RELION (sanity check)
  1. tif movies motion-corrected with MotionCor2 within CS.
    → pre-shiny particle coordinates from S1 used to reextract from mc2Micrographs (Recenter using aligned shifts disabled).
    → Particles refined against original reference (3.1-3.2Å).
    csparc2star.py --movie to generate mc2Micrograph and motion star files*.
    cpsarc2star.py --inverty particle conversion for polishing.
    half_maps and mask_fsc_auto used as is for postprocessing.
    shiny particles yield better results (~2.8-2.9Å; better FSC at medium resolution).

*polishing attempted with positive and negative orientations of _rlnMicrographShiftX, both giving the same outcome, i.e. modelled particle trajectories and refinement FSC. Result seems insensitive to global_shift priors when 30-40 particles/mic to track?

Scenario 3: CS to RELION
  1. a) tif movies Patch Motion-corrected in CS.
    → pre-shiny particle coordinates from S1 used to extract from csMicrographs (Flip mic in Y before extract enabled; Recenter using aligned shifts disabled).
    → Particles refined against original reference (3.1-3.2Å).
    csparc2star.py --movie to generate csMicrograph and motion star files.
    cpsarc2star.py --inverty particle conversion for polishing.
    half_maps and mask_fsc_auto used as is for postprocessing.
    shiny particles yield better results (~2.8-2.9Å; better FSC at medium resolution; maybe slightly worse than S1 and S2, which may or may not be stochastic, but at least it didn’t fail).
  • b) tif movies Patch Motion-corrected in CS.
    → pre-shiny particle coordinates from S1 Y-inverted and used to extract from csMicrographs (Recenter using aligned shifts disabled).
    → Particles refined against original reference (3.1-3.2Å).
    csparc2star.py --movie to generate csMicrograph and motion star files.
    cpsarc2star.py --flipy particle conversion for polishing.
    half_maps and mask_fsc_auto ±(flipZ+Y) for postprocessing.
    shiny particles, both ±(flipZ+Y) polish_reference, yield worse results (~4.5Å).

At least with this dataset, BPP seems largely insensitive to motion initialization inputs (see S2).

S3a gave an improvement from BPP, suggesting that Patch Motion in CS isn’t inherently the primary determinant when things blow up.

However, the differing S3a/b outcomes, depending namely on whether the mics are pre-flipped (a) or the coordinates/transformations are flipped later (b), suggests something isn’t quite right either with the way Relion is perceiving the --flipy-transformed particles, and/or the treatment of the reference?

Cheers,
Yang

@leetleyang Thanks, this is great. Can you test 3b again with line 95 of csparc2star.py commented out? Like that:

95: # df[star.Relion.ORIGINY] = -df[star.Relion.ORIGINY]

Hi @DanielAsarnow

Sure, I’ll give that a go.

In the mean time, I’ve tried to dig a bit into the discrepancy. I took the pre-shiny particle images from S3b, flipped them in Y (relion_image_handler --flipY), replaced the original stacks and refined against the original reference, in order to simulate the necessary shifts/transformations required if particles were sourced from Y-flipped mics.

Averaged across a few thousand particle images, the differences in rlnAngleRot, rlnAngleTilt, rlnAnglePsi, rlnOriginXAngst and rlnOriginYAngst, compared to right-side up particle images seemed best described by…

  • phi+180, 180-theta, -psi, XAngst (as is), -YAngst

Note, it’s similar to the transformation suggested by @sunch here, sans Y-shift inversion. That additional element is incorporated in --flipy. That one difference is perhaps why @olibclarke didn’t quite have success with just the Euler angle modifications at the time.

Scenario 3: CS to RELION
  1. c) tif movies Patch Motion-corrected in CS.
    → pre-shiny particle coordinates from S1 Y-inverted and used to extract from csMicrographs (Recenter using aligned shifts disabled).
    → Particles refined against original reference (3.1-3.2Å).
    csparc2star.py --movie to generate csMicrograph and motion star files.
    csparc2star.py particle conversion for polishing.
    application of the above .star file modifications using awk.
    half_maps and mask_fsc_auto used as is for postprocessing.
    shiny particles now yield comparable, if not identical results to S3a.

I’ve also been wondering about the slight difference in polishing outcomes when sourcing from RC/MC2 vs PM in CS.

The FSC is improved vs un-polished particles in both cases, but RC/MC2 has been giving slightly better FSCs. I wondered earlier if it was stochastic, but I’m beginning to think that it’s due to the fact that RC/MC2 and PM do not share the same reference frame–PM has no reference frame. Meaning if particles are extracted from csMicrographs, the particles won’t be exactly where they should be when Relion goes back to the movies. That is, unless csparc2star.py corrects for that?

Perhaps another reason to stick to RC/MC2, for consistency.

Cheers,
Yang

Hi @DanielAsarnow

I gave this a go.

# Reference particle (Rot, Tilt, Psi, OriginX, OriginY)
-69.794205 65.145355 171.596817 -22.796064 12.710671

# Original csparc2star.py --flipy
69.794205 65.145354 171.596810 -22.796064 -12.710671

# Modified csparc2star.py --flipy
69.794205 65.145354 171.596810 -22.796064 12.710671

Polished against ±(flipZ+Y) maps/masks, unfortunately, both of which produced the same outcome as S3b.

Cheers,
Yang