Skip to main content

ps_eor: Power-spectrum analysis and signal separation for 21-cm cosmology

ps_eor provides data containers, power-spectrum estimators, simulations, and signal-separation tools for low-frequency interferometric 21-cm experiments. It supports the path from gridded visibility data to spatial, cylindrical, and spherical power spectra, including Gaussian-process foreground and systematic separation.

📖 Documentation: https://ps-eor.readthedocs.io/en/latest/ — getting started, topic-based user guide, pstool command reference, and full API reference.

Upgrading from ps_eor 0.x to 1.0? Read the ML-GPR migration guide.

What the package does

Data handling — build analysis-ready visibility cubes from calibrated images:

  • read frequency-ordered FITS images (Jy/PSF), using matching PSF files for an accurate Kelvin conversion, or inferring the PSF area from image metadata;
  • select the field of view and baseline range, Fourier-transform to the uv plane, and store visibilities, weights, frequencies, and metadata as HDF5.

Power spectra — measure 21-cm power spectra:

  • spatial, cylindrical, and spherical spectra, plus cross-spectra between independent observations, with the instrumental and cosmological normalizations applied.

Signal separation — suppress foregrounds and systematics, preserve the 21-cm signal:

  • polynomial and PCA foreground models;
  • ML-GPR, a Gaussian-process framework that infers posterior foreground, systematic, noise, and 21-cm components and propagates them to power spectra — for one observation or jointly across many, separating repeatable sky from observation-dependent excess variance.

Simulation and sensitivity — generate test data and forecast performance:

  • draw Gaussian-process component cubes (foreground, 21-cm, systematic; single- or multi-epoch) from covariance kernels or an input power spectrum;
  • generate thermal-noise data cubes from measured weights or a simulated telescope layout and observing strategy;
  • forecast UV coverage and power-spectrum sensitivity, with built-in models for LOFAR, NenuFAR, MWA, SKA-Low, HERA, AARTFAAC, and OVRO-LWA.

The GPR approach follows Mertens et al. (2018); the multi-observation extension relates to Munshi et al. (2025).

Installation

The base package contains the data and power-spectrum functionality:

pip install ps-eor

Install the Gaussian-process backend and its standard samplers, including NUTS through Pyro, with:

pip install "ps-eor[ml-gpr]"

UltraNest is available separately:

pip install "ps-eor[ml-gpr,ultranest]"

For development:

git clone https://gitlab.com/flomertens/ps_eor.git
cd ps_eor
pip install -e ".[ml-gpr,dev]"

Python 3.10 or newer is required.

Creating a visibility cube from FITS images

Given one calibrated image and one matching PSF image per frequency, ps_eor can perform the Jy/PSF-to-Kelvin conversion and construct a weighted CartDataCube. The files are sorted using their FITS frequency metadata:

from pathlib import Path

import numpy as np

from ps_eor import datacube, psutil

image_files = [str(path) for path in Path("fits/images").glob("*.fits")]
psf_files = [str(path) for path in Path("fits/psfs").glob("*.fits")]

image_files = psutil.sort_by_fits_key(image_files, "CRVAL3")
psf_files = psutil.sort_by_fits_key(psf_files, "CRVAL3")

cube = datacube.CartDataCube.load_from_fits_image_and_psf(
    image_files,
    psf_files,
    umin=50,
    umax=250,
    theta_fov=np.deg2rad(4),
    int_time=10,
    total_time=10 * 3600,
)
cube.save("visibilities.h5")

Here, umin and umax are in wavelengths, theta_fov is in radians, and the integration and total observing times are in seconds. The same operation is available as pstool gen_vis_cube.

Basic power-spectrum workflow

import numpy as np

from ps_eor import datacube, pspec

cube = datacube.CartDataCube.load("visibilities.h5")

config = pspec.PowerSpectraConfig(
    el=2 * np.pi * np.arange(cube.ru.min(), cube.ru.max(), 10),
    window_fct="hann",
)
ps_gen = pspec.PowerSpectraBuilder(config).get(cube)

spatial = ps_gen.get_ps(cube)
cylindrical = ps_gen.get_ps2d(cube)

kbins = np.logspace(np.log10(ps_gen.kmin), np.log10(0.5), 10)
spherical = ps_gen.get_ps3d(kbins, cube)

ML-GPR workflow

The high-level fitter is configured from TOML:

from ps_eor.ml_gpr import MLGPRConfigFile, MLGPRForegroundFitter

config = MLGPRConfigFile.get_defaults()
fitter = MLGPRForegroundFitter(config)
noise_for_fit = fitter.process_noise_cube(noise_cube)
result = fitter.run(data_cube, noise_for_fit)

Advanced users can work directly with the lower-level building blocks:

from ps_eor.ml_gpr.kernels import UVScaledKernel
from ps_eor.ml_gpr.multidata import MultiData
from ps_eor.ml_gpr.regressor import MultiGPRegressor

Command-line interface

The package installs pstool, which can run the main analysis and sensitivity workflows without writing Python code:

Command Purpose
gen_vis_cube Read frequency-ordered FITS image and PSF files, convert Jy/PSF to Kelvin, select the field of view and baseline range, and write an HDF5 visibility cube.
run_flagger Identify bad frequency and UV samples from Stokes I and V cubes, then save the flag mask and a diagnostic plot.
even_odd_to_sum_diff Build signal and noise-proxy cubes from an even/odd data split.
diff_cube Subtract two compatible visibility cubes.
combine Combine observations or nights, with optional flagging and noise-based weighting.
combine_sph Combine spherical-harmonic observations.
make_ps Calculate spatial, cylindrical, and spherical power spectra and save their numerical results and diagnostic plots.
run_ml_gpr Separate foreground, systematic, noise, and 21-cm components and produce their posterior power spectra and diagnostics.
run_ml_gpr_inj Inject a simulated 21-cm signal and measure its recovery through ML-GPR.
vis_to_sph Convert a Cartesian visibility cube into a spherical-harmonic cube.
simu_uv Simulate telescope UV coverage for a pointing and observing setup.
simu_noise_img Generate a thermal-noise FITS image cube from simulated UV coverage.
simu_noise_ps Predict spatial, cylindrical, and spherical power-spectrum sensitivity at one redshift.
simu_noise_ps_zrange Follow the sensitivity of a selected (k)-mode across a redshift range.

Each command documents its inputs and options:

pstool --help
pstool COMMAND --help

ML-GPR tutorials

The numbered notebooks form a focused ML-GPR tutorial series:

  1. Quick start
  2. Simulating data
  3. The covariance model
  4. Running a fit
  5. Training the VAE
  6. ML-GPR with the VAE kernel
  7. Config-driven runs
  8. Multi-epoch GPR
  9. Data in-painting
  10. Validation and failure modes

Specialist examples, including Cross-GPR and sampler-prior comparisons, live in the advanced notebooks.

Tests

pytest

Frozen numerical fixtures used to compare the GPyTorch implementation with the former GPy backend are stored under tests/data/gpr_golden/.

License

ps_eor is distributed under the GNU General Public License v3 or later.

Metadata

Release files for ps_eor 1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ps_eor 1.0
File Size Uploaded
ps_eor-1.0.tar.gz 218.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ps_eor 1.0
File Interpreter ABI Platform
ps_eor-1.0-py3-none-any.whl Python 3 none any Details

Total release size: 453.2 kB

Release files / ps_eor-1.0.tar.gz

Download URL ps_eor-1.0.tar.gz
Size 218.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2b491b93c9790115b66716d8332118b7b350839f7e45d8f756e9e0e8dcf358fe
BLAKE2b-256 checksum
How to use checksums
1bc7779a67a14a717af7fd223759b6ddc62e71d7e827e5c40117ddd356284e61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.4.1 CPython/3.14.4 Linux/7.0.0-28-generic

Release files / ps_eor-1.0-py3-none-any.whl

Download URL ps_eor-1.0-py3-none-any.whl
Size 234.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd5e53262a2a4322c2ec3043536ee5c5d655df6c1d281b30a446d134030a6693
BLAKE2b-256 checksum
How to use checksums
5c3be6a4a729d07f23db8d93ec2805b71c5ea0ac1d06724a030b97173dbc8840
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.4.1 CPython/3.14.4 Linux/7.0.0-28-generic

Release history Release notifications | RSS feed

This release

1.0 This release

2 release files

0.34

2 release files

0.33.1

2 release files

0.33

2 release files

0.32

2 release files

0.31

2 release files

0.30

2 release files

0.29

2 release files

0.28

2 release files

0.26

2 release files

0.25

2 release files

0.24

2 release files

0.23

2 release files

0.22

2 release files

0.21

2 release files

0.20

2 release files

0.19

2 release files

0.18

2 release files

0.17

2 release files

0.16

2 release files

0.14

2 release files

0.13

2 release files

0.12

2 release files

0.11

2 release files

0.10

2 release files

0.9

2 release files

0.8

2 release files

0.7.7

2 release files

0.7.6

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page