Exemple #1
0
def project(f3d,
            p,
            s,
            sx,
            sy,
            a,
            apply_ctf=False,
            size=None,
            flip_phase=False):
    orient = util.euler2rot(np.deg2rad(p[star.Relion.ANGLEROT]),
                            np.deg2rad(p[star.Relion.ANGLETILT]),
                            np.deg2rad(p[star.Relion.ANGLEPSI]))
    pshift = np.exp(
        -2 * np.pi * 1j *
        (-p[star.Relion.ORIGINX] * sx + -p[star.Relion.ORIGINY] * sy))
    f2d = vop.interpolate_slice_numba(f3d, orient, size=size)
    f2d *= pshift
    if apply_ctf or flip_phase:
        apix = star.calculate_apix(p)
        c = ctf.eval_ctf(s / apix,
                         a,
                         p[star.Relion.DEFOCUSU],
                         p[star.Relion.DEFOCUSV],
                         p[star.Relion.DEFOCUSANGLE],
                         p[star.Relion.PHASESHIFT],
                         p[star.Relion.VOLTAGE],
                         p[star.Relion.AC],
                         p[star.Relion.CS],
                         bf=0,
                         lp=2 * apix)
        if flip_phase:
            c = np.sign(c)
        f2d *= c
    return f2d
Exemple #2
0
def transform_star(df,
                   r,
                   t=None,
                   inplace=False,
                   rots=None,
                   invert=False,
                   rotate=True,
                   adjust_defocus=False):
    """
    Transform particle angles and origins according to a rotation
    matrix (in radians) and an optional translation vector.
    The translation may also be given as the 4th column of a 3x4 matrix,
    or as a scalar distance to be applied along the axis of rotation.
    """
    assert (r.shape[0] == 3)
    if r.shape[1] == 4 and t is None:
        t = r[:, -1]
        r = r[:, :3]
    assert (r.shape == (3, 3))
    assert t is None or np.isscalar(t) or len(t) == 3

    if inplace:
        newstar = df
    else:
        newstar = df.copy()

    if rots is None:
        rots = [
            euler2rot(*np.deg2rad(row[1]))
            for row in df[Relion.ANGLES].iterrows()
        ]

    if invert:
        r = r.T

    newrots = [ptcl.dot(r) for ptcl in rots]
    if rotate:
        angles = [np.rad2deg(rot2euler(q)) for q in newrots]
        newstar[Relion.ANGLES] = angles

    if t is not None and np.linalg.norm(t) > 0:
        if np.isscalar(t):
            if invert:
                tt = -np.vstack([np.squeeze(q[:, 2]) * t for q in rots])
            else:
                tt = np.vstack([np.squeeze(q[:, 2]) * t for q in newrots])
        else:
            if invert:
                tt = -np.vstack([q.dot(t) for q in rots])
            else:
                tt = np.vstack([q.dot(t) for q in newrots])
        newshifts = df[Relion.ORIGINS] + tt[:, :-1]
        newstar[Relion.ORIGINS] = newshifts
        if adjust_defocus:
            newstar[Relion.DEFOCUSU] += tt[:, -1] * calculate_apix(df)
            newstar[Relion.DEFOCUSV] += tt[:, -1] * calculate_apix(df)
            newstar[Relion.DEFOCUSANGLE] = np.rad2deg(
                np.arctan2(newstar[Relion.DEFOCUSV], newstar[Relion.DEFOCUSV]))

    return newstar
Exemple #3
0
def subparticle_expansion(s, ops=[np.eye(3)], dists=None, rots=None):
    if rots is None:
        rots = [euler2rot(*np.deg2rad(r[1])) for r in s[ANGLES].iterrows()]
    if dists is not None:
        if np.isscalar(dists):
            dists = [dists] * len(ops)
        for i in range(len(ops)):
            yield transform_star(s, ops[i], dists[i], rots=rots)
    else:
        for op in ops:
            yield transform_star(s, op, rots=rots)
Exemple #4
0
def particle_xcorr(ptcl, refmap_ft):
    r = util.euler2rot(*np.deg2rad(ptcl[star.Relion.ANGLES]))
    proj = vop.interpolate_slice_numba(refmap_ft, r)
    c = ctf.eval_ctf(s / apix,
                     a,
                     def1[i],
                     def2[i],
                     angast[i],
                     phase[i],
                     kv[i],
                     ac[i],
                     cs[i],
                     bf=0,
                     lp=2 * apix)
    pshift = np.exp(-2 * np.pi * 1j * (-xshift[i] * sx + -yshift * sy))
    proj_ctf = proj * pshift * c

    with mrc.ZSliceReader(ptcl[star.Relion.IMAGE_NAME]) as f:
        exp_image_fft = rfft2(fftshift(f.read(i)))

    xcor_fft = exp_image_fft * proj_ctf
    xcor = fftshift(irfft2(xcor_fft))
    return xcor
Exemple #5
0
def main(args):
    log = logging.getLogger(__name__)
    log.setLevel(logging.INFO)
    hdlr = logging.StreamHandler(sys.stdout)
    if args.quiet:
        hdlr.setLevel(logging.WARNING)
    else:
        hdlr.setLevel(logging.INFO)
    log.addHandler(hdlr)

    if args.target is None and args.sym is None:
        log.error(
            "At least a target or symmetry group must be provided via --target or --sym"
        )
        return 1
    elif args.target is not None and args.boxsize is None and args.origin is None:
        log.error("An origin must be provided via --boxsize or --origin")
        return 1

    if args.target is not None:
        try:
            args.target = np.array(
                [np.double(tok) for tok in args.target.split(",")])
        except:
            log.error(
                "Target must be comma-separated list of x,y,z coordinates")
            return 1

    if args.origin is not None:
        if args.boxsize is not None:
            log.warn("--origin supersedes --boxsize")
        try:
            args.origin = np.array(
                [np.double(tok) for tok in args.origin.split(",")])
        except:
            log.error(
                "Origin must be comma-separated list of x,y,z coordinates")
            return 1

    if args.sym is not None:
        args.sym = util.relion_symmetry_group(args.sym)

    df = star.parse_star(args.input)

    if args.apix is None:
        args.apix = star.calculate_apix(df)
        if args.apix is None:
            log.warn(
                "Could not compute pixel size, default is 1.0 Angstroms per pixel"
            )
            args.apix = 1.0
            df[star.Relion.MAGNIFICATION] = 10000
            df[star.DETECTORPIXELSIZE] = 1.0

    if args.cls is not None:
        df = star.select_classes(df, args.cls)

    if args.target is not None:
        if args.origin is not None:
            args.origin /= args.apix
        elif args.boxsize is not None:
            args.origin = np.ones(3) * args.boxsize / 2
        args.target /= args.apix
        c = args.target - args.origin
        c = np.where(np.abs(c) < 1, 0, c)  # Ignore very small coordinates.
        d = np.linalg.norm(c)
        ax = c / d
        cm = util.euler2rot(*np.array(
            [np.arctan2(ax[1], ax[0]),
             np.arccos(ax[2]),
             np.deg2rad(args.psi)]))
        ops = [op.dot(cm) for op in args.sym] if args.sym is not None else [cm]
        dfs = [
            star.transform_star(df,
                                op.T,
                                -d,
                                rotate=args.shift_only,
                                invert=args.target_invert,
                                adjust_defocus=args.adjust_defocus)
            for op in ops
        ]
    elif args.sym is not None:
        dfs = list(
            subparticle_expansion(df, args.sym,
                                  -args.displacement / args.apix))
    else:
        log.error(
            "At least a target or symmetry group must be provided via --target or --sym"
        )
        return 1

    if args.recenter:
        for s in dfs:
            star.recenter(s, inplace=True)

    if args.suffix is None and not args.skip_join:
        if len(dfs) > 1:
            df = util.interleave(dfs)
        else:
            df = dfs[0]
        star.write_star(args.output, df)
    else:
        for i, s in enumerate(dfs):
            star.write_star(os.path.join(args.output, args.suffix + "_%d" % i),
                            s)
    return 0
Exemple #6
0
def main(args):
    log = logging.getLogger(__name__)
    hdlr = logging.StreamHandler(sys.stdout)
    log.addHandler(hdlr)
    log.setLevel(logging.getLevelName(args.loglevel.upper()))

    data, hdr = read(args.input, inc_header=True)
    if args.half2 is not None:
        half2, hdr_half2 = read(args.input, inc_header=True)
        if data.shape == half2.shape:
            data += half2
        else:
            log.error("--half2 map is not the same shape as input map!")
            return 1
    final = None
    box = np.array([hdr[a] for a in ["nx", "ny", "nz"]])
    center = box // 2

    if args.fft:
        if args.final_mask is not None:
            final_mask = read(args.final_mask)
            data *= final_mask
        data_ft = vop.vol_ft(data.T, pfac=args.pfac, threads=args.threads)
        np.save(args.output, data_ft)
        return 0

    if args.transpose is not None:
        try:
            tax = [np.int64(a) for a in args.transpose.split(",")]
            data = np.transpose(data, axes=tax)
        except:
            log.error(
                "Transpose axes must be comma-separated list of three integers"
            )
            return 1

    if args.flip is not None:
        if args.flip.isnumeric():
            args.flip = int(args.flip)
        else:
            args.flip = vop.label_to_axis(args.flip)
        data = np.flip(data, axis=args.flip)

    if args.apix is None:
        args.apix = hdr["xlen"] / hdr["nx"]
        log.info("Using computed pixel size of %f Angstroms" % args.apix)

    if args.normalize:
        if args.diameter is not None:
            if args.diameter > 1.0:
                args.diameter /= args.apix * 2  # Convert Angstrom diameter to pixel radius.
        if args.reference is not None:
            ref, refhdr = read(args.reference, inc_header=True)
            final, mu, sigma = vop.normalize(data,
                                             ref=ref,
                                             return_stats=True,
                                             rmask=args.diameter)
        else:
            final, mu, sigma = vop.normalize(data,
                                             return_stats=True,
                                             rmask=args.diameter)
        log.info("Mean: %f, Standard deviation: %f" % (mu, sigma))

    if args.apix_out is not None:
        if args.scale is not None:
            log.warn("--apix-out supersedes --scale")
        args.scale = args.apix / args.apix_out
    elif args.scale is not None:
        args.apix_out = args.apix / args.scale
    elif args.boxsize is not None:
        args.scale = box[0] / np.double(args.boxsize)

    if args.apix_out is None:
        args.apix_out = args.apix

    if args.boxsize is None:
        if args.scale is None:
            args.boxsize = box[0]
            args.scale = 1
        else:
            args.boxsize = np.int(box[0] * args.scale)

    log.info("Volume will be scaled by %f to size %d @ %f A/px" %
             (args.scale, args.boxsize, args.apix_out))

    if args.target and args.transform:
        log.warn(
            "Target pose transformation will be applied after explicit matrix")
    if args.euler is not None and (args.target is not None
                                   or args.transform is not None):
        log.warn(
            "Euler transformation will be applied after target pose transformation"
        )
    if args.translate is not None and (args.euler is not None
                                       or args.target is not None
                                       or args.transform is not None):
        log.warn("Translation will be applied after other transformations")

    if args.origin is not None:
        try:
            args.origin = np.array(
                [np.double(tok) for tok in args.origin.split(",")]) / args.apix
            assert np.all(args.origin < box)
        except:
            log.error(
                "Origin must be comma-separated list of x,y,z coordinates and lie within the box"
            )
            return 1
    else:
        args.origin = center
        log.info("Origin set to box center, %s" % (args.origin * args.apix))

    if not (args.target is None and args.euler is None and args.transform is None and args.boxsize is None) \
            and vop.ismask(data) and args.spline_order != 0:
        log.warn(
            "Input looks like a mask, --spline-order 0 (nearest neighbor) is recommended"
        )

    if args.transform is not None:
        try:
            args.transform = np.array(json.loads(args.transform))
        except:
            log.error("Transformation matrix must be in JSON/Numpy format")
            return 1
        r = args.transform[:, :3]
        if args.transform.shape[1] == 4:
            t = args.transform[:, -1] / args.apix
            t = r.dot(args.origin) + t - args.origin
            t = -r.T.dot(t)
        else:
            t = 0
        log.debug("Final rotation: %s" % str(r).replace("\n", "\n" + " " * 16))
        log.debug("Final translation: %s (%f px)" %
                  (str(t), np.linalg.norm(t)))
        data = vop.resample_volume(data,
                                   r=r,
                                   t=t,
                                   ori=None,
                                   order=args.spline_order,
                                   invert=args.invert)

    if args.target is not None:
        try:
            args.target = np.array(
                [np.double(tok) for tok in args.target.split(",")]) / args.apix
        except:
            log.error(
                "Standard pose target must be comma-separated list of x,y,z coordinates"
            )
            return 1
        args.target -= args.origin
        args.target = np.where(np.abs(args.target) < 1, 0, args.target)
        ori = None if args.origin is center else args.origin - center
        r = vec2rot(args.target)
        t = np.linalg.norm(args.target)
        log.info("Euler angles are %s deg and shift is %f px" %
                 (np.rad2deg(rot2euler(r)), t))
        log.debug("Final rotation: %s" % str(r).replace("\n", "\n" + " " * 16))
        log.debug("Final translation: %s (%f px)" %
                  (str(t), np.linalg.norm(t)))
        data = vop.resample_volume(data,
                                   r=r,
                                   t=args.target,
                                   ori=ori,
                                   order=args.spline_order,
                                   invert=args.invert)

    if args.euler is not None:
        try:
            args.euler = np.deg2rad(
                np.array([np.double(tok) for tok in args.euler.split(",")]))
        except:
            log.error(
                "Eulers must be comma-separated list of phi,theta,psi angles")
            return 1
        r = euler2rot(*args.euler)
        offset = args.origin - 0.5
        offset = offset - r.T.dot(offset)
        data = affine_transform(data,
                                r.T,
                                offset=offset,
                                order=args.spline_order)

    if args.translate is not None:
        try:
            args.translate = np.array(
                [np.double(tok)
                 for tok in args.translate.split(",")]) / args.apix
        except:
            log.error(
                "Translation vector must be comma-separated list of x,y,z coordinates"
            )
            return 1
        args.translate -= args.origin
        data = shift(data, -args.translate, order=args.spline_order)

    if final is None:
        final = data

    if args.final_mask is not None:
        final_mask = read(args.final_mask)
        final *= final_mask

    if args.scale != 1 or args.boxsize != box[0]:
        final = vop.resample_volume(final,
                                    scale=args.scale,
                                    output_shape=args.boxsize,
                                    order=args.spline_order)

    write(args.output, final, psz=args.apix_out)
    return 0
Exemple #7
0
def main(args):
    log = logging.getLogger(__name__)
    log.setLevel(logging.INFO)
    hdlr = logging.StreamHandler(sys.stdout)
    if args.quiet:
        hdlr.setLevel(logging.ERROR)
    elif args.verbose:
        hdlr.setLevel(logging.INFO)
    else:
        hdlr.setLevel(logging.WARN)
    log.addHandler(hdlr)

    data, hdr = read(args.input, inc_header=True)
    final = None
    box = np.array([hdr[a] for a in ["nx", "ny", "nz"]])
    center = box // 2

    if args.fft:
        data_ft = vop.vol_ft(data.T, threads=args.threads)
        np.save(args.output, data_ft)
        return 0

    if args.transpose is not None:
        try:
            tax = [np.int64(a) for a in args.transpose.split(",")]
            data = np.transpose(data, axes=tax)
        except:
            log.error(
                "Transpose axes must be comma-separated list of three integers"
            )
            return 1

    if args.normalize:
        if args.reference is not None:
            ref, refhdr = read(args.reference, inc_header=True)
            final, mu, sigma = vop.normalize(data, ref=ref, return_stats=True)
        else:
            final, mu, sigma = vop.normalize(data, return_stats=True)
        final = (data - mu) / sigma
        if args.verbose:
            log.info("Mean: %f, Standard deviation: %f" % (mu, sigma))

    if args.apix is None:
        args.apix = hdr["xlen"] / hdr["nx"]
        log.info("Using computed pixel size of %f Angstroms" % args.apix)

    if args.target and args.matrix:
        log.warn(
            "Target pose transformation will be applied after explicit matrix")
    if args.euler is not None and (args.target is not None
                                   or args.matrix is not None):
        log.warn(
            "Euler transformation will be applied after target pose transformation"
        )
    if args.translate is not None and (args.euler is not None or args.target
                                       is not None or args.matrix is not None):
        log.warn("Translation will be applied after other transformations")

    if args.origin is not None:
        try:
            args.origin = np.array(
                [np.double(tok) for tok in args.origin.split(",")]) / args.apix
            assert np.all(args.origin < box)
        except:
            log.error(
                "Origin must be comma-separated list of x,y,z coordinates and lie within the box"
            )
            return 1
    else:
        args.origin = center
        log.info("Origin set to box center, %s" % (args.origin * args.apix))

    if not (args.target is None and args.euler is None and args.matrix is None and args.boxsize is None) \
            and vop.ismask(data) and args.spline_order != 0:
        log.warn(
            "Input looks like a mask, --spline-order 0 (nearest neighbor) is recommended"
        )

    if args.matrix is not None:
        try:
            r = np.array(json.loads(args.matrix))
        except:
            log.error("Matrix format is incorrect")
            return 1
        data = vop.resample_volume(data,
                                   r=r,
                                   t=None,
                                   ori=None,
                                   order=args.spline_order)

    if args.target is not None:
        try:
            args.target = np.array(
                [np.double(tok) for tok in args.target.split(",")]) / args.apix
        except:
            log.error(
                "Standard pose target must be comma-separated list of x,y,z coordinates"
            )
            return 1
        args.target -= args.origin
        args.target = np.where(np.abs(args.target) < 1, 0, args.target)
        ori = None if args.origin is center else args.origin - args.center
        r = vec2rot(args.target)
        t = np.linalg.norm(args.target)
        log.info("Euler angles are %s deg and shift is %f px" %
                 (np.rad2deg(rot2euler(r)), t))
        data = vop.resample_volume(data,
                                   r=r,
                                   t=args.target,
                                   ori=ori,
                                   order=args.spline_order,
                                   invert=args.target_invert)

    if args.euler is not None:
        try:
            args.euler = np.deg2rad(
                np.array([np.double(tok) for tok in args.euler.split(",")]))
        except:
            log.error(
                "Eulers must be comma-separated list of phi,theta,psi angles")
            return 1
        r = euler2rot(*args.euler)
        offset = args.origin - 0.5
        offset = offset - r.T.dot(offset)
        data = affine_transform(data,
                                r.T,
                                offset=offset,
                                order=args.spline_order)

    if args.translate is not None:
        try:
            args.translate = np.array(
                [np.double(tok)
                 for tok in args.translate.split(",")]) / args.apix
        except:
            log.error(
                "Translation vector must be comma-separated list of x,y,z coordinates"
            )
            return 1
        args.translate -= args.origin
        data = shift(data, -args.translate, order=args.spline_order)

    if args.boxsize is not None:
        args.boxsize = np.double(args.boxsize)
        data = zoom(data, args.boxsize / box, order=args.spline_order)
        args.apix = args.apix * box[0] / args.boxsize

    if final is None:
        final = data

    if args.final_mask is not None:
        final_mask = read(args.final_mask)
        final *= final_mask

    write(args.output, final, psz=args.apix)
    return 0
Exemple #8
0
def main(args):
    if args.info:
        args.input.append(args.output)

    df = pd.concat((parse_star(inp, keep_index=False) for inp in args.input),
                   join="inner")

    dfaux = None

    if args.cls is not None:
        df = select_classes(df, args.cls)

    if args.info:
        if is_particle_star(df) and "rlnClassNumber" in df.columns:
            c = df["rlnClassNumber"].value_counts()
            print("%s particles in %d classes" %
                  ("{:,}".format(df.shape[0]), len(c)))
            print("    ".join([
                '%d: %s (%.2f %%)' % (i, "{:,}".format(s), 100. * s / c.sum())
                for i, s in c.sort_index().iteritems()
            ]))
        elif is_particle_star(df):
            print("%s particles" % "{:,}".format(df.shape[0]))
        if "rlnMicrographName" in df.columns:
            mgraphcnt = df["rlnMicrographName"].value_counts()
            print(
                "%s micrographs, %s +/- %s particles per micrograph" %
                ("{:,}".format(len(mgraphcnt)), "{:,.3f}".format(
                    np.mean(mgraphcnt)), "{:,.3f}".format(np.std(mgraphcnt))))
        try:
            print("%f A/px (%sX magnification)" %
                  (calculate_apix(df), "{:,.0f}".format(
                      df["rlnMagnification"][0])))
        except KeyError:
            pass
        return 0

    if args.drop_angles:
        df.drop(Relion.ANGLES, axis=1, inplace=True, errors="ignore")

    if args.drop_containing is not None:
        containing_fields = [
            f for q in args.drop_containing for f in df.columns if q in f
        ]
        if args.invert:
            containing_fields = df.columns.difference(containing_fields)
        df.drop(containing_fields, axis=1, inplace=True, errors="ignore")

    if args.offset_group is not None:
        df["rlnGroupNumber"] += args.offset_group

    if args.subsample_micrographs is not None:
        if args.bootstrap is not None:
            print("Only particle sampling allows bootstrapping")
            return 1
        mgraphs = df["rlnMicrographName"].unique()
        if args.subsample_micrographs < 1:
            args.subsample_micrographs = np.int(
                max(np.round(args.subsample_micrographs * len(mgraphs)), 1))
        ind = np.random.choice(len(mgraphs),
                               size=args.subsample_micrographs,
                               replace=False)
        mask = df["rlnMicrographName"].isin(mgraphs[ind])
        if args.auxout is not None:
            dfaux = df.loc[~mask]
        df = df.loc[mask]

    if args.subsample is not None and args.suffix == "":
        if args.subsample < 1:
            args.subsample = np.int(
                max(np.round(args.subsample * df.shape[0]), 1))
        else:
            args.subsample = np.int(args.subsample)
        ind = np.random.choice(df.shape[0], size=args.subsample, replace=False)
        mask = df.index.isin(ind)
        if args.auxout is not None:
            dfaux = df.loc[~mask]
        df = df.loc[mask]

    if args.copy_angles is not None:
        angle_star = parse_star(args.copy_angles, keep_index=False)
        df = smart_merge(df, angle_star, fields=Relion.ANGLES)

    if args.transform is not None:
        if args.transform.count(",") == 2:
            r = euler2rot(
                *np.deg2rad([np.double(s) for s in args.transform.split(",")]))
        else:
            r = np.array(json.loads(args.transform))
        df = transform_star(df, r, inplace=True)

    if args.copy_paths is not None:
        path_star = parse_star(args.copy_paths, keep_index=False)
        df[Relion.IMAGE_NAME] = path_star[Relion.IMAGE_NAME]

    if args.copy_ctf is not None:
        ctf_star = pd.concat(
            (parse_star(inp, keep_index=False) for inp in glob(args.copy_ctf)),
            join="inner")
        df = smart_merge(df, ctf_star, Relion.CTF_PARAMS)

    if args.copy_micrograph_coordinates is not None:
        coord_star = pd.concat(
            (parse_star(inp, keep_index=False)
             for inp in glob(args.copy_micrograph_coordinates)),
            join="inner")
        df = smart_merge(df, coord_star, fields=Relion.MICROGRAPH_COORDS)

    if args.scale_coordinates is not None:
        df[Relion.COORDS] = df[Relion.COORDS] * args.scale_coordinates

    if args.scale_origins:
        df[Relion.ORIGINS] = df[Relion.ORIGINS] * args.scale_origins
        df["rlnMagnification"] = df["rlnMagnification"] * args.scale_origins

    if args.recenter:
        df = recenter(df, inplace=True)

    if args.zero_origins:
        df = zero_origins(df, inplace=True)

    if args.pick:
        df.drop(df.columns.difference(Relion.PICK_PARAMS),
                axis=1,
                inplace=True,
                errors="ignore")

    if args.subsample is not None and args.suffix != "":
        if args.subsample < 1:
            print("Specific integer sample size")
            return 1
        nsamplings = args.bootstrap if args.bootstrap is not None else df.shape[
            0] / np.int(args.subsample)
        inds = np.random.choice(df.shape[0],
                                size=(nsamplings, np.int(args.subsample)),
                                replace=args.bootstrap is not None)
        for i, ind in enumerate(inds):
            write_star(
                os.path.join(
                    args.output,
                    os.path.basename(args.input[0])[:-5] + args.suffix +
                    "_%d" % (i + 1)), df.iloc[ind])

    if args.to_micrographs:
        gb = df.groupby(Relion.MICROGRAPH_NAME)
        mu = gb.mean()
        df = mu[[
            c for c in Relion.CTF_PARAMS + Relion.MICROSCOPE_PARAMS +
            [Relion.MICROGRAPH_NAME] if c in mu
        ]].reset_index()

    if args.micrograph_range:
        df.set_index(Relion.MICROGRAPH_NAME, inplace=True)
        m, n = [int(tok) for tok in args.micrograph_range.split(",")]
        mg = df.index.unique().sort_values()
        outside = list(range(0, m)) + list(range(n, len(mg)))
        dfaux = df.loc[mg[outside]].reset_index()
        df = df.loc[mg[m:n]].reset_index()

    if args.min_separation is not None:
        gb = df.groupby(Relion.MICROGRAPH_NAME)
        dupes = []
        for n, g in gb:
            nb = query_connected(g[Relion.COORDS],
                                 args.min_separation / calculate_apix(df))
            dupes.extend(g.index[~np.isnan(nb)])
        dfaux = df.loc[dupes]
        df.drop(dupes, inplace=True)

    if args.split_micrographs:
        dfs = split_micrographs(df)
        for mg in dfs:
            write_star(
                os.path.join(args.output,
                             os.path.basename(mg)[:-4]) + args.suffix, dfs[mg])
        return 0

    if args.auxout is not None and dfaux is not None:
        write_star(args.auxout, dfaux)

    if args.output is not None:
        write_star(args.output, df)
    return 0
Exemple #9
0
def main(args):
    log = logging.getLogger(__name__)
    log.setLevel(logging.INFO)
    hdlr = logging.StreamHandler(sys.stdout)
    if args.quiet:
        hdlr.setLevel(logging.WARNING)
    else:
        hdlr.setLevel(logging.INFO)
    log.addHandler(hdlr)

    if args.markers is None and args.target is None and args.sym is None:
        log.error(
            "A marker or symmetry group must be provided via --target, --markers, or --sym"
        )
        return 1
    elif args.sym is None and args.markers is None and args.boxsize is None and args.origin is None:
        log.error(
            "An origin must be provided via --boxsize, --origin, or --markers")
        return 1
    elif args.sym is not None and args.markers is None and args.target is None and \
            (args.boxsize is not None or args.origin is not None):
        log.warn("Symmetry expansion alone will ignore --target or --origin")

    if args.target is not None:
        try:
            args.target = np.array(
                [np.double(tok) for tok in args.target.split(",")])
        except:
            log.error(
                "Target must be comma-separated list of x,y,z coordinates")
            return 1

    if args.origin is not None:
        if args.boxsize is not None:
            logger.warn("--origin supersedes --boxsize")
        try:
            args.origin = np.array(
                [np.double(tok) for tok in args.origin.split(",")])
        except:
            log.error(
                "Origin must be comma-separated list of x,y,z coordinates")
            return 1

    if args.marker_sym is not None:
        args.marker_sym = relion_symmetry_group(args.marker_sym)

    star = parse_star(args.input, keep_index=False)

    if args.apix is None:
        args.apix = calculate_apix(star)
        if args.apix is None:
            logger.warn(
                "Could not compute pixel size, default is 1.0 Angstroms per pixel"
            )
            args.apix = 1.0

    if args.cls is not None:
        star = select_classes(star, args.cls)

    cmms = []

    if args.markers is not None:
        cmmfiles = glob.glob(args.markers)
        for cmmfile in cmmfiles:
            for cmm in parse_cmm(cmmfile):
                cmms.append(cmm / args.apix)

    if args.target is not None:
        cmms.append(args.target / args.apix)

    stars = []

    if len(cmms) > 0:
        if args.origin is not None:
            args.origin /= args.apix
        elif args.boxsize is not None:
            args.origin = np.ones(3) * args.boxsize / 2
        else:
            log.warn("Using first marker as origin")
            if len(cmms) == 1:
                log.error(
                    "Using first marker as origin, expected at least two markers"
                )
                return 1
            args.origin = cmms[0]
            cmms = cmms[1:]

        markers = [cmm - args.origin for cmm in cmms]

        if args.marker_sym is not None and len(markers) == 1:
            markers = [op.dot(markers[0]) for op in args.marker_sym]
        elif args.marker_sym is not None:
            log.error(
                "Exactly one marker is required for symmetry-derived subparticles"
            )
            return 1

        rots = [euler2rot(*np.deg2rad(r[1])) for r in star[ANGLES].iterrows()]
        #origins = star[ORIGINS].copy()
        for m in markers:
            d = np.linalg.norm(m)
            ax = m / d
            op = euler2rot(
                *np.array([np.arctan2(ax[1], ax[0]),
                           np.arccos(ax[2]), 0.]))
            stars.append(transform_star(star, op.T, -d, rots=rots))

    if args.sym is not None:
        args.sym = relion_symmetry_group(args.sym)
        if len(stars) > 0:
            stars = [
                se for se in subparticle_expansion(
                    s, args.sym, -args.displacement / args.apix) for s in stars
            ]
        else:
            stars = list(
                subparticle_expansion(star, args.sym,
                                      -args.displacement / args.apix))

    if args.recenter:
        for s in stars:
            recenter(s, inplace=True)

    if args.suffix is None and not args.skip_join:
        if len(stars) > 1:
            star = interleave(stars)
        else:
            star = stars[0]
        write_star(args.output, star)
    else:
        for i, star in enumerate(stars):
            write_star(os.path.join(args.output, args.suffix + "_%d" % i),
                       star)
    return 0
Exemple #10
0
 def test_euler2rot(self):
     r1test = util.euler2rot(*e1)
     self.assertTrue(np.array_equal(r1, r1test))
     r2test = util.euler2rot(*e3)
     self.assertTrue(np.allclose(r3, r2test))