unite is a Python package for fast, Bayesian inference of emission lines from astronomical spectra. It is built on JAX, NumPyro, and Astropy, and supports fitting multiple spectra simultaneously with shared kinematics, calibration tokens, and flexible priors.
Originally designed for JWST/NIRSpec but extensible to any spectrograph.
- Two pixel-integration modes: analytic (exact CDF-based, default) and Gauss-Legendre quadrature (configurable node count) — fast, memory-efficient, and correct even for undersampled data
- Simultaneous multi-spectrum fitting across gratings and instruments with shared kinematic parameters (redshift, FWHM)
- Multiple line profiles: Gaussian, Cauchy, Pseudo-Voigt, Laplace, SEMG, Gauss-Hermite, Split-Normal, Skew-Voigt
- Emission and absorption lines: flux-parametrized additive profiles and tau-parametrized multiplicative transmission
exp(-tau * phi), with configurable absorber position (foreground,behind_lines,behind_continuum) - Flexible continuum models: Linear, Polynomial, Chebyshev, Bernstein, B-Spline, Power-Law, Blackbody, Modified Blackbody, Attenuated Blackbody — auto-generated from line configurations
- Calibration tokens (flux scale, resolution scale, pixel offset) with free or fixed priors, shared across spectra
- YAML serialization for reproducible, human-editable configurations
- User-controlled sampler —
ModelBuilderreturns(model_fn, model_args)for use with any NumPyro backend (NUTS, SVI, nested sampling, ...) - Instrument support for JWST/NIRSpec (all gratings + PRISM), SDSS, and any custom spectrograph via generic dispersers
pip install uniteOr with Pixi:
pixi add uniteimport jax
import astropy.units as u
from numpyro import infer
from unite import line, model, prior
from unite.continuum import ContinuumConfiguration, Linear
from unite.instrument import nirspec
from unite.results import make_parameter_table, make_spectra_tables
from unite.spectrum import Spectra, from_DJA
# 1. Configure lines with shared kinematics
z = line.Redshift('z', prior=prior.Uniform(-0.005, 0.005))
fwhm = line.FWHM('narrow', prior=prior.Uniform(100, 1000))
lc = line.LineConfiguration()
lc.add_line(
'H_alpha',
6563.0 * u.AA,
redshift=z,
fwhm_gauss=fwhm,
flux=line.Flux(prior=prior.Uniform(0, 10))
)
lc.add_line(
'NII_6585',
6585.0 * u.AA,
redshift=z,
fwhm_gauss=fwhm,
flux=line.Flux(prior=prior.Uniform(0, 10))
)
# Tau-parametrized absorption line: transmission = exp(-tau * phi)
lc.add_line(
'HI_abs',
6563.0 * u.AA,
redshift=z,
fwhm_gauss=line.FWHM('abs', prior=prior.Uniform(50, 500)),
tau=line.Tau(prior=prior.Uniform(0, 5))
)
cc = ContinuumConfiguration.from_lines(lc.centers, width=15_000*u.km/u.s, form=Linear())
# 2. Load spectra (NIRSpec example; any instrument works)
g395m = nirspec.G395M()
spec = from_DJA('dja-spectrum.fits', disperser=g395m)
spectra = Spectra([spec], redshift=5.28)
filtered_lines, filtered_cont = spectra.prepare(lc, cc)
spectra.compute_scales(filtered_lines, filtered_cont, error_scale=True)
# 3. Build and run with any NumPyro sampler
# integration_mode='analytic' (default) uses exact CDF integration;
# integration_mode='quadrature' uses Gauss-Legendre quadrature (n_nodes per pixel)
builder = model.ModelBuilder(filtered_lines, filtered_cont, spectra)
model_fn, model_args = builder.build(integration_mode='analytic')
mcmc = infer.MCMC(infer.NUTS(model_fn), num_warmup=500, num_samples=1000)
mcmc.run(jax.random.PRNGKey(0), model_args)
# 4. Extract results
# Get summary statistics at specific percentiles
samples = mcmc.get_samples()
param_table = make_parameter_table(samples, model_args, percentiles=[0.16, 0.5, 0.84])
spectra_tables = make_spectra_tables(samples, model_args, percentiles=[0.16, 0.5, 0.84])Bug reports, feature requests, and pull requests are welcome on GitHub. If you find a bug or have an idea for an improvement, please open an issue — even a brief description is helpful.
Full documentation, tutorials, and API reference at unite.readthedocs.io.
If you use unite in your research, please cite the Zenodo software release. Each versioned release has a unique DOI minted automatically when a GitHub release is created.
See CITATION.md for BibTeX and details. The Zenodo record lists all releases — visit the link to cite a specific version. GitHub's "Cite this repository" button (top-right of the repo page) also generates citation text directly from CITATION.cff.
GPL v3 or later. See LICENSE for details.