VESPER
Vetting Exoplanet Signals with Pixel-informed Evidence, Rapidly.
VESPER vets transiting-planet candidates around TESS M dwarfs. Give it a candidate ephemeris; it returns a calibrated probability that the signal is a planet, seven named impostor scores, and a keep/reject verdict — in about a tenth of a second per star once the data are in.
Everything else is fetched automatically from public archives: the photometry, the pixel data for the centroid measurement, the PRF models, the stellar parameters. One CSV in, one table out.
VESPER 1.0 ships an ensemble of four sibling networks trained on the
same school, their seeds fixed in advance; each member calibrates its own
probability and the served p_cal is the mean of the four. On its sealed
evaluation (162 sequestered confirmed-planet hosts, 2026-08-17) it keeps
160/167 = 95.8 % of confirmed planets — every one of the 10 deeper
than 50,000 ppm included — at 0.099 false alarms per host, against
155/167 = 92.8 % at 0.119 false alarms per host for the TRICERATOPS
stage it replaces (funnel-only, the same convention as the 0.099;
counting every non-catalogue-planet signal kept, the pair is 0.119 vs
0.139), and the vetting itself took 24.1 s for 150 hosts.
The frozen ensemble, its certified performance and its limitations are documented in the model card (one provenance note matters: the sealed terrain behind these numbers was exposed twice, each time under a pre-registered protocol — 2026-08-07 and 2026-08-17 — and the second read is terminal): https://gitlab.com/yohanntschudi/exoplanets-project/-/blob/main/documentation/pipeline_ml/VETTER_MODEL_CARD.md
Install
Python ≥ 3.10, in a fresh virtual environment. CPU-only torch is enough.
macOS / Linux:
python3.11 -m venv vesper-env
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
vesper-env\Scripts\Activate.ps1
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install "tess-vesper[acquire,spatial]"
If PowerShell blocks Activate.ps1, skip activation and call
vesper-env\Scripts\vesper.exe directly — it works identically.
The wheel bundles the frozen ensemble (~2.7 MB); its SHA-256 fingerprints are verified at every load. Nothing else to configure.
Inside the package the artifacts live in one directory: four member
subdirectories s101/ s202/ s303/ s404/ (each holding model_best.pt,
calibrateur_isotonique.pkl and args.json), candidate_config.json
(the sealed pin table: per-member SHA-256, threshold, school manifest),
threshold.json (threshold provenance) and the bundled stellar catalog.
$VESPER_ARTIFACTS may point to an alternative directory with the same
layout; the fingerprints are checked wherever the artifacts come from.
Try it — two commands
vesper example
vesper vet-batch --candidates candidates_example.csv --curves-dir example_curves --out example_results.csv
The bundled example is twelve signals on six M-dwarf hosts: the confirmed planets of L 98-59 and TOI-700 (including the habitable-zone TOI-700 d), one unconfirmed candidate signal, and four TFOPWG-certified false positives. VESPER downloads the photometry and the pixel data itself — the first run takes a while (TOI-700 alone has 30+ sectors). Everything is cached, and an interrupted run resumes with the same command.
For each host you get a table like:
TIC 307210830 (4 signals)
sig P [d] T0 [BTJD] dur[h] P(pl) verdict BEB alias EB rot comp empty syst
.02 2.2531 1354.9054 0.24 1.000 KEEP 0.000 0.000 0.013 0.000 0.008 0.000 0.000
.01 1.0492 1354.7153 0.32 0.017 REJECT 0.071 0.113 0.811 0.024 0.033 0.008 0.085
The .01 line is the unconfirmed candidate: rejected, and the EB head
says why. (The scores in this table illustrate the output format — run
the example to get the shipped ensemble's actual numbers.)
Your own candidates
One CSV row per candidate:
| column | unit | required |
|---|---|---|
tic_id |
TIC number | yes |
period_days |
days | yes |
t0_btjd |
BTJD = BJD_TDB − 2,457,000 | yes |
duration_hours |
hours | yes |
depth_ppm |
ppm | optional — feeds the cascade_fp diagnostic |
planet_num |
integer label | optional |
vesper vet-batch --candidates my_candidates.csv --curves-dir curves --out results.csv
Two classic traps:
- ExoFOP lists full BJD epochs — subtract 2,457,000, or the row comes
back
blocked:t0_not_btjd. - Header exactly as above, no spaces after the commas.
Single candidate:
vesper vet --tic 307210830 --period 7.450726 --t0 1355.29 --duration-h 1.68 --curves-dir curves
What VESPER fetches for you
| data | source | opt-out | without it |
|---|---|---|---|
| photometry (SPOC light curves) | MAST | --no-fetch |
provide the curve pickles yourself |
| pixel data + PRF models (centroid measurement) | MAST + STScI | --no-spatial |
neutral spatial vector, labelled |
| stellar parameters | bundled M-dwarf catalog, then TIC-8 | --no-tic8 |
training-mean values, labelled |
Everything is cached, nothing is downloaded twice. Centroid measurements
are saved one by one to a <out>_spatial.csv sidecar: an interrupted run
resumes where it stopped, and the sidecar is reusable forever via
--spatial.
Bringing your own photometry: one pickle per host, named
TIC{tic}_stitched.pkl, a dict with time (BTJD), flux (PDCSAP
before any detrending, median ≈ 1.0) and optionally
flux_err/sector — exactly what vesper fetch writes. Never feed
detrended flux: VESPER does its own detrending, and that is part of the
certified contract.
How it works
- You provide the ephemeris. VESPER judges the signal at that period; it does not search for periods.
- It prepares its own photometry — stellar variability is removed with the same Gaussian-process model the network was trained with, on a 200 s grid.
- It folds and judges: shape views (global, transit zoom, secondary, odd/even, per-observing-block), the star's parameters, and the difference-image centroid — the pixel evidence that separates a background eclipsing binary from an on-target signal.
- Four networks answer, in calibrated units: each ensemble member
scores the signal and maps its score through its own isotonic
calibration;
p_calis the mean of the four calibrated probabilities, judged against the shipped decision threshold, alongside the named impostor heads.
Reading the results
The results CSV (--out) echoes your inputs, then:
| column | meaning |
|---|---|
p_cal |
calibrated P(planet) — the mean of the four members' calibrated probabilities; the number to read |
p_cal_s101 … p_cal_s404 |
the individual ensemble members' calibrated probabilities, for audit — a member far from the mean flags a signal worth a second look |
final_literal |
the verdict: True = keep as a planet candidate |
kept_literal |
p_cal at or above the frozen decision threshold. Equal to final_literal unless --cascade is passed |
cascade_fp |
diagnostic only: the retired deep-eclipse rule (depth > 50,000 ppm and p_cal < 0.9) would have rejected this row. Always reported, never decides — unless you opt in with --cascade |
aux_beb … aux_sys |
the impostor scores, in order: background EB, window alias, EB on target, stellar rotation, companion dilution, no signal, spacecraft systematics |
spatial_status |
ok(n/m sec) = centroid measured · failed:... = tried, unusable · unmeasured = skipped |
stellar_source |
catalog / tic8 / imputed |
row_status |
served, or an explicit blocked:... reason |
The deep-eclipse cascade is retired. The shipped disposition is
threshold-only: rejecting deep eclipses is something the network learned
in its school (V-vs-U bottom shape, secondary eclipses, duration–density
coherence, the star's radius), not a depth cut imposed on its output — a
depth cut kills exactly the genuine transiting giants around M dwarfs
that make deep signals interesting. --cascade re-enables the retired
rule for reproducing archived numbers only.
p_cal is calibrated against real M-dwarf light curves carrying injected
planets and constructed impostors. It is not a TRICERATOPS-style FPP,
and a high value is not by itself statistical validation: use it to rank
and triage; validation needs independent evidence.
Domain of validity
- TESS M dwarfs (Teff ≲ 4,000 K); periods ~0.5–100 d; native cadences 20–300 s (served on a 200 s grid; coarser products are refused with an explicit status).
- VESPER checks the data, not the star: a G-dwarf curve will serve and return a number — an uncertified one. Check Teff yourself.
- Known weak spot: ultra-short periods (P < 0.5 d — sub-hour transits leave few points per event on a 200 s grid). Full list in the model card.
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 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tess_vesper-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / tess_vesper-1.0.0-py3-none-any.whl
| Download URL | tess_vesper-1.0.0-py3-none-any.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7c5cb911ea2c775c21a9b23687c054227c0b672830c7bb34e0a0f901e37a5f95
|
|
BLAKE2b-256 checksum How to use checksums |
cd3f3c390794b59536fc350b9c2c1631ccdb96606c326327b0fd0b7a8ae11af9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|