calculating apogee and perigee for moon and sun

The perigee does not necessarily happen when we have a full moon, using swevents we can easily determine the moon phases. Now can we use python to determine when the Moon and the Sun are the closest and furthest from the Earth for a year lets say?

• Swiss Ephemeris is primarily aimed at the astrological community, so questions of "distance" are not very important (astrologers are mostly interested in the relative positions in the sky, and not the 3d positions in space.) You should use an astronomy package, like astropy or skyfield instead of one designed for astrology. There are several questions/examples on [stackoverflow.com] Commented Dec 29, 2023 at 16:06
• How do you get a short link to [stackoverflow.com] in the way that you can do Physics? Commented Dec 29, 2023 at 16:08
• @James Just use [SO]. Thus: Stack Overflow Commented Dec 29, 2023 at 18:07
• James, I am genuinely curious based on this printout. Are those calculations correct in terms of when the moon reaches full moon?  ./swevents -p1 -dolphase -b1.1.2024| grep Full 2024 Jan 25 17:54:02 Full 3 5 LE 14'44" 2024 Feb 24 12:30:28 Full 3 5 VI 23' 4"  Let's forget the astrology nonsense. Commented Dec 29, 2023 at 20:23
• They should be correct, the swevents program isn't making stuff up. But it's not designed to do astronomy. You should probably shift to astropy or similar. Astropy certainly can do distance calculations. Commented Dec 29, 2023 at 20:43

The skyfield library has find_maxima and find_minima functions that take as an argument a function that accepts a timelib.Time object and returns an numpy.ndarray object that gives a value for the requested time, and has a step_days parameter for the initial step size.

So, let's make a function that returns functions that produce the distance from earth for the specified body, and use those in find_maxima and find_minima. Our search window will be the calendar year 2024 in the UTC time zone.

from typing import Callable

import numpy as np
import pytz
import skyfield.searchlib
from skyfield import api, timelib
from skyfield.jpllib import ChebyshevPosition, SpiceKernel
from skyfield.vectorlib import VectorSum

def kilometers_from_earth(ephemeris: SpiceKernel,
target: str | VectorSum | ChebyshevPosition,
step_days: float = 25) -> Callable[[timelib.Time], np.ndarray[float]]:
"""
Creates functions that can be used to find maximum or minimum distances from Earth
:param ephemeris: Ephemeris
:param target: Target distance
:param step_days: Step days for search function. Default 25
:return: Function compatible with find_minima and find_maxima skyfield functions.
"""
earth = ephemeris['earth']
if isinstance(target, str):
target = ephemeris[target]

def function(t: timelib.Time) -> np.ndarray[float]:
"""
Distance from earth function
:param t: Time object representing time
:return: ndarray of corresponding distances in kilometers
"""
distance = earth.at(t).observe(target).distance().km
return distance

function.step_days = step_days

return function

def main():
utc = pytz.timezone("UTC")
start, stop = ts.utc(2024), ts.utc(2025)
sun_from_earth = kilometers_from_earth(ephemeris, 'sun')

pe_times, pe_distances = skyfield.searchlib.find_minima(start, stop, sun_from_earth)
ap_times, ap_distances = skyfield.searchlib.find_maxima(start, stop, sun_from_earth)

print("\nResults for Sun-From-Earth")
print(f"{'Perihelion Time':^25}\t{'Distance':^13}\t\t{'Aphelion Time':^25}\t{'Distance':^13}")
print('\n'.join(f"{pt:%F %T %z}\t{pd:1.4E} km\t\t{at:%F %T %z}\t{ad:1.4E} km"
for pt, pd, at, ad in
zip(pe_times.astimezone(utc), pe_distances, ap_times.astimezone(utc), ap_distances)))

moon_from_earth = kilometers_from_earth(ephemeris, 'moon', step_days=7)

pe_times, pe_distances = skyfield.searchlib.find_minima(start, stop, moon_from_earth)
ap_times, ap_distances = skyfield.searchlib.find_maxima(start, stop, moon_from_earth)

print("\nResults for Moon-From_earth")
print(f"{'Perigee Time':^25}\t{'Distance':^9}\t\t{'Apogee Time':^25}\t{'Distance':^9}")
print('\n'.join(f"{pt:%F %T %z}\t{pd:6.0f} km\t\t{at:%F %T %z}\t{ad:6.0f} km"
for pt, pd, at, ad in
zip(pe_times.astimezone(utc), pe_distances, ap_times.astimezone(utc), ap_distances)))

if __name__ == '__main__':
main()


Which produces the following results for the year 2024, in the maybe-more-precise-than-useful formats below:

Results for Sun-From-Earth
Perihelion Time          Distance                Aphelion Time           Distance
2024-01-03 00:38:40 +0000   1.4710E+08 km       2024-07-05 05:06:07 +0000   1.5210E+08 km

Results for Moon-From_earth
Perigee Time          Distance               Apogee Time          Distance
2024-01-13 10:28:04 +0000   362283 km       2024-01-01 15:24:04 +0000   404873 km
2024-02-10 18:46:22 +0000   358096 km       2024-01-29 08:04:56 +0000   405751 km
2024-03-10 06:57:57 +0000   356895 km       2024-02-25 14:42:46 +0000   406303 km
2024-04-07 17:44:38 +0000   358841 km       2024-03-23 15:30:16 +0000   406306 km
2024-05-05 21:56:41 +0000   363146 km       2024-04-20 02:02:01 +0000   405650 km
2024-06-02 07:07:56 +0000   368072 km       2024-05-17 18:54:59 +0000   404676 km
2024-06-27 11:36:29 +0000   369252 km       2024-06-14 13:34:31 +0000   404116 km
2024-07-24 05:48:41 +0000   364895 km       2024-07-12 08:13:38 +0000   404400 km
2024-08-21 05:08:49 +0000   360184 km       2024-08-09 01:38:02 +0000   405328 km
2024-09-18 13:28:47 +0000   357282 km       2024-09-05 15:05:56 +0000   406229 km
2024-10-17 00:57:22 +0000   357179 km       2024-10-02 19:55:51 +0000   406515 km
2024-11-14 11:22:38 +0000   360122 km       2024-10-29 23:02:20 +0000   406142 km
2024-12-12 13:28:19 +0000   365384 km       2024-11-26 12:02:03 +0000   405281 km


• Whoops, I'm missing one of the apogee times for the moon, because I naiively assumed that there'd be the same number of apoapses and periapses in the chosen time period, and so zip ruthlessly omitted the December 2024 lunar apogee. Commented Dec 30, 2023 at 23:03
• There's also a chance to grab the endpoints of the time window when they're not acutally apogees or perigees, so care should be taken to avoid that as well. Commented Dec 30, 2023 at 23:14
• I saw that, I wanted it for the Sun more which was helpful for me, so thank you! Commented Jan 1 at 4:01