Skip to main content

harv

Tests Docs License: MIT Python 3.12+


harv logo

harv is a Python package for inferring Keplerian orbital parameters of binary-star and star–exoplanet systems from time series data. Built on JAX, NumPyro, and unxt for units-aware computation.

It's pronounced harvey.

⚠️ Warning! ⚠️

harv is in rapid development and is pre-alpha. Meaning the API is not stable or guaranteed! Once the first version is released, we will have some guarantees about backwards compatibility, but there are no guarantees for API stability with the current development versions of this package. Sorry!

Installation

Requires Python 3.12+. Install from GitHub:

pip install git+https://github.com/adrn/harv

Or, if using uv:

uv add git+https://github.com/adrn/harv

Quickstart

TODO: move to a quickstart page in documentation and link here.

Radial velocity modeling

from unxt import Q
import harv
import harv.models as hm

# Load or create RV data with explicit units - some sample RV data:
data = harv.RVData(
    time=Q([56000.0, 56100.0, 56250.0, 56400.0, 56600.0], "day"),
    rv=Q([12.3, -8.7, 5.1, -14.2, 10.8], "km/s"),
    rv_err=Q([1.2, 0.9, 1.1, 0.8, 1.0], "km/s"),
)

# Set up a prior with default structure (log-uniform in period, etc.)
prior = hm.StandardRV().default_prior(
    period_min=Q(10, "day"),
    period_max=Q(1000, "day"),
    sigma_K0=Q(30, "km/s"),   # RV semi-amplitude scale
    sigma_v0=Q(10, "km/s"),   # systemic velocity prior width
)

# Run the rejection sampler
sampler = harv.RejectionSampler(prior, harv.RVModel())
samples = sampler.run(data, n_prior_samples=1_000_000, seed=42)

# Inspect results — quantities carry units:
print(f"Accepted {samples.n_samples} posterior samples")
print(f"Period: {samples['period']}")
print(f"Eccentricity: {samples['eccentricity']}")

Gaia epoch astrometry

import numpyro.distributions as dist
import quaxed.numpy as jnp

astro_data = harv.GaiaAstrometryData(
    time=Q([958.110978, 994.910525, 995.086642, 1010.091395, 1076.918577], "day"),
    al_position=Q([147.066, 379.996, 378.656, 74.666, -293.923], "mas"),
    al_position_err=Q([0.370, 0.446, 0.428, 0.270, 0.247], "mas"),
    scan_angle=Q([-59.047, -5.114, -5.783, -68.579, -134.155], "deg"),
    parallax_factor=jnp.array([0.70828, -0.46657, -0.45946, 0.19659, -0.21379])
)

prior = hm.StandardGaiaAstrometry().default_prior(
    period_min=Q(50, "day"),
    period_max=Q(3000, "day"),
    sigma_a0=Q(1, "au"),   # astrometric semi-major axis prior scale
    sigma_parallax=Q(1.0, "mas"),  # parallax prior width
    sigma_pos=Q(1, "mas"),  # position offset prior width
    sigma_vtan=Q(30, "km/s"),  # tangential velocity prior width
)

sampler = harv.RejectionSampler(prior, harv.GaiaAstrometryModel())
samples = sampler.run(astro_data, n_prior_samples=1_000_000, seed=42)

MCMC continuation

When the rejection sampler returns a small number of samples, you can refine with NumPyro MCMC, started from the posterior samples:

from harv.samplers import NumpyroSampler

samples = sampler.run(n_prior_samples=1_000_000, max_posterior_samples=128)
mcmc_sampler = NumpyroSampler(model=model, prior=prior)
mcmc_samples = mcmc_sampler.run(samples, seed=0)

How it works

harv is built on the same tricks as The Joker (Price-Whelan et al. 2017) to make rejection sampling practical for Keplerian orbit inference. It uses a two-level parameterization that separates orbital parameters into:

  1. Nonlinear parameters (period, eccentricity, argument of pericenter, phase) — sampled directly from the prior via rejection sampling, and
  2. Linear parameters (RV semi-amplitude, systemic velocity, astrometric offsets) — these can be analytically marginalized given each set of nonlinear parameters.

This approach makes rejection sampling possible for high-dimensional parameter spaces by reducing the effective dimensionality of the sampling problem. The main utility of the rejection sampler is to map out the multi-modal posterior distribution of orbital parameters in the low signal-to-noise or low number of observations regime, which is challenging or impossible for MCMC methods. The samples returned by the rejection sampler are exact draws from the posterior distribution, and can be used to initialize MCMC samplers for further refinement, if necessary.

All objects are Equinox modules (valid JAX pytrees), so they work seamlessly with jax.jit, jax.vmap, and jax.grad.

Documentation

TODO: Full documentation will be available at harv.readthedocs.io.

License

harv is free software released under the MIT License. See LICENSE for details.

Metadata

Release files for harv 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for harv 0.0.1
File Size Uploaded
harv-0.0.1.tar.gz 152.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for harv 0.0.1
File Interpreter ABI Platform
harv-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 301.4 kB

Release files / harv-0.0.1.tar.gz

Download URL harv-0.0.1.tar.gz
Size 152.5 kB
Tags Source
SHA-256 checksum
How to use checksums
092cfaec55d09806acc16eb5971349cbb0e4f9925a7182836146aa456d8fc6e2
BLAKE2b-256 checksum
How to use checksums
e87fbcd4b06e512ddb3bfd3dbd0dccbfeaae59635034a3e903cafe0fdbdd5cd7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.

Transparency log

Release files / harv-0.0.1-py3-none-any.whl

Download URL harv-0.0.1-py3-none-any.whl
Size 148.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3e6dd86e56887e707bed794d220e14891ceb922e4e89e319aaa357076ee677b0
BLAKE2b-256 checksum
How to use checksums
44f7f784dfe80af61e653eadfd1ec51269a0e7a1ce07bb0435bbf20f5ed0150c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page