Skip to content

halocat.hmf

hmf

Halo mass function: differential dn/dlog10M and cumulative n(>M).

measure_hmf

measure_hmf(mass: ndarray, box_size: float, log10M_min: float, log10M_max: float, nbins: int) -> dict

Compute the halo mass function (differential + cumulative).

Parameters:

Name Type Description Default
mass array of halo masses (Msun/h, linear).
required
box_size periodic box side length (Mpc/h).
required
log10M_min log10(M) bin range.
required
log10M_max log10(M) bin range.
required
nbins number of bins.
required

Returns:

Type Description
dict with keys

log10M_bin_edges : (nbins+1,) bin edges in log10(M) log10M_bin_left : (nbins,) left edges of each bin log10M_bin_centre : (nbins,) bin centres counts : (nbins,) halo counts per bin dndlog10M : (nbins,) differential mass function n_gt_M : (nbins,) cumulative number density n(>M_left[i]) box_size : float

Source code in halocat/hmf.py
def measure_hmf(mass: np.ndarray, box_size: float,
                log10M_min: float, log10M_max: float,
                nbins: int) -> dict:
    """Compute the halo mass function (differential + cumulative).

    Parameters
    ----------
    mass : array of halo masses (Msun/h, linear).
    box_size : periodic box side length (Mpc/h).
    log10M_min, log10M_max : log10(M) bin range.
    nbins : number of bins.

    Returns
    -------
    dict with keys
        log10M_bin_edges  : (nbins+1,)  bin edges in log10(M)
        log10M_bin_left   : (nbins,)    left edges of each bin
        log10M_bin_centre : (nbins,)    bin centres
        counts            : (nbins,)    halo counts per bin
        dndlog10M         : (nbins,)    differential mass function
        n_gt_M            : (nbins,)    cumulative number density n(>M_left[i])
        box_size          : float
    """
    mass = np.asarray(mass)
    edges = np.linspace(log10M_min, log10M_max, nbins + 1)
    left = edges[:-1]
    centres = 0.5 * (edges[:-1] + edges[1:])
    dlog10M = np.diff(edges)

    log10m = np.log10(mass[mass > 0])
    counts, _ = np.histogram(log10m, bins=edges)

    volume = box_size ** 3
    dndlog10M = counts.astype(np.float64) / (dlog10M * volume)

    # Cumulative n(>M_left[i]): number density of haloes with M >= M_left[i].
    # Sum counts from bin i to the last bin, divided by volume.
    n_gt_M = np.cumsum(counts[::-1])[::-1].astype(np.float64) / volume

    return {
        "log10M_bin_edges": edges,
        "log10M_bin_left": left,
        "log10M_bin_centre": centres,
        "counts": counts,
        "dndlog10M": dndlog10M,
        "n_gt_M": n_gt_M,
        "box_size": float(box_size),
    }

write_hmf

write_hmf(hmf: dict, outpath: str, attrs: dict | None = None) -> None
Source code in halocat/hmf.py
def write_hmf(hmf: dict, outpath: str, attrs: dict | None = None) -> None:
    os.makedirs(os.path.dirname(outpath), exist_ok=True)
    with h5py.File(outpath, "w") as f:
        for k in ("log10M_bin_edges", "log10M_bin_left", "log10M_bin_centre",
                  "counts", "dndlog10M", "n_gt_M"):
            f.create_dataset(k, data=hmf[k])
        f.attrs["box_size"] = hmf["box_size"]
        f.attrs["volume"] = hmf["box_size"] ** 3
        f.attrs["mass_units"] = "Msun/h"
        f.attrs["dndlog10M_units"] = "(Mpc/h)^-3 / dlog10M"
        f.attrs["n_gt_M_units"] = "(Mpc/h)^-3"
        if attrs:
            for k, v in attrs.items():
                f.attrs[k] = v