State-space modelling of X-ray spectral variability in AGNs and X-ray binaries using AR(1) latent dynamics, a forward spectral model under Poisson statistics, and HMC inference via NumPyro.
TeX
0
77 commits
updated Aug 21, 2026
State-space modelling of X-ray spectral variability in Active Galactic Nuclei (AGNs) and X-ray binaries (XRBs). The framework links observed photon count time series to two latent physical parameters --- hydrogen column density NH(t) and coronal height h_c(t) --- each modelled as an AR(1) stochastic process. Posterior inference is performed using Hamiltonian Monte Carlo (HMC/NUTS) implemented in NumPyro.
X-ray variability in AGNs arises from two sources:
| Source | Physical origin | Model component |
|---|---|---|
| Intrinsic | Coronal fluctuations | Power-law normalisation φ(t) |
| External | Absorbing winds / outflows | Hydrogen column density NH(t) |
This pipeline models both simultaneously by embedding an AR(1) stochastic process for each parameter inside a full X-ray spectral forward model:
F(E, t) = ZPOWERLW(E; γ, φ(t)) × ZWABS(E; NH(t)) × WABS(E; NH_gal)
Photon counts are then predicted by folding F through the instrument ARF and RMF, and a Poisson likelihood connects the model to observed counts:
λᵢ(t) = Σⱼ F(Eⱼ, t) · Δt · ΔEⱼ · ARFⱼ · RMFⱼᵢ
Cᵢ(t) ~ Poisson(λᵢ(t))
See Buchner & Boorman (2023) for the theoretical background.
.
├── src/
│ ├── photo_electric_absorption.py # Morrison & McCammon (1983) cross-sections
│ ├── ar1_process_generator.py # AR(1) stochastic process generators
│ ├── count_simulator.py # X-ray count spectrum simulator
│ ├── generate_synthetic_data.py # Grid-search synthetic data generation
│ ├── run_inference.py # HMC/NUTS Bayesian inference
│ └── visualise_results.py # Posterior trace and histogram plots
│
├── data/
│ ├── fake_count.npz # Pre-processed instrument response grid
│ ├── photo_electric_sigma_redshift_0108.npz # Pre-computed cross-sections
│ └── SDSSJ0932+0405.* # Chandra observation files (not tracked)
│
├── output/
│ ├── inference/ # Saved posterior sample arrays (.npz)
│ ├── summary/ # MCMC diagnostic CSVs
│ └── plots/ # Saved figures (.png)
│
├── requirements.txt
└── README.md
The pipeline runs in three stages:
python src/photo_electric_absorption.py
Computes photoelectric absorption cross-sections σ(E) using the
Morrison & McCammon (1983) piecewise
polynomial model at both rest-frame and redshifted energies, and saves
them to data/photo_electric_sigma_redshift_<tag>.npz.
python src/generate_synthetic_data.py
Loops over a grid of (NH_mean, τ, φ_mean) parameter combinations. For each combination it:
count_generator.data/synthetic_count_NH_and_phi_spec_<tag>.npz.Edit the CONFIGURATION block at the top of the script to change the
parameter grid. Expected runtime: several hours for the full 54-combination
grid. Run a single combination for a quick test by temporarily setting each
list to one element.
python src/run_inference.py
Selects one synthetic dataset (configured via NH_LABEL, TAU_LABEL,
PHI_LABEL at the top of the script), runs NUTS with 2000 warm-up and 6000
posterior samples, and saves:
output/inference/<tag>.npz — posterior samples and posterior predictive counts.output/summary/<tag>.csv — per-parameter R-hat, ESS, mean, std.Expected runtime: 30–120 min depending on the time-series length and hardware.
python src/visualise_results.py
Loads the inference output and plots:
conda create -n agn-state-space python=3.11
conda activate agn-state-space
pip install -r requirements.txt
xraystan is not on PyPI; install from source:
pip install git+https://github.com/JohannesBuchner/xraystan
The Chandra observation files for SDSSJ0932+0405
(SDSSJ0932+0405.pi, .rmf, .corr.arf, _bkg.*)
are not tracked in this repository (they are not freely redistributable).
Place them in the data/ directory before running Stage 2 or 3.
The two pre-processed files that are tracked:
| File | Contents |
|---|---|
data/fake_count.npz | Instrument energy grid, ARF, RMF (1070 channels) |
data/photo_electric_sigma_redshift_0108.npz | Pre-computed σ(E) at z = 0.0108 |
| Symbol | Description | Default |
|---|---|---|
| γ | Power-law photon index | inferred |
| NH(t) | Intrinsic hydrogen column density (log₁₀, 10²² cm⁻²) | inferred |
| φ(t) | Power-law normalisation (log₁₀) | inferred |
| α | AR(1) autocorrelation coefficient (= exp(−1/τ)) | inferred |
| τ | AR(1) decorrelation timescale | inferred |
| σ | AR(1) innovation standard deviation | inferred |
| NH_gal | Galactic foreground NH (fixed) | 0.01 × 10²² cm⁻² |
| z | Source redshift (fixed) | 0.0108 |
Nozhan Balafkan and Dr. Johannes Buchner (Max Planck Institute for Extraterrestrial Physics, Garching, Germany)
77 commits
TeX
48.2%
Python
46.1%
BibTeX Style
5.7%
State-space modelling of X-ray spectral variability in AGNs and X-ray binaries using AR(1) latent dynamics, a forward spectral model under Poisson statistics, and HMC inference via NumPyro.
TeX
0
77 commits
updated Aug 21, 2026
State-space modelling of X-ray spectral variability in Active Galactic Nuclei (AGNs) and X-ray binaries (XRBs). The framework links observed photon count time series to two latent physical parameters --- hydrogen column density NH(t) and coronal height h_c(t) --- each modelled as an AR(1) stochastic process. Posterior inference is performed using Hamiltonian Monte Carlo (HMC/NUTS) implemented in NumPyro.
X-ray variability in AGNs arises from two sources:
| Source | Physical origin | Model component |
|---|---|---|
| Intrinsic | Coronal fluctuations | Power-law normalisation φ(t) |
| External | Absorbing winds / outflows | Hydrogen column density NH(t) |
This pipeline models both simultaneously by embedding an AR(1) stochastic process for each parameter inside a full X-ray spectral forward model:
F(E, t) = ZPOWERLW(E; γ, φ(t)) × ZWABS(E; NH(t)) × WABS(E; NH_gal)
Photon counts are then predicted by folding F through the instrument ARF and RMF, and a Poisson likelihood connects the model to observed counts:
λᵢ(t) = Σⱼ F(Eⱼ, t) · Δt · ΔEⱼ · ARFⱼ · RMFⱼᵢ
Cᵢ(t) ~ Poisson(λᵢ(t))
See Buchner & Boorman (2023) for the theoretical background.
.
├── src/
│ ├── photo_electric_absorption.py # Morrison & McCammon (1983) cross-sections
│ ├── ar1_process_generator.py # AR(1) stochastic process generators
│ ├── count_simulator.py # X-ray count spectrum simulator
│ ├── generate_synthetic_data.py # Grid-search synthetic data generation
│ ├── run_inference.py # HMC/NUTS Bayesian inference
│ └── visualise_results.py # Posterior trace and histogram plots
│
├── data/
│ ├── fake_count.npz # Pre-processed instrument response grid
│ ├── photo_electric_sigma_redshift_0108.npz # Pre-computed cross-sections
│ └── SDSSJ0932+0405.* # Chandra observation files (not tracked)
│
├── output/
│ ├── inference/ # Saved posterior sample arrays (.npz)
│ ├── summary/ # MCMC diagnostic CSVs
│ └── plots/ # Saved figures (.png)
│
├── requirements.txt
└── README.md
The pipeline runs in three stages:
python src/photo_electric_absorption.py
Computes photoelectric absorption cross-sections σ(E) using the
Morrison & McCammon (1983) piecewise
polynomial model at both rest-frame and redshifted energies, and saves
them to data/photo_electric_sigma_redshift_<tag>.npz.
python src/generate_synthetic_data.py
Loops over a grid of (NH_mean, τ, φ_mean) parameter combinations. For each combination it:
count_generator.data/synthetic_count_NH_and_phi_spec_<tag>.npz.Edit the CONFIGURATION block at the top of the script to change the
parameter grid. Expected runtime: several hours for the full 54-combination
grid. Run a single combination for a quick test by temporarily setting each
list to one element.
python src/run_inference.py
Selects one synthetic dataset (configured via NH_LABEL, TAU_LABEL,
PHI_LABEL at the top of the script), runs NUTS with 2000 warm-up and 6000
posterior samples, and saves:
output/inference/<tag>.npz — posterior samples and posterior predictive counts.output/summary/<tag>.csv — per-parameter R-hat, ESS, mean, std.Expected runtime: 30–120 min depending on the time-series length and hardware.
python src/visualise_results.py
Loads the inference output and plots:
conda create -n agn-state-space python=3.11
conda activate agn-state-space
pip install -r requirements.txt
xraystan is not on PyPI; install from source:
pip install git+https://github.com/JohannesBuchner/xraystan
The Chandra observation files for SDSSJ0932+0405
(SDSSJ0932+0405.pi, .rmf, .corr.arf, _bkg.*)
are not tracked in this repository (they are not freely redistributable).
Place them in the data/ directory before running Stage 2 or 3.
The two pre-processed files that are tracked:
| File | Contents |
|---|---|
data/fake_count.npz | Instrument energy grid, ARF, RMF (1070 channels) |
data/photo_electric_sigma_redshift_0108.npz | Pre-computed σ(E) at z = 0.0108 |
| Symbol | Description | Default |
|---|---|---|
| γ | Power-law photon index | inferred |
| NH(t) | Intrinsic hydrogen column density (log₁₀, 10²² cm⁻²) | inferred |
| φ(t) | Power-law normalisation (log₁₀) | inferred |
| α | AR(1) autocorrelation coefficient (= exp(−1/τ)) | inferred |
| τ | AR(1) decorrelation timescale | inferred |
| σ | AR(1) innovation standard deviation | inferred |
| NH_gal | Galactic foreground NH (fixed) | 0.01 × 10²² cm⁻² |
| z | Source redshift (fixed) | 0.0108 |
Nozhan Balafkan and Dr. Johannes Buchner (Max Planck Institute for Extraterrestrial Physics, Garching, Germany)
77 commits
TeX
48.2%
Python
46.1%
BibTeX Style
5.7%