Open-source libraries
- Stellarium is the most complete open Besselian implementation.
SolarEclipseComputer.cppcomputes elements from its own Sun and Moon positions with its constantskat 0.2725076 andsat 0.272281, solar radius 696,000 km, and cites Explanatory Supplement equations (11.56, 11.60, 11.78, 11.81) for limits, outlines and rise-set curves. It exports KML and PNG maps. No limb profile, no terrain. - Swiss Ephemeris computes eclipses geometrically, not from Besselian elements.
eclipse_where()follows Montenbruck with a lunar diameter of 3476.3 km, a solar diameter of 1,392,000 km and Earth radius 6378.14 km, claims better than 100 m on the central line, and states that the umbral and penumbral limits are not implemented. Local contacts C2 and C3 use an empirical factorrmoon *= 0.99916. - Astronomy Engine, MIT, in five languages, finds eclipses by intersecting the shadow axis with a dilated spherical Earth (Montenbruck and Pfleger p. 184) using km, mean lunar radius 1737.4 km and flattening 0.996647180302104. It returns obscuration and contact times per observer but no path limits.
- Skyfield has lunar eclipses only. Two open issues and one open pull request (2025) propose a geometric solar routine. PyEphem, libnova, NOVAS and SOFA provide no eclipse functions. astropy has none. sunpy provides
eclipse_amount()with selectable between 0.2725076 and 0.272281. - SPICE provides a smooth-body occultation search.
gfoclt_caccepts two ellipsoids for finite-disc events. DSK support requires a POINT partner and ANY event type, so it cannot directly compute finite-Sun contacts against a lunar DSK 1. - Meeus chapter 54 ports (astronomia, soniakeys/meeus, Starainrt/astro, astronomy-bundle PHP) give global circumstances and, in the Go and PHP cases, local circumstances from VSOP87 and ELP2000.
The question. Which general-purpose astronomy libraries compute anything toward solar eclipses, by what method, with what constants, and where does each stop?
Stellarium
Where the code lives. src/core/SolarEclipseComputer.cpp, 2,183 lines at commit 69888f4 of 2026-09-14, and its header, with the user interface in src/gui/AstroCalcDialog.cpp 2 3 4. Release v1.0, in 2022, "Added capability to create KML map of solar eclipses in AstroCalc tool" and "Added contact times of global solar eclipse in AstroCalc tool" 5. Release v0.22.2 already listed "Improvements in AstroCalc: graphs, eclipses, transits" 6. Release v24.2 moved "solar eclipse computations out from Planet.cpp" and from AstroCalcDialog into the core and "Added export of an equirectangular raster eclipse map" 7.
Besselian elements. calcSolarEclipseBessel() cites "Explanatory Supplement to the Astronomical Ephemeris and the American Ephemeris and Nautical Almanac (1961)". It takes geocentric equatorial Sun and Moon positions with topocentric mode disabled, the Moon's distance in Earth radii, and the Greenwich apparent sidereal time 2. With where is the Sun's distance in Earth radii ( from 149597870.8/6378.1366), the shadow-axis direction is
and the elements are , , , 2. The cone half-angles use SunEarth = 109.12278 ("696000/6378.1366", IERS Conventions 2003, with the comment that NASA's solar radius of 696,000 km comes from the IAU 1976 value of 959.63 arcsec at 1 au):
with const double k = 0.2725076; const double s = 0.272281; and the comment "Ratio of Moon/Earth's radius 0.2725076 is recommended by IAU for both k & s. s = 0.272281 is used by Fred Espenak/NASA for total eclipse to eliminate extreme cases ... we will use two values (same with NASA), because durations seem to agree with NASA. Source: http://eclipsewise.com/solar/SEhelp/SEradius.html" 2. Element rates are finite differences over ±5 minutes 2. Stellarium uses a small-separation angular approximation to the same shadow-axis geometry. The companion ephemeris-to-elements generator gives the rigorous vector equations. Preserve the approximation when reproducing Stellarium, or use the rigorous form and verify the resulting difference 2.
Global products. calcSolarEclipseData() uses the ellipsoidal fundamental-plane reduction (, , ) with the flattening taken from Stellarium's Earth model, and returns the central-line point, diameter ratio, Sun altitude, path width, duration and magnitude 2. getShadowLimitQs() solves the limit condition from identities (11.56) and (11.60) of the 2013 Explanatory Supplement, and zetaFromQ() implements equation (11.81) "restoring the missing dots over a,b,c in the book (cf. eq. (11.78))" 2. generateEclipseMap() produces greatest eclipse, P1 and P4, C1 and C2 (central start and end), penumbra limits, umbra outlines and rise-set curves, and generateKML() and generatePNGMap() write them out 3 2. The AstroCalc dialog exports tables of eclipses, of eclipses visible at the current location, and of contact circumstances, each with the warning that paths "during thousands of years in the past and future are not reliable due to uncertainty in ΔT" 4.
ΔT and ephemeris. The default ΔT algorithm is EspenakMeeusModified, described as the Espenak and Meeus solution based on Morrison and Stephenson (2004) with "Values for 2015-2033 ... interpolated from observations and predictions by IERS Rapid Service/Prediction Center" 8. Stellarium's Sun and Moon positions come from its own ephemeris settings (VSOP87 by default, optional DE430 and DE431 files), so the elements vary with the user's configuration. No limb profile or terrain is used in the eclipse code (no such term appears in SolarEclipseComputer.cpp) 2. Licence GPL-2.0 2.
Swiss Ephemeris
The geometry these routines implement is set out in ephemeris to elements, and the topocentric contact routines in topocentric method. This section keeps the constants and the code reading.
Functions. swe_sol_eclipse_when_glob(), swe_sol_eclipse_when_loc(), swe_sol_eclipse_where() and swe_sol_eclipse_how() return eclipse type flags (SE_ECL_TOTAL, SE_ECL_ANNULAR, SE_ECL_PARTIAL, SE_ECL_ANNULAR_TOTAL, SE_ECL_CENTRAL, SE_ECL_NONCENTRAL), times of maximum and contacts, magnitude, obscuration, the diameter ratio, core-shadow diameter in km, Sun azimuth and altitude, and Saros numbers 9. The documentation states: "The northern and southern limits of the umbra and penumbra are not implemented yet" 9.
Constants. swecl.c defines DSUN (1392000000.0 / AUNIT), DMOON (3476300.0 / AUNIT), DEARTH (6378140.0 * 2 / AUNIT), with an alternative DSUN 1391978489.9 "consistent with 959.63 arcsec at AU distance" disabled by #if 0 10. sweph.h defines SUN_RADIUS (959.63 / 3600 * DEGTORAD) "Meeus germ. p 391", EARTH_RADIUS 6378136.6 "AA 2006 K6", EARTH_OBLATENESS (1.0/ 298.25642), and observer altitude limits of -500 m to 25,000 m 11. Version at reading: 2.10.03 11.
Algorithm. The comment above eclipse_where() states: "Algorithms for the central line is taken from Montenbruck, pp. 179ff., with the exception, that we consider refraction for the maxima of partial and noncentral eclipses. Geographical positions are referred to sea level / the mean ellipsoid." It lists error sources: an assumed JPL ephemeris uncertainty of 0.01 arcseconds worth about 40 m, refraction a few metres, geoid a few metres, polar motion a few metres, "For geographical locations that are interesting for observation, the error is always < 100 m. However, if the sun is close to the horizon, all of these errors can grow up to a km or more" 10. The code computes ΔT with swe_deltat_ex(), takes Moon and Sun Cartesian equatorial positions, and sets
Here denotes Swiss Ephemeris's s0, the Moon's distance from the fundamental plane in the formula's length unit. It is unrelated to the adopted solar angular semidiameter . The program's r0, equal to , is the shadow-axis distance from the geocentre. It classifies central when , noncentral when , partial when 10. eclipse_how() is topocentric: it sets the observer with swe_set_topo(), computes apparent radii and , the centre separation , and classifies annular if , total if , partial if 10. eclipse_when_loc() finds the local maximum with find_maximum(), then contacts by find_zero() on for C2 and C3 and for C1 and C4, and applies rmoon *= 0.99916; /* gives better accuracy for 2nd/3rd contacts */ before the interior contacts, then converts TT to UT by subtracting ΔT 10. That factor is an empirical stand-in for a smaller umbral (0.99916 × 3476.3/2 = 1736.7 km). There is no limb profile and no terrain.
Licence and data. Dual licence, AGPL or the Swiss Ephemeris Professional License at CHF 750 for the first licence 12. Versions since 2.00 are based on JPL DE431 for -13000 to +16800, and version 2.06 introduced a ΔT algorithm based on Stephenson, Morrison and Hohenkerk 2016 12.
Astronomy Engine (Don Cross)
Scope. "Predicts lunar and solar eclipses", accuracy "always within 1 arcminute of results from NOVAS", based on "truncated VSOP87 series", MIT licence, implementations in C, C#, JavaScript, Python and Kotlin, 1,016 stars, last push 2025-01-27 13 14.
Constants. SUN_RADIUS_KM 695700.0, EARTH_EQUATORIAL_RADIUS_KM 6378.1366, EARTH_FLATTENING 0.996647180302104, EARTH_MEAN_RADIUS_KM 6371.0, MOON_MEAN_RADIUS_KM 1737.4, EARTH_ATMOSPHERE_KM 88.0 (lunar eclipses only) 15 16.
Method. CalcShadow() projects the target onto the Sun-body axis, with the projection parameter, and defines the umbra and penumbra radii at the target's distance as
with the perpendicular distance of the target from the axis in km 16. GeoidIntersect() rotates the axis into equator-of-date coordinates, dilates by 1/EARTH_FLATTENING "so that the Earth becomes a perfect sphere", solves the quadratic for the near intersection, and converts back to geodetic latitude and longitude with the sidereal time, citing "p 184 in Montenbruck & Pfleger's 'Astronomy on the Personal Computer', second edition" 16. Eclipse kind follows EclipseKindFromUmbra(k) ((k) > 0.014 ? ECLIPSE_TOTAL : ECLIPSE_ANNULAR) 16. The global result carries distance, "The distance between the Sun/Moon shadow axis and the center of the Earth, in kilometers", and the peak latitude and longitude 15. LocalEclipse() finds partial begin and end within ±0.2 day and total begin and end within ±0.01 day of the geocentric peak by root-finding on observer-specific distance functions, and computes obscuration from disc overlap with Obscuration() 16. The local result has partial_begin, total_begin, peak, total_end, partial_end, each with Sun altitude, and obscuration 15. There are no Besselian elements, no path limits, no limb profile and no terrain. Several repositories in the next note build maps on it.
Skyfield
The almanac provides eclipselib.lunar_eclipses() "using the techniques described in the Explanatory Supplement to the Astronomical Almanac", which finds all 3,642 lunar eclipses of AD 1000 to 2500 in the NASA lunar Canon with 0.2 per cent type disagreement and times "a few seconds earlier" 17. eclipselib.py uses solar radius 696,340 km, lunar radius 1,737.1 km and Danjon's enlargement, and contains no solar routine 18. Issue #445, in 2020, requested eclipses and offered table lookups from the NASA catalogues 19. Pull request #1076, in 2025, adds a solar routine that "uses similar method as lunar eclipse calculation, but instead of looking for maximum of angle between earth-sun and earth-moon, it looks for minimum", classifies by penumbra, umbra or antumbra, and reports agreement with NASA over 400 years except for zero-duration and marginal partial eclipses 20. Issue #1078 tracks it, with no maintainer reply visible at the time of writing (2026 September) 21. Skyfield with JPL kernels is nonetheless the ephemeris layer used by several eclipse repositories below.
PyEphem, libnova, NOVAS, SOFA and ERFA
PyEphem documents separation() and per-body size and radius attributes but no eclipse function 22. libnova's solar group lists coordinates, rise and set, and ln_get_solar_sdiam() only 23. NOVAS 3.1 is "an integrated package of routines for computing various commonly needed quantities in positional astronomy" with no eclipse routine described 24. SOFA provides "an accessible and authoritative set of algorithms and procedures that implement standard models used in fundamental astronomy", release 2023-10-11, with no eclipse routine mentioned 25. ERFA is the SOFA re-licensing and was not checked separately. These libraries supply time scales, Earth orientation and apparent places that an eclipse pipeline needs upstream of the Besselian stage.
astropy and sunpy
The cited Astropy issue inventory documents no dedicated solar-eclipse API 26. sunpy provides sunpy.coordinates.sun.eclipse_amount(observer, moon_radius='IAU') where 'IAU' is "the IAU mean radius (R_moon / R_earth = 0.2725076)" and 'minimum' is "the mean minimum radius (R_moon / R_earth = 0.272281)", under "the simplifying assumption that the Moon has a constant radius", with the warning that "the output can be slightly inaccurate for the start/end of partial solar eclipses ... and the start/end of total solar eclipses" and that a JPL ephemeris should be used 27. The gallery example sets de440s, builds an ITRS observer and scans ±2 hours to find the phases 28.
SPICE and Horizons
gfoclt_c supports FULL, ANNULAR and PARTIAL searches for two ellipsoids. Its DSK mode requires a POINT partner and the ANY condition. The documented Earth-centre solar-eclipse example uses ellipsoids 1. gfsep_c searches angular separation of SPHERE or POINT targets and has no implemented ELLIPSOID option 29. SPICE positions and lunar topography can supply a separate finite-disc limb-containment test. Horizons supplies observer tables, rather than this eclipse product 30.
Meeus chapter 54 ports
astronomia's eclipse.js returns type (None, Partial, Annular, AnnularTotal, Total), central flag, jdeMax, magnitude, gamma, and the umbral and penumbral radii, and computes "global eclipse circumstances ... not local circumstances or ground paths" 31. soniakeys/meeus (Go, 376 stars, last push 2019) has the same Solar(year) and Lunar(year) scope 32 14. Starainrt/astro (Go, Apache-2.0, 157 stars) goes further with built-in VSOP87 and ELP2000/82, SolarEclipseCentralPath for the central line, limits and greatest eclipse, SolarEclipsePartialFootprints, and local circumstances, reporting second-level agreement with NASA for global times 33. andrmoel/astronomy-bundle (PHP, MIT) computes C1 to C4 and maximum for an observer from VSOP87 and Meeus 34. PyMeeus's module index shows no eclipse module 35.
Sources compared
| Library | Global search | Besselian elements | Path and limits | Local contacts | Obscuration | Limb or terrain | Constants | Licence |
|---|---|---|---|---|---|---|---|---|
| Stellarium 2 | Yes | Yes, computed | Yes, KML and PNG | Yes | Yes | No | k 0.2725076, s 0.272281, 696,000 km |
GPL-2.0 |
| Swiss Ephemeris 10 | Yes | No | Central line only | Yes | Yes | No | 3476.3 km, 1,392,000 km, factor 0.99916 | AGPL or paid |
| Astronomy Engine 16 | Yes | No | Peak point only | Yes | Yes | No | 695,700 km, 1737.4 km | MIT |
| Skyfield 17 | Lunar only | No | No | No | No | No | 696,340 km, 1737.1 km | MIT |
| sunpy 27 | No | No | No | By scanning | Yes | No | 0.2725076 or 0.272281 | BSD |
| SPICE gfoclt 1 | Intervals | No | No | FULL/ANNULAR/PARTIAL for two ellipsoids | No | DSK with POINT supports ANY only | Kernel radii | US Government |
| Starainrt/astro 33 | Yes | Not stated | Yes | Yes | Yes | No | VSOP87, ELP2000/82 | Apache-2.0 |
| astronomia, soniakeys/meeus 31 32 | Yes | No | No | No | Partial magnitude | No | Meeus ch. 54 | MIT |
What a developer should do
Use Stellarium's SolarEclipseComputer.cpp as the algorithmic reference for global products because the surveyed file cites the 2013 Explanatory Supplement equations for limits and outlines 2. Use Swiss Ephemeris or Astronomy Engine as independent geometric cross-checks of the central line and of local contacts, remembering that both assume a mean lunar radius and that Swiss Ephemeris applies the 0.99916 factor 10 16. Use Skyfield with DE440 or DE421 kernels as the ephemeris layer and sunpy's eclipse_amount for an obscuration cross-check with the two conventions 27. Use gfoclt_c with two ellipsoids as a smooth-body baseline. A DSK Moon and finite solar disc require a separate limb-containment predicate and transition search 1.
What this changes
Nothing for the stage structure. It supplies three independent implementations for cross-validation of the Besselian stage and identifies the constants each one bakes in.
Open questions
- Obtain Stellarium's git history for
SolarEclipseComputer.cppandPlanet.cppto date when the Besselian code first appeared and who wrote it. The sparse clone read here was at depth 1 2. - Obtain the origin of the
0.99916factor inswecl.cfrom Astrodienst's change history 10. - Obtain the test data Astronomy Engine uses for eclipse regression tests to see whether it compares against Espenak's tables 13.
- Obtain the final state of Skyfield pull request #1076 20.
References
- 1primary NAIF CSPICE gfoclt_c documentation Official documentation read 2026-09-30. Detailed Input accepts ELLIPSOID+ELLIPSOID, ELLIPSOID+POINT, DSK+POINT. POINT requires ANY; exceptions 9 and 14 reject the proposed DSK+finite-Sun FULL search. Cached HTML SHA256 7aef5446d1b4a396bbed8eaba1201da94a2aa118fcaa757a063b7080abf33d3a.
- 2company Stellarium src/core/SolarEclipseComputer.cpp Source read at pinned commit 69888f4f47af2aa4d1c9d14ec3853e874e253c73. SHA256 6ea4ddfac3c2fc921adcb75c06fd6c0062d6e7716ce566c15976c16b2020cbd5. Lines 584-587 use a small-separation angular axis approximation; global limits and observer transformations inspected. Verified 2026-09-30.
- 3company Stellarium src/core/SolarEclipseComputer.hpp Read from the same clone. Documents the EclipseBesselElements and EclipseMapData structures.
- 4company Stellarium src/gui/AstroCalcDialog.cpp Read from the same clone. Eclipse tables, local circumstances export, ΔT warning text.
- 5company Stellarium release v1.0 notes Read live. KML map of solar eclipses and global contact times added to AstroCalc.
- 6company Stellarium release v0.22.2 notes Read live. Mentions improvements to AstroCalc eclipses and transits.
- 7company Stellarium release v24.2 notes Read live. Solar eclipse computations moved out of Planet.cpp and AstroCalcDialog into core; raster map export added.
- 8company Stellarium src/core/StelCore.cpp (ΔT algorithms) Read from the same clone. Default ΔT is EspenakMeeusModified; describes the Espenak and Meeus polynomial and its use in the Canons.
- 9company Swiss Ephemeris Programmer's Documentation Read live. Return flags and output arrays of the swe_sol_eclipse_* functions; note that the umbral and penumbral limits are not implemented.
- 10company Swiss Ephemeris swecl.c (eclipse routines) Read from a depth-1 clone at commit 9083a12 (2026-09-14), SE_VERSION 2.10.03. Functions eclipse_where, eclipse_how, eclipse_when_loc and their constants and comments.
- 11company Swiss Ephemeris sweph.h (constants) Read from the same clone. SUN_RADIUS 959.63 arcsec, EARTH_RADIUS 6378136.6 m, EARTH_OBLATENESS 1/298.25642, eclipse altitude limits.
- 12company Swiss Ephemeris General Documentation Read live. Licensing (AGPL or professional licence), DE431 basis and time range, ΔT model since 2.06 based on Stephenson, Morrison and Hohenkerk 2016.
- 13company Astronomy Engine (cosinekitty/astronomy) README Read live. MIT, C, C#, JS, Python, Kotlin; 1 arcminute accuracy claim against NOVAS; predicts lunar and solar eclipses.
- 14unsourced GitHub repository search API queries run for this survey Queries run 2026-09-15: besselian elements; solar eclipse calculator; solar eclipse path; eclipse circumstances; solar eclipse besselian; eclipse limb profile; baily beads; eclipse explorer; solar eclipse by language (Rust, Go, Julia, Java, C++); pyeclipse; eclipsecalc; eclipse predictor; solar eclipse Python besselian OR circumstances OR contact. Metadata (stars, language, licence, last push) taken from the repos endpoint.
- 15company Astronomy Engine source/c/astronomy.h Raw header downloaded. SUN_RADIUS_KM 695700, EARTH_EQUATORIAL_RADIUS_KM 6378.1366, EARTH_FLATTENING 0.996647180302104, struct field documentation.
- 16company Astronomy Engine source/c/astronomy.c Raw source downloaded 2026-09-15 (122 KB) and grepped. CalcShadow, GeoidIntersect, LocalEclipse, Obscuration, EclipseKindFromUmbra.
- 17company Skyfield: Almanac documentation Read live. Lunar eclipses only; Explanatory Supplement method; comparison against the lunar Canon.
- 18company Skyfield skyfield/eclipselib.py Read live (raw). Constants for the lunar routine; no solar routine.
- 19unsourced Skyfield issue #445 Eclipse Functionality Read live. Feature request from 2020, open.
- 20unsourced Skyfield pull request #1076 Add routine and test for the solar eclipse calculation Read live. Geometric minimum-angle search; open at time of reading.
- 21unsourced Skyfield issue #1078 Solar Eclipse calculation routine Read live. Proposal from 2025 with validation claim against NASA; no maintainer reply visible.
- 22company PyEphem Quick Reference Read live. separation(), size and radius attributes; no eclipse functions.
- 23company libnova: Solar functions (API documentation) Read live. Function list contains coordinates, rise/set and semidiameter only.
- 24primary USNO: NOVAS information Read live. NOVAS 3.1 scope is positional astronomy; no eclipse routines are described.
- 25primary IAU SOFA home page Read live. Scope statement (standard models of fundamental astronomy); release 2023-10-11; no eclipse routine mentioned.
- 26unsourced astropy issues search for solar eclipse Read live. Two unrelated issues; no eclipse prediction feature.
- 27company sunpy.coordinates.sun.eclipse_amount API documentation Read live. moon_radius options IAU 0.2725076 and minimum 0.272281; constant-radius caveat; recommends a JPL ephemeris.
- 28company sunpy gallery: Obtaining solar-eclipse information Read live. Uses de440s and ITRS observer positions.
- 29primary NAIF CSPICE gfsep_c documentation Read live. Angular separation search; ELLIPSOID shape not implemented; restrictions on zero-separation searches.
- 30primary JPL Horizons System Manual Read live. Observer table quantities, DE440/DE441, satellite eclipse circumstances; no solar eclipse product.
- 31company astronomia src/eclipse.js (commenthol) Read live. Meeus chapter 54 global circumstances only.
- 32company soniakeys/meeus eclipse package (Go) Read live. Solar(year) and Lunar(year) return type, central flag, jmax, gamma, magnitude.
- 33company Starainrt/astro (Go astronomy library) README Read live. VSOP87 and ELP2000/82 built in, Meeus-based, central path and footprints, Apache-2.0, 157 stars.
- 34company andrmoel/astronomy-bundle README Read live. PHP library with local circumstances C1 to C4 from VSOP87 and Meeus; MIT.
- 35company PyMeeus documentation index Read live (index only). No eclipse module visible in the module list.