示例#1
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
示例#2
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)
示例#3
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
示例#4
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
示例#5
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
示例#6
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
示例#7
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