diff --git a/crow/cluster_modules/__init__.py b/crow/cluster_modules/__init__.py new file mode 100644 index 0000000..3a982d5 --- /dev/null +++ b/crow/cluster_modules/__init__.py @@ -0,0 +1,30 @@ +"""Cluster modules package. + +Keep this module lightweight: do not import the submodules or classes eagerly +here because several submodules import the top-level ``crow`` package and that +can produce circular imports when the top-level ``crow.__init__`` imports +things from ``cluster_modules``. + +To import classes or modules use the explicit submodule path, for example:: + + from crow.cluster_modules.abundance import ClusterAbundance + from crow.cluster_modules.shear_profile import ClusterShearProfile + +Sphinx/apidoc will still find and document the submodules even if they are not +imported here; this file only needs to exist so Python treats the directory as +a package. +""" + +# Expose the expected subpackage/module names for convenience. Do NOT import +# the modules at package import time to avoid circular import problems. +__all__ = [ + "abundance", + "completeness_models", + "kernel", + "parameters", + "purity_models", + "_clmm_patches", + "shear_profile", + "shear_profile_parallel", + "mass_proxy", +] diff --git a/crow/cluster_modules/abundance.py b/crow/cluster_modules/abundance.py index fab6710..d9aa719 100644 --- a/crow/cluster_modules/abundance.py +++ b/crow/cluster_modules/abundance.py @@ -21,6 +21,18 @@ class ClusterAbundance: an area on the sky, a halo mass function, as well as multiple kernels, where each kernel represents a different distribution involved in the final cluster abundance integrand. + + Attributes + ---------- + cosmo : pyccl.cosmology.Cosmology or None + Cosmology object used for predictions. Set via the `cosmo` property. + halo_mass_function : callable + Halo mass function object compatible with PyCCL's MassFunc interface. + parameters : Parameters + Container for optional model parameters. + _hmf_cache : dict + Cache for previously computed halo mass function evaluations keyed by + (log_mass, scale_factor). """ @property @@ -47,9 +59,28 @@ def __init__( def comoving_volume( self, z: npt.NDArray[np.float64], sky_area: float = 0 ) -> npt.NDArray[np.float64]: - """The differential comoving volume given area sky_area at redshift z. - - :param sky_area: The area of the survey on the sky in square degrees. + """Differential comoving volume for a given sky area. + + Parameters + ---------- + z : array_like + Redshift or array of redshifts at which to compute the differential + comoving volume (dV/dz per steradian). + sky_area : float, optional + Survey area in square degrees. Default 0 returns per-steradian volume. + + Returns + ------- + numpy.ndarray + Differential comoving volume (same shape as `z`) multiplied by the + survey area (converted to steradians). Units: [Mpc/h]^3 (consistent + with the internal PyCCL conventions used here). + + Notes + ----- + This uses PyCCL background helpers to evaluate the angular diameter + distance and h(z) factor. If `sky_area` is zero the returned array is + the per-steradian dV/dz. """ assert self.cosmo is not None scale_factor = 1.0 / (1.0 + z) @@ -73,7 +104,26 @@ def mass_function( log_mass: npt.NDArray[np.float64], z: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """The mass function at z and mass.""" + """Evaluate the halo mass function at given log-mass and redshift. + + Parameters + ---------- + log_mass : array_like + Array of log10 halo masses (M_sun). + z : array_like + Array of redshifts matching `log_mass`. + + Returns + ------- + numpy.ndarray + Array with mass function values (dn/dlnM or as provided by the + configured `halo_mass_function`) evaluated at each (mass, z). + + Notes + ----- + Results are cached in `_hmf_cache` keyed by (log_mass, scale_factor) + to avoid repeated expensive evaluations for identical inputs. + """ scale_factor = 1.0 / (1.0 + z) return_vals = [] diff --git a/crow/cluster_modules/completeness_models.py b/crow/cluster_modules/completeness_models.py index b19346e..fdef2f7 100644 --- a/crow/cluster_modules/completeness_models.py +++ b/crow/cluster_modules/completeness_models.py @@ -1,7 +1,7 @@ """The cluster completeness module. -This module holds the classes that define the kernels that can be included -in the cluster abundance integrand. +This module holds the classes that define completeness kernels that can be included +in the cluster prediction integrand. """ import numpy as np @@ -11,10 +11,15 @@ class Completeness: - """The completeness kernel for the numcosmo simulated survey. + """The completeness kernel base class. - This kernel will affect the integrand by accounting for the incompleteness - of a cluster selection. + This kernel affects the prediction integrand by accounting for the incompleteness + of a cluster selection. Subclasses should implement the ``distribution`` method. + + Attributes + ---------- + parameters : Parameters, optional + Container for completeness model parameters (defined by subclasses). """ def __init__(self): @@ -25,7 +30,22 @@ def distribution( log_mass: npt.NDArray[np.float64], z: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """Evaluates and returns the completeness contribution to the integrand.""" + """Evaluate the completeness kernel contribution. + + Parameters + ---------- + log_mass : array_like + Array of log10 halo masses (units: Msun). + z : array_like + Array of redshifts matching ``log_mass``. + + Returns + ------- + numpy.ndarray + Array of completeness values in the range [0, 1] with the same + broadcastable shape as the inputs. Subclasses should guarantee the + output dtype is floating point. + """ raise NotImplementedError @@ -38,10 +58,25 @@ def distribution( class CompletenessAguena16(Completeness): - """The completeness kernel for the numcosmo simulated survey. - - This kernel will affect the integrand by accounting for the incompleteness - of a cluster selection. + """Completeness model following Aguena et al. (2016) parametrisation. + + The model uses a pivot mass and a redshift-dependent power-law index to + compute a sigmoid-like completeness as a function of mass and redshift. + + Parameters + ---------- + (set during initialization) + a_n, b_n : float + Parameters controlling the redshift evolution of the power-law index. + a_logm_piv, b_logm_piv : float + Parameters controlling the pivot mass (in log10 units) and its + redshift evolution. + + Attributes + ---------- + parameters : Parameters + Container holding the parameter values; defaults are defined in + ``REDMAPPER_DEFAULT_PARAMETERS``. """ def __init__( @@ -50,6 +85,18 @@ def __init__( self.parameters = Parameters({**REDMAPPER_DEFAULT_PARAMETERS}) def _mpiv(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Return the pivot mass (not in log) at redshift `z`. + + Parameters + ---------- + z : array_like + Redshift or array of redshifts. + + Returns + ------- + numpy.ndarray + Pivot mass values in Msun (10**log_mpiv). Returned dtype is float64. + """ log_mpiv = self.parameters["a_logm_piv"] + self.parameters["b_logm_piv"] * ( 1.0 + z ) @@ -57,6 +104,18 @@ def _mpiv(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: return mpiv.astype(np.float64) def _nc(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Return the redshift-dependent power-law index nc(z). + + Parameters + ---------- + z : array_like + Redshift or array of redshifts. + + Returns + ------- + numpy.ndarray + The value of the power-law index at each provided redshift. + """ nc = self.parameters["a_n"] + self.parameters["b_n"] * (1.0 + z) assert isinstance(nc, np.ndarray) return nc @@ -66,7 +125,29 @@ def distribution( log_mass: npt.NDArray[np.float64], z: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """Evaluates and returns the completeness contribution to the integrand.""" + r"""Compute the completeness fraction for given mass and redshift. + The completeness is given by + + .. math:: + c(M, z) = \frac{\left(M / M_{\rm piv}(z)\right)^{n_c(z)}} + {1 + \left(M / M_{\rm piv}(z)\right)^{n_c(z)}} + + where M = 10^{\text{log\_mass}}, M_{\rm piv}(z) is returned by _mpiv(z), + and n_c(z) is returned by _nc(z). + + Parameters + ---------- + log_mass : array_like + Array of log10 halo masses (Msun). + z : array_like + Array of redshifts matching ``log_mass``. + + Returns + ------- + numpy.ndarray + Completeness values in the interval [0, 1] with shape matching the + broadcasted inputs. dtype is float64. + """ mass_norm_pow = (10.0**log_mass / self._mpiv(z)) ** self._nc(z) diff --git a/crow/cluster_modules/kernel.py b/crow/cluster_modules/kernel.py index 0d1705b..76284c7 100644 --- a/crow/cluster_modules/kernel.py +++ b/crow/cluster_modules/kernel.py @@ -9,29 +9,45 @@ class TrueMass: - """The true mass kernel. + """True-mass kernel used in abundance integrals. - Assuming we measure the true mass, this will always be 1. + This kernel represents the case where the observed mass equals the true + halo mass. It therefore contributes a multiplicative factor of unity to + the abundance integrand and does not alter the mass distribution. + + Notes + ----- + The distribution method returns a NumPy array (dtype float) that can be + broadcast with other integrand factors. """ def distribution(self) -> npt.NDArray[np.float64]: - """Evaluates and returns the mass distribution contribution to the integrand. + """Evaluate and return the mass kernel contribution. - We have set this to 1.0 (i.e. it does not affect the mass distribution) + Returns + ------- + numpy.ndarray + Array containing the value 1.0. This can be broadcast to the shape + required by the integrand and is provided as float64. """ return np.atleast_1d(1.0) class SpectroscopicRedshift: - """The spec-z kernel. + """Spectroscopic-redshift kernel for abundance integrals. - Assuming the spectroscopic redshift has no uncertainties, this is akin to - multiplying by 1. + Represents the idealized case where cluster redshifts are known exactly + (spectroscopic precision). The kernel thus contributes a factor of unity + to the redshift part of the integrand. """ def distribution(self) -> npt.NDArray[np.float64]: - """Evaluates and returns the z distribution contribution to the integrand. + """Evaluate and return the redshift kernel contribution. - We have set this to 1.0 (i.e. it does not affect the redshift distribution) + Returns + ------- + numpy.ndarray + Array containing the value 1.0 (dtype float64). This is intended + to be broadcast with other integrand arrays. """ return np.atleast_1d(1.0) diff --git a/crow/cluster_modules/parameters.py b/crow/cluster_modules/parameters.py index 1151a08..e715715 100644 --- a/crow/cluster_modules/parameters.py +++ b/crow/cluster_modules/parameters.py @@ -11,20 +11,51 @@ class Parameters: """ def __init__(self, default_parameters_dict): - """ + """Create a Parameters container. + Parameters ---------- - default_parameters_dict: dict - Dictionary with the default parameters names and values. - Only parameters defined in this dictionary will be accepted - in this class + default_parameters_dict : dict + Dictionary with the default parameter names and values. Only keys + present in this dictionary will be accepted by this instance. """ self.__pars = {**default_parameters_dict} def __getitem__(self, item): + """Retrieve a parameter value by key. + + Parameters + ---------- + item : str + Name of the parameter to retrieve. + + Returns + ------- + Any + The parameter value stored under ``item``. + + Raises + ------ + KeyError + If ``item`` is not a valid parameter name for this instance. + """ return self.__pars[item] def __setitem__(self, item, value): + """Set a parameter value for an existing key. + + Parameters + ---------- + item : str + Name of the parameter to set. Must already exist in the container. + value : Any + Value to assign to the parameter. + + Raises + ------ + KeyError + If ``item`` is not one of the predefined parameter names. + """ if item not in self.__pars: raise KeyError( f"key={item} not accepted, " f"must be in {list(self.__pars.keys())}" @@ -32,19 +63,62 @@ def __setitem__(self, item, value): self.__pars[item] = value def keys(self): + """Return an iterable view of parameter names. + + Returns + ------- + dict_keys + A view of the parameter keys in this container. + """ return self.__pars.keys() def values(self): + """Return an iterable view of parameter values. + + Returns + ------- + dict_values + A view of the parameter values in this container. + """ return self.__pars.values() def items(self): + """Return an iterable view of (key, value) pairs. + + Returns + ------- + dict_items + A view of the parameter (key, value) pairs in this container. + """ return self.__pars.items() def __iter__(self): + """Iterate over parameter keys. + + Yields + ------ + str + Parameter key names. + """ for key in self.keys(): yield key def update(self, update_dict): + """Update multiple parameters at once. + + Parameters + ---------- + update_dict : dict or Parameters + Mapping of parameter names to new values. Keys must be a subset of + the parameters defined for this container. + + Raises + ------ + ValueError + If ``update_dict`` is not a dict or Parameters instance. + KeyError + If ``update_dict`` contains keys not defined in this container. + """ if not isinstance(update_dict, (dict, Parameters)): raise ValueError( "argument of update must be dict or Parameters, " diff --git a/crow/cluster_modules/purity_models.py b/crow/cluster_modules/purity_models.py index 2aaec98..0476302 100644 --- a/crow/cluster_modules/purity_models.py +++ b/crow/cluster_modules/purity_models.py @@ -13,10 +13,21 @@ class Purity: - """The purity kernel for the numcosmo simulated survey. + """Purity kernel base class. - This kernel will affect the integrand by accounting for the inpurity - of a cluster selection. + This kernel represents the probability that a detected object in the + cluster catalogue is a true galaxy cluster (i.e. purity). Subclasses should + implement the ``distribution`` method. + + Notes + ----- + Mass-proxy inputs to methods in this module are provided as log10 values + of the observable mass proxy. + + Attributes + ---------- + parameters : Parameters, optional + Container for model parameters defined by subclasses. """ def __init__(self): @@ -27,7 +38,21 @@ def distribution( z: npt.NDArray[np.float64], log_mass_proxy: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """Evaluates and returns the purity contribution to the integrand.""" + """Evaluate the purity kernel contribution. + + Parameters + ---------- + z : array_like + Redshift or array of redshifts for the objects. + log_mass_proxy : array_like + Array of log10 mass-proxy values corresponding to the objects. + + Returns + ------- + numpy.ndarray + Array with purity values in the interval [0, 1]. The output shape + will follow NumPy broadcasting rules applied to the inputs. + """ raise NotImplementedError @@ -40,10 +65,23 @@ def distribution( class PurityAguena16(Purity): - """The purity kernel for the numcosmo simulated survey. - - This kernel will affect the integrand by accounting for the purity - of a cluster selection. + """Purity model following Aguena et al. (2016) parametrisation. + + The model computes a sigmoid-like purity as a function of a mass proxy + and redshift using a pivot mass and a redshift-dependent power-law index. + + Important + --------- + Note that the base class `Purity.distribution` defines the argument order + as ``(z, log_mass_proxy)`` while this subclass implements + ``distribution(self, log_mass_proxy, z)``. Callers should use the + subclass' signature when invoking the concrete implementation. + + Attributes + ---------- + parameters : Parameters + Container holding default parameters defined in + ``REDMAPPER_DEFAULT_PARAMETERS``. """ def __init__(self): @@ -51,6 +89,18 @@ def __init__(self): self.parameters = Parameters({**REDMAPPER_DEFAULT_PARAMETERS}) def _mpiv(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Return the pivot mass. + + Parameters + ---------- + z : array_like + Redshift or array of redshifts. + + Returns + ------- + numpy.ndarray + Pivot mass values in Msun (10**log_mpiv), dtype float64. + """ log_mpiv = self.parameters["a_logm_piv"] + self.parameters["b_logm_piv"] * ( 1.0 + z ) @@ -58,6 +108,18 @@ def _mpiv(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: return mpiv.astype(np.float64) def _nc(self, z: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Return the redshift-dependent power-law index nc(z). + + Parameters + ---------- + z : array_like + Redshift or array of redshifts. + + Returns + ------- + numpy.ndarray + The value of the power-law index at each provided redshift. + """ nc = self.parameters["a_n"] + self.parameters["b_n"] * (1.0 + z) assert isinstance(nc, np.ndarray) return nc @@ -67,7 +129,27 @@ def distribution( log_mass_proxy: npt.NDArray[np.float64], z: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """Evaluates and returns the purity contribution to the integrand.""" + """Compute the purity fraction for given mass-proxy and redshift. + The purity is given by the sigmoid-like expression + + p(M, z) = ( (M / M_piv(z))**(n_c(z)) ) / ( 1 + (M / M_piv(z))**(n_c(z)) ), + + where M = 10**(log_mass_proxy), M_piv(z) = 10**(a_logm_piv + b_logm_piv*(1 + z)) + and n_c(z) = a_n + b_n*(1 + z). + + Parameters + ---------- + log_mass_proxy : array_like + Array of log10 mass-proxy values. + z : array_like + Array of redshifts matching ``log_mass_proxy``. + + Returns + ------- + numpy.ndarray + Purity values in the interval [0, 1] with shape matching the + broadcasted inputs. dtype is float64. + """ rich_norm_pow = (10**log_mass_proxy / self._mpiv(z)) ** self._nc(z) diff --git a/crow/cluster_modules/shear_profile.py b/crow/cluster_modules/shear_profile.py index a886bde..3c28068 100644 --- a/crow/cluster_modules/shear_profile.py +++ b/crow/cluster_modules/shear_profile.py @@ -57,10 +57,28 @@ def __init__( two_halo_term: bool = False, boost_factor: bool = False, ) -> None: - """ - Note + """Class to compute cluster shear lensing signal. ---- If cluster_concentration < 0, concentration set to None! + + Attributes + ---------- + _is_delta_sigma : bool + If True, work in physical DeltaSigma units; otherwise compute reduced shear. + parameters : Parameters + Container for model parameters (e.g. `cluster_concentration`). + _clmm_cosmo : clmm.Cosmology + CLMM-wrapped cosmology object for evaluations. + beta_parameters : dict or None + Parameters used when computing geometric lensing efficiency . + miscentering_parameters : dict or None + Parameters describing miscentering model (fraction, sigma, distribution, etc). + two_halo_term : bool + If True include 2-halo contribution. + boost_factor : bool + If True apply boost-factor correction. + vectorized : bool + Flag indicating whether vectorized evaluation is used. """ super().__init__(cosmo, halo_mass_function) self.is_delta_sigma = is_delta_sigma @@ -83,20 +101,24 @@ def __init__( @property def cluster_concentration(self): + """The cluster concentration parameter.""" return self.parameters["cluster_concentration"] @cluster_concentration.setter def cluster_concentration(self, value): + """Set the cluster concentration parameter.""" if value is not None and value < 0: value = None self.parameters["cluster_concentration"] = value @property def use_beta_s_interp(self): + """Flag to use beta_s interpolation (interpolate lens efficiency or not).""" return self.__use_beta_s_interp @use_beta_s_interp.setter def use_beta_s_interp(self, value): + """Set flag to use beta_s interpolation (interpolate lens efficiency or not).""" if not isinstance(value, bool): raise ValueError(f"value (={value}) for use_beta_s_interp must be boolean.") self.__use_beta_s_interp = value @@ -160,8 +182,7 @@ def set_beta_parameters( {\left<\beta_s\right>^2}-1\right)\left<\beta_s\right>\kappa_{\infty}\right) Returns ------- - float - Mean value of the geometric lensing efficicency + None """ self._beta_parameters = { "z_inf": z_inf, @@ -173,6 +194,22 @@ def set_beta_parameters( self.approx = approx.lower() def _beta_s_mean_exact(self, z_cl): + r"""Compute exact mean value of the geometric lensing efficiency . + + .. math:: + \left<\beta_s\right> = \frac{\int_{z = z_{min}}^{z_{max}}\beta_s(z)N(z)} + {\int_{z = z_{min}}^{z_{max}}N(z)} + \text{ where } N(z) \text{ is the redshift distribution function.} + + Parameters + ---------- + z_cl: float or npt.NDArray[np.float64] + Cluster redshift(s) + Returns + ------- + npt.NDArray[np.float64] + Mean geometric lensing efficiency at given cluster redshift(s) + """ z_cl = np.asarray(z_cl) if z_cl.ndim == 0: return compute_beta_s_mean_from_distribution( @@ -188,6 +225,21 @@ def _beta_s_mean_exact(self, z_cl): ) def _beta_s_square_mean_exact(self, z_cl): + r"""Compute exact mean value of the geometric lensing efficiency squared . + .. math:: + \left<\beta_s^2\right> = \frac{\int_{z = z_{min}}^{z_{max}}\beta_s^2(z)N(z)} + {\int_{z = z_{min}}^{z_{max}}N(z)} + \text{ where } N(z) \text{ is the redshift distribution function.} + + Parameters + ---------- + z_cl: float or npt.NDArray[np.float64] + Cluster redshift(s) + Returns + ------- + npt.NDArray[np.float64] + Mean geometric lensing efficiency squared at given cluster redshift(s) + """ z_cl = np.asarray(z_cl) if z_cl.ndim == 0: return compute_beta_s_square_mean_from_distribution( @@ -203,7 +255,19 @@ def _beta_s_square_mean_exact(self, z_cl): ) def set_beta_s_interp(self, z_min, z_max, n_intep=3): + """Build quadratic interpolators for and over a redshift grid. + Parameters + ---------- + z_min, z_max : float + Redshift bounds for the interpolation grid. + n_intep : int, optional + Number of interpolation nodes. Default 3. + + Returns + ------- + None + """ # Note: this will set an interpolator with a fixed cosmology # must add check to verify consistency with main cosmology @@ -229,7 +293,22 @@ def compute_shear_profile( z: npt.NDArray[np.float64], radius_center: np.float64, ) -> npt.NDArray[np.float64]: - """Delta sigma for clusters.""" + """Compute DeltaSigma (or reduced shear) for a list of cluster masses/redshifts. + + Parameters + ---------- + log_mass : numpy.ndarray + Array of log10(mass) values for clusters. + z : numpy.ndarray + Array of cluster redshifts (same length as `log_mass`). + radius_center : float + Radius (single value) at which the profile is evaluated [same units used by CLMM Modeling]. + + Returns + ------- + numpy.ndarray + 1D array of DeltaSigma (or reduced shear) values, one per input cluster. + """ mass_def = self.halo_mass_function.mass_def mass_type = mass_def.rho_type if mass_type == "matter": @@ -267,7 +346,23 @@ def compute_shear_profile_vectorized( z: npt.NDArray[np.float64], radius_center: npt.NDArray[np.float64], ) -> npt.NDArray[np.float64]: - """Delta sigma for clusters.""" + """Vectorized evaluation of the cluster profile when inputs are arrays. + + Parameters + ---------- + log_mass : numpy.ndarray + Array (or scalar) of log10(mass) values. + z : numpy.ndarray + Array (or scalar) of redshifts. + radius_center : numpy.ndarray + Radii at which to evaluate the profile (can be 1D array). + + Returns + ------- + numpy.ndarray + Array with profile values. Shape depends on input broadcasting (typically + (n_clusters, n_radii) or (n_radii, n_clusters) depending on call). + """ mass_def = self.halo_mass_function.mass_def mass_type = mass_def.rho_type if mass_type == "matter": @@ -299,7 +394,24 @@ def _one_halo_contribution( sigma_offset=0.12, **kwargs, ) -> npt.NDArray[np.float64]: - """Calculate the second halo contribution to the delta sigma.""" + """Compute the 1-halo contribution (either DeltaSigma or reduced shear). + + Parameters + ---------- + clmm_model : clmm.Modeling + CLMM modeling object configured with mass and concentration. + radius_center : float or array_like + Radius or radii at which to evaluate. + redshift : float or array_like + Cluster redshift(s). + sigma_offset : float, optional + Offset parameter (unused in many flows). + + Returns + ------- + numpy.ndarray + Evaluated 1-halo profile (same shape as input radius_center after broadcasting). + """ beta_s_mean = None beta_s_square_mean = None if self.is_delta_sigma: @@ -330,7 +442,26 @@ def _one_halo_contribution( def _two_halo_contribution( self, clmm_model: clmm.Modeling, radius_center, redshift ) -> npt.NDArray[np.float64]: - """Calculate the second halo contribution to the delta sigma.""" + """Compute the 2-halo contribution for DeltaSigma. + + Notes + ----- + Currently raises if `is_delta_sigma` is False (2-halo for reduced shear not implemented). + + Parameters + ---------- + clmm_model : clmm.Modeling + CLMM modeling object. + radius_center : float + Radius at which to evaluate (single value). + redshift : float + Cluster redshift. + + Returns + ------- + numpy.ndarray or float + 2-halo contribution evaluated at the given radius/redshift (scalar if single radius). + """ # pylint: disable=protected-access if self.is_delta_sigma == False: raise Exception("Two halo contribution for gt is not suported yet.") @@ -342,7 +473,20 @@ def _two_halo_contribution( return second_halo_right_centered[0] def _get_concentration(self, log_m: float, redshift: float) -> float: - """Determine the concentration for a halo.""" + """Return concentration for a halo given log-mass and redshift. + + Parameters + ---------- + log_m : float + log10 of halo mass. + redshift : float + Halo redshift. + + Returns + ------- + float + Halo concentration parameter. + """ if self.cluster_concentration is not None: return self.cluster_concentration @@ -357,7 +501,20 @@ def _get_concentration(self, log_m: float, redshift: float) -> float: def _correct_with_boost_nfw( self, profiles: npt.NDArray[np.float64], radius_list: npt.NDArray[np.float64] ) -> npt.NDArray[np.float64]: - """Determine the nfw boost factor and correct the shear profiles.""" + """Apply boost-factor correction to NFW profiles using CLMM utilities. + + Parameters + ---------- + profiles : numpy.ndarray + Profile values to correct. + radius_list : numpy.ndarray + Radii corresponding to `profiles`. + + Returns + ------- + numpy.ndarray + Corrected profiles (same shape as `profiles`). + """ boost_factors = clmm.utils.compute_powerlaw_boost(radius_list, 1.0) corrected_profiles = clmm.utils.correct_with_boost_values( profiles, boost_factors @@ -397,6 +554,30 @@ def set_miscentering( def compute_miscentering( self, clmm_model, radius_center, redshift, beta_s_mean, beta_s_square_mean ): + """Compute the miscentered profile integral and return fraction. + + Parameters + ---------- + clmm_model : clmm.Modeling + CLMM model used to evaluate (reduced) shear or DeltaSigma. + radius_center : float + Radius where the profile is evaluated. + redshift : float + Cluster redshift. + beta_s_mean : float or None + Mean beta_s if using reduced shear; None if computing DeltaSigma. + beta_s_square_mean : float or None + Mean beta_s^2 for order2 approx; None if not used. + + Returns + ------- + tuple + (miscentering_integral, miscentering_fraction) + miscentering_integral : numpy.ndarray or float + Integral value of the miscentered profile at `radius_center`. + miscentering_fraction : float + Fraction of clusters that are miscentered (from parameters). + """ params = self.miscentering_parameters miscentering_frac = params["miscentering_fraction"] sigma = params["sigma"] diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 0000000..37b02e2 --- /dev/null +++ b/docs/README.rst @@ -0,0 +1,45 @@ +Generating the Crow documentation (package-local docs) +===================================================== + +This README explains how to generate documentation for the `crow` package +itself. It mirrors the top-level `docs/README.rst` but sets paths relative to +this `crow/docs/` directory. + +Overview +-------- +Sphinx builds the API docs by importing the `crow` package in this repository +and pulling docstrings from the Python source files under `crow/` (for +example: `crow/cluster_modules/shear_profile.py`, `crow/cluster_modules/parameters.py`, +`crow/cluster_modules/purity_models.py`, etc.). The `sphinx-apidoc` step scans +these modules and writes reST files that call ``.. automodule::`` for each +module; Sphinx then imports them and extracts the docstrings. + +Quick steps (run from the repository root) +----------------------------------------- +1. Generate module rst files into this folder (overwrite existing): + + sphinx-apidoc -o crow/docs/ crow -f + + This will create a set of reST files in `crow/docs/` referencing the + `crow` package modules. + +2. Build the HTML docs for the package (from repo root): + + sphinx-build -b html crow/docs/ crow/docs/_build/html + +3. Serve the built docs locally to inspect them:: + + python -m http.server --directory crow/docs/_build/html 8000 + +Notes +----- +- Ensure `crow/docs/conf.py` is configured to add the repository root to + ``sys.path`` so that the `crow` package is importable by Sphinx. +- If heavy external dependencies break imports during the build, add them to + ``autodoc_mock_imports`` in `crow/docs/conf.py` or install the real deps. +- Re-run ``sphinx-apidoc -f`` after adding new modules so rst stubs are + regenerated. + +If you want, I can generate the apidoc files for you (write the generated +rst files) and run the build — tell me to proceed and confirm you want the +package-local `crow/docs` built. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..55cd723 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,31 @@ +# Sphinx configuration for the Crow documentation +import os +import sys + +# Add the repo root to sys.path so autodoc can import the crow package +sys.path.insert(0, os.path.abspath("..")) + +project = "Crow" +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.autosummary", + "sphinx.ext.viewcode", +] + +autosummary_generate = True +napoleon_numpy_docstring = True + +# Prevent heavy/optional imports from breaking the build +autodoc_mock_imports = [ + "clmm", + "pyccl", + "numcosmo", + "scipy", + "crow.integrator.numcosmo_integrator", +] + +html_theme = "sphinx_rtd_theme" + +# Basic HTML options +html_static_path = ["_static"] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..7b99bd5 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,13 @@ +Crow documentation +================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + modules + +.. autosummary:: + :toctree: generated/ + + crow