123456789101112131415161718192021222324252627282930313233343536373839404142(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Kepler.mli *)typeelements={a:float;e:float;inclination:float;mean_longitude:float;perihelion:float;node:float}letradiansd=d*.Float.pi/.180.letperiod(a:float):float=a**1.5leteccentric_anomaly~(e:float)(m:float):float=(* Newton's method on f(E) = E - e sin E - M, f'(E) = 1 - e cos E;
* a handful of iterations for the planets' e < 0.21 *)letrecgonx=letdx=(x-.(e*.sinx)-.m)/.(1.-.(e*.cosx))inifn=0||Float.absdx<1e-12thenx-.dxelsego(n-1)(x-.dx)ingo30mletmean_anomaly(el:elements)~(days:float):float=radians(el.mean_longitude-.el.perihelion)+.(2.*.Float.pi*.days/.(365.25*.periodel.a))letin_plane(el:elements)~(days:float):Vec2.t=lete=eccentric_anomaly~e:el.e(mean_anomalyel~days)in(el.a*.(cose-.el.e),el.a*.sqrt(1.-.(el.e*.el.e))*.sine)letposition(el:elements)~(days:float):float*float*float=let(x',y')=in_planeel~daysin(* the argument of perihelion, the node, the inclination (JPL's
* rotations) *)letw=radians(el.perihelion-.el.node)ando=radiansel.nodeandi=radiansel.inclinationinletcw=coswandsw=sinwandco=cosoandso=sinoandci=cosiandsi=siniin((((cw*.co)-.(sw*.so*.ci))*.x')+.((-.(sw*.co)-.(cw*.so*.ci))*.y'),(((cw*.so)+.(sw*.co*.ci))*.x')+.((-.(sw*.so)+.(cw*.co*.ci))*.y'),(sw*.si*.x')+.(cw*.si*.y'))