GammaLib 2.1.0.dev
Loading...
Searching...
No Matches
GSkyDir.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSkyDir.cpp - Sky direction class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2008-2024 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 GSkyDir.cpp
23 * @brief Sky direction class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cstdlib>
32#include <cmath>
33#include "GException.hpp"
34#include "GTools.hpp"
35#include "GSkyDir.hpp"
36#include "GTime.hpp"
37#include "GMatrix.hpp"
38#include "GVector.hpp"
39
40/* __ Method name definitions ____________________________________________ */
41#define G_POSANG "GSkyDir::posang(GSkyDir&, std::string&)"
42
43/* __ Macros _____________________________________________________________ */
44
45/* __ Coding definitions _________________________________________________ */
46
47/* __ Debug definitions __________________________________________________ */
48
49/* __ Prototypes _________________________________________________________ */
50
51/*==========================================================================
52 = =
53 = Constructors/destructors =
54 = =
55 ==========================================================================*/
56
57/***********************************************************************//**
58 * @brief Constructor
59 ***************************************************************************/
61{
62 // Initialise members
64
65 // Return
66 return;
67}
68
69
70/***********************************************************************//**
71 * @brief Coordinate constructor
72 *
73 * @param[in] coord Sky coordinate string.
74 *
75 * Constructs a sky direction from a sky coordinate string. See the
76 * GSkyDir::set() method for sky coordinate format and details.
77 ***************************************************************************/
78GSkyDir::GSkyDir(const std::string& coord)
79{
80 // Initialise members
82
83 // Set sky direction from coordinate string
84 set(coord);
85
86 // Return
87 return;
88}
89
90
91/***********************************************************************//**
92 * @brief Vector constructor
93 *
94 * @param[in] vector Sky vector.
95 *
96 * Constructs a sky direction from a 3-element celestial vector. See the
97 * celvector() method for more information.
98 ***************************************************************************/
100{
101 // Initialise members
102 init_members();
103
104 // Set sky direction from vector
105 celvector(vector);
106
107 // Return
108 return;
109}
110
111
112/***********************************************************************//**
113 * @brief Copy constructor
114 *
115 * @param[in] dir Sky direction.
116 ***************************************************************************/
118{
119 // Initialise members
120 init_members();
121
122 // Copy members
123 copy_members(dir);
124
125 // Return
126 return;
127}
128
129
130/***********************************************************************//**
131 * @brief Destructor
132 ***************************************************************************/
134{
135 // Free members
136 free_members();
137
138 // Return
139 return;
140}
141
142
143/*==========================================================================
144 = =
145 = Operators =
146 = =
147 ==========================================================================*/
148
149/***********************************************************************//**
150 * @brief Assignment operator
151 *
152 * @param[in] dir Sky direction.
153 * @return Sky direction.
154 ***************************************************************************/
156{
157 // Execute only if object is not identical
158 if (this != &dir) {
159
160 // Free members
161 free_members();
162
163 // Initialise members
164 init_members();
165
166 // Copy members
167 copy_members(dir);
168
169 } // endif: object was not identical
170
171 // Return this object
172 return *this;
173}
174
175
176/*==========================================================================
177 = =
178 = Public methods =
179 = =
180 ==========================================================================*/
181
182/***********************************************************************//**
183 * @brief Clear sky direction
184 ***************************************************************************/
186{
187 // Free members
188 free_members();
189
190 // Initialise members
191 init_members();
192
193 // Return
194 return;
195}
196
197
198/***********************************************************************//**
199 * @brief Clone sky direction
200 *
201 * @return Pointer to deep copy of sky direction.
202 ***************************************************************************/
204{
205 // Clone sky direction
206 return new GSkyDir(*this);
207}
208
209
210/***********************************************************************//**
211 * @brief Set equatorial sky direction (radians)
212 *
213 * @param[in] ra Right Ascension in radians.
214 * @param[in] dec Declination in radians.
215 *
216 * Sets Right Ascension and Declination in radians.
217 ***************************************************************************/
218void GSkyDir::radec(const double& ra, const double& dec)
219{
220 // Set attributes
221 m_has_lb = false;
222 m_has_radec = true;
223 #if defined(G_SINCOS_CACHE)
224 m_has_lb_cache = false;
225 m_has_radec_cache = false;
226 #endif
227
228 // Set direction
229 m_ra = ra;
230 m_dec = dec;
231
232 // Return
233 return;
234}
235
236
237/***********************************************************************//**
238 * @brief Set equatorial sky direction (degrees)
239 *
240 * @param[in] ra Right Ascension in degrees.
241 * @param[in] dec Declination in degrees.
242 *
243 * Sets Right Ascension and Declination in degrees.
244 ***************************************************************************/
245void GSkyDir::radec_deg(const double& ra, const double& dec)
246{
247 // Set attributes
248 m_has_lb = false;
249 m_has_radec = true;
250 #if defined(G_SINCOS_CACHE)
251 m_has_lb_cache = false;
252 m_has_radec_cache = false;
253 #endif
254
255 // Set direction
258
259 // Return
260 return;
261}
262
263
264/***********************************************************************//**
265 * @brief Set galactic sky direction (radians)
266 *
267 * @param[in] l Galactic longitude in radians.
268 * @param[in] b Galactic latitude in radians.
269 *
270 * Sets Galactic longitude and latitude in radians.
271 ***************************************************************************/
272void GSkyDir::lb(const double& l, const double& b)
273{
274 // Set attributes
275 m_has_lb = true;
276 m_has_radec = false;
277 #if defined(G_SINCOS_CACHE)
278 m_has_lb_cache = false;
279 m_has_radec_cache = false;
280 #endif
281
282 // Set direction
283 m_l = l;
284 m_b = b;
285
286 // Return
287 return;
288}
289
290
291/***********************************************************************//**
292 * @brief Set galactic sky direction (degrees)
293 *
294 * @param[in] l Galactic longitude in degrees.
295 * @param[in] b Galactic latitude in degrees.
296 *
297 * Sets Galactic longitude and latitude in degrees.
298 ***************************************************************************/
299void GSkyDir::lb_deg(const double& l, const double& b)
300{
301 // Set attributes
302 m_has_lb = true;
303 m_has_radec = false;
304 #if defined(G_SINCOS_CACHE)
305 m_has_lb_cache = false;
306 m_has_radec_cache = false;
307 #endif
308
309 // Set direction
312
313 // Return
314 return;
315}
316
317
318/***********************************************************************//**
319 * @brief Set sky direction from coordinate string
320 *
321 * @param[in] coord Coordinate string.
322 *
323 * Sets sky direction from coordinate string.
324 *
325 * In addition, names of a few emblematic sources are translated into
326 * a sky direction using CDS coordinates. The following names are
327 * implement (case insensitive):
328 * * "Crab" (l=184.5574843227357, b=-5.7843392171240)
329 * * "Vela" (l=263.55197071, b=-2.78725587)
330 * * "CygX-1" (l=71.3349982655144, b=3.0668346317201)
331 ***************************************************************************/
332#define G_SET "GSkyDir::set(std::string&)"
333void GSkyDir::set(const std::string& coord)
334{
335 // Convert coordinate string into upper case
336 std::string ucoord = gammalib::toupper(coord);
337
338 // Handle a few emblematic sources
339 if (ucoord == "CRAB") {
340 this->lb_deg(184.5574843227357, -5.7843392171240); // Crab pulsar location from CDS
341 }
342 else if (ucoord == "VELA") {
343 this->lb_deg(263.55197071, -2.78725587); // Vela pulsar location from CDS
344 }
345 else if ((ucoord == "CYGX-1") || (ucoord == "CYG X-1")) {
346 this->lb_deg(71.3349982655144, 3.0668346317201); // Cyg X-1 location from CDS
347 }
348
349 // ... otherwise analyse coordiate string
350 else {
351
352 // Signal galactic coordinates
353 bool galactic = gammalib::contains(ucoord, "G");
354
355 // Initialise coordinates
356 std::vector<double> coordinates;
357
358 // Extract coordinates
359 int ichar = (galactic) ? 1 : 0;
360 int istart = ichar;
361 int nchar = ucoord.length();
362 while (ichar < nchar) {
363
364 // Search first decimal digit character
365 while (ichar < nchar &&
366 isdigit(ucoord[ichar]) == 0 &&
367 ucoord[ichar] != '.' &&
368 ucoord[ichar] != '+' &&
369 ucoord[ichar] != '-') {
370 ichar++;
371 }
372
373 // Stop if end of string has been reached
374 if (ichar >= nchar) {
375 break;
376 }
377
378 // Set pointer on first decimal digit character
379 int istart = ichar;
380
381 // Search last decimal digit character and determine the number of
382 // subsequent decimal digit characters
383 ichar++;
384 while (ichar < nchar && (isdigit(ucoord[ichar]) != 0 || ucoord[ichar] == '.')) {
385 ichar++;
386 }
387
388 // Determine length of decimal value string
389 int len = ichar - istart;
390
391 // If there were decimal digit charcaters then extract them and
392 // convert them to a floating point coordinate
393 if (len > 0) {
394 coordinates.push_back(gammalib::todouble(ucoord.substr(istart, len)));
395 }
396
397 } // endwhile
398
399 // If there were 2 coordinates then assume that the position was
400 // given in degrees. If there were 6 coordinates and if the system
401 // was celestial, then assume that the position was given in
402 // hours minutes seconds degrees minutes seconds. In all other cases
403 // we signal an error ...
404 if (coordinates.size() == 2) {
405 if (galactic) {
406 this->lb_deg(coordinates[0], coordinates[1]);
407 }
408 else {
409 this->radec_deg(coordinates[0], coordinates[1]);
410 }
411 }
412 else if (coordinates.size() == 6) {
413 if (galactic) {
414 std::string msg = "Six Galactic coordinates specified in \""+
415 coord+"\" but six coordinates imply that they "
416 "are celestial. Please specify a valid "
417 "coordinate string.";
419 }
420 else {
421 double ra = coordinates[0] * 15.0 +
422 coordinates[1] * 0.25 +
423 coordinates[2] * 0.25/60.0;
424 double dec = std::abs(coordinates[3]) +
425 coordinates[4]/60.0 +
426 coordinates[5]/3600.0;
427 if (coordinates[3] < 0.0) {
428 dec = -dec;
429 }
430 this->radec_deg(ra, dec);
431 }
432 }
433 else {
434 std::string msg = "Invalid coordinate string \""+coord+"\" encountered. "
435 "Please specify a valid coordinate string.";
437 }
438
439 } // endelse: analyse coordinate string
440
441 // Return
442 return;
443}
444
445
446/***********************************************************************//**
447 * @brief Set sky direction from 3D vector in celestial coordinates
448 *
449 * @param[in] vector 3D vector.
450 *
451 * Convert a 3-dimensional vector in celestial coordinates into a sky
452 * direction. The transformation is given by
453 *
454 * \f[
455 * \alpha = \arctan \left( \frac{x_1}{x_0} \right)
456 * \f]
457 *
458 * \f[
459 * \delta = \arcsin x_2
460 * \f]
461 ***************************************************************************/
462void GSkyDir::celvector(const GVector& vector)
463{
464 // Set attributes
465 m_has_lb = false;
466 m_has_radec = true;
467 #if defined(G_SINCOS_CACHE)
468 m_has_lb_cache = false;
469 m_has_radec_cache = false;
470 #endif
471
472 // Convert vector into sky position
473 m_dec = std::asin(vector[2]);
474 m_ra = std::atan2(vector[1], vector[0]);
475
476 // Return
477 return;
478}
479
480
481/***********************************************************************//**
482 * @brief Set sky direction from 3D vector in Galactic coordinates
483 *
484 * @param[in] vector 3D vector.
485 *
486 * Convert a 3-dimensional vector in galactic coordinates into a sky
487 * direction. The transformation is given by
488 *
489 * \f[
490 * l = \arctan \left( \frac{x_1}{x_0} \right)
491 * \f]
492 *
493 * \f[
494 * b = \arcsin x_2
495 * \f]
496 ***************************************************************************/
497void GSkyDir::galvector(const GVector& vector)
498{
499 // Set attributes
500 m_has_lb = true;
501 m_has_radec = false;
502 #if defined(G_SINCOS_CACHE)
503 m_has_lb_cache = false;
504 m_has_radec_cache = false;
505 #endif
506
507 // Convert vector into sky position
508 m_b = std::asin(vector[2]);
509 m_l = std::atan2(vector[1], vector[0]);
510
511 // Return
512 return;
513}
514
515
516/***********************************************************************//**
517 * @brief Rotate sky direction by zenith and azimuth angle
518 *
519 * @param[in] phi Azimuth angle (radians).
520 * @param[in] theta Zenith angle (radians).
521 *
522 * Rotate sky direction by a zenith and azimuth angle given in the system
523 * of the sky direction and aligned in celestial coordinates.
524 * The azimuth angle is counted counter clockwise from celestial north
525 * (this is identical to the astronomical definition of a position angle).
526 ***************************************************************************/
527void GSkyDir::rotate(const double& phi, const double& theta)
528{
529 // If we have no equatorial coordinates then get them now
530 if (!m_has_radec && m_has_lb) {
531 gal2equ();
532 }
533
534 // Allocate Euler and rotation matrices
535 GMatrix ry;
536 GMatrix rz;
537
538 // Set up rotation matrix to rotate from native coordinates to
539 // celestial coordinates
540 ry.eulery(m_dec * gammalib::rad2deg - 90.0);
542 GMatrix rot = (ry * rz).transpose();
543
544 // Set up native coordinate vector
545 double cos_phi = std::cos(phi);
546 double sin_phi = std::sin(phi);
547 double cos_theta = std::cos(theta);
548 double sin_theta = std::sin(theta);
549 GVector native(-cos_phi*sin_theta, sin_phi*sin_theta, cos_theta);
550
551 // Rotate vector into celestial coordinates
552 GVector dir = rot * native;
553
554 // Convert vector into sky position
555 celvector(dir);
556
557 // Return
558 return;
559}
560
561
562/***********************************************************************//**
563 * @brief Rotate sky direction by zenith and azimuth angle
564 *
565 * @param[in] phi Azimuth angle (deg).
566 * @param[in] theta Zenith angle (deg).
567 *
568 * Rotate sky direction by a zenith and azimuth angle given in the system
569 * of the sky direction and aligned in celestial coordinates.
570 * The azimuth angle is counted counter clockwise from celestial north
571 * (this is identical to the astronomical definition of a position angle).
572 ***************************************************************************/
573void GSkyDir::rotate_deg(const double& phi, const double& theta)
574{
575 // Convert phi and theta in radians
576 double phi_rad = phi * gammalib::deg2rad;
577 double theta_rad = theta * gammalib::deg2rad;
578
579 // Rotate
580 rotate(phi_rad, theta_rad);
581
582 // Return
583 return;
584}
585
586
587/***********************************************************************//**
588 * @brief Precess sky direction
589 *
590 * @param[in] from_epoch Epoch of the current coordinate.
591 * @param[in] to_epoch Epoch of the returned precessed coordinate.
592 *
593 * Precesses the sky direction from one epoch to another.
594 *
595 * The method is adapted from a set of fortran subroutines based on
596 * (a) pages 30-34 of the Explanatory Supplement to the AE,
597 * (b) Lieske, et al. (1977) A&A 58, 1-16, and
598 * (c) Lieske (1979) A&A 73, 282-284.
599 ***************************************************************************/
600void GSkyDir::precess(const double& from_epoch, const double& to_epoch)
601{
602 // Set constants
603 const double arcsec = gammalib::pi / 180.0 / 3600.0;
604
605 // Continue only if epochs differ
606 if (from_epoch != to_epoch) {
607
608 // t0, t below correspond to Lieske's big T and little T
609 double t0 = (from_epoch - 2000.0) / 100.0;
610 double t = (to_epoch - from_epoch) / 100.0;
611 double t02 = t0*t0;
612 double t2 = t*t;
613 double t3 = t2*t;
614
615 // a,b,c below correspond to Lieske's zeta_A, z_A and theta_A
616 double a = ((2306.2181 + 1.39656 * t0 - 0.000139 * t02) * t +
617 (0.30188 - 0.000344 * t0) * t2 + 0.017998 * t3) * arcsec;
618 double b = ((2306.2181 + 1.39656 * t0 - 0.000139 * t02) * t +
619 (1.09468 + 0.000066 * t0) * t2 + 0.018203 * t3) * arcsec;
620 double c = ((2004.3109 - 0.85330 * t0 - 0.000217 * t02) * t +
621 (-0.42665 - 0.000217 * t0) * t2 - 0.041833 * t3) * arcsec;
622
623 // Compute sines and cosines
624 double sina = std::sin(a);
625 double cosa = std::cos(a);
626 double sinb = std::sin(b);
627 double cosb = std::cos(b);
628 double sinc = std::sin(c);
629 double cosc = std::cos(c);
630
631 // Setup precession rotation matrix
632 double xx = cosa*cosc*cosb - sina*sinb;
633 double yx = -sina*cosc*cosb - cosa*sinb;
634 double zx = -sinc*cosb;
635 double xy = cosa*cosc*sinb + sina*cosb;
636 double yy = -sina*cosc*sinb + cosa*cosb;
637 double zy = -sinc*sinb;
638 double xz = cosa*sinc;
639 double yz = -sina*sinc;
640 double zz = cosc;
641
642 // Get vector of sky position
643 GVector vector = celvector();
644
645 // Perform the rotation:
646 double x2 = xx*vector[0] + yx*vector[1] + zx*vector[2];
647 double y2 = xy*vector[0] + yy*vector[1] + zy*vector[2];
648 double z2 = xz*vector[0] + yz*vector[1] + zz*vector[2];
649
650 // Setup rotated vector
651 GVector rotated_vector(x2, y2, z2);
652
653 // Transform vector to sky direction
654 celvector(rotated_vector);
655
656 } // endif: epochs differed
657
658 // Return
659 return;
660}
661
662
663/***********************************************************************//**
664 * @brief Set sky direction to direction of Sun
665 *
666 * @param[in] time Time.
667 * @param[in] epoch Julian epoch.
668 *
669 * Sets the sky direction to the direction of the Sun at a given @p time.
670 *
671 * The equations were taken from the Astronomical Almanac. They calculate the
672 * apparent coordinates of the Sun to a precision of about 0.01 degrees
673 * (36 arcsec), for dates between 1950 and 2050.
674 *
675 * See https://en.wikipedia.org/wiki/Position_of_the_Sun
676 ***************************************************************************/
677void GSkyDir::sun(const GTime& time, const double& epoch)
678{
679 // Compute number of days since Greenwich noon, Terrestrial Time, on
680 // 1 January 2000
681 double n = time.jd() - 2451545.0;
682
683 // Compute obliquity of the ecliptic in radians
684 double eps_rad = (23.439 - 0.0000004 * n) * gammalib::deg2rad;
685
686 // Compute mean longitude of the Sun in degrees, corrected for the
687 // aberration of light. Put the mean longitude in the interval [0,360[
688 double mean_longitude = 280.460 + 0.9856474 * n;
689 while (mean_longitude < 0.0) {
690 mean_longitude += 360.0;
691 }
692 while (mean_longitude >= 360.0) {
693 mean_longitude -= 360.0;
694 }
695
696 // Compute the mean anomaly of the Sun in radians
697 double mean_anomaly = (357.528 + 0.9856003 * n) * gammalib::deg2rad;
698
699 // Compute the ecliptic longitude of the Sun in degrees
700 double ecliptic_longitude = mean_longitude +
701 1.915 * std::sin(mean_anomaly) +
702 0.020 * std::sin(2.0*mean_anomaly);
703
704 // Compute sine and cosine
705 double ecliptic_longitude_rad = ecliptic_longitude * gammalib::deg2rad;
706 double sin_ecliptic_longitude = std::sin(ecliptic_longitude_rad);
707 double cos_ecliptic_longitude = std::cos(ecliptic_longitude_rad);
708
709 // Compute Right Ascension and Declination of the Sun in degrees
710 double ra = std::atan2(std::cos(eps_rad) * sin_ecliptic_longitude,
711 cos_ecliptic_longitude) * gammalib::rad2deg;
712 double dec = std::asin(std::sin(eps_rad) * sin_ecliptic_longitude) *
714
715 // Set position
716 radec_deg(ra, dec);
717
718 // Precess sky position to requested epoch
719 precess(time.julian_epoch(), epoch);
720
721 // Return
722 return;
723}
724
725
726/***********************************************************************//**
727 * @brief Set sky direction to direction of Moon
728 *
729 * @param[in] time Time.
730 * @param[in] epoch Julian epoch.
731 *
732 * Sets the sky direction to the direction of the Moon at a given @p time.
733 *
734 * The equations are derived from the Chapront ELP2000/82 Lunar Theory
735 * (Chapront-Touze' and Chapront, 1983, 124, 50), as described by Jean Meeus
736 * in Chapter 47 of ``Astronomical Algorithms'' (Willmann-Bell, Richmond),
737 * 2nd edition, 1998. Meeus quotes an approximate accuracy of 10 arcsec in
738 * longitude and 4 arcsec in latitude, but he does not give the time range
739 * for this accuracy.
740 *
741 * The method was compared to the results obtained using PyEphem for the
742 * period 2000 - 2050. Differences in Right Ascension and Declination are
743 * always smaller than 0.015 degrees, corresponding to about 1 arcmin.
744 * The differences increase over time, meaning that the largest distances
745 * are reached by the end of the period.
746 ***************************************************************************/
747void GSkyDir::moon(const GTime& time, const double& epoch)
748{
749 // Set longitude constants. Note that the cos_lng contants are commented
750 // out since they are actually not used. They could be useful in case
751 // that the distance to the Moon should be computed, therefore we leave
752 // them in comments in the code.
753 const int d_lng[] = { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2,
754 0, 1, 0, 2, 0, 0, 4, 0, 4, 2,
755 2, 1, 1, 2, 2, 4, 2, 0, 2, 2,
756 1, 2, 0, 0, 2, 2, 2, 4, 0, 3,
757 2, 4, 0, 2, 2, 2, 4, 0, 4, 1,
758 2, 0, 1, 3, 4, 2, 0, 1, 2, 2};
759 const int m_lng[] = { 0, 0, 0, 0, 1, 0, 0,-1, 0,-1,
760 1, 0, 1, 0, 0, 0, 0, 0, 0, 1,
761 1, 0, 1,-1, 0, 0, 0, 1, 0,-1,
762 0,-2, 1, 2,-2, 0, 0,-1, 0, 0,
763 1,-1, 2, 2, 1,-1, 0, 0,-1, 0,
764 1, 0, 1, 0, 0,-1, 2, 1, 0,0};
765 const int mp_lng[] = { 1,-1, 0, 2, 0, 0,-2,-1, 1, 0,
766 -1, 0, 1, 0, 1, 1,-1, 3,-2,-1,
767 0,-1, 0, 1, 2, 0,-3,-2,-1,-2,
768 1, 0, 2, 0,-1, 1, 0,-1, 2,-1,
769 1,-2,-1,-1,-2, 0, 1, 4, 0,-2,
770 0, 2, 1,-2,-3, 2, 1,-1, 3,-1};
771 const int f_lng[] = { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
772 0, 0, 0,-2, 2,-2, 0, 0, 0, 0,
773 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
774 0, 0, 0, 0, 0,-2, 2, 0, 2, 0,
775 0, 0, 0, 0, 0,-2, 0, 0, 0, 0,
776 -2,-2, 0, 0, 0, 0, 0, 0, 0,-2};
777 const int sin_lng[] = { 6288774, 1274027, 658314, 213618,-185116,
778 -114332, 58793, 57066, 53322, 45758,
779 -40923, -34720, -30383, 15327, -12528,
780 10980, 10675, 10034, 8548, -7888,
781 -6766, -5163, 4987, 4036, 3994,
782 3861, 3665, -2689, -2602, 2390,
783 -2348, 2236, -2120, -2069, 2048,
784 -1773, -1595, 1215, -1110, -892,
785 -810, 759, -713, -700, 691,
786 596, 549, 537, 520, -487,
787 -399, -381, 351, -340, 330,
788 327, -323, 299, 294, 0};
789 /*
790 const int cos_lng[] = {-20905355,-3699111,-2955968,-569925, 48888,
791 -3149, 246158, -152138,-170733,-204586,
792 -129620, 108743, 104755, 10321, 0,
793 79661, -34782, -23210, -21636, 24208,
794 30824, -8379, -16675, -12831, -10445,
795 -11650, 14403, -7003, 0, 10056,
796 6322, -9884, 5751, 0, -4950,
797 4130, 0, -3958, 0, 3258,
798 2616, -1897, -2117, 2354, 0,
799 0, -1423, -1117, -1571, -1739,
800 0, -4421, 0, 0, 0,
801 0, 1165, 0, 0, 8752};
802 */
803
804 // Set latitude constants
805 const int d_lat[] = { 0, 0, 0, 2, 2, 2, 2, 0, 2, 0,
806 2, 2, 2, 2, 2, 2, 2, 0, 4, 0,
807 0, 0, 1, 0, 0, 0, 1, 0, 4, 4,
808 0, 4, 2, 2, 2, 2, 0, 2, 2, 2,
809 2, 4, 2, 2, 0, 2, 1, 1, 0, 2,
810 1, 2, 0, 4, 4, 1, 4, 1, 4, 2};
811 const int m_lat[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
812 -1, 0, 0, 1,-1,-1,-1, 1, 0, 1,
813 0, 1, 0, 1, 1, 1, 0, 0, 0, 0,
814 0, 0, 0, 0,-1, 0, 0, 0, 0, 1,
815 1, 0,-1,-2, 0, 1, 1, 1, 1, 1,
816 0,-1, 1, 0,-1, 0, 0, 0,-1,-2};
817 const int mp_lat[] = { 0, 1, 1, 0,-1,-1, 0, 2, 1, 2,
818 0,-2, 1, 0,-1, 0,-1,-1,-1, 0,
819 0,-1, 0, 1, 1, 0, 0, 3, 0,-1,
820 1,-2, 0, 2, 1,-2, 3, 2,-3,-1,
821 0, 0, 1, 0, 1, 1, 0, 0,-2,-1,
822 1,-2, 2,-2,-1, 1, 1,-1, 0, 0};
823 const int f_lat[] = { 1, 1,-1,-1, 1,-1, 1, 1,-1,-1,
824 -1,-1, 1,-1, 1, 1,-1,-1,-1, 1,
825 3, 1, 1, 1,-1,-1,-1, 1,-1, 1,
826 -3, 1,-3,-1,-1, 1,-1, 1,-1, 1,
827 1, 1, 1,-1, 3,-1,-1, 1,-1,-1,
828 1,-1, 1,-1,-1,-1,-1,-1,-1, 1};
829 const int sin_lat[] = {5128122, 280602, 277693, 173237, 55413,
830 46271, 32573, 17198, 9266, 8822,
831 8216, 4324, 4200, -3359, 2463,
832 2211, 2065, -1870, 1828, -1794,
833 -1749, -1565, -1491, -1475, -1410,
834 -1344, -1335, 1107, 1021, 833,
835 777, 671, 607, 596, 491,
836 -451, 439, 422, 421, -366,
837 -351, 331, 315, 302, -283,
838 -229, 223, 223, -220, -220,
839 -185, 181, -177, 176, 166,
840 -164, 132, -119, 115, 107};
841
842 // Set constants for computation of nutation. The constants have been
843 // taken from https://idlastro.gsfc.nasa.gov/ftp/pro/astro/nutate.pro
844 // which is based on Chapter 22 of "Astronomical Algorithms" by Jean
845 // Meeus (1998, 2nd ed.) which is based on the 1980 IAU Theory of
846 // Nutation and includes all terms larger than 0.0003 arcsec.
847 const int nutate_d_lng[] = { 0,-2, 0, 0, 0, 0,-2, 0, 0,-2,
848 -2,-2, 0, 2, 0, 2, 0, 0,-2, 0,
849 2, 0, 0,-2, 0,-2, 0, 0, 2,-2,
850 0,-2, 0, 0, 2, 2, 0,-2, 0, 2,
851 2,-2,-2, 2, 2, 0,-2,-2, 0,-2,
852 -2, 0,-1,-2, 1, 0, 0,-1, 0, 0,
853 2, 0, 2};
854 const int nutate_m_lng[] = { 0, 0, 0, 0, 1, 0, 1, 0, 0,-1,
855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
856 0, 0, 0, 0, 0, 0, 0, 2, 0, 2,
857 1, 0,-1, 0, 0, 0, 1, 1,-1, 0,
858 0, 0, 0, 0, 0,-1,-1, 0, 0, 0,
859 1, 0, 0, 1, 0, 0, 0,-1, 1,-1,
860 -1, 0,-1};
861 const int nutate_mp_lng[] = { 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
862 1, 0,-1, 0, 1,-1,-1, 1, 2,-2,
863 0, 2, 2, 1, 0, 0,-1, 0,-1, 0,
864 0, 1, 0, 2,-1, 1, 0, 1, 0, 0,
865 1, 2, 1,-2, 0, 1, 0, 0, 2, 2,
866 0, 1, 1, 0, 0, 1,-2, 1, 1, 1,
867 -1, 3, 0};
868 const int nutate_f_lng[] = { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2,
869 0, 2, 2, 0, 0, 2, 0, 2, 0, 2,
870 2, 2, 0, 2, 2, 2, 2, 0, 0, 2,
871 0, 0, 0,-2, 2, 2, 2, 0, 2, 2,
872 0, 2, 2, 0, 0, 0, 2, 0, 2, 0,
873 2,-2, 0, 0, 0, 2, 2, 0, 0, 2,
874 2, 2, 2};
875 const int nutate_om_lng[] = { 1, 2, 2, 2, 0, 0, 2, 1, 2, 2,
876 0, 1, 2, 0, 1, 2, 1, 1, 0, 1,
877 2, 2, 0, 2, 0, 0, 1, 0, 1, 2,
878 1, 1, 1, 0, 1, 2, 2, 0, 2, 1,
879 0, 2, 1, 1, 1, 0, 1, 1, 1, 1,
880 1, 0, 0, 0, 0, 0, 2, 0, 0, 2,
881 2, 2, 2};
882 const int nutate_sin_lng[] = {-171996, -13187, -2274, 2062, 1426,
883 712, -517, -386, -301, 217,
884 -158, 129, 123, 63, 63,
885 -59, -58, -51, 48, 46,
886 -38, -31, 29, 29, 26,
887 -22, 21, 17, 16, -16,
888 -15, -13, -12, 11, -10,
889 -8, 7, -7, -7, -7,
890 6, 6, 6, -6, -6,
891 5, -5, -5, -5, 4,
892 4, 4, -4, -4, -4,
893 3, -3, -3, -3, -3,
894 -3, -3, -3};
895 const int nutate_cos_lng[] = { 92025, 5736, 977, -895, 54,
896 -7, 224, 200, 129, -95,
897 0, -70, -53, 0, -33,
898 26, 32, 27, 0, -24,
899 16, 13, 0, -12, 0,
900 0, -10, 0, -8, 7,
901 9, 7, 6, 0, 5,
902 3, -3, 0, 3, 3,
903 0, -3, -3, 3, 3,
904 0, 3, 3, 3, 0,
905 0, 0, 0, 0, 0,
906 0, 0, 0, 0, 0,
907 0, 0, 0};
908 const double nutate_sdelt[] = {-174.2, -1.6, -0.2, 0.2, -3.4,
909 0.1, 1.2, -0.4, 0.0, -0.5,
910 0.0, 0.1, 0.0, 0.0, 0.1,
911 0.0, -0.1, 0.0, 0.0, 0.0,
912 0.0, 0.0, 0.0, 0.0, 0.0,
913 0.0, 0.0, -0.1, 0.0, 0.1,
914 0.0, 0.0, 0.0, 0.0, 0.0,
915 0.0, 0.0, 0.0, 0.0, 0.0,
916 0.0, 0.0, 0.0, 0.0, 0.0,
917 0.0, 0.0, 0.0, 0.0, 0.0,
918 0.0, 0.0, 0.0, 0.0, 0.0,
919 0.0, 0.0, 0.0, 0.0, 0.0,
920 0.0, 0.0, 0.0};
921 const double nutate_cdelt[] = {8.9, -3.1, -0.5, 0.5, -0.1,
922 0.0, -0.6, 0.0, -0.1, 0.3,
923 0.0, 0.0, 0.0, 0.0, 0.0,
924 0.0, 0.0, 0.0, 0.0, 0.0,
925 0.0, 0.0, 0.0, 0.0, 0.0,
926 0.0, 0.0, 0.0, 0.0, 0.0,
927 0.0, 0.0, 0.0, 0.0, 0.0,
928 0.0, 0.0, 0.0, 0.0, 0.0,
929 0.0, 0.0, 0.0, 0.0, 0.0,
930 0.0, 0.0, 0.0, 0.0, 0.0,
931 0.0, 0.0, 0.0, 0.0, 0.0,
932 0.0, 0.0, 0.0, 0.0, 0.0,
933 0.0, 0.0, 0.0};
934
935 // Compute Julian centuries from 1900.0
936 double t = (time.jd() - 2451545.0) / 36525.0;
937
938 // Compute Moon's mean longitude referred to mean equinox of the date
939 // in degrees and radians
940 double Lprimed = 218.3164477 +
941 (481267.88123421 +
942 (-0.0015786 +
943 (1.0/538841.0 - 1.0/65194000.0 * t) * t) * t) * t;
944 double Lprime = Lprimed * gammalib::deg2rad;
945
946 // Compute Moon's mean elongation in degrees
947 double D = (297.8501921 +
948 (445267.1114034 +
949 (-0.0018819 +
950 (1.0/545868.0 - 1.0/113065000.0 * t) * t) * t) * t) *
952
953 // Compute Sun's mean anomaly in radians
954 double M = (357.5291092 +
955 (35999.0502909 +
956 (-0.0001536 + 1.0/24490000.0 * t) * t) * t) *
958
959 // Compute Moon's mean anomaly in radians
960 double Mprime = (134.9633964 +
961 (477198.8675055 +
962 (0.0087414 +
963 (1.0/69699.0 - 1.0/14712000.0 * t) * t) * t) * t) *
965
966 // Compute Moon's argument of latitude in radians
967 double F = (93.2720950 +
968 (483202.0175233 +
969 (-0.0036539 +
970 (-1.0/35260000 + 1.0/863310000 * t) * t) * t) * t) *
972
973 // Compute longitude of the ascending node of the Moon's mean orbit on
974 // the ecliptic, measured from the mean equinox of the date in radians
975 double Omega = (125.04452 +
976 (-1934.136261 +
977 (0.0020708 + 1.0/4.5e5 * t) * t) * t) *
979
980 // Compute actions of Venus and Jupiter in radians
981 double A1 = (119.75 + 131.849 * t) * gammalib::deg2rad;
982 double A2 = ( 53.09 + 479264.290 * t) * gammalib::deg2rad;
983 double A3 = (313.45 + 481266.484 * t) * gammalib::deg2rad;
984
985 // Compute sum quantities
986 double Al = 3958.0 * std::sin(A1) +
987 1962.0 * std::sin(Lprime - F) +
988 318.0 * std::sin(A2);
989 double Ab = -2235.0 * std::sin(Lprime) +
990 382.0 * std::sin(A3) +
991 175.0 * std::sin(A1 - F) +
992 175.0 * std::sin(A1 + F) +
993 127.0 * std::sin(Lprime - Mprime) -
994 115.0 * std::sin(Lprime + Mprime);
995
996 // Compute eccentricity of Earth's orbit around the Sun
997 double E = 1.0 - (0.002516 + 7.4e-6 * t) * t;
998 double E2 = E * E;
999
1000 // Sum the periodic terms
1001 double sum_l = Al;
1002 double sum_b = Ab;
1003 //double sum_r = 0.0; // A_r = 0
1004 for (int i = 0; i < 60; ++i) {
1005
1006 // Compute sine and cosine of longitude and sine of latitude
1007 double sinlng = sin_lng[i];
1008 //double coslng = cos_lng[i];
1009 double sinlat = sin_lat[i];
1010 if (std::abs(m_lng[i]) == 1) {
1011 sinlng *= E;
1012 // coslng *= E;
1013 }
1014 else if (std::abs(m_lng[i]) == 2) {
1015 sinlng *= E2;
1016 // coslng *= E2;
1017 }
1018 if (std::abs(m_lat[i]) == 1) {
1019 sinlat *= E;
1020 }
1021 else if (std::abs(m_lat[i]) == 2) {
1022 sinlat *= E2;
1023 }
1024
1025 // Compute coefficient
1026 double s_l = d_lng[i] * D + m_lng[i] * M + mp_lng[i] * Mprime +
1027 f_lng[i] * F;
1028 double s_b = d_lat[i] * D + m_lat[i] * M + mp_lat[i] * Mprime +
1029 f_lat[i] * F;
1030
1031 // Compute longitude
1032 sum_l += sinlng * std::sin(s_l);
1033 sum_b += sinlat * std::sin(s_b);
1034 //sum_r += coslng * std::sin(s_l);
1035
1036 } // endfor: looped over sum terms
1037
1038 // Compute Moon's ecliptic coordinates in degrees and distance in km
1039 double geolong = Lprimed + 1.0e-6 * sum_l;
1040 double geolat = 1.0e-6 * sum_b;
1041 //double distance = 385000.56 + 1.0e-3 * sum_r;
1042
1043 // Compute nutation in arcsec, based on Chapter 22 of "Astronomical
1044 // Algorithms" by Jean Meeus (1998, 2nd ed.) which is based on the 1980
1045 // IAU Theory of Nutation and includes all terms larger than 0.0003 arcsec.
1046 double nut_long = 0.0;
1047 double nut_obliq = 0.0;
1048 for (int i = 0; i < 63; ++i) {
1049 double arg = nutate_d_lng[i] * D + nutate_m_lng[i] * M +
1050 nutate_mp_lng[i] * Mprime + nutate_f_lng[i] * F +
1051 nutate_om_lng[i] * Omega;
1052 nut_long += (nutate_sdelt[i] * t + nutate_sin_lng[i]) * std::sin(arg);
1053 nut_obliq += (nutate_cdelt[i] * t + nutate_cos_lng[i]) * std::cos(arg);
1054 }
1055 nut_long *= 0.0001;
1056 nut_obliq *= 0.0001;
1057
1058 // Add nutation in longitude
1059 geolong += nut_long / 3600.0;
1060
1061 // nutate, jd, nlong, elong
1062 // geolong= geolong + nlong/3.6d3
1063 // cirrange,geolong
1064 double lambda = geolong * gammalib::deg2rad;
1065 double beta = geolat * gammalib::deg2rad;
1066
1067 // Find mean obliquity using J. Laskar's formula. For the formula, see
1068 // http://www.neoprogrammics.com/obliquity_of_the_ecliptic/
1069 double y = t / 100.0; // Time in years
1070 double epsilon = (84381.448 + // In degrees
1071 (4680.93 +
1072 (-1.55 +
1073 (1999.25 +
1074 (-51.38 +
1075 (-249.67 +
1076 (-39.05 +
1077 (7.12 +
1078 (27.87 +
1079 (5.79 + 2.45 * y)*y)*y)*y)*y)*y)*y)*y)*y)*y)/3600.0;
1080 double eps = (epsilon + nut_obliq/3600.0) * gammalib::deg2rad;
1081
1082 // Convert (lambda,beta) in radians to (RA,Dec) in degrees
1083 double ra = std::atan2(std::sin(lambda) * std::cos(eps) -
1084 std::tan(beta) * std::sin(eps), std::cos(lambda)) *
1086 double dec = std::asin(std::sin(beta) * std::cos(eps) +
1087 std::cos(beta) * std::sin(eps) * std::sin(lambda)) *
1089
1090 // Set position
1091 radec_deg(ra, dec);
1092
1093 // Precess sky position to requested epoch
1094 precess(time.julian_epoch(), epoch);
1095
1096 // Return
1097 return;
1098}
1099
1100
1101/***********************************************************************//**
1102 * @brief Return sky direction as 3D vector in celestial coordinates
1103 *
1104 * @return Sky direction as 3D vector in celestial coordinates.
1105 ***************************************************************************/
1107{
1108 // If we have no equatorial coordinates then get them now
1109 if (!m_has_radec && m_has_lb) {
1110 gal2equ();
1111 }
1112
1113 // Compute 3D vector
1114 double cosra = std::cos(m_ra);
1115 double sinra = std::sin(m_ra);
1116 #if defined(G_SINCOS_CACHE)
1117 if (!m_has_radec_cache) {
1118 m_has_radec_cache = true;
1119 m_sin_dec = std::sin(m_dec);
1120 m_cos_dec = std::cos(m_dec);
1121 }
1122 GVector vector(m_cos_dec*cosra, m_cos_dec*sinra, m_sin_dec);
1123 #else
1124 double cosdec = std::cos(m_dec);
1125 double sindec = std::sin(m_dec);
1126 GVector vector(cosdec*cosra, cosdec*sinra, sindec);
1127 #endif
1128
1129 // Return vector
1130 return vector;
1131}
1132
1133
1134/***********************************************************************//**
1135 * @brief Return sky direction as 3D vector in galactic coordinates
1136 *
1137 * @return Sky direction as 3D vector in galactic coordinates.
1138 ***************************************************************************/
1140{
1141 // If we have no galactic coordinates then get them now
1142 if (m_has_radec && !m_has_lb) {
1143 equ2gal();
1144 }
1145
1146 // Compute 3D vector
1147 double cosl = std::cos(m_l);
1148 double sinl = std::sin(m_l);
1149 #if defined(G_SINCOS_CACHE)
1150 if (!m_has_lb_cache) {
1151 m_has_lb_cache = true;
1152 m_sin_b = std::sin(m_b);
1153 m_cos_b = std::cos(m_b);
1154 }
1155 GVector vector(m_cos_b*cosl, m_cos_b*sinl, m_sin_b);
1156 #else
1157 double cosb = std::cos(m_b);
1158 double sinb = std::sin(m_b);
1159 GVector vector(cosb*cosl, cosb*sinl, sinb);
1160 #endif
1161
1162 // Return vector
1163 return vector;
1164}
1165
1166
1167/***********************************************************************//**
1168 * @brief Compute cosine of angular distance between sky directions
1169 *
1170 * @param[in] dir Sky direction to which cosine of distance is to be computed.
1171 * @return Cosine of angular distance.
1172 *
1173 * Computes the cosine of the angular distance between two sky directions in
1174 * radians.
1175 ***************************************************************************/
1176double GSkyDir::cos_dist(const GSkyDir& dir) const
1177{
1178 // Initialise cosine of distance
1179 double cosdis;
1180
1181 // Compute dependent on coordinate system availability. This speeds
1182 // up things by avoiding unnecessary coordinate transformations.
1183 if (m_has_lb) {
1184 #if defined(G_SINCOS_CACHE)
1185 if (!m_has_lb_cache) {
1186 m_has_lb_cache = true;
1187 m_sin_b = std::sin(m_b);
1188 m_cos_b = std::cos(m_b);
1189 }
1190 #endif
1191 if (dir.m_has_lb) {
1192 #if defined(G_SINCOS_CACHE)
1193 if (!dir.m_has_lb_cache) {
1194 dir.m_has_lb_cache = true;
1195 dir.m_sin_b = std::sin(dir.m_b);
1196 dir.m_cos_b = std::cos(dir.m_b);
1197 }
1198 cosdis = m_sin_b * dir.m_sin_b +
1199 m_cos_b * dir.m_cos_b *
1200 std::cos(dir.m_l - m_l);
1201 #else
1202 cosdis = std::sin(m_b) * std::sin(dir.m_b) +
1203 std::cos(m_b) * std::cos(dir.m_b) *
1204 std::cos(dir.m_l - m_l);
1205 #endif
1206 }
1207 else {
1208 #if defined(G_SINCOS_CACHE)
1209 cosdis = m_sin_b * std::sin(dir.b()) +
1210 m_cos_b * std::cos(dir.b()) *
1211 std::cos(dir.l() - m_l);
1212 #else
1213 cosdis = std::sin(m_b) * std::sin(dir.b()) +
1214 std::cos(m_b) * std::cos(dir.b()) *
1215 std::cos(dir.l() - m_l);
1216 #endif
1217 }
1218 }
1219 else if (m_has_radec) {
1220 #if defined(G_SINCOS_CACHE)
1221 if (!m_has_radec_cache) {
1222 m_has_radec_cache = true;
1223 m_sin_dec = std::sin(m_dec);
1224 m_cos_dec = std::cos(m_dec);
1225 }
1226 #endif
1227 if (dir.m_has_radec) {
1228 #if defined(G_SINCOS_CACHE)
1229 if (!dir.m_has_radec_cache) {
1230 dir.m_has_radec_cache = true;
1231 dir.m_sin_dec = std::sin(dir.m_dec);
1232 dir.m_cos_dec = std::cos(dir.m_dec);
1233 }
1234 cosdis = m_sin_dec * dir.m_sin_dec +
1235 m_cos_dec * dir.m_cos_dec *
1236 std::cos(dir.m_ra - m_ra);
1237 #else
1238 cosdis = std::sin(m_dec) * std::sin(dir.m_dec) +
1239 std::cos(m_dec) * std::cos(dir.m_dec) *
1240 std::cos(dir.m_ra - m_ra);
1241 #endif
1242 }
1243 else {
1244 #if defined(G_SINCOS_CACHE)
1245 cosdis = m_sin_dec * sin(dir.dec()) +
1246 m_cos_dec * cos(dir.dec()) *
1247 std::cos(dir.ra() - m_ra);
1248 #else
1249 cosdis = sin(m_dec) * sin(dir.dec()) +
1250 cos(m_dec) * cos(dir.dec()) *
1251 std::cos(dir.ra() - m_ra);
1252 #endif
1253 }
1254 }
1255 else {
1256 cosdis = std::sin(dec()) * std::sin(dir.dec()) +
1257 std::cos(dec()) * std::cos(dir.dec()) *
1258 std::cos(dir.ra() - ra());
1259 }
1260
1261 // Return cosine of distance
1262 return cosdis;
1263}
1264
1265
1266/***********************************************************************//**
1267 * @brief Compute position angle between sky directions in radians
1268 *
1269 * @param[in] dir Sky direction.
1270 * @param[in] coordsys Coordinate system ("CEL" or "GAL")
1271 * @return Position angle (rad).
1272 *
1273 * Computes the position angle of a specified sky direction with respect to
1274 * the sky direction of the instance in radians. If "CEL" is specified as
1275 * @p coordsys the position angle is counted counterclockwise from celestial
1276 * North, if "GAL" is specified the position angle is counted
1277 * counterclockwise from Galactic North.
1278 *
1279 * If @p coordsys is "CEL" the position angle is computed using
1280 *
1281 * \f[PA = \arctan \left(
1282 * \frac{\sin( \alpha - \alpha_0 )}
1283 * {\cos \delta_0 \tan \delta -
1284 * \sin \delta_0 \cos(\alpha - \alpha_0)} \right)\f]
1285 * where
1286 * * \f$(\alpha_0,\delta_0)\f$ are the celestial coordinates of the instance,
1287 * and
1288 * * \f$(\alpha,\delta)\f$ are the celestial coordinates of sky direction.
1289 *
1290 * If @p coordsys is "GAL" the position angle is computed using
1291 *
1292 * \f[PA = \arctan \left(
1293 * \frac{\sin( \l - \l_0 )}
1294 * {\cos \b_0 \tan \b - \sin \b_0 \cos(\l - \l_0)} \right)\f]
1295 * where
1296 * * \f$(\l_0,\l_0)\f$ are the Galactic coordinates of the instance,
1297 * and
1298 * * \f$(\l,\b)\f$ are the Galactic coordinates of sky direction.
1299 ***************************************************************************/
1300double GSkyDir::posang(const GSkyDir& dir, const std::string& coordsys) const
1301{
1302 // Initialise arguments of arctan
1303 double arg_1;
1304 double arg_2;
1305
1306 // Case A: Computation in celestial coordinates
1307 if (coordsys == "CEL") {
1308
1309 // If required then compute sin(dec) and cos(dec) cache values
1310 #if defined(G_SINCOS_CACHE)
1311 if (!m_has_radec_cache) {
1312 m_has_radec_cache = true;
1313 m_sin_dec = std::sin(dec());
1314 m_cos_dec = std::cos(dec());
1315 }
1316 #endif
1317
1318 // Compute arguments of arctan
1319 arg_1 = std::sin(dir.ra() - ra());
1320 #if defined(G_SINCOS_CACHE)
1321 arg_2 = m_cos_dec * std::tan(dir.dec()) -
1322 m_sin_dec * std::cos(dir.ra() - ra());
1323 #else
1324 arg_2 = std::cos(dec()) * std::tan(dir.dec()) -
1325 std::sin(dec()) * std::cos(dir.ra() - ra());
1326 #endif
1327
1328 } // endif: computation in celestial coordinates
1329
1330 // Case B: Computation in Galactic coordinates
1331 else if (coordsys == "GAL") {
1332
1333 // If required then compute sin(b) and cos(b) cache values
1334 #if defined(G_SINCOS_CACHE)
1335 if (!m_has_lb_cache) {
1336 m_has_lb_cache = true;
1337 m_sin_b = std::sin(b());
1338 m_cos_b = std::cos(b());
1339 }
1340 #endif
1341
1342 // Compute arguments of arctan
1343 arg_1 = std::sin(dir.l() - l());
1344 #if defined(G_SINCOS_CACHE)
1345 arg_2 = m_cos_b * std::tan(dir.b()) -
1346 m_sin_b * std::cos(dir.l() - l());
1347 #else
1348 arg_2 = std::cos(b()) * std::tan(dir.b()) -
1349 std::sin(b()) * std::cos(dir.l() - l());
1350 #endif
1351
1352 } // endelse: computation in Galactic coordinates
1353
1354 // ... otherwise throw an exception
1355 else {
1356 std::string msg = "Invalid coordinate system \""+coordsys+"\" "
1357 "specified. Please specify either \"CEL\" or "
1358 "\"GAL\".";
1360 }
1361
1362 // Compute position angle
1363 double pa = std::atan2(arg_1, arg_2);
1364
1365 // Return position angle
1366 return pa;
1367}
1368
1369
1370/***********************************************************************//**
1371 * @brief Print sky direction information
1372 *
1373 * @param[in] chatter Chattiness.
1374 * @return String containing sky direction information.
1375 ***************************************************************************/
1376std::string GSkyDir::print(const GChatter& chatter) const
1377{
1378 // Initialise result string
1379 std::string result;
1380
1381 // Continue only if chatter is not silent
1382 if (chatter != SILENT) {
1383
1384 // Put coordinates in string
1385 if (m_has_lb) {
1386 result = "(l,b)=("+gammalib::str(m_l*gammalib::rad2deg) + "," +
1388 }
1389 else if (m_has_radec) {
1390 result = "(RA,Dec)=("+gammalib::str(m_ra*gammalib::rad2deg) + "," +
1392 }
1393 else {
1394 result = "(RA,Dec)=(not initialised)";
1395 }
1396
1397 } // endif: chatter was not silent
1398
1399 // Return result
1400 return result;
1401}
1402
1403
1404/*==========================================================================
1405 = =
1406 = Private methods =
1407 = =
1408 ==========================================================================*/
1409
1410/***********************************************************************//**
1411 * @brief Initialise class members
1412 ***************************************************************************/
1414{
1415 // Initialise members
1416 m_has_lb = false;
1417 m_has_radec = false;
1418 m_l = 0.0;
1419 m_b = 0.0;
1420 m_ra = 0.0;
1421 m_dec = 0.0;
1422
1423 // Initialise sincos cache
1424 #if defined(G_SINCOS_CACHE)
1425 m_has_lb_cache = false;
1426 m_has_radec_cache = false;
1427 m_sin_b = 0.0;
1428 m_cos_b = 0.0;
1429 m_sin_dec = 0.0;
1430 m_cos_dec = 0.0;
1431 #endif
1432
1433 // Return
1434 return;
1435}
1436
1437
1438/***********************************************************************//**
1439 * @brief Copy class members
1440 *
1441 * @param[in] dir Sky direction.
1442 ***************************************************************************/
1444{
1445 // Copy members
1446 m_has_lb = dir.m_has_lb;
1448 m_l = dir.m_l;
1449 m_b = dir.m_b;
1450 m_ra = dir.m_ra;
1451 m_dec = dir.m_dec;
1452
1453 // Copy sincos cache
1454 #if defined(G_SINCOS_CACHE)
1457 m_sin_b = dir.m_sin_b;
1458 m_cos_b = dir.m_cos_b;
1459 m_sin_dec = dir.m_sin_dec;
1460 m_cos_dec = dir.m_cos_dec;
1461 #endif
1462
1463 // Return
1464 return;
1465}
1466
1467
1468/***********************************************************************//**
1469 * @brief Delete class members
1470 ***************************************************************************/
1472{
1473 // Return
1474 return;
1475}
1476
1477
1478/***********************************************************************//**
1479 * @brief Convert equatorial to galactic coordinates
1480 ***************************************************************************/
1481void GSkyDir::equ2gal(void) const
1482{
1483 // Get non-const pointers to data members. This allows to circumvent
1484 // the const correctness and allows treating GSkyDir access methods
1485 // as const
1486 double* l = (double*)&m_l;
1487 double* b = (double*)&m_b;
1488
1489 // Convert from equatorial to galactic
1490 euler(0, m_ra, m_dec, l, b);
1491
1492 // Signal that galactic coordinates are available
1493 m_has_lb = true;
1494
1495 // Return
1496 return;
1497}
1498
1499
1500/***********************************************************************//**
1501 * @brief Convert galactic to equatorial coordinates
1502 ***************************************************************************/
1503void GSkyDir::gal2equ(void) const
1504{
1505 // Get non-const pointers to data members. This allows to circumvent
1506 // the const correctness and allows treating GSkyDir access methods
1507 // as const
1508 double* ra = (double*)&m_ra;
1509 double* dec = (double*)&m_dec;
1510
1511 // Convert from galactic to equatorial
1512 euler(1, m_l, m_b, ra, dec);
1513
1514 // Signal that equatorial coordinates are available
1515 m_has_radec = true;
1516
1517 // Return
1518 return;
1519}
1520
1521
1522/***********************************************************************//**
1523 * @brief General coordinate transformation routine for J2000
1524 *
1525 * @param[in] type Conversion type (0=equ2gal, 1=gal2equ)
1526 * @param[in] xin Input longitude (RA or GLON) in radians.
1527 * @param[in] yin Input latitude (Dec or GLAT) in radians.
1528 * @param[out] xout Output longitude in radians.
1529 * @param[out] yout Output latitude in radians.
1530 ***************************************************************************/
1531void GSkyDir::euler(const int& type, const double& xin, const double &yin,
1532 double* xout, double *yout) const
1533{
1534 // Set transformation constants
1535 const double psi[] = {0.57477043300, 4.9368292465};
1536 const double stheta[] = {0.88998808748, -0.88998808748};
1537 const double ctheta[] = {0.45598377618, 0.45598377618};
1538 const double phi[] = {4.9368292465, 0.57477043300};
1539
1540 // Perform transformation
1541 double a = xin - phi[type];
1542 double b = yin;
1543 double sb = std::sin(b);
1544 double cb = std::cos(b);
1545 double cbsa = cb * std::sin(a);
1546
1547 //
1548 a = std::atan2(ctheta[type] * cbsa + stheta[type] * sb, cb * std::cos(a));
1549 b = -stheta[type] * cbsa + ctheta[type] * sb;
1550 if (b > 1.0)
1551 b = 1.0;
1552
1553 //
1554 *yout = std::asin(b);
1555 *xout = gammalib::modulo((a+psi[type] + gammalib::fourpi), gammalib::twopi);
1556
1557 // Return
1558 return;
1559}
1560
1561
1562/*==========================================================================
1563 = =
1564 = Friends =
1565 = =
1566 ==========================================================================*/
1567
1568/***********************************************************************//**
1569 * @brief Equality operator
1570 *
1571 * @param[in] a First sky direction.
1572 * @param[in] b Second sky direction.
1573 *
1574 * Compare two sky directions. If the coordinate is at the pole, the Right
1575 * Ascension or Longitude value is irrelevant.
1576 *
1577 * Comparisons are done dependent on the available coordinate system. This
1578 * speeds up things and avoids unnecessary coordinate transformations.
1579 ***************************************************************************/
1580bool operator==(const GSkyDir &a, const GSkyDir &b)
1581{
1582 // Initialise result
1583 bool equal = false;
1584
1585 // Compute dependent on coordinate system availability. This speeds
1586 // up things by avoiding unnecessary coordinate transformations.
1587
1588 // Check if both have equatorial coordinates
1589 if (a.m_has_radec && b.m_has_radec) {
1590 if (std::abs(a.m_dec) == 90.0) {
1591 equal = (a.m_dec == b.m_dec);
1592 }
1593 else {
1594 equal = (a.m_dec == b.m_dec && a.m_ra == b.m_ra);
1595 }
1596 }
1597 // ... check if both have Galactic coordinates
1598 else if (a.m_has_lb && b.m_has_lb) {
1599 if (std::abs(a.m_b) == 90.0) {
1600 equal = (a.m_b == b.m_b);
1601 }
1602 else {
1603 equal = (a.m_b == b.m_b && a.m_l == b.m_l);
1604 }
1605 }
1606 // ... otherwise the coordinate systems are different
1607 else {
1608 if (a.m_has_lb) {
1609 if (std::abs(a.m_b) == 90.0) {
1610 equal = (a.m_b == b.b());
1611 }
1612 else {
1613 equal = (a.m_b == b.b() && a.m_l == b.l());
1614 }
1615 }
1616 else if (a.m_has_radec) {
1617 if (std::abs(a.m_dec) == 90.0) {
1618 equal = (a.m_dec == b.dec());
1619 }
1620 else {
1621 equal = (a.m_dec == b.dec() && a.m_ra == b.ra());
1622 }
1623 }
1624 else {
1625 if (std::abs(b.dec()) == 90.0) {
1626 equal = (b.dec() == a.dec());
1627 }
1628 else {
1629 equal = (b.dec() == a.dec() && b.ra() == a.ra());
1630 }
1631 }
1632 }
1633 // Return equality
1634 return equal;
1635}
1636
1637
1638/***********************************************************************//**
1639 * @brief Non equality operator
1640 *
1641 * @param[in] a First sky direction.
1642 * @param[in] b Second sky direction.
1643 ***************************************************************************/
1644bool operator!=(const GSkyDir &a, const GSkyDir &b)
1645{
1646 // Return non equality
1647 return (!(a==b));
1648}
#define G_SET
Definition GEnergies.cpp:46
Exception handler interface definition.
Generic matrix class definition.
bool operator!=(const GSkyDir &a, const GSkyDir &b)
Non equality operator.
Definition GSkyDir.cpp:1644
bool operator==(const GSkyDir &a, const GSkyDir &b)
Equality operator.
Definition GSkyDir.cpp:1580
#define G_POSANG
Definition GSkyDir.cpp:41
Sky direction class interface definition.
Time class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
GVector cos(const GVector &vector)
Computes cosine of vector elements.
Definition GVector.cpp:1258
GVector sin(const GVector &vector)
Computes sine of vector elements.
Definition GVector.cpp:1384
Vector class interface definition.
Generic matrix class definition.
Definition GMatrix.hpp:79
void eulerz(const double &angle)
Set Euler rotation matrix around z axis.
Definition GMatrix.cpp:1194
void eulery(const double &angle)
Set Euler rotation matrix around y axis.
Definition GMatrix.cpp:1157
Sky direction class.
Definition GSkyDir.hpp:62
double m_cos_b
Definition GSkyDir.hpp:137
void radec(const double &ra, const double &dec)
Set equatorial sky direction (radians)
Definition GSkyDir.cpp:218
void rotate_deg(const double &phi, const double &theta)
Rotate sky direction by zenith and azimuth angle.
Definition GSkyDir.cpp:573
void lb_deg(const double &l, const double &b)
Set galactic sky direction (degrees)
Definition GSkyDir.cpp:299
virtual ~GSkyDir(void)
Destructor.
Definition GSkyDir.cpp:133
bool m_has_lb
Has galactic coordinates.
Definition GSkyDir.hpp:125
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition GSkyDir.cpp:245
void free_members(void)
Delete class members.
Definition GSkyDir.cpp:1471
void rotate(const double &phi, const double &theta)
Rotate sky direction by zenith and azimuth angle.
Definition GSkyDir.cpp:527
const double & dec(void) const
Return Declination in radians.
Definition GSkyDir.hpp:243
GSkyDir * clone(void) const
Clone sky direction.
Definition GSkyDir.cpp:203
GVector galvector(void) const
Return sky direction as 3D vector in galactic coordinates.
Definition GSkyDir.cpp:1139
double cos_dist(const GSkyDir &dir) const
Compute cosine of angular distance between sky directions.
Definition GSkyDir.cpp:1176
double m_sin_b
Definition GSkyDir.hpp:136
double m_sin_dec
Definition GSkyDir.hpp:138
void init_members(void)
Initialise class members.
Definition GSkyDir.cpp:1413
const double & l(void) const
Return galactic longitude in radians.
Definition GSkyDir.hpp:162
void lb(const double &l, const double &b)
Set galactic sky direction (radians)
Definition GSkyDir.cpp:272
void clear(void)
Clear sky direction.
Definition GSkyDir.cpp:185
void euler(const int &type, const double &xin, const double &yin, double *xout, double *yout) const
General coordinate transformation routine for J2000.
Definition GSkyDir.cpp:1531
void set(const std::string &coord)
Definition GSkyDir.cpp:333
bool m_has_radec_cache
Definition GSkyDir.hpp:135
GSkyDir & operator=(const GSkyDir &dir)
Assignment operator.
Definition GSkyDir.cpp:155
void equ2gal(void) const
Convert equatorial to galactic coordinates.
Definition GSkyDir.cpp:1481
void precess(const double &from_epoch, const double &to_epoch)
Precess sky direction.
Definition GSkyDir.cpp:600
std::string print(const GChatter &chatter=NORMAL) const
Print sky direction information.
Definition GSkyDir.cpp:1376
void copy_members(const GSkyDir &dir)
Copy class members.
Definition GSkyDir.cpp:1443
GVector celvector(void) const
Return sky direction as 3D vector in celestial coordinates.
Definition GSkyDir.cpp:1106
void moon(const GTime &time, const double &epoch=2000.0)
Set sky direction to direction of Moon.
Definition GSkyDir.cpp:747
const double & ra(void) const
Return Right Ascension in radians.
Definition GSkyDir.hpp:216
double m_dec
Declination in radians.
Definition GSkyDir.hpp:130
const double & b(void) const
Return galactic latitude in radians.
Definition GSkyDir.hpp:189
GSkyDir(void)
Constructor.
Definition GSkyDir.cpp:60
bool m_has_radec
Has equatorial coordinates.
Definition GSkyDir.hpp:126
double m_cos_dec
Definition GSkyDir.hpp:139
double m_l
Galactic longitude in radians.
Definition GSkyDir.hpp:127
void gal2equ(void) const
Convert galactic to equatorial coordinates.
Definition GSkyDir.cpp:1503
double m_b
Galactic latitude in radians.
Definition GSkyDir.hpp:128
bool m_has_lb_cache
Definition GSkyDir.hpp:134
void sun(const GTime &time, const double &epoch=2000.0)
Set sky direction to direction of Sun.
Definition GSkyDir.cpp:677
double m_ra
Right Ascension in radians.
Definition GSkyDir.hpp:129
double posang(const GSkyDir &dir, const std::string &coordsys="CEL") const
Compute position angle between sky directions in radians.
Definition GSkyDir.cpp:1300
Time class.
Definition GTime.hpp:55
double jd(void) const
Return time in Julian Days (TT)
Definition GTime.cpp:284
double julian_epoch(void) const
Return Julian epoch in native reference (TT)
Definition GTime.cpp:425
Vector class.
Definition GVector.hpp:46
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
const double pi
Definition GMath.hpp:35
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:945
const double deg2rad
Definition GMath.hpp:43
bool contains(const std::string &str, const std::string &substring)
Checks if a substring is in a string.
Definition GTools.cpp:1361
const double fourpi
Definition GMath.hpp:37
const double twopi
Definition GMath.hpp:36
double modulo(const double &v1, const double &v2)
Returns the remainder of the division.
Definition GMath.cpp:526
std::string toupper(const std::string &s)
Convert string to upper case.
Definition GTools.cpp:960
const double rad2deg
Definition GMath.hpp:44