Metadata-Version: 2.4
Name: tess-vesper
Version: 1.0.0
Summary: VESPER - fast learned vetting of transiting-planet candidates around TESS M dwarfs
Author: Yohann Tschudi
License: MIT
Project-URL: Repository, https://gitlab.com/yohanntschudi/exoplanets-project
Project-URL: Model card, https://gitlab.com/yohanntschudi/exoplanets-project/-/blob/main/documentation/pipeline_ml/VETTER_MODEL_CARD.md
Keywords: TESS,exoplanets,vetting,M dwarfs,transits
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Astronomy
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.24
Requires-Dist: torch>=2.0
Requires-Dist: scikit-learn>=1.3
Requires-Dist: celerite2>=0.3.0
Provides-Extra: acquire
Requires-Dist: lightkurve>=2.4.0; extra == "acquire"
Provides-Extra: spatial
Requires-Dist: lightkurve>=2.4.0; extra == "spatial"
Requires-Dist: tess_prf==0.1.3; extra == "spatial"
Requires-Dist: scipy>=1.10; extra == "spatial"
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"

# 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

1. **You provide the ephemeris.** VESPER judges the signal at that period;
   it does not search for periods.
2. **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.
3. **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.
4. **Four networks answer, in calibrated units**: each ensemble member
   scores the signal and maps its score through its own isotonic
   calibration; `p_cal` is 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.
