Пример #1
0
def abundanceMatchSnapshot(proxy,
                           scatter,
                           lf,
                           box_size,
                           minmag=-25.,
                           maxmag=10.,
                           debug=False,
                           figname=None):

    af = AbundanceFunction(lf['mag'],
                           lf['phi'],
                           ext_range=(minmag, maxmag),
                           nbin=2000,
                           faint_end_fit_points=6)

    # check the abundance function
    if debug:
        plt.clf()
        plt.semilogy(lf['mag'], lf['phi'])
        x = np.linspace(minmag, maxmag, 101)
        plt.semilogy(x, af(x))
        plt.savefig('abundance_fcn.png')

    # deconvolution and check results (it's a good idea to always check this)
    remainder = af.deconvolute(scatter * LF_SCATTER_MULT, 40)
    x, nd = af.get_number_density_table()

    if debug:
        plt.clf()
        plt.semilogy(x, np.abs(remainder / nd))
        plt.savefig('nd_remainder.png')

    # get number densities of the halo catalog
    nd_halos = calc_number_densities(proxy, box_size)

    # do abundance matching with some scatter
    catalog_sc = af.match(nd_halos, scatter * LF_SCATTER_MULT)

    if debug:
        plt.clf()
        c, e = np.histogram(catalog_sc[~np.isnan(catalog_sc)],
                            bins=np.linspace(minmag, maxmag, 101))
        c = c / box_size**3 / (e[1:] - e[:-1])
        me = (e[:-1] + e[1:]) / 2
        plt.semilogy(me, c)
        plt.semilogy(me, af(me))
        plt.savefig('lf_in_v_out.png')

    return catalog_sc
Пример #2
0
class DeconvolveSHAM(object):
    """
    class to assign stellar mass, or some other primary galaxy property,
    based on the de-convolution SHAM method, based on Yau-Yun Mao's
    implementation of Peter Behroozi's deconvolution package.
    """
    def __init__(self,
                 stellar_mass_function,
                 prim_haloprop='halo_mpeak',
                 prim_galprop='stellar_mass',
                 scatter=0.0,
                 gal_log_prop=True,
                 gal_min_mass=2.0,
                 gal_max_mass=12.5,
                 gal_nbins=200,
                 **kwargs):
        """
        Parameters
        ----------
        stellar_mass_function : callable object

        prim_haloprop : string, optional
            key indicating halo property used to assign the primary
            galaxy property

        prim_galprop : string, optional
            key indicating primary galaxy property

        gal_log_prop : boolean, optional
            boolean indicating whther the scatter in the primary
            galaxy property is modelled as a log-normal.

        gal_min_mass, gal_max_mass, gal_nbins: float, float, int
            parameters used to bin and span galaxy abundance function.
            If gal_log_prop is True, these should also be logged,
            and the spacing will be even in log.

        redshift : float
             redshit for which the model is applicable
        """

        if 'redshift' in list(kwargs.keys()):
            self.redshift = kwargs['redshift']
        else:
            self.redshift = 0.0

        self.prim_haloprop = prim_haloprop
        self.prim_galprop = prim_galprop
        self._galprop_dtypes_to_allocate = np.dtype([(str(self.prim_galprop), 'f4')])
        self._mock_generation_calling_sequence = ['inherit_halocat_properties', 'assign_stellar_mass']
        self.list_of_haloprops_needed = [prim_haloprop]

        # set default box size.
        if 'Lbox' in kwargs.keys():
            self._Lbox = kwargs['Lbox']
        else:
            self._Lbox = np.inf
        # update Lbox if a halo catalog object is passed.
        self._additional_kwargs_dict = dict(inherit_halocat_properties=['Lbox'])

        # store model parametrs
        self.gal_log_prop = gal_log_prop
        self.param_dict = ({'scatter': scatter})
        self.gal_min_mass = gal_min_mass
        self.gal_max_mass = gal_max_mass
        self.gal_nbins = gal_nbins

        # deconvolve abundance function
        self._stellar_mass_function = stellar_mass_function
        self.deconvolve_scatter(self.param_dict['scatter'])

    def inherit_halocat_properties(self, seed=None, **kwargs):
        """
        Inherit the box size during mock population
        """
        try:
            Lbox = kwargs['Lbox']
            self._Lbox = Lbox
        except KeyError:
            print("Error automatically detecting Lbox.")

    def deconvolve_scatter(self, scatter):
        """
        """
        # tabulate stellar mass function
        if self.gal_log_prop is True:
            msample = np.logspace(self.gal_min_mass, self.gal_max_mass, self.gal_nbins)
            nsample = self._stellar_mass_function(msample)
            self.af = AbundanceFunction(np.log10(msample), nsample, faint_end_first=True)
        else:
            msample = np.linspace(self.gal_min_mass, self.gal_max_mass, self.gal_nbins)
            nsample = self._stellar_mass_function(msample)
            self.af = AbundanceFunction(msample, nsample, faint_end_first=True)

        remainder = self.af.deconvolute(scatter, 100)
        return remainder

    def assign_stellar_mass(self,  **kwargs):
        """
        assign stellar mass
        """

        if 'table' in kwargs.keys():
            table = kwargs['table']
            try:
                Lbox = kwargs['Lbox']
            except KeyError:
                Lbox = self._Lbox
        else:
            try:
                Lbox = kwargs['Lbox']
            except KeyError:
                Lbox = self._Lbox

        Lbox = np.atleast_1d(Lbox)
        if len(Lbox) == 3:
            Lbox = (np.prod(Lbox))**(1.0/3.0)
        else:
            Lbox = Lbox[0]

        nd_halos = calc_number_densities(table[self.prim_haloprop], Lbox)
        mstar = self.af.match(nd_halos, self.param_dict['scatter'])

        if self.gal_log_prop is True:
            mstar = 10.0**mstar
            table[self.prim_galprop] = mstar
        else:
            table[self.prim_galprop] = mstar

        if 'table' in kwargs.keys():
            return table
        else:
            return mstar
Пример #3
0
def generate_wp(lf_list,
                halos,
                af_criteria,
                r_p_data,
                box_size,
                mag_cuts,
                pimax=40.0,
                nthreads=1,
                scatters=None,
                deconv_repeat=20,
                verbose=False):
    """	Generate the projected 2D correlation by abundance matching galaxies
		Parameters:
			lf_list: A list of luminosity functions for each mag_cut. The first 
				column is the magnitudes and thesecond column is the density in 
				units of 1/Mpc^3.
			halos: A catalog of the halos in the n-body sim that can be indexed
				into using the quantity name.
			af_criteria: The galaxy property (i.e. vpeak) to use for abundance 
				matching.
			r_p_data: The positions at which to calculate the 2D correlation
				function.
			box_size: The size of the box (box length not volume)
			mag_cuts: The magnitude cuts for w_p(r_p) (must be a list)
			pimax: The maximum redshift seperation to use in w_p(r_p) calculation
			nthreads: The number of threads to use for CorrFunc
			scatters: The scatters to deconvolve / re-introduce in the am (must
				be a list)
			deconv_repeat: The number of deconvolution steps to conduct
			verbose: If set to true, will generate plots for visual inspection
				of am outputs.
		Returns:
			w_p(r_p) at the r_p values specified by r_p_data.
	"""
    # Repeat once for each magnitude cut
    wp_binneds = []
    for mag_cut_i in range(len(mag_cuts)):
        mag_cut = mag_cuts[mag_cut_i]
        lf = lf_list[mag_cut_i]

        # Initialize abundance function and calculate the number density of the
        # halos in the box
        af = AbundanceFunction(lf[:, 0], lf[:, 1], (-25, -5))
        nd_halos = calc_number_densities(halos[af_criteria], box_size)
        if scatters is not None:
            remainders = []
            for scatter in scatters:
                remainders.append(
                    af.deconvolute(scatter * LF_SCATTER_MULT, deconv_repeat))

        # If verbose output the match between abundance function and input data
        if verbose:
            matplotlib.rcParams.update({'font.size': 18})
            plt.figure(figsize=(10, 8))
            plt.plot(lf[:, 0], lf[:, 1], lw=7, c=custom_blues[1])
            x = np.linspace(np.min(lf[:, 0]) - 2, np.max(lf[:, 0]) + 2, 101)
            plt.semilogy(x, af(x), lw=3, c=custom_blues[4])
            plt.xlim([np.max(lf[:, 0]) + 2, np.min(lf[:, 0])])
            plt.ylim([1e-5, 1])
            plt.xlabel('Magnitude (M - 5 log h)')
            plt.ylabel('Number Density (1/ (Mpc^3 h))')
            plt.legend(['Input', 'Fit'])
            plt.title('Luminosity Function')
            plt.yscale('log')
            plt.show()

        # Plot remainder to ensure the deconvolution returned reasonable results
        if verbose and scatters is not None:
            f, ax = plt.subplots(2,
                                 1,
                                 sharex='col',
                                 sharey='row',
                                 figsize=(15, 12),
                                 gridspec_kw={'height_ratios': [2, 1]})

            x, nd = af.get_number_density_table()
            ax[0].plot(x, nd, lw=3, c=custom_blues[4])
            legend = []
            for scatter in scatters:
                ax[0].plot(af._x_deconv[float(scatter * LF_SCATTER_MULT)],
                           nd,
                           lw=3,
                           c=custom_blues_complement[2 * len(legend)])
                legend.append('Scatter = %.2f' % (scatter))
            ax[0].set_xlim([np.max(lf[:, 0]) + 2, np.min(lf[:, 0])])
            ax[0].set_ylim([1e-5, 1])
            ax[0].set_ylabel('Number Density (1/ (Mpc^3 h))')
            ax[0].legend(['Fit'] + legend)
            ax[0].set_title('Deconvolved Luminosity Function')
            ax[0].set_yscale('log')
            ax[1].set_xlabel('Magnitude (M - 5 log h)')
            ax[1].set_ylabel('(LF (deconv $\Rightarrow$ conv) - LF) / LF')
            ax[1].set_xlim([np.max(lf[:, 0]) + 2, np.min(lf[:, 0])])
            y_max = 0
            for r_i in range(len(remainders)):
                remainder = remainders[r_i] / nd
                ax[1].plot(x,
                           remainder,
                           lw=3,
                           c=custom_blues_complement[2 * r_i])
                y_max = max(y_max, np.max(remainder[x > np.min(lf[:, 0])]))
            ax[1].set_ylim([-1.2, y_max * 1.2])
            plt.show()

        # Conduct the abundance matching
        catalogs = []
        if scatters is not None:
            for scatter in scatters:
                catalogs.append(
                    af.match(nd_halos,
                             scatter * LF_SCATTER_MULT,
                             do_rematch=False))
        else:
            catalogs = [af.match(nd_halos)]

        wp_scatts = []
        for catalog in catalogs:
            # A luminosity cutoff to use for the correlation function.
            sub_catalog = catalog < mag_cut
            print('Scatter %.2f catalog has %d galaxies' %
                  (scatters[len(wp_scatts)], np.sum(sub_catalog)))
            x = halos['px'][sub_catalog]
            y = halos['py'][sub_catalog]
            z = halos['pz'][sub_catalog]

            # Generate rbins so that the average falls at r_p_data
            rbins = np.zeros(len(r_p_data) + 1)
            rbins[1:-1] = 0.5 * (r_p_data[:-1] + r_p_data[1:])
            rbins[0] = 2 * r_p_data[0] - rbins[1]
            rbins[-1] = 2 * r_p_data[-1] - rbins[-2]

            # Calculate the projected correlation function
            wp_results = wp(box_size,
                            pimax,
                            nthreads,
                            rbins,
                            x,
                            y,
                            z,
                            verbose=False,
                            output_rpavg=True)

            # Extract the results
            wp_binned = np.zeros(len(wp_results))
            for i in range(len(wp_results)):
                wp_binned[i] = wp_results[i][3]
            wp_scatts.append(wp_binned)
        wp_binneds.append(wp_scatts)

    return wp_binneds