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.
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f019a048c281cb7d4c2ff1093a315ab8cdf873489c8a6d7df19704fd065293d2
|
|
| MD5 |
17635cf359e0cf4952bcc2f770cc8b34
|
|
| BLAKE2b-256 |
2d077ea364f0691339ce91b2e3f2a04f27759fa6d49be6c2f095ded9db8abd12
|
Provenance
The following attestation bundles were made for rvcadence-0.1.0.tar.gz:
Publisher:
publish.yml on pierrotlamontagne/rvcadence
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rvcadence-0.1.0.tar.gz -
Subject digest:
f019a048c281cb7d4c2ff1093a315ab8cdf873489c8a6d7df19704fd065293d2 - Sigstore transparency entry: 2128351899
- Sigstore integration time:
-
Permalink:
pierrotlamontagne/rvcadence@84515c3e6a8a02d0a8993ea4a0684f65815de78f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/pierrotlamontagne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@84515c3e6a8a02d0a8993ea4a0684f65815de78f -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cc419ea38bce8a198314ab67ee1ca00d5bac4ce7ecfb1117a948240a1dc2d6e
|
|
| MD5 |
430bea63bce39e74fcef86f358a87d8a
|
|
| BLAKE2b-256 |
37e619adef65beb041ed4a333eb77393609cbe58a020298b8e5fea36f0e31b65
|
Provenance
The following attestation bundles were made for rvcadence-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on pierrotlamontagne/rvcadence
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rvcadence-0.1.0-py3-none-any.whl -
Subject digest:
1cc419ea38bce8a198314ab67ee1ca00d5bac4ce7ecfb1117a948240a1dc2d6e - Sigstore transparency entry: 2128351968
- Sigstore integration time:
-
Permalink:
pierrotlamontagne/rvcadence@84515c3e6a8a02d0a8993ea4a0684f65815de78f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/pierrotlamontagne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@84515c3e6a8a02d0a8993ea4a0684f65815de78f -
Trigger Event:
release
-
Statement type: