mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
orbitUtils.hpp
Go to the documentation of this file.
1 /** \file orbitUtils.hpp
2  * \author Jared R. Males
3  * \brief Utilities related to orbits.
4  * \ingroup astrofiles
5  *
6  */
7 
8 #ifndef mx_astro_orbitUtils_hpp
9 #define mx_astro_orbitUtils_hpp
10 
11 #include "../math/constants.hpp"
12 #include "kepler.hpp"
13 
14 namespace mx
15 {
16 namespace astro
17 {
18 
19 ///Calculate the period of an orbit, given the masses and semi-major axis.
20 /**
21  * \tparam units specifies the unit system and precision, see \ref astrounits.
22  *
23  * \returns the period in the specified units
24  *
25  * \ingroup orbits
26  */
27 template<typename units>
28 typename units::realT orbitPeriod( typename units::realT m1, ///< [in] mass of one object.
29  typename units::realT m2, ///< [in] mass of the other object (can be 0).
30  typename units::realT a ///< [in] the semi-major axis of the orbit.
31  )
32 {
33  return math::two_pi<typename units::realT>()* sqrt( (a*a*a) / (constants::G<units>()*(m1+m2)));
34 }
35 
36 
37 ///Calculate the semi-major axis of an orbit, given the masses and Period, using SI units.
38 /**
39  * \tparam units specifies the unit system and precision, see \ref astrounits.
40  *
41  * \returns the semi-major axis in the specified units
42  *
43  * \ingroup orbits
44  */
45 template<typename units>
46 typename units::realT orbitSemiMaj( typename units::realT m1, ///< [in] mass of one object.
47  typename units::realT m2, ///< [in] mass of the other object (can be 0).
48  typename units::realT P ///< [in] the period of the orbit.
49  )
50 {
51  typedef typename units::realT realT;
52 
53  constexpr realT two = static_cast<realT>(2); //Just for convenience.
54 
55  return pow( pow(P/(math::two_pi<realT>()),two) * constants::G<units>() *(m1+m2), math::third<realT>());
56 }
57 
58 ///Calculate the mean anomaly at time t, given the time of pericenter passage t0 and period P.
59 /**
60  * \ingroup orbits
61  */
62 template<typename realT>
63 realT orbitMeanAnol( realT t,
64  realT t0,
65  realT P
66  )
67 {
68  return math::two_pi<realT>()*(t-t0)/P;
69 }
70 
71 ///Calculate the separation and true anomaly for an orbit at the specified mean anomaly.
72 /**
73  * \tparam realT is the type used for arithmetic
74  *
75  * \returns the numer of iterations in solving Kepler's equation, if successful.
76  * \returns -1 if itmax is exceeded.
77  *
78  * \ingroup orbits
79  */
80 template<typename realT>
81 long orbitElements( realT & r, ///< [out] is the orbital separation
82  realT & f, ///< [out] is the true anomaly
83  realT E, ///< [out] is the eccentric anomaly, provided since it is free
84  realT D, ///< [out] is the error after the last iteration of the Kepler solution.
85  realT e, ///< [in] is the eccentricity
86  realT M, ///< [in] is the mean anomaly
87  realT a, ///< [in] is the semi-major axis
88  realT tol=KEPLER_TOL, ///< [in] is the desired tolerance
89  long itmax=KEPLER_ITMAX ///< [in] is the maximum number of iterations
90  )
91 {
92  long its;
93 
94  if(e < 0.0)
95  {
96  std::cerr << "e < 0 in rf_elements\n";
97  return -1;
98  }
99 
100  if(e == 1.0)
101  {
102  std::cerr << "e = 1 in rf_elements, which is not currently handled.\n";
103  return -1;
104  }
105 
106  its = solve_kepler(E, D, e, M, tol, itmax);
107 
108  if(e > 1.0)
109  {
110  f = 2.0*std::atan(std::sqrt((e+1.0)/(e-1.0))*std::tanh(E/2.0));
111  r = a*(1.0-e*std::cosh(E));
112  }
113  else if(e<1.0)
114  {
115  if(e == 0.0)
116  {
117  f = M;
118  r = a;
119  }
120  else
121  {
122  f = 2.0*std::atan(std::sqrt((1.0+e)/(1.0-e))*std::tan(E/2.0));
123  r = a * (1.0-e*std::cos(E));
124  }
125  }
126 
127  return its;
128 }
129 
130 ///Get the orbital phase at true anomaly f. Calculates the cos(alfa) where alfa is the orbital phase.
131 /** Only calculates cos(alfa) to save an operation when possible.
132  *
133  * \tparam realT is the type used for arithmetic
134  *
135  * \returns the cosine of the phase angle
136  *
137  * \ingroup orbits
138  */
139 template<typename realT>
140 realT orbitPhaseCosine( realT f, ///< [in] is the true anomoaly at which to calculate alfa
141  realT w, ///< [in] the argument of pericenter of the orbit
142  realT inc ///< [in] is the inclinatin of the orbit
143  )
144 {
145  return sin(f+w)*sin(inc);
146 }
147 
148 ///Get the lambertian phase function at orbital phase specified as cos(alfa), where alfa is the phase angle.
149 /** Uses cos(alfa) to save an operation after calculating orbit phase.
150  *
151  * \tparam realT is the type used for arithmetic
152  *
153  * \returns the lambert phase function at alpha
154  *
155  * \ingroup orbits
156  */
157 template<typename realT>
158 realT orbitLambertPhase( realT cos_alf /**< [in] the cosine of the phase angle*/)
159 {
160  realT alf = std::acos(cos_alf);
161  return (sin(alf) + (math::pi<realT>()-alf)*cos_alf)/math::pi<realT>();
162 }
163 
164 ///Calculate the radial velocity of an orbiting body inclined relative to an observer.
165 /** \returns the radial velocity of the body with mass m1 as it orbits the barycenter of its orbit w.r.t. m2.
166  *
167  * \ingroup orbits
168  */
169 template<typename units>
170 typename units::realT orbitRV( typename units::realT m1, ///< [in] the mass of the body for which the RV is computed
171  typename units::realT m2, ///< [in] the mass of the other body in the orbiting pair
172  typename units::realT inc, ///< [in] the inclination of the orbit of m2.
173  typename units::realT a, ///< [in] the semi-major axis of the orbit
174  typename units::realT e, ///< [in] the eccentricity of the orbit
175  typename units::realT w, ///< [in] the argument of pericenter
176  typename units::realT f ///< [in] the true anomaly at which the RV is to be calculated.
177  )
178 {
179  typedef typename units::realT realT;
180 
181  realT msini = m2*sin(inc);
182 
183  realT rv = (msini)*std::sqrt((constants::G<units>()/(m1+m2))/(a*(1-e*e)));
184 
185  rv *= (std::cos(w+f) + e*std::cos(w));
186 
187  return rv;
188 }
189 
190 
191 ///Calculate various quantities of an orbit given the keplerian elements and a vector of times.
192 /** Only those quantities with non-null pointers are actually calculated.
193  *
194  * The orbital parameters with dimensions, (a, P, and t0) must be in consistent units.
195  *
196  * \tparam vectorT a type whose elements are accessed with the [] operator. No other requirements are placed on this type, so it could be a native pointer (i.e. double *).
197  * \tparam realT the type in which to perform calculations. Does not need to match the storage type of vectorT.
198  *
199  * \retval -1 on error calculating the orbit (from rf_elements)
200  * \retval 0 on success.
201  *
202  * \ingroup orbits
203  */
204 template<typename vectorT, typename realT>
205 int orbitCartesianWork( vectorT * x, ///< [out] [optional] If not NULL, will be the projected x positions of the orbit. Must be at least as long as t.
206  vectorT * y, ///< [out] [optional] If not NULL, will be the projected y positions of the orbit. Must be at least as long as t.
207  vectorT * z, ///< [out] [optional] If not NULL, will be the projected z positions of the orbit. Must be at least as long as t.
208  vectorT * r, ///< [out] [optional] If not NULL, will be the separation of the orbit. Must be at least as long as t.
209  vectorT * rProj, ///< [out] [optional] If not NULL, will be the projected separation of the orbit. Must be at least as long as t.
210  vectorT * f, ///< [out] [optional] If not NULL, will be the true anomaly of the orbit. Must be at least as long as t.
211  vectorT * cos_alf, ///< [out] [optional] If not NULL, will be the phase angle of the orbit. Must be at least as long as t.
212  vectorT * phi, ///< [out] [optional] If not NULL, will be the Lambertian phase function. Must be at least as long as t.
213  const vectorT & t, ///< [in] the times at which to calculate the projected positions
214  const size_t N, ///< [in] the number of points contained in t, and allocated in nx, ny, nz. Avoids requiring a size() member (i.e. if vectorT is native pointers).
215  realT a, ///< [in] the semi-major axis of the orbit.
216  realT P, ///< [in] the orbital period.
217  realT e, ///< [in] the eccentricity of the orbit.
218  realT t0, ///< [in] the time of pericenter passage of the orbit.
219  realT i, ///< [in] the inclination of the orbit [radians].
220  realT w, ///< [in] the argument of pericenter of the orbit [radians].
221  realT W ///< [in] the longitude of the ascending node of the orbit [radians].
222  )
223 {
224  long rv;
225  realT _M, _r, _f, _E, _D;
226 
227  //Just do these calcs once
228  realT cos_i = cos(i);
229  realT sin_i = sin(i);
230  realT cos_W = cos(W);
231  realT sin_W = sin(W);
232 
233  realT cos_wf, sin_wf;
234 
235  for(size_t j=0; j < N; j++)
236  {
237  _M = orbitMeanAnol(t[j], t0, P);
238 
239  rv = orbitElements(_r, _f, _E, _D, e, _M, a);
240 
241  if(rv < 0) return -1;
242 
243  //one calc
244  cos_wf = cos(w+_f);
245  sin_wf = sin(w+_f);
246 
247  //Assumption is that these will be optimized away if NULL
248  if(x) (*x)[j] = _r*(cos_W*cos_wf-sin_W*sin_wf*cos_i);
249  if(y) (*y)[j] = _r*(sin_W*cos_wf+cos_W*sin_wf*cos_i);
250  if(z) (*z)[j] = _r*sin_wf*sin_i;
251  if(r) (*r)[j] = _r;
252  if(rProj)
253  {
254  if(x && y)
255  {
256  (*rProj)[j] = sqrt((*x)[j]*(*x)[j] + (*y)[j]*(*y)[j]);
257  }
258  else if(x && !y)
259  {
260  realT _y = _r*(sin_W*cos_wf+cos_W*sin_wf*cos_i);
261  (*rProj)[j] = sqrt((*x)[j]*(*x)[j] + _y*_y);
262  }
263  else if(!x && y)
264  {
265  realT _x = _r*(cos_W*cos_wf-sin_W*sin_wf*cos_i);
266  (*rProj)[j] = sqrt( _x*_x + (*y)[j]*(*y)[j]);
267  }
268  else
269  {
270  realT _x = _r*(cos_W*cos_wf-sin_W*sin_wf*cos_i);
271  realT _y = _r*(sin_W*cos_wf+cos_W*sin_wf*cos_i);
272  (*rProj)[j] = sqrt( _x*_x + _y*_y);
273  }
274  }
275 
276  if(f) (*f)[j] = _f;
277 
278  if(cos_alf) (*cos_alf)[j] = sin_wf*sin_i;
279 
280  if(phi) (*phi)[j] = orbitLambertPhase<realT>(sin_wf*sin_i);
281 
282  }
283  return 0;
284 }
285 
286 
287 ///Calculate the cartesian x-y position and the Lambert phase function of an orbit given Keplerian elements and a vector of times.
288 /**
289  * \tparam vectorT a type whose elements are accessed with the [] operator.
290  * \tparam arithT the type in which to perform arithmetic
291  *
292  * \retval -1 on error calculating the orbit (from orbitCartesianWork)
293  * \retval 0 on success.
294  *
295  * \ingroup orbits
296  */
297 template<typename vectorT, typename arithT>
298 int orbitCartesian2DPhi( vectorT &x, ///< [out] the projected x positions of the orbit. Must be at least as long as t.
299  vectorT &y, ///< [out] the projected y positions of the orbit. Must be at least as long as t.
300  vectorT &r, ///< [out] the separation of the orbit. Must be at least as long as t.
301  vectorT &rProj, ///< [out] the projected separation of the orbit. Must be at least as long as t.
302  vectorT &phi, ///< [out] the Lambert phase function. Must be at least as long as t.
303  const vectorT & t, ///< [in] the times at which to calculate the projected positions
304  const size_t N, ///< [in] the number of points contained in N, and allocated in nx, ny, nz
305  arithT a, ///< [in] the semi-major axis of the orbit
306  arithT P, ///< [in] the orbital period
307  arithT e, ///< [in] the eccentricity of the orbit
308  arithT t0, ///< [in] the time of pericenter passage of the orbit
309  arithT i, ///< [in] the inclination of the orbit
310  arithT w, ///< [in] the argument of pericenter of the orbit
311  arithT W ///< [in] the longitude of the ascending node of the orbit.
312  )
313 {
314  return orbitCartesianWork(&x, &y, (vectorT *)0, &r, &rProj, (vectorT *)0, (vectorT *)0, &phi, t, N, a, P, e, t0, i, w, W);
315 }
316 
317 
318 
319 } //namespace astro
320 } //namespace mx
321 
322 #endif //mx_astro_orbitUtils_hpp
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:161
realT orbitPhaseCosine(realT f, realT w, realT inc)
Get the orbital phase at true anomaly f. Calculates the cos(alfa) where alfa is the orbital phase.
Definition: orbitUtils.hpp:140
realT orbitLambertPhase(realT cos_alf)
Get the lambertian phase function at orbital phase specified as cos(alfa), where alfa is the phase an...
Definition: orbitUtils.hpp:158
units::realT orbitRV(typename units::realT m1, typename units::realT m2, typename units::realT inc, typename units::realT a, typename units::realT e, typename units::realT w, typename units::realT f)
Calculate the radial velocity of an orbiting body inclined relative to an observer.
Definition: orbitUtils.hpp:170
units::realT orbitSemiMaj(typename units::realT m1, typename units::realT m2, typename units::realT P)
Calculate the semi-major axis of an orbit, given the masses and Period, using SI units.
Definition: orbitUtils.hpp:46
int orbitCartesianWork(vectorT *x, vectorT *y, vectorT *z, vectorT *r, vectorT *rProj, vectorT *f, vectorT *cos_alf, vectorT *phi, const vectorT &t, const size_t N, realT a, realT P, realT e, realT t0, realT i, realT w, realT W)
Calculate various quantities of an orbit given the keplerian elements and a vector of times.
Definition: orbitUtils.hpp:205
long orbitElements(realT &r, realT &f, realT E, realT D, realT e, realT M, realT a, realT tol=KEPLER_TOL, long itmax=KEPLER_ITMAX)
Calculate the separation and true anomaly for an orbit at the specified mean anomaly.
Definition: orbitUtils.hpp:81
int orbitCartesian2DPhi(vectorT &x, vectorT &y, vectorT &r, vectorT &rProj, vectorT &phi, const vectorT &t, const size_t N, arithT a, arithT P, arithT e, arithT t0, arithT i, arithT w, arithT W)
Calculate the cartesian x-y position and the Lambert phase function of an orbit given Keplerian eleme...
Definition: orbitUtils.hpp:298
units::realT orbitPeriod(typename units::realT m1, typename units::realT m2, typename units::realT a)
Calculate the period of an orbit, given the masses and semi-major axis.
Definition: orbitUtils.hpp:28
realT orbitMeanAnol(realT t, realT t0, realT P)
Calculate the mean anomaly at time t, given the time of pericenter passage t0 and period P.
Definition: orbitUtils.hpp:63
Declarations for the utilities related to the Kepler problem.
The mxlib c++ namespace.
Definition: mxError.hpp:107