diff --git a/pyem/metadata.py b/pyem/metadata.py index ff76738..cfd198e 100644 --- a/pyem/metadata.py +++ b/pyem/metadata.py @@ -292,23 +292,53 @@ def cryosparc_2_cs_ctf_parameters(cs, df=None): log = logging.getLogger('root') if df is None: df = pd.DataFrame() - if 'ctf/tilt_A' in cs.dtype.names: - log.debug("Recovering beam tilt and converting to mrad") - df[star.Relion.BEAMTILTX] = np.arcsin(cs['ctf/tilt_A'][:, 0] / cs['ctf/cs_mm'] * 1e-7) * 1e3 - df[star.Relion.BEAMTILTY] = np.arcsin(cs['ctf/tilt_A'][:, 1] / cs['ctf/cs_mm'] * 1e-7) * 1e3 - if 'ctf/shift_A' in cs.dtype.names: - pass - if 'ctf/trefoil_A' in cs.dtype.names: - pass - # df[star.Relion.ODDZERNIKE] = cs['ctf/trefoil_A'] - if 'ctf/tetrafoil_A' in cs.dtype.names: - pass - # df[star.Relion.EVENZERNIKE] = cs['ctf/tetra_A'] + assert 'ctf/accel_kv' in cs.dtype.names + # Calculate electron wavelentgh + kv = cs['ctf/accel_kv'] + wl = 12.2643247 / np.sqrt(kv * (1. + kv * 0.978466e-6)) + wl2 = wl**2 + wl3 = wl**3 + half_pi = 0.5 * np.pi + two_pi = 2 * np.pi + pi_wl = np.pi * wl + two_pi_wl2 = two_pi * wl2 + neg_half_pi_wl3 = -half_pi * wl3 if 'ctf/anisomag' in cs.dtype.names: df[star.Relion.MAGMAT00] = cs['ctf/anisomag'][:, 0] df[star.Relion.MAGMAT01] = cs['ctf/anisomag'][:, 1] df[star.Relion.MAGMAT10] = cs['ctf/anisomag'][:, 2] df[star.Relion.MAGMAT11] = cs['ctf/anisomag'][:, 3] + if 'ctf/tilt_A' in cs.dtype.names: + log.debug("Recovering beam tilt and converting to mrad") + df[star.Relion.BEAMTILTX] = np.arcsin(cs['ctf/tilt_A'][:, 0] / cs['ctf/cs_mm'] * 1e-7) * 1e3 + df[star.Relion.BEAMTILTY] = np.arcsin(cs['ctf/tilt_A'][:, 1] / cs['ctf/cs_mm'] * 1e-7) * 1e3 + log.debug("Converting odd Zernike moments") + if 'ctf/shift_A' in cs.dtype.names: + df[star.UCSF.Z_neg1_1] = -two_pi * cs['ctf/shift_A'][:, 0] + df[star.UCSF.Z_1_1] = -two_pi * cs['ctf/shift_A'][:, 1] + if 'ctf/tilt_A' in cs.dtype.names: + df[star.UCSF.Z_neg1_3] = two_pi_wl2 * cs['ctf/tilt_A'][:, 0] + df[star.UCSF.Z_1_3] = two_pi_wl2 * cs['ctf/tilt_A'][:, 1] + if 'ctf/trefoil_A' in cs.dtype.names and 'ctf/cs_mm' in cs.dtype.names: + df[star.UCSF.Z_neg3_3] = two_pi_wl2 * cs['ctf/trefoil_A'][:, 0] + df[star.UCSF.Z_3_3] = two_pi_wl2 * cs['ctf/trefoil_A'][:, 1] + log.debug("Converting even Zernike moments") + if 'ctf/amp_contrast' in cs.dtype.names: + df[star.UCSF.Z_0_0] = cs['ctf/phase_shift_rad'] - np.arccos(cs['ctf/amp_contrast']) + if 'ctf/df1_A' in cs.dtype.names and 'ctf/df2_A' in cs.dtype.names and 'ctf/df_angle_rad' in cs.dtype.names: + df_avg = (cs['ctf/df1_A'] + cs['ctf/df2_A']) / 2 + df_dev = (cs['ctf/df1_A'] - cs['ctf/df2_A']) / 2 + two_angast = 2 * cs['ctf/df_angle_rad'] + df[star.UCSF.Z_0_2] = pi_wl * df_avg + df[star.UCSF.Z_neg2_2] = pi_wl * np.cos(two_angast) * df_dev # Defocus asigmatism major (Z1). + df[star.UCSF.Z_2_2] = pi_wl * np.sin(two_angast) * df_dev # Defocus astigmatism minor (Z2). + if 'ctf/cs_mm' in cs.dtype.names: + df[star.UCSF.Z_0_4] = neg_half_pi_wl3 * cs['ctf/cs_mm'] * 1e7 # Spherical aberration in Å. + if 'ctf/tetra_A' in cs.dtype.names: + df[star.UCSF.Z_neg4_4] = neg_half_pi_wl3 * cs['ctf/tetra_A'][:, 0] + df[star.UCSF.Z_neg2_4] = neg_half_pi_wl3 * cs['ctf/tetra_A'][:, 1] + df[star.UCSF.Z_2_4] = neg_half_pi_wl3 * cs['ctf/tetra_A'][:, 2] + df[star.UCSF.Z_4_4] = neg_half_pi_wl3 * cs['ctf/tetra_A'][:, 3] return df @@ -430,6 +460,7 @@ def parse_cryosparc_2_cs(csfile, passthroughs=None, minphic=0, boxsize=None, df = cryosparc_2_cs_model_parameters(cs, df, minphic=minphic) df = cryosparc_2_cs_array_parameters(cs, df) df = cryosparc_2_cs_filament_parameters(cs, df) + df = cryosparc_2_cs_ctf_parameters(cs, df) if passthroughs is not None: for passthrough in passthroughs: if type(passthrough) is np.ndarray: