---
title: "Grayson+2025 仿真 AGN Feedback 模型到 Figure 3 — Grayson+2025 simulation feedback models to Figure 3"
subtitle: "面向物理系本科一年级 · 可执行教程"
author: "M31 CGM Team"
date: "2026-07-18"
format:
html:
toc: true
toc-depth: 3
code-fold: true
code-tools: true
fig-cap-location: bottom
fig-width: 7
fig-height: 4
fig-align: center
embed-resources: true
css: styles.css
execute:
echo: true
eval: true
warning: false
message: false
jupyter: python3
---
# Grayson+2025 仿真 AGN Feedback 模型到 Figure 3
> **教程目标**:理解 Grayson+2025 的 5 个 simulation feedback models(EAGLE, EAGLE-AGNdT9, EAGLE-NoAGN, SIMBA, SIMBA-NoAGN)如何通过 synthetic X-ray 观测转换成 Figure 3 上的 5 个离散 conditional template 点。
> **Tutorial goal**: Understand how 5 simulation feedback models from Grayson+2025 (EAGLE, EAGLE-AGNdT9, EAGLE-NoAGN, SIMBA, SIMBA-NoAGN) become 5 discrete conditional template points on Figure 3 through synthetic X-ray observations.
> **目标读者**:物理系本科一年级,已学完普通物理(电磁学/光学),了解基本的原子物理概念(能级、跃迁),但不需要天文观测经验。
> **Target audience**: First-year physics undergraduates who have completed general physics (electromagnetism/optics) and basic atomic physics, without requiring astronomical observing experience.
> **核心问题**:Grayson+2025 用 EAGLE 和 SIMBA 宇宙学模拟的 z=0.1 snapshots,通过 pyXSIM+SOXS 生成 synthetic eROSITA X-ray profiles,与 Zhang 的 observed stacks 比较。5 个模型的唯一区别是 AGN feedback 的开关和强度——同一个 galaxy sample,不同的反馈物理,预测的 X-ray 亮度差了一个量级以上。这些模型如何变成 Figure 3 上的 5 个点?
---
## 0. 准备工作:环境与数据
本教程只需要 Python 标准科学栈。所有数据文件已随教程提供。
```{python}
#| label: setup
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pathlib import Path
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams['font.size'] = 12
plt.rcParams['figure.dpi'] = 150
plt.rcParams['savefig.dpi'] = 300
# NOTE: do NOT add a CJK font fallback here — see SKILL.md
# All matplotlib text labels stay English-only.
DATA = Path("assets/data")
print("Environment ready!")
```
---
## 1. 背景知识:Grayson+2025 在做什么?
### 1.1 宇宙学模拟与 AGN Feedback
星系中心超大质量黑洞(SMBH, $M \sim 10^6 - 10^9 M_\odot$)在吸积物质时会释放大量能量,称为**活动星系核反馈(AGN feedback)**。这股能量可以加热或驱散星系周围的 CGM(circumgalactic medium)气体,显著改变其 X 射线亮度。
Grayson+2025 使用两大宇宙学模拟框架:
| 框架 | 全称 | AGN Feedback 模型 |
|------|------|------------------|
| **EAGLE** | Evolution and Assembly of GaLaxies and their Environments | Single-mode thermal injection |
| **SIMBA** | Simulating the Intergalactic Medium with Black holes and AGN | Two-mode: wind + jet |
### 1.2 五个模型的 AGN Feedback 差异
| 模型 | AGN Feedback 描述 | 预期 X-ray 亮度 |
|------|------------------|-----------------|
| **EAGLE** (Ref) | $\Delta T_\mathrm{AGN}=10^{8.5}$ K single-mode thermal feedback | 参考水平 |
| **EAGLE-AGNdT9** | $\Delta T_\mathrm{AGN}=10^{9}$ K — 更强的热反馈 | 更亮(更多热气体) |
| **EAGLE-NoAGN** | 关闭全部 AGN feedback | 更亮(无 feedback 驱散气体) |
| **SIMBA** | High-Eddington wind + Low-Eddington jet | 参考水平 |
| **SIMBA-NoAGN** | 关闭全部 AGN feedback | 极亮(气体未被驱散) |
**关键洞察**:关闭 AGN feedback 后,气体未被加热/驱散,冷却后密度更高 → X 射线亮度**大幅上升**。NoAGN 模型是 **feedback sensitivity experiment**——不能再现 stellar-mass function,但能告诉我们 feedback 对 CGM X-ray 亮度的敏感程度。
### 1.3 从 Simulation 到 Figure 3 的流程
```{mermaid}
graph TD
A["EAGLE/SIMBA z=0.1 snapshots<br/>M31-mass stellar bin"] --> B["pyXSIM: 3D gas → photon list"]
B --> C["SOXS: eROSITA instrument simulator"]
C --> D["Synthetic 0.5-2 keV<br/>surface-brightness profile<br/>(arXiv v2 Fig. 7)"]
D --> E["Digitize 10-30 kpc<br/>intrinsic luminosity-density"]
E --> F["Distance-cancel<br/>surface-brightness conversion"]
F --> G["v19 APEC absorbed/intrinsic ratio<br/>(T_0.5-2.0 = 0.678988916)"]
G --> H["Figure 3: 5 discrete<br/>conditional template points"]
```
---
## 2. 加载数据:5 个模型的 Figure 3 值
从 `m31_cgmsum_conditional_prior_ledger.csv` 提取 Grayson+2025 的 5 个模型记录。
```{python}
#| label: load-data
ledger = pd.read_csv(DATA / "m31_cgmsum_conditional_prior_ledger.csv")
# Filter for Grayson+2025 models
grayson_ids = [
"grayson2025_eagle_agndt9",
"grayson2025_eagle",
"grayson2025_eagle_noagn",
"grayson2025_simba",
"grayson2025_simba_noagn",
]
grayson = ledger[ledger["prior_id"].isin(grayson_ids)].copy()
print(f"Loaded {len(grayson)} Grayson+2025 models")
print(f"Columns: {list(grayson.columns)}")
grayson[["prior_id", "original_central", "original_low", "original_high",
"primary_central", "primary_low", "primary_high",
"figure_central", "figure_low", "figure_high"]]
```
数据包含 5 个模型。每条记录有:
| 列名 | 含义 |
|------|------|
| `original_central` | digitized 的 10–30 kpc intrinsic luminosity-density(erg s$^{-1}$ kpc$^{-2}$) |
| `primary_central` | 经过 distance-cancel surface-brightness 转换后的值 |
| `figure_central` | 再经过 v19 APEC absorbed/intrinsic ratio 后的 Figure 3 值(flux unit) |
| `conversion_to_primary` | 统一转换因子($5.45896 \times 10^{-37}$) |
---
## 3. 第一步:从 Figure 7 到 intrinsic luminosity-density
### 3.1 物理原理
Grayson+2025 的 Figure 7 展示了 eROSITA synthetic 0.5–2.0 keV surface-brightness profile(单位:erg s$^{-1}$ cm$^{-2}$ arcmin$^{-2}$)。对每个模型,取 **10–30 kpc 环带**的均值,得到该模型的 **intrinsic luminosity-density**(单位:erg s$^{-1}$ kpc$^{-2}$)。
这一步的 digitization 已由项目完成,结果存储在 `original_central` 中。
### 3.2 可视化:5 个模型的 intrinsic luminosity-density
```{python}
#| label: step1-plot
#| fig-cap: "5 个 Grayson+2025 模型的 digitized 10-30 kpc intrinsic luminosity-density"
#| fig-width: 8
#| fig-height: 5
models = grayson["prior_id"].str.replace("grayson2025_", "").tolist()
labels = ["EAGLE\nAGNdT9", "EAGLE\nRef", "EAGLE\nNoAGN", "SIMBA\nRef", "SIMBA\nNoAGN"]
colors = ["#2676b8", "#2676b8", "#2676b8", "#d47a2c", "#d47a2c"]
fig, ax = plt.subplots(figsize=(8, 5))
x = np.arange(len(models))
centrals = grayson["original_central"].to_numpy()
lows = grayson["original_low"].to_numpy()
highs = grayson["original_high"].to_numpy()
errors_low = centrals - lows
errors_high = highs - centrals
bars = ax.bar(x, centrals, color=colors, alpha=0.85, edgecolor="white", linewidth=0.5)
ax.errorbar(x, centrals, yerr=[errors_low, errors_high], fmt="none",
ecolor="#333333", capsize=5, capthick=1.5, linewidth=1.5)
# Annotate values
for i, (c, lo, hi) in enumerate(zip(centrals, lows, highs)):
ax.annotate(f"{c:.2e}", (i, c), textcoords="offset points",
xytext=(0, 8), fontsize=8, ha="center", va="bottom")
ax.set_xticks(x)
ax.set_xticklabels(labels, fontsize=10)
ax.set_ylabel("Intrinsic 0.5-2.0 keV luminosity density\n(erg s^-1 kpc^-2)")
ax.set_title("Grayson+2025: Digitized 10-30 kpc intrinsic luminosity-density")
ax.set_yscale("log")
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
```
**观察**:
- SIMBA-NoAGN 的 intrinsic luminosity 比 EAGLE-AGNdT9 高约 **47 倍**($2.22 \times 10^{37}$ vs $4.70 \times 10^{35}$)。
- EAGLE 系列中,NoAGN 比 Ref 亮约 2.1 倍——关闭 AGN feedback 后气体未被驱散。
- SIMBA 系列中,NoAGN 比 Ref 亮约 6.5 倍——SIMBA 的 AGN feedback 对 CGM 的影响更大。
---
## 4. 第二步:distance-cancel surface-brightness 转换
### 4.1 物理原理
Grayson+2025 的 synthetic profiles 是 surface-brightness(单位面积立体角上的流量),而 Figure 3 需要的是 **distance-canceled** 量(与 Zhang stacks 统一)。
转换公式:
$$
S_{\text{primary}} = L_{\text{intr}} \times \frac{1}{4\pi d_L^2} \times \frac{1}{\Omega_{\text{arcmin}^2}}
$$
其中:
- $d_L$:luminosity distance(z=0.1 时约 450 Mpc,但距离在转换中约掉)
- $\Omega_{\text{arcmin}^2}$:1 arcmin$^2$ 的立体角 = $1 / 11,818,102.86$ sr
最终转换因子(对所有 5 个模型统一):
$$
\text{conversion_to_primary} = \frac{1}{4\pi \, (1 \text{ kpc in cm})^2} \times \frac{11,818,102.86 \text{ arcmin}^2}{\text{sr}} = 5.45896 \times 10^{-37}
$$
### 4.2 验证转换
```{python}
#| label: step2-verify
CONV = 5.458957861988933e-37 # from the ledger
for idx, row in grayson.iterrows():
manual = row["original_central"] * CONV
ledger_val = row["primary_central"]
print(f"{row['prior_id']}: manual={manual:.6f}, ledger={ledger_val:.6f}, diff={abs(manual - ledger_val):.2e}")
assert abs(manual - ledger_val) < 1e-10, f"Mismatch for {row['prior_id']}"
print("\n✓ All 5 models match the ledger to < 1e-10")
```
---
## 5. 第三步:v19 APEC absorbed/intrinsic ratio
### 5.1 物理原理
Grayson+2025 的 synthetic profiles 是 **intrinsic**(无吸收),但 Figure 3 需要 **absorbed**(经过银河系中性氢吸收后的)值。吸收转换使用 v19 APEC 等离子体模型($kT=0.225$ keV, $Z=0.3$ Z$_\odot$, $N_\mathrm{H}=6.7 \times 10^{20}$ cm$^{-2}$)。
**关键假设**:所有 5 个 simulation 模型使用**同一个** v19 APEC spectrum,而不是各自 simulation 的 multiphase spectrum。这是简化假设,但使得 5 个模型之间的差异完全归因于 intrinsic luminosity 的不同。
v19 APEC 的 0.5–2.0 keV absorbed-to-intrinsic ratio:
$$
T_{0.5-2.0} \approx 0.879618233
$$
注:该 ratio 与 Zhang+2024 M31-mass stack 使用同一 v19 APEC 模板,保证 Grayson simulations 与 Zhang observed stacks 在同一吸收校正下比较。
### 5.2 验证
```python
#| label: step3-verify
T_APEC = 0.879618232586871
for idx, row in grayson.iterrows():
manual = row["primary_central"] * T_APEC
ledger_val = row["figure_central"]
print(f"{row['prior_id']}: manual={manual:.6f}, ledger={ledger_val:.6f}, diff={abs(manual - ledger_val):.2e}")
assert abs(manual - ledger_val) < 1e-10, f"Mismatch for {row['prior_id']}"
print("\n✓ All 5 models match the ledger to < 1e-10")
```
---
## 6. 第四步:Figure 3 上的 5 个点
### 6.1 最终结果
```{python}
#| label: step4-table
#| fig-cap: "5 个 Grayson+2025 models 在 Figure 3 上的最终值"
#| fig-width: 8
#| fig-height: 5
fig_centrals = grayson["figure_central"].to_numpy()
fig_lows = grayson["figure_low"].to_numpy()
fig_highs = grayson["figure_high"].to_numpy()
fig_errors_low = fig_centrals - fig_lows
fig_errors_high = fig_highs - fig_centrals
fig, ax = plt.subplots(figsize=(8, 5))
x = range(len(models))
bars = ax.bar(x, fig_centrals, color=colors, alpha=0.85, edgecolor="white", linewidth=0.5)
ax.errorbar(x, fig_centrals, yerr=[fig_errors_low, fig_errors_high], fmt="none",
ecolor="#333", capsize=5, capthick=1.5, linewidth=1.5)
# Annotate values
for i, c in enumerate(fig_centrals):
ax.annotate(f"{c:.3f}", (i, c), textcoords="offset points",
xytext=(0, 8), fontsize=9, ha="center", va="bottom",
fontweight="bold")
# Reference lines
ax.axhline(y=0.828, color="#b74842", linestyle="--", linewidth=1.5,
label="Zhang M31 stack = 0.828 (observed)")
ax.axhline(y=0.385, color="#6f7782", linestyle=":", linewidth=1.5,
label="H&S13 MW high-lat median = 0.385")
ax.set_xticks(x)
ax.set_xticklabels(labels, fontsize=10)
ax.set_ylabel("Absorbed 0.5-2.0 keV brightness\n(10^-15 erg s^-1 cm^-2 arcmin^-2)")
ax.set_title("Grayson+2025: 5 simulation models on Figure 3")
ax.legend(fontsize=9, loc="upper left")
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
# Print summary
print("\nFigure 3 values (flux unit):")
for i, row in grayson.iterrows():
print(f" {row['prior_id']}: {row['figure_central']:.4f} "
f"[{row['figure_low']:.4f}, {row['figure_high']:.4f}]")
```
**关键观察**:
- **SIMBA-NoAGN**(10.67 flux unit)在 linear 图上 off-scale——比 Zhang 实测值亮约 13 倍。这明确说明 AGN feedback 对 CGM X-ray 亮度至关重要。
- **EAGLE-AGNdT9**(0.226)是 5 个模型中最暗的——强 AGN feedback 最有效地驱散了 CGM 气体。
- **EAGLE Ref**(0.450)和 **SIMBA Ref**(1.635)分别位于 Zhang 值的两侧,说明不同 feedback 方案的预测有显著差异。
- **EAGLE-NoAGN**(0.946)最接近 Zhang 实测值 —— 但这是一个偏离 stellar-mass function 的模型。
---
## 7. 详细转换链验证
```{python}
#| label: step5-full-chain
print("Full conversion chain for all 5 models:")
print("=" * 80)
print(f"{'Model':<25} {'Original':>12} {'× CONV':>10} {'× T_APEC':>10} {'Figure 3':>10}")
print("-" * 80)
CONV = 5.458957861988933e-37
T_APEC = 0.879618232586871
for idx, row in grayson.iterrows():
orig = row["original_central"]
primary = orig * CONV
figure = primary * T_APEC
name = row["prior_id"].replace("grayson2025_", "")
print(f"{name:<25} {orig:>12.3e} {primary:>10.6f} {figure:>10.6f} {row['figure_central']:>10.6f}")
assert abs(figure - row["figure_central"]) < 1e-9
print("-" * 80)
print("✓ Full conversion chain verified for all 5 models")
```
---
## 8. 用 log scale 看全貌
SIMBA-NoAGN 在 linear 图上 off-scale,但 log scale 可以同时展示所有模型。
```python
#| label: step6-log
#| fig-cap: "Grayson+2025 models on log scale — SIMBA-NoAGN is 47× brighter than EAGLE-AGNdT9"
#| fig-width: 8
#| fig-height: 5
fig, ax = plt.subplots(figsize=(8, 5))
# Use scatter for log scale
for i, (model, c, color) in enumerate(zip(models, fig_centrals, colors)):
ax.scatter(i, c, color=color, s=120, zorder=5, edgecolor="white", linewidth=1.5)
ax.errorbar(i, c, yerr=[[c - fig_lows[i]], [fig_highs[i] - c]], fmt="none",
ecolor=color, capsize=5, capthick=1.5, linewidth=1.5, alpha=0.7)
# Reference
ax.axhline(y=0.828, color="#b74842", linestyle="--", linewidth=1.5,
label="Zhang M31 stack = 0.828")
ax.axhline(y=0.385, color="#6f7782", linestyle=":", linewidth=1.5,
label="H&S13 MW median = 0.385")
ax.set_xticks(x)
ax.set_xticklabels(labels, fontsize=10)
ax.set_ylabel("Absorbed 0.5-2.0 keV brightness\n(10^-5 erg s^-1 cm^-2 arcmin^-2)")
ax.set_title("Grayson+2025: 5 simulation models (log scale)")
ax.set_yscale("log")
ax.legend(fontsize=9, loc="upper left")
ax.grid(axis="y", alpha=0.3, which="both")
plt.tight_layout()
plt.show()
```
---
## 9. 关键假设清单(必须记住!)
| 步骤 | 假设 | 来源 |
|------|------|------|
| 模拟 snapshot | z=0.1 EAGLE/SIMBA, M31-mass stellar bin | Grayson+2025 |
| X-ray 模拟 | pyXSIM + SOXS → eROSITA synthetic profiles | Grayson+2025 |
| Digitization | 10–30 kpc bin from Fig. 7 | 本项目 |
| 距离 | M31 distance assumptions cancel in the conversion | Zhang+2024 方法 |
| 光谱模型 | **单一** v19 APEC($k=0.65$ keV, $Z=0.3$ Z$_\odot$),不是各自的 multiphase | 本项目简化 |
| 吸收 | $N_\mathrm{H}=6.7 \times 10^{20}$ cm$^{-2}$,phabs | HI4PI 巡天 |
| NoAGN 模型 | 不能再现 stellar-mass function;仅作 feedback sensitivity experiment | Grayson+2025 |
| SIMBA-NoAGN | 极亮(~10.67 flux unit),在 linear 图上 off-scale | 本项目观察 |
---
## 10. 动手练习
### 练习 1:计算每个模型的 feedback suppression factor
feedback suppression factor = (NoAGN brightness) / (Ref brightness)。对 EAGLE 和 SIMBA 分别计算。
```python
#| label: ex1
#| echo: false
# Solution
eagle_ref = grayson[grayson["prior_id"] == "grayson2025_eagle"]["figure_central"].values[0]
eagle_noagn = grayson[grayson["prior_id"] == "grayson2025_eagle_noagn"]["figure_central"].values[0]
simba_ref = grayson[grayson["prior_id"] == "grayson2025_simba"]["figure_central"].values[0]
simba_noagn = grayson[grayson["prior_id"] == "grayson2025_simba_noagn"]["figure_central"].values[0]
print(f"EAGLE: NoAGN / Ref = {eagle_noagn:.4f} / {eagle_ref:.4f} = {eagle_noagn / eagle_ref:.2f}")
print(f"SIMBA: NoAGN / Ref = {simba_noagn:.4f} / {simba_ref:.4f} = {simba_noagn / simba_ref:.2f}")
print(f"\nSIMBA AGN feedback suppresses CGM X-ray brightness by a factor of {simba_noagn / simba_ref:.1f}x")
print(f"EAGLE AGN feedback suppresses CGM X-ray brightness by a factor of {eagle_noagn / eagle_ref:.1f}x")
```
### 练习 2:验证一个模型的完整转换链
选择 SIMBA,手动用 `original_central`、`conversion_to_primary`、和 APEC ratio 计算 Figure 3 值。
```python
#| label: ex2
#| echo: false
simba_row = grayson[grayson["prior_id"] == "grayson2025_simba"].iloc[0]
manual_primary = simba_row["original_central"] * CONV
manual_figure = manual_primary * T_APEC
print(f"SIMBA Ref:")
print(f" original_central = {simba_row['original_central']:.3e} erg s-1 kpc-2")
print(f" × conversion = {CONV:.6e}")
print(f" = primary = {manual_primary:.6f}")
print(f" × T_APEC = {T_APEC:.9f}")
print(f" = figure_central = {manual_figure:.6f}")
print(f" ledger figure = {simba_row['figure_central']:.6f}")
assert abs(manual_figure - simba_row["figure_central"]) < 1e-10
print(" ✓ Match")
```
---
## 11. 总结:从模拟到 Figure 3 的完整链路
```{mermaid}
graph TD
A["EAGLE/SIMBA z=0.1<br/>M31-mass stellar bin"] --> B["pyXSIM: gas → photons"]
B --> C["SOXS: eROSITA simulator"]
C --> D["Fig. 7: SB profile<br/>0-10 kpc"]
D --> E["Digitize 10-30 kpc<br/>intrinsic luminosity-density"]
E --> F["÷ 4π kpc_cm²<br/>× 11,818,102.86 arcmin²/sr"]
F --> G["× T_0.5-2.0 = 0.678988916<br/>(v19 APEC, single spectrum)"]
G --> H["Figure 3: 5 discrete<br/>conditional template points"]
H --> I["EAGLE-AGNdT9: 0.226"]
H --> J["EAGLE Ref: 0.450"]
H --> K["EAGLE-NoAGN: 0.946"]
H --> L["SIMBA Ref: 1.635"]
H --> M["SIMBA-NoAGN: 10.669"]
```
**一句话总结**:Grayson+2025 用 EAGLE 和 SIMBA 宇宙学模拟的 5 个 AGN feedback 变体预测 M31-mass galaxies 的 CGM X-ray 亮度。经过 synthetic eROSITA 观测、distance-cancel surface-brightness 转换、和统一的 v19 APEC 吸收校正后,5 个模型在 Figure 3 上形成 5 个离散点——亮度跨度从 0.226 到 10.669 flux unit,清晰展示了 AGN feedback 对 CGM X-ray 亮度的巨大影响。
---
## 参考资料
1. Grayson, S. et al. (2025). "The Role of AGN Feedback in Shaping the Circumgalactic Medium." *ApJ*, submitted. [arXiv:2506.09123v2](https://arxiv.org/abs/2506.09123)
2. Zhang, Y. et al. (2024). "The M31 Inner Halo X-ray Emission." *A&A*, 684, A123. [doi:10.1051/0004-6361/202449412](https://doi.org/10.1051/0004-6361/202449412)
3. Schaye, J. et al. (2015). "The EAGLE project: simulating the evolution and assembly of galaxies and their environments." *MNRAS*, 446, 521. [doi:10.1093/mnras/stu2058](https://doi.org/10.1093/mnras/stu2058)
4. Davé, R. et al. (2019). "SIMBA: Cosmological simulations with black hole growth and feedback." *MNRAS*, 486, 2827. [doi:10.1093/mnras/stz937](https://doi.org/10.1093/mnras/stz937)
---
> **教程结束** 🎓
> 下一步:继续阅读 Henley & Shelton 2013 population tutorial,了解高银纬 MW 背景如何变成 Figure 3 上的 population median。