mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
astroDynamics.hpp
Go to the documentation of this file.
1 /** \file astroDynamics.hpp
2  * \author Jared R. Males (jaredmales@gmail.com)
3  * \brief Various utilities for astrodynamics.
4  * \ingroup astrofiles
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2018 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 
28 #ifndef astroDynamics_hpp
29 #define astroDynamics_hpp
30 
31 #include <cmath>
32 
33 #include "sofa.hpp"
34 
35 #include "../math/constants.hpp"
36 #include "../math/geo.hpp"
37 
38 namespace mx
39 {
40 namespace astro
41 {
42 
43 
44 
45 ///Breaks down a decimal day into hours, minutes and decimal point seconds.
46 /** Assumes 86400 seconds per day, ignoring leap seconds.
47  *
48  * \tparam realT the floating point type for calculations
49  *
50  * \retval 0 on success
51  * \retval -1 on failure.
52  */
53 template<typename realT>
54 int hrMinSecFromDay( int & Dy, ///< [out] the integer day
55  int & hr, ///< [out] the integer hour
56  int & min, ///< [out] the integer minute
57  realT & sec, ///< [out] the integer second
58  realT day ///< [in] the decimal day to be broken down
59  )
60 {
61  Dy = (int) day;
62  hr = (day - (realT) Dy)*24.0;
63  min = (day - (realT) Dy - ((realT)hr)/24.0) * 60.*24.0;
64  sec = (day - (realT) Dy - ((realT)hr)/24.0 - ((realT) min)/(60.0*24.0)) * 3600.0*24.0;
65 
66  return 0;
67 }
68 
69 
70 ///Returns Greenwich Mean Sidereal Time for a given UTC time.
71 /** Uses the SOFA 2006 GMST function, and a (for now) hardcoded value of dUT1
72  *
73  * \retval 0 on success
74  */
75 template<typename realT>
76 int getGMST( realT & GMST, ///< [out] GMST in hours
77  int Yr, ///< [in] integer year
78  int Mo, ///< [in] integer month (1-12)
79  int Dy, ///< [in] integer day (1-31)
80  int hr, ///< [in] integer hour (0-23)
81  int min, ///< [in] integer minute (0-59)
82  realT sec ///< [in] decimal second (0-59)
83  )
84 {
85  int rv;
86  double utc0, utc1, tai0, tai1, tt0, tt1, ut10, ut11;
87 
88  //Get UTC time in SOFA 2-double format
89  rv = sofa::iauDtf2d ( "UTC", Yr, Mo, Dy, hr, min, static_cast<double>(sec), &utc0, &utc1);
90  if(rv < 0)
91  {
92  /// \todo handle SOFA error.
93  return -1;
94  }
95 
96  //Convert UTC to TAI
97  rv = sofa::iauUtctai(utc0, utc1, &tai0, &tai1);
98  if(rv < 0)
99  {
100  /// \todo handle SOFA error.
101  return -1;
102  }
103 
104  //Convert TAI to TT
105  rv = sofa::iauTaitt (tai0, tai1, &tt0, &tt1);
106  if(rv < 0)
107  {
108  /// \todo handle SOFA error.
109  return -1;
110  }
111 
112  //Convert UTC to UT1
113  rv = sofa::iauUtcut1(utc0, utc1, -.4, &ut10, &ut11); //The current DUT1 - how to keep updated?
114  if(rv < 0)
115  {
116  /// \todo handle SOFA error.
117  return -1;
118  }
119 
120  GMST = sofa::iauGmst06(ut10, ut11, tt0, tt1)/(math::two_pi<realT>())*static_cast<realT>(24);
121 
122  return 0;
123 }
124 
125 ///Returns Greenwich Mean Sidereal Time for a given UTC time.
126 /** Uses the SOFA 2006 GMST function, and a (for now) hardcoded value of dUT1
127  * \param GMST [output] GMST in hours
128  * \param Yr [input] integer year
129  * \param Mo [input] integer month (1-12)
130  * \param day [input] decimal day (1-31)
131  * \retval 0 on sucess
132  */
133 template<typename realT>
134 int getGMST( realT & GMST, ///< [out] GMST in hours
135  int Yr, ///< [in] integer year
136  int Mo, ///< [in] integer month (1-12)
137  realT day ///< [in] decimal day (1-31)
138  )
139 {
140  int Dy, hr, min;
141  double sec;
142 
143  hrMinSecFromDay<realT>(Dy, hr, min, sec, day);
144  return getGMST(GMST, Yr, Mo, Dy, hr, min, sec);
145 }
146 
147 ///Returns Local Mean Sidereal Time for a given UTC time and longitude.
148 /** Uses the SOFA 2006 GMST function, and a (for now) hardcoded value of dUT1
149  *
150  * \retval 0 on success
151  *
152  */
153 template<typename realT>
154 int getLMST( realT & LMST, ///< [out] LMST in hours
155  int Yr, ///< [in] integer year
156  int Mo, ///< [in] integer month (1-12)
157  int Dy, ///< [in] integer day (1-31)
158  int hr, ///< [in] integer hour (0-23)
159  int min, ///< [in] integer minute (0-59)
160  realT sec, ///< [in] decimal second (0-59)
161  realT lon ///< [in] longitude in degrees, E+, W-
162  )
163 {
164  int rv;
165  realT GMST;
166 
167  rv = getGMST(GMST, Yr,Mo, Dy, hr, min, sec);
168 
169  LMST = GMST + lon/static_cast<realT>(15);
170 
171  LMST = fmod(LMST, 24);
172  if(LMST < 0.0) LMST += 24.;
173 
174  return rv;
175 }
176 
177 ///Returns Local Mean Sidereal Time for a given UTC time.
178 /** Uses the SOFA 2006 GMST function, and a (for now) hardcoded value of dUT1
179  *
180  * \tparam realT the floating point type for all calculations
181  *
182  * \retval 0 on sucess
183  */
184 template<typename realT>
185 int getLMST( realT & LMST, ///< [out] LMST in hours
186  int Yr, ///< [in] integer year
187  int Mo, ///< [in] integer month (1-12)
188  realT day, ///< [in] decimal day (1-31)
189  realT lon ///< [in] longitude in degrees, E+, W-
190  )
191 {
192  int Dy, hr, min;
193  realT sec;
194 
195  hrMinSecFromDay<realT>(Dy, hr, min, sec, day);
196 
197  return getLMST(LMST, Yr, Mo, Dy, hr, min, sec, lon);
198 }
199 
200 
201 ///Calculates the Azimuth and Elevation for a given Hour-Angle, Declination, and Latitude.
202 /** References: J. Meeus "Astronomical Algorithms", 1991; V. Pisacane "Fundamentals of Space Systems", 2nd ed., 2005.
203  *
204  * \tparam realT the real floating point type for calculations
205  *
206  * \returns 0 on success
207  * \returns -1 on error
208  *
209  * \ingroup posastro
210  */
211 template<typename realT>
212 int calcAzEl( realT & az, ///< [out] the calculated azimuth [degrees]
213  realT & el, ///< [out] the calculate elevation [degrees]
214  realT ha, ///< [in] the hour ange [degrees]
215  realT dec, ///< [in] the declination [degrees]
216  realT lat ///< [in] the latitude [degrees]
217  )
218 {
219  realT ha_rad, dec_rad, lat_rad, az_rad, el_rad;
220 
221  ha_rad = ha*static_cast<realT>(15)*math::pi<realT>()/static_cast<realT>(180);
222  dec_rad = dec*math::pi<realT>()/static_cast<realT>(180);
223  lat_rad = lat*math::pi<realT>()/static_cast<realT>(180);
224 
225  az_rad = atan2(sin(ha_rad), cos(ha_rad)*sin(lat_rad)-tan(dec_rad)*cos(lat_rad));
226 
227  el_rad = asin(sin(lat_rad)*sin(dec_rad) + cos(lat_rad)*cos(dec_rad)*cos(ha_rad));
228 
229  az = az_rad*static_cast<realT>(180)/math::pi<realT>() + static_cast<realT>(180);
230  el = el_rad*static_cast<realT>(180)/math::pi<realT>();
231 
232  return 0 ;
233 }
234 
235 ///Calculate the Parallactic Angle from the pre-calculated trig functions. Result in radians.
236 /**
237  * \returns the parallactic angle in radians.
238  *
239  * \test Scenario: calculating parallactic angles \ref tests_astrodynamics_parang "[test doc]"
240  *
241  * \ingroup posastro
242  */
243 template<typename realT>
244 realT parAngRad( realT sinHA, ///< [in] the sine of the target hour angle
245  realT cosHA, ///< [in] the cosine of the target hour angle
246  realT sinDec, ///< [in] the sine of the target declination
247  realT cosDec, ///< [in] the cosine of the target declination
248  realT tanLat ///< [in] the tangent of the observer latitude
249  )
250 {
251  return atan2( sinHA, cosDec*tanLat - sinDec*cosHA);
252 }
253 
254 ///Calculate the Parallactic Angle from the pre-calculated trig functions. Result in degrees.
255 /**
256  * \returns the parallactic angle in degrees.
257  *
258  *
259  *
260  * \ingroup posastro
261  */
262 template<typename realT>
263 realT parAngDeg( realT sinHA, ///< [in] the sine of the target hour angle
264  realT cosHA, ///< [in] the cosine of the target hour angle
265  realT sinDec, ///< [in] the sine of the target declination
266  realT cosDec, ///< [in] the cosine of the target declination
267  realT tanLat ///< [in] the tangent of the observer latitude
268  )
269 {
270  return math::rtod( parAngRad(sinHA, cosHA, sinDec, cosDec, tanLat) );
271 }
272 
273 /// Calculate the Parallactic Angle, with angles in radians
274 /**
275  * \return the parallactic angle in radians.
276  *
277  * \test Scenario: calculating parallactic angles \ref tests_astrodynamics_parang "[test doc]"
278  *
279  * \ingroup posastro
280  */
281 template<typename realT>
282 realT parAngRad( realT ha, ///< [in] the hour angle, in radians, negative to the east
283  realT dec, ///< [in] the object declination, in radians.
284  realT lat ///< [in] the observer latitude, in radians.
285  )
286 {
287  return parAngRad( sin(ha), cos(ha), sin(dec), cos(dec), tan(lat));
288 }
289 
290 /// Calculate the Parallactic Angle, with angles in degrees
291 /**
292  * \return the parallactic angle in degrees.
293  *
294  * \test Scenario: calculating parallactic angles \ref tests_astrodynamics_parang "[test doc]"
295  *
296  * \ingroup posastro
297  *
298  * \note 2020-Jan-19: re-reordered arguments and added newflag to prevent compilation of current programs so the new order is implemented.
299  */
300 template<typename realT>
301 realT parAngDeg( realT ha, ///< [in] the hour angle, in degrees, negative to the east
302  realT dec, ///< [in] the object declination, in degrees.
303  realT lat, ///< [in] the observer latitude, in degrees.
304  bool newflag ///< [in] [temporary] to force adaptation of new argument order. Unused, so can be true or false. Added 2020-Jan-19.
305  )
306 {
307  static_cast<void>(newflag); //be unused
308 
309  return math::rtod( parAngRad( math::dtor(ha), math::dtor(dec), math::dtor(lat)) );
310 }
311 
312 
313 
314 
315 } //namespace astro
316 } //namespace mx
317 
318 #endif //astroDynamics_hpp
319 
int getGMST(realT &GMST, int Yr, int Mo, int Dy, int hr, int min, realT sec)
Returns Greenwich Mean Sidereal Time for a given UTC time.
int hrMinSecFromDay(int &Dy, int &hr, int &min, realT &sec, realT day)
Breaks down a decimal day into hours, minutes and decimal point seconds.
int getLMST(realT &LMST, int Yr, int Mo, int Dy, int hr, int min, realT sec, realT lon)
Returns Local Mean Sidereal Time for a given UTC time and longitude.
constexpr units::realT day()
Length of day.
Definition: constants.hpp:100
realT rtod(realT q)
Convert from radians to degrees.
Definition: geo.hpp:147
realT dtor(realT q)
Convert from degrees to radians.
Definition: geo.hpp:132
int calcAzEl(realT &az, realT &el, realT ha, realT dec, realT lat)
Calculates the Azimuth and Elevation for a given Hour-Angle, Declination, and Latitude.
realT parAngRad(realT ha, realT dec, realT lat)
Calculate the Parallactic Angle, with angles in radians.
realT parAngDeg(realT ha, realT dec, realT lat, bool newflag)
Calculate the Parallactic Angle, with angles in degrees.
The mxlib c++ namespace.
Definition: mxError.hpp:107
Wrapper for the sofa library headers, adding a namespace.