Esempio n. 1
0
def remove_shreds_with_highz(base):
    """
    Remove shereded objects that are within 1.25 R of each high-z (beyond NSA
    redshift cutoff) object in the base catalog. Set REMOVE to 4.

    Because this function uses objects with specs, it should be applied to
    base catalog after the specs are cleaned (i.e., after `clean_sdss_spectra`)

    `base` is modified in-place.

    Parameters
    ----------
    base : astropy.table.Table

    Returns
    -------
    base : astropy.table.Table
    """
    highz_spec_cut = Query('SPEC_Z > 0.05', 'ZQUALITY >= 3',
                           'PETRORADERR_R > 0',
                           'PETRORAD_R > 2.0*PETRORADERR_R', 'REMOVE == -1')

    highz_spec_indices = np.flatnonzero(highz_spec_cut.mask(base))

    for idx in highz_spec_indices:

        if base['REMOVE'][idx] != -1:
            continue

        nearby_obj_mask = (base['coord'].separation(base['coord'][idx]).arcsec
                           < 1.25 * base['PETRORAD_R'][idx])
        nearby_obj_mask &= (base['REMOVE'] == -1)

        assert nearby_obj_mask[idx]
        nearby_obj_mask[idx] = False
        nearby_obj_count = np.count_nonzero(nearby_obj_mask)

        if not nearby_obj_count:
            continue

        if nearby_obj_count > 25:
            logging.warning(
                'In SAGA.objects.build.remove_shreds_with_highz()\n Too many (> 25) shreds around high-z object {} ({}, {})'
                .format(base['OBJID'][idx], base['RA'][idx], base['DEC'][idx]))

        base['REMOVE'][nearby_obj_mask] = 4

    return base
Esempio n. 2
0
def remove_shreds_near_spec_obj(base, nsa=None):

    has_nsa = Query('OBJ_NSAID > -1')
    is_high_z = Query('SPEC_Z > 0.05', 'ZQUALITY >= 3', 'is_galaxy',
                      'radius > abs(radius_err) * 2.0', ~has_nsa)

    has_nsa_indices = np.flatnonzero(has_nsa.mask(base))
    has_nsa_indices = has_nsa_indices[base['r_mag'][has_nsa_indices].argsort()]

    is_high_z_indices = np.flatnonzero(is_high_z.mask(base))
    is_high_z_indices = is_high_z_indices[base['r_mag']
                                          [is_high_z_indices].argsort()]

    for idx in chain(has_nsa_indices, is_high_z_indices):
        obj_this = base[idx]

        if nsa is not None and obj_this['OBJ_NSAID'] > -1:
            nsa_obj = Query('NSAID == {}'.format(
                obj_this['OBJ_NSAID'])).filter(nsa)[0]
            ellipse_calculation = dict()
            ellipse_calculation['a'] = nsa_obj['PETRO_TH90'] * 2.0 / 3600.0
            ellipse_calculation[
                'b'] = ellipse_calculation['a'] * nsa_obj['PETRO_BA90']
            ellipse_calculation['t'] = np.deg2rad(nsa_obj['PETRO_PHI90'] +
                                                  270.0)
            ellipse_calculation['s'] = np.sin(ellipse_calculation['t'])
            ellipse_calculation['c'] = np.cos(ellipse_calculation['t'])
            ellipse_calculation['x'] = base['RA'] - nsa_obj['RA']
            ellipse_calculation['y'] = base['DEC'] - nsa_obj['DEC']
            nearby_obj_mask = ne.evaluate(
                '((x*c - y*s)/a)**2.0 + ((x*s + y*c)/b)**2.0 < 1.0',
                local_dict=ellipse_calculation,
                global_dict={})

            no_spec_z_or_close = Query('ZQUALITY < 3')
            no_spec_z_or_close |= Query(
                (lambda z: np.fabs(z - nsa_obj['Z']) < 200.0 / _SPEED_OF_LIGHT,
                 'SPEC_Z'))
            no_spec_z_or_close |= Query((lambda z: np.fabs(z - obj_this[
                'SPEC_Z']) < 200.0 / _SPEED_OF_LIGHT, 'SPEC_Z'))
            nearby_obj_mask &= no_spec_z_or_close.mask(base)

            remove_flag = 21

            values_to_rewrite = {
                'OBJID': nsa_obj['NSAID'],
                'REMOVE': 0,
                'is_galaxy': (nsa_obj['PETRO_TH50'] > 1),
                'RA': nsa_obj['RA'],
                'DEC': nsa_obj['DEC'],
                'radius': nsa_obj['PETRO_TH50'],
                'radius_err': 0,
                'survey': 'NSA',
            }

            invalid_mag = (nsa_obj['SERSIC_FLUX'] <= 0)
            nsa_sersic_flux = np.array(nsa_obj['SERSIC_FLUX'])
            nsa_sersic_flux[invalid_mag] = 1.0

            mag = 22.5 - 2.5 * np.log10(nsa_sersic_flux)
            mag_err = np.fabs((2.5 / np.log(10.0)) / nsa_sersic_flux /
                              np.sqrt(nsa_obj['SERSIC_FLUX_IVAR']))
            mag[invalid_mag] = 99.0
            mag_err[invalid_mag] = 99.0

            for i, b in enumerate(get_sdss_bands()):
                values_to_rewrite['{}_mag'.format(
                    b)] = mag[i + 2] - nsa_obj['EXTINCTION'][i + 2]
                values_to_rewrite['{}_err'.format(b)] = mag_err[i + 2]

            for k, v in values_to_rewrite.items():
                base[k][idx] = v

        elif obj_this['REMOVE'] > 0:
            continue

        else:
            remove_radius = 2.0 * obj_this['radius']
            nearby_obj_mask = (base['coord'].separation(
                obj_this['coord']).arcsec < remove_radius)
            remove_flag = 22

        nearby_obj_mask[idx] = False
        nearby_obj_count = np.count_nonzero(nearby_obj_mask)

        if not nearby_obj_count:
            continue

        if nearby_obj_count > 25 and remove_flag == 22:
            logging.warning(
                'More than 25 photo obj within ~ {:.3f}" of {} spec obj {} ({}, {})'
                .format(remove_radius, obj_this['TELNAME'], obj_this['OBJID'],
                        obj_this['RA'], obj_this['DEC']))

        base['REMOVE'][nearby_obj_mask] += (1 << remove_flag)

    return base
Esempio n. 3
0
def prepare_aat_catalog(
    target_catalog,
    write_to=None,
    verbose=True,
    flux_star_removal_threshold=20.0 * u.arcsec,
    flux_star_r_range=(17, 17.7),
    flux_star_gr_range=(0.1, 0.4),
    sky_fiber_void_radius=10.0 * u.arcsec,
    sky_fiber_needed=100,
    sky_fiber_max=1.1 * u.deg,
    sky_fiber_host_rvir_threshold=0.7 * u.deg,
    sky_fiber_radial_adjustment=2.0,
    targeting_score_threshold=900,
    seed=123,
):
    """
    Prepare AAT target catalog.

    If the host's radius is less than `sky_fiber_host_rvir_threshold`,
    all sky fiber will be distributed between `sky_fiber_max` and  host's radius.

    Otherwise, first fill the annulus between `sky_fiber_max` and host's radius,
    then distribute the rest within the host (but prefer outer region,
    as controlled by `sky_fiber_radial_adjustment`)

    Format needed:
    # TargetName(unique for header) RA(h m s) Dec(d m s) TargetType(Program,Fiducial,Sky) Priority(9 is highest) Magnitude 0 Notes
    1237648721248518305 14 42 17.79 -0 12 05.95 P 2 22.03 0 magcol=fiber2mag_r, model_r=20.69
    1237648721786045341 14 48 37.16 +0 21 33.81 P 1 21.56 0 magcol=fiber2mag_r, model_r=20.55
    """
    # pylint: disable=no-member

    if 'TARGETING_SCORE' not in target_catalog.colnames:
        return KeyError(
            '`target_catalog` does not have column "TARGETING_SCORE".'
            'Have you run `compile_target_list` or `assign_targeting_score`?')

    if not isinstance(flux_star_removal_threshold, u.Quantity):
        flux_star_removal_threshold = flux_star_removal_threshold * u.arcsec

    if not isinstance(sky_fiber_void_radius, u.Quantity):
        sky_fiber_void_radius = sky_fiber_void_radius * u.arcsec

    if not isinstance(sky_fiber_max, u.Quantity):
        sky_fiber_max = sky_fiber_max * u.deg

    if not isinstance(sky_fiber_host_rvir_threshold, u.Quantity):
        sky_fiber_host_rvir_threshold = sky_fiber_host_rvir_threshold * u.deg

    host_ra = target_catalog['HOST_RA'][0] * u.deg
    host_dec = target_catalog['HOST_DEC'][0] * u.deg
    host_dist = target_catalog['HOST_DIST'][0]
    host_rvir = np.arcsin(0.3 / host_dist) * u.rad

    annulus_actual = (sky_fiber_max**2.0 - host_rvir**2.0)
    annulus_wanted = (sky_fiber_max**2.0 - sky_fiber_host_rvir_threshold**2.0)

    if annulus_actual < 0:
        raise ValueError(
            '`sky_fiber_max` too small, this host is larger than that!')

    if annulus_wanted < 0:
        raise ValueError(
            '`sky_fiber_max` must be larger than `sky_fiber_host_rvir_threshold`!'
        )

    def _gen_dist_rand(seed_this, size):
        U = np.random.RandomState(seed_this).rand(size)
        return np.sqrt(U * annulus_actual + host_rvir**2.0)

    if annulus_actual < annulus_wanted:

        def gen_dist_rand(seed_this, size):
            size_out = int(np.around(size * annulus_actual / annulus_wanted))
            size_in = size - size_out
            dist_rand_out = _gen_dist_rand(seed_this, size_out)
            index = (1.0 / (sky_fiber_radial_adjustment + 2.0))
            dist_rand_in = (np.random.RandomState(seed_this + 1).rand(size_in)
                            **index) * host_rvir
            return np.concatenate(
                [dist_rand_out.to_value("deg"),
                 dist_rand_in.to_value("deg")]) * u.deg
    else:
        gen_dist_rand = _gen_dist_rand

    n_needed = sky_fiber_needed
    ra_sky = []
    dec_sky = []
    base_sc = SkyCoord(target_catalog['RA'], target_catalog['DEC'], unit='deg')
    while n_needed > 0:
        n_rand = int(np.ceil(n_needed * 1.1))
        dist_rand = gen_dist_rand(seed, n_rand)
        theta_rand = np.random.RandomState(seed + 1).rand(n_rand) * (2.0 *
                                                                     np.pi)
        ra_rand = np.remainder(host_ra + dist_rand * np.cos(theta_rand),
                               360.0 * u.deg)
        dec_rand = host_dec + dist_rand * np.sin(theta_rand)
        ok_mask = (dec_rand >= -90.0 * u.deg) & (dec_rand <= 90.0 * u.deg)
        ra_rand = ra_rand[ok_mask]
        dec_rand = dec_rand[ok_mask]
        sky_sc = SkyCoord(ra_rand, dec_rand)
        sep = sky_sc.match_to_catalog_sky(base_sc)[1]
        ok_mask = (sep > sky_fiber_void_radius)
        n_needed -= np.count_nonzero(ok_mask)
        ra_sky.append(ra_rand[ok_mask].to_value("deg"))
        dec_sky.append(dec_rand[ok_mask].to_value("deg"))
        seed += np.random.RandomState(seed + 2).randint(100, 200)
        del ra_rand, dec_rand, sky_sc, sep, ok_mask
    del base_sc
    ra_sky = np.concatenate(ra_sky)[:sky_fiber_needed]
    dec_sky = np.concatenate(dec_sky)[:sky_fiber_needed]

    is_target = Query('TARGETING_SCORE >= 0',
                      'TARGETING_SCORE < {}'.format(targeting_score_threshold))
    is_des = Query((lambda s: s == 'des', 'survey'))
    is_star = Query('morphology_info == 0', is_des) | Query(
        ~is_des, ~Query('is_galaxy'))
    is_flux_star = Query(is_star, 'r_mag >= {}'.format(flux_star_r_range[0]),
                         'r_mag < {}'.format(flux_star_r_range[1]))
    is_flux_star &= Query('gr >= {}'.format(flux_star_gr_range[0]),
                          'gr < {}'.format(flux_star_gr_range[1]))

    target_catalog = (is_target | is_flux_star).filter(target_catalog)
    target_catalog['Priority'] = target_catalog['TARGETING_SCORE'] // 100
    target_catalog['Priority'][Query('Priority < 1').mask(target_catalog)] = 1
    target_catalog['Priority'][Query('Priority > 8').mask(target_catalog)] = 8
    target_catalog['Priority'] = 9 - target_catalog['Priority']
    target_catalog['Priority'][is_flux_star.mask(target_catalog)] = 9

    flux_star_indices = np.flatnonzero(is_flux_star.mask(target_catalog))
    flux_star_sc = SkyCoord(*target_catalog[['RA', 'DEC'
                                             ]][flux_star_indices].itercols(),
                            unit='deg')
    target_sc = SkyCoord(*is_target.filter(target_catalog)[['RA',
                                                            'DEC']].itercols(),
                         unit='deg')
    sep = flux_star_sc.match_to_catalog_sky(target_sc)[1]
    target_catalog['Priority'][flux_star_indices[
        sep < flux_star_removal_threshold]] = 0
    target_catalog = Query('Priority > 0').filter(target_catalog)
    n_flux_star = Query('Priority == 9').count(target_catalog)
    del flux_star_indices, flux_star_sc, target_sc, sep

    target_catalog['TargetType'] = 'P'
    target_catalog['0'] = 0
    target_catalog['Notes'] = 'targets'
    target_catalog['Notes'][is_flux_star.mask(target_catalog)] = 'flux'

    target_catalog.rename_column('DEC', 'Dec')
    target_catalog.rename_column('OBJID', 'TargetName')
    target_catalog.rename_column('r_mag', 'Magnitude')

    target_catalog.sort(['TARGETING_SCORE', 'Magnitude'])
    target_catalog = target_catalog[[
        'TargetName', 'RA', 'Dec', 'TargetType', 'Priority', 'Magnitude', '0',
        'Notes'
    ]]

    sky_catalog = Table({
        'TargetName': np.arange(len(ra_sky)),
        'RA': ra_sky,
        'Dec': dec_sky,
        'TargetType': np.repeat('S', len(ra_sky)),
        'Priority': np.repeat(9, len(ra_sky)),
        'Magnitude': np.repeat(99.0, len(ra_sky)),
        '0': np.repeat(0, len(ra_sky)),
        'Notes': np.repeat('sky', len(ra_sky)),
    })

    target_catalog = vstack([target_catalog, sky_catalog])

    if verbose:
        print('# of flux stars =', n_flux_star)
        print('# of sky fibers =', len(sky_catalog))
        for rank in range(1, 10):
            print('# of Priority={} targets ='.format(rank),
                  Query('Priority == {}'.format(rank)).count(target_catalog))

    if write_to:
        if verbose:
            print('Writing to {}'.format(write_to))

        target_catalog.write(
            write_to,
            delimiter=' ',
            quotechar='"',
            format='ascii.fast_commented_header',
            overwrite=True,
            formats={
                'RA':
                lambda x: Angle(x, 'deg').wrap_at(360 * u.deg).to_string(
                    'hr', sep=' ', precision=2),  # pylint: disable=E1101
                'Dec':
                lambda x: Angle(x, 'deg').to_string(
                    'deg', sep=' ', precision=2),
                'Magnitude':
                '%.2f',
            })

        with open(write_to) as fh:
            content = fh.read()

        with open(write_to, 'w') as fh:
            fh.write(content.replace('"', ''))

    return target_catalog
Esempio n. 4
0
def add_stellar_mass(base, cosmology=WMAP9):
    """
    Calculate stellar mass based only on gi colors and redshift and add to base catalog.
    Based on GAMA data using Taylor et al (2011).

    `base` is modified in-place.

    Parameters
    ----------
    base : astropy.table.Table

    Returns
    -------
    base : astropy.table.Table
    """
    base['log_sm'] = np.nan

    global _HAS_KCORRECT
    if not _HAS_KCORRECT:
        logging.warn('No kcorrect module. Stellar mass not calculated!')
        return base

    if 'OBJID_sdss' in base.colnames:  # version 2 base catalog with SDSS
        postfix = '_sdss'
        to_calc_query = Query(C.has_spec, 'OBJID_sdss != -1')
    elif 'EXTINCTION_U' in base.colnames:  # version 1 base catalog
        postfix = ''
        to_calc_query = C.has_spec
        for b in get_sdss_bands():
            base['{}_mag'.format(b)] = base[b] - base['EXTINCTION_{}'.format(
                b.upper())]
    else:  # version 2 base catalog without SDSS
        logging.warn('No SDSS bands! Stellar mass not calculated!')
        return base

    to_calc_mask = to_calc_query.mask(base)
    if not to_calc_mask.any():
        logging.warn('Stellar mass not calculated because no valid entry!')
        return base

    if _HAS_KCORRECT != 'LOADED':
        kcorrect.load_templates()
        kcorrect.load_filters()
        _HAS_KCORRECT = 'LOADED'

    mag = view_table_as_2d_array(base, ('{}_mag{}'.format(b, postfix)
                                        for b in get_sdss_bands()),
                                 to_calc_mask, np.float32)
    mag_err = view_table_as_2d_array(base, ('{}_err{}'.format(b, postfix)
                                            for b in get_sdss_bands()),
                                     to_calc_mask, np.float32)
    redshift = view_table_as_2d_array(base, ['SPEC_Z'], to_calc_mask,
                                      np.float32)

    # CONVERT SDSS MAGNITUDES INTO MAGGIES
    mgy = 10.0**(-0.4 * mag)
    mgy_ivar = (0.4 * np.log(10.0) * mgy * mag_err)**-2.0
    kcorrect_input = np.hstack((redshift, mgy, mgy_ivar))

    # USE ASTROPY TO CALCULATE LUMINOSITY DISTANCE
    lf_distmod = cosmology.distmod(redshift.ravel()).value

    # RUN KCORRECT FIT, AND CALCULATE STELLAR MASS
    tmremain = np.array([0.601525, 0.941511, 0.607033, 0.523732, 0.763937])
    sm_not_normed = np.fromiter((np.dot(kcorrect.fit_coeffs(x)[1:], tmremain)
                                 for x in kcorrect_input), np.float64,
                                len(kcorrect_input))
    base['log_sm'][to_calc_mask] = np.log10(sm_not_normed) + (0.4 * lf_distmod)

    return base