Note
Go to the end to download the full example code.
RELAGN Spin Sweep¶
Demonstrate the effect of BH spin on the relativistic outer-disc SED using the RELAGN model (Hagen & Done 2023) with KYCONV Kerr-metric ray-tracing (Dovciak, Karas & Yaqoob 2004).
Higher spin → smaller ISCO → hotter inner-disc boundary → harder UV spectral slope. The UV slope α (where L_ν ∝ ν^α in 912–3000 Å) is a direct observable of the spin-dependent inner boundary condition.
Requires the precomputed grid data/relagn_disc_grid.h5.
import jax.numpy as jnp
import matplotlib.pyplot as plt
import numpy as np
from tengri.agn import resolve_agn_model
from tengri.analysis.plotting import setup_style
setup_style()
Wavelength grid: 100 Å (UV) to 3 µm (NIR)
wavelength = jnp.logspace(np.log10(100), np.log10(3e4), 800)
wave_aa = np.array(wavelength)
wave_um = wave_aa / 1e4
nu = 2.99792458e18 / wave_aa # Hz
# Fixed BH properties: 10^8.5 Msun, 0.3× Eddington
log_mbh = 8.5
log_mdot = -0.5
# Spin nodes — prograde range [0, 0.998]
astar_values = [0.0, 0.3, 0.6, 0.9, 0.998]
colors = plt.cm.plasma(np.linspace(0.1, 0.9, len(astar_values)))
Load RELAGN model from registry
try:
relagn_fn = resolve_agn_model("relagn")
except KeyError as exc:
raise SystemExit("relagn model not registered — rebuild grid first.") from exc
fig, (ax_sed, ax_slope) = plt.subplots(1, 2, figsize=(12, 5))
uv_slopes = []
for astar, color in zip(astar_values, colors):
l_nu = np.array(
relagn_fn(
wavelength,
agn_log_mbh=log_mbh,
agn_log_mdot=log_mdot,
agn_astar=float(astar),
agn_cos_inc=0.5,
agn_torus_frac=0.0, # disc only for clarity
)
)
mask = l_nu > 0
if not mask.any():
uv_slopes.append(np.nan)
continue
ax_sed.loglog(
wave_um[mask],
l_nu[mask],
lw=1.8,
color=color,
label=rf"$a_* = {astar:.3f}$",
)
# UV spectral slope: fit L_nu ~ nu^alpha in the 912–3000 Å band
uv = (wave_aa >= 912) & (wave_aa <= 3000) & mask
if uv.sum() > 5:
slope = np.polyfit(np.log10(nu[uv]), np.log10(l_nu[uv]), 1)[0]
else:
slope = np.nan
uv_slopes.append(slope)
ax_sed.set_xlabel(r"Wavelength [$\mu$m]")
ax_sed.set_ylabel(r"$L_\nu$ [erg s$^{-1}$ Hz$^{-1}$]")
ax_sed.set_title(rf"RELAGN outer disc: $\log M = {log_mbh}$, $\log \dot{{m}} = {log_mdot}$")
ax_sed.set_xlim(0.01, 3)
ax_sed.legend(frameon=False, fontsize=9)
Panel 2: UV spectral slope α vs spin α becomes less negative (harder) as spin increases because the shrinking ISCO pushes the inner-disc temperature blueward, contributing more flux at 912–3000 Å. α = d log L_ν / d log ν; Rayleigh-Jeans limit → α = +2.
ax_slope.plot(
astar_values,
uv_slopes,
"o-",
color="royalblue",
lw=2,
ms=7,
)
ax_slope.set_xlabel(r"BH spin $a_*$")
ax_slope.set_ylabel(r"UV slope $\alpha$ ($L_\nu \propto \nu^\alpha$, 912–3000 Å)")
ax_slope.set_title("Harder UV slope at high spin")
fig.tight_layout()
# Higher spin concentrates disc emission at smaller ISCO radii. KYCONV
# (Dovciak+2004) applies full Kerr ray-tracing per annulus up to r = 1000 Rg;
# the Novikov-Thorne outer disc uses the non-relativistic formula beyond that.
plt.savefig("plot_relagn_spin.png", dpi=150, bbox_inches="tight")
plt.show()