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:
- Quick start
- Simulating data
- The covariance model
- Running a fit
- Training the VAE
- ML-GPR with the VAE kernel
- Config-driven runs
- Multi-epoch GPR
- Data in-painting
- 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.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ps_eor-1.1.tar.gz | 220.7 kB | Without provenance | Details for ps_eor-1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ps_eor-1.1-py3-none-any.whl | Python 3 | none | any | Details for ps_eor-1.1-py3-none-any.whl |
Total release size: 456.6 kB
Release files / ps_eor-1.1.tar.gz
| Download URL | ps_eor-1.1.tar.gz |
|---|---|
| Size | 220.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9601bfaf06cfb224d6ccc62e40cdd5101ea941f3409bf12414422dbf07928358
|
|
BLAKE2b-256 checksum How to use checksums |
c068330a621ccf8cc71919791e77a5b2b8970940e325a65b2aed7a076aa43219
|
| 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-38-generic
|
Release files / ps_eor-1.1-py3-none-any.whl
| Download URL | ps_eor-1.1-py3-none-any.whl |
|---|---|
| Size | 235.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77db2048321d8a1302c5820bc890fd4c9ff9a344d3e79e6b4957a75b9196aca4
|
|
BLAKE2b-256 checksum How to use checksums |
d460e0c6a29a75470537176e78192ccb1a082df160ef238ddd0f5ed3fd02f911
|
| 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-38-generic
|
Security for ps_eor 1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.