Example #1
0
    def sSFR_peng(self, logMs, z, *ssfr_params):  #PENG sSFR
        z_temp = np.minimum(z, 2)
        #z_temp = z
        t = cosmo.lookback_time(9999).value - cosmo.lookback_time(
            z_temp).value  ##
        Ms = np.power(10, logMs)
        beta = -0

        ssfr = 2.5e-9 * (Ms / (10e10))**(beta) * (t / 3.5)**(-2.2)

        return ssfr  ## per year
Example #2
0
def sSFR_speagle(logMs, z):
    z_temp     = np.minimum(z,6)
    logMs_temp = np.maximum(logMs, 8.5) 
    
    t   = cosmo.lookback_time(9999).value - cosmo.lookback_time(z_temp).value  ##  WARNING:: TRY cosmo.age(z).value instead!!
    x_1 = 0.840
    x_2 = 0.026
    x_3 = 6.510
    x_4 = 0.110
    
    logSFR = (x_1 - x_2*t) * logMs_temp - (x_3 - x_4*t)
    ssfr   = np.power(10, logSFR) / np.power(10,logMs_temp)
    return  ssfr ## peryear
    def gen_field_analytic(self, p):
        self.logMStar_setup = np.arange(self.logM_min, 12, 0.01)

        phi_init_sf = self.schechter_SMF_func(self.logMStar_setup)
        phi_init_q = np.zeros(len(phi_init_sf))

        t_init = cosmo.lookback_time(self.z_init).value  #gyr
        t_final = cosmo.lookback_time(self.z_final).value  #gyr

        t = t_init
        z = self.z_init

        phi_sf = [phi_init_sf]
        phi_q = [phi_init_q]
        z_range = [z]

        integ_an = integration_utils(self.DE_2, hmax=0.1, hmin=1e-5,
                                     htol=1e-9)  #_an == analytic
        condition = True  # Always run at least once
        force = False

        while t >= t_final and condition:
            inits = np.array([phi_init_sf, phi_init_q], copy=True)
            output = integ_an.RK45(p,
                                   inits,
                                   t,
                                   force,
                                   mpp=False,
                                   analytic=True)
            phi_init_sf, phi_init_q = output[0, :], output[1, :]

            phi_sf.append(np.copy(phi_init_sf))
            phi_q.append(np.copy(phi_init_q))

            if (t - integ_an.step) > t_final:
                pass
            else:
                integ_an.step = t - t_final
                force = True
                condition = False

            print(t, integ_an.step)

            t -= integ_an.step
            z = z_at_value(cosmo.age, (cosmo.age(0).value - t) * u.Gyr,
                           zmin=-1e-6)

            z_range.append(z)

        self.phi_sf_interp_an = interp2d(self.logMStar_setup, z_range, phi_sf)
        self.phi_q_interp_an = interp2d(self.logMStar_setup, z_range, phi_q)
Example #4
0
    def setup_evolve(self):
        t_init = cosmo.lookback_time(self.z_init).value  #gyr
        self.t_final = cosmo.lookback_time(self.z_final).value  #gyr

        self.t = t_init
        self.z = self.z_init

        # self.integ     = integration_utils(self.DE, hmax=0.1, hmin=1e-2, htol=1e0)
        self.condition = True  # Always run at least once
        # self.force     = False

        self.hmass = np.ma.power(10, np.array(self.hmass_init,
                                              copy=True))  #halo mass
        self.gmass = np.ma.zeros(self.hmass.shape)  #gas mass
        self.smass = np.ma.zeros(self.hmass.shape)  #stellar mass
Example #5
0
def plot_redshift_ax(ax,
                     z=[0.05, 0.5, 1, 2, 3],
                     cosmology=None,
                     method='time'):
    """Add twin axis for redshift to plots versus time

    Args:
        ax (object): Matplotlib axes object
        z (list, optional): List of redshifts. Defaults to [0.05, 0.5, 1, 2, 3].
        cosmology (object, optional): Astropy cosmology object. Defaults to None.
        method (str): Units of x-axis. Defaults to cosmic time [Gyr].
    Returns:
        object: Matplotlib axes object
    """
    if cosmology is None:
        from astropy.cosmology import Planck15 as cosmology

    if method == 'lookback':
        ages = cosmology.lookback_time(z).value
    elif method == 'time':
        ages = cosmology.age(z).value
    elif method == 'log':
        ages = np.log10(1 + np.asarray(z))
    else:
        raise NotImplementedError

    ax2 = ax.twiny()
    l, r = ax.get_xlim()
    ax2.set_xlim(l, r)
    ax2.set_xticks(ages)
    ax2.set_xticklabels(z)
    return ax2
    def setup_evolve(self):
        t_init = cosmo.lookback_time(self.z_init).value  #gyr
        self.t_final = cosmo.lookback_time(self.z_final).value  #gyr

        self.t = t_init
        self.z = self.z_init

        self.integ = integration_utils(self.DE, hmax=1, hmin=1e-5, htol=1e1)
        self.condition = True  # Always run at least once
        self.force = False

        self.mass_array = np.ma.power(10, np.array(self.sf_masses, copy=True))

        self.ssfr_params = self.gen_ssfr_params(len(self.sf_masses))

        self.phi_sf_interp = self.schechter_SMF_func
    def update_death_date(self, mass_array, ssfr_params):
        tt = time()

        N = mass_array.shape[0]
        n = self.death_date.shape[0]

        dn = int(N - n)

        if dn == 0:
            death_date = self.death_date
        else:
            death_date = np.ma.zeros(N)
            death_date[0:n] = self.death_date[:]

            infall_times = cosmo.lookback_time(self.infall_z[n:N]).value
            delay_times = self.t_delay([
                mass_array[n:N], ssfr_params[:, n:N], self.infall_Mh[n:N],
                self.infall_z[n:N]
            ])
            #delay_times     = pool.map( self.t_delay, ([ms,mh,z] for (ms,mh,z) in zip(mass_array[n:N], self.infall_Mh[n:N], self.infall_z[n:N])))
            death_date[n:N] = infall_times - delay_times

        not_masked = np.logical_not(mass_array.mask)

        if len(mass_array[not_masked]) == 0:
            pass
        else:
            #print(mass_array[not_masked], len(mass_array[not_masked]))

            infall_times = cosmo.lookback_time(self.infall_z[not_masked]).value
            delay_times = self.t_delay([
                mass_array[not_masked], ssfr_params[:, not_masked],
                self.infall_Mh[not_masked], self.infall_z[not_masked]
            ])

            #delay_times = pool.map( self.t_delay, ([ms,mh,z] for (ms,mh,z) in zip(mass_array[not_masked], self.infall_Mh[not_masked], self.infall_z[not_masked])))

            death_date[not_masked] = infall_times - delay_times

        self.death_date = death_date

        print('update death date: {}'.format(time() - tt))
Example #8
0
def local_rate(model,
               zmin,
               zmax,
               cosmic=False,
               cbc_type=None,
               zmerge_min=0,
               zmerge_max=0.1,
               N_zbins=100):
    """
    Calculates the local merger rate, i.e. mergers that occur between zmerge_min and zmerge_max
    """
    if zmin == 0:
        # account for log-spaced bins
        zmin = 1e-3
    zbins = np.logspace(np.log10(zmin), np.log10(zmax), N_zbins + 1)
    zbin_contribution = []

    # work down from highest zbin
    for zbin_low, zbin_high in tqdm(zip(zbins[::-1][1:], zbins[::-1][:-1]),
                                    total=len(zbins) - 1):
        # get local mergers per unit mass
        floc = fmerge_at_z(model,
                           zbin_low,
                           zbin_high,
                           cosmic,
                           cbc_type,
                           zmerge_min=zmerge_min,
                           zmerge_max=zmerge_max)
        # get redshift at middle of the log-spaced zbin
        midz = 10**(np.log10(zbin_low) +
                    (np.log10(zbin_high) - np.log10(zbin_low)) / 2.0)
        # get SFR at this redshift
        sfr = sfr_z(midz) * u.M_sun * u.Mpc**(-3) * u.yr**(-1)
        # cosmological factor
        E_z = (cosmo._Onu0 * (1 + midz)**4 + cosmo._Om0 * (1 + midz)**3 +
               cosmo._Ok0 * (1 + midz)**2 + cosmo._Ode0)**(1. / 2)
        # add the contribution from this zbin to the sum
        zbin_contribution.append(
            ((sfr * floc / ((1 + midz) * E_z)) * (zbin_high - zbin_low)).value)

    # reintroduce units to the list
    zbin_contribution = np.asarray(zbin_contribution) * u.Mpc**-3 * u.yr**-1
    # get the total contribution for all zbins and local rate
    zbin_summation = np.sum(zbin_contribution).to(u.Gpc**-3 * u.yr**-1)
    R_local = ((1.0 / (cosmo._H0 * cosmo.lookback_time(zmerge_max))) *
               zbin_summation).to(u.Gpc**-3 * u.yr**-1)

    # get the midpoints of the bins to return
    midz = 10**(np.log10(zbins[:-1]) +
                (np.log10(zbins[1:]) - np.log10(zbins[:-1])) / 2.0)

    return R_local, zbin_contribution, midz
    def sSFR_speagle(self, logMs, z, ssfr_params):
        z_temp = np.minimum(z, 6)
        logMs_temp = np.maximum(logMs, 8.5)

        t = cosmo.lookback_time(9999).value - cosmo.lookback_time(
            z_temp).value  ##  WARNING:: TRY cosmo.age(z).value instead!!

        try:
            x_1 = ssfr_params[0, :]
            x_2 = ssfr_params[1, :]
            x_3 = ssfr_params[2, :]
            x_4 = ssfr_params[3, :]
        except:
            x_1 = ssfr_params[0]
            x_2 = ssfr_params[1]
            x_3 = ssfr_params[2]
            x_4 = ssfr_params[3]

        logSFR = (x_1 - x_2 * t) * logMs_temp - (x_3 - x_4 * t)
        ssfr = np.power(10, logSFR) / np.power(10, logMs_temp)

        return ssfr  ## peryear
    def func_delta_N_sf_final(self, item):
        z, delays, j = item
        logMs = np.log10(self.M_star(np.power(10, self.logMHalo_eff), z))
        phi_sf = self.phi_sf_z_10_interp(logMs, z)
        phi_q = self.phi_q_z_10_interp(logMs, z)

        t_end = cosmo.lookback_time(self.z_0).value

        for i in range(0, len(logMs)):
            m = logMs[i]
            td = delays[i]
            dt = 0.5  #Gyr
            t = cosmo.lookback_time(z).value
            t_init = np.copy(t)
            end_condition = True
            while t > np.maximum(t_end, t_init - td) and end_condition:
                #print(t)
                dn_b = self.dN_blue(m, z, phi_sf[i]) * phi_sf[i] * dt
                dn_r = self.dN_red(m, z, phi_sf[i], phi_q[i]) * phi_sf[i] * dt

                #print(dn_b,phi_sf[i])

                phi_sf[i] += dn_b
                phi_q[i] += dn_r

                if t - dt <= np.maximum(t_end, t_init - td):
                    dt = t - np.maximum(t_end, t_init - td)
                    end_condition = False

                t -= dt

            if t_end <= t_init - td:
                phi_q[i] += phi_sf[i]
                phi_sf[i] = 0

        return [phi_sf, phi_q]
    def update_ssfr_params(self):
        try:
            delta_t = self.t_old - self.t
        except:
            self.t_old = cosmo.lookback_time(self.z_init).value
            delta_t = self.t_old - self.t

        print(delta_t)

        if delta_t >= self.ssfr_update_time_interval:  #Gyr
            n = len(self.sf_masses)
            self.ssfr_params = self.gen_ssfr_params(n)

            m = len(self.cluster_masses)
            self.cluster_ssfr_p = self.gen_ssfr_params(m)

            self.t_old = self.t
            print('*new ssfr params*')
        else:
            pass
    def grow_cluster(self):
        new_progenitor_mass = np.power(10, self.M_main(self.z))
        mass_increase = new_progenitor_mass - self.progenitor_mass
        A_norm = mass_increase / self.A_denom(self.z) * self.n_cluster

        self.progenitor_mass = new_progenitor_mass

        temp_mass_array = np.ma.copy(
            self.mass_array)  # identify integration range
        temp_mass_array.mask = np.ma.nomask
        Ms_min = np.ma.min(temp_mass_array)
        Ms_max = np.ma.max(temp_mass_array)
        temp_mass_array = None

        phi_sf_at_z = lambda x: self.phi_sf_interp(np.log10(x))
        N = A_norm * quad(phi_sf_at_z, Ms_min, Ms_max, epsrel=1e-2)[0]
        N_floor = int(np.floor(N))
        N_rest = N - N_floor

        if N_floor != 0:
            ii = np.random.randint(low=0,
                                   high=len(self.mass_array),
                                   size=N_floor)

        if np.random.uniform(low=0.0, high=1.0, size=1) <= N_rest:
            iii = np.random.randint(low=0, high=len(self.mass_array), size=1)
            N = int(N_floor + 1)
        else:
            N = int(N_floor)

        print(self.t, self.integ.step, A_norm, N)

        if N == 0:
            pass
        else:
            if self.cluster_masses is None:
                if N_floor > 0:

                    m = len(self.ssfr_params[:, 0])

                    self.cluster_masses = np.ma.zeros(N)
                    self.cluster_ssfr_p = np.ma.zeros([m, N])
                    self.cluster_masses[0:N_floor] = np.ma.copy(
                        self.mass_array[ii])
                    self.cluster_ssfr_p[:, 0:N_floor] = np.ma.copy(
                        self.ssfr_params[:, ii])

                if N == (N_floor + 1) and N_floor > 0:
                    self.cluster_masses[-1] = np.ma.copy(self.mass_array[iii])
                    self.cluster_ssfr_p[:, -1] = np.ma.copy(
                        self.ssfr_params[:, iii]).flatten()
                elif N == (N_floor + 1):
                    self.cluster_masses = np.ma.copy(self.mass_array[iii])
                    self.cluster_ssfr_p = np.ma.copy(
                        self.ssfr_params[:, iii]).flatten()

                self.infall_z = np.ma.zeros(N) + self.z
                self.infall_Ms = np.ma.copy(self.cluster_masses)
                self.infall_Mh = self.find_M_halo(self.infall_Ms,
                                                  self.z)  ##### self.z
                #self.infall_Mh                    = self.p.map(self.find_M_halo, ([ms,self.z] for ms in self.infall_Ms))

                if self.oc_flag and N != 0:
                    td = np.ma.array(
                        self.t_delay([
                            self.cluster_masses, self.cluster_ssfr_p,
                            self.infall_Mh, self.z
                        ]))
                    self.death_date = cosmo.lookback_time(self.z).value - td

                self.mass_history.append(self.cluster_masses)

            else:
                n = len(self.cluster_masses)
                m = len(self.ssfr_params[:, 0])

                new_arr_mass = np.ma.zeros(n + N)
                new_arr_ssfr_p = np.ma.zeros([m, n + N])
                new_arr_z = np.ma.zeros(n + N)
                new_arr_Ms = np.ma.zeros(n + N)
                new_arr_Mh = np.ma.zeros(n + N)

                new_arr_flag_MQ = np.ma.zeros(n + N)

                new_arr_mass[0:n] = self.cluster_masses[:]
                new_arr_ssfr_p[:, 0:n] = self.cluster_ssfr_p[:, :]
                new_arr_z[0:n] = self.infall_z[:]
                new_arr_Ms[0:n] = self.infall_Ms[:]
                new_arr_Mh[0:n] = self.infall_Mh[:]
                new_arr_flag_MQ[0:n] = self.MQ_flags[:]

                if N_floor > 0:
                    new_arr_mass[n:n + N_floor] = np.ma.copy(
                        self.mass_array[ii])
                    new_arr_ssfr_p[:, n:n + N_floor] = np.ma.reshape(
                        self.ssfr_params[:, ii], (m, -1))  #, copy=True)

                if N == (N_floor + 1):
                    new_arr_mass[-1] = np.ma.copy(self.mass_array[iii])
                    new_arr_ssfr_p[:, -1] = np.ma.copy(
                        self.ssfr_params[:, iii]).flatten()

                if self.oc_flag:
                    new_arr_flag_OC = np.ma.zeros(n + N)
                    new_arr_flag_OC[0:n] = self.OC_flags[:]
                    self.OC_flags = new_arr_flag_OC

                new_arr_z[n:n + N] = np.ma.zeros(N) + self.z
                new_arr_Ms[n:n + N] = np.ma.copy(new_arr_mass[n:n + N])
                new_arr_Mh[n:n + N] = self.find_M_halo(new_arr_mass[n:n + N],
                                                       self.z)  ###self.z
                #new_arr_Mh[n:n+N]              = p.map(self.find_M_halo, ([ms,self.z] for ms in new_arr_mass[n:n+N]))

                self.cluster_masses = new_arr_mass
                self.cluster_ssfr_p = new_arr_ssfr_p
                self.infall_z = new_arr_z
                self.infall_Ms = new_arr_Ms
                self.infall_Mh = new_arr_Mh

                self.MQ_flags = new_arr_flag_MQ

                self.mass_history.append(self.cluster_masses)
    def gen_cluster(self):
        '''
        Generates the cluster. Samples N galaxies from the star forming galaxy array
        '''
        self.logM0 = self.cluster_M
        self.z_0 = self.z_final

        self.MQ_flags = []
        self.OC_flags = []

        self.progenitor_mass = np.power(10, self.M_main(self.z_init))

        A_norm = self.progenitor_mass / self.A_denom(
            self.z_init) * self.n_cluster

        temp_mass_array = np.ma.copy(self.mass_array)
        temp_mass_array.mask = np.ma.nomask

        Ms_min = np.ma.min(temp_mass_array)
        Ms_max = np.ma.max(temp_mass_array)

        phi_sf_at_z = lambda x: self.phi_sf_interp(np.log10(x))
        N = A_norm * quad(phi_sf_at_z, Ms_min, Ms_max, epsrel=1e-2)[0]
        N_floor = int(np.floor(N))
        N_rest = N - N_floor

        if N_floor != 0:
            ii = np.random.randint(low=0,
                                   high=len(self.mass_array),
                                   size=N_floor)

        if np.random.uniform(low=0.0, high=1.0, size=1) <= N_rest:
            iii = np.random.randint(low=0, high=len(self.mass_array), size=1)
            N = int(N_floor + 1)
        else:
            N = int(N_floor)

        if N == 0:
            self.cluster_masses = None
            self.cluster_ssfr_p = None
            self.infall_Ms = None
            self.infall_Mh = None
            self.infall_z = None

        else:

            m = len(self.ssfr_params[:, 0])

            if N_floor > 0:
                self.cluster_masses = np.ma.zeros(N)
                self.cluster_ssfr_p = np.ma.zeros([m, N])
                self.cluster_masses[0:N_floor] = np.ma.copy(
                    self.mass_array[ii])
                self.cluster_ssfr_p[:, 0:N_floor] = np.ma.copy(
                    self.ssfr_params[:, ii])

            if N == (N_floor + 1) and N_floor > 0:
                self.cluster_masses[-1] = np.ma.copy(self.mass_array[iii])
                self.cluster_ssfr_p[:, -1] = np.ma.copy(
                    self.ssfr_params[:, iii]).flatten()
            elif N == (N_floor + 1) and N_floor == 0:
                self.cluster_masses = np.ma.copy(self.mass_array[iii])
                self.cluster_ssfr_p = np.ma.copy(
                    self.ssfr_params[:, iii]).flatten()

            self.infall_Ms = np.ma.copy(self.cluster_masses)
            self.infall_Mh = self.find_M_halo(self.infall_Ms,
                                              self.z_init)  ###### z_init

            self.infall_z = np.ma.zeros(N) + self.z_init

            self.mass_history.append(self.cluster_masses)

        if self.oc_flag and N != 0:
            td = np.ma.array(
                self.t_delay([
                    self.cluster_masses, self.cluster_ssfr_p, self.infall_Mh,
                    self.z_init
                ]))
            self.death_date = cosmo.lookback_time(self.z_init).value - td
    def history_tracks(self, model):
        n = len(model.mass_history)
        m = len(model.mass_history[-1])

        number_of_lines = 10000
        prob_threshold = number_of_lines / m

        tt = cosmo.lookback_time(np.unique(model.infall_z))

        mass_history = np.ma.zeros([n, m])
        for i, mass_arr in enumerate(model.mass_history):
            mass_history[i, 0:int(mass_arr.shape[0])] = mass_arr[:]

        mass_history = np.ma.log10(mass_history[::-1, :])

        fig, ax = plt.subplots()

        count_mq = 0
        count_oc = 0
        count_sf = 0

        print('Expected total: {}'.format(number_of_lines))

        for i in range(0, m):

            p = np.random.uniform()

            if p < prob_threshold:

                ax.plot(tt, mass_history[:, i], color='k', alpha=0.01)

                # if model.oc_flag:
                #     if OC_flags[i]:
                #         ax.plot(tt, mass_history[:,i], color='C1', alpha=0.01)

                # if MQ_flags[i] == 0:
                #     #ax.plot(tt, mass_history[:,i], color='b', alpha=0.01)
                #     pass
                # else:
                #     ax.plot(tt, mass_history[:,i], color='r', alpha=0.01)
                #     pass

                # final_masses = mass_history[mass_history[:,i].mask == False, i]

                # try:
                #     if final_masses[0] > 8.9 and final_masses[0] < 9.1:
                #         temp = True
                #         if model.oc_flag:
                #             if OC_flags[i]:
                #                 ax.plot(tt, mass_history[:,i], color='purple', alpha=0.5)
                #                 count_oc += 1
                #                 temp = False

                #         if MQ_flags[i] == 0 and temp:
                #             ax.plot(tt, mass_history[:,i], color='C0', alpha=0.5)
                #             count_sf += 1
                #         elif temp:
                #             ax.plot(tt, mass_history[:,i], color='r', alpha=0.5)
                #             count_mq += 1
                #             pass
                # except:
                #     pass

                # final_masses = mass_history[mass_history[:,i].mask == False, i]

                # try:  #some galaxies infall quenched. those will fail this step
                #     if final_masses[0] > 8.9 and final_masses[0] < 9.1:
                #         ax.plot(tt, mass_history[:,i], color='C0', alpha=0.1)
                # except:
                #     pass

        print('Mass Quenched: {}'.format(count_mq))
        print('Over Consumed: {}'.format(count_oc))
        print('Star Forming: {}'.format(count_sf))

        ax.set_xlabel('Lookback Time [Gyr]')
        ax.set_ylabel('Stellar Mass [log($M_*/M_\odot$)]')
        fig.savefig('./images/history_path.png', dpi=220)
Example #15
0
def fmerge_at_z(model,
                zbin_low,
                zbin_high,
                cosmic=False,
                cbc_type=None,
                zmerge_min=0,
                zmerge_max=0.1):
    """
    Calculates the number of mergers of a particular CBC type per unit mass
    N_cor,i = f_bin f_IMF N_merger,i / Mtot,sim

    `model` should be a dict containing multiple models at different metallicities

    Each model will receive a weight based on its metallicity, and the metallicity
    distribution at that particular redshift

    In COSMIC, Mtot,sim already accounts for f_bin and f_IMF
    """

    f_merge = []
    met_weights = []

    for met in sorted(model.keys()):

        mass_stars = model[met]['mass_stars']
        if cosmic:
            bpp = model[met][cbc_type]
            # get delay times for all merging binaries (merger happens at evol_type=6)
            merger = bpp.loc[bpp['evol_type'] == 6]
        else:
            merger = model[met]['mergers']

        # get the fraction of systems born between [zlow,zhigh] that merger between [zmerge_min,zmerge_max]
        if zbin_low == 0:
            # special treatment for the first bin in the local universe
            tdelay_min = 0
            tdelay_max = cosmo.lookback_time(zbin_high).to(u.Myr).value
        else:
            tdelay_min = (cosmo.lookback_time(zbin_low) -
                          cosmo.lookback_time(zmerge_max)).to(u.Myr).value
            tdelay_max = (cosmo.lookback_time(zbin_high) -
                          cosmo.lookback_time(zmerge_min)).to(u.Myr).value

        if cosmic:
            Nmerge_zbin = len(merger.loc[(merger['tphys'] <= tdelay_max)
                                         & (merger['tphys'] > tdelay_min)])
        else:
            Nmerge_zbin = len(merger.loc[(merger['t_delay'] <= tdelay_max)
                                         & (merger['t_delay'] > tdelay_min)])

        # get the number of mergers per unit mass
        f_merge.append(float(Nmerge_zbin) / mass_stars)

        # get redshift in the middle of this log-spaced interval
        midz = 10**(np.log10(zbin_low) +
                    (np.log10(zbin_high) - np.log10(zbin_low)) / 2.0)

        # append the relative weight of this metallicity at this particular redshift
        met_weights.append(metal_disp_z(midz, met))

    # normalize metallicity weights so that they sum to unity
    met_weights = np.asarray(met_weights) / np.sum(met_weights)

    # return weighted sum of f_merge, units of Msun**-1
    return np.sum(np.asarray(f_merge) * met_weights) * u.Msun**(-1)
    def gen_cluster(self, z_0, z_max, logM0, eta, show_plots):
        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
        print('Generating cluster with :')
        print('z_0 = {}; logM0 = {}; eta = {}'.format(z_0, logM0, eta))

        delta_z = 0.05
        self.eta = eta
        self.z_0 = z_0
        self.logM0 = logM0
        self.z_range = np.arange(self.z_0, z_max, delta_z)
        pool = mp.Pool(processes=3)

        self.delta_m = 0.05

        self.logMStar_setup = np.arange(3, 12, 0.1)
        self.logMHalo_bins = np.arange(self.M_min, self.M_max, self.delta_m)
        self.logMHalo_eff = np.array([
            (self.logMHalo_bins[i] + self.logMHalo_bins[i + 1]) / 2
            for i in range(0,
                           len(self.logMHalo_bins) - 1)
        ])

        self.logMStar_bins = np.array([
            np.log10(self.M_star(np.power(10, self.logMHalo_bins), z))
            for z in self.z_range
        ])
        self.logMStar_eff = np.array([[
            (self.logMStar_bins[i, j] + self.logMStar_bins[i, j + 1]) / 2
            for j in range(0,
                           len(self.logMHalo_bins) - 1)
        ] for i, z in enumerate(self.z_range)])

        self.logMStar_low = np.array([m for m in self.logMStar_bins[:, :-1]])
        self.logMStar_upp = np.array([m for m in self.logMStar_bins[:, 1:]])

        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        phi_init_sf = self.phi_sf_3(self.logMStar_setup)
        phi_init_q = np.zeros(len(phi_init_sf))

        phi_sf_z_10 = []
        phi_q_z_10 = []
        z_eff = []
        for i in range(1, len(self.z_range)):
            z = self.z_range[-i]
            z_eff.append((z + self.z_range[-i - 1]) / 2)
            dt = cosmo.lookback_time(z).value - cosmo.lookback_time(
                self.z_range[-i - 1]).value

            dn_blue = self.dN_blue(self.logMStar_setup, z, phi_init_sf) * dt
            dn_red = self.dN_red(self.logMStar_setup, z, phi_init_sf,
                                 phi_init_q) * dt

            phi_init_sf += dn_blue
            phi_init_q += dn_red

            phi_sf_z_10.append(np.copy(phi_init_sf))
            phi_q_z_10.append(np.copy(phi_init_q))

        z_midp = np.array(z_eff)
        self.phi_sf_z_10_interp = interp2d(self.logMStar_setup,
                                           z_midp[z_midp <= z_max],
                                           phi_sf_z_10)
        self.phi_q_z_10_interp = interp2d(self.logMStar_setup,
                                          z_midp[z_midp <= z_max], phi_q_z_10)

        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        phi_init_sf = self.phi_sf_3(self.logMStar_setup)
        phi_init_q = np.zeros(len(phi_init_sf))

        phi_sf_z_4 = []
        phi_q_z_4 = []
        for i in range(1, len(self.z_range[self.z_range <= 10 + delta_z / 2])):
            z = self.z_range[-i]
            dt = cosmo.lookback_time(z).value - cosmo.lookback_time(
                self.z_range[-i - 1]).value

            dn_blue = self.dN_blue(self.logMStar_setup, z, phi_init_sf) * dt
            dn_red = self.dN_red(self.logMStar_setup, z, phi_init_sf,
                                 phi_init_q) * dt

            phi_init_sf += dn_blue
            phi_init_q += dn_red

            phi_sf_z_4.append(np.copy(phi_init_sf))
            phi_q_z_4.append(np.copy(phi_init_q))

        self.phi_sf_z_4_interp = interp2d(self.logMStar_setup,
                                          z_midp[z_midp <= 10], phi_sf_z_4)
        self.phi_q_z_4_interp = interp2d(self.logMStar_setup,
                                         z_midp[z_midp <= 10], phi_q_z_4)

        Halo_masses = np.array(pool.map(self.M_main,
                                        (z for z in self.z_range)))
        delta_halos = [
            np.log10(
                np.power(10, Halo_masses[i]) -
                np.power(10, Halo_masses[i + 1]))
            for i in range(0,
                           len(self.z_range) - 1)
        ]
        delta_halos.append(Halo_masses[-1])
        delta_halos = np.array(delta_halos)

        self.A = np.power(10, delta_halos) / np.array(
            pool.map(self.func_A_normal, (z for z in self.z_range)))

        self.delta_N_sf_infall = np.array(
            pool.map(self.func_delta_N_sf,
                     ([z, i] for i, z in enumerate(self.z_range))))
        self.delta_N_q_infall = np.array(
            pool.map(self.func_delta_N_q,
                     ([z, i] for i, z in enumerate(self.z_range))))
        self.delta_N_a_infall = self.delta_N_q_infall + self.delta_N_sf_infall

        self.delta_td = np.array(
            pool.map(self.func_delta_td, (m for m in self.logMHalo_bins))).T

        out = np.array(
            pool.map(self.func_delta_N_sf_final,
                     ([z, self.delta_td[i, :], i]
                      for i, z in enumerate(self.z_range))))
        self.delta_N_sf_final, self.delta_N_q_final = out[:, 0, :], out[:,
                                                                        1, :]
        self.delta_N_a_final = self.delta_N_sf_final + self.delta_N_q_final

        logMs_final = np.arange(8, 12, 0.1)

        N_sf_per_mass = self.group_by_mass(self.delta_N_sf_final, logMs_final)
        N_q_per_mass = self.group_by_mass(self.delta_N_q_final, logMs_final)
        N_a_per_mass = N_sf_per_mass + N_q_per_mass

        N_field_q_per_mass = self.phi_q_z_4_interp(logMs_final, self.z_0)
        N_field_a_per_mass = self.phi_q_z_4_interp(
            logMs_final, self.z_0) + self.phi_sf_z_4_interp(
                logMs_final, self.z_0)

        pool.close()

        if show_plots:
            ### final stellar masses of galaxies
            #fig,ax = plt.subplots()
            #contourf_ = plt.contourf(self.z_range, self.logMHalo_bins, self.logMStar_bins.T)
            #ax.set_xlabel('redshift')
            #ax.set_ylabel('halo mass')
            #ax.set_title('Stellar Mass')
            #cbar = fig.colorbar(contourf_)

            ### verification that first derivative is okay!
            #fig,ax = plt.subplots()
            #ax.semilogy(self.logMHalo_bins, self.M_star(np.power(10,self.logMHalo_bins), z=0.35), 'k')
            #ax2 = ax.twinx()
            #ax2.plot(self.logMHalo_bins, self.dMs_dMh(np.power(10,self.logMHalo_bins),z=0.35), linestyle='--')
            #ax.set_ylabel('Stellar Mass [log($M_*/M_\odot$)]')
            #ax.set_xlabel('log Halo Mass')
            #ax2.set_ylabel('$dM_{*}/dMh$')

            ## simple plot of phi
            fig, ax = plt.subplots()
            muzz_q = self.phi_q_2(logMs_final, z=1.2)
            muzz_sf = self.phi_sf_2(logMs_final, z=1.2)
            peng_f = self.phi_q_z_4_interp(logMs_final, 1.2)
            peng_f_sf = self.phi_sf_z_4_interp(logMs_final, 1.2)
            #peng_c = self.phi_q_z_10_interp(logMs_final, 1.2)
            #ax.semilogy(logMs_final, self.phi_sf_2(logMs_final, z=1.2), label='Muzz, SF', color='b')
            ax.semilogy(logMs_final, muzz_sf, label='Muzz, SF', color='C0')
            ax.semilogy(logMs_final, muzz_q, label='Muzz, Q', color='r')
            #ax.semilogy(logMs_final, self.phi_sf_z_4_interp(logMs_final, 1.2)*1.5e2, label='Peng, SF', color='b', linestyle='--')
            ax.semilogy(logMs_final,
                        peng_f * np.max(muzz_q) / np.max(peng_f),
                        label='Peng, Q',
                        color='r',
                        linestyle='--')
            ax.semilogy(logMs_final,
                        peng_f_sf * np.max(muzz_q) / np.max(peng_f),
                        label='Peng, SF',
                        color='C0',
                        linestyle='--')
            #ax.semilogy(logMs_final, peng_c * np.max(muzz_q)/ np.max(peng_c), label='Peng cls, Q', color='r', alpha=0.3)
            ax.set_xlabel('Stellar Mass [log($M_*/M_\odot$)]')
            ax.set_ylabel('$\Phi_{field}$ [z=1.2]')
            ax.set_xlim([8.4, 12])
            ax.set_ylim([1e-6, 1e-2])
            ax.legend()

            ### Contour plot of delay times vs halo mass and redshift
            #fig,ax    = plt.subplots()
            #contourf_ = ax.contourf(self.z_range, self.logMHalo_bins, self.delta_td.T, np.arange(0,14,2), extend='both', cmap=cm.seismic_r)
            #ax.set_xlabel('Redshift [z]')
            #ax.set_ylabel('Halo Mass [log($M_h$/$M_\odot$)]')
            #ax.set_title('$t_{delay}$ [Gyr]')
            #cbar      = fig.colorbar(contourf_)

            ### Contour plot of all galaxies vs halo mass and redshift at INFALL
            #fig,ax    = plt.subplots()
            #contourf_ = ax.contourf(self.z_range, self.logMHalo_eff, np.log10(self.delta_N_a_infall.T))#, np.arange(-15,16,3), extend='both', cmap=cm.seismic_r)
            #ax.set_xlabel('Redshift [z]')
            #ax.set_ylabel('Halo Mass [log($M_h$/$M_\odot$)]')
            #ax.set_title('Delta N [Infall]')
            #cbar      = fig.colorbar(contourf_)

            ### Contour plot of star forming galaxies vs halo mass and redshift
            #fig,ax    = plt.subplots()
            #contourf_ = ax.contourf(self.z_range, self.logMHalo_eff, np.log10(self.delta_N_sf_final.T))#, np.arange(-15,16,3), extend='both', cmap=cm.seismic_r)
            #ax.set_xlabel('Redshift [z]')
            #ax.set_ylabel('Halo Mass [log($M_h$/$M_\odot$)]')
            #ax.set_title('Delta N [SF]')
            #cbar      = fig.colorbar(contourf_)

            ### Contour plot of quiescent vs stellar mass and redshift
            #fig,ax    = plt.subplots()
            #contourf_ = ax.contourf(self.z_range, self.logMHalo_eff, np.log10(self.delta_N_q_final.T))#, np.arange(-15,16,3), extend='both', cmap=cm.seismic_r)
            #ax.set_xlabel('Redshift [z]')
            #ax.set_ylabel('Halo Mass [log($M_h$/$M_\odot$)]')
            #ax.set_title('Delta N [Q]')
            #cbar      = fig.colorbar(contourf_)

            ### Plot of peng sSFR
            #fig,ax    = plt.subplots()
            #ax.plot(self.z_range, self.SSFR(np.array(10),self.z_range))
            #ax.set_xlabel('Redshift [z]')
            #ax.set_ylabel('sSFR yr$^{-1}$')
            #ax.set_title('[Peng+2010]')
            #plt.show()

            ### Plot of Quenched Fraction per mass
            #fig,ax = plt.subplots()#figsize=(5,4), tight_layout=True, sharey=True)
            #ax.plot(logMs_final, N_q_per_mass/N_a_per_mass, label='Cluster')
            #ax.plot(logMs_final, N_field_q_per_mass/N_field_a_per_mass, label='Field')
            #ax.set_xlabel('Stellar Mass [log($M_*$/$M_\odot$)]')
            #ax.set_ylabel('Quenched Fraction')

            #ax.set_xlim([9,12])
            #ax.set_ylim([0,1])

            #ax.legend(bbox_to_anchor=(1,0.9))

            ### Time slice of delay times
            #fig,ax    = plt.subplots()

            #ii   = 20
            #temp = cosmo.lookback_time(self.z_range[ii]).value - cosmo.lookback_time(self.z_0).value

            #ax.plot(self.logMStar_bins[ii,:], self.delta_td[ii,:])
            #ax.plot([8,12], [temp,temp])
            #ax.set_xlabel('Stellar Mass [$M_*$]')
            #ax.set_ylabel('Delay Times [Gyr]')
            #ax.set_title('z = {:.1f}'.format(self.z_range[ii]))
            #ax.set_xlim([8,12])
            #ax.set_ylim([0,12])
            #plt.show()

            plt.show()
            plt.close('all')

        #FIX TDELAY.....

        return (logMs_final, N_q_per_mass, N_a_per_mass, N_field_q_per_mass,
                N_field_a_per_mass)
Example #17
0
        ## CASE 1: system merges
        ## assign lookback time w/ randomly sampled redshift from weighted distribution
        ## alive/disrupted systems have merge_index = -1
        if (merger_type != -1):

            ## check if BBH in COSMIC
            if (merger_type == 1414): this_BBH = True

            remnant_mass_k1 = bpp['mass0_1'].iloc[merge_index]
            remnant_mass_k2 = bpp['mass0_2'].iloc[merge_index]

            delay_time = bpp['tphys'].iloc[merge_index]
            z_merge = z_at_value(cosmo.lookback_time, delay_time * u.Myr)

            lookback_time = cosmo.lookback_time(z_f).to(u.Myr).value

            if (delay_time <= lookback_time):

                merge_by_z0 = True
                p_det = calc_detection_prob(
                    remnant_mass_k1, remnant_mass_k2,
                    z_merge)  ## detection probability for this merger
                if (this_BBH): this_BBHm = True

            else: merge_by_z0 = False

            remnant_mass_k1 = bpp['mass0_1'].iloc[merge_index]
            remnant_mass_k2 = bpp['mass0_2'].iloc[merge_index]

        ## CASE 2: system does not merge
Example #18
0
m15_init_idx = min(enumerate(np.abs(beh['col2'] - 15)),
                   key=itemgetter(1))[0]  # find halo mass 10^15 Msun for SFH3
m13_init_idx = min(enumerate(np.abs(beh['col2'] - 13)),
                   key=itemgetter(1))[0]  # find halo mass 10^13 Msun for SFH4
m11_init_idx = min(
    enumerate(np.abs(beh['col2'] - 11.4)),
    key=itemgetter(1))[0]  # find halo mass 10^11.4 Msun for SFH5

m15_idx = [beh['col2'] == beh['col2'][m15_init_idx]]
m13_idx = [beh['col2'] == beh['col2'][m13_init_idx]]
m11_idx = [beh['col2'] == beh['col2'][m11_init_idx]]

nz = np.sum(m15_idx)
zs = beh['col1'][m15_idx] - 1
dts = np.zeros(nz - 1)
lbt = Cosmo.lookback_time(beh['col1'][m15_idx] - 1)
for i in range(0, nz - 1):
    dts[i] = lbt[i + 1].value - lbt[i].value

Zevol_record = np.zeros((len(Zevol_coeff), nz, len(Zs)))
################ M weighted Z calculation  #######################
for k in range(0, 3):  # for each SFH
    if k == 0:
        sfr = 10**beh['col3'][m15_idx]
    elif k == 1:
        sfr = 10**beh['col3'][m13_idx]
    else:
        sfr = 10**beh['col3'][m11_idx]
    for i in range(0, nz - 1):  # for each z
        nomi = np.zeros(len(Zs))  # Z * dz * SFR
        denomi = 0  # dz * SFR
    def delay_times(self, model):
        z_init = model.z_init
        z_final = model.z_final
        z_range = np.arange(z_final, z_init, 0.1)

        logMh_range = np.arange(7, 15, 0.1)
        Mh_range = np.power(10, logMh_range)

        xx = []
        xx_2 = []
        yy = []
        #zz   = []

        for z in z_range:
            xx.append(np.zeros(len(Mh_range)) + z)
            xx_2.append(np.zeros(len(Mh_range)) + cosmo.lookback_time(z).value)
            yy.append(np.log10(model.M_star(Mh_range, z)))
            #zz.append(cosmo.lookback_time(z).value - model.t_delay_2(Mh_range, z))

        xx = np.array(xx).flatten()
        xx_2 = np.array(xx_2).flatten()
        yy = np.array(yy).flatten()
        #zz   = np.array(zz).flatten()

        fig, ax = plt.subplots(tight_layout=True)
        #contourf_ = ax.tricontourf(xx,yy,zz, np.arange(0,13,0.1), extend='both')

        ax.scatter(model.infall_z_Q, model.final_mass_cluster_Q, s=0.1, c='r')
        ax.scatter(model.infall_z_SF,
                   model.final_mass_cluster_SF,
                   s=0.1,
                   c='b')

        ax.set_xlabel('Redshift [z]')
        ax.set_ylabel('Stellar Mass [log($M_*$/$M_\odot$)]')
        #ax.set_ylim([8,12])
        #cbar      = fig.colorbar(contourf_, label='Quenched due to OC')
        fig.savefig('./images/cluster_final_m_z.png', dpi=220)

        fig, ax = plt.subplots(tight_layout=True)
        #contourf_ = ax.tricontourf(xx_2,yy,zz, np.arange(0,13,0.1), extend='both')
        try:
            ax.scatter(cosmo.lookback_time(model.infall_z_Q).value,
                       model.final_mass_cluster_Q,
                       s=0.1,
                       c='r')
        except:
            pass

        try:
            ax.scatter(cosmo.lookback_time(model.infall_z_SF).value,
                       model.final_mass_cluster_SF,
                       s=0.1,
                       c='b')
        except:
            pass

        ax.set_xlabel('Lookback Time [Gyr]')
        ax.set_ylabel('Stellar Mass [log($M_*$/$M_\odot$)]')
        #ax.set_ylim([8,12])
        #cbar      = fig.colorbar(contourf_, label='Quenched due to OC')
        fig.savefig('./images/cluster_final_m.png', dpi=220)

        fig, ax = plt.subplots(tight_layout=True)
        #contourf_ = ax.tricontourf(xx_2,yy,zz, np.arange(0,13,0.1), extend='both')

        temp_z = np.ma.copy(model.infall_z)
        temp_z.mask = np.ma.nomask
        temp_m = np.ma.copy(model.infall_Ms)
        temp_m.mask = np.ma.nomask
        temp_m = np.ma.log10(temp_m)

        ax.scatter(cosmo.lookback_time(temp_z).value, temp_m, s=0.1, c='r')
        ax.set_xlabel('Lookback Time [Gyr]')
        ax.set_ylabel('Stellar Mass [log($M_*$/$M_\odot$)]')
        #ax.set_ylim([8,12])
        #cbar      = fig.colorbar(contourf_, label='Quenched due to OC')
        fig.savefig('./images/cluster_infall_m.png', dpi=220)