GammaLib 2.0.0
Loading...
Searching...
No Matches
GPulsar.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GPulsar.cpp - Pulsar 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 GPulsar.cpp
23 * @brief Pulsar class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cstdio> // std::fopen, std::fgets, std::fclose, etc...
32#include "GPulsar.hpp"
33#include "GFits.hpp"
34#include "GGti.hpp"
35#include "GEphemerides.hpp"
36#include "GFilename.hpp"
37
38/* __ Method name definitions ____________________________________________ */
39#define G_AT "GPulsarEphemeris& GPulsar::at(int&)"
40#define G_EPHEMERIS "GPulsar::ephemeris(GTime&)"
41#define G_LOAD "GPulsar::load(GFilename&, std::string&)"
42#define G_LOAD_FITS "GPulsar::load_fits(GFilename&, std::string&)"
43#define G_LOAD_INTEGRAL "GPulsar::load_integral(GFitsTable*, std::string&)"
44#define G_LOAD_FERMI "GPulsar::load_fermi(GFitsTable*, std::string&)"
45#define G_LOAD_PSRTIME "GPulsar::load_psrtime(GFilename&, std::string&)"
46#define G_LOAD_PARFILE "GPulsar::load_parfile(GFilename&)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51
52/* __ Debug definitions __________________________________________________ */
53
54
55
56/*==========================================================================
57 = =
58 = Constructors/destructors =
59 = =
60 ==========================================================================*/
61
62/***********************************************************************//**
63 * @brief Void constructor
64 ***************************************************************************/
66{
67 // Initialise class members
69
70 // Return
71 return;
72}
73
74
75/***********************************************************************//**
76 * @brief Filename constructor
77 *
78 * @param[in] filename File name of pulsar ephemerides
79 * @param[in] name Pulsar name
80 *
81 * Constructs a pulsar from an ephemerides file. In case that several pulsars
82 * are present in the specified ephemerides file the name of the pulsar that
83 * should be constructed is to be specified.
84 ***************************************************************************/
85GPulsar::GPulsar(const GFilename& filename, const std::string& name)
86{
87 // Initialise class members
89
90 // Load pulsar ephemerides
91 load(filename, name);
92
93 // Return
94 return;
95}
96
97
98/***********************************************************************//**
99 * @brief Copy constructor
100 *
101 * @param[in] pulsar Pulsar.
102 ***************************************************************************/
104{
105 // Initialise class members
106 init_members();
107
108 // Copy members
109 copy_members(pulsar);
110
111 // Return
112 return;
113}
114
115
116/***********************************************************************//**
117 * @brief Destructor
118 ***************************************************************************/
120{
121 // Free members
122 free_members();
123
124 // Return
125 return;
126}
127
128
129/*==========================================================================
130 = =
131 = Operators =
132 = =
133 ==========================================================================*/
134
135/***********************************************************************//**
136 * @brief Assignment operator
137 *
138 * @param[in] pulsar Pulsar.
139 * @return Pulsar.
140 ***************************************************************************/
142{
143 // Execute only if object is not identical
144 if (this != &pulsar) {
145
146 // Free members
147 free_members();
148
149 // Initialise private members
150 init_members();
151
152 // Copy members
153 copy_members(pulsar);
154
155 } // endif: object was not identical
156
157 // Return this object
158 return *this;
159}
160
161
162/*==========================================================================
163 = =
164 = Public methods =
165 = =
166 ==========================================================================*/
167
168/***********************************************************************//**
169 * @brief Clear Pulsar
170 ***************************************************************************/
172{
173 // Free members
174 free_members();
175
176 // Initialise private members
177 init_members();
178
179 // Return
180 return;
181}
182
183
184/***********************************************************************//**
185 * @brief Clone Pulsar
186 *
187 * @return Pointer to deep copy of Pulsar.
188 ***************************************************************************/
190{
191 return new GPulsar(*this);
192}
193
194/***********************************************************************//**
195 * @brief Return reference to ephemeris
196 *
197 * @param[in] index Ephemeris index [0,...,size()-1].
198 *
199 * @exception GException::out_of_range
200 * Ephemeris index is out of range.
201 *
202 * Returns a reference to the ephemeris with the specified @p index.
203 ***************************************************************************/
205{
206 // Compile option: raise an exception if index is out of range
207 #if defined(G_RANGE_CHECK)
208 if (index < 0 || index >= size()) {
209 throw GException::out_of_range(G_AT, "Ephemeris index", index, size());
210 }
211 #endif
212
213 // Return reference
214 return (m_ephemerides[index]);
215}
216
217
218/***********************************************************************//**
219 * @brief Return reference to ephemeris (const version)
220 *
221 * @param[in] index Ephemeris index [0,...,size()-1].
222 *
223 * @exception GException::out_of_range
224 * Ephemeris index is out of range.
225 *
226 * Returns a const reference to the ephemeris with the specified @p index.
227 ***************************************************************************/
228const GPulsarEphemeris& GPulsar::at(const int& index) const
229{
230 // Compile option: raise an exception if index is out of range
231 #if defined(G_RANGE_CHECK)
232 if (index < 0 || index >= size()) {
233 throw GException::out_of_range(G_AT, "Ephemeris index", index, size());
234 }
235 #endif
236
237 // Return reference
238 return (m_ephemerides[index]);
239}
240
241
242/***********************************************************************//**
243 * @brief Return pulsar ephemeris
244 *
245 * param[in] time Time.
246 * @return Pulsar ephemeris.
247 *
248 * @exception GException::invalid_argument
249 * No valid ephemeris found for specified @p time.
250 *
251 * Returns the pulsar ephemeris as function of time.
252 ***************************************************************************/
254{
255 // Find appropriate ephemerides
256 int ifound = -1;
257 for (int i = 0; i < size(); ++i) {
258 if (time >= m_ephemerides[i].tstart() &&
259 time <= m_ephemerides[i].tstop()) {
260 ifound = i;
261 break;
262 }
263 }
264
265 // Throw an expection if no valid ephemerides were found
266 if (ifound == -1) {
267 std::string msg = "No valid ephemeris found for MJD "+
268 gammalib::str(time.mjd())+". Please specify "
269 "ephemerides that comprise the time.";
271 }
272
273 // Return ephemerides
274 return (m_ephemerides[ifound]);
275}
276
277
278/***********************************************************************//**
279 * @brief Return validity intervals of pulsar ephemerides
280 *
281 * @return Validity intervals of pulsar ephemerides.
282 *
283 * Returns the validity intervals of pulsar ephemerides as Good Time
284 * Intervals.
285 ***************************************************************************/
287{
288 // Initialise Good Time Intervals
289 GGti gti;
290
291 // Loop over ephemerides
292 for (int i = 0; i < size(); ++i) {
293 gti.append(m_ephemerides[i].tstart(), m_ephemerides[i].tstop());
294 }
295
296 // Return Good Time Intervals
297 return gti;
298}
299
300
301/***********************************************************************//**
302 * @brief Load Pulsar from ephemerides file
303 *
304 * @param[in] filename File name of pulsar ephemerides
305 * @param[in] name Pulsar name
306 *
307 * @exception GException::file_error
308 * Could not open specified file as an ASCII file
309 *
310 * Load a pulsar from an ephemerides file. In case that several pulsars are
311 * present in the specified ephemerides file the name of the pulsar that
312 * should be constructed is to be specified.
313 ***************************************************************************/
314void GPulsar::load(const GFilename& filename, const std::string& name)
315{
316 // Clear pulsar
317 clear();
318
319 // If filename is a FITS file then load ephemerides from a FITS file
320 if (filename.is_fits()) {
321 load_fits(filename, name);
322 }
323
324 // ... otherwise we expect that file is an ASCII file and we dispatch
325 // according to ASCII file content
326 else {
327
328 // Allocate line buffer
329 const int n = 1000;
330 char line[n];
331
332 // Open file as ASCII file
333 FILE* fptr = std::fopen(filename.url().c_str(), "r");
334 if (fptr == NULL) {
335 std::string msg = "Pulsar ephemerides file \""+filename.url()+
336 "\" not found or readable. Please specify a "
337 "valid and readable ephemerides file.";
338 throw GException::file_error(G_LOAD, msg);
339 }
340
341 // Read first line in buffer
342 if (std::fgets(line, n, fptr) != NULL) {
343
344 // Close file as we don't need it anymore
345 std::fclose(fptr);
346
347 // Split line in elements
348 std::vector<std::string> elements = gammalib::split(line, " ");
349
350 // If there are many elements in line we deal with a file in
351 // psrtime format
352 if (elements.size() > 10) {
353 load_psrtime(filename, name);
354 }
355
356 // ... otherwise we deal with a tempo2 par file
357 else {
358 load_parfile(filename);
359 }
360
361 } // endif: there was a line in the file
362
363 // ... otherwise the file was empty and we simply close it
364 else {
365 std::fclose(fptr);
366 }
367
368 } // endelse: handled ASCII files
369
370 // Return
371 return;
372}
373
374
375/***********************************************************************//**
376 * @brief Print Pulsar
377 *
378 * @param[in] chatter Chattiness.
379 * @return String containing Pulsar information.
380 ***************************************************************************/
381std::string GPulsar::print(const GChatter& chatter) const
382{
383 // Initialise result string
384 std::string result;
385
386 // Continue only if chatter is not silent
387 if (chatter != SILENT) {
388
389 // Get ephemerides validity interval
390 GGti gti = validity();
391
392 // Append header
393 result.append("=== GPulsar ===");
394
395 // Append information
396 result.append("\n"+gammalib::parformat("Pulsar name"));
397 result.append(m_name);
398 result.append("\n"+gammalib::parformat("Number of ephemerides"));
399 result.append(gammalib::str(m_ephemerides.size()));
400 if (!is_empty()) {
401 result.append("\n"+gammalib::parformat("Validity MJD range"));
402 result.append(gammalib::str(gti.tstart().mjd()));
403 result.append(" - ");
404 result.append(gammalib::str(gti.tstop().mjd()));
405 result.append("\n"+gammalib::parformat("Validity UTC range"));
406 result.append(gti.tstart().utc());
407 result.append(" - ");
408 result.append(gti.tstop().utc());
409 }
410
411 // EXPLICIT: Append ephemerides
412 if (chatter >= EXPLICIT) {
413 for (int i = 0; i < m_ephemerides.size(); ++i) {
414 result.append("\n"+m_ephemerides[i].print());
415 }
416 }
417
418 } // endif: chatter was not silent
419
420 // Return result
421 return result;
422}
423
424
425/*==========================================================================
426 = =
427 = Private methods =
428 = =
429 ==========================================================================*/
430
431/***********************************************************************//**
432 * @brief Initialise class members
433 ***************************************************************************/
435{
436 // Initialise members
437 m_name.clear();
438 m_ephemerides.clear();
439
440 // Return
441 return;
442}
443
444
445/***********************************************************************//**
446 * @brief Copy class members
447 *
448 * @param[in] pulsar Pulsar.
449 ***************************************************************************/
451{
452 // Copy members
453 m_name = pulsar.m_name;
455
456 // Return
457 return;
458}
459
460
461/***********************************************************************//**
462 * @brief Delete class members
463 ***************************************************************************/
465{
466 // Return
467 return;
468}
469
470
471/***********************************************************************//**
472 * @brief Load Pulsar from ephemerides FITS file
473 *
474 * @param[in] filename Name of pulsar ephemerides FITS file
475 * @param[in] name Pulsar name
476 *
477 * @exception GException::file_error
478 * FITS file format not recognised
479 *
480 * Load a pulsar from an ephemerides FITS file. In case that several pulsars
481 * are present in the specified ephemerides file the name of the pulsar that
482 * should be constructed is to be specified.
483 ***************************************************************************/
484void GPulsar::load_fits(const GFilename& filename, const std::string& name)
485{
486 // Open FITS file
487 GFits fits(filename);
488
489 // If FITS file is an INTEGRAL file then load ephemerides from INTEGRAL
490 // FITS table
491 if (fits.contains("GNRL-EPHE-CAT")) {
492 const GFitsTable* table = fits.table("GNRL-EPHE-CAT");
493 load_integral(table, name);
494 }
495
496 // ... otherwise if FITS file is a Fermi D4 file then load ephemerides
497 // from Fermi D4 table
498 else if (fits.contains("SPIN_PARAMETERS")) {
499 const GFitsTable* table = fits.table("SPIN_PARAMETERS");
500 load_fermi(table, name);
501 }
502
503 // ... otherwise signal that the FITS file was not recognised
504 else {
505 std::string msg = "Could not recognised format of FITS file \""+
506 filename.url()+"\". Please specify either an "
507 "INTEGRAL or a D4 Fermi file.";
509 }
510
511 // Return
512 return;
513}
514
515
516/***********************************************************************//**
517 * @brief Load Pulsar from INTEGRAL ephemerides FITS table
518 *
519 * @param[in] table INTEGRAL ephemerides FITS table
520 * @param[in] name Pulsar name
521 *
522 * @exception GException::invalid_argument
523 * Specified pulsar name not found in FITS table
524 *
525 * Load a pulsar from INTEGRAL ephemerides FITS table. In the INTEGRAL format
526 * only a single pulsar will be present in the FITS file, specified by
527 * the SOURCEID keyword.
528 ***************************************************************************/
529void GPulsar::load_integral(const GFitsTable* table, const std::string& name)
530{
531 // Get pulsar attributes from FITS table
532 m_name = table->string("SOURCEID");
533 double ra = table->real("RA_OBJ");
534 double dec = table->real("DEC_OBJ");
535
536 // Check name if provided
537 if (!name.empty()) {
538 if (name != m_name) {
539 std::string msg = "Pulsar \""+m_name+"\" found in ephemerides "
540 "file yet pulsar \""+name+"\" was requested. "
541 "Please check the requested pulsar name.";
543 }
544 }
545
546 // Set sky direction
547 GSkyDir dir;
548 dir.radec_deg(ra, dec);
549
550 // Get pointers to table columns
551 const GFitsTableCol* col_mjdstart = (*table)["MJDSTART"];
552 const GFitsTableCol* col_mjdstop = (*table)["MJDSTOP"];
553 const GFitsTableCol* col_tref0 = (*table)["TREF0"];
554 const GFitsTableCol* col_t2peak = (*table)["T2PEAK"];
555 const GFitsTableCol* col_f0 = (*table)["F0"];
556 const GFitsTableCol* col_f1 = (*table)["FDOT0"];
557 const GFitsTableCol* col_f2 = (*table)["FDOTDOT0"];
558
559 // Extract ephemerides
560 for (int i = 0; i < col_mjdstart->nrows(); ++i) {
561
562 // Set validity interval
563 GTime tstart;
564 GTime tstop;
565 tstart.mjd(col_mjdstart->real(i));
566 tstop.mjd(col_mjdstop->real(i));
567
568 // Set t0. The interpretation of the FITS table information has been
569 // validated by inspecting the code in the INTEGRAL OSA task
570 // spi_phase_hist and specifically the file spi_phase_hist.cpp which
571 // defines the Ephem::load method that loads an ephemeris from a
572 // GNRL-EPHE-CAT extension. The computation of a pulsar phase from
573 // ephemeris data is implemented in Evt::phase, confirming that
574 // T2PEAK is to be added to TREF0 to define the pulsar reference
575 // time. The original code is
576 //
577 // double deltaT = 86400.0 * ( _orbi - ephem.tref0 ) - ephem.t2peak0;
578 //
579 // taking into account that tref0 is given in days and t2peak0 is
580 // given in seconds. _orbi is the time in days in the above code.
581 GTime t0;
582 t0.mjd(double(int(col_tref0->real(i))));
583 //t0 += col_t2peak->real(i);
584
585 // Get frequency and derivatives
586 double f0 = col_f0->real(i);
587 double f1 = col_f1->real(i);
588 double f2 = col_f2->real(i);
589
590 // Compute phase of first pulse
591 const double c1 = 1.0/2.0;
592 const double c2 = 1.0/6.0;
593 double dt = col_t2peak->real(i);
594 double phase = -((f0 + (f1 * c1 + f2 * dt * c2) * dt) * dt);
595 phase -= floor(phase);
596
597 // Allocate ephemeris
599
600 // Set attributes
602 ephemeris.dir(dir);
603 ephemeris.tstart(tstart);
604 ephemeris.tstop(tstop);
605 ephemeris.t0(t0);
606 ephemeris.phase(phase);
607 ephemeris.f0(f0);
608 ephemeris.f1(f1);
609 ephemeris.f2(f2);
610
611 // Push back ephemeris
612 m_ephemerides.push_back(ephemeris);
613
614 } // endfor: looped over ephemerides
615
616 // Return
617 return;
618}
619
620
621/***********************************************************************//**
622 * @brief Load Pulsar from Fermi ephemerides FITS table
623 *
624 * @param[in] table Fermi ephemerides FITS table
625 * @param[in] name Pulsar name
626 *
627 * @exception GException::invalid_argument
628 * Specified pulsar name not found in FITS table
629 *
630 * Load a pulsar from Fermi ephemerides FITS table.
631 ***************************************************************************/
632void GPulsar::load_fermi(const GFitsTable* table, const std::string& name)
633{
634 // Get pointers to table columns
635 const GFitsTableCol* col_psrname = (*table)["PSRNAME"];
636 const GFitsTableCol* col_ra = (*table)["RA"];
637 const GFitsTableCol* col_dec = (*table)["DEC"];
638 const GFitsTableCol* col_valid_since = (*table)["VALID_SINCE"];
639 const GFitsTableCol* col_valid_until = (*table)["VALID_UNTIL"];
640 const GFitsTableCol* col_toabary_int = (*table)["TOABARY_INT"];
641 const GFitsTableCol* col_toabary_frac = (*table)["TOABARY_FRAC"];
642 const GFitsTableCol* col_f0 = (*table)["F0"];
643 const GFitsTableCol* col_f1 = (*table)["F1"];
644 const GFitsTableCol* col_f2 = (*table)["F2"];
645
646 // Extract ephemerides
647 for (int i = 0; i < col_psrname->nrows(); ++i) {
648
649 // Skip if pulsar name does not correspond to specified name
650 if (col_psrname->string(i) != name) {
651 continue;
652 }
653
654 // Save the pulsar name
655 m_name = col_psrname->string(i);
656
657 // Set sky direction
658 GSkyDir dir;
659 dir.radec_deg(col_ra->real(i), col_dec->real(i));
660
661 // Set validity interval
662 GTime tstart;
663 GTime tstop;
664 tstart.mjd(col_valid_since->real(i));
665 tstop.mjd(col_valid_until->real(i));
666
667 // Set t0
668 GTime t0;
669 //t0.mjd(col_toabary_int->integer(i)+col_toabary_frac->real(i));
670 t0.mjd(double(col_toabary_int->integer(i)));
671
672 // Get frequency and derivatives
673 double f0 = col_f0->real(i);
674 double f1 = col_f1->real(i);
675 double f2 = col_f2->real(i);
676
677 // Compute phase of first pulse
678 const double c1 = 1.0/2.0;
679 const double c2 = 1.0/6.0;
680 double dt = col_toabary_frac->real(i) * gammalib::sec_in_day;
681 double phase = -((f0 + (f1 * c1 + f2 * dt * c2) * dt) * dt);
682 phase -= floor(phase);
683
684 // Allocate ephemeris
686
687 // Set attributes
689 ephemeris.dir(dir);
690 ephemeris.tstart(tstart);
691 ephemeris.tstop(tstop);
692 ephemeris.t0(t0);
693 ephemeris.phase(phase);
694 ephemeris.f0(f0);
695 ephemeris.f1(f1);
696 ephemeris.f2(f2);
697
698 // Push back ephemeris
699 m_ephemerides.push_back(ephemeris);
700
701 } // endfor: looped over ephemerides
702
703 // Signal if no pulsar was found
704 if (m_ephemerides.empty()) {
705 if (name.empty()) {
706 std::string msg = "No pulsar name was specified. Please specify "
707 "the name of the pulsar for which ephemerides "
708 "should be extracted from the file.";
710 }
711 else {
712 std::string msg = "No pulsar \""+name+"\" found in ephemerides "
713 "file. Please check the specified file or the "
714 "requested pulsar name.";
716 }
717 }
718
719 // Return
720 return;
721}
722
723
724/***********************************************************************//**
725 * @brief Load Pulsar from ephemerides psrtime file
726 *
727 * @param[in] filename Name of pulsar ephemerides psrtime file
728 * @param[in] name Pulsar name
729 *
730 * @exception GException::file_error
731 * Could not open ephemerides ASCII file
732 * @exception GException::invalid_argument
733 * No pulsar name specified for a file that contains multiple
734 * pulsars
735 *
736 * Load a pulsar from an ephemerides psrtime file. In case that several
737 * pulsars are present in the specified ephemerides file the name of the
738 * pulsar that should be constructed is to be specified.
739 ***************************************************************************/
740void GPulsar::load_psrtime(const GFilename& filename, const std::string& name)
741{
742 // Allocate line buffer
743 const int n = 1000;
744 char line[n];
745
746 // Initialise ephemerides
747 GEphemerides ephemerides;
748
749 // Open file
750 FILE* fptr = std::fopen(filename.url().c_str(), "r");
751 if (fptr == NULL) {
752 std::string msg = "Pulsar ephemerides file \""+filename.url()+
753 "\" not found or readable. Please specify a "
754 "valid and readable ephemerides file.";
756 }
757
758 // Initialise used pulsar name
759 std::string psrname;
760
761 // Read lines
762 while (std::fgets(line, n, fptr) != NULL) {
763
764 // Split line in elements
765 std::vector<std::string> elements = gammalib::split(line, " ");
766
767 // Get pulsar name
768 std::string psrb = elements[0];
769
770 // Skip if pulsar name does not correspond to specified name
771 if (!name.empty()) {
772 std::string psrb_alt = "PSR B" + psrb;
773 if ((psrb != name) && (psrb_alt != name)) {
774 continue;
775 }
776 }
777
778 // ... otherwise if no pulsar name was specified then check
779 // that the file only contains a single pulsar name
780 else {
781 if (!psrname.empty() && (psrb != psrname)) {
782 std::string msg = "Pulsar ephemerides file \""+filename.url()+
783 "\" contains several pulsar but not pulsar "
784 "name was specified. Please specify for which "
785 "pulsar you want to load ephemerides.";
787 }
788 }
789
790 // Save the pulsar name
791 psrname = psrb;
792 m_name = "PSR B" + psrb;
793
794 // Convert elements in attributes
795 double ra_h = gammalib::todouble(elements[1]);
796 double ra_m = gammalib::todouble(elements[2]);
797 double ra_s = gammalib::todouble(elements[3]);
798 double dec_d = gammalib::todouble(elements[4]);
799 double dec_m = gammalib::todouble(elements[5]);
800 double dec_s = gammalib::todouble(elements[6]);
801 double mjdstart = gammalib::todouble(elements[7]);
802 double mjdstop = gammalib::todouble(elements[8]);
803 double t0geo = gammalib::todouble(elements[9]);
804 double f0 = gammalib::todouble(gammalib::replace_segment(elements[10],"D","E"));
805 double f1 = gammalib::todouble(gammalib::replace_segment(elements[11],"D","E"));
806 double f2 = gammalib::todouble(gammalib::replace_segment(elements[12],"D","E"));
807
808 // Compute Right Ascension and Declination
809 double ra = (ra_h + ra_m/60.0 + ra_s/3600.0) * 15.0;
810 double dec = (dec_d < 0.0) ? -(-dec_d + dec_m/60.0 + dec_s/3600.0)
811 : (dec_d + dec_m/60.0 + dec_s/3600.0);
812
813 // Set sky direction
814 GSkyDir dir;
815 dir.radec_deg(ra, dec);
816
817 // Set validity interval
818 GTime tstart;
819 GTime tstop;
820 tstart.mjd(mjdstart);
821 tstop.mjd(mjdstop);
822
823 // Compute the barycentric (TDB) epoch of the spin parameters
824 double t0nom = double(int(t0geo));
825
826 // Set t0 = t0nom
827 GTime t0;
828 t0.mjd(t0nom, "UTC");
829
830 // Set infinite-frequency geocentric UTC arrival time of a pulse
831 GTime toa;
832 toa.mjd(t0geo, "UTC");
833
834 // Compute phase of first pulse according to formulae given in
835 // COM-RP-DOL-DRG-065. Note that the phase is negative, see for
836 // example Eq. (3) in Yan et al. (2017), ApJ, 845, 119
837 double geo2ssb = ephemerides.geo2ssb(dir, toa);
838 double utc2tt = toa.utc2tt();
839 double dt = (t0geo - t0nom) * gammalib::sec_in_day + geo2ssb + utc2tt;
840 const double c1 = 1.0/2.0;
841 const double c2 = 1.0/6.0;
842 double phase = ((f0 + (f1 * c1 + f2 * dt * c2) * dt) * dt);
843 phase -= floor(phase);
844
845 // Allocate ephemeris
847
848 // Set attributes
850 ephemeris.dir(dir);
851 ephemeris.tstart(tstart);
852 ephemeris.tstop(tstop);
853 ephemeris.timesys("UTC"); // psrtime ephemerides are in UTC
854 ephemeris.t0(t0);
855 ephemeris.phase(-phase);
856 ephemeris.f0(f0);
857 ephemeris.f1(f1);
858 ephemeris.f2(f2);
859
860 // Push back ephemeris
861 m_ephemerides.push_back(ephemeris);
862
863 } // endwhile: looped over lines
864
865 // Close file
866 std::fclose(fptr);
867
868 // Return
869 return;
870}
871
872
873/***********************************************************************//**
874 * @brief Load Pulsar from ephemeris par file
875 *
876 * @param[in] filename Name of pulsar ephemeris par file
877 *
878 * @exception GException::file_error
879 * Could not open ephemeris ASCII file
880 * @exception GException::invalid_argument
881 * No valid Right Ascension and Declination found
882 *
883 * Load a pulsar from an ephemeris par file.
884 ***************************************************************************/
885void GPulsar::load_parfile(const GFilename& filename)
886{
887 // Allocate line buffer
888 const int n = 1000;
889 char line[n];
890
891 // Open file
892 FILE* fptr = std::fopen(filename.url().c_str(), "r");
893 if (fptr == NULL) {
894 std::string msg = "Pulsar ephemeris file \""+filename.url()+
895 "\" not found or readable. Please specify a "
896 "valid and readable ephemeris file.";
898 }
899
900 // Allocate ephemeris
902 double ra = 9999.0;
903 double dec = 9999.0;
904
905 // Read lines
906 while (std::fgets(line, n, fptr) != NULL) {
907
908 // Split line in elements
909 std::vector<std::string> elements = gammalib::split(line, " \t");
910
911 // Find index of second non-empty element
912 int i = 1;
913 for (; i < elements.size(); ++i) {
914 if (!elements[i].empty()) {
915 break;
916 }
917 }
918 if (i >= elements.size()) {
919 continue;
920 }
921
922 // Extract keywords
923 if (elements[0] == "PSRJ") {
924 m_name = "PSR " + gammalib::rstrip_chars(elements[i], "\n");
926 }
927 else if (elements[0] == "RAJ") {
928 std::vector<std::string> ras = gammalib::split(elements[i], ":");
929 double ra_h = gammalib::todouble(ras[0]);
930 double ra_m = gammalib::todouble(ras[1]);
931 double ra_s = gammalib::todouble(ras[2]);
932 ra = (ra_h + ra_m/60.0 + ra_s/3600.0) * 15.0;
933 }
934 else if (elements[0] == "DECJ") {
935 std::vector<std::string> decs = gammalib::split(elements[i], ":");
936 double dec_d = gammalib::todouble(decs[0]);
937 double dec_m = gammalib::todouble(decs[1]);
938 double dec_s = gammalib::todouble(decs[2]);
939 dec = (dec_d < 0.0) ? -(-dec_d + dec_m/60.0 + dec_s/3600.0)
940 : (dec_d + dec_m/60.0 + dec_s/3600.0);
941 }
942 else if (elements[0] == "START") {
943 GTime tstart;
944 tstart.mjd(gammalib::todouble(elements[i]));
945 ephemeris.tstart(tstart);
946 }
947 else if (elements[0] == "FINISH") {
948 GTime tstop;
949 tstop.mjd(gammalib::todouble(elements[i]));
950 ephemeris.tstop(tstop);
951 }
952 else if (elements[0] == "PEPOCH") { // Period epoch
953 GTime t0;
954 t0.mjd(gammalib::todouble(elements[i]));
955 ephemeris.t0(t0);
956 }
957 else if (elements[0] == "F0") {
958 ephemeris.f0(gammalib::todouble(elements[i]));
959 }
960 else if (elements[0] == "F1") {
961 ephemeris.f1(gammalib::todouble(elements[i]));
962 }
963 else if (elements[0] == "F2") {
964 ephemeris.f2(gammalib::todouble(elements[i]));
965 }
966
967 } // endwhile: looped over lines
968
969 // If Right Ascension and Declination is valid then set sky direction
970 // and push back ephemeris
971 if (ra >= 0.0 && ra <= 360.0 && dec >= -90.0 && dec <= 90.0) {
972 GSkyDir dir;
973 dir.radec_deg(ra, dec);
974 ephemeris.dir(dir);
975 m_ephemerides.push_back(ephemeris);
976 }
977
978 // ... otherwise throw an exception
979 else {
980 std::string msg = "Right Ascension "+gammalib::str(ra)+
981 " or Declination "+gammalib::str(dec)+" in "
982 "pulsar ephemeris file \""+filename.url()+
983 "\" are invalid. Please verify the ephemeris file.";
985 }
986
987 // Close file
988 std::fclose(fptr);
989
990 // Return
991 return;
992}
#define G_AT
#define G_EPHEMERIS
Ephemerides class definition.
Filename class interface definition.
FITS file class interface definition.
Good time interval class interface definition.
#define G_LOAD
#define G_LOAD_PSRTIME
Definition GPulsar.cpp:45
#define G_LOAD_PARFILE
Definition GPulsar.cpp:46
#define G_LOAD_FITS
Definition GPulsar.cpp:42
#define G_LOAD_FERMI
Definition GPulsar.cpp:44
#define G_LOAD_INTEGRAL
Definition GPulsar.cpp:43
Pulsar class definition.
GChatter
Definition GTypemaps.hpp:33
@ EXPLICIT
Definition GTypemaps.hpp:37
@ SILENT
Definition GTypemaps.hpp:34
Ephemerides class.
double geo2ssb(const GSkyDir &srcdir, const GTime &time) const
Get time difference between geocentric and SSB (seconds)
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)
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 int integer(const int &row, const int &inx=0) const =0
virtual double real(const int &row, const int &inx=0) const =0
virtual std::string string(const int &row, const int &inx=0) const =0
void nrows(const int &nrows)
Set number of rows in column.
Abstract interface for FITS table.
FITS file class.
Definition GFits.hpp:63
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition GFits.hpp:282
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
Good Time Interval class.
Definition GGti.hpp:62
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition GGti.hpp:207
void append(const GTime &tstart, const GTime &tstop)
Append Good Time Interval.
Definition GGti.cpp:269
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition GGti.hpp:194
Pulsar ephemeris class.
const GTime & tstop(void) const
Returns validity stop time.
const std::string & timesys(void) const
Returns pulsar ephemeris time system.
double f0(void) const
Returns pulsar frequency (Hz)
GTime t0(void) const
Returns reference epoch of pulsar ephemeris.
double f1(void) const
Returns pulsar frequency derivative (s^-2)
const std::string & name(void) const
Returns pulsar name.
double f2(void) const
Returns pulsar second frequency derivative (s^-3)
double phase(void) const
Returns pulse phase.
const GSkyDir & dir(void) const
Returns pulsar sky direction.
const GTime & tstart(void) const
Returns validity start time.
Pulsar class.
Definition GPulsar.hpp:53
std::vector< GPulsarEphemeris > m_ephemerides
Pulsar ephemerides.
Definition GPulsar.hpp:98
virtual GPulsar * clone(void) const
Clone Pulsar.
Definition GPulsar.cpp:189
void load_fits(const GFilename &filename, const std::string &name="")
Load Pulsar from ephemerides FITS file.
Definition GPulsar.cpp:484
virtual ~GPulsar(void)
Destructor.
Definition GPulsar.cpp:119
void load_parfile(const GFilename &filename)
Load Pulsar from ephemeris par file.
Definition GPulsar.cpp:885
std::string m_name
Pulsar name.
Definition GPulsar.hpp:97
void copy_members(const GPulsar &pulsar)
Copy class members.
Definition GPulsar.cpp:450
const std::string & name(void) const
Return pulsar name.
Definition GPulsar.hpp:176
void load(const GFilename &filename, const std::string &name="")
Load Pulsar from ephemerides file.
Definition GPulsar.cpp:314
const GPulsarEphemeris & ephemeris(const GTime &time) const
Return pulsar ephemeris.
Definition GPulsar.cpp:253
void load_fermi(const GFitsTable *table, const std::string &name="")
Load Pulsar from Fermi ephemerides FITS table.
Definition GPulsar.cpp:632
virtual void clear(void)
Clear Pulsar.
Definition GPulsar.cpp:171
void init_members(void)
Initialise class members.
Definition GPulsar.cpp:434
virtual std::string print(const GChatter &chatter=NORMAL) const
Print Pulsar.
Definition GPulsar.cpp:381
GPulsar(void)
Void constructor.
Definition GPulsar.cpp:65
GPulsar & operator=(const GPulsar &pulsar)
Assignment operator.
Definition GPulsar.cpp:141
void load_integral(const GFitsTable *table, const std::string &name="")
Load Pulsar from INTEGRAL ephemerides FITS table.
Definition GPulsar.cpp:529
void free_members(void)
Delete class members.
Definition GPulsar.cpp:464
int size(void) const
Return number of ephemerides for pulsar.
Definition GPulsar.hpp:150
GPulsarEphemeris & at(const int &index)
Return reference to ephemeris.
Definition GPulsar.cpp:204
void load_psrtime(const GFilename &filename, const std::string &name="")
Load Pulsar from ephemerides psrtime file.
Definition GPulsar.cpp:740
bool is_empty(void) const
Signals if there are no ephemerides for pulsar.
Definition GPulsar.hpp:164
GGti validity(void) const
Return validity intervals of pulsar ephemerides.
Definition GPulsar.cpp:286
Sky direction class.
Definition GSkyDir.hpp:62
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition GSkyDir.cpp:224
Time class.
Definition GTime.hpp:55
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 utc2tt(void) const
Return time difference between UTC and TT (seconds)
Definition GTime.hpp:197
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
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:926
std::string replace_segment(const std::string &arg, const std::string &segment, const std::string &replacement)
Replace string segment in string.
Definition GTools.cpp:168
std::string rstrip_chars(const std::string &arg, const std::string &chars)
Strip trailing character from string.
Definition GTools.cpp:131
const double sec_in_day
Definition GTools.hpp:49
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition GTools.cpp:983