GammaLib 2.0.0
Loading...
Searching...
No Matches
GCOMDri.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GCOMDri.cpp - COMPTEL Data Space class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2017-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 GCOMDri.cpp
23 * @brief COMPTEL Data Space class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GTools.hpp"
32#include "GMath.hpp"
33#include "GWcs.hpp"
34#include "GFits.hpp"
35#include "GFitsImage.hpp"
36#include "GNodeArray.hpp"
37#include "GModelSky.hpp"
38#include "GModelSpatial.hpp"
40#include "GEphemerides.hpp"
41#include "GCOMTools.hpp"
42#include "GCOMSupport.hpp"
43#include "GCOMDri.hpp"
44#include "GCOMOad.hpp"
45#include "GCOMOads.hpp"
46#include "GCOMTim.hpp"
47#include "GCOMStatus.hpp"
48#include "GCOMSupport.hpp"
49#include "GCOMObservation.hpp"
50#include "GCOMEventList.hpp"
51#include "GCOMSelection.hpp"
52
53/* __ Method name definitions ____________________________________________ */
54#define G_COMPUTE_DRE "GCOMDri::compute_dre(GCOMObservation&, "\
55 "GCOMSelection&, double&)"
56#define G_COMPUTE_DRX "GCOMDri::compute_drx(GCOMObservation&, "\
57 "GCOMSelection&, double&)"
58#define G_COMPUTE_DRM "GCOMDri::compute_drm(GCOMObservation&, GModel&)"
59#define G_COMPUTE_TOF_CORRECTION "GCOMDri::compute_tof_correction()"
60
61/* __ Macros _____________________________________________________________ */
62
63/* __ Coding definitions _________________________________________________ */
64//#define G_CHECK_EHA_COMPUTATION
65
66/* __ Debug definitions __________________________________________________ */
67//#define G_DEBUG_COMPUTE_DRE
68//#define G_DEBUG_COMPUTE_DRG
69//#define G_DEBUG_COMPUTE_DRX
70
71/* __ Constants __________________________________________________________ */
72const double superpacket_duration = 16.384; // Duration of superpacket (s)
73const double r1 = 13.8; // D1 module radius (cm)
74
75/* __ Derived constants __________________________________________________ */
76const double r1sq = r1 * r1;
77const double d1_area = 7.0 * gammalib::pi * r1sq;
78
79
80/*==========================================================================
81 = =
82 = Constructors/destructors =
83 = =
84 ==========================================================================*/
85
86/***********************************************************************//**
87 * @brief Void constructor
88 ***************************************************************************/
90{
91 // Initialise class members
93
94 // Return
95 return;
96}
97
98
99/***********************************************************************//**
100 * @brief File name constructor
101 *
102 * @param[in] filename COMPTEL Data Space FITS file name.
103 ***************************************************************************/
105{
106 // Initialise class members
107 init_members();
108
109 // Load DRI FITS file
110 load(filename);
111
112 // Return
113 return;
114}
115
116
117/***********************************************************************//**
118 * @brief Sky map constructor
119 *
120 * @param[in] map Sky map defining the DRI cube.
121 * @param[in] phimin Minimum Phibar angle (deg).
122 * @param[in] phibin Bin size of Phibar angle (deg).
123 * @param[in] nphibin Number of Phibar bins.
124 *
125 * Constructs a DRI cube from a sky map and a Phibar binning definition.
126 ***************************************************************************/
128 const double& phimin,
129 const double& phibin,
130 const int& nphibin)
131{
132 // Initialise class members
133 init_members();
134
135 // Set sky map
136 m_dri = map;
137
138 // Make sure that sky map can hold the required number of maps
139 if (nphibin > 0) {
140 m_dri.nmaps(nphibin);
141 }
142
143 // Set all sky map pixels to zero
144 m_dri = 0;
145
146 // Store minimum Phibar and bin size
149
150 // Return
151 return;
152}
153
154
155/***********************************************************************//**
156 * @brief Copy constructor
157 *
158 * @param[in] dri COMPTEL Data Space.
159 ***************************************************************************/
161{
162 // Initialise class members
163 init_members();
164
165 // Copy members
166 copy_members(dri);
167
168 // Return
169 return;
170}
171
172
173/***********************************************************************//**
174 * @brief Destructor
175 ***************************************************************************/
177{
178 // Free members
179 free_members();
180
181 // Return
182 return;
183}
184
185
186/*==========================================================================
187 = =
188 = Operators =
189 = =
190 ==========================================================================*/
191
192/***********************************************************************//**
193 * @brief Assignment operator
194 *
195 * @param[in] dri COMPTEL Data Space.
196 * @return COMPTEL Data Space.
197 ***************************************************************************/
199{
200 // Execute only if object is not identical
201 if (this != &dri) {
202
203 // Free members
204 free_members();
205
206 // Initialise private members
207 init_members();
208
209 // Copy members
210 copy_members(dri);
211
212 } // endif: object was not identical
213
214 // Return this object
215 return *this;
216}
217
218
219/*==========================================================================
220 = =
221 = Public methods =
222 = =
223 ==========================================================================*/
224
225/***********************************************************************//**
226 * @brief Clear COMPTEL Data Space
227 ***************************************************************************/
229{
230 // Free members
231 free_members();
232
233 // Initialise private members
234 init_members();
235
236 // Return
237 return;
238}
239
240
241/***********************************************************************//**
242 * @brief Clone COMPTEL Data Space
243 *
244 * @return Pointer to deep copy of COMPTEL Data Space.
245 ***************************************************************************/
247{
248 return new GCOMDri(*this);
249}
250
251
252/***********************************************************************//**
253 * @brief Compute event cube
254 *
255 * @param[in] obs COMPTEL observation.
256 * @param[in] select Selection set.
257 * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
258 *
259 * @exception GException::invalid_argument
260 * DRE cube has a non-positive Phibar bin size.
261 * @exception GException::invalid_value
262 * No BVC data available for pulsar selection
263 *
264 * Compute DRE event cube for a COMPTEL observation.
265 ***************************************************************************/
267 const GCOMSelection& select,
268 const double& zetamin)
269{
270 // Debug
271 #if defined(G_DEBUG_COMPUTE_DRE)
272 std::cout << "GCOMDri::compute_dre" << std::endl;
273 std::cout << "====================" << std::endl;
274 #endif
275
276 // Check if observation contains a COMPTEL event list
277 const GCOMEventList* events = dynamic_cast<const GCOMEventList*>(obs.events());
278 if (events == NULL) {
279 std::string msg = "No event list found in COMPTEL observation. Please "
280 "specify an observation that contains an event list.";
282 }
283
284 // Check for positive Phibar bin size
285 if (m_phibin <= 0.0) {
286 std::string msg = "DRE cube has a non-positive Phibar bin size. Please "
287 "specify a DRE cube with a positive Phibar bin size.";
289 }
290
291 // Initialise event counter
292 int i_evt = 0;
293
294 // Initialise superpacket statistics
296
297 // Store selection set
298 m_selection = select;
299
300 // Initialise selection statistics
302
303 // Signal that event selection was used (this will enable writing into
304 // the FITS HDU) and store Earth horizon cut
305 m_has_selection = true;
306 m_zetamin = zetamin;
307
308 // Compute ToF correction
310
311 // Initialise statistics
312 int num_used_events = 0;
313 int num_event_outside_sp = 0;
314 int num_energy_too_low = 0;
315 int num_energy_too_high = 0;
316 int num_eha_too_small = 0;
317 int num_phibar_too_low = 0;
318 int num_phibar_too_high = 0;
319 int num_outside_dre = 0;
320 int num_event_before_dre = 0;
321 int num_event_after_dre = 0;
322 int num_processed = 0;
323
324 // Set all DRE bins to zero
325 init_cube();
326
327 // Signal that loop should be terminated
328 bool terminate = false;
329
330 // Initialise JPL DE200 ephemerides (use in case that no BVC data are
331 // available)
332 GEphemerides ephem;
333
334 // Get Good Time Intervals. If a pulsar selection is specified then
335 // reduce the Good Time Intervals to the validity intervals of the pulsar
336 // emphemerides.
337 GCOMTim tim = obs.tim();
338 if (m_selection.has_pulsar()) {
342 }
343
344 // Loop over Orbit Aspect Data
345 for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
346
347 // Get reference to Orbit Aspect Data of superpacket
348 const GCOMOad &oad = obs.oads()[i_oad];
349
350 // Check superpacket usage
351 if (!use_superpacket(oad, tim, select)) {
352 continue;
353 }
354
355 // Prepare Earth horizon angle comparison
356 GSkyDir sky_geocentre;
357 double theta_geocentre = double(oad.gcel());
358 double phi_geocentre = double(oad.gcaz());
359 sky_geocentre.radec_deg(phi_geocentre, 90.0-theta_geocentre);
360
361 // Collect all events within superpacket. Break if the end
362 // of the event list was reached.
363 for (; i_evt < events->size(); ++i_evt) {
364
365 // Get pointer to event
366 const GCOMEventAtom* event = (*events)[i_evt];
367
368 // Break loop if the end of the superpacket was reached
369 if (event->time() > oad.tstop()) {
370 break;
371 }
372
373 // Increase number of processed events
374 num_processed++;
375
376 // Check GTIs if the DRE has GTIs
377 if (m_gti.size() > 0) {
378
379 // Skip event if it lies before the DRE start.
380 if (event->time() < m_gti.tstart()) {
381 num_event_before_dre++;
382 continue;
383 }
384
385 // Break if event lies after the DRE stop
386 else if (event->time() > m_gti.tstop()) {
387 num_event_after_dre++;
388 terminate = true;
389 break;
390 }
391
392 } // endif: DRE had GTIs
393
394 // Skip event if it lies before the superpacket start
395 if (event->time() < oad.tstart()) {
396 num_event_outside_sp++;
397 continue;
398 }
399
400 // Skip event if it lies outside energy range
401 if (event->energy() < m_ebounds.emin()) {
402 num_energy_too_low++;
403 continue;
404 }
405 else if (event->energy() > m_ebounds.emax()) {
406 num_energy_too_high++;
407 continue;
408 }
409
410 // Apply event selection
411 if (!m_selection.use_event(*event)) {
412 continue;
413 }
414
415 // Compute Compton scatter angle index. Skip if it's invalid.
416 int iphibar = int((event->phibar() - m_phimin) / m_phibin);
417 if (iphibar < 0) {
418 num_phibar_too_low++;
419 continue;
420 }
421 else if (iphibar >= nphibar()) {
422 num_phibar_too_high++;
423 continue;
424 }
425
426 // Option: Earth horizon angle comparison
427 #if defined(G_CHECK_EHA_COMPUTATION)
428 GSkyDir sky_event;
429 double theta_event = double(event->theta());
430 double phi_event = double(event->phi());
431 sky_event.radec_deg(-phi_event, 90.0-theta_event);
432 double eha = sky_geocentre.dist_deg(sky_event) - oad.georad();
433 if (std::abs(eha - event->eha()) > 1.5) {
434 std::string msg = "Earth horizon angle from EVP dataset ("+
435 gammalib::str(event->eha())+" deg) "
436 "differs from Earth horizon angle "
437 "computed from Orbit Aspect Data ("+
438 gammalib::str(eha)+" deg). Use the EVP "
439 "value.";
441 }
442 #endif
443
444 // Check for Earth horizon angle. There is a constant EHA limit
445 // over a Phibar layer to be compliant with the DRG.
446 double ehamin = double(iphibar) * m_phibin + zetamin;
447 if (event->eha() < ehamin) {
448 num_eha_too_small++;
449 continue;
450 }
451
452 // Optionally apply pulsar phase selection
453 if (m_selection.has_pulsar()) {
454
455 // Get pulsar ephemeris
456 const GPulsarEphemeris& ephemeris =
457 m_selection.pulsar().ephemeris(event->time());
458
459 // Convert event time to Solar System Barycentre time. If BVC
460 // information is available it will be used for the computation,
461 // otherwise the time correction will be computed on-the-fly
462 // from the JPL DE200 ephemerides.
463 //
464 // Note that the time correction includes an UTC_TO_TT conversion
465 // term, but this terms has already applied when setting the GTime
466 // object. Hence if time is read as time.mjd() the correction
467 // would be applied twice, yet reading the time as time.mjd('UTC')
468 // will remove the correation again.
469 double tdelta = 0.0;
470 if (obs.bvcs().is_empty()) {
471 tdelta = ephem.geo2ssb(ephemeris.dir(), event->time(), oad.pos()) +
472 event->time().utc2tt();
473 }
474 else {
475 tdelta = obs.bvcs().tdelta(ephemeris.dir(), event->time());
476 }
477 GTime time = event->time() + tdelta;
478
479 // Compute pulsar phase. See comment above why "UTC" needs
480 // to be specified.
481 double phase = ephemeris.phase(time, "UTC");
482
483 // If phase is not contained in phase interval then skip event
484 if (!m_selection.pulsar_phases().contains(phase)) {
485 continue;
486 }
487
488 } // endif: applied pulsar selection
489
490 // Now fill the event into the DRE. Put this in a try-catch
491 // block so that any invalid transformations are catched.
492 try {
493 GSkyPixel pixel = m_dri.dir2pix(event->dir().dir());
494 if (m_dri.contains(pixel)) {
495 int inx = m_dri.pix2inx(pixel) + iphibar * m_dri.npix();
496 (*this)[inx] += 1.0;
497 num_used_events++;
498 }
499 else {
500 num_outside_dre++;
501 }
502 }
504 num_outside_dre++;
505 }
506
507 } // endfor: collected events
508
509 // Break if termination was signalled or if there are no more events
510 if (terminate || i_evt >= events->size()) {
511 break;
512 }
513
514 } // endfor: looped over Orbit Aspect Data
515
516 // Set Good Time interval for DRE
517 if (m_num_used_superpackets > 0) {
519 }
520
521 // Debug
522 #if defined(G_DEBUG_COMPUTE_DRE)
523 std::cout << "Total number of superpackets .: " << m_num_superpackets << std::endl;
524 std::cout << "Used superpackets ............: " << m_num_used_superpackets << std::endl;
525 std::cout << "Skipped superpackets .........: " << m_num_skipped_superpackets << std::endl;
526 std::cout << "Total number of events .......: " << events.size() << std::endl;
527 std::cout << "Processed events .............: " << num_processed << std::endl;
528 std::cout << "Used events ..................: " << num_used_events << std::endl;
529 std::cout << "Events outside superpacket ...: " << num_event_outside_sp << std::endl;
530 std::cout << "Events before DRE GTI ........: " << num_event_before_dre << std::endl;
531 std::cout << "Events after DRE GTI .........: " << num_event_after_dre << std::endl;
532 std::cout << "Energy too low ...............: " << num_energy_too_low << std::endl;
533 std::cout << "Energy too high ..............: " << num_energy_too_high << std::endl;
534 std::cout << "Phibar too low ...............: " << num_phibar_too_low << std::endl;
535 std::cout << "Phibar too high ..............: " << num_phibar_too_high << std::endl;
536 std::cout << "Outside DRE cube .............: " << num_outside_dre << std::endl;
537 std::cout << "Earth horizon angle too small : " << num_eha_too_small << std::endl;
538 std::cout << m_selection << std::endl;
539 #endif
540
541 // Return
542 return;
543}
544
545
546/***********************************************************************//**
547 * @brief Compute geometry cube
548 *
549 * @param[in] obs COMPTEL observation.
550 * @param[in] select Selection set.
551 * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
552 *
553 * @exception GException::invalid_value
554 * No BVC data available for pulsar selection
555 *
556 * Compute DRG cube for a COMPTEL observation.
557 ***************************************************************************/
559 const GCOMSelection& select,
560 const double& zetamin)
561{
562 // Debug
563 #if defined(G_DEBUG_COMPUTE_DRG)
564 std::cout << "GCOMDri::compute_drg" << std::endl;
565 std::cout << "====================" << std::endl;
566 #endif
567
568 // Initialise D1 & D2 module status
569 GCOMStatus status;
570
571 // Initialise superpacket statistics
573
574 // Store selection set so that handling of failed PMT flag is correctly
575 // written into the FITS header
576 m_selection = select;
577
578 // Set all DRG bins to zero
579 init_cube();
580
581 // Get Good Time Intervals. If a pulsar selection is specified then
582 // reduce the Good Time Intervals to the validity intervals of the pulsar
583 // emphemerides.
584 GCOMTim tim = obs.tim();
585 if (m_selection.has_pulsar()) {
587 }
588
589 // Loop over Orbit Aspect Data
590 for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
591
592 // Get reference to Orbit Aspect Data of superpacket
593 const GCOMOad &oad = obs.oads()[i_oad];
594
595 // Check superpacket usage
596 if (!use_superpacket(oad, tim, select)) {
597 continue;
598 }
599
600 // Prepare Earth horizon angle computation. The celestial system
601 // is reinterpreted as the COMPTEL coordinate system, where the
602 // 90 degrees - zenith angle becomes the declination and the azimuth
603 // angle becomes Right Ascension. This allows us later to use the
604 // GSkyDir::dist method to compute the distance between the geocentre
605 // and the telescope Z-axis.
606 double theta_geocentre = double(oad.gcel());
607 double phi_geocentre = double(oad.gcaz());
608 GSkyDir geocentre_comptel;
609 geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
610
611 // Compute geometrical factors for all (Chi, Psi)
612 for (int index = 0; index < m_dri.npix(); ++index) {
613
614 // Get sky direction for (Chi, Psi)
615 GSkyDir sky = m_dri.inx2dir(index);
616
617 // Convert sky direction to COMPTEL coordinates
618 double theta = oad.theta(sky);
619 double phi = oad.phi(sky);
620
621 // Compute geometric factor summed over all D1, D2
622 double geometry = compute_geometry(oad.tjd(), theta, phi, select, status);
623
624 // Compute Earth horizon angle as the distance between the Earth
625 // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
626 // COMPTEL coordinates minus the radius of the Earth.
627 GSkyDir chipsi_comptel;
628 chipsi_comptel.radec_deg(phi, 90.0-theta);
629 double eha = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
630
631 // Loop over Phibar
632 for (int iphibar = 0; iphibar < nphibar(); ++iphibar) {
633
634 // Compute minimum Earth horizon angle for Phibar layer
635 double ehamin = double(iphibar) * m_phibin + zetamin;
636
637 // Add up geometry if the Earth horizon angle is equal or
638 // larger than the minimum
639 if (eha >= ehamin) {
640 int inx = index + iphibar * m_dri.npix();
641 (*this)[inx] += geometry;
642 }
643
644 } // endfor: looped over Phibar
645
646 } // endfor: looped over (Chi, Psi)
647
648 } // endfor: looped over Orbit Aspect Data
649
650 // Divide DRG by number of used superpackets
651 if (m_num_used_superpackets > 0) {
652 double norm = 1.0 / double(m_num_used_superpackets);
653 for (int i = 0; i < size(); ++i) {
654 (*this)[i] *= norm;
655 }
656 }
657
658 // Clear energy boundaries for DRG since DRG does not depend on energy)
660
661 // Set the Good Time interval for DRG
662 if (m_num_used_superpackets > 0) {
664 }
665
666 // Debug
667 #if defined(G_DEBUG_COMPUTE_DRG)
668 std::cout << "Total number of superpackets .: " << m_num_superpackets << std::endl;
669 std::cout << "Used superpackets ............: " << m_num_used_superpackets << std::endl;
670 std::cout << "Skipped superpackets .........: " << m_num_skipped_superpackets << std::endl;
671 #endif
672
673 // Return
674 return;
675}
676
677
678/***********************************************************************//**
679 * @brief Compute DRX exposure map
680 *
681 * @param[in] obs COMPTEL observation.
682 * @param[in] select Selection set.
683 *
684 * @exception GException::invalid_value
685 * No BVC data available for pulsar selection
686 *
687 * Compute DRX exposure map for a COMPTEL observation.
688 *
689 * For a given superpacket, the exposure is computed using
690 *
691 * \f[
692 * X_i(\theta_c) = 7 \pi r_1^2 \cos \theta_c
693 * \frac{1 - \exp \left( -\tau \ \cos \theta_c \right)}
694 * {1 - \exp \left( -\tau \right)}
695 * \f]
696 *
697 * where
698 * \f$\tau=0.2\f$ is the typical thickness of a D1 module in radiation
699 * lengths,
700 * \f$r_1=13.8\f$ cm is the radius of a D1 module, and
701 * \f$\theta_c\f$ is the zenith angle in COMPTEL coordinates.
702 ***************************************************************************/
704 const GCOMSelection& select)
705{
706 // Debug
707 #if defined(G_DEBUG_COMPUTE_DRX)
708 std::cout << "GCOMDri::compute_drx" << std::endl;
709 std::cout << "====================" << std::endl;
710 #endif
711
712 // Initialise constants
713 const double tau = 0.2; // Thickness in radiation lenghts
714
715 // Initialise superpacket statistics
717
718 // Set all DRX bins to zero
719 init_cube();
720
721 // Get Good Time Intervals. If a pulsar selection is specified then
722 // reduce the Good Time Intervals to the validity intervals of the pulsar
723 // emphemerides.
724 GCOMTim tim = obs.tim();
725 if (select.has_pulsar()) {
726 tim.reduce(select.pulsar().validity());
727 }
728
729 // Loop over Orbit Aspect Data
730 for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
731
732 // Get reference to Orbit Aspect Data of superpacket
733 const GCOMOad &oad = obs.oads()[i_oad];
734
735 // Check superpacket usage
736 if (!use_superpacket(oad, tim, select)) {
737 continue;
738 }
739
740 // Loop over all DRX pixels
741 for (int index = 0; index < m_dri.npix(); ++index) {
742
743 // Get sky direction for DRX pixel
744 GSkyDir sky = m_dri.inx2dir(index);
745
746 // Compute zenith angle of pixel in COMPTEL coordinates
747 double theta = oad.theta(sky);
748
749 // Initialise exposure
750 double exposure = 0.0;
751
752 // Skip pixel if zenith angle is beyond 90 degrees
753 if (theta >= 90.0) {
754 continue;
755 }
756
757 // ... otherwise compute the exposure
758 else {
759 double costheta = std::cos(theta * gammalib::deg2rad);
760 if (theta < 89.0) {
761 exposure = d1_area * costheta *
762 (1.0 - std::exp(-tau / costheta)) /
763 (1.0 - std::exp(-tau));
764 }
765 else {
766 exposure = d1_area * costheta / (1.0 - std::exp(-tau));
767 }
768 }
769
770 // Accumulate exposure
771 (*this)[index] += exposure;
772
773 } // endfor: looped over all DRX pixels
774
775 } // endfor: looped over Orbit Aspect Data
776
777 // Multiply by time per superpacket to give the result in cm^2 s
778 for (int i = 0; i < size(); ++i) {
779 (*this)[i] *= superpacket_duration;
780 }
781
782 // Clear energy boundaries for DRX since DRX does not depend on energy)
784
785 // Set the Good Time interval for DRX
786 if (m_num_used_superpackets > 0) {
788 }
789
790 // Debug
791 #if defined(G_DEBUG_COMPUTE_DRX)
792 std::cout << "Total number of superpackets .: " << m_num_superpackets << std::endl;
793 std::cout << "Used superpackets ............: " << m_num_used_superpackets << std::endl;
794 std::cout << "Skipped superpackets .........: " << m_num_skipped_superpackets << std::endl;
795 #endif
796
797 // Return
798 return;
799}
800
801
802/***********************************************************************//**
803 * @brief Compute DRM model
804 *
805 * @param[in] obs COMPTEL observation.
806 * @param[in] model Model.
807 *
808 * Compute DRM model cube for a COMPTEL observation.
809 ***************************************************************************/
811 const GModel& model)
812{
813 // Evaluate model
814 GVector values = model.eval(obs);
815
816 // Get number of Chi/Psi pixels
817 int npix = nchi() * npsi();
818
819 // Fill DRM with model values
820 for (int iphibar = 0, i = 0; iphibar < nphibar(); ++iphibar) {
821 for (int ipix = 0; ipix < npix; ++ipix, ++i) {
822 m_dri(ipix, iphibar) = values[i];
823 }
824 }
825
826 // Return
827 return;
828}
829
830
831/***********************************************************************//**
832 * @brief Compute content in cone
833 *
834 * @param[in] dir Sky direction of cone apex.
835 * @param[in] armmin Minimum Angular Resolution Measure (deg).
836 * @param[in] armmax Maximum Angular Resolution Measure (deg).
837 * @return Content in cone.
838 *
839 * Compute the sum of the DRI bins within an event cone with apex at a given
840 * sky direction. All bins with an Angular Resolution Measure comprised
841 * between @p armmin (inclusive) and @p armmax (exclusive) will be
842 * considered. The bin centres will be used for the computation of the
843 * Angular Resolution Measure. The Angular Resolution Measure is defined as
844 * phibar - phigeo.
845 ***************************************************************************/
847 const double& armmin,
848 const double& armmax) const
849{
850 // Initialise content
851 double content = 0.0;
852
853 // Create Phigeo map in degrees
854 GSkyMap phigeo = m_dri.extract(0);
855 for (int i = 0; i < phigeo.npix(); ++i) {
856 phigeo(i) = dir.dist_deg(phigeo.inx2dir(i));
857 }
858
859 // Loop over phibar layers
860 for (int iphibar = 0; iphibar < this->nphibar(); ++iphibar) {
861
862 // Compute phibar
863 double phibar = this->phimin() + (iphibar+0.5) * this->phibin();
864
865 // Compute index offset
866 int offset = iphibar * phigeo.npix();
867
868 // Loop over bins in phibar layer
869 for (int i = 0; i < phigeo.npix(); ++i) {
870
871 // Compute ARM
872 double arm = phibar - phigeo(i);
873
874 // If ARM is within specified interval then add bin content
875 if (arm >= armmin && arm < armmax) {
876 content += (*this)[i + offset];
877 }
878
879 } // endfor: looped over bins in phibar layers
880
881 } // endfor: looped over phibar layers
882
883 // Return content
884 return content;
885}
886
887
888/***********************************************************************//**
889 * @brief Load COMPTEL Data Space from DRI FITS file
890 *
891 * @param[in] filename DRI FITS file name.
892 ***************************************************************************/
893void GCOMDri::load(const GFilename& filename)
894{
895 // Open FITS file
896 GFits fits(filename);
897
898 // Get HDU (pointer is always valid)
899 const GFitsImage& hdu = *fits.image(0);
900
901 // Read DRI file
902 read(hdu);
903
904 // Close FITS file
905 fits.close();
906
907 // Return
908 return;
909}
910
911
912/***********************************************************************//**
913 * @brief Save COMPTEL Data Space into DRI FITS file
914 *
915 * @param[in] filename DRI FITS file name.
916 * @param[in] clobber Overwrite existing file?
917 ***************************************************************************/
918void GCOMDri::save(const GFilename& filename, const bool& clobber) const
919{
920 // Create FITS file
921 GFits fits;
922
923 // Write data space into FITS file
924 write(fits, filename.extname(gammalib::extname_dri));
925
926 // Save FITS file
927 fits.saveto(filename, clobber);
928
929 // Close FITS file
930 fits.close();
931
932 // Return
933 return;
934}
935
936
937/***********************************************************************//**
938 * @brief Read COMPTEL Data Space from DRI FITS image
939 *
940 * @param[in] image DRI FITS image.
941 ***************************************************************************/
942void GCOMDri::read(const GFitsImage& image)
943{
944 // Clear
945 clear();
946
947 // Read sky map
948 m_dri.read(image);
949
950 // Correct WCS projection (HEASARC data format kluge)
952
953 // Read attributes
954 read_attributes(&image);
955
956 // Return
957 return;
958}
959
960
961/***********************************************************************//**
962 * @brief Write COMPTEL Data Space into FITS image
963 *
964 * @param[in] fits FITS file.
965 * @param[in] extname Extension name.
966 ***************************************************************************/
967void GCOMDri::write(GFits& fits, const std::string& extname) const
968{
969 // Write sky map into FITS file
970 GFitsHDU *image = m_dri.write(fits, extname);
971
972 // Write DRI attributes
973 if (image != NULL) {
974 write_attributes(image);
975 }
976
977 // Return
978 return;
979}
980
981
982/***********************************************************************//**
983 * @brief Print COMPTEL Data Space
984 *
985 * @param[in] chatter Chattiness.
986 * @return String containing COMPTEL Data Space information.
987 ***************************************************************************/
988std::string GCOMDri::print(const GChatter& chatter) const
989{
990 // Initialise result string
991 std::string result;
992
993 // Continue only if chatter is not silent
994 if (chatter != SILENT) {
995
996 // Compute scatter angle dimensions
997 double chimin = 0.0;
998 double chimax = 0.0;
999 double chibin = 0.0;
1000 double psimin = 0.0;
1001 double psimax = 0.0;
1002 double psibin = 0.0;
1003 const GWcs* wcs = dynamic_cast<const GWcs*>(m_dri.projection());
1004 if (wcs != NULL) {
1005 chibin = wcs->cdelt(0);
1006 chimin = wcs->crval(0) - (wcs->crpix(0)-0.5) * chibin;
1007 chimax = chimin + m_dri.nx() * chibin;
1008 psibin = wcs->cdelt(1);
1009 psimin = wcs->crval(1) - (wcs->crpix(1)-0.5) * psibin;
1010 psimax = psimin + m_dri.ny() * psibin;
1011 }
1012
1013 // Compute Phibar maximum
1014 double phimax = m_phimin + m_dri.nmaps() * m_phibin;
1015
1016 // Append header
1017 result.append("=== GCOMDri ===");
1018
1019 // Append Phibar information
1020 result.append("\n"+gammalib::parformat("Chi range"));
1021 result.append(gammalib::str(chimin)+" - ");
1022 result.append(gammalib::str(chimax)+" deg");
1023 result.append("\n"+gammalib::parformat("Chi bin size"));
1024 result.append(gammalib::str(chibin)+" deg");
1025 result.append("\n"+gammalib::parformat("Psi range"));
1026 result.append(gammalib::str(psimin)+" - ");
1027 result.append(gammalib::str(psimax)+" deg");
1028 result.append("\n"+gammalib::parformat("Psi bin size"));
1029 result.append(gammalib::str(psibin)+" deg");
1030 result.append("\n"+gammalib::parformat("Phibar range"));
1031 result.append(gammalib::str(m_phimin)+" - ");
1032 result.append(gammalib::str(phimax)+" deg");
1033 result.append("\n"+gammalib::parformat("Phibar bin size"));
1034 result.append(gammalib::str(m_phibin)+" deg");
1035 if (m_tofcor > 1.0) {
1036 result.append("\n"+gammalib::parformat("ToF correction"));
1037 result.append(gammalib::str(m_tofcor));
1038 }
1039
1040 // Append energy boundaries
1041 result.append("\n"+m_ebounds.print(gammalib::reduce(chatter)));
1042
1043 // Append GTI
1044 result.append("\n"+m_gti.print(gammalib::reduce(chatter)));
1045
1046 // EXPLICIT: Append sky map
1047 if (chatter >= EXPLICIT) {
1048 result.append("\n"+m_dri.print(gammalib::reduce(chatter)));
1049 }
1050
1051 // Append computation statistics
1052 result.append("\n"+gammalib::parformat("Input superpackets"));
1053 result.append(gammalib::str(m_num_superpackets));
1054 result.append("\n"+gammalib::parformat("Used superpackets"));
1055 result.append(gammalib::str(m_num_used_superpackets));
1056 result.append("\n"+gammalib::parformat("Skipped superpackets"));
1058
1059 // Append selection
1060 if (m_has_selection) {
1061 result.append("\n"+m_selection.print(gammalib::reduce(chatter)));
1062 }
1063
1064 } // endif: chatter was not silent
1065
1066 // Return result
1067 return result;
1068}
1069
1070
1071/*==========================================================================
1072 = =
1073 = Private methods =
1074 = =
1075 ==========================================================================*/
1076
1077/***********************************************************************//**
1078 * @brief Initialise class members
1079 ***************************************************************************/
1081{
1082 // Initialise members
1083 m_name.clear();
1084 m_dri.clear();
1085 m_ebounds.clear();
1086 m_gti.clear();
1087 m_phimin = 0.0;
1088 m_phibin = 0.0;
1089 m_tofcor = 1.0;
1090 m_phasecor = 1.0;
1091
1092 // Initialise statistics
1094
1095 // Initialise selection parameters
1096 m_has_selection = false;
1098 m_zetamin = -90.0; // Signals no selection
1099
1100 // Return
1101 return;
1102}
1103
1104
1105/***********************************************************************//**
1106 * @brief Copy class members
1107 *
1108 * @param[in] dri COMPTEL Data Space.
1109 ***************************************************************************/
1111{
1112 // Copy members
1113 m_name = dri.m_name;
1114 m_dri = dri.m_dri;
1115 m_ebounds = dri.m_ebounds;
1116 m_gti = dri.m_gti;
1117 m_phimin = dri.m_phimin;
1118 m_phibin = dri.m_phibin;
1119 m_tofcor = dri.m_tofcor;
1120 m_phasecor = dri.m_phasecor;
1121
1122 // Copy statistics
1123 m_tstart = dri.m_tstart;
1124 m_tstop = dri.m_tstop;
1128
1129 // Copy selection parameters
1132 m_zetamin = dri.m_zetamin;
1133
1134 // Return
1135 return;
1136}
1137
1138
1139/***********************************************************************//**
1140 * @brief Delete class members
1141 ***************************************************************************/
1143{
1144 // Return
1145 return;
1146}
1147
1148
1149/***********************************************************************//**
1150 * @brief Initialise DRI cube
1151 *
1152 * Sets all DRI cube bins to zero.
1153 ***************************************************************************/
1155{
1156 // Set all cube bins to zero
1157 for (int i = 0; i < size(); ++i) {
1158 (*this)[i] = 0.0;
1159 }
1160
1161 // Return
1162 return;
1163}
1164
1165
1166/***********************************************************************//**
1167 * @brief Initialise computation statistics
1168 ***************************************************************************/
1170{
1171 // Initialise statistics
1172 m_tstart.clear();
1173 m_tstop.clear();
1177
1178 // Return
1179 return;
1180}
1181
1182
1183/***********************************************************************//**
1184 * @brief Check if superpacket should be used
1185 *
1186 * @param[in] oad Orbit Aspect Data record (i.e. superpacket).
1187 * @param[in] tim Good Time Intervals.
1188 * @param[in] select Selection set.
1189 * @return True if superpacket should be used, false otherwise.
1190 *
1191 * Checks if a superpacket should be used. A superpacket will be used if
1192 * it is fully enclosed within the COMPTEL Good Time Intervals and the
1193 * Good Time Intervals of the DRI dataset. In case that orbital phases are
1194 * present in the selection set, the superpacket will be used when the start
1195 * time is comprised in one of the orbital phases.
1196 *
1197 * The method updates the superpacket statistics and selected time interval.
1198 ***************************************************************************/
1200 const GCOMTim& tim,
1201 const GCOMSelection& select)
1202{
1203 // Initialise usage flag
1204 bool use = true;
1205
1206 // Increment superpacket counter
1208
1209 // Skip superpacket if it is not fully enclosed within the COMPTEL
1210 // Good Time Intervals
1211 if (!(tim.contains(oad.tstart()) && tim.contains(oad.tstop()))) {
1213 use = false;
1214 }
1215
1216 // Skip superpacket if it is not fully enclosed within the DRI Good
1217 // Time Intervals. Only check if there are Good Time Intervals in the
1218 // DRI.
1219 else if ((m_gti.size() > 0) &&
1220 !(m_gti.contains(oad.tstart()) && m_gti.contains(oad.tstop()))) {
1222 use = false;
1223 }
1224
1225 // If there are phase intervals then skip if superpacket is the phase
1226 // corresponding to the start time does not fall into any of the phase
1227 // intervals
1228 else if (!select.orbital_phases().is_empty()) {
1229 double phase = select.orbital_phase(oad.tstart());
1230 if (select.orbital_phases().contains(phase)) {
1232 }
1233 else {
1235 use = false;
1236 }
1237 }
1238
1239 // ... otherwise use superpacket
1240 else {
1242 }
1243
1244 // Update selection validity interval
1245 if (m_num_used_superpackets == 1) {
1246 m_tstart = oad.tstart();
1247 m_tstop = oad.tstop();
1248 }
1249 else {
1250 m_tstop = oad.tstop();
1251 }
1252
1253 // Return usage
1254 return use;
1255}
1256
1257
1258/***********************************************************************//**
1259 * @brief Read DRI attributes from FITS HDU
1260 *
1261 * @param[in] hdu FITS HDU pointer.
1262 *
1263 * Reads the time interval from the FITS header and sets the Phibar definiton
1264 * and energy boundaries from the header keywords if they are provided.
1265 ***************************************************************************/
1267{
1268 // Get time attributes
1269 GTime tstart = gammalib::com_time(hdu->integer("VISDAY"), hdu->integer("VISTIM"));
1270 GTime tstop = gammalib::com_time(hdu->integer("VIEDAY"), hdu->integer("VIETIM"));
1271
1272 // Set Good Time Intervals
1273 if (tstop > tstart) {
1274 m_gti = GGti(tstart, tstop);
1275 }
1276
1277 // Optionally read Phibar attributes
1278 if (hdu->has_card("CDELT3") &&
1279 hdu->has_card("CRVAL3") &&
1280 hdu->has_card("CRPIX3")) {
1281
1282 // Get phibar attributes
1283 m_phibin = hdu->real("CDELT3");
1284 m_phimin = hdu->real("CRVAL3") - (hdu->real("CRPIX3")-0.5) * m_phibin;
1285
1286 }
1287
1288 // ... otherwise set Phibar attributes to zero
1289 else {
1290 m_phimin = 0.0;
1291 m_phibin = 0.0;
1292 }
1293
1294 // Optionally read energy attributes
1295 if (hdu->has_card("E_MIN") && hdu->has_card("E_MAX")) {
1296
1297 // Get energy attributes
1298 GEnergy emin(hdu->real("E_MIN"), "MeV");
1299 GEnergy emax(hdu->real("E_MAX"), "MeV");
1300
1301 // Set energy boundaries
1302 m_ebounds = GEbounds(emin, emax);
1303
1304 }
1305
1306 // ... otherwise clear energy boundaries
1307 else {
1308 m_ebounds.clear();
1309 }
1310
1311 // Read selection set
1312 m_selection.read(*hdu);
1313
1314 // Signal if selected set keywords were present. For simplicity we just
1315 // search for the first keyword
1316 if (hdu->has_card("D1EMIN")) {
1317 m_has_selection = true;
1318 }
1319
1320 // Optionally read Earth horizon cut
1321 if (hdu->has_card("EHAMIN")) {
1322 m_zetamin = hdu->real("EHAMIN");
1323 }
1324
1325 // Optionally read ToF correction
1326 if (hdu->has_card("TOFCOR")) {
1327 m_tofcor = hdu->real("TOFCOR");
1328 }
1329
1330 // Optionally read pulsar phase correction
1331 if (hdu->has_card("PHASECOR")) {
1332 m_phasecor = hdu->real("PHASECOR");
1333 }
1334
1335 // Optionally read superpacket statistics
1336 if (hdu->has_card("NSPINP")) {
1337 m_num_superpackets = hdu->integer("NSPINP");
1338 }
1339 if (hdu->has_card("NSPUSE")) {
1340 m_num_used_superpackets = hdu->integer("NSPUSE");
1341 }
1342 if (hdu->has_card("NSPSKP")) {
1343 m_num_skipped_superpackets = hdu->integer("NSPSKP");
1344 }
1345
1346 // Return
1347 return;
1348}
1349
1350
1351/***********************************************************************//**
1352 * @brief Write DRI attributes into FITS HDU
1353 *
1354 * @param[in] hdu FITS HDU pointer.
1355 ***************************************************************************/
1357{
1358 // Write 3rd dimension keywords in case that a third dimension exists.
1359 // This avoids writing a Phibar layer for DRX.
1360 if (m_phibin > 0.0) {
1361
1362 // Set Phibar keywords
1363 double crval3 = m_phimin + 0.5 * m_phibin;
1364
1365 // Write Phibar keywords
1366 hdu->card("CTYPE3", "Phibar", "Compton scatter angle");
1367 hdu->card("CRPIX3", 1.0, "Pixel coordinate of reference point (starting from 1)");
1368 hdu->card("CRVAL3", crval3, "[deg] Coordinate value at reference point");
1369 hdu->card("CDELT3", m_phibin, "[deg] Coordinate increment at reference point");
1370
1371 } // endif: DRI was 3D
1372
1373 // Write OGIP time keywords
1374 m_gti.reference().write(*hdu);
1375 hdu->card("TSTART", m_gti.tstart().secs(), "[s] Start time");
1376 hdu->card("TSTOP", m_gti.tstop().secs(), "[s] Stop time");
1377 hdu->card("DATE-OBS", m_gti.tstart().utc(), "Start of observation in UTC");
1378 hdu->card("DATE-END", m_gti.tstop().utc(), "Stop of observation in UTC");
1379
1380 // Set time keywords
1381 int visday = gammalib::com_tjd(m_gti.tstart());
1382 int vistim = gammalib::com_tics(m_gti.tstart());
1383 int vieday = gammalib::com_tjd(m_gti.tstop());
1384 int vietim = gammalib::com_tics(m_gti.tstop());
1385
1386 // Write COMPTEL time keywords
1387 hdu->card("VISDAY", visday, "[TJD] Data validity interval start day");
1388 hdu->card("VISTIM", vistim, "[tics] Data validity interval start time");
1389 hdu->card("VIEDAY", vieday, "[TJD] Data validity interval end day");
1390 hdu->card("VIETIM", vietim, "[tics] Data validity interval end time");
1391
1392 // If there are energy boundaries then write them
1393 if (m_ebounds.size() > 0) {
1394 hdu->card("E_MIN", m_ebounds.emin().MeV(), "[MeV] Lower bound of energy range");
1395 hdu->card("E_MAX", m_ebounds.emax().MeV(), "[MeV] Upper bound of energy range");
1396 }
1397
1398 // If there was an event seletion then write selection set. Otherwise write
1399 // handling D1 and D2 module usage and handling mode of D2 PMT failures.
1400 if (m_has_selection) {
1401 m_selection.write(*hdu);
1402 }
1403 else {
1404
1405 // Write D2 PMT failure handling flag
1406 hdu->card("D2FPMT", m_selection.fpmtflag(), "D2 PMT failure handling");
1407
1408 // Write D1 module usage
1409 std::string d1use = "0000000";
1410 for (int i = 0; i < 7; ++i) {
1411 if (m_selection.use_d1(i)) {
1412 d1use[i] = '1';
1413 }
1414 }
1415 hdu->card("D1USE", d1use, "D1 module usage");
1416
1417 // Write D2 module usage
1418 std::string d2use = "00000000000000";
1419 for (int i = 0; i < 14; ++i) {
1420 if (m_selection.use_d2(i)) {
1421 d2use[i] = '1';
1422 }
1423 }
1424 hdu->card("D2USE", d2use, "D2 module usage");
1425
1426 }
1427
1428 // If there was a valid Earth horizon cut then write it
1429 if (m_zetamin != -90.0) {
1430 hdu->card("EHAMIN", m_zetamin, "[deg] Minimum Earth horizon - Phibar cut");
1431 }
1432
1433 // If there is a ToF correction then write it
1434 if (m_tofcor > 1.0) {
1435 hdu->card("TOFCOR", m_tofcor, "ToF correction");
1436 }
1437
1438 // If there is a pulsar phase correction then write it
1439 if (m_phasecor < 1.0) {
1440 hdu->card("PHASECOR", m_phasecor, "Pulsar phase correction");
1441 }
1442
1443 // Write superpacket statistics
1444 hdu->card("NSPINP", m_num_superpackets, "Number of input superpackets");
1445 hdu->card("NSPUSE", m_num_used_superpackets, "Number of used superpackets");
1446 hdu->card("NSPSKP", m_num_skipped_superpackets, "Number of skipped superpackets");
1447
1448 // Return
1449 return;
1450}
1451
1452
1453/***********************************************************************//**
1454 * @brief Compute DRG geometry factor
1455 *
1456 * @param[in] tjd TJD for module status
1457 * @param[in] theta Zenith angle in COMPTEL coordinates (deg).
1458 * @param[in] phi Azimuth angle in COMPTEL coordinates (deg).
1459 * @param[in] select Selection set.
1460 * @param[in] status D1 and D2 module status
1461 * @return Geometry factor.
1462 *
1463 * Computes the DRG geometry factor as function of zenith and azimuth angles
1464 * given in the COMPTEL coordinate system.
1465 ***************************************************************************/
1466double GCOMDri::compute_geometry(const int& tjd,
1467 const double& theta,
1468 const double& phi,
1469 const GCOMSelection& select,
1470 const GCOMStatus& status) const
1471{
1472 // Set D1 module positions (from COM-RP-MPE-M10-123, Issue 1, Page 3-3)
1473 const double xd1[] = {0.0,-42.3,-26.0,26.0, 42.3,26.0,-26.0};
1474 const double yd1[] = {0.0, 0.0, 39.1,39.1, 0.0,-39.1,-39.1};
1475
1476 // Set D2 module positions (from COM-RP-MPE-M10-123, Issue 1, Page 4-4)
1477 const double xd2[] = { 30.2, 0.0, -30.2, 45.3, 15.1, -15.1, -45.3,
1478 45.3, 15.1, -15.1, -45.3, 30.2, 0.0, -30.2};
1479 const double yd2[] = {-41.254,-41.254,-41.254,-15.1, -15.1, -15.1, -15.1,
1480 15.1, 15.1, 15.1 , 15.1, 41.254,41.254,41.254};
1481
1482 // Set distance between D1 and D2 levels in cm (from COM-SP-MPE-M10-123,
1483 // Issue 1, page 8-5
1484 const double delz = 158.0;
1485
1486 // Set D1 module radius in cm (from COM-TN-UNH-F70-051)
1487 //const double r1 = 13.8; // Defined globally
1488
1489 // Set D2 module radius in cm (from SIM-AL-005)
1490 const double r2 = 14.085;
1491
1492 // Derive some constants
1493 //const double r1sq = r1 * r1; // Defined globally
1494 const double r2sq = r2 * r2;
1495 const double drsq = r1sq - r2sq;
1496 const double norm_geo = 1.0 / (gammalib::pi * r1sq);
1497
1498 // Initialise geometry factor
1499 double geometry = 0.0;
1500
1501 // Precompute results
1502 double theta_rad = theta * gammalib::deg2rad;
1503 double phi_rad = phi * gammalib::deg2rad;
1504 double cosphi = std::cos(phi_rad);
1505 double sinphi = std::sin(phi_rad);
1506 double tantheta = std::tan(theta_rad);
1507
1508 // Loop over all D1 modules
1509 for (int id1 = 0; id1 < 7; ++id1) {
1510
1511 // Skip D1 module if it's off
1512 if (status.d1status(tjd, id1+1) != 1) {
1513 continue;
1514 }
1515
1516 // Compute coordinates of D1 projected on D2 plane
1517 double xd1_prj = xd1[id1] - delz * tantheta * cosphi;
1518 double yd1_prj = yd1[id1] - delz * tantheta * sinphi;
1519
1520 // Loop over all D2 modules
1521 for (int id2 = 0; id2 < 14; ++id2) {
1522
1523 // Skip if coresponding modules should not be used
1524 if (!select.use_d1(id1) || !select.use_d2(id2)) {
1525 continue;
1526 }
1527
1528 // Get D2 module status
1529 int d2status = status.d2status(tjd, id2+1);
1530
1531 // Skip D2 module if it's off or if module has failed PMT and
1532 // should be excluded
1533 if ((d2status < 1) || ((d2status > 1) && (select.fpmtflag() == 0))) {
1534 continue;
1535 }
1536
1537 // Compute distance between center of D2 and projected centre
1538 // of D1
1539 double dx = xd2[id2] - xd1_prj;
1540 double dy = yd2[id2] - yd1_prj;
1541 double dsq = dx * dx + dy * dy;
1542 double d = std::sqrt(dsq);
1543
1544 // If there is no overlap then skip the module
1545 if (d >= r1 + r2) {
1546 continue;
1547 }
1548
1549 // If D2 modules has failed PMT, the failed PMT zone should be
1550 // excluded and the module has an exclusion radius then compute
1551 // now the overlap of the failure zone; if the module has no
1552 // exclusion radius then exclude the entire module.
1553 double overlap = 0.0;
1554 if ((d2status > 1) && (select.fpmtflag() == 2)) {
1555 double r = gammalib::com_exd2r(id2+1);
1556 if (r >= 0.1) {
1557 overlap = compute_overlap(xd1_prj, yd1_prj, r1,
1558 xd2[id2], yd2[id2], r2,
1559 gammalib::com_exd2x(id2+1),
1560 gammalib::com_exd2y(id2+1),
1561 r);
1562 }
1563 else {
1564 continue;
1565 }
1566 } // endif: handled D2 modules with failed PMTs
1567
1568 // If there is total overlap (within 0.1 cm) then add 1-overlap
1569 // to the geometry factor
1570 if (d <= r2 - r1 + 0.1) {
1571 double gmt = (1.0 > overlap) ? 1.0 - overlap : 0.0;
1572 geometry += gmt;
1573 }
1574
1575 // ... otherwise if there is a partial overlap then compute the
1576 // semiangle subtended by overlap sector of D2 and projected
1577 // D1 module
1578 else {
1579
1580 // Cosine beta
1581 double d2 = 2.0 * d;
1582 double cbeta1 = (dsq + drsq) / (d2 * r1);
1583 double cbeta2 = (dsq - drsq) / (d2 * r2);
1584
1585 // Sin beta
1586 double sbeta1 = std::sqrt(1.0 - cbeta1 * cbeta1);
1587 double sbeta2 = std::sqrt(1.0 - cbeta2 * cbeta2);
1588
1589 // Beta
1590 double beta1 = std::acos(cbeta1);
1591 double beta2 = std::acos(cbeta2);
1592
1593 // Projection
1594 double gmt = (r1sq * (beta1 - sbeta1 * cbeta1) +
1595 r2sq * (beta2 - sbeta2 * cbeta2)) * norm_geo -
1596 overlap;
1597 if (gmt < 0.0) {
1598 gmt = 0.0;
1599 }
1600 geometry += gmt;
1601
1602 } // endelse: there was partial overlap
1603
1604 } // endfor: looped over D2 modules
1605
1606 } // endfor: looped over D1 modules
1607
1608 // Now divide by 7 since we want the probability of hitting a given
1609 // D1 module
1610 geometry /= 7.0;
1611
1612 // Return geometry factor
1613 return geometry;
1614}
1615
1616
1617/***********************************************************************//**
1618 * @brief Compute surface of overlap between two circles
1619 *
1620 * @param[in] x1 X position of D2 module (cm).
1621 * @param[in] y1 Y position of D2 module (cm).
1622 * @param[in] r1 Radius D2 module (cm).
1623 * @param[in] x2 X position of dead PMT (cm).
1624 * @param[in] y2 Y position of dead PMT (cm).
1625 * @param[in] r2 Radius of dead PMT (cm).
1626 * @return Surface of overlap (cm^2)
1627 *
1628 * Computes the surface of overlap in cm^2 between two circles, composed of
1629 * D2 module and failed PMT exclusion circle.
1630 *
1631 * The method is a reimplementation of the COMPASS SKYDRS17.COM2 function.
1632 ***************************************************************************/
1633double GCOMDri::compute_surface(const double& x1, const double& y1, const double& r1,
1634 const double& x2, const double& y2, const double& r2) const
1635{
1636 // Initialise surface
1637 double surface = 0.0;
1638
1639 // Compute distance between center of D2 and failed PMT exclusion circle
1640 double dx = x1 - x2;
1641 double dy = y1 - y2;
1642 double dsq = dx * dx + dy * dy;
1643 double d = std::sqrt(dsq);
1644
1645 // If failed PMT exclusion circle is fully comprised within D2 then use
1646 // failed PMT exclusion circle surface as overlap
1647 if (r1 > (d+r2)) {
1648 surface = gammalib::pi * r2 * r2;
1649 }
1650
1651 // ... otherwise, if D2 module is fully comprised in failed PMT exclusion
1652 // circle then use D2 module surface as overlap. This case is only relevant
1653 // if the failed PMTs exclusion circle is larger than the D2 modules.
1654 else if (r2 > (d+r1)) {
1655 surface = gammalib::pi * r1 * r1;
1656 }
1657
1658 // ... otherwise if D2 module and failed PMT exclusion circle overlap then
1659 // compute the area of overlap
1660 else if (d < (r1+r2)) {
1661
1662 // Cosine beta
1663 double d2 = 2.0 * d;
1664 double r1sq = r1 * r1;
1665 double r2sq = r2 * r2;
1666 double cbeta1 = (r1sq - r2sq + dsq) / (d2 * r1);
1667 double cbeta2 = (r2sq - r1sq + dsq) / (d2 * r2);
1668
1669 // Sin beta
1670 double sbeta1 = std::sqrt(1.0 - cbeta1 * cbeta1);
1671 double sbeta2 = std::sqrt(1.0 - cbeta2 * cbeta2);
1672
1673 // Beta
1674 double beta1 = std::acos(cbeta1);
1675 double beta2 = std::acos(cbeta2);
1676
1677 // Compute surface
1678 surface = r1sq * (beta1 - sbeta1 * cbeta1) +
1679 r2sq * (beta2 - sbeta2 * cbeta2);
1680
1681 }
1682
1683 // Return
1684 return surface;
1685}
1686
1687
1688/***********************************************************************//**
1689 * @brief Compute overlap between three circles
1690 *
1691 * @param[in] x1 X position of D1 projection (cm).
1692 * @param[in] y1 Y position of D1 projection (cm).
1693 * @param[in] r1 Radius D1 module (cm).
1694 * @param[in] x2 X position of D2 module (cm).
1695 * @param[in] y2 Y position of D2 module (cm).
1696 * @param[in] r2 Radius D2 module (cm).
1697 * @param[in] x3 X position of dead PMT (cm).
1698 * @param[in] y3 Y position of dead PMT (cm).
1699 * @param[in] r3 Radius of dead PMT (cm).
1700 * @return Fractional overlap [0.0,...,1.0]
1701 *
1702 * Compute fractional overlap between three circles, composed of projected
1703 * D1 module, D2 module and failed PMT exclusion circle.
1704 *
1705 * The method is a reimplementation of the COMPASS SKYDRS17.OVERLP function.
1706 ***************************************************************************/
1707double GCOMDri::compute_overlap(const double& x1, const double& y1, const double& r1,
1708 const double& x2, const double& y2, const double& r2,
1709 const double& x3, const double& y3, const double& r3) const
1710{
1711 // Initialise constants
1712 const int steps = 25;
1713 const int size = steps*steps;
1714 static double o23_x[size];
1715 static double o23_y[size];
1716 static double last_x2 = 1.0e25;
1717 static double last_y2 = 1.0e25;
1718 static double last_x3 = 1.0e25;
1719 static double last_y3 = 1.0e25;
1720 static int no23 = 0;
1721
1722 // Initialise overlap
1723 double overlap = 0.0;
1724
1725 // Create single-pass loop so that method has a single exit point
1726 do {
1727
1728 // If there is no overlap between D1 module projection and D2 module
1729 // then return zero overlap
1730 double dx12 = x1 - x2;
1731 double dy12 = y1 - y2;
1732 double d12 = std::sqrt(dx12*dx12 + dy12*dy12);
1733 if (d12 > (r1+r2)) {
1734 continue;
1735 }
1736
1737 // If there is no overlap between D1 module and failed PMT exclusion
1738 // circle then return zero overlap
1739 double dx13 = x1 - x3;
1740 double dy13 = y1 - y3;
1741 double d13 = std::sqrt(dx13*dx13 + dy13*dy13);
1742 if (d13 > (r1+r3)) {
1743 continue;
1744 }
1745
1746 // If PMT exclusion circle is contained within D1 module projection
1747 // then the overlap is the overlap between D2 module and PMT
1748 // exclusion circle
1749 if (d13+r3 < r1) {
1750 overlap = compute_surface(x2, y2, r2, x3, y3, r3);
1751 continue;
1752 }
1753
1754 // Start integration over the smallest circle which is the PMT
1755 // exclusion circle. Since the D2 module circle and the PMT
1756 // exclusion circle do not change position too often, their overlap
1757 // will be kept in a table. Then only the changing position of the
1758 // D1 projection needs to be taken care of in the seperate calls
1759 // to the routine.
1760 double step = 2.0 * r3 / double(steps-3);
1761 double stepsq = step * step;
1762 double r1sq = r1 * r1;
1763 if ((last_x2 != x2) || (last_y2 != y2) || (last_x3 != x3) || (last_y3 != y3)) {
1764
1765 // Store positions
1766 last_x2 = x2;
1767 last_y2 = y2;
1768 last_x3 = x3;
1769 last_y3 = y3;
1770
1771 // Compute arrays o23_x and o23_y which hold all (x,y) positions
1772 // that overlap with the D2 module and the PMT exclusion circle
1773 double r2sq = r2 * r2;
1774 double r3sq = r3 * r3;
1775 no23 = 0;
1776 double yy = y3 - r3 - step;
1777 for (int i = 0; i < steps; ++i, yy += step) {
1778 double xx = x3 - r3 - step;
1779 for (int j = 0; j < steps; ++j, xx += step) {
1780 double dx3 = xx - x3;
1781 double dy3 = yy - y3;
1782 if (dx3*dx3 + dy3*dy3 < r3sq) {
1783 double dx2 = xx - x2;
1784 double dy2 = yy - y2;
1785 if (dx2*dx2 + dy2*dy2 < r2sq) {
1786 o23_x[no23] = xx;
1787 o23_y[no23] = yy;
1788 no23++;
1789 }
1790 }
1791 }
1792 }
1793
1794 } // endif: update required
1795
1796 // Now compute overlap by checking all (x,y) positions that overlap
1797 // with the D2 module and the PMT exclusion circle
1798 for (int i = 0; i < no23; ++i) {
1799 double dx1 = o23_x[i] - x1;
1800 double dy1 = o23_y[i] - y1;
1801 if (dx1*dx1 + dy1*dy1 < r1sq) {
1802 overlap += stepsq;
1803 }
1804 }
1805
1806 } while(false);
1807
1808 // Finally divide by the D1 module area to get the fractional overlap
1809 if (overlap > 0.0) {
1810 overlap /= (gammalib::pi * r1sq);
1811 }
1812
1813 // Return
1814 return overlap;
1815}
1816
1817
1818/***********************************************************************//**
1819 * @brief Compute ToF correction
1820 *
1821 * Compute the ToF correction according to COM-RP-ROL-DRG-057.
1822 ***************************************************************************/
1824{
1825 // ToF correction factors according to Table 1 of COM-RP-ROL-DRG-057
1826 const double tofcoreng[] = {0.8660, 1.7321, 5.4772, 17.3205};
1827 const double tofcor110[] = {1.14, 1.07, 1.02, 1.01};
1828 const double tofcor111[] = {1.17, 1.09, 1.03, 1.01};
1829 const double tofcor112[] = {1.21, 1.11, 1.05, 1.02};
1830 const double tofcor113[] = {1.26, 1.15, 1.07, 1.04};
1831 const double tofcor114[] = {1.32, 1.20, 1.11, 1.06};
1832 const double tofcor115[] = {1.40, 1.27, 1.17, 1.11};
1833 const double tofcor116[] = {1.50, 1.36, 1.24, 1.17};
1834 const double tofcor117[] = {1.63, 1.47, 1.35, 1.28};
1835 const double tofcor118[] = {1.79, 1.63, 1.51, 1.43};
1836 const double tofcor119[] = {2.01, 1.85, 1.73, 1.67};
1837 const double* tofcor[] = {tofcor110, tofcor111, tofcor112,
1838 tofcor113, tofcor114, tofcor115,
1839 tofcor116, tofcor117, tofcor118,
1840 tofcor119};
1841
1842 // Determine ToF correction
1843 if (m_selection.tof_min() < 110) {
1844 std::string msg = "Minimum of ToF selection window "+
1846 " is smaller than 110. No ToF correction is "
1847 "available for this value.";
1849 }
1850 else if (m_selection.tof_min() > 119) {
1851 std::string msg = "Minimum of ToF selection window "+
1853 " is larger than 119. No ToF correction is "
1854 "available for this value.";
1856 }
1857 else if (m_selection.tof_max() != 130) {
1858 std::string msg = "Maximum of ToF selection window "+
1860 " is not 130. No ToF correction is available for "
1861 "this value.";
1863 }
1864 else {
1865
1866 // Compute mean energy of DRE
1867 double energy = std::sqrt(m_ebounds.emin().MeV() *
1868 m_ebounds.emax().MeV());
1869
1870 // Set node array
1871 GNodeArray nodes(4, tofcoreng);
1872
1873 // Set interpolation value
1874 nodes.set_value(energy);
1875
1876 // Get ToF correction index
1877 int i = m_selection.tof_min() - 110;
1878
1879 // Interpolate
1880 m_tofcor = tofcor[i][nodes.inx_left()] * nodes.wgt_left() +
1881 tofcor[i][nodes.inx_right()] * nodes.wgt_right();
1882
1883 }
1884
1885 // Return
1886 return;
1887}
#define G_COMPUTE_TOF_CORRECTION
Definition GCOMDri.cpp:59
const double r1sq
Definition GCOMDri.cpp:76
const double r1
Definition GCOMDri.cpp:73
const double d1_area
Definition GCOMDri.cpp:77
const double superpacket_duration
Definition GCOMDri.cpp:72
#define G_COMPUTE_DRE
Definition GCOMDri.cpp:54
COMPTEL Data Space class definition.
COMPTEL event list class definition.
COMPTEL Orbit Aspect Data class definition.
COMPTEL Orbit Aspect Data container class definition.
COMPTEL observation class interface definition.
COMPTEL selection set class definition.
COMPTEL instrument status class definition.
Implementation of support function used by COMPTEL classes.
COMPTEL Good Time Intervals class definition.
Definition of COMPTEL tools.
Ephemerides class definition.
Abstract FITS image base class definition.
FITS file class interface definition.
Mathematical function definitions.
Sky model class interface definition.
Point source spatial model class interface definition.
Abstract spatial model base class interface definition.
Node array class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ EXPLICIT
Definition GTypemaps.hpp:37
@ SILENT
Definition GTypemaps.hpp:34
double norm(const GVector &vector)
Computes vector norm.
Definition GVector.cpp:864
Abstract world coordinate system base class definition.
bool is_empty(void) const
Signals if there are no Solar System Barycentre Data in container.
Definition GCOMBvcs.hpp:163
double tdelta(const GSkyDir &dir, const GTime &time) const
Return time difference between photon arrival time at CGRO and the Solar System Barycentre (SSB)
Definition GCOMBvcs.cpp:564
COMPTEL Data Space class.
Definition GCOMDri.hpp:61
void init_statistics(void)
Initialise computation statistics.
Definition GCOMDri.cpp:1169
virtual void clear(void)
Clear COMPTEL Data Space.
Definition GCOMDri.cpp:228
GCOMDri & operator=(const GCOMDri &dri)
Assignment operator.
Definition GCOMDri.cpp:198
int m_num_skipped_superpackets
Number of skipped superpackets.
Definition GCOMDri.hpp:166
void save(const GFilename &filename, const bool &clobber=false) const
Save COMPTEL Data Space into DRI FITS file.
Definition GCOMDri.cpp:918
double compute_overlap(const double &x1, const double &y1, const double &r1, const double &x2, const double &y2, const double &r2, const double &x3, const double &y3, const double &r3) const
Compute overlap between three circles.
Definition GCOMDri.cpp:1707
virtual GCOMDri * clone(void) const
Clone COMPTEL Data Space.
Definition GCOMDri.cpp:246
int nchi(void) const
Return number of Chi bins.
Definition GCOMDri.hpp:231
void compute_drm(const GCOMObservation &obs, const GModel &model)
Compute DRM model.
Definition GCOMDri.cpp:810
double m_phibin
Phibar binsize (deg)
Definition GCOMDri.hpp:157
double m_phasecor
Pulsar phase correction.
Definition GCOMDri.hpp:159
void write_attributes(GFitsHDU *hdu) const
Write DRI attributes into FITS HDU.
Definition GCOMDri.cpp:1356
GTime m_tstart
Selection start time.
Definition GCOMDri.hpp:162
virtual ~GCOMDri(void)
Destructor.
Definition GCOMDri.cpp:176
double compute_surface(const double &x1, const double &y1, const double &r1, const double &x2, const double &y2, const double &r2) const
Compute surface of overlap between two circles.
Definition GCOMDri.cpp:1633
void free_members(void)
Delete class members.
Definition GCOMDri.cpp:1142
GGti m_gti
Good Time Intervals of data cube.
Definition GCOMDri.hpp:155
int m_num_used_superpackets
Number of used superpackets.
Definition GCOMDri.hpp:165
void compute_drx(const GCOMObservation &obs, const GCOMSelection &select=GCOMSelection())
Compute DRX exposure map.
Definition GCOMDri.cpp:703
void compute_drg(const GCOMObservation &obs, const GCOMSelection &select=GCOMSelection(), const double &zetamin=5.0)
Compute geometry cube.
Definition GCOMDri.cpp:558
void compute_tof_correction(void)
Compute ToF correction.
Definition GCOMDri.cpp:1823
double compute_geometry(const int &tjd, const double &theta, const double &phi, const GCOMSelection &select, const GCOMStatus &status) const
Compute DRG geometry factor.
Definition GCOMDri.cpp:1466
void init_members(void)
Initialise class members.
Definition GCOMDri.cpp:1080
const double & phibin(void) const
Return Compton scatter angle bin of DRI cube.
Definition GCOMDri.hpp:372
void init_cube(void)
Initialise DRI cube.
Definition GCOMDri.cpp:1154
void load(const GFilename &filename)
Load COMPTEL Data Space from DRI FITS file.
Definition GCOMDri.cpp:893
const GSkyMap & map(void) const
Return DRI sky map.
Definition GCOMDri.hpp:267
double m_zetamin
Minimum zeta angle.
Definition GCOMDri.hpp:171
const double & phimin(void) const
Return minimum Compton scatter angle of DRI cube.
Definition GCOMDri.hpp:360
GCOMDri(void)
Void constructor.
Definition GCOMDri.cpp:89
virtual std::string print(const GChatter &chatter=NORMAL) const
Print COMPTEL Data Space.
Definition GCOMDri.cpp:988
GSkyMap m_dri
Data cube.
Definition GCOMDri.hpp:153
GCOMSelection m_selection
Selection parameters.
Definition GCOMDri.hpp:170
GEbounds m_ebounds
Energy boundaries of data cube.
Definition GCOMDri.hpp:154
int npsi(void) const
Return number of Psi bins.
Definition GCOMDri.hpp:243
double m_phimin
Phibar minimum (deg)
Definition GCOMDri.hpp:156
void compute_dre(const GCOMObservation &obs, const GCOMSelection &select=GCOMSelection(), const double &zetamin=5.0)
Compute event cube.
Definition GCOMDri.cpp:266
std::string m_name
Data cube name.
Definition GCOMDri.hpp:152
GTime m_tstop
Selection stop time.
Definition GCOMDri.hpp:163
int size(void) const
Return number of bins.
Definition GCOMDri.hpp:219
int m_num_superpackets
Number of superpackets.
Definition GCOMDri.hpp:164
bool use_superpacket(const GCOMOad &oad, const GCOMTim &tim, const GCOMSelection &select)
Check if superpacket should be used.
Definition GCOMDri.cpp:1199
bool m_has_selection
Signal that selection was applied.
Definition GCOMDri.hpp:169
void read_attributes(const GFitsHDU *hdu)
Read DRI attributes from FITS HDU.
Definition GCOMDri.cpp:1266
void write(GFits &fits, const std::string &extname="") const
Write COMPTEL Data Space into FITS image.
Definition GCOMDri.cpp:967
double m_tofcor
ToF correction.
Definition GCOMDri.hpp:158
int nphibar(void) const
Return number of Phibar bins.
Definition GCOMDri.hpp:255
void read(const GFitsImage &image)
Read COMPTEL Data Space from DRI FITS image.
Definition GCOMDri.cpp:942
void copy_members(const GCOMDri &dri)
Copy class members.
Definition GCOMDri.cpp:1110
double cone_content(const GSkyDir &dir, const double &armmin, const double &armmax) const
Compute content in cone.
Definition GCOMDri.cpp:846
COMPTEL event atom class.
COMPTEL event list class.
virtual int size(void) const
Return number of events in list.
COMPTEL Orbit Aspect Data class.
Definition GCOMOad.hpp:49
const int & tjd(void) const
Return Truncated Julian Days of Orbit Aspect Record.
Definition GCOMOad.hpp:193
double theta(const GSkyDir &sky) const
Return zenith angle of sky direction in COMPTEL coordinates.
Definition GCOMOad.hpp:428
const float & gcaz(void) const
Return Geocentre azimuth angle.
Definition GCOMOad.hpp:251
const GTime & tstart(void) const
Return start time of superpacket.
Definition GCOMOad.hpp:133
const float & gcel(void) const
Return Geocentre zenith angle.
Definition GCOMOad.hpp:280
const float & georad(void) const
Return apparent radius of Earth.
Definition GCOMOad.hpp:309
const GTime & tstop(void) const
Return stop time of superpacket.
Definition GCOMOad.hpp:164
const GVector & pos(void) const
Return telescope position vector (km)
Definition GCOMOad.hpp:398
double phi(const GSkyDir &sky) const
Return azimuth angle of sky direction in COMPTEL coordinates.
Definition GCOMOad.hpp:443
Interface class for COMPTEL observations.
const GCOMTim & tim(void) const
Return COMPTEL Good Time Intervals.
const GCOMOads & oads(void) const
Return Orbit Aspect Data.
const GCOMBvcs & bvcs(void) const
Return Solar System Barycentre Data.
COMPTEL selection set class.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print COMPTEL selection set.
const int & tof_min(void) const
Return minimum of ToF selection window.
const int & fpmtflag(void) const
Return failed PMT flag for D2 modules.
void read(const GFitsHDU &hdu)
Read selection set from FITS HDU keywords.
void write(GFitsHDU &hdu) const
Write selection set keywords into FITS HDU.
bool has_pulsar(void) const
Signals that pulsar selection should be performed.
bool use_event(const GCOMEventAtom &event) const
Check if event should be used.
double orbital_phase(const GTime &time) const
Return orbital phase for a given time.
void init_statistics(void) const
Initialise selection statistics.
const int & tof_max(void) const
Return maximum of ToF selection window.
const GPhases & pulsar_phases(void) const
Return pulsar phases.
const bool & use_d1(const int &id1) const
Return D1 module usage flag.
const bool & use_d2(const int &id2) const
Return D2 module usage flag.
virtual void clear(void)
Clear COMPTEL selection set.
const GPhases & orbital_phases(void) const
Return orbital phases.
const GPulsar & pulsar(void) const
Return pulsar.
COMPTEL instrument status class.
int d2status(const int &tjd, const int &module) const
Return D2 module status.
int d1status(const int &tjd, const int &module) const
Return D1 module status.
COMPTEL Good Time Intervals class.
Definition GCOMTim.hpp:50
void reduce(const GGti &gti)
Reduces Good Time Intervals to intersection with intervals.
Definition GCOMTim.hpp:129
bool contains(const GTime &time) const
Check if time is comprised in the Good Time Intervals.
Definition GCOMTim.hpp:114
Energy boundaries container class.
Definition GEbounds.hpp:60
const GEnergy & emax(void) const
Return maximum energy of all intervals.
Definition GEbounds.hpp:199
std::string print(const GChatter &chatter=NORMAL) const
Print energy boundaries.
int size(void) const
Return number of energy boundaries.
Definition GEbounds.hpp:163
void clear(void)
Clear energy boundaries.
Definition GEbounds.cpp:268
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition GEbounds.hpp:187
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:321
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
std::string extname(const std::string &defaultname="") const
Return extension name.
Abstract FITS extension base class.
Definition GFitsHDU.hpp:51
bool has_card(const int &cardno) const
Check existence of header card.
Definition GFitsHDU.hpp:233
double real(const std::string &keyname) const
Return card value as double precision.
Definition GFitsHDU.hpp:423
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition GFitsHDU.hpp:259
int integer(const std::string &keyname) const
Return card value as integer.
Definition GFitsHDU.hpp:436
Abstract FITS image base class.
FITS file class.
Definition GFits.hpp:63
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition GFits.cpp:1293
GFitsImage * image(const int &extno)
Get pointer to image HDU.
Definition GFits.cpp:368
void close(void)
Close FITS file.
Definition GFits.cpp:1342
Good Time Interval class.
Definition GGti.hpp:62
bool contains(const GTime &time) const
Checks whether Good Time Intervals contains time.
Definition GGti.cpp:1070
std::string print(const GChatter &chatter=NORMAL) const
Print Good Time Intervals.
Definition GGti.cpp:1106
void reference(const GTimeReference &ref)
Set time reference for Good Time Intervals.
Definition GGti.hpp:257
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition GGti.hpp:207
int size(void) const
Return number of Good Time Intervals.
Definition GGti.hpp:154
void reduce(const GTime &tstart, const GTime &tstop)
Reduce Good Time Intervals to specified interval.
Definition GGti.cpp:401
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition GGti.hpp:194
void clear(void)
Clear Good Time Intervals.
Definition GGti.cpp:237
Abstract model class.
Definition GModel.hpp:100
virtual double eval(const GEvent &event, const GObservation &obs, const bool &gradients=false) const =0
Node array class.
void set_value(const double &value) const
Set indices and weighting factors for interpolation.
const int & inx_right(void) const
Returns right node index.
const int & inx_left(void) const
Returns left node index.
const double & wgt_right(void) const
Returns right node weight.
const double & wgt_left(void) const
Returns left node weight.
virtual GEvents * events(void)
Return events.
double length(void) const
Returns total length of phase intervals.
Definition GPhases.cpp:365
bool contains(const double &phase) const
Check whether phase is contained in phases.
Definition GPhases.cpp:200
bool is_empty(void) const
Signal if there are no phase intervals.
Definition GPhases.hpp:114
Pulsar ephemeris class.
double phase(void) const
Returns pulse phase.
const GSkyDir & dir(void) const
Returns pulsar sky direction.
const GPulsarEphemeris & ephemeris(const GTime &time) const
Return pulsar ephemeris.
Definition GPulsar.cpp:253
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
double dist_deg(const GSkyDir &dir) const
Compute angular distance between sky directions in degrees.
Definition GSkyDir.hpp:286
Sky map class.
Definition GSkyMap.hpp:89
const int & nmaps(void) const
Returns number of maps.
Definition GSkyMap.hpp:389
void clear(void)
Clear instance.
Definition GSkyMap.cpp:1100
GSkyDir inx2dir(const int &index) const
Returns sky direction of pixel.
Definition GSkyMap.cpp:1331
GSkyMap extract(const int &map, const int &nmaps=1) const
Extract maps into a new sky map object.
Definition GSkyMap.cpp:2139
const int & nx(void) const
Returns number of pixels in x coordinate.
Definition GSkyMap.hpp:361
void read(const GFitsHDU &hdu)
Read skymap from FITS HDU.
Definition GSkyMap.cpp:2664
const int & npix(void) const
Returns number of pixels.
Definition GSkyMap.hpp:345
const int & ny(void) const
Returns number of pixels in y coordinate.
Definition GSkyMap.hpp:377
const GSkyProjection * projection(void) const
Returns pointer to sky projection.
Definition GSkyMap.hpp:463
GFitsHDU * write(GFits &file, const std::string &extname="") const
Write sky map into FITS file.
Definition GSkyMap.cpp:2697
bool contains(const GSkyDir &dir) const
Checks if sky direction falls in map.
Definition GSkyMap.cpp:2023
int pix2inx(const GSkyPixel &pixel) const
Converts sky map pixel into pixel index.
Definition GSkyMap.cpp:1407
GSkyPixel dir2pix(const GSkyDir &dir) const
Returns sky map pixel for a given sky direction.
Definition GSkyMap.cpp:1472
std::string print(const GChatter &chatter=NORMAL) const
Print sky map.
Definition GSkyMap.cpp:2787
Sky map pixel class.
Definition GSkyPixel.hpp:74
Time class.
Definition GTime.hpp:55
void clear(void)
Clear time.
Definition GTime.cpp:252
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Definition GTime.cpp:465
const double & secs(void) const
Return time in seconds in native reference (TT)
Definition GTime.hpp:156
Vector class.
Definition GVector.hpp:46
Abstract world coordinate system base class.
Definition GWcs.hpp:51
double cdelt(const int &inx) const
Return pixel size.
Definition GWcs.cpp:935
double crpix(const int &inx) const
Return reference pixel.
Definition GWcs.cpp:911
double crval(const int &inx) const
Return value of reference pixel.
Definition GWcs.cpp:887
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
const double & com_exd2r(const int &id2)
Return D2 module exclusion region radius.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const double pi
Definition GMath.hpp:35
const double & com_exd2x(const int &id2)
Return D2 module exclusion region X position.
const std::string extname_dri
Definition GCOMDri.hpp:52
const double deg2rad
Definition GMath.hpp:43
void com_wcs_mer2car(GSkyMap &map)
Changes Mercator's projection to cartesian projection.
const double & com_exd2y(const int &id2)
Return D2 module exclusion region Y position.
int com_tics(const GTime &time)
Convert GTime in COMPTEL tics.
GChatter reduce(const GChatter &chatter)
Reduce chattiness by one level.
Definition GTypemaps.hpp:65
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1386
int com_tjd(const GTime &time)
Convert GTime in COMPTEL TJD.
Definition GCOMTools.cpp:91
GTime com_time(const int &tjd, const int &tics)
Convert TJD and COMPTEL tics in GTime object.
Definition GCOMTools.cpp:55