Skip to main content

Greedy observing-calendar scheduler for radial-velocity follow-up campaigns

Project description

rvcadence

Greedy observing-calendar scheduler for radial-velocity follow-up campaigns.

Given a number of observations to schedule, one or more planets' orbital periods (and, optionally, the star's rotation period), and a set of visibility windows, rvcadence picks the calendar dates that best cover all phase cycles while keeping observations temporally spread out. Optionally excludes nights where the Moon is too close to the target for high-resolution spectroscopy.

Algorithm walkthrough

Full-quality version: examples/explainer/CadenceGreedyExplainer.mp4

Install

pip install rvcadence          # core scheduler, zero dependencies
pip install rvcadence[moon]    # + lunar pollution avoidance (astropy)

Quickstart

from datetime import date
from rvcadence import plan_calendar

result = plan_calendar(
    n_obs=20,
    periods_d=9.53,
    season_start=date(2026, 5, 1),
    season_end=date(2027, 4, 30),
    rotation_period_d=12.45,
    windows="2026-05-01 to 2026-05-19; 2026-07-29 to 2027-04-30",
)
print(result.dates)
print(f"median gap: {result.median_gap_d} d, mean gap: {result.mean_gap_d} d")

For a multi-planet system, pass a list of periods — coverage is optimized for the worst-covered planet at each step, not an average:

result = plan_calendar(
    n_obs=20,
    periods_d=[9.53, 21.7],   # two known/candidate planets
    season_start=date(2026, 5, 1),
    season_end=date(2027, 4, 30),
)

With lunar avoidance (requires pip install rvcadence[moon]):

import astropy.units as u
from astropy.coordinates import EarthLocation, SkyCoord

paranal = EarthLocation(lat=-24.6272 * u.deg, lon=-70.4039 * u.deg, height=2635 * u.m)
target = SkyCoord(ra=123.45 * u.deg, dec=-12.3 * u.deg)

result = plan_calendar(
    n_obs=20,
    periods_d=9.53,
    season_start=date(2026, 5, 1),
    season_end=date(2027, 4, 30),
    target_coord=target,
    observer_location=paranal,
    min_moon_sep_deg=30.0,
)

The default 30° threshold is a widely-used rule-of-thumb avoidance radius against lunar scattered-light contamination in high-resolution spectroscopy; override min_moon_sep_deg for a different instrument or tolerance. Nights are evaluated at local solar midnight, sunset-labeled (the night of date D runs from sunset on D to sunrise on D+1).

How it works

Starting from the first and last available dates, the algorithm repeatedly adds the candidate date that best fills gaps in planet-orbital-phase coverage (and stellar-rotation-phase coverage, if known), weighted against how far it is in time from already-selected dates. For multiple planets, phase coverage is the worst-case across all periods — a candidate only scores well if it improves coverage for whichever planet is currently least-covered, so one well-phased planet can't mask a poorly-phased one:

score = 0.55 · d_planet_phase + 0.30 · d_rotation_phase + 0.15 · d_time_spread   (rotation period known)
score = 0.80 · d_planet_phase + 0.20 · d_time_spread                             (rotation period unknown)

See examples/explainer/ for the full animated walkthrough (manim source + rendered mp4) — the example imports its scoring logic directly from this package (see tests/test_explainer_example.py), so it can't drift out of sync with the real algorithm.

Development

git clone <repo-url>
cd rvcadence
pip install -e ".[dev,moon]"
pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rvcadence-0.1.0.tar.gz (3.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rvcadence-0.1.0-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file rvcadence-0.1.0.tar.gz.

File metadata

  • Download URL: rvcadence-0.1.0.tar.gz
  • Upload date:
  • Size: 3.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rvcadence-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f019a048c281cb7d4c2ff1093a315ab8cdf873489c8a6d7df19704fd065293d2
MD5 17635cf359e0cf4952bcc2f770cc8b34
BLAKE2b-256 2d077ea364f0691339ce91b2e3f2a04f27759fa6d49be6c2f095ded9db8abd12

See more details on using hashes here.

Provenance

The following attestation bundles were made for rvcadence-0.1.0.tar.gz:

Publisher: publish.yml on pierrotlamontagne/rvcadence

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rvcadence-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rvcadence-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rvcadence-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1cc419ea38bce8a198314ab67ee1ca00d5bac4ce7ecfb1117a948240a1dc2d6e
MD5 430bea63bce39e74fcef86f358a87d8a
BLAKE2b-256 37e619adef65beb041ed4a333eb77393609cbe58a020298b8e5fea36f0e31b65

See more details on using hashes here.

Provenance

The following attestation bundles were made for rvcadence-0.1.0-py3-none-any.whl:

Publisher: publish.yml on pierrotlamontagne/rvcadence

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page