spino.pipeline.phase_scheduler module

Phase Scheduler

Standalone tool to schedule transit, pre-eclipse, and post-eclipse observations. Reads the NASA Exoplanet Archive PS table, filters by user criteria, computes observable events per night, and produces altitude-vs-time plots, calendar summaries, and a P-R desert landscape.

All configuration lives in phase_config.py.

spino.pipeline.phase_scheduler.load_catalog(csv_path, source)[source]

Load a NASA Exoplanet Archive PS CSV. Keep only confirmed, non-controversial planets.

source is one of “NEA”, “TESS”, “BOTH” and controls the derived catalog_source column:

  • “NEA” → all rows get “NEA”

  • “TESS” → all rows get “TESS”

  • “BOTH” → per row: “TESS” if disc_facility contains “TESS”,

    else “NEA”

spino.pipeline.phase_scheduler.load_desert_polygon(boundary_file)[source]

Load the CG24 KDE boundary as a closed matplotlib Path.

spino.pipeline.phase_scheduler.is_in_desert(period, radius_earth, polygon)[source]

True if planet is in the desert (outside KDE contour, inside bbox).

spino.pipeline.phase_scheduler.filter_catalog(df, desert_filter, polygon, extra_filters)[source]

Apply desert polygon filter + extra column filters.

spino.pipeline.phase_scheduler.compose_best_rows(df)[source]

Merge multiple references per planet into one composite row.

Per planet:
  • Ephemeris (pl_orbper, pl_tranmid, errors, pl_tsystemref) comes from the row minimizing combined relative ephemeris uncertainty (sqrt((sigma_P/P)^2 + sigma_T0^2)); ties broken by pl_pubdate desc. Mimics NEA TransitView’s “most precise ephemeris” rule.

  • All other fields: per-field, the most recent (pl_pubdate desc) non-null value across this planet’s rows.

  • Identity fields are inherited from the chosen ephemeris row.

The returned DataFrame carries an extra column _field_sources (dict[field → pl_refname]) so the summary PDF can attribute each displayed value to its donor reference.

Planets with no row containing pl_orbper, pl_tranmid, ra, and dec simultaneously are skipped (cannot schedule).

spino.pipeline.phase_scheduler.to_bjd_tdb(t0_value, system_ref, ra_deg, dec_deg)[source]

Convert t0_value (Julian Date in the time system named by system_ref) to BJD_TDB. Returns the converted JD as a float.

Recognized values (NEA convention, matched case-insensitive after stripping non-alphanumerics):

  • BJD_TDB / BJD-TDB / BJD : returned unchanged

  • HJD / HJD_UTCadd (BJD-HJD) using astropy

    light_travel_time barycentric/heliocentric

  • JD_UTC / JD : add (BJD-JD) ≈ (TDB-UTC) + barycentric ltt

Missing/unknown system refs are treated as BJD_TDB with a one-time warning per token, and the value is returned unchanged.

spino.pipeline.phase_scheduler.compute_transit_geometry(row)[source]

Compute primary transit and secondary eclipse geometry.

Uses Winn (2010) arXiv:1001.2010:

Eq. 14-15 for T14/T23, Eq. 16 for ecc correction, Eq. 33 for phi_sec.

Omega convention: NEA pl_orblper = omega_planet. Winn uses omega_star = omega_planet + 180 deg.

spino.pipeline.phase_scheduler.compute_event_windows(geom)[source]

Phase windows for transit, pre-eclipse, post-eclipse. Phases in [0, 1). Transit wraps around 0.

spino.pipeline.phase_scheduler.compute_all_nights(target, obs, date_range, constraints, resolution_min=2)[source]

Compute observable windows for every night in date_range.

Parameters:
  • target (dict {name, ra_deg, dec_deg, period, t0_bjd})

  • obs (dict {lat, lon, alt, name})

  • date_range (dict {start, end} YYYY-MM-DD)

  • constraints (dict {min_target_alt, max_sun_alt, moon_dist_factor})

  • resolution_min (int grid resolution in minutes)

Return type:

List of night dicts.

spino.pipeline.phase_scheduler.match_events(night, event_windows, event_constraints, geom)[source]

For one observable night, check which events are schedulable.

Returns list of event dicts.

spino.pipeline.phase_scheduler.main()[source]