nullcal
A Python package for constraining calibration errors of a closed-geometry network of gravitational-wave detectors. It provides the null stream formalism for noise-only data combinations and Bayesian recalibration likelihoods to quantify detector miscalibration.
Features
- Null stream construction for closed-geometry detector networks
- Calibration error constraint via Bayesian recalibration likelihood
- Time-frequency transforms (Short-Time Fourier Transform, wavelet transforms)
- Clustering algorithms for time-frequency map analysis
- Modular architecture with clean separation between null stream, likelihood, calibration, immutable data, result, and utility layers
Installation
We recommend using uv to manage virtual environments for installing nullcal.
If you don't have uv installed, you can install it with pip. See the project
pages for more details:
- Install via pip:
pip install --upgrade pip && pip install uv - Project pages: uv on PyPI | uv on GitHub
- Full documentation and usage guide: uv docs
Note: The package requires Python 3.12 or later and is built and tested
against Python 3.12–3.14. When creating a virtual environment with uv, specify
the Python version to ensure compatibility: uv venv --python 3.12 (replace
3.12 with your preferred supported version: 3.12, 3.13, or 3.14). This avoids
potential issues with unsupported Python versions.
From PyPI
# Create a virtual environment (recommended with uv)
uv venv --python 3.12
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install nullcal
From Source
git clone git@github.com:Leuven-Gravity-Institute/nullcal.git
cd nullcal
# Create a virtual environment (recommended with uv)
uv venv --python 3.12
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv sync --extra jax
Quick Start
import numpy as np
from nullcal.data import InterferometerData
from nullcal.likelihood import RecalibrationLikelihood
from nullcal.null_stream.null_stream import NullStream
from nullcal.time_frequency_transform.wavelet_transforms import WaveletTransform
# Load arrays from your strain source. The loader also accepts detector objects
# exposing these fields via InterferometerData.from_interferometers(...).
duration = 4.0
sampling_frequency = 4096.0
frequency_array = np.fft.rfftfreq(int(duration * sampling_frequency), 1 / sampling_frequency)
data = InterferometerData(
psd=np.ones((3, frequency_array.size)),
strain=np.zeros((3, frequency_array.size), dtype=complex),
mask=np.broadcast_to(frequency_array >= 4.0, (3, frequency_array.size)).copy(),
frequency_array=frequency_array,
duration=duration,
sampling_frequency=sampling_frequency,
start_time=0.0,
name=("ET1", "ET2", "ET3"),
)
# Compute the null stream
wavelet_transform = WaveletTransform(
duration=duration, sampling_frequency=sampling_frequency, nx=4, frequency_resolution=4
)
time_frequency_filter = np.ones(wavelet_transform.shape, dtype=bool)
null_stream = NullStream(
interferometers=data,
time_frequency_transform=wavelet_transform,
time_frequency_filter=time_frequency_filter,
)
null_data = null_stream.compute_calibrated_frequency_domain_null_stream(calibration_factor=np.ones_like(data.strain))
# Set up a recalibration likelihood for calibration error constraints
likelihood = RecalibrationLikelihood(
interferometers=data,
knot_frequencies=np.geomspace(4.0, 2048.0, 10),
time_frequency_filter=time_frequency_filter,
wavelet_transform_frequency_resolution=4,
wavelet_transform_nx=4,
)
params = {
"amplitude": np.zeros((3, 10)),
"phase": np.zeros((3, 10)),
}
log_posterior = likelihood.logdensity_fn(params)
Development
Pre-commit hooks
Install prek (a wrapper around pre-commit):
uv run prek install
Run all hooks against all files:
uv run prek run --all-files
Documentation
Full documentation is available at https://leuven-gravity-institute.github.io/nullcal/.
Contributing
Contributions are welcome!
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
Release Schedule
Releases follow a fixed schedule: every Tuesday at 00:00 UTC, unless an emergent bugfix is required. This ensures predictable updates while allowing flexibility for critical issues. Users can view upcoming changes in the draft release on the GitHub Releases page.
Testing
Run the test suite:
uv run pytest
License
This project is licensed under the MIT License. See the LICENSE file for the full license text.
Support
For questions or issues, please open an issue on GitHub or contact the maintainers.
Metadata
Release files for nullcal 0.2.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 | |
|---|---|---|---|
| nullcal-0.2.1.tar.gz | 7.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nullcal-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 7.5 MB
Release files / nullcal-0.2.1.tar.gz
| Download URL | nullcal-0.2.1.tar.gz |
|---|---|
| Size | 7.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
60e5d6257d75319d57bdd207b9bfa87b7e5d5fba25eda602bc695ce55e8f6655
|
|
BLAKE2b-256 checksum How to use checksums |
80c5e487d71824e0715c0f12e6c9cd6de640de0ebca994247f53e46f76c0d61c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / nullcal-0.2.1-py3-none-any.whl
| Download URL | nullcal-0.2.1-py3-none-any.whl |
|---|---|
| Size | 46.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e56797f735ed423eac9d78868cd32c832576166cc0d6d0eff1197e2bc5a9267e
|
|
BLAKE2b-256 checksum How to use checksums |
a1af2de4526b04fb18d3de7a63281a7189eede3f09eac85a5abb766e3bb7bafe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|