Metadata-Version: 2.4
Name: snapshot_imager
Version: 0.3.0
Summary: Snapshot imaging of radio interferometric visibilities using non-uniform FFTs
Author-email: Tyler Cox <tyler.a.cox@berkeley.edu>
Maintainer-email: Tyler Cox <tyler.a.cox@berkeley.edu>
License-Expression: MIT
Project-URL: Homepage, https://github.com/HERA-Team/snapshot_imager
Project-URL: Repository, https://github.com/HERA-Team/snapshot_imager
Project-URL: Issues, https://github.com/HERA-Team/snapshot_imager/issues
Keywords: radio astronomy,visibility,imaging,interferometry,nufft,HERA
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Astronomy
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=2.0
Requires-Dist: astropy>=6.1
Requires-Dist: finufft>=2.3
Requires-Dist: tqdm>=4.40
Requires-Dist: hera-calibration>=3.7.4
Provides-Extra: gpu
Requires-Dist: cupy-cuda12x; extra == "gpu"
Requires-Dist: cufinufft>=2.4; extra == "gpu"
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: dev
Requires-Dist: snapshot_imager[test]; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Dynamic: license-file

# snapshot_imager

[![CI](https://github.com/HERA-Team/snapshot_imager/actions/workflows/ci.yml/badge.svg)](https://github.com/HERA-Team/snapshot_imager/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/HERA-Team/snapshot_imager/graph/badge.svg)](https://codecov.io/gh/HERA-Team/snapshot_imager)
[![PyPI](https://img.shields.io/pypi/v/snapshot-imager.svg)](https://pypi.org/project/snapshot-imager/)

`snapshot_imager` is a Python package for radio interferometric snapshot imaging using Non-Uniform Fast Fourier Transforms (NUFFT). It is designed to efficiently produce dirty image cubes from visibility data, with support for multiple NUFFT strategies (Type 1, Type 3, and multi-frequency synthesis) and optional GPU acceleration via CuPy and cuFINUFFT.

## Installation

Install the latest release from PyPI:

```bash
pip install snapshot-imager
```

For GPU support (CUDA 12), install the `gpu` extra, which pulls in `cupy-cuda12x` and `cufinufft`:

```bash
pip install "snapshot-imager[gpu]"
```

For other CUDA versions, install the matching CuPy wheel (e.g. `cupy-cuda11x` or `cupy-cuda13x`) and `cufinufft` yourself.

> **macOS note:** on Apple-silicon Macs, use Python 3.13 or newer. The healpy wheels
> for Python 3.10–3.12 (installed via `hera_cal`) bundle their own OpenMP runtime,
> which conflicts with FINUFFT's and crashes on the first imaging call.

To install from source:

```bash
git clone https://github.com/HERA-Team/snapshot_imager.git
cd snapshot_imager
pip install .
```

## Basic Usage

The typical workflow is to unpack HERA `DataContainer` objects into an `ImagingData` container, then pass that to `dirty_image`.

```python
from snapshot_imager import unpack_data_containers, dirty_image

# data, flags, and nsamples are hera_cal DataContainer objects
imaging_data = unpack_data_containers(
    data=data,
    flags=flags,
    nsamples=nsamples,
    pol="ee",
    antpos=antpos,
    freqs=freqs,
)

# One image per channel: a (ntimes, nfreqs, npix, npix) cube
result = dirty_image(imaging_data, npix=256, fov=10.0)

# One multi-frequency synthesis (MFS) image per time: (ntimes, 1, npix, npix)
mfs = dirty_image(imaging_data, npix=256, fov=10.0, mfs=True)

print(result.images.shape)
```

The returned `ImageResult` holds the image cube (indexed `images[time, freq, m, l]`), the pixel direction cosines `l_coords` and `m_coords`, and the `times` and `freqs` of the images. Per-channel images are normalized so a unit point source has peak 1; MFS images are the unnormalized weighted sum. Pixels below the horizon (only when `fov` > 90°) are NaN.

`dirty_image` uses a Type 1 NUFFT by default; pass `method="type3"` to evaluate the same image with a Type 3 NUFFT (much slower on a regular grid, mainly useful for validation).

The earlier functions `snapshot_imager_type1`, `snapshot_imager_type3`, `snapshot_imager_mfs_type_1`, and `snapshot_imager_mfs_type_3` are still available, with their original defaults and outputs; they are thin wrappers around `dirty_image`.

## GPU Acceleration

`snapshot_imager` supports GPU-accelerated imaging via [CuPy](https://cupy.dev/) and [cuFINUFFT](https://github.com/flatironinstitute/finufft). Pass `use_gpu=True`:

```python
result = dirty_image(imaging_data, npix=256, fov=10.0, use_gpu=True)
```

If CuPy or cuFINUFFT are not installed, or no CUDA device is available, it falls back to the CPU with a warning.

## Development

Set up a development environment with the test and lint tools, and install the git hooks:

```bash
pip install -e ".[dev]"
pre-commit install
```

Run the test suite (GPU tests are skipped automatically when no GPU is available):

```bash
pytest --cov
```

Lint with [ruff](https://docs.astral.sh/ruff/) (this also runs on every commit via pre-commit, and in CI):

```bash
pre-commit run --all-files
```

Benchmark the imagers on synthetic HERA-like data (see `--help` for sizes and options):

```bash
python benchmarks/benchmark_imagers.py
```

## Releasing

Versions are derived from git tags by [setuptools-scm](https://setuptools-scm.readthedocs.io/), so there is no version string to bump in the code. To publish a release to PyPI:

1. Make sure CI is passing on `main`.
2. Tag the release commit and push the tag:

   ```bash
   git tag -a v0.2.0 -m "v0.2.0"
   git push origin v0.2.0
   ```

3. The [Publish to PyPI](.github/workflows/publish.yml) workflow builds the sdist and wheel and uploads them using PyPI trusted publishing. Optionally, create a GitHub release from the tag to record release notes.

## License

MIT
