예제 #1
0
    def _StarformingEvol(self):
        ''' Evolve the star-forming galaxy population. This involves evolving their 
        stellar mass and star formation rates while quenching some of them to match 
        the quiescent fraction, fQ(M*, z), simultaneously. 
        '''
        for nsnap_d in self.descendant_dict.keys():
            allwill = self.descendant_dict[str(nsnap_d)].will.copy()
            allsucc = self.descendant_dict[str(nsnap_d)].succession.copy()
            anc_sfr_class = self.ancestor.sfr_class.copy()

            q_ancestors = np.where(
                anc_sfr_class[allwill] == 'quiescent')[0]  # Q ancestors
            sf_ancestors = np.where(
                anc_sfr_class[allwill] == 'star-forming')[0]  # SF ancestors

            # star-formation duty cycle parameters (takes a long time ~15 sec)
            if not self.quiet:
                dutycycle_time = time.time()
            self.dutycycle_prop = sfr_evol.dutycycle_param(
                len(sf_ancestors),
                dutycycle_prop=self.evol_prop['sfr']['dutycycle'])
            self.dutycycle_prop['delta_sfr'] = self.ancestor.delta_sfr[
                allwill[sf_ancestors]].copy()
            if not self.quiet:
                print 'SFR dutycycle properties take ', time.time(
                ) - dutycycle_time, ' to generate'
            logsfr, t_quench = self._Evol_MshamSFR(nsnap_d, allwill,
                                                   sf_ancestors, q_ancestors)

            self.descendant_dict[str(nsnap_d)].sfr[
                allsucc[sf_ancestors]] = logsfr
            self.descendant_dict[str(nsnap_d)].ssfr[allsucc[sf_ancestors]] = \
                    self.descendant_dict[str(nsnap_d)].sfr[allsucc[sf_ancestors]] - \
                    self.descendant_dict[str(nsnap_d)].mass[allsucc[sf_ancestors]]

            is_qing = np.where(
                t_quench < self.descendant_dict[str(nsnap_d)].t_cosmic)
            is_notqing = np.where(
                t_quench >= self.descendant_dict[str(nsnap_d)].t_cosmic)

            self.descendant_dict[str(nsnap_d)].sfr_class[allsucc[sf_ancestors[is_qing]]] = \
                    'quiescent'
            self.descendant_dict[str(nsnap_d)].sfr_class[allsucc[sf_ancestors[is_notqing]]] = \
                    'star-forming'
            self.descendant_dict[str(nsnap_d)].t_quench[allsucc[
                sf_ancestors[is_qing]]] = t_quench[is_qing]

        return None
예제 #2
0
    def _StarformingEvol(self): 
        ''' Evolve the star-forming galaxy population. This involves evolving their 
        stellar mass and star formation rates while quenching some of them to match 
        the quiescent fraction, fQ(M*, z), simultaneously. 
        '''
        for nsnap_d in self.descendant_dict.keys(): 
            allwill = self.descendant_dict[str(nsnap_d)].will.copy()
            allsucc = self.descendant_dict[str(nsnap_d)].succession.copy()
            anc_sfr_class = self.ancestor.sfr_class.copy()
            
            q_ancestors = np.where(anc_sfr_class[allwill] == 'quiescent')[0]  # Q ancestors
            sf_ancestors = np.where(anc_sfr_class[allwill] == 'star-forming')[0]  # SF ancestors

            # star-formation duty cycle parameters (takes a long time ~15 sec)
            if not self.quiet: 
                dutycycle_time = time.time()
            self.dutycycle_prop = sfr_evol.dutycycle_param(
                    len(sf_ancestors), 
                    dutycycle_prop=self.evol_prop['sfr']['dutycycle'])
            self.dutycycle_prop['delta_sfr'] = self.ancestor.delta_sfr[allwill[sf_ancestors]].copy()
            if not self.quiet: 
                print 'SFR dutycycle properties take ', time.time() - dutycycle_time, ' to generate'
            logsfr, t_quench = self._Evol_MshamSFR(nsnap_d, allwill, sf_ancestors, q_ancestors)

            self.descendant_dict[str(nsnap_d)].sfr[allsucc[sf_ancestors]] = logsfr
            self.descendant_dict[str(nsnap_d)].ssfr[allsucc[sf_ancestors]] = \
                    self.descendant_dict[str(nsnap_d)].sfr[allsucc[sf_ancestors]] - \
                    self.descendant_dict[str(nsnap_d)].mass[allsucc[sf_ancestors]]

            is_qing = np.where(t_quench < self.descendant_dict[str(nsnap_d)].t_cosmic) 
            is_notqing = np.where(t_quench >= self.descendant_dict[str(nsnap_d)].t_cosmic) 

            self.descendant_dict[str(nsnap_d)].sfr_class[allsucc[sf_ancestors[is_qing]]] = \
                    'quiescent'
            self.descendant_dict[str(nsnap_d)].sfr_class[allsucc[sf_ancestors[is_notqing]]] = \
                    'star-forming'
            self.descendant_dict[str(nsnap_d)].t_quench[allsucc[sf_ancestors[is_qing]]] = t_quench[is_qing]

        return None
예제 #3
0
def _StarformingEvol_Pq(ancestor,
                        descendant,
                        succession=None,
                        will=None,
                        sfr_prop=None,
                        evol_prop=None,
                        lineage=None):
    ''' Evolve the stellar mass and star formation rates simultaneously. 
    The stellar mass evolution is dictated by the SFR.
    '''
    sfms_prop = sfr_prop['sfms']
    pq_prop = evol_prop['pq']
    tau_prop = evol_prop['tau']
    sfrevol_prop = evol_prop['sfr']
    dutycycle_prop = sfrevol_prop['dutycycle']
    massevol_prop = evol_prop['mass']

    # quenching probability
    pq_time = time.time()
    P_q = _getPq(ancestor,
                 descendant,
                 succession=succession,
                 will=will,
                 pq_prop=pq_prop,
                 sfr_prop=sfr_prop)
    print 'Quenching Probabilities takes : ', time.time() - pq_time

    # quenching time/redshift
    tq_time = time.time()
    descendant, t_q, z_q = _tQuench(ancestor,
                                    descendant,
                                    P_q,
                                    succession=succession,
                                    will=will)
    print 'tQuench takes: ', time.time() - tq_time

    # star forming ancestors
    sf_ancestors = np.where(
        ancestor.sfr_class[will] == 'star-forming')[0]  # SF ancestors

    # star-formation duty cycle parameters
    dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors),
                                              dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[will[sf_ancestors]]
    print 'SFR dutycycle properties take ', time.time(
    ) - dutycycle_time, ' to generate'

    M_q = np.repeat(-999., len(sf_ancestors))
    # keywords for logSFR(M*,t)
    kwargs_sfr = {
        't_init': descendant.tsnap_genesis[succession[sf_ancestors]],
        't_q': t_q,
        'z_q': z_q,
        'M_q': M_q,
        'dutycycle_prop': dutycycle_prop,
        'tau_prop': tau_prop,
        'sfms_prop': sfms_prop
    }

    sham_mass = descendant.mass[
        succession[sf_ancestors]].copy()  # descendant SHAM masses

    if massevol_prop['name'] == 'integrated':  # integrated stellar mass
        mass_time = time.time()
        descendant.mass[succession[sf_ancestors]], descendant.sfr[succession[sf_ancestors]], blah = \
                M_integrate(
                        ancestor.mass_genesis[will[sf_ancestors]],
                        ancestor.tsnap_genesis[will[sf_ancestors]],
                        descendant.t_cosmic,
                        massevol_prop=massevol_prop,
                        kwargs_sfr=kwargs_sfr               # kwargs for logSFR(M*,t) function
                        )
        if np.min(descendant.mass[succession[sf_ancestors]] -
                  ancestor.mass[will[sf_ancestors]]) < 0.0:
            raise ValueError("Integrated mass can't reduce the mass")
        print 'Integrated Masses takes ', time.time() - mass_time

    elif massevol_prop['name'] == 'sham':  # SHAM masses
        # determine the quenching stellar mass (the SHAM stellar mass at t_Q)
        M_q = _SHAM_Mquenching(kwargs_sfr['t_q'],
                               lineage=lineage,
                               descendant=descendant,
                               descendant_index=succession[sf_ancestors])
        kwargs_sfr['M_q'] = M_q

        descendant.sfr[succession[sf_ancestors]] = \
                logSFR_M_t(sham_mass, descendant.t_cosmic, **kwargs_sfr)

    # calculate SSFR based on evloved SFR and M*
    descendant.ssfr[succession[sf_ancestors]] = \
            descendant.sfr[succession[sf_ancestors]] - descendant.mass[succession[sf_ancestors]]

    return
예제 #4
0
def _StarformingEvol_SimulEvo(ancestor,
                              descendants,
                              successions=None,
                              wills=None,
                              sfr_prop=None,
                              evol_prop=None,
                              lineage=None,
                              quiet=True):
    ''' Evolve the stellar mass, star formation rates, and quench galaxies simultaneously. 
    '''
    sfms_prop = sfr_prop['sfms']  # SFMS properties
    fq_prop = sfr_prop['fq']  # fq_prop
    tau_prop = evol_prop['tau']  # Quenching timescale properties
    fudge_prop = evol_prop['fudge']
    dutycycle_prop = evol_prop['sfr']['dutycycle']  # SF dutycycle properties
    massevol_prop = evol_prop['mass']  # mass evolution properties

    if len(descendants) > 1:
        allwill = np.array(list(set(list(
            np.concatenate(wills)))))  # combine will of unique elements
        t_output = []
        for des in descendants:
            t_output.append(des.t_cosmic)
    else:
        t_output = [descendants[0].t_cosmic]
        allwill = wills[0]
    sf_ancestors = np.where(
        ancestor.sfr_class[allwill] == 'star-forming')[0]  # SF ancestors
    q_ancestors = np.where(
        ancestor.sfr_class[allwill] == 'quiescent')[0]  # Q ancestors

    # star-formation duty cycle parameters
    if not quiet:
        dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors),
                                              dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[allwill[sf_ancestors]]

    if not quiet:
        print 'SFR dutycycle properties take ', time.time(
        ) - dutycycle_time, ' to generate'

    MshamEvol = ancestor.Msham_evol[0]
    # keywords for logSFR(M*,t)
    kwargs_sfr = {
        'dutycycle_prop': dutycycle_prop,
        'tau_prop': tau_prop,
        'fudge_prop': fudge_prop,
        'fq_prop': fq_prop,
        'sfms_prop': sfms_prop,
        'massevol_prop': massevol_prop
    }
    if not quiet:
        mass_time = time.time()

    # DEFUNCT FOR NOW. needs to be updated
    #if massevol_prop['name'] == 'integrated':
    #    M_evolved, SFR_evolved, tQ = \
    #            Evol_IntegMstarSFR(
    #                    ancestor.mass_genesis[will[sf_ancestors]],
    #                    ancestor.tsnap_genesis[will[sf_ancestors]],
    #                    descendant.t_cosmic,
    #                    tQ0=ancestor.tQ[will[sf_ancestors]],
    #                    MQ0=ancestor.MQ[will[sf_ancestors]],
    #                    ancestor_Mq=MshamEvol[will[q_ancestors],:],
    #                    **kwargs_sfr
    #                    )
    #elif massevol_prop['name'] == 'sham':
    bef_tsnap = ancestor.tsnap_genesis[allwill[sf_ancestors]]
    bef_tQ = ancestor.tQ[allwill[sf_ancestors]]
    bef_MQ = ancestor.MQ[allwill[sf_ancestors]]
    bef_sfr = ancestor.sfr[allwill[sf_ancestors]]
    bef_MshamEvol = MshamEvol[allwill]
    SFRs_evolved, tQ = \
            Evol_shamMstarSFR(
                    ancestor.tsnap_genesis[allwill[sf_ancestors]],
                    t_output,
                    tQ0=ancestor.tQ[allwill[sf_ancestors]],
                    MQ0=ancestor.MQ[allwill[sf_ancestors]],
                    SFR0=ancestor.sfr[allwill[sf_ancestors]],
                    q_Mshams=MshamEvol[allwill[q_ancestors],:],
                    sf_Mshams=MshamEvol[allwill[sf_ancestors],:],
                    **kwargs_sfr
                    )
    print 'tsnap stays the same', np.array_equal(
        bef_tsnap, ancestor.tsnap_genesis[allwill[sf_ancestors]])
    print 'tQ stays the same', np.array_equal(
        bef_tQ, ancestor.tQ[allwill[sf_ancestors]])
    print 'MQ stays the same', np.array_equal(
        bef_MQ, ancestor.MQ[allwill[sf_ancestors]])
    print 'SFR stays the same', np.array_equal(
        bef_sfr, ancestor.sfr[allwill[sf_ancestors]])
    print 'MshamEvol stays the same', np.array_equal(bef_MshamEvol,
                                                     MshamEvol[allwill])

    print 'recalculating for just t=', t_output[0]
    SFRs_evolved1, tQ1 = \
            Evol_shamMstarSFR(
                    ancestor.tsnap_genesis[allwill[sf_ancestors]],
                    [t_output[0]],
                    tQ0=ancestor.tQ[allwill[sf_ancestors]],
                    MQ0=ancestor.MQ[allwill[sf_ancestors]],
                    SFR0=ancestor.sfr[allwill[sf_ancestors]],
                    q_Mshams=MshamEvol[allwill[q_ancestors],:],
                    sf_Mshams=MshamEvol[allwill[sf_ancestors],:],
                    **kwargs_sfr
                    )

    print 'tsnap stays the same', np.array_equal(
        bef_tsnap, ancestor.tsnap_genesis[allwill[sf_ancestors]])
    print 'tQ stays the same', np.array_equal(
        bef_tQ, ancestor.tQ[allwill[sf_ancestors]])
    print 'MQ stays the same', np.array_equal(
        bef_MQ, ancestor.MQ[allwill[sf_ancestors]])
    print 'SFR stays the same', np.array_equal(
        bef_sfr, ancestor.sfr[allwill[sf_ancestors]])
    print 'MshamEvol stays the same', np.array_equal(bef_MshamEvol,
                                                     MshamEvol[allwill])

    print np.array_equal(SFRs_evolved[0], SFRs_evolved1)

    dist, bins = np.histogram(SFRs_evolved[0], range=[-5, 2])
    plt.plot(0.5 * (bins[:-1] + bins[1:]), dist)
    dist, bins = np.histogram(SFRs_evolved1, range=[-5, 2])
    plt.plot(0.5 * (bins[:-1] + bins[1:]), dist)

    plt.show()

    for i_d in range(len(t_output)):
        sf_anc = np.where(ancestor.sfr_class[wills[i_d]] == 'star-forming')[0]
        sf_succession = (successions[i_d])[sf_anc]
        sf_will = (wills[i_d])[sf_anc]

        sf_allwill = allwill[sf_ancestors]

        ss, ww = intersection_index(sf_allwill, sf_will)
        if len(ww) != len(sf_will):
            raise ValueError

        #descendants[i_d].mass[sf_succession[ww]] = (Ms_evolved[i_d])[ss]
        descendants[i_d].sfr[sf_succession[ww]] = (SFRs_evolved[i_d])[ss]

        is_qing = np.where(tQ[ss] < t_output[i_d])
        is_notqing = np.where(tQ[ss] >= t_output[i_d])
        descendants[i_d].sfr_class[sf_succession[is_qing]] = 'quiescent'
        descendants[i_d].sfr_class[sf_succession[is_notqing]] = 'star-forming'

        # calculate SSFR based on evloved SFR and M*
        descendants[i_d].ssfr[sf_succession[ww]] = \
                descendants[i_d].sfr[sf_succession[ww]] - descendants[i_d].mass[sf_succession[ww]]

        #if massevol_prop['name'] == 'integrated':
        #    if np.min(descendant.mass[succession[sf_ancestors]] - ancestor.mass[will[sf_ancestors]]) < 0.0:
        #        raise ValueError("Integrated mass can't reduce the mass")
    return descendants
def _StarformingEvol_Pq(ancestor, descendant, succession=None, will=None, 
        sfr_prop=None, evol_prop=None, lineage=None): 
    ''' Evolve the stellar mass and star formation rates simultaneously. 
    The stellar mass evolution is dictated by the SFR.
    '''
    sfms_prop = sfr_prop['sfms']
    pq_prop = evol_prop['pq'] 
    tau_prop = evol_prop['tau']
    sfrevol_prop = evol_prop['sfr']
    dutycycle_prop = sfrevol_prop['dutycycle']
    massevol_prop = evol_prop['mass']

    # quenching probability 
    pq_time = time.time() 
    P_q = _getPq(ancestor, descendant, 
            succession=succession, will=will, 
            pq_prop=pq_prop, sfr_prop=sfr_prop)
    print 'Quenching Probabilities takes : ', time.time() - pq_time
    
    # quenching time/redshift
    tq_time = time.time()
    descendant, t_q, z_q = _tQuench(ancestor, descendant, 
            P_q, succession=succession, will=will)
    print 'tQuench takes: ', time.time() - tq_time     
    
    # star forming ancestors
    sf_ancestors = np.where(ancestor.sfr_class[will] == 'star-forming')[0]  # SF ancestors

    # star-formation duty cycle parameters
    dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors), dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[will[sf_ancestors]]
    print 'SFR dutycycle properties take ', time.time() - dutycycle_time, ' to generate'
    
    M_q = np.repeat(-999., len(sf_ancestors))
    # keywords for logSFR(M*,t)
    kwargs_sfr = {
            't_init': descendant.tsnap_genesis[succession[sf_ancestors]], 
            't_q': t_q, 
            'z_q': z_q, 
            'M_q': M_q, 
            'dutycycle_prop': dutycycle_prop, 
            'tau_prop': tau_prop, 
            'sfms_prop': sfms_prop
            }

    sham_mass =  descendant.mass[succession[sf_ancestors]].copy()   # descendant SHAM masses

    if massevol_prop['name'] == 'integrated':   # integrated stellar mass 
        mass_time = time.time()
        descendant.mass[succession[sf_ancestors]], descendant.sfr[succession[sf_ancestors]], blah = \
                M_integrate(
                        ancestor.mass_genesis[will[sf_ancestors]], 
                        ancestor.tsnap_genesis[will[sf_ancestors]], 
                        descendant.t_cosmic,
                        massevol_prop=massevol_prop,
                        kwargs_sfr=kwargs_sfr               # kwargs for logSFR(M*,t) function
                        )
        if np.min(descendant.mass[succession[sf_ancestors]] - ancestor.mass[will[sf_ancestors]]) < 0.0: 
            raise ValueError("Integrated mass can't reduce the mass")
        print 'Integrated Masses takes ', time.time() - mass_time
        
    elif massevol_prop['name'] == 'sham':       # SHAM masses 
        # determine the quenching stellar mass (the SHAM stellar mass at t_Q)
        M_q = _SHAM_Mquenching(kwargs_sfr['t_q'], lineage=lineage, 
                descendant=descendant, 
                descendant_index=succession[sf_ancestors])
        kwargs_sfr['M_q'] = M_q

        descendant.sfr[succession[sf_ancestors]] = \
                logSFR_M_t(sham_mass, descendant.t_cosmic, **kwargs_sfr)
    
    # calculate SSFR based on evloved SFR and M*
    descendant.ssfr[succession[sf_ancestors]] = \
            descendant.sfr[succession[sf_ancestors]] - descendant.mass[succession[sf_ancestors]]
    
    return 
def _StarformingEvol_SimulEvo(ancestor, descendants, successions=None, wills=None, 
        sfr_prop=None, evol_prop=None, lineage=None, quiet=True): 
    ''' Evolve the stellar mass, star formation rates, and quench galaxies simultaneously. 
    '''
    sfms_prop = sfr_prop['sfms']        # SFMS properties
    fq_prop = sfr_prop['fq']            # fq_prop 
    tau_prop = evol_prop['tau']         # Quenching timescale properties
    fudge_prop = evol_prop['fudge']
    dutycycle_prop = evol_prop['sfr']['dutycycle']   # SF dutycycle properties 
    massevol_prop = evol_prop['mass']   # mass evolution properties
    
    if len(descendants) > 1: 
        allwill = np.array(list(set(list(np.concatenate(wills)))))   # combine will of unique elements
        t_output = [] 
        for des in descendants: 
            t_output.append(des.t_cosmic)
    else: 
        t_output = [descendants[0].t_cosmic]
        allwill = wills[0]
    sf_ancestors = np.where(ancestor.sfr_class[allwill] == 'star-forming')[0]  # SF ancestors
    q_ancestors = np.where(ancestor.sfr_class[allwill] == 'quiescent')[0]  # Q ancestors

    # star-formation duty cycle parameters
    if not quiet: 
        dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors), dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[allwill[sf_ancestors]]

    if not quiet: 
        print 'SFR dutycycle properties take ', time.time() - dutycycle_time, ' to generate'
    
    MshamEvol = ancestor.Msham_evol[0]
    # keywords for logSFR(M*,t)
    kwargs_sfr = {'dutycycle_prop': dutycycle_prop, 'tau_prop': tau_prop, 'fudge_prop': fudge_prop,
            'fq_prop': fq_prop, 'sfms_prop': sfms_prop, 'massevol_prop': massevol_prop}
    if not quiet: 
        mass_time = time.time()

    # DEFUNCT FOR NOW. needs to be updated
    #if massevol_prop['name'] == 'integrated': 
    #    M_evolved, SFR_evolved, tQ = \
    #            Evol_IntegMstarSFR(
    #                    ancestor.mass_genesis[will[sf_ancestors]], 
    #                    ancestor.tsnap_genesis[will[sf_ancestors]], 
    #                    descendant.t_cosmic,
    #                    tQ0=ancestor.tQ[will[sf_ancestors]],
    #                    MQ0=ancestor.MQ[will[sf_ancestors]],
    #                    ancestor_Mq=MshamEvol[will[q_ancestors],:], 
    #                    **kwargs_sfr               
    #                    )
    #elif massevol_prop['name'] == 'sham': 
    bef_tsnap = ancestor.tsnap_genesis[allwill[sf_ancestors]]
    bef_tQ = ancestor.tQ[allwill[sf_ancestors]] 
    bef_MQ = ancestor.MQ[allwill[sf_ancestors]] 
    bef_sfr = ancestor.sfr[allwill[sf_ancestors]]
    bef_MshamEvol = MshamEvol[allwill]
    SFRs_evolved, tQ = \
            Evol_shamMstarSFR(
                    ancestor.tsnap_genesis[allwill[sf_ancestors]], 
                    t_output,
                    tQ0=ancestor.tQ[allwill[sf_ancestors]],
                    MQ0=ancestor.MQ[allwill[sf_ancestors]],
                    SFR0=ancestor.sfr[allwill[sf_ancestors]], 
                    q_Mshams=MshamEvol[allwill[q_ancestors],:], 
                    sf_Mshams=MshamEvol[allwill[sf_ancestors],:],
                    **kwargs_sfr               
                    )
    print 'tsnap stays the same', np.array_equal(bef_tsnap, ancestor.tsnap_genesis[allwill[sf_ancestors]])
    print 'tQ stays the same', np.array_equal(bef_tQ, ancestor.tQ[allwill[sf_ancestors]])
    print 'MQ stays the same', np.array_equal(bef_MQ, ancestor.MQ[allwill[sf_ancestors]]) 
    print 'SFR stays the same', np.array_equal(bef_sfr, ancestor.sfr[allwill[sf_ancestors]])
    print 'MshamEvol stays the same', np.array_equal(bef_MshamEvol, MshamEvol[allwill])

    print 'recalculating for just t=', t_output[0]
    SFRs_evolved1, tQ1 = \
            Evol_shamMstarSFR(
                    ancestor.tsnap_genesis[allwill[sf_ancestors]], 
                    [t_output[0]],
                    tQ0=ancestor.tQ[allwill[sf_ancestors]],
                    MQ0=ancestor.MQ[allwill[sf_ancestors]],
                    SFR0=ancestor.sfr[allwill[sf_ancestors]], 
                    q_Mshams=MshamEvol[allwill[q_ancestors],:], 
                    sf_Mshams=MshamEvol[allwill[sf_ancestors],:],
                    **kwargs_sfr               
                    )

    print 'tsnap stays the same', np.array_equal(bef_tsnap, ancestor.tsnap_genesis[allwill[sf_ancestors]])
    print 'tQ stays the same', np.array_equal(bef_tQ, ancestor.tQ[allwill[sf_ancestors]])
    print 'MQ stays the same', np.array_equal(bef_MQ, ancestor.MQ[allwill[sf_ancestors]]) 
    print 'SFR stays the same', np.array_equal(bef_sfr, ancestor.sfr[allwill[sf_ancestors]])
    print 'MshamEvol stays the same', np.array_equal(bef_MshamEvol, MshamEvol[allwill])

    print np.array_equal(SFRs_evolved[0], SFRs_evolved1) 
    
    dist, bins = np.histogram(SFRs_evolved[0], range=[-5, 2])
    plt.plot(0.5 * (bins[:-1] + bins[1:]), dist)
    dist, bins = np.histogram(SFRs_evolved1, range=[-5, 2])
    plt.plot(0.5 * (bins[:-1] + bins[1:]), dist)

    plt.show()

    for i_d in range(len(t_output)): 
        sf_anc = np.where(ancestor.sfr_class[wills[i_d]] == 'star-forming')[0] 
        sf_succession = (successions[i_d])[sf_anc]
        sf_will = (wills[i_d])[sf_anc]

        sf_allwill = allwill[sf_ancestors]

        ss, ww = intersection_index(sf_allwill, sf_will)
        if len(ww) != len(sf_will): 
            raise ValueError

        #descendants[i_d].mass[sf_succession[ww]] = (Ms_evolved[i_d])[ss]
        descendants[i_d].sfr[sf_succession[ww]] = (SFRs_evolved[i_d])[ss]

        is_qing = np.where(tQ[ss] < t_output[i_d]) 
        is_notqing = np.where(tQ[ss] >= t_output[i_d]) 
        descendants[i_d].sfr_class[sf_succession[is_qing]] = 'quiescent'
        descendants[i_d].sfr_class[sf_succession[is_notqing]] = 'star-forming'

        # calculate SSFR based on evloved SFR and M*
        descendants[i_d].ssfr[sf_succession[ww]] = \
                descendants[i_d].sfr[sf_succession[ww]] - descendants[i_d].mass[sf_succession[ww]]
    
        #if massevol_prop['name'] == 'integrated': 
        #    if np.min(descendant.mass[succession[sf_ancestors]] - ancestor.mass[will[sf_ancestors]]) < 0.0: 
        #        raise ValueError("Integrated mass can't reduce the mass")
    return descendants 
def _StarformingEvol(ancestor, descendant, succession=None, will=None, sfr_prop=None, evol_prop=None, lineage=None): 
    ''' Evolve the stellar mass, star formation rates, and quench galaxies simultaneously. 
    '''
    # SFMS properties
    sfms_prop = sfr_prop['sfms']
    # fq_prop 
    fq_prop = sfr_prop['fq']
    # Quenching timescale properties
    tau_prop = evol_prop['tau']
    # SFR evolution properties 
    sfrevol_prop = evol_prop['sfr']
    # SF dutycycle properties 
    dutycycle_prop = sfrevol_prop['dutycycle']
    # mass evolution properties
    massevol_prop = evol_prop['mass']
    
    # star forming ancestors
    sf_ancestors = np.where(ancestor.sfr_class[will] == 'star-forming')[0]  # SF ancestors

    # star-formation duty cycle parameters
    dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors), dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[will[sf_ancestors]]
    print 'SFR dutycycle properties take ', time.time() - dutycycle_time, ' to generate'
    
    # keywords for logSFR(M*,t)
    kwargs_sfr = {
            'dutycycle_prop': dutycycle_prop, 
            'tau_prop': tau_prop, 
            'fq_prop': fq_prop, 
            'sfms_prop': sfms_prop, 
            'massevol_prop': massevol_prop
            }

    sham_mass =  descendant.mass[succession[sf_ancestors]].copy()   # descendant SHAM masses

    mass_time = time.time()
    descendant.mass[succession[sf_ancestors]], descendant.sfr[succession[sf_ancestors]] = \
            MstarSFR_simul_evol(
                    ancestor.mass_genesis[will[sf_ancestors]], 
                    ancestor.tsnap_genesis[will[sf_ancestors]], 
                    descendant.t_cosmic,
                    **kwargs_sfr               
                    )
    if np.min(descendant.mass[succession[sf_ancestors]] - ancestor.mass[will[sf_ancestors]]) < 0.0: 
        raise ValueError("Integrated mass can't reduce the mass")
    '''    
    elif massevol_prop['name'] == 'sham':       # SHAM masses 
        # determine the quenching stellar mass (the SHAM stellar mass at t_Q)
        M_q = _SHAM_Mquenching(kwargs_sfr['t_q'], lineage=lineage, 
                descendant=descendant, 
                descendant_index=succession[sf_ancestors])
        kwargs_sfr['M_q'] = M_q

        descendant.sfr[succession[sf_ancestors]] = \
                logSFR_M_t(sham_mass, descendant.t_cosmic, **kwargs_sfr)
    ''' 
    # calculate SSFR based on evloved SFR and M*
    descendant.ssfr[succession[sf_ancestors]] = \
            descendant.sfr[succession[sf_ancestors]] - descendant.mass[succession[sf_ancestors]]
    return     
def _StarformingEvol(ancestor,
                     descendant,
                     succession=None,
                     will=None,
                     sfr_prop=None,
                     evol_prop=None,
                     lineage=None):
    ''' Evolve the stellar mass, star formation rates, and quench galaxies simultaneously. 
    '''
    # SFMS properties
    sfms_prop = sfr_prop['sfms']
    # fq_prop
    fq_prop = sfr_prop['fq']
    # Quenching timescale properties
    tau_prop = evol_prop['tau']
    # SFR evolution properties
    sfrevol_prop = evol_prop['sfr']
    # SF dutycycle properties
    dutycycle_prop = sfrevol_prop['dutycycle']
    # mass evolution properties
    massevol_prop = evol_prop['mass']

    # star forming ancestors
    sf_ancestors = np.where(
        ancestor.sfr_class[will] == 'star-forming')[0]  # SF ancestors

    # star-formation duty cycle parameters
    dutycycle_time = time.time()
    dutycycle_prop = sfr_evol.dutycycle_param(len(sf_ancestors),
                                              dutycycle_prop=dutycycle_prop)
    dutycycle_prop['delta_sfr'] = ancestor.delta_sfr[will[sf_ancestors]]
    print 'SFR dutycycle properties take ', time.time(
    ) - dutycycle_time, ' to generate'

    # keywords for logSFR(M*,t)
    kwargs_sfr = {
        'dutycycle_prop': dutycycle_prop,
        'tau_prop': tau_prop,
        'fq_prop': fq_prop,
        'sfms_prop': sfms_prop,
        'massevol_prop': massevol_prop
    }

    sham_mass = descendant.mass[
        succession[sf_ancestors]].copy()  # descendant SHAM masses

    mass_time = time.time()
    descendant.mass[succession[sf_ancestors]], descendant.sfr[succession[sf_ancestors]] = \
            MstarSFR_simul_evol(
                    ancestor.mass_genesis[will[sf_ancestors]],
                    ancestor.tsnap_genesis[will[sf_ancestors]],
                    descendant.t_cosmic,
                    **kwargs_sfr
                    )
    if np.min(descendant.mass[succession[sf_ancestors]] -
              ancestor.mass[will[sf_ancestors]]) < 0.0:
        raise ValueError("Integrated mass can't reduce the mass")
    '''    
    elif massevol_prop['name'] == 'sham':       # SHAM masses 
        # determine the quenching stellar mass (the SHAM stellar mass at t_Q)
        M_q = _SHAM_Mquenching(kwargs_sfr['t_q'], lineage=lineage, 
                descendant=descendant, 
                descendant_index=succession[sf_ancestors])
        kwargs_sfr['M_q'] = M_q

        descendant.sfr[succession[sf_ancestors]] = \
                logSFR_M_t(sham_mass, descendant.t_cosmic, **kwargs_sfr)
    '''
    # calculate SSFR based on evloved SFR and M*
    descendant.ssfr[succession[sf_ancestors]] = \
            descendant.sfr[succession[sf_ancestors]] - descendant.mass[succession[sf_ancestors]]
    return