Esempio n. 1
0
    def _set_percentile_splitting(self, split=0.5, **kwargs):
        """
        Method interprets the arguments passed to the constructor
        and sets up the interpolation scheme for how halos will be
        divided into two types as a function of the primary halo property.
        """

        if 'splitting_model' in kwargs:
            self.splitting_model = kwargs['splitting_model']
            func = getattr(self.splitting_model, kwargs['splitting_method_name'])
            if isinstance(func, collections.Callable):
                self._input_split_func = func
            else:
                raise HalotoolsError("Input ``splitting_model`` must have a callable function "
                    "named ``%s``" % kwargs['splitting_method_name'])
        elif 'split_abscissa' in list(kwargs.keys()):
            if custom_len(kwargs['split_abscissa']) != custom_len(split):
                raise HalotoolsError("``split`` and ``split_abscissa`` must have the same length")
            self._split_abscissa = kwargs['split_abscissa']
            self._split_ordinates = split
        else:
            try:
                self._split_abscissa = [2]
                self._split_ordinates = [split]
            except KeyError:
                msg = ("The _set_percentile_splitting method must at least be called with a ``split``"
                    "keyword argument, or alternatively ``split`` and ``split_abscissa`` arguments.")
                raise HalotoolsError(msg)
Esempio n. 2
0
def compute_conditional_shuffled_ranks(indices_of_prim_haloprop_bin,
                                       sec_haloprop, correlation_coeff,
                                       **kwargs):
    '''
    TODO Docs
    '''
    if sec_haloprop is None:
        msg = (
            "\n``sec_haloprop`` must be passed into compute_conditional_shuffled_ranks, or a table"
            "with ``sec_haloprop_key`` as a column.\n")
        raise HalotoolsError(msg)

    try:
        assert np.all(
            np.logical_and(-1 <= correlation_coeff, correlation_coeff <= 1))
    except AssertionError:
        msg = (
            "\n``correlation_coeff`` must be passed into compute_conditional_percentiles,"
            "and must be between -1 and 1\n")
        raise HalotoolsError(msg)

    num_in_bin = len(indices_of_prim_haloprop_bin)
    original_ranks = rankdata(sec_haloprop[indices_of_prim_haloprop_bin],
                              'ordinal') - 0.5
    original_ranks /= num_in_bin

    return noisy_percentile(original_ranks,
                            correlation_coeff=correlation_coeff)
def _process_args(sample1, sample2, period, Nsub):
    """
    utility function to process common function arguments
    """

    # check to make sure Nsub is reasonable
    Nsub = np.atleast_1d(Nsub)
    if len(Nsub) == 1:
        Nsub = np.array([Nsub[0]] * 3)
    try:
        assert np.all(Nsub < np.inf)
        assert np.all(Nsub > 0)
    except AssertionError:
        msg = ("`Nsub` must be a bounded positive number in all dimensions.")
        raise HalotoolsError(msg)

    # check to see if we are using periodic boundary conditions
    if period is None:
        PBCs = False
    else:
        PBCs = True

    # determine minimum box size the data occupies.
    if PBCs is False:
        sample1, sample2, randoms, Lbox = _enclose_in_box(sample1, sample2)
    else:
        Lbox = period

    j_index_1, N_sub_vol = cuboid_subvolume_labels(sample1, Nsub, Lbox)
    j_index_2, N_sub_vol = cuboid_subvolume_labels(sample2, Nsub, Lbox)

    return sample1, sample2, j_index_1, j_index_2, Nsub, N_sub_vol, Lbox, PBCs
Esempio n. 4
0
    def _initialize_assembias_param_dict(self, assembias_strength=0.5, assembias_slope=1.0, **kwargs):
        r"""
        For full documentation, see the Heaviside Assembias Declaration in Halotools.

        This function calls the superclass's version.
        Then, it adds the parameters from disp_func to the dict as well.

        Parameters
        ----------
        assembias_strength : float, optional
            Strength of assembias. Default is 1.0 for maximum strength

        assembias_slope : float, optional
            Effective slopes of disp_func.
            Can be an iterator of float. Uses the same abscissa as assembias_strength
        """
        super(ContinuousAssembias, self)._initialize_assembias_param_dict(
                assembias_strength=assembias_strength, **kwargs)
        #  Accept float or iterable
        slope = assembias_slope
        try:
            iterator = iter(slope)
            slope = list(slope)
        except TypeError:
            slope = [slope]

        # assert it has the proper length
        if custom_len(self._assembias_strength_abscissa) != custom_len(slope):
            raise HalotoolsError("``assembias_strength`` and ``assembias_slope`` "
                                 "must have the same length")

        for ipar, val in enumerate(slope):
            self.param_dict[self._get_continuous_assembias_param_dict_key(ipar)] = val
Esempio n. 5
0
    def _initialize_assembias_param_dict(self, assembias_strength=0.5, **kwargs):
        """
        """
        if not hasattr(self, 'param_dict'):
            self.param_dict = {}

        # Make sure the code behaves properly whether or not we were passed an iterable
        strength = assembias_strength
        try:
            iterator = iter(strength)
            strength = list(strength)
        except TypeError:
            strength = [strength]

        if 'assembias_strength_abscissa' in kwargs:
            abscissa = kwargs['assembias_strength_abscissa']
            try:
                iterator = iter(abscissa)
                abscissa = list(abscissa)
            except TypeError:
                abscissa = [abscissa]
        else:
            abscissa = [2]

        if custom_len(abscissa) != custom_len(strength):
            raise HalotoolsError("``assembias_strength`` and ``assembias_strength_abscissa`` "
                "must have the same length")

        self._assembias_strength_abscissa = abscissa
        for ipar, val in enumerate(strength):
            self.param_dict[self._get_assembias_param_dict_key(ipar)] = val
Esempio n. 6
0
def compute_prim_haloprop_bins(dlog10_prim_haloprop=0.05, **kwargs):
    """
    Parameters
    ----------
    prim_haloprop : array
        Array storing the value of the primary halo property column of the ``table``
        passed to ``compute_conditional_percentiles``.
    prim_haloprop_bin_boundaries : array, optional
        Array defining the boundaries by which we will bin the input ``table``.
        Default is None, in which case the binning will be automatically determined using
        the ``dlog10_prim_haloprop`` keyword.
    dlog10_prim_haloprop : float, optional
        Logarithmic spacing of bins of the mass-like variable within which
        we will assign secondary property percentiles. Default is 0.05.
    Returns
    --------
    output : array
        Numpy array of integers storing the bin index of the prim_haloprop bin
        to which each halo in the input table was assigned.
    """
    try:
        prim_haloprop = kwargs['prim_haloprop']
    except KeyError:
        msg = ("The ``compute_prim_haloprop_bins`` method "
               "requires the ``prim_haloprop`` keyword argument")
        raise HalotoolsError(msg)

    try:
        prim_haloprop_bin_boundaries = kwargs['prim_haloprop_bin_boundaries']
    except KeyError:
        lg10_min_prim_haloprop = np.log10(np.min(prim_haloprop)) - 0.001
        lg10_max_prim_haloprop = np.log10(np.max(prim_haloprop)) + 0.001
        num_prim_haloprop_bins = (
            lg10_max_prim_haloprop -
            lg10_min_prim_haloprop) / dlog10_prim_haloprop
        prim_haloprop_bin_boundaries = np.logspace(
            lg10_min_prim_haloprop,
            lg10_max_prim_haloprop,
            num=ceil(num_prim_haloprop_bins))

    # digitize the masses so that we can access them bin-wise
    #print "PHP",np.max(prim_haloprop), prim_haloprop_bin_boundaries[-1]
    output = np.digitize(prim_haloprop, prim_haloprop_bin_boundaries)

    # Use the largest bin for any points larger than the largest bin boundary,
    # and raise a warning if such points are found
    Nbins = len(prim_haloprop_bin_boundaries)
    if Nbins in output:
        msg = (
            "\n\nThe ``compute_prim_haloprop_bins`` function detected points in the \n"
            "input array of primary halo property that were larger than the largest value\n"
            "of the input ``prim_haloprop_bin_boundaries``. All such points will be assigned\n"
            "to the largest bin.\nBe sure that this is the behavior you expect for your application.\n\n"
        )
        warn(msg)
        output = np.where(output == Nbins, Nbins - 1, output)

    return output
Esempio n. 7
0
    def _set_percentile_splitting(self, split=0.5, **kwargs):
        """
        Interpret constructor arguments and set up interpolation scheme

        In this subclass, add "split" as a free parameter, similar to assembias.
        """
        if not hasattr(self, 'param_dict'):
            self.param_dict = {}

        if 'splitting_model' in kwargs:
            #self.splitting_model = kwargs['splitting_model']
            #func = getattr(self.splitting_model, kwargs['splitting_method_name'])
            #if isinstance(func, collections.Callable):
            #    self._input_split_func = func
            #else:
            raise HalotoolsError(
                "Input ``splitting_model`` has not yet been implemented for the "
                "FreeSplitAssembias subclass.")

        # Make sure the code behaves properly whether or not we were passed an iterable
        try:
            iterator = iter(split)
            split = list(split)
        except TypeError:
            split = [split]

        if 'assembias_strength_abscissa' in kwargs:
            abscissa = kwargs['assembias_strength_abscissa']
            try:
                iterator = iter(abscissa)
                abscissa = list(abscissa)
            except TypeError:
                abscissa = [abscissa]
        else:
            abscissa = [2]

        if custom_len(abscissa) != custom_len(split):
            raise HalotoolsError(
                "``assembias_strength`` and ``assembias_strength_abscissa`` "
                "must have the same length")

        self._split_abscissa = abscissa
        for ipar, val in enumerate(split):
            self.param_dict[self._get_free_split_assembias_param_dict_key(
                ipar)] = val
Esempio n. 8
0
    def _interpret_constructor_inputs(self, loginterp=True,
            sec_haloprop_key=model_defaults.sec_haloprop_key, **kwargs):
        """
        """
        self._loginterp = loginterp
        self.sec_haloprop_key = sec_haloprop_key

        required_attr_list = ['prim_haloprop_key', 'gal_type']
        for attr in required_attr_list:
            if not hasattr(self, attr):
                msg = ("In order to use the HeavisideAssembias class "
                    "to decorate your model component with assembly bias, \n"
                    "the component instance must have a %s attribute")
                raise HalotoolsError(msg % attr)

        try:
            self._method_name_to_decorate = kwargs['method_name_to_decorate']
        except KeyError:
            msg = ("The constructor to the HeavisideAssembiasComponent class "
                "must be called with the following keyword arguments:\n"
                "``%s``")
            raise HalotoolsError(msg % ('_method_name_to_decorate'))

        try:
            lower_bound = float(kwargs['lower_assembias_bound'])
            lower_bound_key = 'lower_bound_' + self._method_name_to_decorate + '_' + self.gal_type
            setattr(self, lower_bound_key, lower_bound)
            upper_bound = float(kwargs['upper_assembias_bound'])
            upper_bound_key = 'upper_bound_' + self._method_name_to_decorate + '_' + self.gal_type
            setattr(self, upper_bound_key, upper_bound)
        except KeyError:
            msg = ("The constructor to the HeavisideAssembiasComponent class "
                "must be called with the following keyword arguments:\n"
                "``%s``, ``%s``")
            raise HalotoolsError(msg % ('lower_assembias_bound', 'upper_assembias_bound'))

        self._set_percentile_splitting(**kwargs)
        self._initialize_assembias_param_dict(**kwargs)

        if 'halo_type_tuple' in kwargs:
            self.halo_type_tuple = kwargs['halo_type_tuple']
Esempio n. 9
0
    def percentile_splitting_function(self, prim_haloprop):
        """
        Method returns the fraction of halos that are ``type-2``
        as a function of the input primary halo property.

        Parameters
        -----------
        prim_haloprop : array_like
            Array storing the primary halo property.

        Returns
        -------
        split : float
            Fraction of ``type2`` halos at the input primary halo property.
        """

        if hasattr(self, '_input_split_func'):
            result = self._input_split_func(prim_haloprop=prim_haloprop)

            if np.any(result < 0):
                msg = ("The input split_func passed to the HeavisideAssembias class"
                    "must not return negative values")
                raise HalotoolsError(msg)
            if np.any(result > 1):
                msg = ("The input split_func passed to the HeavisideAssembias class"
                    "must not return values exceeding unity")
                raise HalotoolsError(msg)

            return result

        elif self._loginterp is True:
            spline_function = model_helpers.custom_spline(
                np.log10(self._split_abscissa), self._split_ordinates, k=3)
            result = spline_function(np.log10(prim_haloprop))
        else:
            spline_function = model_helpers.custom_spline(
                self._split_abscissa, self._split_ordinates, k=3)
            result = spline_function(prim_haloprop)

        return result
Esempio n. 10
0
    def _galprop_perturbation(self, **kwargs):
        """
        Method determines how much to boost the baseline function
        according to the strength of assembly bias and the min/max
        boost allowable by the requirement that the all-halo baseline
        function be preserved. The returned perturbation applies to type-1 halos.
        """
        lower_bound_key = 'lower_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        baseline_lower_bound = getattr(self, lower_bound_key)
        upper_bound_key = 'upper_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        baseline_upper_bound = getattr(self, upper_bound_key)

        try:
            baseline_result = kwargs['baseline_result']
            prim_haloprop = kwargs['prim_haloprop']
            splitting_result = kwargs['splitting_result']
        except KeyError:
            msg = ("Must call _galprop_perturbation method of the"
                "HeavisideAssembias class with the following keyword arguments:\n"
                "``baseline_result``, ``splitting_result`` and ``prim_haloprop``")
            raise HalotoolsError(msg)

        result = np.zeros(len(prim_haloprop))

        strength = self.assembias_strength(prim_haloprop)
        positive_strength_idx = strength > 0
        negative_strength_idx = strength < 0

        if len(baseline_result[positive_strength_idx]) > 0:
            base_pos = baseline_result[positive_strength_idx]
            split_pos = splitting_result[positive_strength_idx]
            type1_frac_pos = 1 - split_pos
            strength_pos = strength[positive_strength_idx]

            upper_bound1 = baseline_upper_bound - base_pos
            upper_bound2 = ((1 - type1_frac_pos)/type1_frac_pos)*(base_pos - baseline_lower_bound)
            upper_bound = np.minimum(upper_bound1, upper_bound2)
            result[positive_strength_idx] = strength_pos*upper_bound

        if len(baseline_result[negative_strength_idx]) > 0:
            base_neg = baseline_result[negative_strength_idx]
            split_neg = splitting_result[negative_strength_idx]
            type1_frac_neg = 1 - split_neg
            strength_neg = strength[negative_strength_idx]

            lower_bound1 = baseline_lower_bound - base_neg
            lower_bound2 = (1 - type1_frac_neg)/type1_frac_neg*(base_neg - baseline_upper_bound)
            lower_bound = np.maximum(lower_bound1, lower_bound2)
            result[negative_strength_idx] = np.abs(strength_neg)*lower_bound

        return result
Esempio n. 11
0
    def _decorate_baseline_method(self):
        """
        """

        try:
            baseline_method = getattr(self, self._method_name_to_decorate)
            setattr(self, 'baseline_'+self._method_name_to_decorate,
                baseline_method)
            decorated_method = self.assembias_decorator(baseline_method)
            setattr(self, self._method_name_to_decorate, decorated_method)
        except AttributeError:
            msg = ("The baseline model constructor must be called before "
                "calling the HeavisideAssembias constructor, \n"
                "and the baseline model must have a method named ``%s``")
            raise HalotoolsError(msg % self._method_name_to_decorate)
Esempio n. 12
0
    def assembias_mc_occupation(self, seed=None, **kwargs):
        first_occupation_moment_orig = self.mean_occupation_orig(**kwargs)
        first_occupation_moment = self.mean_occupation(**kwargs)
        if self._upper_occupation_bound == 1:
            with NumpyRNGContext(seed):
                score = np.random.rand(
                    custom_len(first_occupation_moment_orig))
            total = np.count_nonzero(first_occupation_moment_orig > score)
            result = np.where(first_occupation_moment > score, 1, 0)
            diff = result.sum() - total
            if diff < 0:
                x = (first_occupation_moment / score)
                result.fill(0)
                result[x.argsort()[-total:]] = 1
            elif diff > 0:
                x = (1.0 - first_occupation_moment) / (1.0 - score)
                result.fill(0)
                result[x.argsort()[:total]] = 1
        elif self._upper_occupation_bound == float("inf"):
            total = self._poisson_distribution(
                first_occupation_moment_orig.sum(), seed=seed)
            if seed is not None:
                seed += 1
            with NumpyRNGContext(seed):
                score = np.random.rand(total)
            score.sort()
            x = first_occupation_moment.cumsum(dtype=np.float64)
            x /= x[-1]
            result = np.ediff1d(np.insert(np.searchsorted(score, x), 0, 0))
        else:
            msg = (
                "\nYou have chosen to set ``_upper_occupation_bound`` to some value \n"
                "besides 1 or infinity. In such cases, you must also \n"
                "write your own ``mc_occupation`` method that overrides the method in the \n"
                "OccupationComponent super-class\n")
            raise HalotoolsError(msg)

        if 'table' in kwargs:
            kwargs['table']['halo_num_' + self.gal_type] = result
        return result
Esempio n. 13
0
        def wrapper(*args, **kwargs):

            #################################################################################
            #  Retrieve the arrays storing prim_haloprop and sec_haloprop
            #  The control flow below is what permits accepting an input
            #  table or a directly inputting prim_haloprop and sec_haloprop arrays

            _HAS_table = False
            if 'table' in kwargs:
                try:
                    table = kwargs['table']
                    prim_haloprop = table[self.prim_haloprop_key]
                    sec_haloprop = table[self.sec_haloprop_key]
                    _HAS_table = True
                except KeyError:
                    msg = ("When passing an input ``table`` to the "
                           " ``assembias_decorator`` method,\n"
                           "the input table must have a column with name ``%s``"
                           "and a column with name ``%s``.\n")
                    raise HalotoolsError(msg % (self.prim_haloprop_key), self.sec_haloprop_key)
            else:
                try:
                    prim_haloprop = np.atleast_1d(kwargs['prim_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                           "``assembias_decorator`` method,\n"
                           "you must pass ``prim_haloprop`` argument.\n")
                    raise HalotoolsError(msg)
                try:
                    sec_haloprop = np.atleast_1d(kwargs['sec_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                           "``assembias_decorator`` method,\n"
                           "you must pass ``sec_haloprop`` argument")
                    raise HalotoolsError(msg)

            #################################################################################

            #  Compute the percentile to split on as a function of the input prim_haloprop
            split = self.percentile_splitting_function(prim_haloprop)

            #  Compute the baseline, undecorated result
            result = func(*args, **kwargs)

            #  We will only decorate values that are not edge cases,
            #  so first compute the mask for non-edge cases
            no_edge_mask = (
                (split > 0) & (split < 1) &
                (result > baseline_lower_bound) & (result < baseline_upper_bound)
            )
            #  Now create convenient references to the non-edge-case sub-arrays
            no_edge_result = result[no_edge_mask]
            no_edge_split = split[no_edge_mask]

            #  Retrieve percentile values (medians) if they've been precomputed. Else, compute them.
            if _HAS_table is True:
                if self.sec_haloprop_key + '_percentile_values' in table.keys():
                    no_edge_percentile_values = table[self.sec_haloprop_key + '_percentile_value'][no_edge_mask]
                else:
                    #  the value of sec_haloprop_percentile will be computed from scratch
                    no_edge_percentile_values = compute_conditional_percentile_values( p=no_edge_split,
                        prim_haloprop=prim_haloprop[no_edge_mask],
                        sec_haloprop=sec_haloprop[no_edge_mask]
                    )
            else:
                try:
                    percentiles = kwargs['sec_haloprop_percentile_values']
                    if custom_len(percentiles) == 1:
                        percentiles = np.zeros(custom_len(prim_haloprop)) + percentiles
                    no_edge_percentile_values = percentiles[no_edge_mask]
                except KeyError:
                    no_edge_percentile_values = compute_conditional_percentile_values(p=no_edge_split,
                        prim_haloprop=prim_haloprop[no_edge_mask],
                        sec_haloprop=sec_haloprop[no_edge_mask]
                    )

            #  NOTE I've removed the type 1 mask as it is not well-defined in this implementation
            #  this has all been rolled into the galprop_perturbation function

            #  normalize by max value away from percentile
            #  This ensures that the "slope" definition and boundaries are universal
            pv_sub_sec_haloprop = sec_haloprop[no_edge_mask] - no_edge_percentile_values

            if prim_haloprop[no_edge_mask].shape[0] == 0:
                perturbation = np.zeros_like(no_edge_result)
            else:
                perturbation = self._galprop_perturbation(
                    prim_haloprop=prim_haloprop[no_edge_mask],
                    sec_haloprop=pv_sub_sec_haloprop/np.max(np.abs(pv_sub_sec_haloprop)),
                    #sec_haloprop = compute_conditional_percentiles(prim_haloprop = prim_haloprop[no_edge_mask], sec_haloprop=sec_haloprop[no_edge_mask])-no_edge_split,
                    baseline_result=no_edge_result)

            no_edge_result += perturbation
            result[no_edge_mask] = no_edge_result

            return result
Esempio n. 14
0
    def __call__(self, *args, **kwargs):
        if 'table' in kwargs:
            table = kwargs['table']
            try:
                prim_haloprop_key = kwargs['prim_haloprop_key']
                prim_haloprop = table[prim_haloprop_key]
            except KeyError:
                msg = (
                    "\nWhen passing an input ``table`` to a ``compute_conditional_*`` method,\n"
                    "you must also pass ``prim_haloprop_key``  keyword arguments\n"
                    "whose values are column keys of the input ``table``\n")
                raise HalotoolsError(msg)
            # Note sec_haloprop is not necessary for all methods.
            try:
                sec_haloprop_key = kwargs['sec_haloprop_key']
                sec_haloprop = table[sec_haloprop_key]
            except KeyError:
                sec_haloprop = None
        else:
            try:
                prim_haloprop = kwargs['prim_haloprop']
            except KeyError:
                msg = (
                    "\nIf not passing an input ``table`` to a ``compute_conditional_*`` method,\n"
                    "you must pass a ``prim_haloprop`` arguments\n")
                raise HalotoolsError(msg)
            try:
                sec_haloprop = kwargs['sec_haloprop']
            except KeyError:
                sec_haloprop = None

        compute_prim_haloprop_bins_dict = {}
        compute_prim_haloprop_bins_dict['prim_haloprop'] = prim_haloprop
        try:
            compute_prim_haloprop_bins_dict['prim_haloprop_bin_boundaries'] = (
                kwargs['prim_haloprop_bin_boundaries'])
        except KeyError:
            pass
        try:
            compute_prim_haloprop_bins_dict['dlog10_prim_haloprop'] = kwargs[
                'dlog10_prim_haloprop']
        except KeyError:
            pass

        # Check if we need to recompute the mass bins, or if it's been memoized
        same_dict = False

        if compute_prim_haloprop_bins_dict.keys(
        ) == self.last_compute_prim_haloprop_bins_dict.keys(
        ):  # same as we were last asked for, don't recompute
            for key, val in compute_prim_haloprop_bins_dict.iteritems():
                last_val = self.last_compute_prim_haloprop_bins_dict[key]
                if hasattr(val, 'shape'):
                    if val.shape != last_val.shape:
                        break
                    # We now know they have the same shape
                    if not np.all(np.equal(val, last_val)):
                        break
                elif val != last_val:
                    break
            else:
                same_dict = True

        if same_dict:
            prim_haloprop_bins = self.last_prim_haloprop_bins
        else:
            prim_haloprop_bins = compute_prim_haloprop_bins(
                **compute_prim_haloprop_bins_dict)
            #update cache
            self.last_compute_prim_haloprop_bins_dict = compute_prim_haloprop_bins_dict
            self.last_prim_haloprop_bins = prim_haloprop_bins

        output = np.zeros_like(prim_haloprop)

        # toss these in here so we don't have to repeat the above!
        fkwargs = kwargs.copy()
        if 'prim_haloprop' not in fkwargs:
            fkwargs['prim_haloprop'] = prim_haloprop
        if 'sec_haloprop' not in fkwargs:
            fkwargs['sec_haloprop'] = sec_haloprop
        # sort on secondary property only with each mass bin
        bins_in_halocat = set(prim_haloprop_bins)

        #idx is usully the same; however, some edge cases make this work better
        for idx, ibin in enumerate(bins_in_halocat):
            indices_of_prim_haloprop_bin = np.where(
                prim_haloprop_bins == ibin)[0]

            output[indices_of_prim_haloprop_bin] = self.func(
                idx=idx,
                ibin=ibin,
                indices_of_prim_haloprop_bin=indices_of_prim_haloprop_bin,
                *args,
                **fkwargs)

        return output
Esempio n. 15
0
def compute_conditional_percentiles(indices_of_prim_haloprop_bin, sec_haloprop,
                                    **kwargs):
    r"""
        In bins of the ``prim_haloprop``, compute the rank-order percentile
        of the input ``table`` based on the value of ``sec_haloprop``.

        Note indices_of_prim_haloprop_bin is passed in from the decorator and does not need to be specified.

        Parameters
        ----------
        table : astropy table, optional
            a keyword argument that stores halo catalog being used to make mock galaxy population
            If a `table` is passed, the `prim_haloprop_key` and `sec_haloprop_key` keys
            must also be passed. If not passing a `table`, you must directly pass the
            `prim_haloprop` and `sec_haloprop` keyword arguments.

        prim_haloprop_key : string, optional
            Name of the column of the input ``table`` that will be used to access the
            primary halo property. `compute_conditional_percentiles` bins the ``table`` by
            ``prim_haloprop_key`` when computing the result.

        sec_haloprop_key : string, optional
            Name of the column of the input ``table`` that will be used to access the
            secondary halo property. `compute_conditional_percentiles` bins the ``table`` by
            ``prim_haloprop_key``, and in each bin uses the value stored in ``sec_haloprop_key``
            to compute the ``prim_haloprop``-conditioned rank-order percentile.

        prim_haloprop : array_like, optional
            Array storing the primary halo property used to bin the input points.
            If a `prim_haloprop` is passed, you must also pass a `sec_haloprop`.

        sec_haloprop : array_like, optional
            Array storing the secondary halo property used to define the conditional percentiles
            in each bin of `prim_haloprop`.

        prim_haloprop_bin_boundaries : array, optional
            Array defining the boundaries by which we will bin the input ``table``.
            Default is None, in which case the binning will be automatically determined using
            the ``dlog10_prim_haloprop`` keyword.

        dlog10_prim_haloprop : float, optional
            Logarithmic spacing of bins of the mass-like variable within which
            we will assign secondary property percentiles. Default is 0.2.

        Examples
        --------
        >>> from halotools.sim_manager import FakeSim
        >>> fakesim = FakeSim()
        >>> result = compute_conditional_percentiles(table = fakesim.halo_table, prim_haloprop_key = 'halo_mvir', sec_haloprop_key = 'halo_vmax')


        Notes
        -----
        The sign of the result is such that in bins of the primary property,
        *smaller* values of the secondary property
        receive *smaller* values of the returned percentile.

        """
    if sec_haloprop is None:
        msg = (
            "\n``sec_haloprop`` must be passed into compute_conditional_percentiles, or a table"
            "with ``sec_haloprop_key`` as a column.\n")
        raise HalotoolsError(msg)
    num_in_bin = len(sec_haloprop[indices_of_prim_haloprop_bin])

    # Find the indices that sort by the secondary property
    ind_sorted = np.argsort(sec_haloprop[indices_of_prim_haloprop_bin])

    percentiles = np.zeros(num_in_bin)
    percentiles[ind_sorted] = (np.arange(num_in_bin) + 1.0) / float(num_in_bin)

    return percentiles
Esempio n. 16
0
def compute_conditional_percentile_values(idx,
                                          indices_of_prim_haloprop_bin,
                                          sec_haloprop,
                                          p=0.5,
                                          **kwargs):
    """
    In bins of the ``prim_haloprop``, compute the percentile given by p of the input
     ``table`` based on the value of ``sec_haloprop``.

    Note indices_of_prim_haloprop_bin is passed in from the decorator and does not need to be specified.

    Parameters
    ----------
    p: float or array
        Percentile to find. Float or array of floats between 0 and 1. Default is 0.5, the median.
    table : astropy table, optional
        a keyword argument that stores halo catalog being used to make mock galaxy population
        If a `table` is passed, the `prim_haloprop_key` and `sec_haloprop_key` keys
        must also be passed. If not passing a `table`, you must directly pass the
        `prim_haloprop` and `sec_haloprop` keyword arguments.
    prim_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        primary halo property. `compute_conditional_percentile_values` bins the ``table`` by
        ``prim_haloprop_key`` when computing the result.
    sec_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        secondary halo property. `compute_conditional_percentile_values` bins the ``table`` by
        ``prim_haloprop_key``, and in each bin uses the value stored in ``sec_haloprop_key``
        to compute the ``prim_haloprop``-conditioned rank-order percentile.
    prim_haloprop : array_like, optional
        Array storing the primary halo property used to bin the input points.
        If a `prim_haloprop` is passed, you must also pass a `sec_haloprop`.
    sec_haloprop : array_like, optional
        Array storing the secondary halo property used to define the conditional percentiles
        in each bin of `prim_haloprop`.
    prim_haloprop_bin_boundaries : array, optional
        Array defining the boundaries by which we will bin the input ``table``.
        Default is None, in which case the binning will be automatically determined using
        the ``dlog10_prim_haloprop`` keyword.
    dlog10_prim_haloprop : float, optional
        Logarithmic spacing of bins of the mass-like variable within which
        we will assign secondary property percentiles. Default is 0.2.
    Examples
    --------
    >>> from halotools.sim_manager import FakeSim
    >>> fakesim = FakeSim()
    >>> result = compute_conditional_percentile_values(table = fakesim.halo_table, prim_haloprop_key = 'halo_mvir', sec_haloprop_key = 'halo_vmax')
    Notes
    -----
    The sign of the result is such that in bins of the primary property,
    *smaller* values of the secondary property
    receive *smaller* values of the returned percentile.
    """
    pp = p if type(p) is float else p[idx - 1]
    try:
        assert 0 <= pp <= 1
    except AssertionError:
        raise HalotoolsError(
            'The value of `p=%0.2f` in ``compute_conditional_percentile_values`` must be between 0 and 1'
            % pp)

    return np.percentile(sec_haloprop[indices_of_prim_haloprop_bin], pp * 100)
Esempio n. 17
0
    def _galprop_perturbation(self, **kwargs):
        r"""
        Method determines hwo much to boost the baseline function
        according to the strength of assembly bias and the min/max
        boost allowable by the requirement that the all-halo baseline
        function be preserved. The returned perturbation applies to all halos.

        Required kwargs are: ``baseline_result``, ``prim_haloprop``, ``sec_haloprop``.

        Note that this is defined where sec_haloprop has had the p-th percentile subtracted
        and is normalized by the maximum value.

        Returns ndarray with dimensions of prim_haloprop detailing the perturbation.
        """

        lower_bound_key = 'lower_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        baseline_lower_bound = getattr(self, lower_bound_key)
        upper_bound_key = 'upper_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        baseline_upper_bound = getattr(self, upper_bound_key)

        try:
            baseline_result = kwargs['baseline_result']
            prim_haloprop = kwargs['prim_haloprop']
            sec_haloprop = kwargs['sec_haloprop']
        except KeyError:
            msg = ("Must call _galprop_perturbation method of the"
                   "HeavisideAssembias class with the following keyword arguments:\n"
                   "``baseline_result``, ``splitting_result`` and ``prim_haloprop``")
            raise HalotoolsError(msg)

        #  evaluate my continuous modification
        strength = self.assembias_strength(prim_haloprop)
        slope = self.assembias_slope(prim_haloprop)

        #  the average displacement acts as a normalization we need.
        max_displacement = self._disp_func(sec_haloprop=sec_haloprop, slope=slope)
        disp_average = compute_conditional_averages(vals=max_displacement,prim_haloprop=prim_haloprop)
        #disp_average = np.ones((prim_haloprop.shape[0], ))*0.5

        result = np.zeros(len(prim_haloprop))

        greater_than_half_avg_idx = disp_average > 0.5
        less_than_half_avg_idx = disp_average <= 0.5

        #print max_displacement
        #print strength, slope

        if len(max_displacement[greater_than_half_avg_idx]) > 0:
            base_pos = baseline_result[greater_than_half_avg_idx]
            strength_pos = strength[greater_than_half_avg_idx]
            avg_pos = disp_average[greater_than_half_avg_idx]

            upper_bound1 = (base_pos - baseline_lower_bound)/avg_pos
            upper_bound2 = (baseline_upper_bound - base_pos)/(1-avg_pos)
            upper_bound = np.minimum(upper_bound1, upper_bound2)
            result[greater_than_half_avg_idx] = strength_pos*upper_bound*(max_displacement[greater_than_half_avg_idx]-avg_pos)

        if len(max_displacement[less_than_half_avg_idx]) > 0:
            base_neg = baseline_result[less_than_half_avg_idx]
            strength_neg = strength[less_than_half_avg_idx]
            avg_neg = disp_average[less_than_half_avg_idx]

            lower_bound1 = (base_neg-baseline_lower_bound)/avg_neg#(1- avg_neg)
            lower_bound2 = (baseline_upper_bound - base_neg)/(1-avg_neg)#avg_neg
            lower_bound = np.minimum(lower_bound1, lower_bound2)
            result[less_than_half_avg_idx] = strength_neg*lower_bound*(max_displacement[less_than_half_avg_idx]-avg_neg)

        return result
Esempio n. 18
0
def compute_conditional_percentile(p=0.5, **kwargs):
    """
    In bins of the ``prim_haloprop``, compute the percentile given by p of the input
     ``table`` based on the value of ``sec_haloprop``.
    Parameters
    ----------
    p: float or array
        Percentile to find. Float or array of floats between 0 and 1. Default is 0.5, the median.
    table : astropy table, optional
        a keyword argument that stores halo catalog being used to make mock galaxy population
        If a `table` is passed, the `prim_haloprop_key` and `sec_haloprop_key` keys
        must also be passed. If not passing a `table`, you must directly pass the
        `prim_haloprop` and `sec_haloprop` keyword arguments.
    prim_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        primary halo property. `compute_conditional_percentiles` bins the ``table`` by
        ``prim_haloprop_key`` when computing the result.
    sec_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        secondary halo property. `compute_conditional_percentiles` bins the ``table`` by
        ``prim_haloprop_key``, and in each bin uses the value stored in ``sec_haloprop_key``
        to compute the ``prim_haloprop``-conditioned rank-order percentile.
    prim_haloprop : array_like, optional
        Array storing the primary halo property used to bin the input points.
        If a `prim_haloprop` is passed, you must also pass a `sec_haloprop`.
    sec_haloprop : array_like, optional
        Array storing the secondary halo property used to define the conditional percentiles
        in each bin of `prim_haloprop`.
    prim_haloprop_bin_boundaries : array, optional
        Array defining the boundaries by which we will bin the input ``table``.
        Default is None, in which case the binning will be automatically determined using
        the ``dlog10_prim_haloprop`` keyword.
    dlog10_prim_haloprop : float, optional
        Logarithmic spacing of bins of the mass-like variable within which
        we will assign secondary property percentiles. Default is 0.2.
    Examples
    --------
    >>> from halotools.sim_manager import FakeSim
    >>> fakesim = FakeSim()
    >>> result = compute_conditional_percentiles(table = fakesim.halo_table, prim_haloprop_key = 'halo_mvir', sec_haloprop_key = 'halo_vmax')
    Notes
    -----
    The sign of the result is such that in bins of the primary property,
    *smaller* values of the secondary property
    receive *smaller* values of the returned percentile.
    """

    try:
        assert np.all(0 < p) and np.all(1 > p)
    except AssertionError:
        raise HalotoolsError("p must be a floating number between 0 and 1. ")

    if 'table' in kwargs:
        table = kwargs['table']
        try:
            prim_haloprop_key = kwargs['prim_haloprop_key']
            prim_haloprop = table[prim_haloprop_key]
            sec_haloprop_key = kwargs['sec_haloprop_key']
            sec_haloprop = table[sec_haloprop_key]
        except KeyError:
            msg = (
                "\nWhen passing an input ``table`` to the ``compute_conditional_percentiles`` method,\n"
                "you must also pass ``prim_haloprop_key`` and ``sec_haloprop_key`` keyword arguments\n"
                "whose values are column keys of the input ``table``\n")
            raise HalotoolsError(msg)
    else:
        try:
            prim_haloprop = kwargs['prim_haloprop']
            sec_haloprop = kwargs['sec_haloprop']
        except KeyError:
            msg = (
                "\nIf not passing an input ``table`` to the ``compute_conditional_percentiles`` method,\n"
                "you must pass a ``prim_haloprop`` and ``sec_haloprop`` arguments\n"
            )
            raise HalotoolsError(msg)

    compute_prim_haloprop_bins_dict = {}
    compute_prim_haloprop_bins_dict['prim_haloprop'] = prim_haloprop
    try:
        compute_prim_haloprop_bins_dict['prim_haloprop_bin_boundaries'] = (
            kwargs['prim_haloprop_bin_boundaries'])
    except KeyError:
        pass
    try:
        compute_prim_haloprop_bins_dict['dlog10_prim_haloprop'] = kwargs[
            'dlog10_prim_haloprop']
    except KeyError:
        pass
    prim_haloprop_bins = compute_prim_haloprop_bins(
        **compute_prim_haloprop_bins_dict)

    output = np.zeros_like(prim_haloprop)

    if type(p) is float:
        p = np.array([p for i in xrange(len(prim_haloprop))])

    # sort on secondary property only with each mass bin
    bins_in_halocat = set(prim_haloprop_bins)
    for ibin, pp in izip(bins_in_halocat, p):
        indices_of_prim_haloprop_bin = np.where(prim_haloprop_bins == ibin)[0]

        num_in_bin = len(sec_haloprop[indices_of_prim_haloprop_bin])

        # Find the indices that sort by the secondary property
        perc = np.percentile(sec_haloprop[indices_of_prim_haloprop_bin],
                             pp * 100)

        # place the percentiles into the catalog
        output[indices_of_prim_haloprop_bin] = perc

    return output
# First check to see if the log has any matching entries before 
# requesting the download 
# This is technically redundant with the functionality in the downloading methods, 
# but this makes it easier to issue the right error message
if args.overwrite == False:

    if download_halos == True:

        gen = downman.halo_table_cache.matching_log_entry_generator
        matching_halocats = list(
            gen(simname = simname, halo_finder = halo_finder, 
                version_name = version_name, redshift = redshift, dz_tol = 0.1))

        if len(matching_halocats) > 0:
            matching_fname = matching_halocats[0].fname
            raise HalotoolsError(existing_fname_error_msg % matching_fname)

    if download_ptcls == True:

        gen2 = downman.ptcl_table_cache.matching_log_entry_generator
        matching_ptcl_cats = list(
            gen2(simname = simname, version_name = ptcl_version_name, 
                redshift = redshift, dz_tol = 0.1))

        if len(matching_ptcl_cats) > 0:
            matching_fname = matching_ptcl_cats[0].fname
            raise HalotoolsError(existing_fname_error_msg % matching_fname)        

##################################################################

##################################################################
Esempio n. 20
0
        def wrapper(*args, **kwargs):

            #################################################################################
            # Retrieve the arrays storing prim_haloprop and sec_haloprop
            # The control flow below is what permits accepting an input
            # table or a directly inputting prim_haloprop and sec_haloprop arrays
            _HAS_table = False
            if 'table' in kwargs:
                try:
                    table = kwargs['table']
                    prim_haloprop = table[self.prim_haloprop_key]
                    sec_haloprop = table[self.sec_haloprop_key]
                    _HAS_table = True
                except KeyError:
                    msg = ("When passing an input ``table`` to the "
                        " ``assembias_decorator`` method,\n"
                        "the input table must have a column with name ``%s``"
                        "and a column with name ``%s``.\n")
                    raise HalotoolsError(msg % (self.prim_haloprop_key), self.sec_haloprop_key)
            else:
                try:
                    prim_haloprop = np.atleast_1d(kwargs['prim_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                        "``assembias_decorator`` method,\n"
                        "you must pass ``prim_haloprop`` argument.\n")
                    raise HalotoolsError(msg)
                try:
                    sec_haloprop = np.atleast_1d(kwargs['sec_haloprop'])
                except KeyError:
                    if 'sec_haloprop_percentile' not in kwargs:
                        msg = ("\nIf not passing an input ``table`` to the "
                            "``assembias_decorator`` method,\n"
                            "you must pass either a ``sec_haloprop`` or "
                            "``sec_haloprop_percentile`` argument.\n")
                        raise HalotoolsError(msg)

            #################################################################################

            # Compute the fraction of type-2 halos as a function of the input prim_haloprop
            split = self.percentile_splitting_function(prim_haloprop)

            # Compute the baseline, undecorated result
            result = func(*args, **kwargs)

            # We will only decorate values that are not edge cases,
            # so first compute the mask for non-edge cases
            no_edge_mask = (
                (split > 0) & (split < 1) &
                (result > baseline_lower_bound) & (result < baseline_upper_bound)
                )
            # Now create convenient references to the non-edge-case sub-arrays
            no_edge_result = result[no_edge_mask]
            no_edge_split = split[no_edge_mask]

            #################################################################################
            # Compute the array type1_mask
            # This array will serve as a boolean mask that divides the halo sample into two subsamples
            # There are several possible ways that the type1_mask can be computed, depending on
            # what the decorator was passed as input

            if _HAS_table is True:
                # we were passed halo_type_tuple:
                if hasattr(self, 'halo_type_tuple'):
                    halo_type_key = self.halo_type_tuple[0]
                    halo_type1_val = self.halo_type_tuple[1]
                    type1_mask = table[halo_type_key][no_edge_mask] == halo_type1_val

                # the value of sec_haloprop_percentile is already stored as a column of the table
                elif self.sec_haloprop_key + '_percentile' in list(table.keys()):
                    no_edge_percentiles = table[self.sec_haloprop_key + '_percentile'][no_edge_mask]
                    type1_mask = no_edge_percentiles > no_edge_split
                else:
                    # the value of sec_haloprop_percentile will be computed from scratch
                    percentiles = compute_conditional_percentiles(
                        prim_haloprop=prim_haloprop,
                        sec_haloprop=sec_haloprop
                        )
                    no_edge_percentiles = percentiles[no_edge_mask]
                    type1_mask = no_edge_percentiles > no_edge_split
            else:
                try:
                    percentiles = kwargs['sec_haloprop_percentile']
                    if custom_len(percentiles) == 1:
                        percentiles = np.zeros(custom_len(prim_haloprop)) + percentiles
                except KeyError:
                    percentiles = compute_conditional_percentiles(
                        prim_haloprop=prim_haloprop,
                        sec_haloprop=sec_haloprop
                        )
                no_edge_percentiles = percentiles[no_edge_mask]
                type1_mask = no_edge_percentiles > no_edge_split

            # type1_mask has now been computed for all possible branchings
            #################################################################################

            perturbation = self._galprop_perturbation(
                    prim_haloprop=prim_haloprop[no_edge_mask],
                    baseline_result=no_edge_result,
                    splitting_result=no_edge_split)

            frac_type1 = 1 - no_edge_split
            frac_type2 = 1 - frac_type1
            perturbation[~type1_mask] *= (-frac_type1[~type1_mask] /
                (frac_type2[~type1_mask]))

            no_edge_result += perturbation
            result[no_edge_mask] = no_edge_result

            return result
Esempio n. 21
0
    def _galprop_perturbation(self, **kwargs):
        """
        Method determines hwo much to boost the baseline function
        according to the strength of assembly bias and the min/max
        boost allowable by the requirement that the all-halo baseline
        function be preserved. The returned perturbation applies to type-1 halos.

        Uses the disp_func passed in duing perturbation
        :param kwargs:
            Required kwargs are:
                baseline_result
                prim_haloprop
                sec_haloprop
                splitting_result
        :return: result, np.arry with dimensions of prim_haloprop detailing the perturbation.
        """

        #lower_bound_key = 'lower_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        #baseline_lower_bound = getattr(self, lower_bound_key)
        upper_bound_key = 'upper_bound_' + self._method_name_to_decorate + '_' + self.gal_type
        baseline_upper_bound = getattr(self, upper_bound_key)

        try:
            baseline_result = kwargs['baseline_result']
            prim_haloprop = kwargs['prim_haloprop']
            sec_haloprop = kwargs['sec_haloprop']
            splitting_result = kwargs['splitting_result']
        except KeyError:
            msg = (
                "Must call _galprop_perturbation method of the"
                "HeavisideAssembias class with the following keyword arguments:\n"
                "``baseline_result``, ``splitting_result`` and ``prim_haloprop``"
            )
            raise HalotoolsError(msg)

        #evaluate my continuous modification
        strength = self.assembias_strength(prim_haloprop)

        #get the kwargs for disp_func from the param dict
        disp_func_kwargs = {}
        for key, val in self.param_dict.iteritems():
            if key[:10] == 'disp_func_' and self.gal_type in key:
                split_key = key.split('_')
                disp_func_kwargs[split_key[-2]] = val

        #subtract the central value to make sure the right value is in the center of the function
        #t0 = time()
        central_val = compute_conditional_percentile(
            splitting_result,
            prim_haloprop=prim_haloprop,
            sec_haloprop=sec_haloprop)
        #the average displacement acts as a normalization we need.
        #t1 = time()
        disp_average = compute_conditional_averages(
            self.disp_func,
            disp_func_kwargs,
            prim_haloprop=prim_haloprop,
            sec_haloprop=sec_haloprop - central_val)
        #t2 = time()
        #x = compute_conditional_percentiles(prim_haloprop=prim_haloprop, sec_haloprop=sec_haloprop-central_val)
        #t3 = time()

        #print type(self)
        #print t1-t0, t2-t1, t3-t2

        bound1 = baseline_result / disp_average
        bound2 = (baseline_upper_bound -
                  baseline_result) / (baseline_upper_bound - disp_average)
        #stop NaN broadcasting
        bound1[np.isnan(bound1)] = np.inf
        bound2[np.isnan(bound2)] = np.inf

        bound = np.minimum(bound1, bound2)

        result = strength * bound * (self.disp_func(
            sec_haloprop - central_val, **disp_func_kwargs) - disp_average)
        #print 'Perturbations'
        #print result.mean(),result.std(), result.max(), result.min()

        return result
#!/usr/bin/env python
"""Command-line script to rebuild the particle table cache log"""

import argparse, os, fnmatch
from astropy.table import Table
import numpy as np
from time import time

try:
    import h5py
except ImportError:
    msg = (
        "\nMust have h5py installed to use the rebuild_ptcl_table_cache_log script.\n"
    )
    raise HalotoolsError(msg)

from halotools.custom_exceptions import HalotoolsError
from halotools.sim_manager import PtclTableCache
from halotools.sim_manager.ptcl_table_cache_log_entry import PtclTableCacheLogEntry

old_cache = PtclTableCache()
old_cache_log_exists = os.path.isfile(old_cache.cache_log_fname)

cache_log_dirname = os.path.dirname(old_cache.cache_log_fname)
corrupted_cache_log_basename = 'corrupted_ptcl_table_cache_log.txt'
corrupted_cache_log_fname = os.path.join(cache_log_dirname,
                                         corrupted_cache_log_basename)

rejected_filename_log_fname = 'rejected_ptcl_table_filenames.txt'
rejected_filename_log_fname = os.path.join(cache_log_dirname,
                                           rejected_filename_log_fname)
Esempio n. 23
0
        def wrapper(*args, **kwargs):

            #################################################################################
            # Retrieve the arrays storing prim_haloprop and sec_haloprop
            # The control flow below is what permits accepting an input
            # table or a directly inputting prim_haloprop and sec_haloprop arrays
            _HAS_table = False
            if 'table' in kwargs:
                try:
                    table = kwargs['table']
                    prim_haloprop = table[self.prim_haloprop_key]
                    sec_haloprop = table[self.sec_haloprop_key]
                    _HAS_table = True
                except KeyError:
                    msg = (
                        "When passing an input ``table`` to the "
                        " ``assembias_decorator`` method,\n"
                        "the input table must have a column with name ``%s``"
                        "and a column with name ``%s``.\n")
                    raise HalotoolsError(msg % (self.prim_haloprop_key),
                                         self.sec_haloprop_key)
            else:
                try:
                    prim_haloprop = np.atleast_1d(kwargs['prim_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                           "``assembias_decorator`` method,\n"
                           "you must pass ``prim_haloprop`` argument.\n")
                    raise HalotoolsError(msg)
                try:
                    sec_haloprop = np.atleast_1d(kwargs['sec_haloprop'])
                except KeyError:
                    if 'sec_haloprop_percentile' not in kwargs:
                        msg = ("\nIf not passing an input ``table`` to the "
                               "``assembias_decorator`` method,\n"
                               "you must pass either a ``sec_haloprop`` or "
                               "``sec_haloprop_percentile`` argument.\n")
                        raise HalotoolsError(msg)

            #################################################################################

            # Compute the fraction of type-2 halos as a function of the input prim_haloprop
            split = self.percentile_splitting_function(prim_haloprop)

            # Compute the baseline, undecorated result
            #t0 = time()
            result = func(*args, **kwargs)
            #t1 = time()
            #print 'Baseline time:',t1 - t0

            # We will only decorate values that are not edge cases,
            # so first compute the mask for non-edge cases
            no_edge_mask = ((split > 0) & (split < 1) &
                            (result > baseline_lower_bound) &
                            (result < baseline_upper_bound))
            # Now create convenient references to the non-edge-case sub-arrays
            no_edge_result = result[no_edge_mask]
            no_edge_split = split[no_edge_mask]

            #NOTE I've removed the type 1 mask as it is not necessary
            # this has all been rolled into the galprop_perturbation function

            if prim_haloprop[no_edge_mask].shape[0] == 0:
                perturbation = np.zeros_like(no_edge_result)
            else:
                perturbation = self._galprop_perturbation(
                    prim_haloprop=prim_haloprop[no_edge_mask],
                    sec_haloprop=sec_haloprop[no_edge_mask],
                    baseline_result=no_edge_result,
                    splitting_result=no_edge_split)

            no_edge_result += perturbation
            #print result.mean(), result.std(), result.max(), result.min()
            result[no_edge_mask] = no_edge_result

            #print 'End Wrapper'
            #print result.mean(), result.std(), result.max(), result.min()

            return result
Esempio n. 24
0
        def wrapper(*args, **kwargs):

            #################################################################################
            #  Retrieve the arrays storing prim_haloprop and sec_haloprop
            #  The control flow below is what permits accepting an input
            #  table or a directly inputting prim_haloprop and sec_haloprop arrays

            _HAS_table = False
            if 'table' in kwargs:
                try:
                    table = kwargs['table']
                    prim_haloprop = table[self.prim_haloprop_key]
                    sec_haloprop = table[self.sec_haloprop_key]
                    _HAS_table = True
                except KeyError:
                    msg = (
                        "When passing an input ``table`` to the "
                        " ``assembias_decorator`` method,\n"
                        "the input table must have a column with name ``%s``"
                        "and a column with name ``%s``.\n")
                    raise HalotoolsError(msg % (self.prim_haloprop_key),
                                         self.sec_haloprop_key)
            else:
                try:
                    prim_haloprop = np.atleast_1d(kwargs['prim_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                           "``assembias_decorator`` method,\n"
                           "you must pass ``prim_haloprop`` argument.\n")
                    raise HalotoolsError(msg)
                try:
                    sec_haloprop = np.atleast_1d(kwargs['sec_haloprop'])
                except KeyError:
                    msg = ("\nIf not passing an input ``table`` to the "
                           "``assembias_decorator`` method,\n"
                           "you must pass ``sec_haloprop`` argument")
                    raise HalotoolsError(msg)

            #################################################################################

            #  Compute the percentile to split on as a function of the input prim_haloprop
            split = self.percentile_splitting_function(prim_haloprop)

            #  Compute the baseline, undecorated result
            result = func(*args, **kwargs)

            #  We will only decorate values that are not edge cases,
            #  so first compute the mask for non-edge cases
            no_edge_mask = ((split > 0) & (split < 1) &
                            (result > baseline_lower_bound) &
                            (result < baseline_upper_bound))
            #  Now create convenient references to the non-edge-case sub-arrays
            no_edge_result = result[no_edge_mask]
            no_edge_split = split[no_edge_mask]

            # TODO i can maybe figure out how to cache the percentiles in the table, but for hte time being i'll just to retrieve them everytime
            if _HAS_table is True:
                if self.sec_haloprop_key + '_percentile_values' in table.keys(
                ):
                    #                    no_edge_percentile_values = table[self.sec_haloprop_key + '_percentile_value'][no_edge_mask]
                    pass
                else:
                    #  the value of sec_haloprop_percentile will be computed from scratch
                    #no_edge_percentile_values = compute_conditional_percentile_values( p=no_edge_split,
                    #    prim_haloprop=prim_haloprop[no_edge_mask],
                    #    sec_haloprop=sec_haloprop[no_edge_mask]
                    #)
                    pass
            else:
                pass
                '''
                try:
                    percentiles = kwargs['sec_haloprop_percentile_values']
                    if custom_len(percentiles) == 1:
                        percentiles = np.zeros(custom_len(prim_haloprop)) + percentiles
                    no_edge_percentile_values = percentiles[no_edge_mask]
                except KeyError:
                    no_edge_percentile_values = compute_conditional_percentile_values(p=no_edge_split,
                        prim_haloprop=prim_haloprop[no_edge_mask],
                        sec_haloprop=sec_haloprop[no_edge_mask]
                    )
                 '''

            #  NOTE I've removed the type 1 mask as it is not well-defined in this implementation
            strength = self.assembias_strength(prim_haloprop[no_edge_mask])

            shuffled_ranks = compute_conditional_shuffled_ranks(
                prim_haloprop=prim_haloprop[no_edge_mask],
                sec_haloprop=sec_haloprop[no_edge_mask],
                correlation_coeff=strength)

            dist = bernoulli if baseline_upper_bound == 1 else poisson

            return dist.isf(1 - shuffled_ranks, mu=result)
Esempio n. 25
0
def compute_conditional_averages(disp_func=lambda x: x,
                                 disp_func_kwargs={},
                                 **kwargs):
    """
    In bins of the ``prim_haloprop``, compute the average value of disp_func given
    the input ``table`` based on the value of ``sec_haloprop``.
    Parameters
    ----------
    disp_func: function, optional
        A kwarg that is the function to calculate the conditional average of.
        Default is 'lambda x: x' which will compute the average value of sec_haloprop
        in bins of prim_haloprop
    disp_func_kwargs: dictionary, optional
        kwargs for the disp_func. Default is an empty dictionary
    table : astropy table, optional
        a keyword argument that stores halo catalog being used to make mock galaxy population
        If a `table` is passed, the `prim_haloprop_key` and `sec_haloprop_key` keys
        must also be passed. If not passing a `table`, you must directly pass the
        `prim_haloprop` and `sec_haloprop` keyword arguments.
    prim_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        primary halo property. `compute_conditional_percentiles` bins the ``table`` by
        ``prim_haloprop_key`` when computing the result.
    sec_haloprop_key : string, optional
        Name of the column of the input ``table`` that will be used to access the
        secondary halo property. `compute_conditional_percentiles` bins the ``table`` by
        ``prim_haloprop_key``, and in each bin uses the value stored in ``sec_haloprop_key``
        to compute the ``prim_haloprop``-conditioned rank-order percentile.
    prim_haloprop : array_like, optional
        Array storing the primary halo property used to bin the input points.
        If a `prim_haloprop` is passed, you must also pass a `sec_haloprop`.
    sec_haloprop : array_like, optional
        Array storing the secondary halo property used to define the conditional percentiles
        in each bin of `prim_haloprop`.
    prim_haloprop_bin_boundaries : array, optional
        Array defining the boundaries by which we will bin the input ``table``.
        Default is None, in which case the binning will be automatically determined using
        the ``dlog10_prim_haloprop`` keyword.
    dlog10_prim_haloprop : float, optional
        Logarithmic spacing of bins of the mass-like variable within which
        we will assign secondary property percentiles. Default is 0.2.
    Examples
    --------
    >>> from halotools.sim_manager import FakeSim
    >>> fakesim = FakeSim()
    >>> result = compute_conditional_percentiles(table = fakesim.halo_table, prim_haloprop_key = 'halo_mvir', sec_haloprop_key = 'halo_vmax')
    Notes
    -----
    The sign of the result is such that in bins of the primary property,
    *smaller* values of the secondary property
    receive *smaller* values of the returned percentile.
    """

    if 'table' in kwargs:
        table = kwargs['table']
        try:
            prim_haloprop_key = kwargs['prim_haloprop_key']
            prim_haloprop = table[prim_haloprop_key]
            sec_haloprop_key = kwargs['sec_haloprop_key']
            sec_haloprop = table[sec_haloprop_key]
        except KeyError:
            msg = (
                "\nWhen passing an input ``table`` to the ``compute_conditional_percentiles`` method,\n"
                "you must also pass ``prim_haloprop_key`` and ``sec_haloprop_key`` keyword arguments\n"
                "whose values are column keys of the input ``table``\n")
            raise HalotoolsError(msg)
    else:
        try:
            prim_haloprop = kwargs['prim_haloprop']
            sec_haloprop = kwargs['sec_haloprop']
        except KeyError:
            msg = (
                "\nIf not passing an input ``table`` to the ``compute_conditional_percentiles`` method,\n"
                "you must pass a ``prim_haloprop`` and ``sec_haloprop`` arguments\n"
            )
            raise HalotoolsError(msg)

    compute_prim_haloprop_bins_dict = {}
    compute_prim_haloprop_bins_dict['prim_haloprop'] = prim_haloprop
    try:
        compute_prim_haloprop_bins_dict['prim_haloprop_bin_boundaries'] = (
            kwargs['prim_haloprop_bin_boundaries'])
    except KeyError:
        pass
    try:
        compute_prim_haloprop_bins_dict['dlog10_prim_haloprop'] = kwargs[
            'dlog10_prim_haloprop']
    except KeyError:
        pass
    prim_haloprop_bins = compute_prim_haloprop_bins(
        **compute_prim_haloprop_bins_dict)

    output = np.zeros_like(prim_haloprop)

    # sort on secondary property only with each mass bin
    bins_in_halocat = set(prim_haloprop_bins)
    for ibin in bins_in_halocat:
        indices_of_prim_haloprop_bin = np.where(prim_haloprop_bins == ibin)[0]

        # place the percentiles into the catalog
        output[indices_of_prim_haloprop_bin] = np.mean(
            disp_func(sec_haloprop[indices_of_prim_haloprop_bin],
                      **disp_func_kwargs))
    #TODO i'm not sure if this should have dimensions of prim_haloprop or the binning...
    return output