HOD Fitting Module
The hod_mod.fitting module provides two-stage HOD fitting of observed galaxy
clustering data: a fast MAP estimate via Nelder-Mead optimisation, followed by an
MCMC posterior exploration with emcee.
—
Statistical framework
Given observed \(w_p\) values \(\mathbf{d}\) with covariance matrix \(\mathbf{C}\), the log-likelihood under a Gaussian noise model is
where \(\mathbf{m}(\boldsymbol{\theta})\) is the model prediction for parameter vector \(\boldsymbol{\theta}\). In terms of a reduced chi-squared:
where \(\nu = N_{\rm data} - N_{\rm free}\) is the number of degrees of freedom.
The log-posterior is
where \(\ln\pi(\boldsymbol{\theta})\) is the log-prior (see Prior distributions below).
Covariance matrix
When data are loaded from a sum_stat HDF5 file, the full covariance matrix from the
file is used. A 1% diagonal regularisation is applied before inversion to guard against
numerical singularities:
When data are loaded from a CSV file (legacy), only diagonal errors are available and \(C_{ij} = \sigma_i^2 \delta_{ij}\).
Prior distributions
Uniform prior (default for HOD parameters)
For each free parameter \(\theta_i\) with bounds \([l_i, u_i]\):
Gaussian prior (optional, for cosmological parameters)
For each parameter with Gaussian prior \(\mathcal{N}(\mu_i, \sigma_i^2)\):
where hard bounds \([l_i, u_i]\) are applied in addition. When
param_prior_types[name] = "gaussian" the fitter adds this term on top of the
chi-squared.
—
Planck 2018 cosmological prior
(hod_mod.fitting.planck_prior)
The Planck 2018 TT,TE,EE+lowE best-fit values and 1σ uncertainties
(Planck Collaboration 2020, Table 2) [PlanckCollaboration2018] are
encoded in PLANCK18_MEANS and PLANCK18_SIGMAS:
Parameter |
Symbol |
Best-fit |
1σ |
3σ range |
|---|---|---|---|---|
Hubble constant |
\(h\) |
0.6736 |
0.0054 |
[0.6574, 0.6898] |
Matter density |
\(\Omega_m\) |
0.3153 |
0.0073 |
[0.2934, 0.3372] |
Baryon density |
\(\Omega_b\) |
0.0493 |
0.0006 |
[0.0475, 0.0511] |
Spectral index |
\(n_s\) |
0.9649 |
0.0042 |
[0.9523, 0.9775] |
Log amplitude |
\(\ln 10^{10}A_s\) |
3.044 |
0.014 |
[3.002, 3.086] |
\(\sigma_8\) |
\(\sigma_8\) |
0.8111 |
0.0060 |
[0.7931, 0.8291] |
The 3σ bounds are used as hard truncation limits for the Gaussian priors. The
function planck18_log_prior(theta) returns the sum of all Gaussian log-prior terms;
it returns \(-\infty\) if any parameter is outside its 3σ range.
Usage in fitting scripts:
from hod_mod.fitting.planck_prior import PLANCK18_MEANS, PLANCK18_SIGMAS
from hod_mod.fitting import WpFitConfig, WpFitter
cfg = WpFitConfig(
...
param_prior_types = {"h": "gaussian", "Omega_m": "gaussian"},
param_prior_means = {"h": PLANCK18_MEANS["h"],
"Omega_m": PLANCK18_MEANS["Omega_m"]},
param_prior_sigmas = {"h": PLANCK18_SIGMAS["h"],
"Omega_m": PLANCK18_SIGMAS["Omega_m"]},
)
—
MAP estimation
WpFitter.map_fit() minimises \(-\ln P\) using the Nelder-Mead simplex
algorithm (via scipy.optimize.minimize). Nelder-Mead is gradient-free and robust
to the discontinuous derivatives that arise from hard prior bounds. The result is the
MAP (maximum a posteriori) point estimate.
A good starting point is critical: param_init in the config should be set to a
physically plausible value (e.g. set log10mmin close to the expected characteristic
halo mass for the sample).
—
MCMC posterior sampling
WpFitter.mcmc_fit() uses the emcee ensemble
sampler (Foreman-Mackey et al. 2013) [Foreman-Mackey2013]. The
default configuration uses 64 walkers initialised in a Gaussian ball around the MAP
estimate.
Convergence diagnostics:
Acceptance fraction: should be between 0.2 and 0.5. If too low, the proposal scale
movesparameter needs tuning.Integrated autocorrelation time \(\hat{\tau}\): the chain is considered converged when the number of steps exceeds \(50\hat{\tau}\). Access via
sampler.get_autocorr_time().Gelman-Rubin statistic \(\hat{R}\): for multi-chain runs, \(\hat{R} < 1.1\) indicates convergence.
—
Configuration
Fitting is driven by a WpFitConfig dataclass (or equivalently a YAML file parsed
by load_config):
data_file: /path/to/data.h5
data_format: hdf5 # "csv" or "hdf5"
rp_min: 0.3 # Mpc/h
rp_max: 30.0 # Mpc/h
hod_model: MoreHODModel
hmf_backend: csst # pipeline baseline (default if omitted); use
# tinker08 to reproduce literature results
z: 0.15
pi_max: 100.0 # Mpc/h
free_params: [log10mmin, sigma_logm, log10m1, alpha]
param_bounds:
log10mmin: [11.0, 13.5]
sigma_logm: [0.1, 1.0]
log10m1: [12.0, 15.0]
alpha: [0.5, 2.0]
param_init:
log10mmin: 12.5
sigma_logm: 0.38
log10m1: 13.5
alpha: 1.0
kappa: 1.0
alpha_inc: 1.0
log10m_inc: 12.0
# Optional: Gaussian cosmological priors
param_prior_types: {h: gaussian}
param_prior_means: {h: 0.6736}
param_prior_sigmas: {h: 0.0054}
output_dir: results/bgs_ls10/mstar10.5/
—
Usage example
from hod_mod.fitting import WpFitter, load_config
cfg = load_config("configs/hod_fit_more2015_cmass.yml")
fitter = WpFitter(cfg)
result = fitter.map_fit() # Nelder-Mead MAP estimate
print(result.x, result.fun)
sampler = fitter.mcmc_fit() # emcee MCMC posterior
flat = sampler.get_chain(flat=True, discard=100, thin=5)
HOD fitting: MAP + MCMC via emcee, unified FitConfig, Planck 2018 prior.
Planck 2018 cosmological priors for HOD fitting.
Provides best-fit values, 1σ uncertainties, and 3σ flat bounds from the Planck 2018 primary CMB analysis (TT,TE,EE+lowE likelihood, Table 2).
Reference
Planck Collaboration 2020, A&A 641, A6 https://arxiv.org/abs/1807.06209
The primary parameters and their 68% confidence intervals are:
The 3σ flat bounds are \([\mu - 3\sigma, \mu + 3\sigma]\).
Usage in YAML config
Set prior_type: gaussian for any cosmological parameter to activate the
Gaussian prior. The bounds field is still required and acts as hard
clipping beyond which the log-prior returns -inf:
parameters:
h:
free: true
init: 0.6736
bounds: [0.6574, 0.6898] # 3σ hard bounds
prior_type: gaussian
prior_mean: 0.6736
prior_sigma: 0.0054
- hod_mod.fitting.planck_prior.gaussian_log_prior(val: float, mean: float, sigma: float, lo: float = -inf, hi: float = inf) float[source]
Gaussian log-prior for a single parameter.
\[\ln \pi(\theta) = -\frac{1}{2} \left( \frac{\theta - \mu}{\sigma} \right)^2\]Returns
-infifvalis outside[lo, hi](hard bounds).- Parameters:
val (float)
mean, sigma (float) – Gaussian mean and standard deviation.
lo, hi (float) – Hard bounds (uniform outside returns -inf).
- hod_mod.fitting.planck_prior.planck18_log_prior(theta: dict, params: list | None = None) float[source]
Sum of Gaussian log-prior terms for Planck 2018 cosmological parameters.
\[\ln \pi(\theta) = -\frac{1}{2} \sum_i \left( \frac{\theta_i - \mu_i}{\sigma_i} \right)^2\]- Parameters:
theta (dict) – Parameter dict. Only keys present in
PLANCK18_MEANScontribute.params (list of str, optional) – Restrict to these parameters only. Default: all keys in
PLANCK18_MEANSthat also appear intheta.
- Returns:
float – Log-prior value. Returns
-infif any parameter is outside its 3σ hard bounds.
—
Key references
Lensing and galaxy–matter cross-correlation: [BartelmannSchneider2001], [Mandelbaum2005], [Mandelbaum2006], [Leauthaud2017], [Miyatake2022], [Lange2023], [Heydenreich2025], [Lange2025].
Intrinsic alignments: [Catelan2001], [HirataSeljak2004], [Brown2002], [BridleKing2007], [Blazek2019], [DESI_KP6].
Surveys: [Blanton2003], [BOSS_CMASS], [HSC_Aihara2018], [HSC_Mandelbaum2018], [KiDS_Heymans2021], [DES_Abbott2022], [DESI_EDR], [DESI_BGS_Hahn2023], [Comparat2023], [Lange2024], [Lange2025phz].
Inference: [Phan2019].