Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions exotic/api/elca.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,9 +374,17 @@ def transit_duration(values):
if not np.isfinite(chord_sq) or chord_sq <= 0 or not np.isfinite(impact_scale) or impact_scale <= 0:
return np.nan

argument = np.sqrt(chord_sq) / (impact_scale * sin_inc)
# The arcsin argument is normalized by a*sin(i) (NOT by the eccentricity-
# scaled planet-star separation), and the eccentric orbital-speed factor
# sqrt(1-e^2)/(1+e*sin(omega)) multiplies the whole duration — the same
# correction issue #1383 / PR #1384 applied to the three copies of this
# formula in exotic.py and transit QC; this fourth copy was missed. The
# broken form biased the ns duration prior, the QC duration score, and the
# exposure-smearing window for every eccentric target.
argument = np.sqrt(chord_sq) / (ars * sin_inc)
argument = float(np.clip(argument, -1.0, 1.0))
duration = (period / np.pi) * np.arcsin(argument)
eccentric_speed_factor = np.sqrt(1.0 - ecc ** 2) / max(np.finfo(float).eps, 1.0 + ecc * np.sin(omega))
duration = (period / np.pi) * np.arcsin(argument) * eccentric_speed_factor
return float(duration) if np.isfinite(duration) and duration > 0 else np.nan


Expand Down
21 changes: 21 additions & 0 deletions tests/test_ephemeris_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,24 @@ def archive_lookup():
{'pName': 'Example b', 'pPer': None, 'midT': 2460000.25},
archive_lookup=archive_lookup,
)


def test_elca_transit_duration_matches_model_for_eccentric_orbits():
"""Regression for the fourth site of issue #1383: elca.transit_duration
retained the inverted-eccentricity formula after PR #1384 fixed the three
copies in exotic.py. The analytic duration must match the transit model's
own first-to-fourth-contact duration for eccentric geometries (it was off
by 1.95x at e=0.3/omega=90 and 3.48x at e=0.5/omega=90)."""
import numpy as np
from exotic.api.elca import transit, transit_duration

for ecc, omega in [(0.0, 90.0), (0.3, 90.0), (0.3, 270.0), (0.5, 90.0)]:
values = dict(u0=0.5, u1=0.1, u2=0.3, u3=-0.1, rprs=0.1, per=3.0,
ars=8.0, tmid=1.0, ecc=ecc, omega=omega, inc=88.0)
times = 1.0 + np.linspace(-0.35, 0.35, 300001)
flux = transit(times, values)
in_transit = np.flatnonzero(flux < 1 - 1e-9)
measured = times[in_transit[-1]] - times[in_transit[0]]
analytic = transit_duration(values)
assert analytic == pytest.approx(measured, rel=0.01), (
f"e={ecc} omega={omega}: analytic {analytic*24:.4f} h vs model {measured*24:.4f} h")