GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GEphemerides.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GEphemerides.cpp - Ephemerides class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2022 by Juergen Knoedlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GEphemerides.cpp
23  * @brief Ephemerides class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GEphemerides.hpp"
32 #include "GFits.hpp"
33 #include "GFitsTable.hpp"
34 #include "GFitsTableCol.hpp"
35 #include "GSkyDir.hpp"
36 
37 /* __ Method name definitions ____________________________________________ */
38 #define G_EPHEMERIS "GEphemerides::ephemeris(GTime&, GVector*, GVector*, "\
39  "GVector*, double*)"
40 #define G_FETCH_DATA "GEphemerides::fetch_data()"
41 
42 /* __ Macros _____________________________________________________________ */
43 
44 /* __ Coding definitions _________________________________________________ */
45 
46 /* __ Debug definitions __________________________________________________ */
47 
48 
49 
50 /*==========================================================================
51  = =
52  = Constructors/destructors =
53  = =
54  ==========================================================================*/
55 
56 /***********************************************************************//**
57  * @brief Void constructor
58  ***************************************************************************/
60 {
61  // Initialise class members
62  init_members();
63 
64  // Return
65  return;
66 }
67 
68 
69 /***********************************************************************//**
70  * @brief Copy constructor
71  *
72  * @param[in] ephemerides Ephemerides.
73  ***************************************************************************/
75 {
76  // Initialise class members
77  init_members();
78 
79  // Copy members
80  copy_members(ephemerides);
81 
82  // Return
83  return;
84 }
85 
86 
87 /***********************************************************************//**
88  * @brief Destructor
89  ***************************************************************************/
91 {
92  // Free members
93  free_members();
94 
95  // Return
96  return;
97 }
98 
99 
100 /*==========================================================================
101  = =
102  = Operators =
103  = =
104  ==========================================================================*/
105 
106 /***********************************************************************//**
107  * @brief Assignment operator
108  *
109  * @param[in] ephemerides Ephemerides.
110  * @return Ephemerides.
111  ***************************************************************************/
113 {
114  // Execute only if object is not identical
115  if (this != &ephemerides) {
116 
117  // Free members
118  free_members();
119 
120  // Initialise private members
121  init_members();
122 
123  // Copy members
124  copy_members(ephemerides);
125 
126  } // endif: object was not identical
127 
128  // Return this object
129  return *this;
130 }
131 
132 
133 /*==========================================================================
134  = =
135  = Public methods =
136  = =
137  ==========================================================================*/
138 
139 /***********************************************************************//**
140  * @brief Clear Ephemerides
141  ***************************************************************************/
143 {
144  // Free members
145  free_members();
146 
147  // Initialise private members
148  init_members();
149 
150  // Return
151  return;
152 }
153 
154 
155 /***********************************************************************//**
156  * @brief Clone Ephemerides
157  *
158  * @return Pointer to deep copy of Ephemerides.
159  ***************************************************************************/
161 {
162  return new GEphemerides(*this);
163 }
164 
165 
166 /***********************************************************************//**
167  * @brief Load Ephemerides
168  *
169  * @param[in] filename Ephemerides file name.
170  *
171  * Load ephemerides from FITS file.
172  ***************************************************************************/
173 void GEphemerides::load(const GFilename& filename)
174 {
175  // Clear members
176  clear();
177 
178  // Open JPL ephemerides FITS file
179  GFits fits(filename);
180 
181  // Get ephemerides table
182  const GFitsTable* ephem = fits.table("EPHEM");
183 
184  // Extract number of events in FITS file
185  int num = ephem->nrows();
186 
187  // Continue if there are ephemerides
188  if (num > 0) {
189 
190  // Reserve data
191  m_times.reserve(num);
192  m_earth.reserve(num);
193  m_earth_dt.reserve(num);
194  m_earth_d2t.reserve(num);
195  m_earth_d3t.reserve(num);
196  m_sun.reserve(num);
197  m_tdb2tt.reserve(num);
198 
199  // Get validity interval
200  double tstart = ephem->real("TSTART");
201  m_tstart.jd(tstart);
202  m_tstop.jd(ephem->real("TSTOP"));
203 
204  // Get column pointers
205  const GFitsTableCol* ptr_earth = (*ephem)["EARTH"]; // light seconds
206  const GFitsTableCol* ptr_sun = (*ephem)["SUN"]; // light seconds
207  const GFitsTableCol* ptr_tbd2tt = (*ephem)["TIMEDIFF"]; // sec
208 
209  // Extract data
210  for (int i = 0; i < num; ++i) {
211 
212  // Set time
213  GTime time;
214  time.jd(tstart + double(i));
215 
216  // Set vectors
217  GVector earth(ptr_earth->real(i,0),
218  ptr_earth->real(i,1),
219  ptr_earth->real(i,2));
220  GVector earth_dt(ptr_earth->real(i,3),
221  ptr_earth->real(i,4),
222  ptr_earth->real(i,5));
223  GVector earth_d2t(ptr_earth->real(i,6),
224  ptr_earth->real(i,7),
225  ptr_earth->real(i,8));
226  GVector earth_d3t(ptr_earth->real(i,9),
227  ptr_earth->real(i,10),
228  ptr_earth->real(i,11));
229  GVector sun(ptr_sun->real(i,0),
230  ptr_sun->real(i,1),
231  ptr_sun->real(i,2));
232 
233  // Set tbd2tt
234  double tbd2tt = ptr_tbd2tt->real(i);
235 
236  // Push back data
237  m_times.push_back(time);
238  m_earth.push_back(earth);
239  m_earth_dt.push_back(earth_dt);
240  m_earth_d2t.push_back(earth_d2t);
241  m_earth_d3t.push_back(earth_d3t);
242  m_sun.push_back(sun);
243  m_tdb2tt.push_back(tbd2tt);
244 
245  } // endfor: looped over rows
246 
247  // Store attributes
248  m_name = ephem->string("NAME");
249  m_filename = filename;
250 
251  } // endif: there were ephemerides to load
252 
253  // Return
254  return;
255 }
256 
257 
258 /***********************************************************************//**
259  * @brief Get ephemeris vector and TBD->TT value for a given time
260  *
261  * @param[in] time Time.
262  * @param[out] rce Pointer to vector from SSBC to Earth (light-s).
263  * @param[out] rcs Pointer to vector from SSBC to Sun (light-s).
264  * @param[out] vce Pointer to first time derivative of vector from SSBC to
265  * Earth (light-s/s).
266  * @param[out] etut Time difference TDB-TT (s)
267  *
268  * Get ephemeris vector and TBD-TT value for a given time. Information is
269  * only returned for pointers that are not NULL.
270  *
271  * The code was inspired from the ftools routine xtereadeph.f and the COMPASS
272  * routine bvceph.f.
273  ***************************************************************************/
275  GVector* rce,
276  GVector* rcs,
277  GVector* vce,
278  double* etut) const
279 {
280  // Fetch ephemerides
281  const_cast<GEphemerides*>(this)->fetch_data();
282 
283  // Compute jd_utc as int
284  double jd = time.jd("UTC");
285  int jd_utc = int(jd);
286 
287  // Compute dt in TT as day fraction, between -0.5 and 0.5. While the
288  // time system in the xtereadeph.f routine is not specified, the
289  // bvceph.f routine explicitly adds the UTC->TT conversion coefficient
290  // to the delta
291  //double dt = jd - double(jd_utc);
292  double dt = time.jd("TT") - double(int(time.jd("TT")));
293  if (dt > 0.5) {
294  jd_utc += 1;
295  dt -= 1.0;
296  }
297 
298  // Get Julian Day validity interval as int
299  int jd0 = int(m_tstart.jd());
300  int jd1 = int(m_tstop.jd());
301 
302  // If date is outside range of ephemeris then throw an exception
303  if (jd_utc < jd0) {
304  std::string msg = "Time JD "+gammalib::str(jd_utc)+ " is before "
305  "validity start JD "+gammalib::str(jd0)+" of "
306  "ephemerides. Please specify a time later than "
307  "the validity start.";
309  }
310  else if (jd_utc > jd1) {
311  std::string msg = "Time JD "+gammalib::str(jd_utc)+ " is after "
312  "validity end JD "+gammalib::str(jd1)+" of "
313  "ephemerides. Please specify a time earlier than "
314  "the validity end.";
316  }
317 
318  // Compute ephemeris index
319  int index = jd_utc - jd0;
320 
321  // Make rough computation of time derivative of TDB-TDT
322  double tbd2tt_dot = (index+1 < size()) ? m_tdb2tt[index+1] - m_tdb2tt[index]
323  : m_tdb2tt[index] - m_tdb2tt[index-1];
324 
325  // Get Earth position and velocity vector at the desired time using
326  // Taylor expansion
327  const double c1 = 1.0/2.0;
328  const double c2 = 1.0/6.0;
329  if (rce != NULL) {
330  *rce = m_earth[index] + (m_earth_dt[index] + (m_earth_d2t[index] *
331  c1 + m_earth_d3t[index] * dt * c2) * dt) * dt;
332  }
333  if (vce != NULL) {
334  *vce = (m_earth_dt[index] + (m_earth_d2t[index] + m_earth_d3t[index] *
335  dt * c1)) * dt * gammalib::sec2day;
336  }
337 
338  // Get Sun vector
339  if (rcs != NULL) {
340  *rcs = m_sun[index];
341  }
342 
343  // Get TBD-TT (seconds)
344  if (etut != NULL) {
345  *etut = m_tdb2tt[index] + dt * tbd2tt_dot;
346  }
347 
348  // Return
349  return;
350 }
351 
352 
353 /***********************************************************************//**
354  * @brief Get time difference between geocentric and SSB (seconds)
355  *
356  * @param[in] srcdir Source direction.
357  * @param[in] time Geocentric time.
358  * @return Time difference in seconds.
359  ***************************************************************************/
360 double GEphemerides::geo2ssb(const GSkyDir& srcdir, const GTime& time) const
361 {
362  // Set constants
363  const double t_sun = 4.92549089483e-6; // s
364  const double r_sun = 2.315; // light s
365 
366  // Get ephemerides
367  GVector rce(3);
368  GVector rcs(3);
369  GVector vce(3);
370  double etut;
371  ephemeris(time, &rce, &rcs, &vce, &etut);
372 
373  // Get sky direction as celestial vector
374  GVector dir = srcdir.celvector();
375 
376  // Calculate light-travel time to barycenter in Euclidean space
377  double light_travel_time = dir * rce;
378 
379  // Now calculate the time delay due to the gravitational field of the
380  // Sun (I.I. Shapiro, Phys. Rev. Lett. 13, 789 (1964))
381  GVector rsa = rce - rcs;
382  double sundis = norm(rsa);
383  //double sunsiz = r_sun/sundis;
384  double cos_theta = (dir * rsa) / sundis;
385 
386  // Special handling if sky direction is inside the Sun
387  /*
388  if (cth + 1.0 < 0.5 * sunsiz * sunsiz) {
389 
390  }
391  */
392 
393  // Compute Shapiro delay
394  double shapiro_delay = -2.0 * t_sun * std::log(1.0 + cos_theta);
395 
396  // Compute time difference between geocentric and Solar System Barycentric
397  // frame
398  double geo2ssb = light_travel_time - shapiro_delay + etut;
399 
400  // Return barycentric correction (seconds)
401  return geo2ssb;
402 }
403 
404 
405 /***********************************************************************//**
406  * @brief Get time difference between observatory and SSB (seconds)
407  *
408  * @param[in] srcdir Source direction.
409  * @param[in] time Geocentric time.
410  * @param[in] obs Observatory vector (km).
411  * @return Time difference in seconds.
412  *
413  * Computes the time difference between the location of an observatory,
414  * specified by an observatory position vector @p obs in units of km, and the
415  * Solar System Barycentre.
416  ***************************************************************************/
417 double GEphemerides::geo2ssb(const GSkyDir& srcdir,
418  const GTime& time,
419  const GVector& obs) const
420 {
421  // Set constants
422  const double t_sun = 4.92549089483e-6; // s
423  const double r_sun = 2.315; // light s
424  const double inv_c = 1000.0 / gammalib::speed_of_light; // s/km
425 
426  // Get ephemerides
427  GVector rce(3);
428  GVector rcs(3);
429  GVector vce(3);
430  double etut;
431  ephemeris(time, &rce, &rcs, &vce, &etut);
432 
433  // Compute vector from Solar System Barycentre to observatory
434  GVector rca = rce + obs * inv_c;
435 
436  // Get sky direction as celestial vector
437  GVector dir = srcdir.celvector();
438 
439  // Calculate light-travel time to barycenter in Euclidean space
440  double light_travel_time = dir * rca;
441 
442  // Now calculate the time delay due to the gravitational field of the
443  // Sun (I.I. Shapiro, Phys. Rev. Lett. 13, 789 (1964))
444  GVector rsa = rca - rcs;
445  double sundis = norm(rsa);
446  //double sunsiz = r_sun / sundis;
447  double cos_theta = (dir * rsa) / sundis;
448 
449  // Special handling if sky direction is inside the Sun
450  /*
451  if (cth + 1.0 < 0.5 * sunsiz * sunsiz) {
452 
453  }
454  */
455 
456  // Compute Shapiro delay
457  double shapiro_delay = -2.0 * t_sun * std::log(1.0 + cos_theta);
458 
459  // Compute time difference between geocentric and Solar System Barycentric
460  // frame
461  double geo2ssb = light_travel_time - shapiro_delay + etut;
462 
463  // Return barycentric correction (seconds)
464  return geo2ssb;
465 }
466 
467 
468 /***********************************************************************//**
469  * @brief Print Ephemerides
470  *
471  * @param[in] chatter Chattiness.
472  * @return String containing Ephemerides information.
473  ***************************************************************************/
474 std::string GEphemerides::print(const GChatter& chatter) const
475 {
476  // Initialise result string
477  std::string result;
478 
479  // Continue only if chatter is not silent
480  if (chatter != SILENT) {
481 
482  // Append header
483  result.append("=== GEphemerides ===");
484 
485  // Append information
486  result.append("\n"+gammalib::parformat("Ephemerides name"));
487  result.append(m_name);
488  result.append("\n"+gammalib::parformat("File name"));
489  result.append(m_filename.url());
490  if (!is_empty()) {
491  result.append("\n"+gammalib::parformat("Validity MJD range"));
492  result.append(gammalib::str(m_tstart.mjd()));
493  result.append(" - ");
494  result.append(gammalib::str(m_tstop.mjd()));
495  result.append("\n"+gammalib::parformat("Validity UTC range"));
496  result.append(m_tstart.utc());
497  result.append(" - ");
498  result.append(m_tstop.utc());
499  }
500 
501  } // endif: chatter was not silent
502 
503  // Return result
504  return result;
505 }
506 
507 
508 /*==========================================================================
509  = =
510  = Private methods =
511  = =
512  ==========================================================================*/
513 
514 /***********************************************************************//**
515  * @brief Initialise class members
516  ***************************************************************************/
518 {
519  // Initialise members
520  m_name.clear();
521  m_filename.clear();
522  m_tstart.clear();
523  m_tstop.clear();
524  m_times.clear();
525  m_earth.clear();
526  m_earth_dt.clear();
527  m_earth_d2t.clear();
528  m_earth_d3t.clear();
529  m_sun.clear();
530  m_tdb2tt.clear();
531 
532  // Return
533  return;
534 }
535 
536 
537 /***********************************************************************//**
538  * @brief Copy class members
539  *
540  * @param[in] ephemerides Ephemerides.
541  ***************************************************************************/
542 void GEphemerides::copy_members(const GEphemerides& ephemerides)
543 {
544  // Copy members
545  m_name = ephemerides.m_name;
546  m_filename = ephemerides.m_filename;
547  m_tstart = ephemerides.m_tstart;
548  m_tstop = ephemerides.m_tstop;
549  m_times = ephemerides.m_times;
550  m_earth = ephemerides.m_earth;
551  m_earth_dt = ephemerides.m_earth_dt;
552  m_earth_d2t = ephemerides.m_earth_d2t;
553  m_earth_d3t = ephemerides.m_earth_d3t;
554  m_sun = ephemerides.m_sun;
555  m_tdb2tt = ephemerides.m_tdb2tt;
556 
557  // Return
558  return;
559 }
560 
561 
562 /***********************************************************************//**
563  * @brief Delete class members
564  ***************************************************************************/
566 {
567  // Return
568  return;
569 }
570 
571 
572 /***********************************************************************//**
573  * @brief Fetch ephemerides data
574  *
575  * @exception GException::file_error
576  * Ephemerides data file not found.
577  *
578  * This method loads the DE200 ephemerides data from the file provided in
579  * the reference data repository if no ephemerides are loaded.
580  ***************************************************************************/
582 {
583  // If no ephemerides data are loaded then load the JPL DE200 ephemerides
584  if (is_empty()) {
585 
586  // Initialise filename
587  GFilename filename("$GAMMALIB/share/refdata/ephem_jpl_de200.fits");
588 
589  // If file exists then load ephemerides
590  if (filename.is_fits()) {
591  load(filename);
592  }
593 
594  // ... otherwise the file may not yet be installed, possibly because
595  // a unit test is performed. Therefore try to get file in the source
596  // directory.
597  else {
598 
599  // Initialise filename based on source directory
600  GFilename src_filename("$TEST_SRCDIR/refdata/ephem_jpl_de200.fits");
601 
602  // If file exists then load ephemerides
603  if (src_filename.is_fits()) {
604  load(src_filename);
605  }
606 
607  // ... otherwise throw an exception
608  else {
609  std::string msg = "Could not find ephemerides file in \""+
610  filename.url()+"\" or in \""+
611  src_filename.url()+"\". Unable to return "
612  "information based on ephemerides.";
614  }
615 
616  } // endelse: check for file in source directory
617 
618  } // endif: no data were loaded
619 
620  // Return
621  return;
622 }
GFilename m_filename
Ephemerides filename.
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:482
void copy_members(const GEphemerides &ephemerides)
Copy class members.
double norm(const GVector &vector)
Computes vector norm.
Definition: GVector.cpp:864
Sky direction class interface definition.
std::string m_name
Ephemerides (e.g. DE200)
bool is_empty(void) const
Signals if there are no ephemerides.
void clear(void)
Clear time.
Definition: GTime.cpp:252
const double sec2day
Definition: GTools.hpp:50
Time class.
Definition: GTime.hpp:55
FITS file class.
Definition: GFits.hpp:63
FITS file class interface definition.
#define G_FETCH_DATA
FITS table column abstract base class definition.
double jd(void) const
Return time in Julian Days (TT)
Definition: GTime.cpp:284
virtual std::string print(const GChatter &chatter=NORMAL) const
Print Ephemerides.
virtual GEphemerides * clone(void) const
Clone Ephemerides.
GEphemerides & operator=(const GEphemerides &ephemerides)
Assignment operator.
double real(const std::string &keyname) const
Return card value as double precision.
Definition: GFitsHDU.hpp:423
Ephemerides class definition.
GEphemerides(void)
Void constructor.
const double speed_of_light
Definition: GTools.hpp:53
Filename class.
Definition: GFilename.hpp:62
Abstract interface for FITS table column.
double geo2ssb(const GSkyDir &srcdir, const GTime &time) const
Get time difference between geocentric and SSB (seconds)
void celvector(const GVector &vector)
Set sky direction from 3D vector in celestial coordinates.
Definition: GSkyDir.cpp:313
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
void init_members(void)
Initialise class members.
Ephemerides class.
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
virtual void clear(void)
Clear Ephemerides.
GChatter
Definition: GTypemaps.hpp:33
bool is_fits(void) const
Checks whether file is a FITS file.
Definition: GFilename.cpp:313
std::vector< GTime > m_times
Times of vectors.
void ephemeris(const GTime &time, GVector *rce, GVector *rcs, GVector *vce, double *etut) const
Get ephemeris vector and TBD-&gt;TT value for a given time.
std::vector< GVector > m_earth_dt
First derivative of Earth vectors.
void load(const GFilename &filename)
Load Ephemerides.
const int & nrows(void) const
Return number of rows in table.
Definition: GFitsTable.hpp:119
std::vector< double > m_tdb2tt
TBD to TT conversion term.
std::vector< GVector > m_earth_d3t
Third derivative of Earth vectors.
GTime m_tstop
Ephemerides validity stop time.
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
virtual ~GEphemerides(void)
Destructor.
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
virtual double real(const int &row, const int &inx=0) const =0
std::vector< GVector > m_earth
Earth vectors.
void fetch_data(void)
Fetch ephemerides data.
void free_members(void)
Delete class members.
std::string string(const std::string &keyname) const
Return card value as string.
Definition: GFitsHDU.hpp:410
#define G_EPHEMERIS
GTime m_tstart
Ephemerides validity start time.
double mjd(void) const
Return time in Modified Julian Days (TT)
Definition: GTime.cpp:320
Vector class.
Definition: GVector.hpp:46
std::vector< GVector > m_earth_d2t
Second derivative of Earth vectors.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
int size(void) const
Return number of ephemerides.
Sky direction class.
Definition: GSkyDir.hpp:62
std::vector< GVector > m_sun
Sun vectors.
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Definition: GTime.cpp:465
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
FITS table abstract base class interface definition.