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