Metadata-Version: 2.4
Name: tess-vesper
Version: 0.2.7
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 :: 4 - Beta
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.**

The frozen model, its certified performance and its limitations are
documented in the model card:
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 model (2.5 MB); its SHA-256 fingerprints are
verified at every load. Nothing else to configure.

## 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.

## 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 deep-eclipse prior |
| `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. **It answers in calibrated units**: `p_cal`, the shipped decision
   threshold, and the named impostor heads.

## Reading the results

The results CSV (`--out`) echoes your inputs, then:

| column | meaning |
|---|---|
| `p_cal` | calibrated P(planet) — the number to read |
| `final_literal` | the verdict: True = keep as a planet candidate |
| `kept_literal` | threshold-only verdict (deep-eclipse prior ignored) |
| `cascade_fp` | the deep-eclipse prior fired (depth > 50,000 ppm and `p_cal` < 0.9). Giant planets around small stars can trip it — read `kept_literal` too, or use `--no-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 |

`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 < 1 d). 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.
