TKS Eclipse Engine

Solar & lunar eclipse computation

Research-grade eclipse computation + large-scale baseline catalogue

Every solar (place-dependent) and lunar (geocentric) eclipse in a chosen range, each with contacts, magnitude, obscuration, a shadow diagram and a Besselian elements central path — from an independent ephemeris pipeline using DE kernels only as reference state data.

Technical Grade Platinum A++ NASA 5MC Validated Eclipse Catalogue ~30,189 years 1000-yr query 166 ms

Live computation · select a range

Scans every solar & lunar eclipse from From year to To year (inclusive), starting at the given month/day.
How to put BCE: choose Era = BCE and type the BCE year directly — e.g. From 3139 scans 3139 BCE. Internally a BCE year N is the astronomical year 1 − N (there is no year 0): 3139 BCE → −3138 · 1 BCE → 0. You may also leave Era = CE and type a negative astronomical year yourself.
Every range within DE441 coverage (−13000…+17189) is served instantly from the precomputed baseline catalogue (30,189 yr · 144,168 events) — no cap.
Beyond DE441 coverage, the ±2000-yr beyond-edge band is also precomputed (edge / edge200 / edge2000, Engine B) and served instantly via /v1/tks/eclipse-catalogue-edge-full — a reconstruction (timing degrades with span; no independent reference). Only a range outside ±2000 yr needs the CLI: panchanga --eclipse-scan --engine b.

Overview

Solar

topocentric
True (light-time corrected) topocentric directions to Sun and Moon give the centre separation s(t); comparing with the apparent angular radii yields type, magnitude, obscuration and contacts C1–C4.

Lunar

geocentric
The Moon's angular distance from the anti-solar shadow axis is compared with umbral/penumbral radii (parallax ± solar radius, +2% atmosphere) to classify penumbral/partial/total and give P1, U1–U4, P4.

Path & Saros

derived
The umbral axis is intersected with the Earth ellipsoid for the central path and umbral width; the saros series is identified from a catalog of active series.

Performance benchmark

HTTP API

warm · this server
Range list · catalogue · 100 yr17 ms
Range list · catalogue · 500 yr83 ms
Range list · catalogue · 1000 yr166 ms
Range list · catalogue · 3000 yr490 ms
Live scan · 1 yr22 ms
Live ad-hoc scan · ≤10 yr (fallback)52 ms
Full-catalogue page (200 rows)7 ms
Single eclipse detail5 ms
Large ranges are served from the precomputed catalogue — local circumstances from stored Besselian elements (1000 yr ≈ 0.17 s, no ephemeris query).

CLI (offline)

reader · stored Besselian
--eclipse-query · 1 yr0.15 s
--eclipse-query · 10 yr0.15 s
--eclipse-query · 100 yr0.16 s
--eclipse-query · 1000 yr0.31 s
Reader = precomputed catalogue se, koi engine scan nahi. (Builder --eclipse-scan: 1000 yr ≈ 5 s, full 30,189 yr ≈ 197 s.) Same Besselian method as HTTP; includes file parse per run.

Accuracy · validated vs NASA/GSFC Five Millennium Canon

Solar eclipses

11,898 · −1999…+3000
Saros number0 / 11,898 mismatches
Type (total/annular/partial)0 mismatches (37 hybrid/grazing edges excluded)
Gamma γ|Δγ| mean 0.0003 · max 0.0022 R⊕
Magnitude|Δ| mean 0.0022 · max 0.067
Greatest time · 900–2000 CEsub-second … 2 s
Greatest time · ±2000 yr≤ 360 s (lunar-theory diff.)
Central-path widthmean 2.6 km · max 24 km
Greatest-eclipse pointmean 50 km (NASA 1° rounding)

Lunar eclipses

12,064 · −1999…+3000
Saros number0 / 12,064 mismatches
Type (penumbral/partial/total)0 mismatches (32 boundary edges excluded)
Gamma γ|Δγ| mean 0.0003 · max 0.0022 R⊕
Umbral / penumbral magnitude|Δ| mean 0.0034 · max 0.008
Greatest time · 900–2000 CE~1 s
Greatest time · ±2000 yr≤ 355 s (lunar-theory diff.)
Reference = NASA/GSFC Five Millennium Canon (Espenak & Meeus; VSOP87/ELP-2000 + MS2004 ΔT). Modern era matches to seconds; the growing ancient-time difference is the lunar-theory / secular-acceleration difference (ELP-2000 vs our DE441) — not an error; DE441 is the more modern ephemeris. Local circumstances validated to the minute against published circumstances (e.g. Dallas 2024-04-08: C1 17:23 · C2 18:40 · max 18:42 · C3 18:44 · C4 20:02 UTC, magnitude 1.013, total).

Theory

Syzygy

epoch
Δλ(t) = sn180( λ☾ − λ☉ ) ; new moon Δλ = 0 ; full moon Δλ = 180°
Root-finding on the apparent ecliptic-of-date longitudes locates the conjunction/opposition instant.

Solar geometry

local
ρ☉ = asin(R☉/Δ☉) , ρ☾ = asin(R☾/Δ☾) m = (ρ☉ + ρ☾ − s) / (2ρ☉) , O = A_overlap / (π ρ☉²) contacts: s(t) = ρ☉ + ρ☾ (C1,C4) ; s(t) = |ρ☉ − ρ☾| (C2,C3)

Lunar geometry

geocentric
δ = angle from shadow axis ; π = asin(R⊕/|r☾|) ; s☉ = asin(R☉/|r☉|) ρ_umbra = 1.02 (π − s☉) ; ρ_pen = 1.02 (π + s☉) U = (ρ_umbra + s☾ − δ)/(2 s☾) ; P = (ρ_pen + s☾ − δ)/(2 s☾)

Besselian elements path

central
P(s) = r☾ + s·d̂ , d̂ = normalize(r☾ − r☉) ; |P| = R_ellipsoid(φ′) → central (lat,lon) w = 2 ( R☾ − L (R☉−R☾)/|r☉−r☾| ) (negative width = annular)

Validation · 2026

Lunar

vs NASA/Espenak
3 March — Totalumag 1.152 · P1 08:44 → P4 14:26 UTC
28 August — Partialumag 0.931

Solar

vs NASA/Espenak
12 August — TotalReykjavik · mag 1.014
17 February — AnnularAntarctica (70°S,140°E) · mag 0.976

Saros

One saros = 223 synodic months = 6585.3213 days ≈ 18 y 11 d 8 h. The engine identifies the active series (solar 117–156, lunar 110–150) from a catalog of member epochs and reports the next same-series eclipse.

Methods & provenance

EngineEngine A — reference DE path (independent SPK/DAF evaluator) within JPL DE441 coverage (−13,202 … +17,191); beyond that → Engine B (independent N-body, dynamical reconstruction)
State sourceJPL DE440 / DE441 (reference state data only)
Reductionlight-time · aberration · solar deflection · IAU 2006 precession · IAU 2000B nutation · ecliptic of date
TimeTT/TDB; ΔT = SMH2016; observer via GAST (GMST + equation of equinoxes)
Earth figureWGS84 ellipsoid for observer & shadow-axis intersection
ReferenceNASA/Espenak eclipse catalogs (validation), IAU/SOFA conventions
Numerical precision ≠ physical accuracy ≠ observational uncertainty. Contact times carry model/ΔT uncertainty of order seconds.

Full catalogue · geocentric · −13000 → +17190

… loading catalogue …
Precomputed once over the full JPL DE441 range — geocentric: every solar eclipse worldwide (penumbra touches Earth; magnitude at the greatest-eclipse point) + all lunar eclipses — with magnitude, Saros, contacts and Pañcāṅga at greatest eclipse. Times UTC; contacts labelled (solar C1·C2·C3·C4, lunar P1·U1–U4·P4). Sorted/filtered server-side; full range precomputed because JPL is available throughout.

Engine B catalogue · beyond DE441 · filterable

… loading Engine-B catalogue …
eyond JPL DE441 coverage (−13,202 … +17,191) the reference ephemeris ends, so these events come from Engine B — planets from the independent 11-body N-body integrator (DOPRI5, EIH 1PN, J2–J6) seeded at each coverage edge and integrated outward (full range ±2000 yr; narrow it with From/To year). The Moon is taken from a fitted truncated lunar series (λ,β,r least-squares fitted to DE441, with a linearized argument-drift basis), replacing the divergent N-body Moon: validated on held-out DE441 to λ ≈ 5–7′ / β ≈ 0.2° (±200-yr band) and λ ≈ 7′ over a ~2200-yr extrapolation. Planets ~arcmin. Runs the same full eclipse engine as Engine A (magnitude, contacts C1–C4 / P1–P4, Saros, Besselian, Pañcāṅga). Honest caveat: no independent reference exists beyond the edge, and accuracy degrades with span — these are reconstructions. Source data/eclipse_catalogue_edge2000.json · /v1/tks/eclipse-catalogue-edge-full.
संस्करणः bin-1790611335
`; const w=window.open("","_blank"); if(!w){ alert("Pop-up blocked — allow pop-ups to export the PDF."); return; } w.document.open(); w.document.write(html); w.document.close(); setTimeout(function(){ try{ w.focus(); w.print(); }catch(e){} }, 500); }); { const QQ=new URLSearchParams(location.search); ["year","month","day","years","lat","lon","place"].forEach(k=>{ const el=$(k); if(el&&QQ.has(k)) el.value=QQ.get(k); }); } $("go").click(); // ---- Full geocentric catalogue (precomputed over the whole DE441 range) ---- let cOff=0; const catRows=()=>parseInt($("cLim").value||"20",10); async function loadCat(){ $("cat").innerHTML=`loading…`; const q=`type=${$("cType").value}&kind=${$("cKind").value}&sort=${$("cSortSel").value}&from_year=${$("cFrom").value}&to_year=${$("cTo").value}&limit=${catRows()}&offset=${cOff}`; try{ const d=await fetch(`${API_BASE}/v1/tks/eclipse-catalogue-full?${q}`).then(r=>r.json()); if(!d.success){ $("cat").innerHTML=`failed`; return; } $("cInfo").innerHTML=`Showing ${d.total_matched?(d.offset+1):0}–${d.offset+d.rows.length} of ${d.total_matched} · sort ${d.sort} · catalogue: ${d.counts.solar||0} solar / ${d.counts.lunar||0} lunar · self-contained (Besselian + ΔT)`; $("cat").innerHTML=`DateTypeKindMagWidth kmΔt sSarosTithiNakṣatraRāśi S/MContacts (UTC)` + d.rows.map(r=>`${r.date}${r.type}${r.kind||"—"}${f(r.magnitude,3)}${r.greatest?Math.abs(r.greatest[2]).toFixed(0):"—"}${r.dt_s==null?"—":r.dt_s.toFixed(0)}${r.saros==null?"—":r.saros}${r.paksha||""} ${r.tithi==null?"":r.tithi}${esc(r.nakshatra)} · ${r.pada==null?"—":r.pada}${esc(r.sun_rashi)} / ${esc(r.moon_rashi)}${(r.contacts||[]).filter(Boolean).join(" · ")||"—"}`).join(""); }catch(e){ $("cat").innerHTML=`${e.message||e}`; } } $("cLoad").onclick=()=>{ cOff=0; loadCat(); }; $("cPrev").onclick=()=>{ cOff=Math.max(0,cOff-catRows()); loadCat(); }; $("cNext").onclick=()=>{ cOff+=catRows(); loadCat(); }; loadCat(); // ---- Engine-B catalogue (beyond JPL DE441), filterable like the main catalogue ---- let eOff=0; const eRows=()=>parseInt($("eLim").value||"20",10); async function loadEdgeFull(){ $("edgeFull").innerHTML=`loading…`; const q=`type=${$("eType").value}&kind=${$("eKind").value}&sort=${$("eSortSel").value}&from_year=${$("eFrom").value}&to_year=${$("eTo").value}&limit=${eRows()}&offset=${eOff}`; try{ const d=await fetch(`${API_BASE}/v1/tks/eclipse-catalogue-edge-full?${q}`).then(r=>r.json()); if(!d.success){ $("edgeFull").innerHTML=`failed`; return; } $("edgeInfo").innerHTML=`Showing ${d.total_matched?(d.offset+1):0}–${d.offset+d.rows.length} of ${d.total_matched} · ${d.counts.solar||0} solar / ${d.counts.lunar||0} lunar · Engine B reconstruction (beyond DE441; Moon = fitted lunar series)`; $("edgeFull").innerHTML=`DateTypeKindMagWidth kmΔt sSarosTithiNakṣatraRāśi S/MContacts (UTC)` + d.rows.map(r=>`${esc(r.date)}${r.type}${esc(r.kind)}${f(r.magnitude,3)}${r.width_km==null?"—":Math.abs(r.width_km).toFixed(0)}${r.dt_s==null?"—":r.dt_s.toFixed(0)}${r.saros==null?"—":r.saros}${esc(r.paksha||"")} ${r.tithi==null?"":r.tithi}${esc(r.nakshatra||"")}${r.pada==null?"":" · "+r.pada}${esc(r.sun_rashi||"")} / ${esc(r.moon_rashi||"")}${(r.contacts||[]).filter(Boolean).join(" · ")||"—"}`).join(""); }catch(e){ $("edgeFull").innerHTML=`${e.message||e}`; } } $("eLoad").onclick=()=>{ eOff=0; loadEdgeFull(); }; $("ePrev").onclick=()=>{ eOff=Math.max(0,eOff-eRows()); loadEdgeFull(); }; $("eNext").onclick=()=>{ eOff+=eRows(); loadEdgeFull(); }; loadEdgeFull();