Loading [MathJax]/extensions/tex2jax.js
mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
kepler.hpp
Go to the documentation of this file.
1/** \file kepler.hpp
2 * \author Jared R. Males
3 * \brief Declarations for the utilities related to the Kepler problem.
4 * \ingroup astrofiles
5 *
6 */
7
8#ifndef __mx_astro_kepler_hpp__
9#define __mx_astro_kepler_hpp__
10
11#include <iostream>
12#include <cmath>
13#include <cstdlib>
14
15#include "units.hpp"
16
17namespace mx
18{
19
20namespace astro
21{
22
23#ifndef KEPLER_TOL
24/// The default tolerance for solutions to the Kepler problem
25#define KEPLER_TOL ( 1e-8 )
26#endif
27
28#ifndef KEPLER_ITMAX
29/// The default maximum number of iterations for solutions to the Kepler problem
30#define KEPLER_ITMAX ( 1000 )
31#endif
32
33/// Solve the hyperbolic kepler equation (for e> 1).
34/** \note this is not tested very well (as of 2014.08.09)
35 *
36 *
37 * \returns -1 on exceeding itmax, otherwise reurns the number of iterations.
38 *
39 * \tparam realT is the type used for arithmetic
40 *
41 * \ingroup kepler
42 */
43template <typename realT>
44long hyperbolic_kepler( realT &E, ///< [out] is the eccentric anomaly
45 realT &err, ///< [out] is the error after the last iteration
46 realT e, ///< [in] is the eccentricity
47 realT M, ///< [in] is the mean anomaly
48 realT tol, ///< [in] is the desired tolerance
49 long itmax ///< [in] is the maximum number of iterations
50)
51{
52 realT curr, thresh;
53 int is_negative = 0;
54 long n_iter = 0;
55
56 if( e == 1 )
57 e = 1.000001;
58
59 if( M == 0 )
60 return ( 0. );
61
62 err = e * sinh( curr ) - curr - M;
63 while( fabs( err ) > tol && n_iter < 10000 )
64 {
65 n_iter++;
66 curr -= err / ( e * cosh( curr ) - 1. );
67 err = e * sinh( curr ) - curr - M;
68 }
69
70 E = ( is_negative ? -curr : curr );
71
72 if( n_iter > itmax )
73 {
74 std::cerr << "hyperbolic kepler failed to converge e=" << e << "\n";
75 return -1;
76 }
77
78 return n_iter;
79}
80
81/// Calculate the next iteration of Danby's quartic Newton-Raphson method.
82/** \ingroup kepler
83 */
84template <typename realT>
85realT kepler_danby_1( realT e, realT M, realT Ei )
86{
87 realT cosE, sinE, fi, fi1, fi2, fi3, di1, di2, di3;
88
89 // These are expensive, do them just once.
90 cosE = cos( Ei );
91 sinE = sin( Ei );
92
93 fi = Ei - e * sinE - M;
94 fi1 = 1.0 - e * cosE;
95 fi2 = e * sinE;
96 fi3 = e * cosE;
97
98 di1 = -fi / fi1;
99 di2 = -fi / ( fi1 + 0.5 * di1 * fi2 );
100 di3 = -fi / ( fi1 + 0.5 * di2 * fi2 + di2 * di2 * fi3 / 6.0 );
101
102 return Ei + di3;
103}
104
105/// Solve Kepler's equation using Danby's quartic Newton-Raphson method.
106/**
107 * \returns -1 on exceeding itmax.
108 * \returns the number of iterations on success.
109 *
110 * \ingroup kepler
111 */
112template <typename realT>
113long solve_kepler_danby( realT &E, ///< [out] is the eccentric anomaly
114 realT &D, ///< [out] is the error after the last iteration
115 realT e, ///< [in] is the eccentricity
116 realT M, ///< [in] is the mean anomaly
117 realT tol, ///< [in] is the desired tolerance
118 long itmax ///< [in] is the maximum number of iterations
119)
120{
121 long i;
122 realT lastE, sinE, sign;
123
124 sinE = sin( M );
125 sign = 1.0;
126 if( sinE < 0.0 )
127 sign = -1.0;
128
129 E = M + 0.85 * e * sign;
130
131 for( i = 0; i < itmax; i++ )
132 {
133 lastE = E;
134 E = kepler_danby_1( e, M, E );
135
136 // Test for convergence to within tol
137 // Make sure we have iterated at least twice to prevent early convergence
138 if( i > 1 && fabs( E - lastE ) < tol )
139 {
140 D = M - ( E - e * sin( E ) );
141 return i;
142 }
143 }
144
145 return -1; // This means itmax exceeded.
146}
147
148/// Solve Kepler's equation for any e. Uses solve_kepler_danby if e < 1.0, hyperbolic_kepler otherwise.
149/**
150 * \returns the number of iterations on success.
151 * \returns -1 if itmax is exceeded.
152 *
153 * \ingroup kepler
154 */
155template <typename realT>
156long solve_kepler( realT &E, ///< [out] is the eccentric anomaly
157 realT &D, ///< [out] is the error after the last iteration
158 realT e, ///< [in] is the eccentricity
159 realT M, ///< [in] is the mean anomaly
160 realT tol = KEPLER_TOL, ///< [in] is the desired tolerance
161 long itmax = KEPLER_ITMAX ///< [in] is the maximum number of iterations
162)
163{
164 if( e < 1.0 )
165 {
166 return solve_kepler_danby( E, D, e, M, tol, itmax );
167 }
168 else
169 return hyperbolic_kepler( E, D, e, M, tol, itmax );
170}
171
172#if 0
173
174#endif
175
176#if 0
177
178///Calculate the next iteration of Danby's quartic Newton-Raphson method (difference form).
179//floatT keplerdiff_1(floatT EC, floatT ES, floatT dM, floatT dEi);
180template<typename arithT>
181arithT kepler_danby_diff_1(arithT EC, arithT ES, arithT dM, arithT dEi)
182{
183 arithT cosE0, sinE0, cosdE, sindE, fi, fi1, fi2, fi3, di1, di2, di3;
184
185 //These are expensive, do them just once.
186 //cosE0 = cos(E0);
187 //sinE0 = sin(E0);
188 cosdE = cos(dEi);
189 sindE = sin(dEi);
190
191 fi = dEi - EC*sindE + ES*(1-cosdE) - dM;
192 fi1 = 1.0 - EC*cosdE + ES*sindE;
193 fi2 = EC*sindE + ES*cosdE;
194 fi3 = EC*cosdE - ES*sindE;
195
196 di1 = -fi / fi1;
197 di2 = -fi/(fi1 + 0.5*di1*fi2);
198 di3 = -fi/(fi1 + 0.5*di2*fi2 + di2*di2*fi3/6.0);
199
200 return dEi + di3;
201}
202
203///Solve Kepler's equation in difference form using Danby's quartic Newton-Raphson method.
204/** \param dE [output] is the eccentric anomaly
205 * \param D [output] is the error after the last iteration
206 * \param e [input] is the eccentricity
207 * \param EC [input]
208 * \param ES [input]
209 * \param dM [input]
210 * \param tol [input] is the desired tolerance
211 * \param itmax [input] is the maximum number of iterations
212 * \retval -1 on exceeding itmax, otherwise reurns the number of iterations.
213 */
214template<typename arithT>
215long solve_keplerdiff_danby(arithT *dE, arithT *D, arithT e, arithT EC, arithT ES, arithT dM, arithT tol, long itmax)
216{
217 long i;
218 arithT lastdE, sindE, sign;
219
220 sindE = ES*cos(dM-ES) + EC*sin(dM-ES);
221 sign = 1.0;
222 if(sindE < 0.0) sign = -1.0;
223
224 (*dE) = dM + 0.85*sign*e-ES;
225
226 for(i=0; i < itmax; i++)
227 {
228 lastdE = (*dE);
229 (*dE) = kepler_danby_diff_1(EC, ES, dM, (*dE));
230
231 //Test for convergence to within tol
232 //Make sure we have iterated at least twice to prevent early convergence
233 if(i > 0. && fabs((*dE)-lastdE) < tol)
234 {
235 (*D) = dM - (*dE - EC*sin(*dE) + ES*(1-cos(*dE)));
236 return i;
237 }
238 }
239
240 return -1; //This means itmax exceeded.
241}
242
243
244
245
246
247
248///Calculate the inclination and the longitude of the ascending node given a point on the orbit projected onto the plane of the sky, the argument of pericenter, the current true radius, and the current true anomaly.
249/** Solutions are not always possible. You must check the return value to know if the results are valid.
250 * \param i [output] the inclination (there will be 2)
251 * \param W [output] the longitude of the ascending node (there will be 2)
252 * \param x [input] the x coordinate of the projection onto the reference plane
253 * \param y [input] the y coordinate of the projection onto the reference plane
254 * \param rho [input] the projected separation (yes this is redundant to x and y, but it is passed independently for efficiency)
255 * \param r [input] the physical (3D) separation
256 * \param f [input] the true anomaly
257 * \param w [input] the argument of pericenter
258 * \retval 0 on success
259 * \retval -1 if no solution is possible due to ...
260 * \retval -2 if no solution is possible due to z = 0
261 * \retval -3 if no solution is possible due to ...
262 */
263//int get_iW_1pt(mx::Vectord &i, mx::Vectord &W, double x, double y, double rho, double r, double f, double w);
264
265///Calculate the longitude of the ascending node given a point on the orbit projected onto the plane of the sky, the argument of pericenter, the current radius, and the current true anomaly.
266/** Used for the z = 0, i != 0/PI case. i.e. sin(w+f) = 0, cos(w+f) = +/- 1.
267 * w must be either -f or PI - f.
268 * \param W [output] the longitude of the ascending node.
269 * \param x [input] the x coordinate of the starting point
270 * \param y [input] the y coordinate of the starting point
271 * \param r [input] the current 3D separation from the star
272 * \param f [input] the current true anomaly
273 * \param w [input] the argument of pericenter
274 * \retval 0 on success
275 * \retval -1 if the conditions aren't met by w an df
276 */
277template<typename arithT>
278int get_W_1pt_z0(arithT &W, arithT x, arithT y, arithT r, arithT f, arithT w)
279{
280 arithT sinW, cosW;
281
282 if(w == -f)
283 {
284 sinW = y/r;
285 cosW = x/r;
286 }
287 else if(w == DPI - f)
288 {
289 sinW = -y/r;
290 cosW = -x/r;
291 }
292 else return -1;
293
294 W = atan2(sinW, cosW);
295 return 0;
296}
297
298#endif
299
300} // namespace astro
301} // namespace mx
302#endif //__mx_astro_kepler_hpp__
long solve_kepler_danby(realT &E, realT &D, realT e, realT M, realT tol, long itmax)
Solve Kepler's equation using Danby's quartic Newton-Raphson method.
Definition kepler.hpp:113
realT kepler_danby_1(realT e, realT M, realT Ei)
Calculate the next iteration of Danby's quartic Newton-Raphson method.
Definition kepler.hpp:85
long hyperbolic_kepler(realT &E, realT &err, realT e, realT M, realT tol, long itmax)
Solve the hyperbolic kepler equation (for e> 1).
Definition kepler.hpp:44
long solve_kepler(realT &E, realT &D, realT e, realT M, realT tol=KEPLER_TOL, long itmax=KEPLER_ITMAX)
Solve Kepler's equation for any e. Uses solve_kepler_danby if e < 1.0, hyperbolic_kepler otherwise.
Definition kepler.hpp:156
arithT kepler_danby_diff_1(arithT EC, arithT ES, arithT dM, arithT dEi)
Calculate the next iteration of Danby's quartic Newton-Raphson method (difference form).
Definition kepler.hpp:181
int get_W_1pt_z0(arithT &W, arithT x, arithT y, arithT r, arithT f, arithT w)
Calculate the inclination and the longitude of the ascending node given a point on the orbit projecte...
Definition kepler.hpp:278
long solve_keplerdiff_danby(arithT *dE, arithT *D, arithT e, arithT EC, arithT ES, arithT dM, arithT tol, long itmax)
Solve Kepler's equation in difference form using Danby's quartic Newton-Raphson method.
Definition kepler.hpp:215
The mxlib c++ namespace.
Definition mxError.hpp:106
Unit specifications and conversions.