Esempio n. 1
0
def main(args):
    log = logging.getLogger('root')
    hdlr = logging.StreamHandler(sys.stdout)
    log.addHandler(hdlr)
    log.setLevel(logging.getLevelName(args.loglevel.upper()))
    if args.boxsize is None:
        log.error("Please specify box size")
        return 1
    df = star.parse_star(args.input, keep_index=False)
    if args.cls is not None:
        df = star.select_classes(df, args.cls)
    if args.apix is None:
        args.apix = star.calculate_apix(df)
    if args.sym is not None:
        args.sym = util.relion_symmetry_group(args.sym)
        df[star.Relion.ANGLEPSI] = 0
        rots = geom.e2r_vec(np.deg2rad(df[star.Relion.ANGLES].values))
        dfs = [star.transform_star(df, op, rots=rots) for op in args.sym]
        dfi = pd.concat(dfs, axis=0, keys=[0, 1, 2, 3])
        newrots = np.array([
            geom.e2r_vec(np.deg2rad(x[star.Relion.ANGLES].values)) for x in dfs
        ])
        mag = np.array([geom.phi5(r)
                        for r in newrots.reshape(-1, 3, 3)]).reshape(4, -1)
        idx = np.argmin(mag, axis=0)
        midx = [(i, a) for a, i in enumerate(idx)]
        df = dfi.loc[midx]
    nside = 2**args.healpix_order
    angular_sampling = np.sqrt(3 / np.pi) * 60 / nside
    theta, phi = pix2ang(nside, np.arange(12 * nside**2))
    phi = np.pi - phi
    hp = np.column_stack((np.sin(theta) * np.cos(phi),
                          np.sin(theta) * np.sin(phi), np.cos(theta)))
    kdtree = cKDTree(hp)
    st = np.sin(np.deg2rad(df[star.Relion.ANGLETILT]))
    ct = np.cos(np.deg2rad(df[star.Relion.ANGLETILT]))
    sp = np.sin(np.deg2rad(df[star.Relion.ANGLEROT]))
    cp = np.cos(np.deg2rad(df[star.Relion.ANGLEROT]))
    ptcls = np.column_stack((st * cp, st * sp, ct))
    _, idx = kdtree.query(ptcls)
    cnts = np.bincount(idx, minlength=theta.size)
    frac = cnts / np.max(cnts).astype(np.float64)
    mu = np.mean(frac)
    sigma = np.std(frac)
    color_scale = (frac - mu) / sigma
    color_scale[color_scale > 5] = 5
    color_scale[color_scale < -1] = -1
    color_scale /= 6
    color_scale += 1 / 6.
    r = args.boxsize * args.apix / 2
    rp = np.reshape(r + r * frac * args.height_scale, (-1, 1))
    base1 = hp * r
    base2 = hp * rp
    base1 = base1[:, [0, 1, 2]] + np.array([r] * 3)
    base2 = base2[:, [0, 1, 2]] + np.array([r] * 3)
    height = np.squeeze(np.abs(rp - r))
    idx = np.where(height >= 0.01)[0]
    width = args.width_scale * np.pi * r * angular_sampling / 360
    bild = np.hstack((base1, base2, np.ones((base1.shape[0], 1)) * width))
    fmt_color = ".color %f 0 %f\n"
    fmt_cyl = ".cylinder %f %f %f %f %f %f %f\n"
    with open(args.output, "w") as f:
        for i in idx:
            f.write(fmt_color % (color_scale[i], 1 - color_scale[i]))
            f.write(fmt_cyl % tuple(bild[i]))
    return 0
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
0
def main(args):
    log = logging.getLogger(__name__)
    hdlr = logging.StreamHandler(sys.stdout)
    log.addHandler(hdlr)
    log.setLevel(logging.getLevelName(args.loglevel.upper()))

    if args.target is None and args.sym is None and args.transform is None and args.euler is None:
        log.error("At least a target, transformation matrix, Euler angles, or a symmetry group must be provided")
        return 1
    elif (args.target is not None or args.transform 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.apix is None:
        df = star.parse_star(args.input, nrows=1)
        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.Relion.DETECTORPIXELSIZE] = 1.0

    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.euler is not None:
        try:
            args.euler = np.deg2rad(np.array([np.double(tok) for tok in args.euler.split(",")]))
            args.transform = np.zeros((3, 4))
            args.transform[:, :3] = geom.euler2rot(*args.euler)
            if args.target is not None:
                args.transform[:, -1] = args.target
        except:
            log.error("Euler angles must be comma-separated list of rotation, tilt, skew in degrees")
            return 1

    if args.transform is not None and not hasattr(args.transform, "dtype"):
        if args.target is not None:
            log.warn("--target supersedes --transform")
        try:
            args.transform = np.array(json.loads(args.transform))
        except:
            log.error("Transformation matrix must be in JSON/Numpy format")
            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(",")])
            args.origin /= args.apix
        except:
            log.error("Origin must be comma-separated list of x,y,z coordinates")
            return 1
    elif args.boxsize is not None:
        args.origin = np.ones(3) * args.boxsize / 2
    
    if args.sym is not None:
        args.sym = util.relion_symmetry_group(args.sym)

    df = star.parse_star(args.input)

    if star.calculate_apix(df) != args.apix:
        log.warn("Using specified pixel size of %f instead of calculated size %f" %
                 (args.apix, star.calculate_apix(df)))

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

    if args.target is not None:
        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
        r = geom.euler2rot(*np.array([np.arctan2(ax[1], ax[0]), np.arccos(ax[2]), np.deg2rad(args.psi)]))
        d = -d
    elif args.transform is not None:
        r = args.transform[:, :3]
        if args.transform.shape[1] == 4:
            d = args.transform[:, -1] / args.apix
            d = r.dot(args.origin) + d - args.origin
        else:
            d = 0
    elif args.sym is not None:
        r = np.identity(3)
        d = -args.displacement / args.apix
    else:
        log.error("At least a target or symmetry group must be provided via --target or --sym")
        return 1

    log.debug("Final rotation: %s" % str(r).replace("\n", "\n" + " " * 16))
    ops = [op.dot(r.T) for op in args.sym] if args.sym is not None else [r.T]
    log.debug("Final translation: %s (%f px)" % (str(d), np.linalg.norm(d)))
    dfs = list(subparticle_expansion(df, ops, d, rotate=args.shift_only, invert=args.invert, adjust_defocus=args.adjust_defocus))
 
    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]
        df = star.compatible(df, relion2=args.relion2, inplace=True)
        star.write_star(args.output, df, optics=(not args.relion2))
    else:
        for i, s in enumerate(dfs):
            s = star.compatible(s, relion2=args.relion2, inplace=True)
            star.write_star(os.path.join(args.output, args.suffix + "_%d" % i), s, optics=(not args.relion2))
    return 0