sffjunkie / astral

Python calculations for the position of the sun and moon.
Apache License 2.0
242 stars 47 forks source link

Sunrise/sunset sometimes throws "sun always above horizon" during polar (24h) night #74

Open acrylic-origami opened 3 years ago

acrylic-origami commented 3 years ago

On the current master (96496f0), during a polar (24-hour) night, calling sunrise()/sunset() will occasionally throw the exact opposite error:

ValueError: Sun is always above the horizon on this day, at this location.

This happens at latitudes just above to the critical latitude for polar night. As an MVE: the coordinate (72, 0) in the UTC timezone does this in the middle of winter on Jan 28, 1970:

o = LocationInfo(timezone='UTC', latitude=72, longitude=0).observer
sunrise(o, date=datetime.date(1970, 1, 28))

The error is 1º wide: that is, coordinates from 71.4º to 72.3º will fail.

I see sunrise/sunset evaluates which error to throw by looking at the angle to zenith at noon to see if it's above the horizon. It seems that what causes it is a difference between what triggers the trig domain error in hour_angle and the zenith calculation. The full stack trace is:

Traceback (most recent call last):
  File "sun.py", line 771, in sunrise
    return time_of_transit(
  File "sun.py", line 343, in time_of_transit
    hourangle = hour_angle(
  File "sun.py", line 243, in hour_angle
    HA = acos(h)
ValueError: math domain error

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    sunrise(o, date=datetime.date(1970, 1, 28))
  File "sun.py", line 781, in sunrise
    raise ValueError(msg) from exc
ValueError: Sun is always above the horizon on this day, at this location.

I was relying on this error to identify if it is polar night or polar day, especially near the poles at solstices. If there is a more robust way to calculate that directly, then I am also all ears.