Metadata-Version: 2.4
Name: ampere-astro
Version: 1.0.0b2
Summary: Bayesian fitting of heterogeneous astronomical data, with a flexible likelihood that stays robust when the model is misspecified.
Author: Francisca Kemper, Sundar Srinivasan, Jonathan Marshall, Oscar Morata, Alfonso Trejo, Sascha Zeegers, Lapo Fanciullo, Thavisha Dharmawardena
Author-email: Peter Scicluna <peter.scicluna@eso.org>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/ICSM/ampere
Project-URL: Documentation, https://ampere.readthedocs.io/
Project-URL: Repository, https://github.com/ICSM/ampere
Project-URL: Issues, https://github.com/ICSM/ampere/issues
Project-URL: Changelog, https://ampere.readthedocs.io/en/latest/changelog.html
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Astronomy
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: astropy>=4.0.0
Requires-Dist: scipy
Requires-Dist: matplotlib
Requires-Dist: spectres
Requires-Dist: tqdm
Requires-Dist: pyphot
Requires-Dist: requests
Requires-Dist: emcee
Requires-Dist: dynesty
Requires-Dist: corner
Requires-Dist: arviz>=1
Requires-Dist: h5netcdf
Requires-Dist: celerite2
Provides-Extra: torch
Requires-Dist: torch; extra == "torch"
Requires-Dist: pyro-ppl; extra == "torch"
Provides-Extra: jax
Requires-Dist: jax; extra == "jax"
Requires-Dist: numpyro; extra == "jax"
Requires-Dist: equinox; extra == "jax"
Provides-Extra: sbi
Requires-Dist: torch; extra == "sbi"
Requires-Dist: sbi; extra == "sbi"
Provides-Extra: zeus
Requires-Dist: zeus-mcmc; extra == "zeus"
Provides-Extra: nautilus
Requires-Dist: nautilus-sampler; extra == "nautilus"
Provides-Extra: ultranest
Requires-Dist: ultranest; extra == "ultranest"
Provides-Extra: blackjax
Requires-Dist: blackjax; extra == "blackjax"
Provides-Extra: rhmf
Requires-Dist: robusta-hmf; extra == "rhmf"
Provides-Extra: extinction
Requires-Dist: dust_extinction; extra == "extinction"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: coverage; extra == "dev"
Requires-Dist: pytest-benchmark; extra == "dev"
Requires-Dist: pytest-xdist; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: pyrefly; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: check-wheel-contents; extra == "dev"
Requires-Dist: ampere-astro[docs]; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx; extra == "docs"
Requires-Dist: nbsphinx; extra == "docs"
Requires-Dist: nbconvert; extra == "docs"
Requires-Dist: ipykernel; extra == "docs"
Requires-Dist: ampere-astro[zeus]; extra == "docs"
Provides-Extra: all
Requires-Dist: ampere-astro[blackjax,extinction,jax,nautilus,sbi,torch,ultranest,zeus]; extra == "all"
Dynamic: license-file

# ampere

[![PyPI](https://img.shields.io/pypi/v/ampere-astro.svg)](https://pypi.org/project/ampere-astro/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23151412.svg)](https://doi.org/10.5281/zenodo.23151412) [![Documentation](https://readthedocs.org/projects/ampere/badge/?version=latest)](https://ampere.readthedocs.io/)

Ampere is a Bayesian fitting environment for astronomers: a tool for modelling
several kinds of astronomical data at once — SEDs, spectra, and more — **even
when the model cannot explain everything in the data**.

That last clause is the point of the package. Deficiencies in a physical model
show up as structure in the residuals, and structure in the residuals is
indistinguishable from correlated noise. So ampere gives each dataset a
flexible likelihood: a Gaussian process over the residuals, marginalised over
while the physical parameters are fitted. Whatever the model cannot explain is
absorbed by the GP instead of biasing the parameters you care about, and no
one has to identify the offending regions by hand.

It works, and the cost is measured. On a deliberately misspecified 20 000-point
spectrum, an ordinary chi-square fit reports a parameter **113 of its own
posterior standard deviations away from the truth** — a precise answer that is
wrong, with nothing in the fit to say so — while the flexible likelihood stays
within 0.6 and keeps the truth inside its 68 % interval. The error of the
standard fit *grows* as √N along the size ladder; the flexible fit's does not,
which is why misspecification matters more, not less, for real spectra with
thousands of pixels. That is only reachable because the Matérn-3/2 kernel is
exactly quasiseparable: ampere solves the GP in **O(N)** rather than O(N³), and
on the jax backend takes a value *and* a gradient of a 20 000-point GP
likelihood in **4.7 ms**. The whole study is
`docs/source/m2_misspecification.rst`, and it is re-run by `pixi run test-m2`.

Ampere is in **beta** (`1.0.0b2`), the second beta of its v2 redesign. It is a
backend-neutral core of frozen contracts, three backends that implement it
(pure numpy/scipy, torch and jax), and nine inference engines written once
against the contracts and run on any of them. One of them is for models with no
likelihood to write down at all: `ampere.inference.SBIEngine` fits a
black-box simulator by simulation-based inference (NPE/NLE/NRE, and truncated
marginal ratio estimation for a tighter fit), over the same `FittingProblem`
every other engine consumes, with the same posterior-calibration diagnostics
— which is how `docs/source/wstat_comparison.rst`'s coverage study catches a
profiled statistic's spectral index failing calibration (KS *p* = 4×10⁻⁴)
where the equivalent Bayesian joint fit, on the same simulated data, does not
(*p* = 0.18).

Phase 4 proved the redesign extends past spectra and photometry: spectra,
photometry, images, time series, interferometric visibilities and closure
phases all compose through the same five nouns (model, instrument,
likelihood, dataset, fitting problem), with `docs/source/interferometry.rst`
written as the template for adding the next observable and
`docs/source/astrometry.rst` the proof that the template works. Any
`astropy.modeling` model — compound models included — wraps as an ampere
model with `ampere.core.from_astropy`, with an opt-in, never-silent
translation to a differentiable native equivalent for six common cases
(`docs/source/astropy.rst`). And the flexible likelihood's kernel algebra
goes beyond one Matérn-3/2 term: `Sum`/`Product`/`SpectralMixture`
compositions, a damped-oscillator term for periodic residuals, an `axes=`
selector for a container whose coordinates carry more than one physical
meaning, and a public registry for a user's own quasiseparable term
(`docs/source/kernels.rst`).

Phase 5 (scale-out and advanced inference) widened the same five nouns
rather than adding a sixth: an approximate reduced-rank GP solver alongside
the two exact ones, chosen the same way the exact one was — by measurement
— and gridded (`Image`) data with PSF convolution composing through the
identical likelihood machinery (`docs/source/solvers.rst`,
`docs/source/image.rst`); a non-stationary kernel wrapper (input and
amplitude warping) and a sparsity prior for a sum of noise components
(`docs/source/kernels.rst`); a correlated noise model over a tuple of
channels, homoscedastic and heteroscedastic, for the astrometric and
polarimetric case a single-channel GP cannot express; three more sampling
engines and two more variational guide families behind extras; simulation-
based inference amortised over the observation context, including a batched
native path; and a hierarchical `Population` container, fitted either
jointly or by reweighting archived single-object fits
(`docs/source/population.rst`). If you are interested, please get in touch.

## Installation

Ampere needs Python 3.12–3.14. It has three names: the distribution on PyPI
is **`ampere-astro`**, the import name is **`ampere`**, and the documentation
is at **<https://ampere.readthedocs.io/>**. (The PyPI name `ampere` belongs to
an unrelated package.)

```bash
pip install ampere-astro
```

That is the base install, and it is a complete fitting environment rather than
a stub: the reference backend, the flexible GP likelihood with its exact O(N)
solver, emcee and dynesty, and the ArviZ results format. celerite2, arviz and
h5netcdf are base dependencies, not extras, for exactly that reason.

| Extra | Adds | Unlocks |
|---|---|---|
| *(none)* | numpy, scipy, astropy, matplotlib, spectres, tqdm, pyphot, emcee, dynesty, corner, celerite2, arviz, h5netcdf | the base install; must always work |
| `torch` | torch, pyro-ppl | `ampere.backends.torch`, and NUTS/VI on a torch problem |
| `jax` | jax, numpyro, equinox | `ampere.backends.jax`, and NUTS/VI on a jax problem |
| `zeus` | zeus-mcmc | `ampere.inference.ZeusEngine` |
| `nautilus` | nautilus-sampler | `ampere.inference.NautilusEngine` |
| `ultranest` | ultranest | `ampere.inference.UltranestEngine` |
| `blackjax` | blackjax | `ampere.inference.BlackjaxEngine` (with `jax`) |
| `sbi` | torch, sbi | `ampere.inference.SBIEngine` (simulation-based inference) and legacy `ampere.infer.sbi` |
| `extinction` | dust_extinction | legacy `ampere.models.extinctionModels.F99Extinction` |
| `dev` | pytest, ruff, pyrefly, sphinx, build, twine, … | contributor tooling |
| `all` | every feature extra above | — |

```bash
pip install "ampere-astro[torch]"     # or [jax], [zeus], [all], …
```

**From a clone — the contributor route.** To work on ampere itself, clone the
repository and use [pixi](https://pixi.sh), which builds the whole
environment, interpreter included, from `pyproject.toml` and the committed
lock file:

```bash
git clone https://github.com/ICSM/ampere.git
cd ampere
pixi install -e dev
pixi run test-all        # everything the v2 namespaces own
pixi run docs            # build the documentation
```

(or `pip install -e ".[dev]"` in an environment of your own). The
corresponding pixi environments are `pixi run -e torch …`,
`pixi run -e jax …`, `pixi run -e sbi …`. Only the `gpu` environment, which
exists to run `tests/gpu` on an accelerator, carries both torch and jax;
nothing in ampere needs them together.

## Where to look next

- **Documentation**: hosted per version at <https://ampere.readthedocs.io/>, or
  build it yourself with `pixi run docs`, then `docs/_build/html/index.html`.
  What each release added is the
  [changelog](https://ampere.readthedocs.io/en/latest/changelog.html).
  Start at the architecture overview (`docs/source/overview.rst`), then the
  misspecification study (`docs/source/m2_misspecification.rst`).
- **Citing**: `ampere.cite()` prints the citation (or
  `ampere.cite(format="bibtex")`); `CITATION.cff` carries the same facts for
  GitHub's "Cite this repository" button.
- **Runnable examples**: `examples/m2_misspecification` (the study above),
  `examples/sed_composition` (a spectrum and a photometric catalogue, one
  model, the simplest multi-instrument composition), `examples/interferometry`
  (the modality template, proved on a resolved binary observed as
  visibilities and closure phases), `examples/astrometry` (the second
  modality, a reflex orbit on two time-series channels),
  `examples/wstat_comparison.py` (registering your own likelihood family) and
  `examples/sbi/` (fitting a black-box simulator with `SBIEngine`; needs the
  `sbi` extra). All are covered by tests, so none can rot unnoticed.
- **Design**: `docs/design/` holds the frozen contract specifications
  (`spec-v1.0`) the v2 API implements — start with `architecture.md`.
- **Contributing**: see `CONTRIBUTING.md` for how to set up, what to run
  before a pull request, and what is frozen. For the agent-facing reader,
  `DEVELOPMENT_PLAN.md` is the source of truth for where the redesign is
  going; `WORK_ITEMS.md` is the current work, item by item; and
  `docs/development.md` is the onboarding note.

Legacy ampere — `ampere.data`, `ampere.models`, `ampere.infer` — is the v1
code that produced the published science. It still runs and is frozen in
place; it implements none of the v2 contracts and the two halves do not
interoperate.
