Skip to content

Major update microlensing - #35

Merged
eagnespuerto merged 2 commits into
mainfrom
major-update-microlensing
Aug 12, 2026
Merged

Major update microlensing#35
eagnespuerto merged 2 commits into
mainfrom
major-update-microlensing

Conversation

@eagnespuerto

Copy link
Copy Markdown
Owner

Refined the microlensing sevtion to add FFI and Gaia overlay and other changes to fully align it with the transit tab such as ExoFOP compatible observables section

eagnespuerto and others added 2 commits August 10, 2026 18:34
Delivers the follow-on from the Harris et al. 2026 credit: an in-app
implementation of the joint TESS + Gaia PSPL fit that paper uses to break
the tE ↔ u0 degeneracy TESS's short single-sector baseline cannot resolve.
Single-lens only for now — binary-lens (planetary anomaly) joint fits
remain future work.

Backend:
- backend/app/gaia_photometry.py — pulls a per-alert G-band CSV from the
  public Gaia Alerts feed (https://gsaweb.ast.cam.ac.uk/alerts), plus a
  cone-search helper against the cached alerts master index. Errors
  inflated per Kruszynska+2022 (A&A 662 A59) approximation: σ² =
  (1.5·σ_reported)² + (3 mmag)². Permissive CSV parser handles the
  various header spellings the Gaia feed has drifted through, drops
  99.999 sentinel rows, and validates alert IDs against /^Gaia[0-9A-Za-z]+$/
  to keep path segments clean.

- backend/app/microlensing.py::fit_pspl_joint — 7-parameter fit sharing
  (t0, tE, u0) across bands with per-band (f_s, f_b). Residuals from both
  bands concatenated with per-cadence weights, one scipy.optimize.least_squares
  call. Returns per-band χ² and joint BIC.

- backend/app/microlensing.py::analyze_event_joint — full pipeline: TESS
  windowing + baseline-normalisation (same recipe as single-band),
  Gaia mag → relative flux via 10^(-0.4·(G-G_base)) with propagated errors
  σ_F = F·0.4·ln(10)·σ_G, out-of-event baseline mag from median of epochs
  outside t0 ± 100 d (faint-tail-quantile fallback), JD_TCB → BTJD via
  −2 457 000 (TCB↔TDB seconds-level offset ignored — negligible for
  microlensing scales). Recomputes observables + planet predictions
  from the joint-fit shared geometry.

Three new endpoints:
- POST /api/microlensing/gaia_alert_lightcurve  {alert_id} → GaiaLightcurve
- GET  /api/microlensing/gaia_alerts_near       ?ra&dec&radius_arcsec&microlensing_only
- POST /api/microlensing/fit_joint              {tess…, gaia…, window, t0_guess} → JointFitResponse

Frontend:
- MicrolensingClassifier gains a Gaia baseline section: alert-ID text input +
  Fetch Gaia LC button, Search near target coords button (uses prefill or
  autoload coords), clickable list of nearby microlensing alerts, and a
  compact loaded-state summary (n_points, JD range, G range, error-model note).
- Fit joint (TESS + Gaia) button appears alongside the standard Fit button
  once a Gaia LC is loaded. Runs the joint fit; results render in a new
  JointResultsPanel showing shared params + per-band χ² + BIC +
  observables + planet predictions.

Tests: 43 pass total. New:
- test_gaia_photometry.py (14): URL validation, Kruszynska error inflation
  with a known reported error + missing-error magnitude-tiered fallback,
  permissive CSV parsing across header variants + sentinel-null filtering,
  mocked fetch, alerts index parsing, cone-search filtering by class +
  distance (Haversine on sphere).
- test_microlensing.py joint fit (3): shared-parameter recovery from a
  synthetic two-band PSPL (t0/tE/u0 recovered within few-percent), input
  validation (rejects <5 Gaia points), stable response-shape contract.

Docs:
- SCIENCE.md §18.3 added: full joint-fit derivation (mag→flux conversion,
  error propagation, time-system handling, Kruszynska calibration formula,
  scipy fit setup), references Harris et al. 2026 §5 for the pyLIMA
  reference implementation Vetstar mirrors in single-lens form.
- README §API endpoints lists the three new routes with query/body shapes.
- README §Project layout adds gaia_photometry.py.

Verified end-to-end in the browser with a synthetic Gaia LC (mag = 17.5 −
2.5·log10(A(t)), 60 epochs over 5 years) injected into the frontend Gaia
fetcher via fetch mock: joint fit recovered Gaia baseline G = 17.500
exactly, χ²(Gaia) ≈ 0 (noiseless), χ²(TESS) = 99.1 on 120 noisy points,
BIC = 135.5, joint results panel rendered with shared params + per-band
goodness + observables + planet predictions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fixes the "ExoFOP zip" that was actually just an analysis bundle, adds a
proper transit-tab ExoFOP-TESS bulk-upload panel, brings in the missing
FFI+Gaia overlay, an ExoFOP planet-parameters table, and CyclingLoader
loading circles across every long-running action.

ExoFOP zip conventions (fix)
- Reuse the shared ExofopBulkPanel from the transit tab: bundles PNGs as
  TIC{id}O-xxYYYYMMDD.slug.png inside xxYYYYMMDD-nnn.zip with the
  matching .txt descriptor per the ExoFOP-TESS bulk file upload spec.
  Initials + data tag persisted in localStorage the same way. Only
  mounts once the classifier has a TIC id.
- Rename the old ad-hoc "Download ExoFOP package" button to
  "Analysis bundle" so it stops claiming an ExoFOP-conformant format.
  The bundle itself (summary.csv, lightcurve_windowed.csv, fit_full.json,
  notes.md, plot.png) is unchanged and still useful for local archiving.

FFI cutout + Gaia DR3 overlay
- New backend module microlensing_ffi.py: tangent-plane sky→pixel
  projection at 21″/px, matplotlib inset overlay of Gaia DR3 sources
  sized by G-band magnitude, target crosshair, source table with
  source_id + separation returned alongside the PNG. Gaia cone-search
  via astroquery.gaia (radius = cutout diagonal). Non-fatal on Gaia
  query failure — base cutout still returned.
- New endpoint POST /api/microlensing/ffi_cutout, reuses the transit
  pipeline's make_ffi_cutout() for the underlying TESScut fetch.
- Classifier auto-fetches when target coords + sector are known.
  FfiCutoutSection renders the PNG + a summary card (sector, frames
  stacked, FOV radius, Gaia source count, brightest neighbours drawer).
- PDF vetting report gains an FFI + Gaia overlay section.

ExoFOP planet parameters (microlensing-derivable subset)
- New helper compute_exofop_planet_rows() mirrors the transit tab's
  observables.exofop_param_rows in shape and naming but scoped to what
  a single-lens fit can honestly report: t0/tE/u0 direct outputs; host
  M_L and R_star under fiducial bulge priors via a Pecaut & Mamajek
  (2013) dwarf-sequence M-R interpolation; r_E in AU and projected
  a_perp; planet mass floor in Earth/Jupiter units + Rp/R_star from
  the Chen & Kipping (2017) forecaster + q_min. Un-derivable rows
  (Orbital Period, Eccentricity, Inclination, T_eq, RV K) explicit
  None so the frontend renders "—" without pretending.
- analyze_event + analyze_event_joint both populate exofop_rows.
- Frontend ExofopPlanetParamsPanel renders the table with required-
  field markers and the "—" convention.
- PDF report gains an ExoFOP planet-parameters table.

Loading circles (transit-tab convention)
- Extract CyclingLoader from App.tsx into a shared Loaders.tsx.
- Add microlensing message packs (MICROLENSING_FIT_MSGS,
  MICROLENSING_JOINT_MSGS, GAIA_FETCH_MSGS, GAIA_SEARCH_MSGS,
  TIC_LC_MSGS, COORD_LC_MSGS, COVERAGE_MSGS, PDF_MSGS, FFI_CUTOUT_MSGS)
  matching the transit tone.
- Swap every plain "Fitting…"/"Fetching…" text for the appropriate
  CyclingLoader (Fit PSPL, Fit joint, TIC fetch, coord-autoload,
  Gaia fetch, Gaia search, PDF download, FFI section).

Tests: 45 pass (2 new — ExoFOP row shape/naming, Pecaut-Mamajek
R_star interpolation).

Verified end-to-end in browser: fit → verdict MICROLENSING, ExoFOP
planet table with Host R_star=0.30 R_Sun, planet mass floor 4.82 M_Earth,
Rp/R_star=0.062, a_perp=1.91 AU. FFI section auto-populated (mocked
backend): sector S088, 2 Gaia sources in FOV. ExofopBulkPanel mounted
once TIC was known.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@eagnespuerto
eagnespuerto merged commit fbfb5d2 into main Aug 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant