예제 #1
0
def _Overquenching(descendants,
                   successions=None,
                   wills=None,
                   sf_ancestors=None):
    for i_d, descendant in enumerate(descendants):
        # Assign final quenched SSFR to star-forming galaxies. This is specified
        # due to the fact that there's a lower bound on the SSFR. These values are effectively
        # hardcoded in order to reproduce the quiescent peak of the SSFR
        # distribution, which is more of a lower bound.
        #q_ssfr_mean = get_q_ssfr_mean(descendant.mass[succession[sf_ancestors]])

        sf_succession = (successions[i_d])[sf_ancestors[i_d]]
        avg_q_ssfr = sfr_evol.AverageLogSSFR_q_peak(
            descendant.mass[sf_succession])
        sigma_q_ssfr = sfr_evol.ScatterLogSSFR_q_peak(
            descendant.mass[sf_succession])

        min_q_ssfr = sigma_q_ssfr * np.random.randn(
            len(sf_succession)) + avg_q_ssfr
        descendants[i_d].min_ssfr[sf_succession] = min_q_ssfr

        # Deal with over quenched galaxies
        overquenched = np.where(descendants[i_d].min_ssfr[sf_succession] >
                                descendants[i_d].ssfr[sf_succession])
        if len(overquenched[0]) > 0:
            descendants[i_d].ssfr[sf_succession[overquenched]] = \
                    descendant.min_ssfr[sf_succession[overquenched]]
            descendants[i_d].sfr[sf_succession[overquenched]] = \
                    descendant.ssfr[sf_succession[overquenched]] \
                    + descendant.mass[sf_succession[overquenched]]
    return descendants
예제 #2
0
def _tQuench(ancestor, descendant, P_q, succession=None, will=None):
    ''' Given ancestor and descendent galaxy populations AND the quenching
    probabilities, calculate the cosmic time when the star-forming 
    ancestor galaxies, begins to quench. The the quenching time is 
    sampled uniformly between t_final and t_snap_gensis.
    '''
    sf_ancestors = np.where(
        ancestor.sfr_class[will] == 'star-forming')[0]  # SF ancestors

    np.random.seed()
    randoms = np.random.uniform(0., 1., len(sf_ancestors))
    is_qing = np.where(P_q > randoms)  # quenching
    is_notqing = np.where(P_q <= randoms)  # not quenching

    descendant.sfr_class[succession[sf_ancestors[is_qing]]] = 'quiescent'
    descendant.sfr_class[succession[sf_ancestors[is_notqing]]] = 'star-forming'
    #print len(is_qing[0]), ' is quenching'
    #print len(is_notqing[0]), ' is not quenching'

    np.random.seed()
    t_final = descendant.t_cosmic  # final t_cosmic
    t_q = (t_final -
           ancestor.tsnap_genesis[will[sf_ancestors]]) * np.random.uniform(
               0., 1., len(sf_ancestors))
    t_q += ancestor.tsnap_genesis[will[sf_ancestors]]
    z_q = z_of_t(t_q)
    t_q[is_notqing] = 999.0  # galaxies that will never quench
    z_q[is_notqing] = -999.0

    # Assign final quenched SSFR to star-forming galaxies. This is specified
    # due to the fact that there's a lower bound on the SSFR. These values are effectively
    # hardcoded in order to reproduce the quiescent peak of the SSFR
    # distribution, which is more of a lower bound.
    #q_ssfr_mean = get_q_ssfr_mean(descendant.mass[succession[sf_ancestors]])
    avg_q_ssfr = sfr_evol.AverageLogSSFR_q_peak(
        descendant.mass[succession[sf_ancestors]])
    sigma_q_ssfr = sfr_evol.ScatterLogSSFR_q_peak(
        descendant.mass[succession[sf_ancestors]])

    min_q_ssfr = sigma_q_ssfr * np.random.randn(len(sf_ancestors)) + avg_q_ssfr
    descendant.min_ssfr[sf_ancestors] = min_q_ssfr
    return descendant, t_q, z_q
예제 #3
0
    def _Overquenching(self):
        ''' Account for overquenching 

        Assign final quenched SSFR to star-forming galaxies. This is specified 
        due to the fact that there's a lower bound on the SSFR. These values are effectively 
        hardcoded in order to reproduce the quiescent peak of the SSFR 
        distribution, which is more of a lower bound. 
        '''
        for n_d in self.descendant_dict.keys():

            des = self.descendant_dict[str(n_d)]
            sf_succ = des.succession[des.sf_ancestor]

            avg_q_ssfr = sfr_evol.AverageLogSSFR_q_peak(des.mass[sf_succ])
            sigma_q_ssfr = sfr_evol.ScatterLogSSFR_q_peak(des.mass[sf_succ])

            min_q_ssfr = sigma_q_ssfr * np.random.randn(
                len(sf_succ)) + avg_q_ssfr

            self.descendant_dict[str(
                n_d)].min_ssfr[sf_succ] = min_q_ssfr.copy()

            # Deal with over quenched galaxies
            overquenched = np.where(
                self.descendant_dict[str(n_d)].min_ssfr[sf_succ] >
                self.descendant_dict[str(n_d)].ssfr[sf_succ])
            if len(overquenched[0]) > 0:
                self.descendant_dict[str(n_d)].ssfr[sf_succ[overquenched]] = \
                        self.descendant_dict[str(n_d)].min_ssfr[sf_succ[overquenched]]
                self.descendant_dict[str(n_d)].sfr[sf_succ[overquenched]] = \
                    self.descendant_dict[str(n_d)].ssfr[sf_succ[overquenched]] + \
                    self.descendant_dict[str(n_d)].mass[sf_succ[overquenched]]
                # some indicator that the galaxy has fully quenched!
                # 1 = has fully quenched 0 = otherwise
                self.descendant_dict[str(n_d)].quenched[
                    sf_succ[overquenched]] = 1
            del n_d
            del des
        return None
예제 #4
0
def EvolveSatSFR(sg_in, tqdelay_dict=None):
    ''' Evolve the infalling SFR assigned based on central galaxy SFRs
    '''
    if tqdelay_dict == None:
        raise ValueError

    # initalize
    sg_obj = SGPop()
    sg_obj.ilk = sg_in.ilk.copy()
    sg_obj.pos = sg_in.pos.copy()
    sg_obj.snap_index = sg_in.snap_index.copy()
    sg_obj.zsnap = sg_in.zsnap.copy()
    sg_obj.t_cosmic = sg_in.t_cosmic.copy()
    sg_obj.sfms_prop = sg_in.sfms_prop.copy()
    sg_obj.abcrun = sg_in.abcrun
    sg_obj.prior_name = sg_in.prior_name
    sg_obj.mass = sg_in.mass.copy()
    sg_obj.sfr = np.repeat(-999., len(sg_obj.mass))
    sg_obj.ssfr = np.repeat(-999., len(sg_obj.mass))
    sg_obj.halo_mass = sg_in.halo_mass.copy()
    sg_obj.first_infall_nsnap = sg_in.first_infall_nsnap.copy()
    sg_obj.first_infall_z = sg_in.first_infall_z.copy()
    sg_obj.first_infall_t = sg_in.first_infall_t.copy()
    sg_obj.first_infall_sfr = sg_in.first_infall_sfr.copy()
    sg_obj.first_infall_mass = sg_in.first_infall_mass.copy()
    sg_obj.t_qstart = np.repeat(-999., len(sg_obj.mass))
    sg_obj.z_qstart = np.repeat(-999., len(sg_obj.mass))
    sg_obj.q_ssfr = np.repeat(-999., len(sg_obj.mass))

    # First classify the galaxies into SF, Q, and Qing
    # this is so that t_Q,start = t_inf for Qing galaxies,
    # Q galaxies are left alone
    # SF galaxies are affected by the delay time
    infall = np.where((sg_obj.first_infall_mass > 0.)
                      & (sg_obj.first_infall_sfr > -999.))

    fq_obj = Fq()
    sfq_class = fq_obj.Classify(sg_obj.first_infall_mass[infall],
                                sg_obj.first_infall_sfr[infall],
                                sg_obj.first_infall_z[infall],
                                sg_obj.sfms_prop)

    sf_infall = (infall[0])[np.where(
        sfq_class == 'star-forming')]  # starforming @ infall
    q_infall = (infall[0])[np.where(
        sfq_class == 'quiescent')]  # quiescent @ infall

    ssfr_final = sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[infall]) + \
            sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[infall]) * np.random.randn(len(infall[0]))

    # sub-divide the quiescent @ infall population to those that are
    # quenching @ infall + quiescent @ infall based on simple SSFR cut
    q_mass_infall = sg_obj.first_infall_mass[q_infall]
    q_sfr_infall = sg_obj.first_infall_sfr[q_infall]
    q_ssfr_infall = q_sfr_infall - q_mass_infall

    q_cut_SSFR = sfr_evol.AverageLogSSFR_q_peak(q_mass_infall) + \
            1.5 * sfr_evol.ScatterLogSSFR_q_peak(q_mass_infall)

    qing_infall = q_infall[np.where(q_ssfr_infall > q_cut_SSFR)]  # quenching
    qq_infall = q_infall[np.where(q_ssfr_infall <= q_cut_SSFR)]  # quenched

    # Quiescent @ infall-----
    # The SSFR is preserved from infall, so effectively their SFR decreases
    sg_obj.ssfr[qq_infall] = sg_obj.first_infall_sfr[qq_infall] - \
            sg_obj.first_infall_mass[qq_infall]
    sg_obj.sfr[qq_infall] = sg_obj.mass[qq_infall] + sg_obj.ssfr[qq_infall]

    # Quenching @ infall-----
    # Quenching satellite galaxies skip the delay phase and immediately
    # start quenching when the simulation begins.
    sg_obj.t_qstart[qing_infall] = sg_obj.first_infall_t[qing_infall]
    sg_obj.z_qstart[qing_infall] = sg_obj.first_infall_z[qing_infall]
    sg_obj.q_ssfr[qing_infall] = sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[qing_infall]) + \
            sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[qing_infall]) * np.random.randn(len(qing_infall))

    dlogSFR_MS_M = 0.53 * (sg_obj.mass[qing_infall] -
                           sg_obj.first_infall_mass[qing_infall])

    dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * (
        sg_obj.zsnap - sg_obj.first_infall_z[qing_infall])

    dlogSFR_Q = sfr_evol.DeltaLogSFR_quenching(sg_obj.t_qstart[qing_infall],
                                               sg_obj.t_cosmic,
                                               M_q=sg_obj.mass[qing_infall],
                                               tau_prop={'name': 'satellite'})

    sg_obj.sfr[qing_infall] = sg_obj.first_infall_sfr[qing_infall] + \
            dlogSFR_MS_M + dlogSFR_MS_z + dlogSFR_Q
    sg_obj.ssfr[
        qing_infall] = sg_obj.sfr[qing_infall] - sg_obj.mass[qing_infall]

    # deal with over quenching
    #overquenched = np.where(sg_obj.ssfr[qing_infall] < sg_obj.q_ssfr[qing_infall])
    #sg_obj.ssfr[qing_infall[overquenched]] = sg_obj.q_ssfr[qing_infall[overquenched]]

    # Star-forming @ infall
    if tqdelay_dict['name'] == 'hacked':
        sg_obj.t_qstart[sf_infall] = sg_obj.first_infall_t[sf_infall] + \
                tDelay(sg_obj.mass[sf_infall], **tqdelay_dict)
    else:
        sg_obj.t_qstart[sf_infall] = sg_obj.first_infall_t[sf_infall] + \
                tDelay(sg_obj.first_infall_mass[sf_infall], **tqdelay_dict)
    # if t_qstart > t_cosmic, then it does not quenching during the simualtion
    sf_q = np.where(sg_obj.t_qstart[sf_infall] < sg_obj.t_cosmic)
    sf_noq = np.where(sg_obj.t_qstart[sf_infall] >= sg_obj.t_cosmic)
    sf_infall_q = sf_infall[sf_q]
    sf_infall_noq = sf_infall[sf_noq]

    sg_obj.z_qstart[sf_infall_q] = Util.get_zsnap(sg_obj.t_qstart[sf_infall_q])
    sg_obj.z_qstart[sf_infall_noq] = 999.

    # SF galaxies that quench
    sg_obj.q_ssfr[sf_infall_q] = \
            sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[sf_infall_q]) + \
            sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[sf_infall_q]) * \
            np.random.randn(len(sf_infall_q))

    dlogSFR_MS_M = 0.53 * (sg_obj.mass[sf_infall_q] -
                           sg_obj.first_infall_mass[sf_infall_q])

    dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * (
        sg_obj.zsnap - sg_obj.first_infall_z[sf_infall_q])
    dlogSFR_Q = sfr_evol.DeltaLogSFR_quenching(sg_obj.t_qstart[sf_infall_q],
                                               sg_obj.t_cosmic,
                                               M_q=sg_obj.mass[sf_infall_q],
                                               tau_prop={'name': 'satellite'})

    sg_obj.sfr[sf_infall_q] = sg_obj.first_infall_sfr[sf_infall_q] + \
            dlogSFR_MS_M + dlogSFR_MS_z + dlogSFR_Q
    sg_obj.ssfr[
        sf_infall_q] = sg_obj.sfr[sf_infall_q] - sg_obj.mass[sf_infall_q]
    # deal with over quenching
    #overquenched = np.where(sg_obj.ssfr[sf_infall_q] < sg_obj.q_ssfr[sf_infall_q])
    #sg_obj.ssfr[sf_infall_q[overquenched]] = sg_obj.q_ssfr[sf_infall_q[overquenched]]

    # SF galaxies that do NOT quench
    dlogSFR_MS_M = 0.53 * (sg_obj.mass[sf_infall_noq] -
                           sg_obj.first_infall_mass[sf_infall_noq])

    dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * (
        sg_obj.zsnap - sg_obj.first_infall_z[sf_infall_noq])

    sg_obj.sfr[sf_infall_noq] = sg_obj.first_infall_sfr[sf_infall_noq] + \
            dlogSFR_MS_M + dlogSFR_MS_z
    sg_obj.ssfr[
        sf_infall_noq] = sg_obj.sfr[sf_infall_noq] - sg_obj.mass[sf_infall_noq]

    # deal with overquenching all at once
    overquench = np.where(sg_obj.ssfr[infall] < ssfr_final)
    sg_obj.ssfr[infall[0][overquench]] = ssfr_final[overquench]
    sg_obj.sfr[infall[0][overquench]] = ssfr_final[overquench] + sg_obj.mass[
        infall[0][overquench]]

    return sg_obj
예제 #5
0
def AssignCenSFR(tf, abcrun=None, prior_name=None):
    ''' Given SGPop object, assign SFRs at infalling time based on the 
    median ABC Run of the Central Galaxy evolution 
    '''
    if abcrun is None:
        raise ValueError
    if prior_name is None:
        raise ValueError
    abcinh = ABCInherit(tf, abcrun=abcrun, prior_name=prior_name)

    inh = abcinh.PickleLoad('all')

    sg_obj = SGPop()
    sg_obj.ImportSubhalo(subhalo_prop=abcinh.sim_kwargs['subhalo_prop'])
    sg_obj.sfms_prop = abcinh.sim_kwargs['sfr_prop']['sfms']
    sg_obj.abcrun = abcrun
    sg_obj.prior_name = prior_name

    sg_obj.first_infall_sfr = np.repeat(-999., len(sg_obj.first_infall_nsnap))
    for i_snap in range(2, abcinh.sim_kwargs['nsnap_ancestor']):
        infall_now = np.where((sg_obj.first_infall_nsnap == i_snap)
                              & (sg_obj.first_infall_mass > 0.))[0]

        # satellite galaxies that end up massive but have 0. infalling mass
        #massive_infall_zero =np.where(
        #        (sg_obj.first_infall_mass[infall_now] == 0.) &
        #        (sg_obj.mass[infall_now] > 0.)
        #        )

        des_snap = inh[str(i_snap)]
        m_bins = np.arange(des_snap.mass.min() - 0.1,
                           des_snap.mass.max() + 0.2, 0.2)

        for i_m in range(len(m_bins) - 1):
            in_massbin = np.where((des_snap.mass >= m_bins[i_m])
                                  & (des_snap.mass < m_bins[i_m + 1]))

            infall_massbin = np.where(
                (sg_obj.first_infall_nsnap == i_snap)
                & (sg_obj.first_infall_mass >= m_bins[i_m])
                & (sg_obj.first_infall_mass < m_bins[i_m + 1]))

            if len(infall_massbin[0]) == 0:
                continue

            des_ssfrs = des_snap.sfr[in_massbin] - des_snap.mass[in_massbin]
            pdf_ssfr_i, ssfr_binedges = np.histogram(des_ssfrs,
                                                     bins=np.arange(
                                                         -13.0, -8.0, 0.2),
                                                     normed=True)

            cdf_ssfr_i = np.zeros(len(ssfr_binedges))
            cdf_ssfr_i[1:] = np.cumsum(pdf_ssfr_i * np.diff(ssfr_binedges))
            cdf_interp = interp1d(cdf_ssfr_i, ssfr_binedges, kind='linear')

            rand_i = np.random.uniform(size=len(infall_massbin[0]))
            sg_obj.first_infall_sfr[infall_massbin] = cdf_interp(rand_i) + \
                    sg_obj.first_infall_mass[infall_massbin]

    # assign SFR to galaxies that fell in before nsnap = 15
    old_infall = np.where(
        (sg_obj.first_infall_nsnap >= abcinh.sim_kwargs['nsnap_ancestor'])
        & (sg_obj.first_infall_mass > 0.))[0]

    Pq = np.random.uniform(size=len(old_infall))
    qfrac = Fq()
    fq_oldinfall = qfrac.model(sg_obj.first_infall_mass[old_infall],
                               sg_obj.first_infall_z[old_infall],
                               lit='wetzel')

    # star-forming
    sfing = np.where(Pq > fq_oldinfall)
    sig_sfms = sfr_evol.ScatterLogSFR_sfms(
        sg_obj.first_infall_mass[old_infall[sfing]],
        sg_obj.first_infall_z[old_infall[sfing]],
        sfms_prop=sg_obj.sfms_prop)
    mu_sfms = sfr_evol.AverageLogSFR_sfms(
        sg_obj.first_infall_mass[old_infall[sfing]],
        sg_obj.first_infall_z[old_infall[sfing]],
        sfms_prop=sg_obj.sfms_prop)
    sg_obj.first_infall_sfr[old_infall[sfing]] = mu_sfms + np.random.randn(
        len(sfing[0])) * sig_sfms

    # quiescent
    qed = np.where(Pq <= fq_oldinfall)
    mu_ssfr_q = sfr_evol.AverageLogSSFR_q_peak(
        sg_obj.first_infall_mass[old_infall[qed]])
    sig_ssfr_q = sfr_evol.ScatterLogSSFR_q_peak(
        sg_obj.first_infall_mass[old_infall[qed]])

    ssfr_q = mu_ssfr_q + np.random.randn(len(qed[0])) * sig_ssfr_q

    sg_obj.first_infall_sfr[
        old_infall[qed]] = ssfr_q + sg_obj.first_infall_mass[old_infall[qed]]

    return sg_obj