Example #1
0
def switch_to_soft_ellipses(cat):
    from tractor.galaxy import DevGalaxy, ExpGalaxy, FixedCompositeGalaxy
    from tractor.ellipses import EllipseESoft
    for src in cat:
        if isinstance(src, (DevGalaxy, ExpGalaxy)):
            src.shape = EllipseESoft.fromEllipseE(src.shape)
        elif isinstance(src, FixedCompositeGalaxy):
            src.shapeDev = EllipseESoft.fromEllipseE(src.shapeDev)
            src.shapeExp = EllipseESoft.fromEllipseE(src.shapeExp)
Example #2
0
def switch_to_soft_ellipses(cat):
    from tractor.galaxy import DevGalaxy, ExpGalaxy, FixedCompositeGalaxy
    from tractor.ellipses import EllipseESoft
    for src in cat:
        if isinstance(src, (DevGalaxy, ExpGalaxy)):
            src.shape = EllipseESoft.fromEllipseE(src.shape)
        elif isinstance(src, FixedCompositeGalaxy):
            src.shapeDev = EllipseESoft.fromEllipseE(src.shapeDev)
            src.shapeExp = EllipseESoft.fromEllipseE(src.shapeExp)
Example #3
0
 def __init__(self, *args, **kwargs):
     super(EllipseWithPriors, self).__init__(*args, **kwargs)
     if self.ellipsePriors is None:
         ellipsePriors = _GaussianPriors(None)
         ellipsePriors.add('ee1', 0., self.ellipticityStd,
                           param=EllipseESoft(1.,0.,0.))
         ellipsePriors.add('ee2', 0., self.ellipticityStd,
                           param=EllipseESoft(1.,0.,0.))
         self.__class__.ellipsePriors = ellipsePriors
     self.gpriors = self.ellipsePriors
     self.uppers[0] = 5.
Example #4
0
    def fromStamp(stamp, N=3, P0=None, approx=1e-6, damp=0.):
        '''
        optional P0 = (list of floats): initial parameter guess.

        (parameters of a GaussianMixtureEllipsePSF)
        '''
        from tractor.ellipses import EllipseESoft
        w = np.ones(N) / float(N)
        mu = np.zeros((N, 2))
        ell = [EllipseESoft(np.log(2 * r), 0., 0.) for r in range(1, N + 1)]
        psf = GaussianMixtureEllipsePSF(w, mu, ell)
        if P0 is not None:
            psf.setAllParams(P0)
        tim = Image(data=stamp, invvar=1e6 * np.ones_like(stamp), psf=psf)
        H, W = stamp.shape
        src = PointSource(PixPos(W // 2, H // 2), Flux(1.))
        tr = Tractor([tim], [src])
        tr.freezeParam('catalog')
        tim.freezeAllBut('psf')
        # print 'Fitting:'
        # tr.printThawedParams()
        tim.modelMinval = approx
        alphas = [0.1, 0.3, 1.0]
        for step in range(50):
            dlnp, X, alpha = tr.optimize(shared_params=False,
                                         alphas=alphas,
                                         damp=damp)
            # print 'dlnp', dlnp, 'alpha', alpha
            # print 'X', X
            if dlnp < 1e-6:
                break
            # print 'psf', psf
        return psf
Example #5
0
    def __init__(self, *args):
        '''
        args = (amp, mean, ell)

        or

        args = (a0,a1,..., mx0,my0,mx1,my1,..., logr0,ee1-0,ee2-0,logr1,ee1-2,...)


        amp:  np array (size K) of Gaussian amplitudes
        mean: np array (size K,2) of means
        ell:  list (length K) of EllipseESoft objects
        '''
        if len(args) == 3:
            amp, mean, ell = args
        else:
            from tractor.ellipses import EllipseESoft
            assert (len(args) % 6 == 0)
            K = len(args) // 6
            amp = np.array(args[:K])
            mean = np.array(args[K:3 * K]).reshape((K, 2))
            args = args[3 * K:]
            ell = [EllipseESoft(*args[3 * k:3 * (k + 1)]) for k in range(K)]

        K = len(amp)
        var = np.zeros((K, 2, 2))
        for k in range(K):
            var[k, :, :] = self.ellipseToVariance(ell[k])
        self.ellipses = [e.copy() for e in ell]
        super(GaussianMixtureEllipsePSF, self).__init__(amp, mean, var)
        self.stepsizes = [0.001] * K + [0.001] * (K * 2) + [0.001] * (K * 3)
Example #6
0
 def __init__(self, *args, **kwargs):
     super(EllipseWithPriors, self).__init__(*args, **kwargs)
     if self.ellipsePriors is None:
         ellipsePriors = _GaussianPriors(None)
         ellipsePriors.add('ee1',
                           0.,
                           self.ellipticityStd,
                           param=EllipseESoft(1., 0., 0.))
         ellipsePriors.add('ee2',
                           0.,
                           self.ellipticityStd,
                           param=EllipseESoft(1., 0., 0.))
         self.__class__.ellipsePriors = ellipsePriors
     self.gpriors = self.ellipsePriors
     # MAGIC -- 30" default max r_e!
     # SEE ALSO survey.py : class(LogRadius)!
     self.uppers[0] = np.log(30.)
Example #7
0
def switch_to_soft_ellipses(cat):
    '''
    Converts our softened-ellipticity EllipseESoft parameters into
    normal EllipseE ellipses.
    
    *cat*: an iterable of tractor Sources, which will be modified
     in-place.

    '''
    from tractor.galaxy import DevGalaxy, ExpGalaxy, FixedCompositeGalaxy
    from tractor.ellipses import EllipseESoft
    for src in cat:
        if isinstance(src, (DevGalaxy, ExpGalaxy)):
            src.shape = EllipseESoft.fromEllipseE(src.shape)
        elif isinstance(src, FixedCompositeGalaxy):
            src.shapeDev = EllipseESoft.fromEllipseE(src.shapeDev)
            src.shapeExp = EllipseESoft.fromEllipseE(src.shapeExp)
Example #8
0
 def fromRAbPhi(cls, r, ba, phi):
     logr, ee1, ee2 = EllipseESoft.rAbPhiToESoft(r, ba, phi)
     return cls(logr, ee1, ee2)
Example #9
0
 def fromRAbPhi(cls, r, ba, phi):
     logr, ee1, ee2 = EllipseESoft.rAbPhiToESoft(r, ba, phi)
     return cls(logr, ee1, ee2)
Example #10
0
def get_reference_sources(survey,
                          targetwcs,
                          pixscale,
                          bands,
                          tycho_stars=True,
                          gaia_stars=True,
                          large_galaxies=True,
                          star_clusters=True):

    from legacypipe.survey import GaiaSource
    from legacypipe.survey import LegacyEllipseWithPriors
    from tractor import NanoMaggies, RaDecPos
    from tractor.galaxy import ExpGalaxy
    from tractor.ellipses import EllipseESoft

    H, W = targetwcs.shape
    H, W = int(H), int(W)

    # How big of a margin to search for bright stars and star clusters --
    # this should be based on the maximum radius they are considered to
    # affect.
    ref_margin = 0.125
    mpix = int(np.ceil(ref_margin * 3600. / pixscale))
    marginwcs = targetwcs.get_subimage(-mpix, -mpix, W + 2 * mpix,
                                       H + 2 * mpix)

    refs = []

    # Tycho-2 stars
    if tycho_stars:
        tycho = read_tycho2(survey, marginwcs)
        if len(tycho):
            refs.append(tycho)

    # Add Gaia stars
    gaia = None
    if gaia_stars:
        from astrometry.libkd.spherematch import match_radec
        gaia = read_gaia(marginwcs)
    if gaia is not None:
        gaia.isbright = (gaia.phot_g_mean_mag < 13.)
        gaia.ismedium = (gaia.phot_g_mean_mag < 16.)
        gaia.donotfit = np.zeros(len(gaia), bool)
        # Handle sources that appear in both Gaia and Tycho-2 by
        # dropping the entry from Tycho-2.
        if len(gaia) and len(tycho):
            # Before matching, apply proper motions to bring them to
            # the same epoch.  We want to use the more-accurate Gaia
            # proper motions, so rewind Gaia positions to the
            # approximate epoch of Tycho-2: 1991.5.
            cosdec = np.cos(np.deg2rad(gaia.dec))
            gra = gaia.ra + (1991.5 - gaia.ref_epoch) * gaia.pmra / (
                3600. * 1000.) / cosdec
            gdec = gaia.dec + (1991.5 - gaia.ref_epoch) * gaia.pmdec / (3600. *
                                                                        1000.)
            I, J, _ = match_radec(tycho.ra,
                                  tycho.dec,
                                  gra,
                                  gdec,
                                  1. / 3600.,
                                  nearest=True)
            debug('Matched', len(I), 'Tycho-2 stars to Gaia stars.')
            if len(I):
                keep = np.ones(len(tycho), bool)
                keep[I] = False
                tycho.cut(keep)
                gaia.isbright[J] = True
        if gaia is not None and len(gaia) > 0:
            refs.append(gaia)

    # Read the catalog of star (open and globular) clusters and add them to the
    # set of reference stars (with the isbright bit set).
    if star_clusters:
        clusters = read_star_clusters(marginwcs)
        if clusters is not None:
            debug('Found', len(clusters), 'star clusters nearby')
            clusters.iscluster = np.ones(len(clusters), bool)
            refs.append(clusters)

    # Read large galaxies nearby.
    if large_galaxies:
        galaxies = read_large_galaxies(survey, targetwcs)
        if galaxies is not None:
            # Resolve possible Gaia-large-galaxy duplicates
            if gaia and len(gaia):
                I, J, _ = match_radec(galaxies.ra,
                                      galaxies.dec,
                                      gaia.ra,
                                      gaia.dec,
                                      2. / 3600.,
                                      nearest=True)
                print('Matched', len(I), 'large galaxies to Gaia stars.')
                if len(I):
                    gaia.donotfit[J] = True
            refs.append(galaxies)

    refcat = None
    if len(refs):
        refs = merge_tables([r for r in refs if r is not None],
                            columns='fillzero')
    if len(refs) == 0:
        return None, None

    refs.radius_pix = np.ceil(refs.radius * 3600. / pixscale).astype(int)

    ok, xx, yy = targetwcs.radec2pixelxy(refs.ra, refs.dec)
    # ibx = integer brick coords
    refs.ibx = np.round(xx - 1.).astype(int)
    refs.iby = np.round(yy - 1.).astype(int)

    # cut ones whose position + radius are outside the brick bounds.
    refs.cut((xx > -refs.radius_pix) * (xx < W + refs.radius_pix) *
             (yy > -refs.radius_pix) * (yy < H + refs.radius_pix))
    # mark ones that are actually inside the brick area.
    refs.in_bounds = ((refs.ibx >= 0) * (refs.ibx < W) * (refs.iby >= 0) *
                      (refs.iby < H))

    for col in [
            'isbright', 'ismedium', 'islargegalaxy', 'iscluster', 'donotfit'
    ]:
        if not col in refs.get_columns():
            refs.set(col, np.zeros(len(refs), bool))

    ## Create Tractor sources from reference stars
    refcat = []
    for g in refs:
        if g.donotfit or g.iscluster:
            refcat.append(None)

        elif g.islargegalaxy:
            fluxes = dict([(band, NanoMaggies.magToNanomaggies(g.mag))
                           for band in bands])
            assert (np.all(np.isfinite(list(fluxes.values()))))
            rr = g.radius * 3600. / 0.5  # factor of two accounts for R(25)-->reff
            pa = 180 - g.pa
            if not np.isfinite(pa):
                pa = 0.
            logr, ee1, ee2 = EllipseESoft.rAbPhiToESoft(rr, g.ba, pa)
            gal = ExpGalaxy(RaDecPos(g.ra, g.dec),
                            NanoMaggies(order=bands, **fluxes),
                            LegacyEllipseWithPriors(logr, ee1, ee2))
            refcat.append(gal)

        else:
            # Gaia star -- which we want to create a source for, regardless of
            # whether it is marked medium | bright (or neither).
            refcat.append(GaiaSource.from_catalog(g, bands))

    for src in refcat:
        if src:
            src.is_reference_source = True

    return refs, refcat
Example #11
0
def get_galaxy_sources(galaxies, bands):
    from legacypipe.catalog import fits_reverse_typemap
    from legacypipe.survey import (LegacySersicIndex, LegacyEllipseWithPriors,
                                   LogRadius, RexGalaxy)
    from tractor import NanoMaggies, RaDecPos, PointSource
    from tractor.ellipses import EllipseE, EllipseESoft
    from tractor.galaxy import DevGalaxy, ExpGalaxy
    from tractor.sersic import SersicGalaxy

    # Factor of HyperLEDA to set the galaxy max radius
    radius_max_factor = 2.

    srcs = [None for g in galaxies]

    # If we have pre-burned galaxies, re-create the Tractor sources for them.
    I, = np.nonzero(galaxies.preburned)
    for ii, g in zip(I, galaxies[I]):
        typ = fits_reverse_typemap[g.type.strip()]
        pos = RaDecPos(g.ra, g.dec)
        fluxes = dict([(band, g.get('flux_%s' % band)) for band in bands])
        bright = NanoMaggies(order=bands, **fluxes)
        shape = None
        # put the Rex branch first, because Rex is a subclass of ExpGalaxy!
        if issubclass(typ, RexGalaxy):
            assert (np.isfinite(g.shape_r))
            logre = np.log(g.shape_r)
            shape = LogRadius(logre)
            # set prior max at 2x SGA radius
            shape.setMaxLogRadius(logre + np.log(radius_max_factor))
        elif issubclass(typ, (DevGalaxy, ExpGalaxy, SersicGalaxy)):
            assert (np.isfinite(g.shape_r))
            assert (np.isfinite(g.shape_e1))
            assert (np.isfinite(g.shape_e2))
            shape = EllipseE(g.shape_r, g.shape_e1, g.shape_e2)
            # switch to softened ellipse (better fitting behavior)
            shape = EllipseESoft.fromEllipseE(shape)
            # and then to our custom ellipse class
            logre = shape.logre
            shape = LegacyEllipseWithPriors(logre, shape.ee1, shape.ee2)
            assert (np.all(np.isfinite(shape.getParams())))
            # set prior max at 2x SGA radius
            shape.setMaxLogRadius(logre + np.log(radius_max_factor))

        if issubclass(typ, PointSource):
            src = typ(pos, bright)
        # this catches Rex too
        elif issubclass(typ, (DevGalaxy, ExpGalaxy)):
            src = typ(pos, bright, shape)
        elif issubclass(typ, (SersicGalaxy)):
            assert (np.isfinite(g.sersic))
            sersic = LegacySersicIndex(g.sersic)
            src = typ(pos, bright, shape, sersic)
        else:
            raise RuntimeError('Unknown preburned SGA source type "%s"' % typ)
        debug('Created', src)
        assert (np.isfinite(src.getLogPrior()))
        srcs[ii] = src

    # SGA parent catalog: 'preburned' is not set
    # This also can happen in the preburned/ellipse catalog when fitting
    # fails, or no-grz, etc.
    I, = np.nonzero(np.logical_not(galaxies.preburned))
    for ii, g in zip(I, galaxies[I]):
        # Initialize each source with an exponential disk--
        fluxes = dict([(band, NanoMaggies.magToNanomaggies(g.mag))
                       for band in bands])
        assert (np.all(np.isfinite(list(fluxes.values()))))
        rr = g.radius * 3600. / 2  # factor of two accounts for R(25)-->reff [arcsec]
        assert (np.isfinite(rr))
        assert (np.isfinite(g.ba))
        assert (np.isfinite(g.pa))
        ba = g.ba
        if ba <= 0.0 or ba > 1.0:
            # Make round!
            ba = 1.0
        logr, ee1, ee2 = EllipseESoft.rAbPhiToESoft(
            rr, ba, 180 - g.pa)  # note the 180 rotation
        assert (np.isfinite(logr))
        assert (np.isfinite(ee1))
        assert (np.isfinite(ee2))
        shape = LegacyEllipseWithPriors(logr, ee1, ee2)
        shape.setMaxLogRadius(logr + np.log(radius_max_factor))
        src = ExpGalaxy(RaDecPos(g.ra, g.dec),
                        NanoMaggies(order=bands, **fluxes), shape)
        assert (np.isfinite(src.getLogPrior()))
        src.needs_initial_flux = True
        srcs[ii] = src

    return srcs