GammaLib  2.0.0
 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-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 __________________________________________________________ */
72 const double superpacket_duration = 16.384; // Duration of superpacket (s)
73 const double r1 = 13.8; // D1 module radius (cm)
74 
75 /* __ Derived constants __________________________________________________ */
76 const double r1sq = r1 * r1;
77 const 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
92  init_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  ***************************************************************************/
104 GCOMDri::GCOMDri(const GFilename& filename)
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
147  m_phimin = phimin;
148  m_phibin = phibin;
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  ***************************************************************************/
228 void GCOMDri::clear(void)
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
295  init_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
572  init_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)
659  m_ebounds.clear();
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
716  init_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)
783  m_ebounds.clear();
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  ***************************************************************************/
846 double GCOMDri::cone_content(const GSkyDir& dir,
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  ***************************************************************************/
893 void 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  ***************************************************************************/
918 void 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  ***************************************************************************/
942 void 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  ***************************************************************************/
967 void 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  ***************************************************************************/
988 std::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"));
1057  result.append(gammalib::str(m_num_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
1093  init_statistics();
1094 
1095  // Initialise selection parameters
1096  m_has_selection = false;
1097  m_selection.clear();
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
1131  m_selection = dri.m_selection;
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();
1174  m_num_superpackets = 0;
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  ***************************************************************************/
1466 double 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  ***************************************************************************/
1633 double 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  ***************************************************************************/
1707 double 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 }
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 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:377
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:463
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:162
GCOMSelection m_selection
Selection parameters.
Definition: GCOMDri.hpp:170
const double & phimin(void) const
Return minimum Compton scatter angle of DRI cube.
Definition: GCOMDri.hpp:360
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:72
double m_tofcor
ToF correction.
Definition: GCOMDri.hpp:158
const GCOMBvcs & bvcs(void) const
Return Solar System Barycentre Data.
int size(void) const
Return number of bins.
Definition: GCOMDri.hpp:219
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:1707
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:153
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:157
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:558
void write_attributes(GFitsHDU *hdu) const
Write DRI attributes into FITS HDU.
Definition: GCOMDri.cpp:1356
COMPTEL observation class interface definition.
const float & gcel(void) const
Return Geocentre zenith angle.
Definition: GCOMOad.hpp:280
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:164
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:443
Time class.
Definition: GTime.hpp:55
Gammalib tools definition.
const GTime & tstop(void) const
Return stop time of superpacket.
Definition: GCOMOad.hpp:164
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:231
GCOMDri(void)
Void constructor.
Definition: GCOMDri.cpp:89
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:309
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
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:133
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
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:1110
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:246
const double d1_area
Definition: GCOMDri.cpp:77
const GVector & pos(void) const
Return telescope position vector (km)
Definition: GCOMOad.hpp:398
double cone_content(const GSkyDir &dir, const double &armmin, const double &armmax) const
Compute content in cone.
Definition: GCOMDri.cpp:846
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:389
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:1154
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:159
GTime m_tstop
Selection stop time.
Definition: GCOMDri.hpp:163
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:967
void compute_drm(const GCOMObservation &obs, const GModel &model)
Compute DRM model.
Definition: GCOMDri.cpp:810
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:169
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:267
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:1466
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:166
const double & com_exd2x(const int &id2)
Return D2 module exclusion region X position.
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:1142
void save(const GFilename &filename, const bool &clobber=false) const
Save COMPTEL Data Space into DRI FITS file.
Definition: GCOMDri.cpp:918
void clear(void)
Clear instance.
Definition: GSkyMap.cpp:1100
Good Time Interval class.
Definition: GGti.hpp:62
const double r1
Definition: GCOMDri.cpp:73
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:54
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:176
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:703
int nphibar(void) const
Return number of Phibar bins.
Definition: GCOMDri.hpp:255
Pulsar ephemeris class.
GCOMDri & operator=(const GCOMDri &dri)
Assignment operator.
Definition: GCOMDri.cpp:198
bool use_event(const GCOMEventAtom &event) const
Check if event should be used.
void compute_tof_correction(void)
Compute ToF correction.
Definition: GCOMDri.cpp:1823
const std::string extname_dri
Definition: GCOMDri.hpp:52
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:1169
Sky model class interface definition.
#define G_COMPUTE_TOF_CORRECTION
Definition: GCOMDri.cpp:59
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:228
const int & tjd(void) const
Return Truncated Julian Days of Orbit Aspect Record.
Definition: GCOMOad.hpp:193
void read(const GFitsImage &image)
Read COMPTEL Data Space from DRI FITS image.
Definition: GCOMDri.cpp:942
void init_members(void)
Initialise class members.
Definition: GCOMDri.cpp:1080
GGti m_gti
Good Time Intervals of data cube.
Definition: GCOMDri.hpp:155
Interface class for COMPTEL observations.
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:243
virtual void clear(void)
Clear COMPTEL selection set.
void load(const GFilename &filename)
Load COMPTEL Data Space from DRI FITS file.
Definition: GCOMDri.cpp:893
GEbounds m_ebounds
Energy boundaries of data cube.
Definition: GCOMDri.hpp:154
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:266
COMPTEL event list class.
const int & nx(void) const
Returns number of pixels in x coordinate.
Definition: GSkyMap.hpp:361
COMPTEL Data Space class.
Definition: GCOMDri.hpp:61
int m_num_used_superpackets
Number of used superpackets.
Definition: GCOMDri.hpp:165
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
double m_zetamin
Minimum zeta angle.
Definition: GCOMDri.hpp:171
bool use_superpacket(const GCOMOad &oad, const GCOMTim &tim, const GCOMSelection &select)
Check if superpacket should be used.
Definition: GCOMDri.cpp:1199
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:345
const double & phibin(void) const
Return Compton scatter angle bin of DRI cube.
Definition: GCOMDri.hpp:372
void read_attributes(const GFitsHDU *hdu)
Read DRI attributes from FITS HDU.
Definition: GCOMDri.cpp:1266
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:988
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:156
const double r1sq
Definition: GCOMDri.cpp:76
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:428
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:251
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:152