Skip to content

RuntimeWarning from almanac.py line 339 (divide by zero?) #1114

@aendie

Description

@aendie

Using Skyfield 1.54 I came across a somewhat rare warning:

Image

I have reduced the code to an MWE as best I could. I get no information where this fails in my code.
Here is my simplified code to reproduce the error:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from datetime import date, datetime, timedelta
from skyfield import VERSION
from skyfield.api import Loader, wgs84, N, S, E, W
from skyfield import almanac

d = date(2000, 1, 1)        # select DATE       year, month, day
lat = 67.0                  # select latitude
obj = 6                     # select PLANET     0, 1, 2, 3, 4, 5, 6

print("\nSkyfield version = ",VERSION)
load = Loader("./")
ts = load.timescale()
eph = load('de421.bsp')
mercury = eph['mercury']
venus   = eph['venus']
earth   = eph['earth']
mars    = eph['mars']
jupiter = eph['jupiter barycenter']
saturn  = eph['saturn barycenter']
uranus  = eph['uranus barycenter']
neptune = eph['neptune barycenter']

pl_name = ['Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
pl_name2 = ['Mercury', 'Venus  ', 'Mars   ', 'Jupiter', 'Saturn ', 'Uranus ', 'Neptune']
pl_eph  = [mercury, venus, mars, jupiter, saturn, uranus, neptune]
planet = pl_eph[obj]

dt = datetime(d.year, d.month, d.day, 0, 0, 0)
dt_start = dt
daysinyear = (date(d.year+1, 1, 1) - date(d.year, 1, 1)).days
latns = 'N' if lat >= 0.0 else 'S'
print("year {}:  {} at latitude {:.1f}°{}".format(d.year,pl_name2[obj],abs(lat),latns))

#---------------------------------------------------------------------------
topos = wgs84.latlon(lat, 0.0 * E, elevation_m=0.0)
observer = earth + topos

print("... raw data from almanac.find_settings and almanac.find_risings:")
for i in range(daysinyear):
#for i in range(5):

    t0 = ts.ut1(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
    t1 = ts.ut1(dt.year, dt.month, dt.day+1, dt.hour, dt.minute, dt.second)

    planetset,  iS = almanac.find_settings(observer, planet, t0, t1)
    planetrise, iR = almanac.find_risings(observer, planet, t0, t1)
    for ndx, dt0 in enumerate(planetset):
        print("  set ",dt0.utc_iso(' ') ,"   ",iS[ndx])
    for ndx, dt0 in enumerate(planetrise):
        print("  rise",dt0.utc_iso(' '),"   ",iR[ndx])

    dt += timedelta(days = 1)

dt = dt_start
print("... ditto in chronological order and filtered for True events only:")
for i in range(daysinyear):
#for i in range(5):

    t0 = ts.ut1(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
    t1 = ts.ut1(dt.year, dt.month, dt.day+1, dt.hour, dt.minute, dt.second)

    planetset,  iS = almanac.find_settings(observer, planet, t0, t1)
    planetrise, iR = almanac.find_risings(observer, planet, t0, t1)

    # assemble TRUE events in chronological order
    nR = len(planetrise); nS = len(planetset)
    ndxR = ndxS = 0
    riseset_time = []; isrise = []
    while ndxR < nR or ndxS < nS:
        if ndxR < nR and ndxS < nS:
            if iR[ndxR] and iS[ndxS]:
                if planetrise[ndxR] < planetset[ndxS]:
                    riseset_time.append(planetrise[ndxR]); isrise.append(True)
                    riseset_time.append(planetset[ndxS]); isrise.append(False)
                else:
                    riseset_time.append(planetset[ndxS]); isrise.append(False)
                    riseset_time.append(planetrise[ndxR]); isrise.append(True)
            elif iR[ndxR]:
                riseset_time.append(planetrise[ndxR]); isrise.append(True)
            elif iS[ndxS]:
                riseset_time.append(planetset[ndxS]); isrise.append(False)
            ndxR += 1; ndxS += 1
        elif ndxR < nR:
            if iR[ndxR]:
                riseset_time.append(planetrise[ndxR]); isrise.append(True)
            ndxR += 1
        elif ndxS < nS:
            if iS[ndxS]:
                riseset_time.append(planetset[ndxS]); isrise.append(False)
            ndxS += 1

    dt += timedelta(days = 1)

I am using Python 3.13.9. My code works perfectly, i.e. as expected, in 99.999% of cases and I have since enhanced the code to over double the length above. As far as I can tell, there are TWO ISSUES here:

  • the RuntimeWarning from almanc.py in line 339 (Skyfield 1.54)
  • and most likely as a consequence of the RuntimeWarning: almanac.find_settings() or almanac.find_risings() can output NaN instead of an event TIME in the first output parameter, which should never be the case - this causes my code to crash

I would REALLY APPRECIATE it if this abrupt warning could be eliminated.
As always.... sincere thanks for all assistance!

UPDATES:
It occurs on 2031-04-18 and you can set for i in range(1): in the last for loop.
It then fails also with a second RuntimeWarning, this time in timelib.py at line 673:

Image

I have now switched to incrementing the latitude in tenths of a degree as an integer, e.g. from 670 to 720, increment 1, and I divide by 10 to get the latitude (degrees) as a float. This way I avoid accumulating the error using a float increment of 0.1 repetitively.

Next failure point I noticed (using a later program version) is with Neptune on 2000-03-18 at 68.7°N:

Image

By comparison, here is correct data from Skyfield 1.49:

Image

Nothing unusual happens on 2000-03-18 ,,,,,,,,
Take a look at my chart for Neptune in 2000 at 68.7°N with Skyfield 1.49:

Image

Initially I thought that something broke in Skyfield 1.54
Here are some random test cases using Skyfield 1.54 where I detected this issue occurs:

2000-06-08 Neptune 67.0N
2000-03-18 Neptune 68.7N
2000-10-06 Neptune 69.3N
2000-05-13 Uranus 71.6N
2001-10-14 Neptune 67.0N
2001-06-23 Uranus 68.1N
2001-09-20 Neptune 70.0N
2001-07-05 Uranus 70.2N
2020-05-23 Uranus 68.4N
2021-06-03 Saturn 67.3N
2021-06-30 Uranus 68.7N
2023-12-31 Uranus 70.9N
2025-02-09 Uranus 69.8N
2026-02-08 Uranus 50.7N
2027-07-16 Uranus 60.2N
2028-04-04 Uranus 56.9N
2028-07-23 Saturn 69.3N
2029-11-04 Mars 52.0N
2029-04-23 Uranus 54.0N
2029-01-26 Jupiter 62.2N
2029-12-23 Uranus 65.9N

Initially I suspected this issue is caused by Skyfield 1.54 alone, though I saw no reason for it.

So I decided to test using Skyfield 1.53.
I tested the years 2027, 2028 and 2029 for latitudes between 50.0°N and 72.0°N in 0.1 degree steps [using integer steps because it is impossible to represent 0.1 (decimal) precisely in binary with a finite number of digits]

I found these cases where Skyfield 1.53 fails with the same symptoms:

2027-08-11 Neptune 50.0N
2028-01-20 Jupiter 55.7N
2029-07-14 Saturn 56.8N

So I see that this issue is not limited to Skyfield 1.54 (though 1.54 is more error-prone than 1.53).
I now want to look at Skyfield 1.49, which I thought was 100% free of this problem.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions