Skip to content

Commit

Permalink
Finish up new rising/setting docs
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-rhodes committed Jan 13, 2024
1 parent 208b12b commit 3879956
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 40 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ Changelog
.. TODO After finding how to test TIRS reference frame, add it to changelog.
And double-check the constellation boundaries array.
v1.47 — Unreleased
------------------
v1.47 — 2023 January 13
-----------------------

* Added faster and more accurate
* Added faster and more accurate almanac routines
:func:`~skyfield.almanac.find_risings()` and
:func:`~skyfield.almanac.find_settings()` almanac routines.
:func:`~skyfield.almanac.find_settings()` and
:func:`~skyfield.almanac.find_transits()`.

* Constellation abbreviations are now consistent between the
:func:`~skyfield.api.load_constellation_map()` table and the
Expand Down
43 changes: 43 additions & 0 deletions skyfield/almanac.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,13 +413,56 @@ def _find(observer, target, start_time, end_time, horizon_degrees, f):
return t, is_above_horizon

def find_risings(observer, target, start_time, end_time, horizon_degrees=None):
"""Return the times at which a target rises above the eastern horizon.
Given an observer on the Earth’s surface, a target like the Sun or
Moon or a planet, and start and stop :class:`~skyfield.timelib.Time`
objects, this returns two arrays that have the same length. The
first is a :class:`~skyfield.timelib.Time` listing the moments at
which the target rises. The second array has ``True`` for each time
the target really crosses the horizon, and ``False`` when the target
merely transits without actually touching the horizon.
See :ref:`horizon_degrees` for how to use the ``horizon_degrees``
argument.
.. versionadded:: 1.47
"""
return _find(observer, target, start_time, end_time, horizon_degrees,
_rising_hour_angle)

def find_settings(observer, target, start_time, end_time, horizon_degrees=None):
"""Return the times at which a target sets below the western horizon.
Given an observer on the Earth’s surface, a target like the Sun or
Moon or a planet, and start and stop :class:`~skyfield.timelib.Time`
objects, this returns two arrays that have the same length. The
first is a :class:`~skyfield.timelib.Time` listing the moments at
which the target sets. The second array has ``True`` for each time
the target really crosses the horizon, and ``False`` when the target
merely transits without actually touching the horizon.
See :ref:`horizon_degrees` for how to use the ``horizon_degrees``
argument.
.. versionadded:: 1.47
"""
return _find(observer, target, start_time, end_time, horizon_degrees,
_setting_hour_angle)

def find_transits(observer, target, start_time, end_time):
"""Return the times at which a target transits across the meridian.
Given an observer on the Earth’s surface, a target like the Sun or
Moon or a planet, and start and stop :class:`~skyfield.timelib.Time`
objects, this returns a :class:`~skyfield.timelib.Time` array
listing the moments at which the target transits across the
meridian.
.. versionadded:: 1.47
"""
t, _ = _find(observer, target, start_time, end_time, 0.0, _transit_ha)
return t
87 changes: 51 additions & 36 deletions skyfield/documentation/almanac.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ is exactly 34 arcminutes below the horizon.
Read the previous section :ref:`polar-day-and-night`
to learn about the Boolean array ``y``.

.. _horizon_degrees:

Computing your own refraction angle
-----------------------------------

Expand Down Expand Up @@ -387,7 +389,8 @@ If you are interested in finding the times
when a fixed point in the sky rises and sets,
simply create a star object with the coordinates
of the position you are interested in
(see :doc:`stars`).
(see :doc:`stars`)
and then call the routines described above.
Here, for example, is the rising time for the Galactic Center:

.. testcode::
Expand All @@ -397,9 +400,7 @@ Here, for example, is the rising time for the Galactic Center:
galactic_center = Star(ra_hours=(17, 45, 40.04),
dec_degrees=(-29, 0, 28.1))

f = almanac.risings_and_settings(eph, galactic_center, bluffton)
t, y = almanac.find_discrete(t0, t1, f)

t, y = almanac.find_risings(observer, galactic_center, t0, t1)
print('The Galactic Center rises at', t[0].utc_iso(' '))

.. testoutput::
Expand Down Expand Up @@ -577,8 +578,28 @@ crosses your meridian:

['2020-11-06 03:32', '2020-11-07 03:28']

Skyfield also has an older mechanism for detecting transits
that isn’t as fast but that also returns the moments of anti-transit,
Observers often think of transit as the moment
when an object is highest in the sky,
but that’s only roughly true.
At very high precision,
if the body has any north or south velocity
then its moment of highest altitude will be slightly earlier or later.

Bodies near the poles are exceptions to the general rule
that a body is visible at transit but below the horizon at antitransit.
For a body that’s circumpolar from your location,
transit and antitransit are both moments of visibility,
when it stands above and below the pole.
And objects close to the opposite pole will always be below the horizon,
even as they invisibly transit your line of longitude
down below your horizon.

Legacy transit routine
======================

Skyfield has an older mechanism for detecting transits
that isn’t as fast as the function described in the previous section,
but it also returns the moments of anti-transit,
when a body crosses the line of right ascension that crosses your local nadir:

.. testcode::
Expand All @@ -601,37 +622,20 @@ when a body crosses the line of right ascension that crosses your local nadir:
Some astronomers call these moments
“upper culmination” and “lower culmination” instead.

Observers often think of transit as the moment
when an object is highest in the sky,
but that’s only roughly true.
At very high precision,
if the body has any north or south velocity
then its moment of highest altitude will be slightly earlier or later.

Bodies near the poles are exceptions to the general rule
that a body is visible at transit but below the horizon at antitransit.
For a body that’s circumpolar from your location,
transit and antitransit are both moments of visibility,
when it stands above and below the pole.
And objects close to the opposite pole will always be below the horizon,
even as they invisibly transit your line of longitude
down below your horizon.

TODO
====
Legacy rising and setting routines
==================================

In case you are maintaining older code,
versions of Skyfield before 1.47 could only compute sunrises and sunsets
with an almanac routine
that was both slower than the routine described above,
and that also tended to miss sunrises and sunsets in the Arctic and Antarctic.
Here’s how the older routine is called:
versions of Skyfield before 1.47
could only compute sunrises and sunsets
with a routine that was much slower than the functions described above.
It also tended to miss sunrises and sunsets in the Arctic and Antarctic.
Here’s how it was called:

.. testcode::

t0 = ts.utc(2018, 9, 12, 4)
t1 = ts.utc(2018, 9, 13, 4)
t, y = almanac.find_discrete(t0, t1, almanac.sunrise_sunset(eph, bluffton))
f = almanac.sunrise_sunset(eph, bluffton)
t, y = almanac.find_discrete(t0, t1, f)

print(t.utc_iso())
print(y)
Expand All @@ -644,10 +648,21 @@ Here’s how the older routine is called:
The result ``t`` will be an array of times, and ``y`` will be ``1`` if
the sun rises at the corresponding time and ``0`` if it sets.

If you need to provide your own custom value for refraction, adjust the
estimate of the Sun’s radius, or account for a vantage point above the
Earth’s surface, see :ref:`risings-and-settings` to learn about the more
versatile :func:`~skyfield.almanac.risings_and_settings()` routine.
Another old routine :func:`~skyfield.almanac.risings_and_settings()`
worked the same way, but for general targets like planets.

.. testcode::

f = almanac.risings_and_settings(eph, eph['Mars'], bluffton)
t, y = almanac.find_discrete(t0, t1, f)

print(t.utc_iso())
print(y)

.. testoutput::

['2020-02-01T09:29:16Z', '2020-02-01T18:42:57Z']
[1 0]

Twilight
========
Expand Down
6 changes: 6 additions & 0 deletions skyfield/documentation/api-almanac.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
See :doc:`almanac` for a guide to using these routines to search for the
times of sunrise, sunset, and the phases of the moon.

.. autofunction:: find_risings

.. autofunction:: find_settings

.. autofunction:: find_transits

.. autofunction:: find_discrete

.. autofunction:: seasons
Expand Down
3 changes: 3 additions & 0 deletions skyfield/documentation/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ Routines to search for events like sunrise, sunset, and Moon phase.

.. autosummary::

find_risings
find_settings
find_transits
seasons
moon_phase
moon_phases
Expand Down

0 comments on commit 3879956

Please sign in to comment.