GammaLib 2.0.0
Loading...
Searching...
No Matches
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
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
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
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 ***************************************************************************/
173void 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 ***************************************************************************/
360double 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 ***************************************************************************/
417double 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 ***************************************************************************/
474std::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();
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 ***************************************************************************/
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}
#define G_FETCH_DATA
#define G_EPHEMERIS
Ephemerides class definition.
FITS table column abstract base class definition.
FITS table abstract base class interface definition.
FITS file class interface definition.
Sky direction class interface definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double norm(const GVector &vector)
Computes vector norm.
Definition GVector.cpp:864
Ephemerides class.
std::vector< GVector > m_earth_dt
First derivative of Earth vectors.
GTime m_tstart
Ephemerides validity start time.
void ephemeris(const GTime &time, GVector *rce, GVector *rcs, GVector *vce, double *etut) const
Get ephemeris vector and TBD->TT value for a given time.
void free_members(void)
Delete class members.
GFilename m_filename
Ephemerides filename.
std::vector< double > m_tdb2tt
TBD to TT conversion term.
GEphemerides & operator=(const GEphemerides &ephemerides)
Assignment operator.
std::vector< GVector > m_earth_d3t
Third derivative of Earth vectors.
virtual void clear(void)
Clear Ephemerides.
std::vector< GVector > m_sun
Sun vectors.
void fetch_data(void)
Fetch ephemerides data.
virtual GEphemerides * clone(void) const
Clone Ephemerides.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print Ephemerides.
void init_members(void)
Initialise class members.
void copy_members(const GEphemerides &ephemerides)
Copy class members.
virtual ~GEphemerides(void)
Destructor.
GEphemerides(void)
Void constructor.
std::vector< GVector > m_earth_d2t
Second derivative of Earth vectors.
std::string m_name
Ephemerides (e.g. DE200)
bool is_empty(void) const
Signals if there are no ephemerides.
GTime m_tstop
Ephemerides validity stop time.
double geo2ssb(const GSkyDir &srcdir, const GTime &time) const
Get time difference between geocentric and SSB (seconds)
std::vector< GVector > m_earth
Earth vectors.
std::vector< GTime > m_times
Times of vectors.
void load(const GFilename &filename)
Load Ephemerides.
int size(void) const
Return number of ephemerides.
Filename class.
Definition GFilename.hpp:62
bool is_fits(void) const
Checks whether file is a FITS file.
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
double real(const std::string &keyname) const
Return card value as double precision.
Definition GFitsHDU.hpp:423
std::string string(const std::string &keyname) const
Return card value as string.
Definition GFitsHDU.hpp:410
Abstract interface for FITS table column.
virtual double real(const int &row, const int &inx=0) const =0
Abstract interface for FITS table.
const int & nrows(void) const
Return number of rows in table.
FITS file class.
Definition GFits.hpp:63
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
Sky direction class.
Definition GSkyDir.hpp:62
void celvector(const GVector &vector)
Set sky direction from 3D vector in celestial coordinates.
Definition GSkyDir.cpp:313
Time class.
Definition GTime.hpp:55
void clear(void)
Clear time.
Definition GTime.cpp:252
double mjd(void) const
Return time in Modified Julian Days (TT)
Definition GTime.cpp:320
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Definition GTime.cpp:465
double jd(void) const
Return time in Julian Days (TT)
Definition GTime.cpp:284
Vector class.
Definition GVector.hpp:46
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const double sec2day
Definition GTools.hpp:50
const double speed_of_light
Definition GTools.hpp:53