Skip to content

Fix: times_rise_transit_set returns phantom rise/set at a grazing crossing#55

Merged
architest merged 1 commit into
architest:masterfrom
mondsichtung:fix/rise-set-grazing-crossing-guard
Jul 7, 2026
Merged

Fix: times_rise_transit_set returns phantom rise/set at a grazing crossing#55
architest merged 1 commit into
architest:masterfrom
mondsichtung:fix/rise-set-grazing-crossing-guard

Conversation

@mondsichtung

Copy link
Copy Markdown
Contributor

The function that computes when a body rises, crosses the meridian, and sets starts with a good first guess for the setting time, then nudges it a couple of times to sharpen it. Each nudge divides by sin(H), where H is how far the body is from due south when it touches the horizon.

For a normal setting H is a healthy angle and the nudge is small. But when a body only just barely dips to the horizon (a "grazing" set, common for the Moon seen from far-north latitudes), H is almost zero, so sin(H) is almost zero, and dividing by it produces an enormous nudge. One nudge throws the estimate not
minutes but days away. The next nudge is then computed from a point so far off that it makes things worse, and the function reports a moonset time like 389 hours (about 16 days) from the requested day, an event that does not exist.

A legitimate nudge can only ever move the guess within the same rise-to-set window, which is at most half a day wide. So any nudge bigger than half a day is not a real correction, it is the calculation breaking down.

Concrete example (Moon, year 13, 22 December, high northern latitude):

latitude setting time returned (buggy) setting time (correct)
61.0 deg 37.3 hours 13.2 hours
61.1 deg 389.4 hours 13.1 hours

Before:

>>> from pymeeus.Angle import Angle
>>> from pymeeus.Coordinates import times_rise_transit_set
>>> # Moon apparent RA/Dec at 0h TD on 0013-12-21 / -22 / -23; a young crescent
>>> # whose diurnal arc barely clears the horizon at latitude 61.1 deg
>>> rising, transit, setting = times_rise_transit_set(
...     Angle(-89.8), Angle(61.1),
...     Angle(262.0147698256), Angle(-28.0285215200),
...     Angle(279.4044051918), Angle(-28.3676715704),
...     Angle(296.4258016266), Angle(-26.5431300711),
...     Angle(0.125), 10291.8794055557, Angle(3.6781774569))
>>> round(setting, 3)     # should be 13.095, the true moonset within the day
389.415

After:

>>> rising, transit, setting = times_rise_transit_set(
...     Angle(-89.8), Angle(61.1),
...     Angle(262.0147698256), Angle(-28.0285215200),
...     Angle(279.4044051918), Angle(-28.3676715704),
...     Angle(296.4258016266), Angle(-26.5431300711),
...     Angle(0.125), 10291.8794055557, Angle(3.6781774569))
>>> round(setting, 3)
13.095

The fix

Remember the original first guess. If a nudge would move the setting time by more than half a day, throw the nudge away, keep the first guess, and stop nudging that value.

The rising time and the setting time are handled separately, and the
meridian-crossing time (which never had this problem) is left alone. For every ordinary rise and set the nudges are tiny, well under the half-day limit, so nothing about the normal results changes.

@architest architest merged commit 6c5f0a1 into architest:master Jul 7, 2026
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.

2 participants