def param_sfms(self, nsnap = None, **pltkwargs): 
        '''
        Plot parameterized SFMS
        '''
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if nsnap is None: 
            if self.cenque_nsnap is not None: 
                nsnap = self.cenque_nsnap
            else: 
                raise ValueError('nsnap needs to be specified')
        
        if 'justsf' in self.kwargs: 
            self.sub.plot(
                np.arange(8.5, 12.0, 0.1), 
                sfr_mstar_z(np.arange(8.5, 12.0, 0.1), get_z_nsnap(nsnap)), 
                c = 'k', 
                ls = '--', 
                lw = 3 
                )
        else:
            plt.plot(
                    np.arange(8.5, 12.0, 0.1), 
                    sfr_mstar_z(np.arange(8.5, 12.0, 0.1), get_z_nsnap(nsnap)), 
                    c = 'k', 
                    ls = '--', 
                    lw = 3 
                    )

        return None
Exemple #2
0
    def param_sfms(self, nsnap=None, **pltkwargs):
        '''
        Plot parameterized SFMS
        '''
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if nsnap is None:
            if self.cenque_nsnap is not None:
                nsnap = self.cenque_nsnap
            else:
                raise ValueError('nsnap needs to be specified')

        if 'justsf' in self.kwargs:
            self.sub.plot(np.arange(8.5, 12.0, 0.1),
                          sfr_mstar_z(np.arange(8.5, 12.0, 0.1),
                                      get_z_nsnap(nsnap)),
                          c='k',
                          ls='--',
                          lw=3)
        else:
            plt.plot(np.arange(8.5, 12.0, 0.1),
                     sfr_mstar_z(np.arange(8.5, 12.0, 0.1),
                                 get_z_nsnap(nsnap)),
                     c='k',
                     ls='--',
                     lw=3)

        return None
def rho_ssfr_cq_evol(
        start_nsnap = 13, 
        final_nsnap = 1, 
        sf_prop = {'name': 'average'}, 
        fq_prop = {'name': 'wetzelsmooth'}, 
        tau_prop = {'name': 'instant'}, 
        mass_evol = 'sham', 
        Mrcut=18, 
        **kwargs
        ): 
    """ Compare sSFR distribution of evolved CenQue and
    SDSS Group Catalog in the green valley
    """

    if Mrcut == 18: 
        z_med = 0.03
    elif Mrcut == 19: 
        z_med = 0.05
    elif Mrcut == 20: 
        z_med = 0.08

    evol_cq_ssfr_bin, evol_cq_ssfr_hist = ssfr_cq_evol(
            start_nsnap = start_nsnap, 
            final_nsnap = final_nsnap, 
            sf_prop = sf_prop, 
            fq_prop = fq_prop, 
            tau_prop = tau_prop, 
            mass_evol = mass_evol, 
            **kwargs
            )

    group_ssfr = Ssfr()
    group_ssfr_bin, group_ssfr_hist = group_ssfr.groupcat(Mrcut=Mrcut)
    
    l2_ssfr = 0.0
    for i_massbin, massbin in enumerate(group_ssfr.mass_bins): 

        if not np.array_equal(evol_cq_ssfr_bin[i_massbin], group_ssfr_bin[i_massbin]):
            raise ValueError()

        # sSFR comparison range

        q_ssfr_massbin = np.mean(get_q_ssfr_mean(massbin)) 

        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        sf_ssfr_massbin = sfr_mstar_z(massbin[1], z_med) - massbin[1]

        green_range = np.where(
                (evol_cq_ssfr_bin[i_massbin] > q_ssfr_massbin) &
                (evol_cq_ssfr_bin[i_massbin] < sf_ssfr_massbin)
                )

        #print np.sum((evol_cq_ssfr_hist[i_massbin][green_range] - group_ssfr_hist[i_massbin][green_range])**2)

        l2_ssfr += np.sum((evol_cq_ssfr_hist[i_massbin][green_range] - group_ssfr_hist[i_massbin][green_range])**2)

    return l2_ssfr
def rho_ssfr_cq_evol(start_nsnap=13,
                     final_nsnap=1,
                     sf_prop={'name': 'average'},
                     fq_prop={'name': 'wetzelsmooth'},
                     tau_prop={'name': 'instant'},
                     mass_evol='sham',
                     Mrcut=18,
                     **kwargs):
    """ Compare sSFR distribution of evolved CenQue and
    SDSS Group Catalog in the green valley
    """

    if Mrcut == 18:
        z_med = 0.03
    elif Mrcut == 19:
        z_med = 0.05
    elif Mrcut == 20:
        z_med = 0.08

    evol_cq_ssfr_bin, evol_cq_ssfr_hist = ssfr_cq_evol(start_nsnap=start_nsnap,
                                                       final_nsnap=final_nsnap,
                                                       sf_prop=sf_prop,
                                                       fq_prop=fq_prop,
                                                       tau_prop=tau_prop,
                                                       mass_evol=mass_evol,
                                                       **kwargs)

    group_ssfr = Ssfr()
    group_ssfr_bin, group_ssfr_hist = group_ssfr.groupcat(Mrcut=Mrcut)

    l2_ssfr = 0.0
    for i_massbin, massbin in enumerate(group_ssfr.mass_bins):

        if not np.array_equal(evol_cq_ssfr_bin[i_massbin],
                              group_ssfr_bin[i_massbin]):
            raise ValueError()

        # sSFR comparison range

        q_ssfr_massbin = np.mean(get_q_ssfr_mean(massbin))

        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        sf_ssfr_massbin = sfr_mstar_z(massbin[1], z_med) - massbin[1]

        green_range = np.where((evol_cq_ssfr_bin[i_massbin] > q_ssfr_massbin) &
                               (evol_cq_ssfr_bin[i_massbin] < sf_ssfr_massbin))

        #print np.sum((evol_cq_ssfr_hist[i_massbin][green_range] - group_ssfr_hist[i_massbin][green_range])**2)

        l2_ssfr += np.sum((evol_cq_ssfr_hist[i_massbin][green_range] -
                           group_ssfr_hist[i_massbin][green_range])**2)

    return l2_ssfr
def plot_sfms_wetzel_vs_lee():
    '''
    Plot Wetzel parameterized SFMS and Lee et al. (2015) parameterized SFMS. 
    '''
    
    # wetzel 
    wetzel_sfr_mstar_z, wetzel_sig_sfr_mstar_z = get_param_sfr_mstar_z()

    # Lee et al. (2015)

    z_mid = np.array([0.36, 0.55, 0.70, 0.85, 0.99, 1.19])
    logM_lim = np.array([8.50, 9.00, 9.00, 9.30, 9.30, 9.30])

    masses = np.arange(7.5, 12.0, 0.1) 

    prettyplot()
    pretty_colors = prettycolors()

    fig = plt.figure(figsize=(10,10))
    sub = fig.add_subplot(111)

    for i_z, z in enumerate(z_mid): 

        sub.scatter(
                masses, 
                lee_et_al_2015(masses, z),
                c = pretty_colors[i_z],
                label = r"$\mathtt{z = "+str(round(z, 2))+"}$"
                )

        sub.plot(
                masses, 
                wetzel_sfr_mstar_z(masses, z),
                c = pretty_colors[i_z], 
                ls = '--', 
                lw = 3 
                )
        #sub.vlines(logM_lim[i_z], -5.0, 2.0, color='k', linestyle='--', lw=2)

    sub.set_xlim([7.0, 12.0])
    sub.set_ylim([-3.0, 2.0])
    sub.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=30)
    sub.set_ylabel(r'$\mathtt{log\;SFR}$', fontsize=30)
    sub.legend(loc='lower right', scatterpoints=1)
    fig_file = ''.join([
        'figure/', 
        'qaplot_sfms_wetzel_vs_lee.png'
        ])
    fig.savefig(fig_file, bbox_inches='tight')

    plt.show()
Exemple #6
0
def plot_sfms_wetzel_vs_lee():
    '''
    Plot Wetzel parameterized SFMS and Lee et al. (2015) parameterized SFMS. 
    '''

    # wetzel
    wetzel_sfr_mstar_z, wetzel_sig_sfr_mstar_z = get_param_sfr_mstar_z()

    # Lee et al. (2015)

    z_mid = np.array([0.36, 0.55, 0.70, 0.85, 0.99, 1.19])
    logM_lim = np.array([8.50, 9.00, 9.00, 9.30, 9.30, 9.30])

    masses = np.arange(7.5, 12.0, 0.1)

    prettyplot()
    pretty_colors = prettycolors()

    fig = plt.figure(figsize=(10, 10))
    sub = fig.add_subplot(111)

    for i_z, z in enumerate(z_mid):

        sub.scatter(masses,
                    lee_et_al_2015(masses, z),
                    c=pretty_colors[i_z],
                    label=r"$\mathtt{z = " + str(round(z, 2)) + "}$")

        sub.plot(masses,
                 wetzel_sfr_mstar_z(masses, z),
                 c=pretty_colors[i_z],
                 ls='--',
                 lw=3)
        #sub.vlines(logM_lim[i_z], -5.0, 2.0, color='k', linestyle='--', lw=2)

    sub.set_xlim([7.0, 12.0])
    sub.set_ylim([-3.0, 2.0])
    sub.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=30)
    sub.set_ylabel(r'$\mathtt{log\;SFR}$', fontsize=30)
    sub.legend(loc='lower right', scatterpoints=1)
    fig_file = ''.join(['figure/', 'qaplot_sfms_wetzel_vs_lee.png'])
    fig.savefig(fig_file, bbox_inches='tight')

    plt.show()
def assign_sfr(cenque,
               sf_prop={'name': 'average'},
               fq_prop={'name': 'wetzelsmooth'},
               quiet=True,
               **kwargs):
    """ Assign star-formation properties to CenQue object. 

    The function Goes through mass bins and then classifies unassigned 
    galaxies into quiescent/star-forming based on quiescent fraction 
    function. 
    
    Then SF properties are assigned to the galaxies. For quiescent 
    galaxies the sSFR is drawn from a log normal distribution about 
    some predeterimined mu_sSFR. For star-forming galaxies, SFR is
    sampled from a designated SF-MS model. 
    
    ----------------------------------------------------------------
    Parameters
    ----------------------------------------------------------------
    cenque : CenQue class object 

    ----------------------------------------------------------------
    Notes 
    ----------------------------------------------------------------
    * Re imagine how to set up SFR 

    """

    # time the code
    start_time = time.time()

    if cenque.mass == None:
        raise ValueError()

    if cenque.zsnap == None:
        raise ValueError()

    if 'sf_prop' not in cenque.__dict__.keys():
        cenque.sf_prop = sf_prop
    else:
        if cenque.sf_prop != sf_prop:
            cenque.sf_prop = sf_prop
            warnings.warn("SF properties do not match; Replacing SF_prop")

    if 'fq_prop' not in cenque.__dict__.keys():
        cenque.fq_prop = fq_prop
    else:
        if cenque.fq_prop != fq_prop:
            warnings.warn("fQ properties do not match")

    mass_bins = cenque.mass_bins
    mass_bin_low = mass_bins.mass_low
    mass_bin_mid = mass_bins.mass_mid
    mass_bin_high = mass_bins.mass_high

    # remove galaxies below the minimum and maximum mass and galaxies without children
    within_massbin_with_child = np.where(
        (cenque.mass > mass_bins.mass_low.min())
        & (cenque.mass <= mass_bins.mass_high.max()) & (cenque.child >= 0))

    if (min(cenque.mass) < mass_bins.mass_low.min()) or (max(
            cenque.mass) > mass_bins.mass_high.max()):
        cenque.sample_trim(within_massbin_with_child)

    ngal_tot = len(within_massbin_with_child[0])

    for attrib in ['sf_prop', 'fq_prop']:
        if attrib not in cenque.metadata:
            cenque.metadata.append(attrib)

    for attrib in ['gal_type', 'sfr', 'ssfr']:
        if attrib not in cenque.data_columns:
            cenque.data_columns.append(attrib)

    if cenque.gal_type is None:
        cenque.gal_type = np.array(['' for i in xrange(ngal_tot)],
                                   dtype='|S16')
        cenque.sfr = np.array([-999. for i in xrange(ngal_tot)])
        cenque.ssfr = np.array([-999. for i in xrange(ngal_tot)])

    # simplest SFR assignment for starforming galaxies. Use mu_SFR(M*, z)
    # and randomly sampled normal delta_SFR.
    if sf_prop['name'] == 'average':
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if 'delta_sfr' not in cenque.__dict__.keys():
            cenque.delta_sfr = np.array([-999. for i in xrange(ngal_tot)])

        if 'avg_sfr' not in cenque.__dict__.keys():
            cenque.avg_sfr = np.array([-999. for i in xrange(ngal_tot)])

        extra_attr = ['avg_sfr', 'delta_sfr']

    elif sf_prop['name'] == 'average_noscatter':
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if 'delta_sfr' not in cenque.__dict__.keys():
            cenque.delta_sfr = np.array([-999. for i in xrange(ngal_tot)])

        if 'avg_sfr' not in cenque.__dict__.keys():
            cenque.avg_sfr = np.array([-999. for i in xrange(ngal_tot)])

        extra_attr = ['avg_sfr', 'delta_sfr']

    else:
        raise NotImplementedError()

    for attrib in extra_attr:
        if attrib not in cenque.data_columns:
            cenque.data_columns.append(attrib)

    # f_Q(M_*,mid, z_snapshot)
    qf_massbin = get_fq(mass_bin_mid, cenque.zsnap, lit=fq_prop['name'])

    massbin_unassigned = [
        np.where((cenque.mass > mass_bin_low[i_m])
                 & (cenque.mass <= mass_bin_high[i_m])
                 & (cenque.gal_type == ''))[0]
        for i_m in xrange(mass_bins.nbins)
    ]

    # Ngal(M_mid), Ngal,Q(M_mid) and Ngal,SF(M_mid)
    ngal_massbin = np.array([x.size for x in massbin_unassigned])
    ngal_q_massbin = np.rint(qf_massbin *
                             ngal_massbin.astype(float)).astype(int)
    ngal_sf_massbin = ngal_massbin - ngal_q_massbin

    # fail-safe for ngal_q_massbin
    if len(np.where(ngal_q_massbin > ngal_massbin)[0]) > 0:
        ngal_q_massbin[np.where(
            ngal_q_massbin > ngal_massbin)] = ngal_massbin[np.where(
                ngal_q_massbin > ngal_massbin)]

    for i_m in xrange(mass_bins.nbins):

        if len(massbin_unassigned[i_m]) == 0:
            continue

        begin_loop_time = time.time()
        if not quiet:
            print mass_bin_low[i_m], ' < M < ', mass_bin_high[i_m]
            print 'fQ = ', qf_massbin[i_m], ' Ngal = ', ngal_massbin[i_m]
            print 'Ngal,Q = ', ngal_q_massbin[
                i_m], ' Ngal,SF = ', ngal_sf_massbin[i_m]

        shuffled_massbin_index = np.arange(ngal_massbin[i_m])
        np.random.seed()
        np.random.shuffle(shuffled_massbin_index)
        i_q_end = ngal_q_massbin[i_m]

        # Randomly select ngal_q_massbin quiescent galaxies from the
        # massbin. Assign them 'quiescent' gal_type and sSFR and SFR
        # based on a predetermined gaussian distribution about sSFR.
        if ngal_q_massbin[i_m] > 0:

            q_massbin = shuffled_massbin_index[:i_q_end]
            i_q_massbin = (massbin_unassigned[i_m])[q_massbin]

            cenque.gal_type[i_q_massbin] = 'quiescent'

            # sample SSFR from log-normal distribution with a preset
            # 0.18 dex scatter centered about some predetermined mean
            mu_q_ssfr = util.get_q_ssfr_mean(cenque.mass[i_q_massbin])
            if len(i_q_massbin) != ngal_q_massbin[i_m]:
                print shuffled_massbin_index
                print q_massbin
                print i_q_massbin
                print i_q_end, ngal_q_massbin[i_m]

            cenque.ssfr[i_q_massbin] = 0.18 * np.random.randn(
                ngal_q_massbin[i_m]) + mu_q_ssfr
            cenque.sfr[i_q_massbin] = cenque.ssfr[i_q_massbin] + cenque.mass[
                i_q_massbin]

        # ngal_sf_massbin starforming galaxies from the massbin. Assign
        # them 'star-forming' gal_type and sSFR and SFR in some manner
        if ngal_sf_massbin[i_m] > 0:

            #sf_massbin = shuffled_massbin_index[i_q_end:i_sf_end]
            sf_massbin = shuffled_massbin_index[i_q_end:]
            i_sf_massbin = (massbin_unassigned[i_m])[sf_massbin]

            cenque.gal_type[i_sf_massbin] = 'star-forming'

            # sample SFR
            if sf_prop['name'] == 'average':

                mu_sf_sfr = sfr_mstar_z(cenque.mass[i_sf_massbin],
                                        cenque.zsnap)
                sigma_sf_sfr = sig_sfr_mstar_z(cenque.mass[i_sf_massbin],
                                               cenque.zsnap)

                cenque.avg_sfr[i_sf_massbin] = mu_sf_sfr
                cenque.delta_sfr[
                    i_sf_massbin] = sigma_sf_sfr * np.random.randn(
                        ngal_sf_massbin[i_m])

                cenque.sfr[
                    i_sf_massbin] = mu_sf_sfr + cenque.delta_sfr[i_sf_massbin]

                if not quiet:
                    print 'Starforming galaxies: '
                    print 'Average(SFR) = ', mu_sf_sfr, ' sigma(SFR) = ', sigma_sf_sfr

            elif sf_prop['name'] == 'average_noscatter':

                mu_sf_sfr = sfr_mstar_z(cenque.mass[i_sf_massbin],
                                        cenque.zsnap)
                sigma_sf_sfr = 0.0

                cenque.avg_sfr[i_sf_massbin] = mu_sf_sfr
                cenque.delta_sfr[
                    i_sf_massbin] = sigma_sf_sfr * np.random.randn(
                        ngal_sf_massbin[i_m])

                cenque.sfr[
                    i_sf_massbin] = mu_sf_sfr + cenque.delta_sfr[i_sf_massbin]

                if not quiet:
                    print 'Starforming galaxies: '
                    print 'Average(SFR) = ', mu_sf_sfr, ' sigma(SFR) = ', sigma_sf_sfr

            else:
                raise NotImplementedError

            cenque.ssfr[i_sf_massbin] = cenque.sfr[i_sf_massbin] - cenque.mass[
                i_sf_massbin]

    # double check that SF assign didn't fail anywhere
    assign_fail = np.where((cenque.sfr == -999.0) | (cenque.ssfr == -999.0))
    if len(assign_fail[0]) > 0:
        raise NameError('Function failed!')

    if not quiet:
        print 'Assign SFR function takes', (time.time() -
                                            start_time) / 60.0, ' minutes'

    if 'evol_from' in cenque.cenque_type:
        pass
    else:
        cenque.cenque_type = 'sf_assigned'

    return cenque
Exemple #8
0
def test_mass_evol(
    mass0,
    t0,
    tf,
    delmass0=0.1,
    t_initial=4.0079,
    sfrevol_param=[1.0, 1.0],
    sfrevol_prop={'name': 'notperiodic'},
    massevol_prop={
        'name': 'integrated',
        'type': 'euler',
        'f_retain': 0.6,
        't_step': 0.025
    },
):
    '''

    Testing integrated mass evolution

    logSFR(z) function is implemented within this module

    '''

    # spline between z and t_cosmic
    z, t = np.loadtxt(Util.snapshottable(), unpack=True, usecols=[2, 3])
    z_of_t = interpolate.interp1d(list(reversed(t)),
                                  list(reversed(z)),
                                  kind='cubic')
    z0 = z_of_t(t0)
    zf = z_of_t(tf)

    # average SFR of SF MS
    logsfr_mstar_z, sig_logsfr_mstar_z = get_param_sfr_mstar_z()

    def logsfr_notquenched(logmass, t_input, **kwargs):

        zi = kwargs['z0']
        mass_i = kwargs['mass0']
        delmass_i = kwargs['deltamass0']

        avglogsfr = logsfr_mstar_z(logmass, zi)
        #print 'SFMS(', mass0[0], ',', str(zi), ') ', avglogsfr[0]

        # Contribution from the SF evolution of the SFMS
        logsfr_sfms = sfr_evol.logsfr_sfms_evol(zi, z_of_t(t_input))

        # Contribution from the SF Duty cycle
        logsfr_sfduty = sfr_evol.logsfr_sfduty_fluct(
            t_initial,
            t_input,
            delta_sfr=delmass_i,
            sfrevol_param=sfrevol_param,
            **sfrevol_prop)
        #print logsfr_sfduty

        logsfr_f = avglogsfr + logsfr_sfms + logsfr_sfduty
        #print np.max(logsfr_f - logsfr_mstar_z(logmass, z_of_t(t_input))), np.min(logsfr_f - logsfr_mstar_z(logmass, z_of_t(t_input)))

        return logsfr_f

    sfrkwargs = {'z0': z0, 'mass0': mass0, 'deltamass0': delmass0}
    mass_f, sfr_f = mass_evol.integrated(massevol_prop['type'],
                                         logsfr_notquenched,
                                         mass0,
                                         t0,
                                         tf,
                                         f_retain=massevol_prop['f_retain'],
                                         delt=massevol_prop['t_step'],
                                         **sfrkwargs)
    #print sfr_f[:3]
    #print logsfr_notquenched(mass_f, tf, **sfrkwargs)[:3]
    #print logsfr_mstar_z(mass0, zf)[:3]

    return mass_f, sfr_f
Exemple #9
0
def plot_integrated_mass_evol(mass0,
                              t0,
                              tf,
                              sfrevol_prop={'name': 'notperiodic'},
                              massevol_prop={
                                  'name': 'integrated',
                                  'type': 'euler',
                                  'f_retain': 0.6,
                                  't_step': 0.05
                              },
                              title=None,
                              fig_file=None):
    '''
    
    Plot of the integrated mass and SFR evolution as a function of cosmic time 

    '''
    if title is None:
        raise ValueError
    delt = (tf - t0) / 10.0
    tfs = np.arange(t0 + delt, tf + delt, delt)

    z, t = np.loadtxt(Util.snapshottable(), unpack=True, usecols=[2, 3])
    z_of_t = interpolate.interp1d(list(reversed(t)),
                                  list(reversed(z)),
                                  kind='cubic')

    # SF MS
    logsfr_mstar_z, sig_logsfr_mstar_z = get_param_sfr_mstar_z()

    # figure
    prettyplot()
    pretty_colors = prettycolors()
    fig = plt.figure(1, figsize=(10, 12))
    # mass evolution
    m_sub = fig.add_subplot(211)
    # SFR evolution
    sub = fig.add_subplot(212)

    delta_masses = np.arange(-0.3, 0.3, 0.05)
    #delta_masses = [0.0]    # test case
    for delmass in delta_masses:
        # SFR evolution parameters (for SF duty cycle)
        sfrevol_param = sfr_evol.get_sfrevol_param(1, np.array([0]),
                                                   **sfrevol_prop)

        masses = [mass0]
        sfmssfrs = [logsfr_mstar_z(mass0, z_of_t(t0))]
        sfrs = [logsfr_mstar_z(mass0, z_of_t(t0)) + delmass]

        mass_i_1 = mass0
        t_i_1 = t0

        for tf_i in tfs:

            mass_i, sfr_i = test_mass_evol(mass0,
                                           t0,
                                           tf_i,
                                           delmass0=delmass,
                                           t_initial=t0,
                                           sfrevol_param=sfrevol_param,
                                           sfrevol_prop=sfrevol_prop,
                                           massevol_prop=massevol_prop)

            masses.append(mass_i)
            sfrs.append(sfr_i)
            sfmssfrs.append(logsfr_mstar_z(mass0, z_of_t(tf_i)))

            t_i_1 = tf_i
            mass_i_1 = mass_i

        tfs = np.hstack([t0, tfs])
        for i in xrange(len(masses[0])):
            if delmass == delta_masses[0]:
                m_label = str(mass0[i])
            else:
                m_label = None
            m_sub.plot(tfs,
                       np.array(masses)[:, i],
                       c=pretty_colors[i],
                       lw=3,
                       alpha=0.5,
                       label=m_label)

        for i in xrange(len(masses[0])):
            if delmass == delta_masses[0]:
                sfr_label = str(mass0[i])
            else:
                sfr_label = None
            sub.plot(tfs,
                     np.array(sfrs)[:, i],
                     c=pretty_colors[i],
                     lw=2,
                     alpha=0.5,
                     label=sfr_label)
            sub.plot(tfs, np.array(sfmssfrs)[:, i], c='k', lw=2, ls='--')

        for tf_i in tfs:
            sub.vlines(tf_i, -1.0, 2.5, color='k', linewidth=1, linestyle=':')

    m_sub.set_xlim([t0 - 2.5, tf + 0.5])
    m_sub.set_ylim([8.5, 12.5])
    m_sub.set_ylabel(r"$\mathtt{log\;M_*}$", fontsize=20)
    m_sub.set_title(title)

    sub.set_xlim([t0 - 2.5, tf + 0.5])
    sub.set_ylim([-2.0, 2.0])
    sub.set_xlabel(r"$\mathtt{t_{cosmic}}$", fontsize=20)
    sub.set_ylabel(r"$\mathtt{log\;SFR}$", fontsize=20)
    sub.legend(loc='upper left')

    if fig_file is not None:
        figfile = ''.join(['figure/', fig_file])
        fig.savefig(figfile, bbox_inches='tight')
    #plt.show()
    plt.close()
def evolve_onestep(parent_cq, child_cq, predict_step = 3, quiet=False):
    """ Evolve CenQue class object by one time step 
    """
    evo_start = time.time()

    mass_bins = child_cq.mass_bins
    
    # remove galaxies below the min and max mass
    within_massbin = np.where(
            (child_cq.mass > min(mass_bins.mass_low)) & 
            (child_cq.mass <= max(mass_bins.mass_high))
            ) 
    child_cq.sample_trim(within_massbin)                   

    n_child = len(within_massbin[0])     
    n_parent = len(parent_cq.mass)

    # SF and stellar mass properties are added as attributes 
    # to the CenQue object
    child_cq.gal_type         = np.array(['' for i in xrange(n_child)], dtype='|S16') 
    child_cq.sfr              = np.array([-999. for i in xrange(n_child)]) 
    child_cq.ssfr             = np.array([-999. for i in xrange(n_child)]) 
    child_cq.q_ssfr           = np.array([-999. for i in xrange(n_child)]) 
    child_cq.tau              = np.array([-999. for i in xrange(n_child)]) 
    child_cq.parent_sfr       = np.array([-999. for i in xrange(n_child)]) 
    child_cq.parent_mass      = np.array([-999. for i in xrange(n_child)]) 
    child_cq.parent_halo_mass = np.array([-999. for i in xrange(n_child)]) 

    for attrib in ['gal_type', 'sfr', 'ssfr', 'q_ssfr', 'tau', 
            'parent_sfr', 'parent_mass', 'parent_halo_mass']: 
        if attrib not in child_cq.data_columns: 
            child_cq.data_columns.append(attrib)

    if child_cq.sf_prop['name'] == 'average': 
        child_cq.delta_sfr = np.array([-999. for i in range(n_child)]) 
        extra_attr = ['delta_sfr']
    else: 
        raise NotImplementedError() 

    for attrib in extra_attr: 
        if attrib not in child_cq.data_columns: 
            child_cq.data_columns.append(attrib)

    # parent children match which assigns indices into dictionaries and then get dictionary values
    parents, children = parent_children_match(parent_cq.snap_index, child_cq.parent)

    # Deal with parent to children inheritance (children inherit the parents' attributes)
    # This step needs to be thought out more. 
    if not quiet: 
        inheritance_time = time.time()

    child_cq.parent_sfr[children]       = parent_cq.sfr[parents]
    child_cq.parent_mass[children]      = parent_cq.mass[parents]
    child_cq.parent_halo_mass[children] = parent_cq.halo_mass[parents]
    
    for attr in child_cq.data_columns: 
        # Inherit everything but the TreePM and Halo information
        if attr not in ('mass', 'halo_mass', 'parent', 'child', 'ilk', 'snap_index', 'pos', 
                'parent_sfr', 'parent_mass', 'parent_halo_mass'): 
            try: 
                parent_attr = getattr(parent_cq, attr)[parents]
                getattr(child_cq, attr)[children] = parent_attr
            except AttributeError: 
                if 'evol_from' not in parent_cq.cenque_type:
                    pass 
                else: 
                    raise ValueError()
    if not quiet: 
        print 'Inheritance takes ', time.time() - inheritance_time
    
    # Stellar mass evolution of star forming galaxies. Either integrated or 
    # SHAM masses assigned from TreePM 
    if child_cq.mass_evol == 'integrated':
        # integrated SFR mass evolution of star-forming galaxies 
        # (only star-forming galaxies) 

        if kwargs['sfr'] == 'sfr_func': 

            integrated_mass = util.integrated_mass_rk4(
                    util.sfr_squarewave, (child_cq.parent_mass)[sf_child_indx], 
                    parent_cq.t_cosmic, child_cq.t_cosmic, 
                    amp = (child_cq.sfr_amp)[sf_child_indx], 
                    freq = (child_cq.sfr_freq)[sf_child_indx], 
                    phase = (child_cq.sfr_phase)[sf_child_indx])
            (child_cq.mass)[sf_child_indx] = integrated_mass

        elif kwargs['sfr'] == 'sfr_avg': 

            (child_cq.mass)[sf_child_indx] = util.integrated_mass_rk4(
                    util.sfr_avg_residual, (child_cq.parent_mass)[sf_child_indx], 
                    parent_cq.t_cosmic, child_cq.t_cosmic, 
                    resid = (child_cq.sfr_resid)[sf_child_indx])
            if not silent: 
                print 'Integrated Mass vs SHAM mass' 
                print (child_cq.mass)[sf_child_indx] - (child_cq.sham_mass)[sf_child_indx]

    # Evolve Quiescent Children. 
    # Quiecsent galaxies keep the same sSFR while the quiescent galaxy 
    # masses are assigned by SHAM masses
    quiescent_children = np.where(
            (child_cq.gal_type[children] == 'quiescent') & 
            (child_cq.tau[children] == -999.0)
            )
    q_children = children[quiescent_children]
    
    # correct the SFR in order to preserve SSFR
    # this is because the mass evolves through SHAM  
    child_cq.sfr[q_children] = child_cq.ssfr[q_children] + child_cq.mass[q_children]
    
    # Evolve Star-forming Children 
    # include doucmentation details 
    # include doucmentation details 
    # include doucmentation details 
    # include doucmentation details 
    # include doucmentation details 
    starforming_children = np.where(
            child_cq.gal_type[children] == 'star-forming'
            )
    sf_children = children[starforming_children] 

    if child_cq.sf_prop['name'] == 'average': 

        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        child_sfr = sfr_mstar_z(
                child_cq.mass[sf_children], 
                child_cq.zsnap
                )

        child_cq.sfr[sf_children] = child_sfr + child_cq.delta_sfr[sf_children]
    else: 
        raise NotImplementedError() 

    child_cq.ssfr[sf_children] = child_cq.sfr[sf_children] - child_cq.mass[sf_children]

    # Evolve quenching children by exp(- delta t_cosmic / tau)
    quenching_time = time.time()
    still_quenching = np.where(child_cq.tau > 0.0)

    if len(still_quenching[0]) > 0: 

        # for galaxies with tau, keep them quenching!
        tau_quench = np.log10( 
                np.exp( 
                    -(child_cq.t_cosmic - parent_cq.t_cosmic) / child_cq.tau[still_quenching]
                    )
                )                                              # SFR quenching amount  

        child_cq.sfr[still_quenching] = child_cq.parent_sfr[still_quenching] + tau_quench 
        child_cq.ssfr[still_quenching] = child_cq.sfr[still_quenching] - child_cq.mass[still_quenching]
    else: 
        if 'evol_from' in parent_cq.cenque_type:
            if child_cq.tau_prop['name'] != 'instant': 
                raise ValueError()
    
    if not quiet: 
        print 'Quenching SF galaxies takes ', time.time() - quenching_time
    
    # numpy.where of mass bins 
    mass_bin_indices = np.array([
        np.where(
            (child_cq.mass > mass_bins.mass_low[i_m]) & 
            (child_cq.mass <= mass_bins.mass_high[i_m]) & 
            (child_cq.gal_type != '') 
            )
        for i_m in xrange(mass_bins.nbins)
        ])
    
    # number of galaxies in each of the mass bins 
    ngal_mass_bin = np.array([
        len(mass_bin_indices[i_m][0])
        for i_m in xrange(mass_bins.nbins)
        ])
        
    # f_Q of child CenQue as a function of mass
    # f_Q(M_bin)
    child_fq = get_fq(
            mass_bins.mass_mid, 
            child_cq.zsnap, 
            lit = child_cq.fq_prop['name']
            ) 
    
    # f_Q of descendant 
    child_cq.predict_nsnap = child_cq.nsnap - predict_step
    if child_cq.predict_nsnap < 0: 
        child_cq.predict_nsnap = 0

    descendant_fq = get_fq_nsnap(
            mass_bins.mass_mid, 
            child_cq.predict_nsnap, 
            lit = child_cq.fq_prop['name']
            )
    descendant_tcosmic = util.get_t_nsnap(child_cq.predict_nsnap)
    
    # expected number of quiescent galaxies = Ngal * f_Q
    # N_gal,exp * f_Q(M_bin)
    exp_ngal_q = np.rint( child_fq * ngal_mass_bin ).astype(int)

    child_galtype_list = [
            child_cq.gal_type[mass_bin_indices[i_m][0]]
            for i_m in xrange(mass_bins.nbins)
            ]
    sf_massbin_indices = [ 
            (mass_bin_indices[i_m][0])[np.where(child_galtype_list[i_m] == 'star-forming')]
            for i_m in xrange(mass_bins.nbins)
            ]
    ngal_sf_mass_bin = [ 
            len(sf_massbin_indices[i_m]) 
            for i_m in xrange(mass_bins.nbins)
            ]
    
    # quiescent + quenching galaxies
    q_massbin_indices = [ 
            (mass_bin_indices[i_m][0])[np.where(child_galtype_list[i_m] == 'quiescent')]
            for i_m in xrange(mass_bins.nbins)
            ]
    ngal_q_obs = [ 
            len(np.where(sfq_classify(
                child_cq.mass[q_massbin_index], 
                child_cq.sfr[q_massbin_index], 
                child_cq.zsnap) == 'quiescent'
                )[0])
            for q_massbin_index in q_massbin_indices
            ]
    ngal2quench = exp_ngal_q - ngal_q_obs 
    print ngal2quench
    #ngal2quench = exp_ngal_q - ngal_mass_bin + ngal_sf_mass_bin 
    
    exp_exp_ngal_q = np.rint( descendant_fq * ngal_mass_bin ).astype(int)
    ngal2quenchfuture = exp_exp_ngal_q - ngal_q_obs 

    quench_index = [] 
    quenching_start_time = time.time()
    # Quench a number of star-forming galaxies in order to match the 
    # quiescent fraction at the next cosmic time step 
            
    # Tau specifier
    if child_cq.tau_prop['name'] in ('instant', 'constant', 'satellite', 'long'): 
        tau_str = ''.join(['_', child_cq.tau_prop['name'], 'tau'])
    elif child_cq.tau_prop['name'] in ('line'):
        tau_str = ''.join([
            '_', child_cq.tau_prop['name'], 'tau', 
            '_Mfid', str(child_cq.tau_prop['fid_mass']), 
            '_slope', str(round(child_cq.tau_prop['slope'], 4)), 
            '_yint', str(round(child_cq.tau_prop['yint'],4))
            ])

    f = open(''.join(['dat/f_quenching/quenching_fraction', tau_str, '_nsnap', str(child_cq.nsnap), '.dat']), 'w')
    f.write('# mass, f_quenching\n')
    
    f_quenchings = [] 
    for i_m in xrange(mass_bins.nbins):              

        quench_is, f_quenching = quenching_galaxies_massbin(
                child_cq, 
                child_cq.t_cosmic - parent_cq.t_cosmic, 
                descendant_tcosmic - parent_cq.t_cosmic, 
                child_cq.prev_fquenching[i_m], 
                mass_bins.mass_mid[i_m], 
                mass_bin_indices[i_m], 
                sf_massbin_indices[i_m], 
                ngal2quench[i_m], 
                ngal2quenchfuture[i_m], 
                quiet=quiet
                )
        print mass_bins.mass_mid[i_m], f_quenching, child_cq.prev_fquenching[i_m]

        f_quenchings.append(f_quenching)

        quench_index += quench_is
        f.write(
                '\t'.join([str(mass_bins.mass_mid[i_m]), str(f_quenching), '\n'])
                )
    f.close()
    quench_index = np.array(quench_index)

    child_cq.prev_fquenching = f_quenchings

    if len(quench_index) != 0:

        child_cq.gal_type[quench_index] = 'quiescent'  # boom quenched 

        # assign quenching e-folds for quenching galaxies
        child_cq.tau[quench_index] = get_quenching_efold(
                child_cq.parent_mass[quench_index], 
                tau_param = child_cq.tau_prop
                )

        tau_quench = np.log10( np.exp( 
            -(child_cq.t_cosmic - parent_cq.t_cosmic) / child_cq.tau[quench_index]
            )) 

        child_cq.sfr[quench_index] = child_cq.parent_sfr[quench_index] + tau_quench 
        child_cq.ssfr[quench_index] = child_cq.sfr[quench_index] - child_cq.mass[quench_index]

        q_ssfr_mean = util.get_q_ssfr_mean(child_cq.mass[quench_index]) 
        child_cq.q_ssfr[quench_index] = 0.18 * np.random.randn(len(quench_index)) + q_ssfr_mean 
        
    if not quiet: 
        print 'Quenching takes ', time.time() - quenching_start_time 

        print "Child's redshift = ", child_cq.zsnap

    # deal with orphans ------------------------------------------------------------
    if not quiet: 
        orphan_time = time.time()
        print len(child_cq.gal_type[child_cq.gal_type == '']), ' child galaxies are orphans' 
    child_cq = assign_sfr(child_cq, tau_prop = child_cq.tau_prop, quiet=quiet)

    if len(child_cq.gal_type[child_cq.gal_type == '']) != 0:
        print len(child_cq.gal_type[child_cq.gal_type == '']), ' child galaxies are orphans' 
        raise ValueError() 

    if not quiet:
        print 'Orphan care takes ', time.time() - orphan_time

    # deal with galaxies that are being quenched beyond the designated final quenching  
    overquench_time = time.time()
    over_quenched = np.where(child_cq.ssfr < child_cq.q_ssfr)
    child_cq.ssfr[over_quenched] = child_cq.q_ssfr[over_quenched]
    child_cq.tau[over_quenched] = -999.0            # done quenching 
    if not quiet: 
        print 'Overquenching takes ', time.time() - overquench_time

        print 'Evolution for one time step takes ', time.time() - evo_start

        print 'Quiescent Fraction = ', np.float(len(parent_cq.gal_type[parent_cq.gal_type == 'quiescent']))/np.float(len(parent_cq.gal_type)) 

    return child_cq
def test_mass_evol(mass0, t0, tf, 
        delmass0 = 0.1, 
        t_initial = 4.0079, 
        sfrevol_param = [1.0, 1.0],
        sfrevol_prop = {'name': 'notperiodic'}, 
        massevol_prop = {'name': 'integrated', 'type': 'euler', 'f_retain': 0.6, 't_step': 0.025}, 
        ): 
    '''

    Testing integrated mass evolution

    logSFR(z) function is implemented within this module

    '''

    # spline between z and t_cosmic
    z, t = np.loadtxt(Util.snapshottable(), unpack=True, usecols=[2, 3]) 
    z_of_t = interpolate.interp1d(list(reversed(t)), list(reversed(z)), kind='cubic') 
    z0 = z_of_t(t0)
    zf = z_of_t(tf)
    
    # average SFR of SF MS
    logsfr_mstar_z, sig_logsfr_mstar_z = get_param_sfr_mstar_z()
            
    def logsfr_notquenched(logmass, t_input, **kwargs): 

        zi = kwargs['z0']
        mass_i = kwargs['mass0']
        delmass_i = kwargs['deltamass0']

        avglogsfr = logsfr_mstar_z(logmass, zi)
        #print 'SFMS(', mass0[0], ',', str(zi), ') ', avglogsfr[0]
    
        # Contribution from the SF evolution of the SFMS 
        logsfr_sfms = sfr_evol.logsfr_sfms_evol(zi, z_of_t(t_input))
        
        # Contribution from the SF Duty cycle 
        logsfr_sfduty = sfr_evol.logsfr_sfduty_fluct(
                t_initial, 
                t_input, 
                delta_sfr=delmass_i,
                sfrevol_param=sfrevol_param, 
                **sfrevol_prop
                )
        #print logsfr_sfduty

        logsfr_f = avglogsfr + logsfr_sfms + logsfr_sfduty
        #print np.max(logsfr_f - logsfr_mstar_z(logmass, z_of_t(t_input))), np.min(logsfr_f - logsfr_mstar_z(logmass, z_of_t(t_input)))

        return logsfr_f
    
    sfrkwargs = {'z0': z0, 'mass0': mass0, 'deltamass0': delmass0}
    mass_f, sfr_f = mass_evol.integrated(
            massevol_prop['type'], 
            logsfr_notquenched, 
            mass0, 
            t0, 
            tf, 
            f_retain = massevol_prop['f_retain'], 
            delt = massevol_prop['t_step'], 
            **sfrkwargs
            )
    #print sfr_f[:3] 
    #print logsfr_notquenched(mass_f, tf, **sfrkwargs)[:3]
    #print logsfr_mstar_z(mass0, zf)[:3]

    return mass_f, sfr_f
def plot_integrated_mass_evol(mass0, t0, tf, 
        sfrevol_prop = {'name': 'notperiodic'},
        massevol_prop = {'name': 'integrated', 'type': 'euler', 'f_retain': 0.6, 't_step': 0.05},
        title=None, fig_file=None):
    '''
    
    Plot of the integrated mass and SFR evolution as a function of cosmic time 

    '''
    if title is None: 
        raise ValueError 
    delt = (tf-t0)/10.0
    tfs = np.arange(t0+delt, tf+delt, delt)

    z, t = np.loadtxt(Util.snapshottable(), unpack=True, usecols=[2, 3]) 
    z_of_t = interpolate.interp1d(list(reversed(t)), list(reversed(z)), kind='cubic') 
    
    # SF MS 
    logsfr_mstar_z, sig_logsfr_mstar_z = get_param_sfr_mstar_z()

    # figure
    prettyplot()
    pretty_colors = prettycolors()
    fig = plt.figure(1, figsize=(10,12))
    # mass evolution 
    m_sub = fig.add_subplot(211)
    # SFR evolution 
    sub = fig.add_subplot(212)

    delta_masses = np.arange(-0.3, 0.3, 0.05) 
    #delta_masses = [0.0]    # test case 
    for delmass in delta_masses: 
        # SFR evolution parameters (for SF duty cycle)
        sfrevol_param = sfr_evol.get_sfrevol_param(1, np.array([0]), **sfrevol_prop)

        masses = [mass0]
        sfmssfrs = [logsfr_mstar_z(mass0, z_of_t(t0))]
        sfrs = [logsfr_mstar_z(mass0, z_of_t(t0)) + delmass]

        mass_i_1 = mass0
        t_i_1 = t0

        for tf_i in tfs: 

            mass_i, sfr_i = test_mass_evol(
                    mass0, 
                    t0, 
                    tf_i, 
                    delmass0 = delmass,
                    t_initial = t0,
                    sfrevol_param=sfrevol_param, 
                    sfrevol_prop = sfrevol_prop,
                    massevol_prop=massevol_prop
                    )

            masses.append(mass_i)
            sfrs.append(sfr_i)
            sfmssfrs.append(logsfr_mstar_z(mass0, z_of_t(tf_i)))
            
            t_i_1 = tf_i
            mass_i_1 = mass_i
        
        tfs = np.hstack([t0, tfs])
        for i in xrange(len(masses[0])):
            if delmass == delta_masses[0]: 
                m_label = str(mass0[i])
            else: 
                m_label = None
            m_sub.plot(tfs, np.array(masses)[:,i], c=pretty_colors[i], lw=3, alpha=0.5, label=m_label)
        
        for i in xrange(len(masses[0])):
            if delmass == delta_masses[0]: 
                sfr_label = str(mass0[i])
            else: 
                sfr_label = None
            sub.plot(tfs, np.array(sfrs)[:,i], c=pretty_colors[i], lw=2, alpha=0.5, label=sfr_label)
            sub.plot(tfs, np.array(sfmssfrs)[:,i], c='k', lw=2, ls='--')
        
        for tf_i in tfs: 
            sub.vlines(tf_i, -1.0, 2.5, color='k', linewidth=1, linestyle=':')

    m_sub.set_xlim([t0-2.5, tf+0.5])
    m_sub.set_ylim([8.5, 12.5])
    m_sub.set_ylabel(r"$\mathtt{log\;M_*}$", fontsize=20)
    m_sub.set_title(title)

    sub.set_xlim([t0-2.5, tf+0.5])
    sub.set_ylim([-2.0, 2.0])
    sub.set_xlabel(r"$\mathtt{t_{cosmic}}$", fontsize=20)
    sub.set_ylabel(r"$\mathtt{log\;SFR}$", fontsize=20)
    sub.legend(loc='upper left')

    if fig_file is not None: 
        figfile = ''.join([
            'figure/', 
            fig_file
            ])
        fig.savefig(figfile, bbox_inches='tight')
    #plt.show()
    plt.close()
def assign_sfr(
        cenque, 
        sf_prop={'name': 'average'}, 
        fq_prop={'name': 'wetzelsmooth'}, 
        quiet=True, 
        **kwargs
        ):
    """ Assign star-formation properties to CenQue object. 

    The function Goes through mass bins and then classifies unassigned 
    galaxies into quiescent/star-forming based on quiescent fraction 
    function. 
    
    Then SF properties are assigned to the galaxies. For quiescent 
    galaxies the sSFR is drawn from a log normal distribution about 
    some predeterimined mu_sSFR. For star-forming galaxies, SFR is
    sampled from a designated SF-MS model. 
    
    ----------------------------------------------------------------
    Parameters
    ----------------------------------------------------------------
    cenque : CenQue class object 

    ----------------------------------------------------------------
    Notes 
    ----------------------------------------------------------------
    * Re imagine how to set up SFR 

    """

    # time the code 
    start_time = time.time()

    if cenque.mass == None: 
        raise ValueError()

    if cenque.zsnap == None: 
        raise ValueError()
    
    if 'sf_prop' not in cenque.__dict__.keys(): 
        cenque.sf_prop = sf_prop
    else: 
        if cenque.sf_prop != sf_prop: 
            cenque.sf_prop = sf_prop
            warnings.warn("SF properties do not match; Replacing SF_prop")

    if 'fq_prop' not in cenque.__dict__.keys():
        cenque.fq_prop = fq_prop 
    else: 
        if cenque.fq_prop != fq_prop:
            warnings.warn("fQ properties do not match")
    
    mass_bins = cenque.mass_bins
    mass_bin_low  = mass_bins.mass_low
    mass_bin_mid  = mass_bins.mass_mid
    mass_bin_high = mass_bins.mass_high

    # remove galaxies below the minimum and maximum mass and galaxies without children 
    within_massbin_with_child = np.where(
            (cenque.mass > mass_bins.mass_low.min()) & 
            (cenque.mass <= mass_bins.mass_high.max()) & 
            (cenque.child >= 0) 
            ) 

    if (min(cenque.mass) < mass_bins.mass_low.min()) or (max(cenque.mass) > mass_bins.mass_high.max()): 
        cenque.sample_trim(within_massbin_with_child)

    ngal_tot = len(within_massbin_with_child[0])

    for attrib in ['sf_prop', 'fq_prop']:
        if attrib not in cenque.metadata: 
            cenque.metadata.append(attrib)

    for attrib in ['gal_type', 'sfr', 'ssfr']: 
        if attrib not in cenque.data_columns: 
            cenque.data_columns.append(attrib)

    if cenque.gal_type is None:         
        cenque.gal_type = np.array(['' for i in xrange(ngal_tot)], dtype='|S16') 
        cenque.sfr      = np.array([-999. for i in xrange(ngal_tot)]) 
        cenque.ssfr     = np.array([-999. for i in xrange(ngal_tot)]) 
    
    # simplest SFR assignment for starforming galaxies. Use mu_SFR(M*, z)
    # and randomly sampled normal delta_SFR. 
    if sf_prop['name'] == 'average': 
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if 'delta_sfr' not in cenque.__dict__.keys(): 
            cenque.delta_sfr = np.array([-999. for i in xrange(ngal_tot)])
        
        if 'avg_sfr' not in cenque.__dict__.keys(): 
            cenque.avg_sfr = np.array([-999. for i in xrange(ngal_tot)])

        extra_attr = ['avg_sfr', 'delta_sfr']

    elif sf_prop['name'] == 'average_noscatter': 
        sfr_mstar_z, sig_sfr_mstar_z = get_param_sfr_mstar_z()

        if 'delta_sfr' not in cenque.__dict__.keys(): 
            cenque.delta_sfr = np.array([-999. for i in xrange(ngal_tot)])
        
        if 'avg_sfr' not in cenque.__dict__.keys(): 
            cenque.avg_sfr = np.array([-999. for i in xrange(ngal_tot)])

        extra_attr = ['avg_sfr', 'delta_sfr']

    else: 
        raise NotImplementedError() 

    for attrib in extra_attr: 
        if attrib not in cenque.data_columns: 
            cenque.data_columns.append(attrib)

    # f_Q(M_*,mid, z_snapshot) 
    qf_massbin = get_fq(
            mass_bin_mid, 
            cenque.zsnap, 
            lit = fq_prop['name']
            ) 

    massbin_unassigned = [
            np.where(
                (cenque.mass > mass_bin_low[i_m]) &
                (cenque.mass <= mass_bin_high[i_m]) &
                (cenque.gal_type == '')
                )[0]
            for i_m in xrange(mass_bins.nbins)
            ]

    # Ngal(M_mid), Ngal,Q(M_mid) and Ngal,SF(M_mid)
    ngal_massbin = np.array([x.size for x in massbin_unassigned])
    ngal_q_massbin = np.rint(qf_massbin * ngal_massbin.astype(float)).astype(int)
    ngal_sf_massbin = ngal_massbin - ngal_q_massbin

    # fail-safe for ngal_q_massbin
    if len(np.where(ngal_q_massbin > ngal_massbin)[0]) > 0: 
        ngal_q_massbin[np.where(ngal_q_massbin > ngal_massbin)] = ngal_massbin[np.where(ngal_q_massbin > ngal_massbin)]

    for i_m in xrange(mass_bins.nbins):             

        if len(massbin_unassigned[i_m]) == 0: 
            continue

        begin_loop_time = time.time()
        if not quiet: 
            print mass_bin_low[i_m], ' < M < ', mass_bin_high[i_m]
            print 'fQ = ', qf_massbin[i_m], ' Ngal = ', ngal_massbin[i_m]
            print 'Ngal,Q = ', ngal_q_massbin[i_m], ' Ngal,SF = ', ngal_sf_massbin[i_m]

        shuffled_massbin_index = np.arange(ngal_massbin[i_m])
        np.random.seed()
        np.random.shuffle(shuffled_massbin_index)
        i_q_end = ngal_q_massbin[i_m]
        
        # Randomly select ngal_q_massbin quiescent galaxies from the 
        # massbin. Assign them 'quiescent' gal_type and sSFR and SFR 
        # based on a predetermined gaussian distribution about sSFR.
        if ngal_q_massbin[i_m] > 0: 

            q_massbin = shuffled_massbin_index[:i_q_end]
            i_q_massbin = (massbin_unassigned[i_m])[q_massbin]

            cenque.gal_type[i_q_massbin] = 'quiescent'   

            # sample SSFR from log-normal distribution with a preset
            # 0.18 dex scatter centered about some predetermined mean
            mu_q_ssfr = util.get_q_ssfr_mean(
                    cenque.mass[i_q_massbin]
                    ) 
            if len(i_q_massbin) != ngal_q_massbin[i_m]:
                print shuffled_massbin_index
                print q_massbin
                print i_q_massbin
                print i_q_end, ngal_q_massbin[i_m]

            cenque.ssfr[i_q_massbin] = 0.18 * np.random.randn(ngal_q_massbin[i_m]) + mu_q_ssfr 
            cenque.sfr[i_q_massbin]  = cenque.ssfr[i_q_massbin] + cenque.mass[i_q_massbin]
        
        # ngal_sf_massbin starforming galaxies from the massbin. Assign 
        # them 'star-forming' gal_type and sSFR and SFR in some manner
        if ngal_sf_massbin[i_m] > 0: 

            #sf_massbin = shuffled_massbin_index[i_q_end:i_sf_end]
            sf_massbin = shuffled_massbin_index[i_q_end:]
            i_sf_massbin = (massbin_unassigned[i_m])[sf_massbin]
            
            cenque.gal_type[i_sf_massbin] = 'star-forming'
            
            # sample SFR 
            if  sf_prop['name'] == 'average': 

                mu_sf_sfr = sfr_mstar_z(cenque.mass[i_sf_massbin], cenque.zsnap)
                sigma_sf_sfr = sig_sfr_mstar_z(cenque.mass[i_sf_massbin], cenque.zsnap)
                
                cenque.avg_sfr[i_sf_massbin] = mu_sf_sfr
                cenque.delta_sfr[i_sf_massbin] = sigma_sf_sfr * np.random.randn(ngal_sf_massbin[i_m])

                cenque.sfr[i_sf_massbin] = mu_sf_sfr + cenque.delta_sfr[i_sf_massbin]

                if not quiet:
                    print 'Starforming galaxies: '
                    print 'Average(SFR) = ', mu_sf_sfr, ' sigma(SFR) = ', sigma_sf_sfr 

            elif sf_prop['name'] == 'average_noscatter': 
            
                mu_sf_sfr = sfr_mstar_z(cenque.mass[i_sf_massbin], cenque.zsnap)
                sigma_sf_sfr = 0.0
                
                cenque.avg_sfr[i_sf_massbin] = mu_sf_sfr
                cenque.delta_sfr[i_sf_massbin] = sigma_sf_sfr * np.random.randn(ngal_sf_massbin[i_m])

                cenque.sfr[i_sf_massbin] = mu_sf_sfr + cenque.delta_sfr[i_sf_massbin]

                if not quiet:
                    print 'Starforming galaxies: '
                    print 'Average(SFR) = ', mu_sf_sfr, ' sigma(SFR) = ', sigma_sf_sfr 

            else:
                raise NotImplementedError

            cenque.ssfr[i_sf_massbin] = cenque.sfr[i_sf_massbin] - cenque.mass[i_sf_massbin]

    # double check that SF assign didn't fail anywhere
    assign_fail = np.where(
            (cenque.sfr == -999.0) | 
            (cenque.ssfr == -999.0)
            )
    if len(assign_fail[0]) > 0: 
        raise NameError('Function failed!')
    
    if not quiet: 
        print 'Assign SFR function takes', (time.time()-start_time)/60.0, ' minutes'

    if 'evol_from' in cenque.cenque_type: 
        pass
    else: 
        cenque.cenque_type = 'sf_assigned'

    return cenque
Exemple #14
0
def qaplot_parameterized_sfms(): 
    """ QAplot comparison for the parameterized SFMS redshift 
    evolution in comparison to observed SF-MS redshift evolution.

    """
    gc_zmid, gc_slope, gc_yint = get_bestfit_sfms_groupcat()
    
    ec_zmid, ec_slope, ec_yint = get_bestfit_sfms_envcount(
            fid_mass = 10.5
            )

    avg_sfr_sfms, sig_sfr_sfms = get_param_sfr_mstar_z()

    mass_bin = np.arange(9.0, 12.0, 0.25)       # mass bin 

    fig = plt.figure()
    sub = fig.add_subplot(111)
    
    sub.scatter(
            0.03, 
            gc_yint,
            c='k', 
            s=50, 
            label='Observed GroupCatalog'
            )

    sub.scatter(
            ec_zmid, 
            ec_yint, 
            c=prettycolors()[3], 
            label='Observed EnvCount'
            )
        
    sfr_fidmass = np.array([
        avg_sfr_sfms(10.5, zmid) 
        for zmid in np.arange(0.0, 1.0, 0.05)
        ])
    sub.plot(
            np.arange(0.0, 1.0, 0.05),
            sfr_fidmass, 
            c='k', 
            lw=4, 
            ls='--',
            label='Parameterized'
            )
    
    sub.plot(
            np.arange(0.0, 1.0, 0.05),
            sfr_fidmass+0.15, 
            c=prettycolors()[3], 
            lw=4, 
            ls='--'
            )

    sfr_cutoff = np.array([
        sfr_cut(10.5, ec_zmid[i_z]) 
        for i_z in xrange(len(ec_zmid))
        ])
    sub.plot(ec_zmid, sfr_cutoff, c='k', lw=3, ls='--', label='SF/Q Classification')

    sub.set_xlim([0.0, 1.0])
    sub.set_ylim([-1.0, 2.0])
    sub.set_ylabel('SFR(M=10.5,z)', fontsize=20)
    sub.set_xlabel('Redshift (z)', fontsize=20)
    sub.legend(scatterpoints=1, loc='upper left')

    plt.show()