Skip to main content

VESPER

Vetting Exoplanet Signals with Pixel-informed Evidence, Rapidly.

VESPER is a fast, learned vetter for transiting-planet candidates around TESS M dwarfs. Give it a star's TESS photometry and a candidate ephemeris (period, epoch, duration); it returns a calibrated probability that the signal is a planet, seven named impostor scores — in the output's aux_* column order: background eclipsing binary (aux_beb), window alias (aux_alias), eclipsing binary on target (aux_eb), stellar rotation (aux_rot), companion dilution (aux_comp), no signal at the ephemeris (aux_vide, printed as "empty"), spacecraft systematics (aux_sys) — and a keep/reject disposition, in about a tenth of a second per star, entirely offline (no external service calls).

The frozen model, its full performance record and its known limitations are documented in the model card, linked from this page: https://gitlab.com/yohanntschudi/exoplanets-project/-/blob/main/documentation/pipeline_ml/VETTER_MODEL_CARD.md

Install

Python ≥ 3.10 required — check with python3 --version. Work in a fresh virtual environment (system Pythons are often older and their site-packages messy):

macOS / Linux:

python3.11 -m venv vesper-env          # any Python >= 3.10
source vesper-env/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install "tess-vesper[acquire,spatial]"

Windows (PowerShell):

python -m venv vesper-env              # any Python >= 3.10
vesper-env\Scripts\Activate.ps1
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install "tess-vesper[acquire,spatial]"

If PowerShell refuses to run Activate.ps1 (execution policy), skip activation entirely and call the venv's executables by path — it works identically: vesper-env\Scripts\vesper.exe vet-batch ....

CPU-only torch is enough. The [acquire] extra adds lightkurve, used by vesper fetch to download and prepare TESS photometry; the [spatial] extra (lightkurve + tess_prf) lets VESPER measure the difference-image centroid itself — the pixel evidence that separates a background eclipsing binary from an on-target signal, and the configuration the model was certified with. The wheel bundles the frozen model (weights, calibrator, decision threshold, M-dwarf stellar catalog) and the artifacts' SHA-256 fingerprints are checked at every load.

How it works

  1. You provide the ephemeris — VESPER judges a candidate at a given (period, T0, duration); it complements your transit search and your follow-up, taking the statistical-vetting step in between.
  2. VESPER prepares its own photometry. From stitched, median-normalised PDCSAP flux before any detrending, it removes stellar variability with its own Gaussian-process model on a 200 s grid — the exact preparation the network was trained and certified on. vesper fetch builds that input for any TIC directly from the TESS archive. Supplying your own curves instead: one pickle per host, named TIC{tic}_stitched.pkl, holding a dict with keys time (BTJD), flux (PDCSAP, quality flag 0, per-sector median-normalised to ~1.0, before any stellar-variability detrending), and optionally flux_err and sector — exactly what vesper fetch writes. Do not feed already-detrended flux: the certified numbers do not hold for it.
  3. It folds and judges — pixels included. The signal is folded into shape views (global, transit zoom, secondary, odd/even, per-observing-block), normalised to the star's own noise, and weighed together with the stellar parameters (bundled M-dwarf catalog, with an automatic TIC-8 lookup for hosts outside it — the stellar_source column says which) and the difference-image centroid: with the [spatial] extra installed, VESPER downloads the target pixel files and measures where on the pixels the dip occurs (deterministic, all available sectors — the heaviest step: every 2-min TPF of the host). --no-spatial skips it; without the extra, signals serve with a neutral spatial vector, labelled spatial_status=unmeasured — keep-rates on true planets are measured to be lower in that mode.
  4. It answers in calibrated units. p_cal is a calibrated probability; the shipped threshold (0.29565…, set on the model's sealed calibration split to keep ≥ 95 % of its planets — 96.1 % realized there, 92.2 % of confirmed planets kept on the certified hold-out) turns it into a disposition, and the named impostor heads tell you what the signal most resembles when it is not a planet.

Domain of validity: TESS M dwarfs (Teff ≲ 4,000 K), periods ~0.5–100 d, native cadences 20–300 s (served on a uniform 200 s grid; coarser products — e.g. native 600 s — are not servable). Anything the data contract cannot serve comes back as an explicit blocked:... status, never a silent skip. The contract checks the data, not the star: VESPER does not verify that your target is an M dwarf — a K- or G-dwarf curve will serve and return a number, but an unvalidated one. Check Teff yourself; outside the M-dwarf regime the output is uncertified.

Try it — the bundled example

Twelve signals on six M-dwarf hosts, both sides of the decision: L 98-59 (three small confirmed planets, plus one unconfirmed 1.05 d candidate signal — judge it yourself), TOI-700 (four confirmed planets, including the habitable-zone TOI-700 d), and four TFOPWG-certified false positives spanning the impostor zoo — a 22.6 % deep eclipse, a short-period eclipsing binary, a long-period shallow false alarm, and a 790 ppm signal with a perfectly planet-like depth.

vesper example
vesper fetch --candidates candidates_example.csv --out-dir example_curves
vesper vet-batch --candidates candidates_example.csv --curves-dir example_curves --out example_results.csv

The fetch downloads every SPOC-family sector of all six stars — TOI-700 alone has 30+ — through lightkurve's cache (~/.lightkurve/cache): a few hundred MB of FITS and several network-bound minutes on the first run. Stars whose pickle already exists in --out-dir are skipped, so an interrupted fetch can simply be re-run. With the [spatial] extra installed, vet-batch then also measures the difference-image centroid of each signal — that step downloads the 2-min target pixel files and is the long one on many-sector stars; add --no-spatial for a quick photometry-only pass. Measurements are saved to a <out>_spatial.csv sidecar written incrementally and reloaded on start-up: an interrupted run resumes where it stopped by simply re-running the same command, and finished measurements can be reused forever via --spatial <sidecar>.

For your own targets, write the same kind of CSV (header exactly as below, no spaces after the commas; extra columns such as toi or note are ignored):

tic_id,period_days,t0_btjd,duration_hours,depth_ppm,planet_num
307210830,7.450726,1355.290002,1.68,1002.2,4

t0_btjd is BTJD = BJD_TDB − 2,457,000 (native TESS time). ExoFOP lists full BJD epochs — subtract 2,457,000, or the row comes back blocked:t0_not_btjd. The four first columns are required on every row; depth_ppm (feeds the deep-eclipse prior) and planet_num (row labelling) are optional. Single candidates:

vesper vet --tic 307210830 --period 7.450726 --t0 1355.29 --duration-h 1.68 \
           --curves-dir example_curves

Reading the output

The results CSV (--out) echoes your input columns, then carries the science columns below, plus diagnostics (p_raw — the pre-calibration score; kept_0.5/kept_0.9 — stricter fixed thresholds; cascade_depth_source; n_sec_measured/n_sec_served — centroid-evidence sector count before/after its cap; log_scatter; cadence_s_native/ cadence_s_served). The console prints the same information as one aligned table per host.

Column Meaning
p_cal calibrated P(planet) — the number to read
kept_literal p_cal ≥ the shipped threshold — the threshold-only verdict (the calibration-split recall-95 operating point; hold-out performance in the model card §5)
cascade_fp the deep-eclipse prior fired (depth > 50,000 ppm and p_cal < 0.9). For very deep candidates around small stars, read kept_literal — already in the CSV — since giant planets on M dwarfs can exceed that depth; --no-cascade disables the rule outright
final_literal the disposition: True = keep as a planet candidate
aux_beb … aux_sys the seven impostor heads (mapping in the opening paragraph) — triage pointers to the most likely false-positive channel, not individually calibrated probabilities
spatial_status ok(n/m sec) = centroid measured (n sectors passed the S/N gate of m usable); failed:... = measurement attempted, unusable; unmeasured = neutral mode (--no-spatial, or the [spatial] extra not installed)
stellar_source catalog (bundled M-dwarf catalog) / tic8 (live TIC-8 lookup) / imputed (no parameters found — served with training-mean values)
row_status served, or an explicit blocked:... reason

What p_cal is calibrated against. The calibration set is real M-dwarf light curves carrying injected planets and constructed impostors, held out from training — p_cal is well-scaled under that mixture. It is not a TRICERATOPS-style false-positive probability computed against a Galactic stellar-population model, and a high p_cal is not by itself grounds for statistical validation. Use it to rank and triage; validation still requires independent evidence.

License and citation

MIT. The reference article is in preparation; until it is out, cite this package and its model card (linked above), which carries the full provenance of the frozen model.

Metadata

Release files for tess-vesper 0.2.4

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

Built distribution (wheel)

Table of built distributions (wheels) for tess-vesper 0.2.4
File Interpreter ABI Platform
tess_vesper-0.2.4-py3-none-any.whl Python 3 none any Details

Release files / tess_vesper-0.2.4-py3-none-any.whl

Download URL tess_vesper-0.2.4-py3-none-any.whl
Size 645.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ca9c0dee0a43d43c84501bdfa65a3d89fd4d5c734ec69c2510f78fcf1b92a6a
BLAKE2b-256 checksum
How to use checksums
98644364163e9a10a98e58f4437bb97ae209c2f513fffc86735f7a378df1c320
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

1.0.0

1 release file

0.2.7

1 release file

0.2.6

1 release file

0.2.5

1 release file

This release

0.2.4 This release

1 release file

0.2.3

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

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