计算宇宙学与数值模拟

宇宙学核心课程 · 大学前沿篇

第一章:N 体模拟

1.1 引力 N 体问题

import numpy as np

class NBodySimulation:
    """
    N 体引力模拟
    
    用于模拟宇宙大尺度结构形成
    """
    
    def __init__(self, n_particles=1000, box_size=100.0):
        self.n_particles = n_particles
        self.box_size = box_size
        
        # 初始化粒子
        self.positions = np.random.uniform(0, box_size, (n_particles, 3))
        self.velocities = np.zeros((n_particles, 3))
        self.masses = np.ones(n_particles) / n_particles
        
        # 物理常数
        self.G = 1.0  # 引力常数(归一化)
        self.softening = 0.1  # 软化长度(避免奇点)
    
    def compute_forces(self):
        """
        计算所有粒子间的引力
        
        复杂度:O(N²)
        优化:Barnes-Hut 算法 O(N log N)
        """
        forces = np.zeros((self.n_particles, 3))
        
        for i in range(self.n_particles):
            for j in range(i + 1, self.n_particles):
                # 位置差
                r_vec = self.positions[j] - self.positions[i]
                r = np.linalg.norm(r_vec) + self.softening
                
                # 引力大小
                F = self.G * self.masses[i] * self.masses[j] / r**3
                
                # 力的方向
                force = F * r_vec
                
                # 牛顿第三定律
                forces[i] += force
                forces[j] -= force
        
        return forces
    
    def leapfrog_step(self, dt):
        """
        Leapfrog 积分(辛积分器)
        
        优点:能量守恒好,适合长时间模拟
        """
        # 半步速度更新
        forces = self.compute_forces()
        accelerations = forces / self.masses[:, np.newaxis]
        self.velocities += 0.5 * dt * accelerations
        
        # 全步位置更新
        self.positions += dt * self.velocities
        
        # 半步速度更新
        forces = self.compute_forces()
        accelerations = forces / self.masses[:, np.newaxis]
        self.velocities += 0.5 * dt * accelerations
    
    def run(self, n_steps, dt=0.01):
        """运行模拟"""
        for step in range(n_steps):
            self.leapfrog_step(dt)
            
            if step % 100 == 0:
                print(f"Step {step}/{n_steps}")
        
        return self.positions, self.velocities

1.2 Barnes-Hut 算法

Barnes-Hut 算法优化:

思想:
├── 将空间划分为八叉树
├── 远处粒子群用质心近似
├── 近处粒子精确计算
└── 复杂度:O(N log N)

树结构:
├── 根节点:包含所有粒子
├── 每个节点最多 8 个子节点
├── 叶节点:包含单个粒子
└── 内部节点:存储质心和总质量

力计算:
├── 对于每个粒子
├── 遍历树
├── 如果节点足够远(s/d < θ)→ 用质心
├── 否则 → 递归进入子节点
└── θ 典型值:0.5~1.0

第二章:宇宙微波背景模拟

2.1 CMB 功率谱计算

import numpy as np
from scipy.integrate import quad

class CMBSpectrum:
    """
    CMB 温度功率谱计算
    
    基于 Boltzmann 方程
    """
    
    def __init__(self, cosmology):
        self.cosmo = cosmology
    
    def transfer_function(self, k, ell):
        """
        转移函数
        
        描述初始扰动如何演化为 CMB 各向异性
        """
        # 简化模型
        k_eq = 0.073  # 物质-辐射平衡尺度
        
        # 声波振荡
        sound_horizon = 147.0  # Mpc
        acoustic_scale = ell * sound_horizon / 1000
        
        # 转移函数近似
        T = np.cos(acoustic_scale) * np.exp(-k / k_eq)
        
        return T
    
    def compute_power_spectrum(self, ell):
        """
        计算 C_ell
        
        C_ell = (2/π) ∫ k² P(k) |T_ell(k)|² dk
        """
        # 原初功率谱
        def integrand(k):
            P_k = k ** 0.965  # 标量谱指数
            T = self.transfer_function(k, ell)
            return k**2 * P_k * T**2
        
        result, _ = quad(integrand, 1e-4, 1, limit=100)
        
        return (2 / np.pi) * result
    
    def plot_spectrum(self, ell_range=range(2, 2500)):
        """绘制功率谱"""
        ells = list(ell_range)
        C_ells = [self.compute_power_spectrum(ell) for ell in ells]
        
        return ells, C_ells

第三章:引力波数据分析

3.1 匹配滤波

import numpy as np
from scipy import signal

class GravitationalWaveAnalysis:
    """
    引力波数据分析
    
    应用:LIGO/Virgo 数据
    """
    
    def __init__(self, sample_rate=4096):
        self.fs = sample_rate
    
    def generate_waveform(self, m1, m2, distance, duration=2.0):
        """
        生成双黑洞并合波形模板
        
        参数:
            m1, m2: 两个黑洞质量(太阳质量)
            distance: 距离(Mpc)
        """
        t = np.linspace(0, duration, int(self.fs * duration))
        
        # 啁啾质量
        M_chirp = (m1 * m2)**(3/5) / (m1 + m2)**(1/5)
        
        # 频率演化(后牛顿近似)
        f_gw = (1 / (8 * np.pi * M_chirp)) * (5 * M_chirp / (t + 1))**(3/8)
        
        # 相位
        phase = 2 * np.pi * np.cumsum(f_gw) / self.fs
        
        # 振幅
        amplitude = (M_chirp / distance) * f_gw**(2/3)
        
        # 波形
        h = amplitude * np.cos(phase)
        
        return t, h
    
    def matched_filter(self, data, template):
        """
        匹配滤波
        
        从噪声中提取已知波形的信号
        """
        # 傅里叶变换
        data_fft = np.fft.fft(data)
        template_fft = np.fft.fft(template)
        
        # 互相关
        cross_corr = np.fft.ifft(data_fft * np.conj(template_fft))
        
        # 信噪比
        snr = np.abs(cross_corr) / np.std(cross_corr)
        
        return snr
    
    def detect_event(self, data, threshold=8.0):
        """
        检测引力波事件
        
        参数:
            threshold: 检测阈值(信噪比)
        """
        # 生成模板库
        templates = []
        for m1 in np.linspace(10, 50, 10):
            for m2 in np.linspace(10, 50, 10):
                _, h = self.generate_waveform(m1, m2, distance=100)
                templates.append(h)
        
        # 对每个模板计算信噪比
        max_snr = 0
        for template in templates:
            snr = self.matched_filter(data, template)
            max_snr = max(max_snr, np.max(snr))
        
        # 判断是否检测到
        detected = max_snr > threshold
        
        return detected, max_snr

第四章:机器学习用于宇宙学

4.1 用 CNN 估计宇宙学参数

import torch
import torch.nn as nn

class CosmoParameterEstimator(nn.Module):
    """
    用 CNN 从 CMB 图估计宇宙学参数
    
    输入:CMB 温度图
    输出:Ω_m, Ω_Λ, H₀, n_s, σ₈
    """
    
    def __init__(self, n_params=5):
        super().__init__()
        
        # CNN 特征提取
        self.features = nn.Sequential(
            nn.Conv2d(1, 32, 3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            
            nn.Conv2d(32, 64, 3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            
            nn.Conv2d(64, 128, 3, padding=1),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d(4),
        )
        
        # 回归头
        self.regressor = nn.Sequential(
            nn.Linear(128 * 4 * 4, 256),
            nn.ReLU(),
            nn.Dropout(0.3),
            nn.Linear(256, n_params)
        )
    
    def forward(self, x):
        """
        x: (batch, 1, height, width) CMB 图
        """
        features = self.features(x)
        features = features.view(features.size(0), -1)
        params = self.regressor(features)
        
        return params
    
    def training_step(self, batch, optimizer):
        """训练步骤"""
        cmb_maps, true_params = batch
        
        # 预测
        pred_params = self(cmb_maps)
        
        # 损失(MSE)
        loss = torch.nn.functional.mse_loss(pred_params, true_params)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        return loss.item()

课后项目

项目 1:N 体模拟

# 运行简单的 N 体模拟
sim = NBodySimulation(n_particles=100)
positions, velocities = sim.run(n_steps=1000, dt=0.01)

# 可视化
import matplotlib.pyplot as plt
plt.scatter(positions[:, 0], positions[:, 1], s=1)
plt.show()

项目 2:引力波信号检测

# 生成模拟数据(噪声 + 信号)
t, signal = gw.generate_waveform(m1=30, m2=30, distance=100)
noise = np.random.normal(0, 1e-21, len(signal))
data = signal + noise

# 检测
detected, snr = gw.detect_event(data)
print(f"Detected: {detected}, SNR: {snr:.2f}")

前沿论文推荐

  • Springel (2005) - "The Cosmological Simulation Code GADGET-2"
  • Planck Collaboration (2020) - "Planck 2018 results"
  • Abbott et al. (2016) - "Observation of Gravitational Waves from a Binary Black Hole Merger"
  • He et al. (2023) - "Deep Learning for Cosmological Parameter Estimation"

参考资源:
- GADGET N-body code
- CAMB Boltzmann code
- LIGO Open Science Center
- CosmoML