似然函数
HIcosmo 提供丰富的观测数据似然函数,涵盖超新星、BAO、CMB、强引力透镜等多种宇宙学探针。所有似然函数都遵循统一的 API 设计,支持 JAX JIT 编译优化。
似然函数概览
类型 |
数据集 |
描述 |
|---|---|---|
超新星 Ia |
Pantheon+ (2022) |
1701 个 SNe Ia,红移 \(z < 2.3\) |
BAO |
DESI 2024 |
最新 BAO 约束,6 个红移 bin,默认使用 \(H_0 r_d\) 作为 nuisance |
BAO |
SDSS/BOSS DR12 |
经典 BAO 数据集 |
CMB |
Planck 2018 |
压缩距离先验 \((R, l_a, \omega_b h^2)\) |
强透镜 |
H0LiCOW |
6 个透镜系统的时延距离 |
强透镜 |
TDCOSMO |
层次贝叶斯分析,含 MST 效应 |
局部 H0 |
SH0ES |
造父变星距离阶梯 |
统一 API 设计
所有似然函数都遵循统一的接口设计:
**快捷接口**(推荐):
from hicosmo.likelihoods import SN_likelihood, BAO_likelihood
from hicosmo.models import LCDM
# 字符串指定数据集
sne = SN_likelihood(LCDM, "pantheon+")
bao = BAO_likelihood(LCDM, "desi2024") # 默认 H0_rd 模式
# 直接调用计算 log-likelihood
# 注意:BAO 需要 H0_rd nuisance 参数
log_L = sne(H0=70, Omega_m=0.3) + bao(H0=70, Omega_m=0.3, H0_rd=100)
**类接口**(高级用法):
from hicosmo.likelihoods import PantheonPlusLikelihood, DESI2024BAO
sne = PantheonPlusLikelihood(cosmology_class=LCDM)
bao = DESI2024BAO(cosmology_class=LCDM)
超新星 Ia (SNe Ia)
Pantheon+ 数据集
Pantheon+ (Brout et al. 2022) 包含 1701 个 Ia 型超新星,是目前最大的 SNe Ia 样本。
似然函数:
其中:
\(\Delta \boldsymbol{\mu} = \mu_{\rm obs} - \mu_{\rm theory}\)
\(\mu_{\rm theory} = 5 \log_{10}(d_L/\text{Mpc}) + 25\)
\(C\) 是完整协方差矩阵(统计 + 系统误差)
基本用法:
from hicosmo.likelihoods import SN_likelihood
from hicosmo.models import LCDM
# Pantheon+ (无 SH0ES Cepheid 标校)
sne = SN_likelihood(LCDM, "pantheon+", M_B="marginalize")
# Pantheon+SH0ES (含 Cepheid 标校)
sne_shoes = SN_likelihood(LCDM, "pantheon+shoes", M_B="marginalize")
# 计算 log-likelihood
log_L = sne(H0=70.0, Omega_m=0.3)
print(f"log L = {log_L:.2f}")
绝对星等处理:
超新星分析需要处理绝对星等 \(\mathcal{M}_B = M_B + 5\log_{10}(c/H_0) + 25\):
选项 |
说明 |
|---|---|
|
解析边际化(推荐,默认) |
|
作为自由参数采样 |
# 解析边际化 M_B (默认,推荐)
sne = SN_likelihood(LCDM, "pantheon+", M_B="marginalize")
log_L = sne(H0=70, Omega_m=0.3) # 无需提供 M_B
# M_B 作为自由参数
sne = SN_likelihood(LCDM, "pantheon+", M_B="free")
log_L = sne(H0=70, Omega_m=0.3, M_B=-19.3) # 需提供 M_B
高级选项:
from hicosmo.likelihoods import PantheonPlusLikelihood
sne = PantheonPlusLikelihood(
cosmology_class=LCDM,
include_shoes=True, # 使用 SH0ES Cepheid 数据
include_systematics=True, # 包含系统误差 (默认)
z_min=0.01, # 最小红移截断
z_max=None, # 最大红移截断
marginalize_M_B=True # 边际化绝对星等
)
BAO (重子声学振荡)
BAO 提供对 \(H(z) r_d\) 和 \(D_M(z)/r_d\) 的精确测量,是宇宙学距离阶梯的关键环节。
观测量
HIcosmo 支持以下 BAO 观测量:
观测量 |
物理含义 |
|---|---|
\(D_M/r_d\) |
横向共动距离 / 声音视界 |
\(D_H/r_d = c/(H(z) r_d)\) |
径向 Hubble 距离 / 声音视界 |
\(D_V/r_d\) |
球平均距离 \([z D_M^2 D_H]^{1/3} / r_d\) |
球平均距离:
可用数据集
数据集 |
年份 |
参考文献 |
|---|---|---|
|
2024 |
DESI Collaboration 2024 |
|
2017 |
Alam et al. 2017, MNRAS 470, 2617 |
|
2020 |
eBOSS Collaboration 2020 |
|
2017 |
Alam et al. 2017 |
|
2011 |
Beutler et al. 2011 |
DESI 2024
DESI 2024 提供 6 个红移 bin 的 BAO 测量:
from hicosmo.likelihoods import BAO_likelihood
from hicosmo.models import LCDM
bao = BAO_likelihood(LCDM, "desi2024")
# 计算 log-likelihood(需要提供 H0_rd nuisance 参数)
log_L = bao(H0=67.36, Omega_m=0.3, H0_rd=100.0)
print(f"DESI BAO log L = {log_L:.2f}")
声视界处理模式 (omega_b_mode):
BAO 测量约束的是 \(D_M/r_d\) 和 \(D_H/r_d\),其中声视界 \(r_d\) 依赖于 \(\Omega_b\)。 BAO 数据单独只能约束 \(H_0 r_d\) 这个组合量,而无法单独约束 \(H_0\)。
HIcosmo 提供多种处理模式:
模式 |
Nuisance 参数 |
说明 |
|---|---|---|
|
|
直接采样 \(H_0 r_d / (100\,{\rm km\,s^{-1}})\),推荐用于 BAO-only 分析 |
|
|
使用 BBN 先验 (\(\omega_b = 0.02218 \pm 0.00055\)) |
|
无 |
固定 \(\Omega_b\) 为 Planck 2018 值 (0.0493) |
使用示例:
from hicosmo.likelihoods import BAO_likelihood
from hicosmo.models import LCDM
# 默认模式:H0_rd 作为 nuisance parameter(推荐用于 BAO-only)
bao = BAO_likelihood(LCDM, "desi2024")
# nuisance: H0_rd, prior: [95, 110]
# 使用 BBN 先验
bao_bbn = BAO_likelihood(LCDM, "desi2024", omega_b_mode='bbn_prior')
# nuisance: Omega_b, 并对 Omega_b*h^2 施加 BBN 约束
# 固定 Omega_b(使用 Planck 值)
bao_fixed = BAO_likelihood(LCDM, "desi2024", omega_b_mode='fixed')
# 无 nuisance 参数
物理说明:
\(H_0 r_d\) 的典型值约 \(10000\,{\rm km\,s^{-1}}`(对应 :math:`H_0 \approx 70\),\(r_d \approx 147\,{\rm Mpc}\))。
H0_rd 参数定义为 \(H_0 r_d / (100\,{\rm km\,s^{-1}})\),数值约为 100。
红移分布:
红移 bin |
有效红移 |
观测量 |
|---|---|---|
BGS |
\(z = 0.30\) |
\(D_V/r_d\) |
LRG1 |
\(z = 0.51\) |
\(D_M/r_d, D_H/r_d\) |
LRG2 |
\(z = 0.71\) |
\(D_M/r_d, D_H/r_d\) |
LRG3+ELG |
\(z = 0.93\) |
\(D_M/r_d, D_H/r_d\) |
ELG |
\(z = 1.32\) |
\(D_M/r_d, D_H/r_d\) |
QSO |
\(z = 1.49\) |
\(D_M/r_d, D_H/r_d\) |
多数据集联合
from hicosmo.likelihoods import BAO_likelihood
# 单独使用
desi = BAO_likelihood(LCDM, "desi2024")
sdss = BAO_likelihood(LCDM, "sdss_dr12")
# 联合约束
log_L = desi(H0=67, Omega_m=0.3) + sdss(H0=67, Omega_m=0.3)
CMB 距离先验
Planck 2018
HIcosmo 使用 Planck 2018 压缩距离先验,包含三个观测量:
压缩似然观测量:
其中:
\(R = \sqrt{\Omega_m H_0^2} \, D_M(z_*) / c\):位移参数
\(l_a = \pi D_M(z_*) / r_s(z_*)\):声学尺度
\(\omega_b h^2 = \Omega_b h^2\):重子密度参数
\(z_* \approx 1090\) 是最后散射面红移。
Planck 2018 中心值:
观测量 |
值 |
说明 |
|---|---|---|
\(R\) |
1.7502 |
位移参数 |
\(l_a\) |
301.47 |
声学尺度 |
\(\omega_b h^2\) |
0.02236 |
重子密度 |
基本用法:
from hicosmo.likelihoods import Planck
from hicosmo.models import LCDM
cmb = Planck(LCDM)
# 需要提供 Omega_b
log_L = cmb(H0=67.36, Omega_m=0.315, Omega_b=0.049)
print(f"Planck log L = {log_L:.2f}")
注意:Planck 距离先验需要 Omega_b 参数。
强引力透镜
强引力透镜时延宇宙学提供独立于距离阶梯的 \(H_0\) 测量。
H0LiCOW
H0LiCOW (Wong et al. 2019) 使用 6 个透镜系统的时延距离约束 \(H_0\)。
时延距离:
其中 \(D_{\rm lens,source}\) 是透镜到源的角直径距离。
基本用法:
from hicosmo.likelihoods import H0LiCOW
from hicosmo.models import LCDM
lensing = H0LiCOW(LCDM)
log_L = lensing(H0=73.3, Omega_m=0.3)
print(f"H0LiCOW log L = {log_L:.2f}")
透镜系统:
系统名 |
\(z_{\rm lens}\) |
\(z_{\rm source}\) |
类型 |
|---|---|---|---|
B1608+656 |
0.630 |
1.394 |
KDE |
RXJ1131-1231 |
0.295 |
0.654 |
Skewed log-normal |
HE0435-1223 |
0.454 |
1.693 |
KDE |
SDSS1206+4332 |
0.745 |
1.789 |
KDE |
WFI2033-4723 |
0.661 |
1.662 |
KDE |
PG1115+080 |
0.311 |
1.722 |
KDE |
TDCOSMO
TDCOSMO 提供层次贝叶斯分析,正确处理质量面变换 (MST) 和恒星速度弥散的系统误差。
关键参数:
参数 |
默认值 |
描述 |
|---|---|---|
|
1.0 |
内部 MST 群体均值 |
|
0.05 |
内部 MST 散布 |
|
1.0 |
恒星各向异性均值 |
|
0.1 |
各向异性散布 |
基本用法:
from hicosmo.likelihoods import TDCOSMO
from hicosmo.models import LCDM
tdcosmo = TDCOSMO(LCDM)
# 获取 nuisance 参数
for p in tdcosmo.nuisance_parameters:
print(f"{p.name}: {p.value} ({p.prior['min']}, {p.prior['max']})")
# 计算 log-likelihood(含 nuisance 参数)
log_L = tdcosmo(
H0=73.0,
Omega_m=0.3,
lambda_int_mean=1.0,
a_ani_mean=1.0
)
SH0ES
SH0ES 提供基于造父变星的局部 \(H_0\) 测量。
from hicosmo.likelihoods import SH0ESLikelihood
from hicosmo.models import LCDM
shoes = SH0ESLikelihood(cosmology_class=LCDM)
log_L = shoes(H0=73.0)
print(f"SH0ES log L = {log_L:.2f}")
SH0ES 约束:
联合似然
HIcosmo 支持多种方式组合似然函数。
加法运算符
from hicosmo.likelihoods import SN_likelihood, BAO_likelihood, Planck
from hicosmo.models import LCDM
# 创建各似然
sne = SN_likelihood(LCDM, "pantheon+")
bao = BAO_likelihood(LCDM, "desi2024") # 默认 H0_rd 模式
cmb = Planck(LCDM)
# 联合似然 = 各似然之和
# 注意:BAO 需要 H0_rd,CMB 需要 Omega_b
params = {'H0': 67.36, 'Omega_m': 0.315, 'Omega_b': 0.049, 'H0_rd': 100.0}
log_L_joint = (
sne(**params) +
bao(**params) +
cmb(**params)
)
CombinedLikelihood 类
from hicosmo.likelihoods import CombinedLikelihood
joint = CombinedLikelihood([sne, bao, cmb])
log_L = joint(H0=67.36, Omega_m=0.315, Omega_b=0.049, H0_rd=100.0)
Nuisance 参数
某些似然函数包含需要采样的 nuisance 参数。
获取 Nuisance 参数
from hicosmo.likelihoods import BAO_likelihood, TDCOSMO
from hicosmo.models import LCDM
# BAO 默认使用 H0_rd 作为 nuisance 参数
bao = BAO_likelihood(LCDM, "desi2024")
for p in bao.nuisance_parameters:
print(f"{p.name}: {p.value}, prior: {p.prior}")
# 输出: H0_rd: 102.5, prior: {'dist': 'uniform', 'min': 95.0, 'max': 110.0}
# TDCOSMO 有多个 nuisance 参数
tdcosmo = TDCOSMO(LCDM)
for p in tdcosmo.nuisance_parameters:
print(f"{p.name}:")
print(f" Default: {p.value}")
print(f" Prior: {p.prior}")
print(f" LaTeX: {p.latex_label}")
Nuisance 参数自动收集:
在 MCMC 采样时,nuisance 参数会自动收集:
from hicosmo.samplers import MCMC
# 宇宙学参数
params = {
'H0': (70.0, 60.0, 80.0),
'Omega_m': (0.3, 0.1, 0.5),
}
# MCMC 自动从 likelihood 收集 nuisance 参数
mcmc = MCMC(params, tdcosmo)
samples = mcmc.run(num_samples=2000)
与 MCMC 结合
完整 MCMC 示例
from hicosmo import hicosmo
# 快捷 API:3 行完成
inf = hicosmo(
cosmology="LCDM",
likelihood=["sn", "bao", "cmb"],
free_params=["H0", "Omega_m"]
)
samples = inf.run()
inf.summary()
类接口示例
from hicosmo.likelihoods import SN_likelihood, BAO_likelihood
from hicosmo.samplers import MCMC
from hicosmo.models import LCDM
# 创建联合似然
sne = SN_likelihood(LCDM, "pantheon+")
bao = BAO_likelihood(LCDM, "desi2024")
def joint_likelihood(**params):
return sne(**params) + bao(**params)
# 配置 MCMC
params = {
'H0': (70.0, 60.0, 80.0),
'Omega_m': (0.3, 0.1, 0.5),
}
mcmc = MCMC(params, joint_likelihood, chain_name="sn_bao")
samples = mcmc.run(num_samples=4000, num_chains=4)
mcmc.print_summary()
Traced-Aware 接口
似然函数内部使用 traced-aware 接口与 NumPyro 兼容:
import numpyro
import numpyro.distributions as dist
from hicosmo.models import LCDM
def numpyro_model(z_obs, mu_obs, mu_err):
H0 = numpyro.sample('H0', dist.Uniform(60, 80))
Omega_m = numpyro.sample('Omega_m', dist.Uniform(0.1, 0.5))
params = {'H0': H0, 'Omega_m': Omega_m}
grid = LCDM.compute_grid_traced(z_obs, params)
d_L = grid['d_L']
mu_theory = 5 * jnp.log10(d_L) + 25
numpyro.sample('obs', dist.Normal(mu_theory, mu_err), obs=mu_obs)
性能优化
JIT 编译
所有似然函数的核心计算都经过 JAX JIT 编译:
# 首次调用:含编译
%timeit sne(H0=70, Omega_m=0.3) # ~100ms
# 后续调用:已编译
%timeit sne(H0=70, Omega_m=0.3) # ~1ms
协方差矩阵预计算
协方差矩阵逆在初始化时预计算:
# 协方差矩阵逆只计算一次
sne = PantheonPlusLikelihood() # 预计算 C^{-1}
# 后续调用直接使用
log_L = sne(H0=70, Omega_m=0.3)
性能基准
似然函数 |
首次调用 |
后续调用 |
数据量 |
|---|---|---|---|
Pantheon+ |
150 ms |
1.2 ms |
1701 SNe |
DESI BAO |
50 ms |
0.5 ms |
12 点 |
Planck |
30 ms |
0.3 ms |
3 点 |
添加自定义似然函数
HIcosmo 的基类设计使创建自定义似然函数变得非常简单。
最小实现
只需继承 Likelihood 并实现 log_likelihood 方法:
from hicosmo.likelihoods import Likelihood
from hicosmo.models import LCDM
import jax.numpy as jnp
class MyDistanceModulusLikelihood(Likelihood):
"""自定义距离模数似然函数示例。"""
def __init__(self, cosmology_class=LCDM, **kwargs):
super().__init__(**kwargs)
self._cosmology_class = cosmology_class
# 你的观测数据
self.z_data = jnp.array([0.5, 1.0, 1.5, 2.0])
self.mu_obs = jnp.array([42.5, 44.1, 45.2, 46.0])
self.sigma = jnp.array([0.1, 0.15, 0.12, 0.18])
def log_likelihood(self, model, **kwargs):
"""计算 log-likelihood。
Parameters
----------
model : CosmologyBase
宇宙学模型实例(自动从参数构建)
**kwargs
附加参数(如 nuisance 参数)
Returns
-------
float
Log-likelihood 值
"""
mu_theory = model.distance_modulus(self.z_data)
chi2 = jnp.sum(((self.mu_obs - mu_theory) / self.sigma)**2)
return -0.5 * chi2
# 使用
my_lik = MyDistanceModulusLikelihood()
log_L = my_lik(H0=70, Omega_m=0.3) # 宇宙学模型自动构建
关键点:
设置
self._cosmology_class使基类自动构建宇宙学模型log_likelihood(model, **kwargs)接收已构建的模型实例无需重写
__call__、__add__等方法,基类已提供
含 Nuisance 参数
添加需要采样的 nuisance 参数:
from hicosmo.likelihoods import Likelihood, NuisanceList
from hicosmo.parameters import Parameter
from hicosmo.models import LCDM
import jax.numpy as jnp
class SNeLikelihoodWithMB(Likelihood):
"""含绝对星等 nuisance 参数的超新星似然。"""
def __init__(self, cosmology_class=LCDM, **kwargs):
super().__init__(**kwargs)
self._cosmology_class = cosmology_class
# 观测数据
self.z_data = jnp.array([0.1, 0.3, 0.5, 0.8, 1.0])
self.m_obs = jnp.array([23.5, 26.2, 27.8, 29.1, 29.8]) # 视星等
self.sigma = jnp.array([0.15, 0.12, 0.10, 0.12, 0.15])
@property
def nuisance_parameters(self):
"""声明 nuisance 参数。
MCMC 采样器会自动收集这些参数并采样。
"""
return NuisanceList([
Parameter(
name='M_B',
value=-19.3,
free=True,
prior={'dist': 'uniform', 'min': -20.0, 'max': -18.0},
latex_label=r'$\mathcal{M}_B$',
description='SNe Ia 绝对星等'
)
])
def log_likelihood(self, model, M_B=-19.3, **kwargs):
"""计算 log-likelihood。
Parameters
----------
model : CosmologyBase
宇宙学模型实例
M_B : float
绝对星等(nuisance 参数)
"""
mu_theory = model.distance_modulus(self.z_data)
m_theory = mu_theory + M_B
chi2 = jnp.sum(((self.m_obs - m_theory) / self.sigma)**2)
return -0.5 * chi2
# 使用
sne = SNeLikelihoodWithMB()
# 获取 nuisance 参数信息
for p in sne.nuisance_parameters:
print(f"{p.name}: {p.value}, prior: {p.prior}")
# MCMC 自动采样 nuisance 参数
from hicosmo.samplers import MCMC
params = {
'H0': (70.0, 60.0, 80.0),
'Omega_m': (0.3, 0.1, 0.5),
}
mcmc = MCMC(params, sne) # M_B 自动加入采样
samples = mcmc.run(num_samples=2000)
联合似然
自定义似然可与内置似然组合:
from hicosmo.likelihoods import BAO_likelihood
# 组合自定义 + 内置
my_lik = MyDistanceModulusLikelihood()
bao = BAO_likelihood(LCDM, "desi2024")
joint = my_lik + bao
# MCMC 采样
mcmc = MCMC(params, joint)
samples = mcmc.run()
使用协方差矩阵
对于需要完整协方差矩阵的似然:
class CorrelatedDataLikelihood(Likelihood):
"""带协方差矩阵的似然函数。"""
def __init__(self, cosmology_class=LCDM, **kwargs):
super().__init__(**kwargs)
self._cosmology_class = cosmology_class
# 数据
self.z_data = jnp.array([0.3, 0.5, 0.7, 0.9])
self.obs = jnp.array([1.02, 1.05, 1.08, 1.12])
# 协方差矩阵
cov = jnp.array([
[0.01, 0.002, 0.001, 0.0],
[0.002, 0.012, 0.003, 0.001],
[0.001, 0.003, 0.015, 0.002],
[0.0, 0.001, 0.002, 0.018]
])
self.inv_cov = jnp.linalg.inv(cov)
def log_likelihood(self, model, **kwargs):
# 理论预测
theory = model.E_z(self.z_data)
# 带协方差的 chi2
diff = self.obs - theory
chi2 = diff @ self.inv_cov @ diff
return -0.5 * chi2
高级:JIT 编译优化
对于性能关键的似然,使用 traced 接口:
from jax import jit
import jax.numpy as jnp
class FastTracedLikelihood(Likelihood):
"""使用 traced 接口的高性能似然。"""
def __init__(self, cosmology_class=LCDM, **kwargs):
super().__init__(**kwargs)
self._cosmology_class = cosmology_class
self.z_data = jnp.array([0.1, 0.3, 0.5, 0.7, 1.0, 1.5, 2.0])
self.mu_obs = jnp.array([38.5, 41.2, 42.8, 43.9, 44.9, 46.1, 46.8])
self.sigma = jnp.array([0.1, 0.1, 0.1, 0.1, 0.15, 0.15, 0.2])
# 预编译 JIT 函数
self._build_jit_loglike()
def _build_jit_loglike(self):
z = self.z_data
mu_obs = self.mu_obs
sigma = self.sigma
cosmo_class = self._cosmology_class
@jit
def _loglike_impl(params):
# 使用 traced 接口直接计算
grid = cosmo_class.compute_grid_traced(z, params)
d_L = grid['d_L']
mu_theory = 5 * jnp.log10(d_L) + 25
chi2 = jnp.sum(((mu_obs - mu_theory) / sigma)**2)
return -0.5 * chi2
self._loglike_jit = _loglike_impl
def __call__(self, **params):
# 准备 JAX 参数
params_jax = self._prepare_params_for_jax(params)
return self._loglike_jit(params_jax)
设计原则
创建自定义似然时,请遵循以下原则:
只覆盖必要的方法 - 必须:
__init__和log_likelihood- 可选:nuisance_parameters(如有 nuisance 参数)使用 JAX 数组 - 数据存储使用
jnp.array- 计算使用 JAX 函数设置 cosmology_class -
self._cosmology_class = cosmology_class- 使基类__call__自动构建模型勿重复造轮子 -
__add__/__radd__已由基类提供 - 协方差处理可用_prepare_params_for_jaxnuisance 参数必须有 LaTeX 标签 - 用于绘图显示 - 见
nuisance-parameters.md规范
常见模式
BAO 类型(观测量 / r_d):
def log_likelihood(self, model, **kwargs):
DM = model.transverse_comoving_distance(self.z)
DH = model.hubble_distance(self.z)
rd = model.sound_horizon_drag()
DM_rd_theory = DM / rd
DH_rd_theory = DH / rd
chi2 = ...
return -0.5 * chi2
CMB 距离先验类型:
def log_likelihood(self, model, **kwargs):
z_star = model.recombination_redshift()
DA = model.angular_diameter_distance(z_star)
rs = model.sound_horizon(z_star)
# 计算 R, l_a 等
...
强透镜类型:
def log_likelihood(self, model, **kwargs):
Ddt = model.time_delay_distance(z_lens, z_source)
# 与观测 Ddt 比较
...