GammaLib  2.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GCOMObservation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GCOMObservation.cpp - COMPTEL Observation class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2012-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 GCOMObservation.cpp
23  * @brief COMPTEL observation class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <typeinfo>
32 #include "GObservationRegistry.hpp"
33 #include "GTools.hpp"
34 #include "GMath.hpp"
35 #include "GException.hpp"
36 #include "GFits.hpp"
37 #include "GFitsHDU.hpp"
38 #include "GCaldb.hpp"
39 #include "GSource.hpp"
40 #include "GModels.hpp"
41 #include "GModelSky.hpp"
42 #include "GModelSpectralConst.hpp"
43 #include "GXmlElement.hpp"
44 #include "GCOMObservation.hpp"
45 #include "GCOMEventBin.hpp"
46 #include "GCOMStatus.hpp"
47 #include "GCOMSupport.hpp"
48 
49 /* __ Globals ____________________________________________________________ */
51 const GObservationRegistry g_obs_com_registry(&g_obs_com_seed);
52 
53 /* __ Method name definitions ____________________________________________ */
54 #define G_RESPONSE "GCOMObservation::response(GResponse&)"
55 #define G_READ "GCOMObservation::read(GXmlElement&)"
56 #define G_WRITE "GCOMObservation::write(GXmlElement&)"
57 #define G_LOAD_DRB "GCOMObservation::load_drb(GFilename&)"
58 #define G_LOAD_DRG "GCOMObservation::load_drg(GFilename&)"
59 #define G_DRM "GCOMObservation::drm(GModels&)"
60 #define G_COMPUTE_DRB "GCOMObservation::compute_drb(std::string&, GCOMDri&, "\
61  "int&, int&, int&, int&"
62 #define G_COMPUTE_DRB_PHINOR "GCOMObservation::compute_drb_phinor(GCOMDri&)"
63 #define G_COMPUTE_DRB_BGDLIXA "GCOMObservation::compute_drb_bgdlixa("\
64  "GCOMDri&, int&, int&, int&, int&)"
65 #define G_COMPUTE_DRB_BGDLIXE "GCOMObservation::compute_drb_bgdlixe("\
66  "GCOMDri&, int&, int&, int&, int&)"
67 
68 /* __ Macros _____________________________________________________________ */
69 
70 /* __ Coding definitions _________________________________________________ */
71 
72 /* __ Debug definitions __________________________________________________ */
73 
74 
75 /*==========================================================================
76  = =
77  = Constructors/destructors =
78  = =
79  ==========================================================================*/
80 
81 /***********************************************************************//**
82  * @brief Void constructor
83  *
84  * Creates an empty COMPTEL observation.
85  ***************************************************************************/
87 {
88  // Initialise members
89  init_members();
90 
91  // Return
92  return;
93 }
94 
95 
96 /***********************************************************************//**
97  * @brief XML constructor
98  *
99  * @param[in] xml XML element.
100  *
101  * Constructs a COMPTEL observation from the information that is found in an
102  * XML element.
103  ***************************************************************************/
105 {
106  // Initialise members
107  init_members();
108 
109  // Read XML
110  read(xml);
111 
112  // Return
113  return;
114 }
115 
116 
117 /***********************************************************************//**
118  * @brief Binned observation DRI constructor
119  *
120  * @param[in] dre Event cube.
121  * @param[in] drb Background cube.
122  * @param[in] drg Geometry cube.
123  * @param[in] drx Exposure map.
124  *
125  * Creates COMPTEL observation from DRI instances.
126  *
127  * The method fixes the deadtime correction factor deadc to 0.965.
128  ***************************************************************************/
130  const GCOMDri& drb,
131  const GCOMDri& drg,
132  const GCOMDri& drx) : GObservation()
133 {
134  // Initialise members
135  init_members();
136 
137  // Store DRIs
138  m_events = new GCOMEventCube(dre);
139  m_drb = drb;
140  m_drg = drg;
141  m_drx = drx;
142 
143  // Set attributes
144  m_obs_id = 0;
145  m_ontime = m_events->gti().ontime();
146  m_deadc = 0.965;
148  m_ewidth = m_events->emax().MeV() - m_events->emin().MeV();
149  m_name = "unknown";
150  m_drename = "";
151  m_drbname = "";
152  m_drgname = "";
153  m_drxname = "";
154 
155  // Return
156  return;
157 }
158 
159 
160 /***********************************************************************//**
161  * @brief Binned observation filename constructor
162  *
163  * @param[in] drename Event cube name.
164  * @param[in] drbname Background cube name.
165  * @param[in] drgname Geometry cube name.
166  * @param[in] drxname Exposure map name.
167  *
168  * Creates COMPTEL observation by loading the following FITS files:
169  *
170  * DRE - Events cube
171  * DRB - Background model cube
172  * DRG - Geometry factors cube
173  * DRX - Exposure map
174  *
175  * Each of the four files is mandatory.
176  ***************************************************************************/
178  const GFilename& drbname,
179  const GFilename& drgname,
180  const GFilename& drxname) : GObservation()
181 {
182  // Initialise members
183  init_members();
184 
185  // Load observation
186  load(drename, drbname, drgname, drxname);
187 
188  // Return
189  return;
190 }
191 
192 
193 /***********************************************************************//**
194  * @brief Unbinned observation constructor
195  *
196  * @param[in] evpname Event list FITS file name.
197  * @param[in] timname Good Time Intervals FITS file name.
198  * @param[in] oadnames List of Orbit Aspect Data FITS file names.
199  * @param[in] bvcname Solar System Barycentre Data FITS file name.
200  *
201  * Creates a COMPTEL unbinned observation by loading the event list, Good
202  * Time Interval, Orbit Aspect Data and optionally the Solar System
203  * Barycentre Data from FITS files. Except of the Solar System Barycentre
204  * Data all files are mandatory. The Solar System Barycentre Data will only
205  * be loaded if the file name is not empty.
206  ***************************************************************************/
208  const GFilename& timname,
209  const std::vector<GFilename>& oadnames,
210  const GFilename& bvcname)
211 {
212  // Initialise members
213  init_members();
214 
215  // Load observation
216  load(evpname, timname, oadnames, bvcname);
217 
218  // Return
219  return;
220 }
221 
222 
223 /***********************************************************************//**
224  * @brief Copy constructor
225  *
226  * @param[in] obs COMPTEL observation.
227  *
228  * Creates COMPTEL observation by copying an existing COMPTEL observation.
229  ***************************************************************************/
231 {
232  // Initialise members
233  init_members();
234 
235  // Copy members
236  copy_members(obs);
237 
238  // Return
239  return;
240 }
241 
242 
243 /***********************************************************************//**
244  * @brief Destructor
245  ***************************************************************************/
247 {
248  // Free members
249  free_members();
250 
251  // Return
252  return;
253 }
254 
255 
256 /*==========================================================================
257  = =
258  = Operators =
259  = =
260  ==========================================================================*/
261 
262 /***********************************************************************//**
263  * @brief Assignment operator
264  *
265  * @param[in] obs COMPTEL observation.
266  * @return COMPTEL observation.
267  *
268  * Assign COMPTEL observation to this object.
269  ***************************************************************************/
271 {
272  // Execute only if object is not identical
273  if (this != &obs) {
274 
275  // Copy base class members
276  this->GObservation::operator=(obs);
277 
278  // Free members
279  free_members();
280 
281  // Initialise members
282  init_members();
283 
284  // Copy members
285  copy_members(obs);
286 
287  } // endif: object was not identical
288 
289  // Return this object
290  return *this;
291 }
292 
293 
294 /*==========================================================================
295  = =
296  = Public methods =
297  = =
298  ==========================================================================*/
299 
300 /***********************************************************************//**
301  * @brief Clear COMPTEL observation
302  ***************************************************************************/
304 {
305  // Free members
306  free_members();
308 
309  // Initialise members
311  init_members();
312 
313  // Return
314  return;
315 }
316 
317 
318 /***********************************************************************//**
319  * @brief Clone COMPTEL observation
320  *
321  * @return Pointer to deep copy of COMPTEL observation.
322  ***************************************************************************/
324 {
325  return new GCOMObservation(*this);
326 }
327 
328 
329 /***********************************************************************//**
330  * @brief Set response function
331  *
332  * @param[in] rsp Response function.
333  *
334  * @exception GException::invalid_argument
335  * Specified response is not a COMPTEL response.
336  *
337  * Sets the response function for the observation.
338  ***************************************************************************/
340 {
341  // Get pointer on COM response
342  const GCOMResponse* comrsp = dynamic_cast<const GCOMResponse*>(&rsp);
343  if (comrsp == NULL) {
344  std::string cls = std::string(typeid(&rsp).name());
345  std::string msg = "Response of type \""+cls+"\" is "
346  "not a COMPTEL response. Please specify a COMPTEL "
347  "response as argument.";
349  }
350 
351  // Clone response function
352  m_response = *comrsp;
353 
354  // Return
355  return;
356 }
357 
358 
359 /***********************************************************************//**
360  * @brief Set response function
361  *
362  * @param[in] caldb Calibration database.
363  * @param[in] rspname Name of COMPTEL response.
364  *
365  * Sets the response function by loading the response information from the
366  * calibration database.
367  ***************************************************************************/
368 void GCOMObservation::response(const GCaldb& caldb, const std::string& rspname)
369 {
370  // Clear COM response function
371  m_response.clear();
372 
373  // Set calibration database
374  m_response.caldb(caldb);
375 
376  // Load instrument response function
377  m_response.load(rspname);
378 
379  // Return
380  return;
381 }
382 
383 
384 /***********************************************************************//**
385  * @brief Read observation from XML element
386  *
387  * @param[in] xml XML element.
388  *
389  * Reads information for a COMPTEL observation from an XML element. The
390  * method supports both an unbinned and a binned observation.
391  *
392  * For an unbinned observation the XML format is
393  *
394  * <observation name="Crab" id="000001" instrument="COM">
395  * <parameter name="EVP" file="m16992_evp.fits"/>
396  * <parameter name="TIM" file="m10695_tim.fits"/>
397  * <parameter name="OAD" file="m20039_oad.fits"/>
398  * <parameter name="OAD" file="m20041_oad.fits"/>
399  * <parameter name="BVC" file="s10150_bvc.fits"/>
400  * ...
401  * </observation>
402  *
403  * where the observation can contain an arbitrary number of OAD file
404  * parameters. The @p file attribute provide either absolute or relative
405  * file names. If a file name includes no access path it is assumed that
406  * the file resides in the same location as the XML file. The BVC file is
407  * optional and does not need to be specified.
408  *
409  * For a binned observation the XML format is
410  *
411  * <observation name="Crab" id="000001" instrument="COM">
412  * <parameter name="DRE" file="m50438_dre.fits"/>
413  * <parameter name="DRB" file="m34997_drg.fits"/>
414  * <parameter name="DRG" file="m34997_drg.fits"/>
415  * <parameter name="DRX" file="m32171_drx.fits"/>
416  * <parameter name="IAQ" value="UNH(1.0-3.0)MeV"/>
417  * </observation>
418  ***************************************************************************/
420 {
421  // Clear observation
422  clear();
423 
424  // Extract instrument name
425  m_instrument = xml.attribute("instrument");
426 
427  // If the XML elements has a "EVP" attribute we have an unbinned
428  // observation
429  if (gammalib::xml_has_par(xml, "EVP")) {
430 
431  // Get EVP and TIM file names
432  std::string evpname = gammalib::xml_get_attr(G_READ, xml, "EVP", "file");
433  std::string timname = gammalib::xml_get_attr(G_READ, xml, "TIM", "file");
434 
435  // Expand EVP and TIM file names
436  evpname = gammalib::xml_file_expand(xml, evpname);
437  timname = gammalib::xml_file_expand(xml, timname);
438 
439  // Get OAD file names
440  std::vector<GFilename> oadnames;
441  for (int i = 0; i < xml.elements("parameter"); ++i) {
442  const GXmlElement* element = xml.element("parameter", i);
443  if (element->attribute("name") == "OAD") {
444  std::string oadname = element->attribute("file");
445  oadname = gammalib::xml_file_expand(xml, oadname);
446  oadnames.push_back(GFilename(oadname));
447  }
448  }
449 
450  // Get and expand optional BVC file name
451  std::string bvcname = "";
452  if (gammalib::xml_has_par(xml, "BVC")) {
453  bvcname = gammalib::xml_get_attr(G_READ, xml, "BVC", "file");
454  bvcname = gammalib::xml_file_expand(xml, bvcname);
455  }
456 
457  // Load observation
458  load(evpname, timname, oadnames, bvcname);
459 
460  } // endif: unbinned observation
461 
462  // ... otherwise we have a binned observation
463  else {
464 
465  // Get parameters
466  std::string drename = gammalib::xml_get_attr(G_READ, xml, "DRE", "file");
467  std::string drbname = gammalib::xml_get_attr(G_READ, xml, "DRB", "file");
468  std::string drgname = gammalib::xml_get_attr(G_READ, xml, "DRG", "file");
469  std::string drxname = gammalib::xml_get_attr(G_READ, xml, "DRX", "file");
470  std::string iaqname = gammalib::xml_get_attr(G_READ, xml, "IAQ", "value");
471 
472  // Expand file names
473  drename = gammalib::xml_file_expand(xml, drename);
474  drbname = gammalib::xml_file_expand(xml, drbname);
475  drgname = gammalib::xml_file_expand(xml, drgname);
476  drxname = gammalib::xml_file_expand(xml, drxname);
477  std::string iaqname_expanded = gammalib::xml_file_expand(xml, iaqname);
478 
479  // Load observation
480  load(drename, drbname, drgname, drxname);
481 
482  // Load IAQ by trying first the expanded name as a FITS file and
483  // otherwise the unexpanded name
484  GFilename filename_expanded(iaqname_expanded);
485  if (filename_expanded.is_fits()) {
486  response(GCaldb("cgro", "comptel"), iaqname_expanded);
487  }
488  else {
489  response(GCaldb("cgro", "comptel"), iaqname);
490  }
491 
492  // Get optional Phibar layer attributes
493  if (xml.has_attribute("phi_first")) {
494  m_phi_first = gammalib::toint(xml.attribute("phi_first"));
495  }
496  if (xml.has_attribute("phi_last")) {
497  m_phi_last = gammalib::toint(xml.attribute("phi_last"));
498  }
499 
500  } // endelse: binned observation
501 
502  // Return
503  return;
504 }
505 
506 
507 /***********************************************************************//**
508  * @brief Write observation into XML element
509  *
510  * @param[in] xml XML element.
511  *
512  * Writes information for a COMPTEL observation into an XML element. The
513  * method supports both an unbinned and a binned observation.
514  *
515  * For an unbinned observation the XML format is
516  *
517  * <observation name="Crab" id="000001" instrument="COM">
518  * <parameter name="EVP" file="m16992_evp.fits"/>
519  * <parameter name="TIM" file="m10695_tim.fits"/>
520  * <parameter name="OAD" file="m20039_oad.fits"/>
521  * <parameter name="OAD" file="m20041_oad.fits"/>
522  * <parameter name="BVC" file="s10150_bvc.fits"/>
523  * ...
524  * </observation>
525  *
526  * where the observation can contain an arbitrary number of OAD file
527  * parameters. The @p file attribute provide either absolute or relative
528  * file names. If a file name includes no access path it is assumed that
529  * the file resides in the same location as the XML file. The BVC file is
530  * optional and is only written if BVC information is contained in the
531  * observation.
532  *
533  * For a binned observation the XML format is
534  *
535  * <observation name="Crab" id="000001" instrument="COM">
536  * <parameter name="DRE" file="m50438_dre.fits"/>
537  * <parameter name="DRB" file="m34997_drg.fits"/>
538  * <parameter name="DRG" file="m34997_drg.fits"/>
539  * <parameter name="DRX" file="m32171_drx.fits"/>
540  * <parameter name="IAQ" value="UNH(1.0-3.0)MeV"/>
541  * </observation>
542  ***************************************************************************/
544 {
545  // Allocate XML element pointer
546  GXmlElement* par;
547 
548  // Handle unbinned observation
549  if (is_unbinned()) {
550 
551  // Set EVP parameter
552  par = gammalib::xml_need_par(G_WRITE, xml, "EVP");
553  par->attribute("file", gammalib::xml_file_reduce(xml, m_evpname));
554 
555  // Set TIM parameter
556  par = gammalib::xml_need_par(G_WRITE, xml, "TIM");
557  par->attribute("file", gammalib::xml_file_reduce(xml, m_timname));
558 
559  // Remove all existing OAD parameters
560  for (int i = 0; i < xml.elements("parameter"); ++i) {
561  GXmlElement* element = xml.element("parameter", i);
562  if (element->attribute("name") == "OAD") {
563  xml.remove(i);
564  }
565  }
566 
567  // Set OAD parameters
568  for (int i = 0; i < m_oadnames.size(); ++i) {
569  par = static_cast<GXmlElement*>(xml.append(GXmlElement("parameter name=\"OAD\"")));
570  par->attribute("file", gammalib::xml_file_reduce(xml, m_oadnames[i]));
571  }
572 
573  // Optionally set BVC parameters
574  if (!m_bvcs.is_empty()) {
575  par = gammalib::xml_need_par(G_WRITE, xml, "BVC");
576  par->attribute("file", gammalib::xml_file_reduce(xml, m_bvcname));
577  }
578 
579  } // endif: observation was unbinned
580 
581  // ... otherwise handle a binned observation
582  else if (is_binned()) {
583 
584  // Set DRE parameter
585  par = gammalib::xml_need_par(G_WRITE, xml, "DRE");
586  par->attribute("file", gammalib::xml_file_reduce(xml, m_drename));
587 
588  // Set DRB parameter
589  par = gammalib::xml_need_par(G_WRITE, xml, "DRB");
590  par->attribute("file", gammalib::xml_file_reduce(xml, m_drbname));
591 
592  // Set DRG parameter
593  par = gammalib::xml_need_par(G_WRITE, xml, "DRG");
594  par->attribute("file", gammalib::xml_file_reduce(xml, m_drgname));
595 
596  // Set DRX parameter
597  par = gammalib::xml_need_par(G_WRITE, xml, "DRX");
598  par->attribute("file", gammalib::xml_file_reduce(xml, m_drxname));
599 
600  // Set IAQ parameter
601  par = gammalib::xml_need_par(G_WRITE, xml, "IAQ");
602  par->attribute("value", gammalib::xml_file_reduce(xml, m_response.rspname()));
603 
604  // If there is a first Phibar layer selection then write it into XML file
605  if (m_phi_first != -1) {
606  xml.attribute("phi_first", gammalib::str(m_phi_first));
607  }
608 
609  // If there is a last Phibar layer selection then write it into XML file
610  if (m_phi_last != -1) {
611  xml.attribute("phi_last", gammalib::str(m_phi_last));
612  }
613 
614  } // endif: observation was binned
615 
616  // Return
617  return;
618 }
619 
620 
621 /***********************************************************************//**
622  * @brief Load data for a binned observation
623  *
624  * @param[in] drename Event cube name.
625  * @param[in] drbname Background cube name.
626  * @param[in] drgname Geometry cube name.
627  * @param[in] drxname Exposure map name.
628  *
629  * Load event cube from DRE file, background model from DRB file, geometry
630  * factors from DRG file and the exposure map from the DRX file. All files
631  * are mandatory.
632  ***************************************************************************/
633 void GCOMObservation::load(const GFilename& drename,
634  const GFilename& drbname,
635  const GFilename& drgname,
636  const GFilename& drxname)
637 {
638  // Load DRE
639  load_dre(drename);
640 
641  // Load DRB
642  load_drb(drbname);
643 
644  // Load DRG
645  load_drg(drgname);
646 
647  // Load DRX
648  load_drx(drxname);
649 
650  // Return
651  return;
652 }
653 
654 
655 /***********************************************************************//**
656  * @brief Load data for an unbinned observation
657  *
658  * @param[in] evpname Event list FITS file name.
659  * @param[in] timname Good Time Intervals FITS file name.
660  * @param[in] oadnames List of Orbit Aspect Data FITS file names.
661  * @param[in] bvcname Solar System Barycentre Data FITS file name.
662  *
663  * Loads the event list, Good Time Interval, Orbit Aspect Data and optionally
664  * the Solar System Barycentre Data for an unbinned observation. Except of
665  * the Solar System Barycentre Data all files are mandatory. The Solar
666  * System Barycentre Data will only be loaded if the file name is not empty.
667  *
668  * The method fixes the deadtime correction factor deadc to 0.965.
669  ***************************************************************************/
670 void GCOMObservation::load(const GFilename& evpname,
671  const GFilename& timname,
672  const std::vector<GFilename>& oadnames,
673  const GFilename& bvcname)
674 {
675  // Clear object
676  clear();
677 
678  // Extract observation information from event list
679  GFits fits(evpname);
680  read_attributes(fits[1]);
681  fits.close();
682 
683  // Allocate event list
684  GCOMEventList *evp = new GCOMEventList(evpname);
685  m_events = evp;
686 
687  // Load TIM data
688  m_tim.load(timname);
689 
690  // Extract ontime from TIM and compute livetime assuming the value of
691  // 0.965 from Rob van Dijk's thesis, page 62
692  m_ontime = m_tim.gti().ontime();
693  m_deadc = 0.965;
695 
696  // Initialise intermediate vector for OADs
697  std::vector<GCOMOads> oads;
698 
699  // Load OAD data
700  for (int i = 0; i < oadnames.size(); ++i) {
701 
702  // Load OAD file
703  GCOMOads oad(oadnames[i]);
704 
705  // Skip file if it is empty
706  if (oad.size() < 1) {
707  continue;
708  }
709 
710  // Find index of where to insert OAD file
711  int index = 0;
712  for (; index < oads.size(); ++index) {
713  if (oad[0].tstop() < oads[index][oads[index].size()-1].tstart()) {
714  break;
715  }
716  }
717 
718  // Inserts Orbit Aspect Data
719  if (index < oads.size()) {
720  oads.insert(oads.begin()+index, oad);
721  }
722  else {
723  oads.push_back(oad);
724  }
725 
726  }
727 
728  // Now put all OAD into a single container
729  for (int i = 0; i < oads.size(); ++i) {
730  m_oads.extend(oads[i]);
731  }
732 
733  // Optionally load BVC data
734  if (bvcname != "") {
735  m_bvcs.load(bvcname);
736  }
737 
738  // Store filenames
739  m_evpname = evpname;
740  m_timname = timname;
741  m_oadnames = oadnames;
742  m_bvcname = bvcname;
743 
744  // Return
745  return;
746 }
747 
748 
749 /***********************************************************************//**
750  * @brief Compute DRM cube
751  *
752  * @param[in] models Model container.
753  * @return DRM cube (units of counts)
754  *
755  * @exception GException::invalid_value
756  * Observation does not contain an event cube.
757  *
758  * Computes a COMPTEL DRM cube from the information provided in a model
759  * container. The values of the DRM cube are in units of counts.
760  ***************************************************************************/
762 {
763  // Get pointer on COMPTEL event cube
764  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(m_events);
765  if (cube == NULL) {
766  std::string cls = std::string(typeid(m_events).name());
767  std::string msg = "Events of type \""+cls+"\" is not a COMPTEL event "
768  "cube. Please specify a COMPTEL event cube when "
769  "using this method.";
770  throw GException::invalid_value(G_DRM, msg);
771  }
772 
773  // Create DRM cube as copy of DRE cube
774  GCOMEventCube drm_cube = *cube;
775 
776  // Get vector of model values
777  GVector values = models.eval(*this);
778 
779  // Loop over all cube bins
780  for (int i = 0; i < drm_cube.size(); ++i) {
781 
782  // Get pointer to cube bin
783  GCOMEventBin* bin = drm_cube[i];
784 
785  // Compute model value for cube bin
786  double model = values[i] * bin->size();
787 
788  // Store model value in cube bin
789  bin->counts(model);
790 
791  } // endfor: looped over DRM cube bins
792 
793  // Get a copy of the DRM
794  GCOMDri drm = drm_cube.dre();
795 
796  // Return DRM
797  return drm;
798 }
799 
800 
801 /***********************************************************************//**
802  * @brief Compute DRB cube
803  *
804  * @param[in] method Background method (PHINOR, BGDLIXA or BGDLIXE).
805  * @param[in] drm DRM cube.
806  * @param[in] nrunav BGDLIXA: number of bins used for running average.
807  * @param[in] navgr BGDLIXA: number of bins used for averaging.
808  * @param[in] nincl BGDLIXA: number of Phibar layers to include.
809  * @param[in] nexcl BGDLIXA: number of Phibar layers to exclude.
810  *
811  * Computes a COMPTEL DRB cube using either the PHINOR or BGDLIXA method.
812  * See the protected methods compute_drb_phinor() and compute_drb_bgdlixa()
813  * for more information.
814  ***************************************************************************/
815 void GCOMObservation::compute_drb(const std::string& method,
816  const GCOMDri& drm,
817  const int& nrunav,
818  const int& navgr,
819  const int& nincl,
820  const int& nexcl)
821 {
822  // Branch to relevant method based on specified background method
823  if (method == "PHINOR") {
824  compute_drb_phinor(drm);
825  }
826  else if (method == "BGDLIXA") {
827  compute_drb_bgdlixa(drm, nrunav, navgr, nincl, nexcl);
828  }
829  else if (method == "BGDLIXE") {
830  compute_drb_bgdlixe(drm, nrunav, navgr, nincl, nexcl);
831  }
832  else {
833  std::string msg = "Unknown background method \""+method+"\". "
834  "Specify either \"PHINOR\", \"BGDLIXA\" or "
835  "\"BGDLIXE\".";
837  }
838 
839  // Return
840  return;
841 }
842 
843 
844 /***********************************************************************//**
845  * @brief Print observation information
846  *
847  * @param[in] chatter Chattiness.
848  * @return String containing observation information.
849  ***************************************************************************/
850 std::string GCOMObservation::print(const GChatter& chatter) const
851 {
852  // Initialise result string
853  std::string result;
854 
855  // Continue only if chatter is not silent
856  if (chatter != SILENT) {
857 
858  // Append header
859  result.append("=== GCOMObservation ===");
860 
861  // Append information
862  result.append("\n"+gammalib::parformat("Name")+name());
863  result.append("\n"+gammalib::parformat("Identifier")+id());
864  result.append("\n"+gammalib::parformat("Instrument")+instrument());
865  result.append("\n"+gammalib::parformat("Statistic")+statistic());
866  result.append("\n"+gammalib::parformat("Ontime"));
867  result.append(gammalib::str(ontime())+" sec");
868  result.append("\n"+gammalib::parformat("Livetime"));
869  result.append(gammalib::str(livetime())+" sec");
870  result.append("\n"+gammalib::parformat("Deadtime correction"));
871  result.append(gammalib::str(m_deadc));
872 
873  // Append Phibar selection
874  int phi_first = (m_phi_first != -1) ? m_phi_first : 0;
875  int phi_last = (m_phi_last != -1) ? m_phi_last : m_drg.map().nmaps();
876  if ((m_phi_first != -1) || (m_phi_last != -1)) {
877  result.append("\n"+gammalib::parformat("Likelihood Phibar range"));
878  result.append(gammalib::str(phi_first));
879  result.append(" - ");
880  result.append(gammalib::str(phi_last));
881  }
882 
883  // Append response (if available)
884  if (response()->rspname().length() > 0) {
885  result.append("\n"+response()->print(gammalib::reduce(chatter)));
886  }
887 
888  // Append events
889  if (m_events != NULL) {
890  result.append("\n"+m_events->print(gammalib::reduce(chatter)));
891  }
892  else {
893  result.append("\n"+gammalib::parformat("Events")+"undefined");
894  }
895 
896  // Append TIM (if available)
897  if (m_tim.gti().size() > 0) {
898  result.append("\n"+m_tim.print(gammalib::reduce(chatter)));
899  }
900  else {
901  result.append("\n"+gammalib::parformat("TIM")+"undefined");
902  }
903 
904  // Append OADs (if available)
905  if (!m_oads.is_empty()) {
906  result.append("\n"+m_oads.print(gammalib::reduce(chatter)));
907  }
908  else {
909  result.append("\n"+gammalib::parformat("OADs")+"undefined");
910  }
911 
912  // Append BVCs (if available)
913  if (!m_bvcs.is_empty()) {
914  result.append("\n"+m_bvcs.print(gammalib::reduce(chatter)));
915  }
916  else {
917  result.append("\n"+gammalib::parformat("BVCs")+"undefined");
918  }
919 
920  // Append DRB, DRG and DRX
921  //result.append("\n"+m_drb.print(chatter));
922  //result.append("\n"+m_drg.print(chatter));
923  //result.append("\n"+m_drx.print(chatter));
924 
925  } // endif: chatter was not silent
926 
927  // Return result
928  return result;
929 }
930 
931 
932 /*==========================================================================
933  = =
934  = Private methods =
935  = =
936  ==========================================================================*/
937 
938 /***********************************************************************//**
939  * @brief Initialise class members
940  ***************************************************************************/
942 {
943  // Initialise members
944  m_instrument = "COM";
945  m_response.clear();
946  m_obs_id = 0;
947  m_ontime = 0.0;
948  m_livetime = 0.0;
949  m_deadc = 0.0;
950 
951  // Initialise members for binned observation
952  m_drename.clear();
953  m_drbname.clear();
954  m_drgname.clear();
955  m_drxname.clear();
956  m_drb.clear();
957  m_drg.clear();
958  m_drx.clear();
959  m_ewidth = 0.0;
960  m_phi_first = -1;
961  m_phi_last = -1;
962 
963  // Initialise members for unbinned observation
964  m_evpname.clear();
965  m_timname.clear();
966  m_oadnames.clear();
967  m_bvcname.clear();
968  m_tim.clear();
969  m_oads.clear();
970  m_bvcs.clear();
971 
972  // Return
973  return;
974 }
975 
976 
977 /***********************************************************************//**
978  * @brief Copy class members
979  *
980  * @param[in] obs COMPTEL observation.
981  ***************************************************************************/
983 {
984  // Copy members
986  m_response = obs.m_response;
987  m_obs_id = obs.m_obs_id;
988  m_ontime = obs.m_ontime;
989  m_livetime = obs.m_livetime;
990  m_deadc = obs.m_deadc;
991 
992  // Copy members for binned observation
993  m_drename = obs.m_drename;
994  m_drbname = obs.m_drbname;
995  m_drgname = obs.m_drgname;
996  m_drxname = obs.m_drxname;
997  m_drb = obs.m_drb;
998  m_drg = obs.m_drg;
999  m_drx = obs.m_drx;
1000  m_ewidth = obs.m_ewidth;
1001  m_phi_first = obs.m_phi_first;
1002  m_phi_last = obs.m_phi_last;
1003 
1004  // Copy members for unbinned observation
1005  m_evpname = obs.m_evpname;
1006  m_timname = obs.m_timname;
1007  m_oadnames = obs.m_oadnames;
1008  m_bvcname = obs.m_bvcname;
1009  m_tim = obs.m_tim;
1010  m_oads = obs.m_oads;
1011  m_bvcs = obs.m_bvcs;
1012 
1013  // Return
1014  return;
1015 }
1016 
1017 
1018 /***********************************************************************//**
1019  * @brief Delete class members
1020  ***************************************************************************/
1022 {
1023  // Return
1024  return;
1025 }
1026 
1027 
1028 /***********************************************************************//**
1029  * @brief Load event cube data from DRE file
1030  *
1031  * @param[in] drename DRE filename.
1032  *
1033  * Loads the event cube from a DRE file.
1034  *
1035  * The ontime is extracted from the Good Time Intervals. The deadtime
1036  * correction factor deadc is fixed to 0.965. The livetime is computed by
1037  * multiplying the deadtime correction by the ontime, i.e.
1038  * LIVETIME = ONTIME * DEADC.
1039  ***************************************************************************/
1041 {
1042  // Delete any existing event container (do not call clear() as we do not
1043  // want to delete the response function)
1044  if (m_events != NULL) delete m_events;
1045  m_events = NULL;
1046 
1047  // Allocate event cube
1048  m_events = new GCOMEventCube;
1049 
1050  // Open FITS file
1051  GFits fits(drename);
1052 
1053  // Read event cube
1054  m_events->read(fits);
1055 
1056  // Extract ontime
1057  m_ontime = m_events->gti().ontime();
1058 
1059  // Set fixed deadtime fraction (see Rob van Dijk's thesis, page 62)
1060  m_deadc = 0.965;
1061 
1062  // Compute livetime
1064 
1065  // Compute energy width
1066  m_ewidth = m_events->emax().MeV() - m_events->emin().MeV();
1067 
1068  // Read additional observation attributes from primary extension
1069  read_attributes(fits[0]);
1070 
1071  // Close FITS file
1072  fits.close();
1073 
1074  // Store event filename
1075  m_drename = drename;
1076 
1077  // Return
1078  return;
1079 }
1080 
1081 
1082 /***********************************************************************//**
1083  * @brief Load background model from DRB file
1084  *
1085  * @param[in] drbname DRB filename.
1086  *
1087  * @exception GException::invalid_value
1088  * DRB data space incompatible with DRE data space.
1089  *
1090  * Load the background model from the primary image of the specified FITS
1091  * file. Since a DRB file is optional the method does nothing if the DRB
1092  * filename is empty.
1093  ***************************************************************************/
1095 {
1096  // Continue only if filename is not empty
1097  if (!drbname.is_empty()) {
1098 
1099  // Open FITS file
1100  GFits fits(drbname);
1101 
1102  // Get image
1103  const GFitsImage& image = *fits.image("Primary");
1104 
1105  // Read background model
1106  m_drb.read(image);
1107 
1108  // Correct WCS projection (HEASARC data format kludge)
1109  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drb.map()));
1110 
1111  // Close FITS file
1112  fits.close();
1113 
1114  // Check map dimensions
1115  if (!check_dri(m_drb)) {
1116  std::string msg = "DRB data cube \""+drbname+"\" incompatible with "
1117  "DRE data cube \""+m_drename+"\".";
1119  }
1120 
1121  // Store DRB filename
1122  m_drbname = drbname;
1123 
1124  } // endif: DRB filename was empty
1125 
1126  // Return
1127  return;
1128 }
1129 
1130 
1131 /***********************************************************************//**
1132  * @brief Load geometry factors from DRG file
1133  *
1134  * @param[in] drgname DRG filename.
1135  *
1136  * @exception GException::invalid_value
1137  * DRG data space incompatible with DRE data space.
1138  *
1139  * Load the geometry factors from the primary image of the specified FITS
1140  * file.
1141  ***************************************************************************/
1143 {
1144  // Open FITS file
1145  GFits fits(drgname);
1146 
1147  // Get image
1148  const GFitsImage& image = *fits.image("Primary");
1149 
1150  // Read geometry factors
1151  m_drg.read(image);
1152 
1153  // Correct WCS projection (HEASARC data format kludge)
1154  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drg.map()));
1155 
1156  // Close FITS file
1157  fits.close();
1158 
1159  // Check map dimensions
1160  if (!check_dri(m_drg)) {
1161  std::string msg = "DRG data cube \""+drgname+"\" incompatible with "
1162  "DRE data cube \""+m_drename+"\".";
1164  }
1165 
1166  // Store DRG filename
1167  m_drgname = drgname;
1168 
1169  // Return
1170  return;
1171 }
1172 
1173 
1174 /***********************************************************************//**
1175  * @brief Load exposure from DRX file
1176  *
1177  * @param[in] drxname DRX filename.
1178  *
1179  * Load the exposure map from the primary image of the specified FITS file.
1180  ***************************************************************************/
1182 {
1183  // Open FITS file
1184  GFits fits(drxname);
1185 
1186  // Get HDU
1187  const GFitsImage& image = *fits.image("Primary");
1188 
1189  // Read exposure map
1190  m_drx.read(image);
1191 
1192  // Correct WCS projection (HEASARC data format kludge)
1193  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drx.map()));
1194 
1195  // Close FITS file
1196  fits.close();
1197 
1198  // Store DRX filename
1199  m_drxname = drxname;
1200 
1201  // Return
1202  return;
1203 }
1204 
1205 
1206 /***********************************************************************//**
1207  * @brief Check if DRI is compatible with event cube
1208  *
1209  * @param[in] dri DRI.
1210  * @return True if DRI is compatible, false otherwise.
1211  *
1212  * Compares the dimension and the WCS definition of a DRI to that of the
1213  * event cube. If both are identical, true is returned, false otherwise.
1214  ***************************************************************************/
1215 bool GCOMObservation::check_dri(const GCOMDri& dri) const
1216 {
1217  // Get references to event cube map and DRI map
1218  const GSkyMap& ref = dynamic_cast<GCOMEventCube*>(m_events)->dre().map();
1219  const GSkyMap& map = dri.map();
1220 
1221  // Compare dimensions
1222  bool same_dimension = ((map.nx() == ref.nx()) &&
1223  (map.ny() == ref.ny()) &&
1224  (map.nmaps() == ref.nmaps()));
1225 
1226  // Compare projections
1227  bool same_projection = false;
1228  const GSkyProjection* proj_ref = ref.projection();
1229  const GSkyProjection* proj_map = map.projection();
1230  if ((proj_ref == NULL) && (proj_map == NULL)) {
1231  same_projection = true;
1232  }
1233  else if ((proj_ref != NULL) && (proj_map != NULL)) {
1234  same_projection = (*proj_map == *proj_ref);
1235  }
1236 
1237  // Return
1238  return (same_dimension && same_projection);
1239 }
1240 
1241 
1242 /***********************************************************************//**
1243  * @brief Read observation attributes
1244  *
1245  * @param[in] hdu FITS HDU pointer
1246  *
1247  * Reads optional attributes are
1248  *
1249  * OBS_ID - Observation identifier
1250  * OBJECT - Object
1251  *
1252  * Nothing is done if the HDU pointer is NULL.
1253  ***************************************************************************/
1255 {
1256  // Continue only if HDU is valid
1257  if (hdu != NULL) {
1258 
1259  // Read observation information
1260  m_obs_id = (hdu->has_card("OBS_ID")) ? hdu->real("OBS_ID") : 0;
1261  m_name = (hdu->has_card("OBJECT")) ? hdu->string("OBJECT") : "unknown";
1262 
1263  } // endif: HDU was valid
1264 
1265  // Return
1266  return;
1267 }
1268 
1269 
1270 /***********************************************************************//**
1271  * @brief Write observation attributes
1272  *
1273  * @param[in] hdu FITS HDU pointer
1274  *
1275  * Nothing is done if the HDU pointer is NULL.
1276  *
1277  * @todo Implement method.
1278  ***************************************************************************/
1280 {
1281  // Continue only if HDU is valid
1282  if (hdu != NULL) {
1283 
1284  } // endif: HDU was valid
1285 
1286  // Return
1287  return;
1288 }
1289 
1290 
1291 /***********************************************************************//**
1292  * @brief Compute DRB cube using PHINOR method
1293  *
1294  * @param[in] drm DRM cube.
1295  *
1296  * @exception GException::invalid_value
1297  * Observation does not contain an event cube
1298  * @exception GException::invalid_argument
1299  * DRM cube is incompatible with DRE
1300  ***************************************************************************/
1302 {
1303  // Extract COMPTEL event cube
1304  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
1305  if (cube == NULL) {
1306  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
1307  "does not contain a COMPTEL event cube. Please "
1308  "specify a COMPTEL observation containing and event "
1309  "cube.";
1311  }
1312 
1313  // Check DRM
1314  if (!check_dri(drm)) {
1315  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
1316  "specify a DRM with a data-space definition that is "
1317  "identical to that of the DRE.";
1319  }
1320 
1321  // Initialise DRB by cloning DRG
1322  m_drb = m_drg;
1323 
1324  // Get DRI sky maps
1325  const GSkyMap& map_dre = cube->dre().map();
1326  const GSkyMap& map_drm = drm.map();
1327  GSkyMap map_drg = get_weighted_drg_map();
1328  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
1329 
1330  // Get data space dimensions
1331  int npix = m_drg.map().npix();
1332  int nphibar = m_drg.nphibar();
1333 
1334  // Phibar normalise DRB
1335  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1336  double sum_dre = 0.0;
1337  double sum_drm = 0.0;
1338  double sum_drg = 0.0;
1339  for (int ipix = 0; ipix < npix; ++ipix) {
1340  sum_dre += map_dre(ipix, iphibar);
1341  sum_drm += map_drm(ipix, iphibar);
1342  sum_drg += map_drg(ipix, iphibar);
1343  }
1344  if (sum_drg > 0.0) {
1345  double norm = (sum_dre - sum_drm) / sum_drg;
1346  for (int ipix = 0; ipix < npix; ++ipix) {
1347  map_drb(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1348  }
1349  }
1350  else {
1351  for (int ipix = 0; ipix < npix; ++ipix) {
1352  map_drb(ipix, iphibar) = 0.0;
1353  }
1354  }
1355  }
1356 
1357  // Make sure that DRB is non-negative
1358  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1359  for (int ipix = 0; ipix < npix; ++ipix) {
1360  if (map_drb(ipix, iphibar) < 0.0) {
1361  map_drb(ipix, iphibar) = 0.0;
1362  }
1363  }
1364  }
1365 
1366  // Return
1367  return;
1368 }
1369 
1370 
1371 /***********************************************************************//**
1372  * @brief Compute DRB cube using BGDLIXA method
1373  *
1374  * @param[in] drm DRM cube.
1375  * @param[in] nrunav Number of bins used for running average.
1376  * @param[in] navgr Number of bins used for averaging.
1377  * @param[in] nincl Number of Phibar layers to include.
1378  * @param[in] nexcl Number of Phibar layers to exclude.
1379  *
1380  * @exception GException::invalid_value
1381  * Observation does not contain an event cube
1382  * @exception GException::invalid_argument
1383  * DRM cube is incompatible with DRE
1384  *
1385  * Computes a DRB cube using the BGDLIXA method that is documented in Rob
1386  * van Dijk's PhD thesis. The revelant equations from the thesis that are
1387  * implemented here are 3.12, 3.12 and 3.14.
1388  ***************************************************************************/
1390  const int& nrunav,
1391  const int& navgr,
1392  const int& nincl,
1393  const int& nexcl)
1394 {
1395  // Extract COMPTEL event cube
1396  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
1397  if (cube == NULL) {
1398  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
1399  "does not contain a COMPTEL event cube. Please "
1400  "specify a COMPTEL observation containing and event "
1401  "cube.";
1403  }
1404 
1405  // Check DRM
1406  if (!check_dri(drm)) {
1407  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
1408  "specify a DRM with a data-space definition that is "
1409  "identical to that of the DRE.";
1411  }
1412 
1413  // Initialise DRB and scratch DRI by cloning DRG
1414  m_drb = m_drg;
1415  GCOMDri dri = m_drg;
1416 
1417  // Get references to relevant sky maps
1418  const GSkyMap& map_dre = cube->dre().map();
1419  const GSkyMap& map_drm = drm.map();
1420  GSkyMap map_drg = get_weighted_drg_map();
1421  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
1422  GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map());
1423 
1424  // Get data space dimensions
1425  int nchi = m_drg.nchi();
1426  int npsi = m_drg.npsi();
1427  int nphibar = m_drg.nphibar();
1428  int npix = nchi * npsi;
1429 
1430  // Precompute half running average lengths
1431  int navgr2 = int(navgr/2);
1432 
1433  // Initialise DRB and scratch DRI
1434  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1435  for (int ipix = 0; ipix < npix; ++ipix) {
1436  map_drb(ipix, iphibar) = 0.0;
1437  map_dri(ipix, iphibar) = 0.0;
1438  }
1439  }
1440 
1441  // Phibar normalise DRB (Equation 3.12 in Rob van Dijk's PhD thesis).
1442  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1443  double sum_dre = 0.0;
1444  double sum_drm = 0.0;
1445  double sum_drg = 0.0;
1446  for (int ipix = 0; ipix < npix; ++ipix) {
1447  sum_dre += map_dre(ipix, iphibar);
1448  sum_drm += map_drm(ipix, iphibar);
1449  sum_drg += map_drg(ipix, iphibar);
1450  }
1451  if (sum_drg > 0.0) {
1452  double norm = (sum_dre - sum_drm) / sum_drg;
1453  for (int ipix = 0; ipix < npix; ++ipix) {
1454  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1455  }
1456  }
1457  }
1458 
1459  // Do 3D running average of DRE and Phibar normalised DRG (Equation 3.13
1460  // in Rob van Dijk's PhD thesis). The result is a Phibar normalised DRG
1461  // that is normalised over the 3D region to the DRE. The 3D region is all
1462  // Phibar layers and [-nrunav,+nrunav] Chi/Psi pixels around the pixel of
1463  // consideration.
1464  if (nrunav >= 1) {
1465 
1466  // Loop over Chi pixels
1467  for (int ichi = 0; ichi < nchi; ++ichi) {
1468 
1469  // Compute running average window in Chi
1470  int kchi_min = ichi - nrunav;
1471  int kchi_max = ichi + nrunav;
1472  if (kchi_min < 0) {
1473  kchi_min = 0;
1474  }
1475  if (kchi_max >= nchi) {
1476  kchi_max = nchi - 1;
1477  }
1478 
1479  // Loop over Psi pixels
1480  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
1481 
1482  // Compute running average window in Psi
1483  int kpsi_min = ipsi - nrunav;
1484  int kpsi_max = ipsi + nrunav;
1485  if (kpsi_min < 0) {
1486  kpsi_min = 0;
1487  }
1488  if (kpsi_max >= npsi) {
1489  kpsi_max = npsi - 1;
1490  }
1491 
1492  // Initialise sums
1493  double sum_dre = 0.0;
1494  double sum_drm = 0.0;
1495  double sum_dri = 0.0;
1496 
1497  // Compute running average
1498  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
1499  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
1500  int kpix = kchi + kpsi * nchi;
1501  for (int kphibar = 0; kphibar < nphibar; ++kphibar) {
1502  if (map_drg(kpix, kphibar) != 0.0) {
1503  sum_dre += map_dre(kpix, kphibar);
1504  sum_drm += map_drm(kpix, kphibar);
1505  sum_dri += map_dri(kpix, kphibar);
1506  }
1507  }
1508  }
1509  }
1510 
1511  // Renormalise scratch array
1512  if (sum_dri != 0.0) {
1513  int ipix = ichi + ipsi * nchi;
1514  double norm = (sum_dre - sum_drm) / sum_dri;
1515  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1516  map_dri(ipix, iphibar) *= norm;
1517  }
1518  }
1519 
1520  } // endfor: looped over Phi
1521 
1522  } // endfor: looped over Chi
1523 
1524  } // endif: running averaging was requested
1525 
1526  // First part of Equation (3.14) in Rob van Dijk's PhD thesis.
1527  // (DRB = B^0C_L / sum B^0C_L). The DRB is pre-computed by adjusting the
1528  // scratch DRI over nincl Phibar layers.
1529  int ksel1 = 0;
1530  int kex1 = 0;
1531  int kex2 = 0;
1532  int ksel2 = 0;
1533  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1534 
1535  // Get Phibar index range for sums
1536  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
1537  &ksel1, &kex1, &kex2, &ksel2);
1538 
1539  // Loop over Chi/Psi pixels
1540  for (int ipix = 0; ipix < npix; ++ipix) {
1541 
1542  // Initialise DRB value
1543  map_drb(ipix, iphibar) = 0.0;
1544 
1545  // Continue only if scratch DRI is non-zero
1546  if (map_dri(ipix, iphibar) != 0.0) {
1547 
1548  // Initialise sum
1549  double sum_dri = 0.0;
1550 
1551  // Take sum over [ksel1, kex1]
1552  if (kex1 >= 0) {
1553  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
1554  sum_dri += map_dri(ipix, kphibar);
1555  }
1556  }
1557 
1558  // Take sum over [kxe2, ksel2]
1559  if (kex2 < nphibar) {
1560  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
1561  sum_dri += map_dri(ipix, kphibar);
1562  }
1563  }
1564 
1565  // If sum is not zero then set DRB
1566  if (sum_dri != 0.0) {
1567  map_drb(ipix, iphibar) = map_dri(ipix, iphibar) / sum_dri;
1568  }
1569 
1570  } // endif: scratch DRI was non-zero
1571 
1572  } // endfor: looped over Chi/Psi pixels
1573 
1574  } // endfor: looped over Phibar
1575 
1576  // Second part of Equation (3.14) in Rob van Dijk's PhD thesis that
1577  // corresponds to G * [E / G]^s that will be stored in scratch DRI.
1578  //
1579  // NOTES:
1580  // - we replaced DRE by DRE-DRM in the nominator of the running
1581  // average since and source component should of course be
1582  // subtracted
1583  // - we implemented an alternative running average computation where
1584  // the ratio between the DRE and DRG sums is taken. This avoids
1585  // the divergence of the ratio at the edge of the DRG.
1586  for (int ichi = 0; ichi < nchi; ++ichi) {
1587 
1588  // Compute running average window in Chi
1589  int kchi_min = ichi - navgr2;
1590  int kchi_max = ichi + navgr2;
1591  if (kchi_min < 0) {
1592  kchi_min = 0;
1593  }
1594  if (kchi_max >= nchi) {
1595  kchi_max = nchi - 1;
1596  }
1597 
1598  // Loop over Psi pixels
1599  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
1600 
1601  // Compute running average window in Psi
1602  int kpsi_min = ipsi - navgr2;
1603  int kpsi_max = ipsi + navgr2;
1604  if (kpsi_min < 0) {
1605  kpsi_min = 0;
1606  }
1607  if (kpsi_max >= npsi) {
1608  kpsi_max = npsi - 1;
1609  }
1610 
1611  // Loop over Phibar layers
1612  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1613 
1614  // Initialise sums
1615  double sum_dre = 0.0;
1616  double sum_drm = 0.0;
1617  double sum_drg = 0.0;
1618 
1619  // Compute running average
1620  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
1621  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
1622  int kpix = kchi + kpsi * nchi;
1623  sum_dre += map_dre(kpix, iphibar);
1624  sum_drm += map_drm(kpix, iphibar);
1625  sum_drg += map_drg(kpix, iphibar);
1626  }
1627  }
1628 
1629  // Multiply average by DRG and store it in scratch DRI
1630  int ipix = ichi + ipsi * nchi;
1631  if (sum_drg > 0.0) {
1632  double norm = (sum_dre - sum_drm) / sum_drg;
1633  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1634  }
1635  else {
1636  map_dri(ipix, iphibar) = 0.0;
1637  }
1638 
1639  } // endfor: looped over Phibar layers
1640 
1641  } // endfor: looped over Psi pixels
1642 
1643  } // endfor: looped over Chi pixels
1644 
1645  // Third part of Equation (3.14) in Rob van Dijk's PhD thesis that sums
1646  // G * [E / G]^s over a subset of Phibar layers (the first parenthesis)
1647  // and multplies with B^0C_L / sum B^0C_L
1648  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1649 
1650  // Get Phibar index range for sums
1651  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
1652  &ksel1, &kex1, &kex2, &ksel2);
1653 
1654  // Loop over Chi/Psi pixels
1655  for (int ipix = 0; ipix < npix; ++ipix) {
1656 
1657  // If DRB is not empty then correct it
1658  if (map_drb(ipix, iphibar) != 0.0) {
1659 
1660  // Initialise DRI sum
1661  double sum_dri = 0.0;
1662 
1663  // Take sum over [ksel1, kex1]
1664  if (kex1 >= 0) {
1665  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
1666  sum_dri += map_dri(ipix, kphibar);
1667  }
1668  }
1669 
1670  // Take sum over [kxe2, ksel2]
1671  if (kex2 < nphibar) {
1672  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
1673  sum_dri += map_dri(ipix, kphibar);
1674  }
1675  }
1676 
1677  // Correct DRB
1678  map_drb(ipix, iphibar) *= sum_dri;
1679 
1680  } // endif: DRB was not empty
1681 
1682  } // endfor: looped over Chi/Psi pixels
1683 
1684  } // endfor: looped over Phibar
1685 
1686  // Phibar normalise DRB
1687  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1688  double sum_dre = 0.0;
1689  double sum_drm = 0.0;
1690  double sum_drb = 0.0;
1691  for (int ipix = 0; ipix < npix; ++ipix) {
1692  sum_dre += map_dre(ipix, iphibar);
1693  sum_drm += map_drm(ipix, iphibar);
1694  sum_drb += map_drb(ipix, iphibar);
1695  }
1696  if (sum_drb > 0.0) {
1697  double norm = (sum_dre - sum_drm) / sum_drb;
1698  for (int ipix = 0; ipix < npix; ++ipix) {
1699  map_drb(ipix, iphibar) *= norm;
1700  }
1701  }
1702  else {
1703  for (int ipix = 0; ipix < npix; ++ipix) {
1704  map_drb(ipix, iphibar) = 0.0;
1705  }
1706  }
1707  }
1708 
1709  // Make sure that DRB is non-negative
1710  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1711  for (int ipix = 0; ipix < npix; ++ipix) {
1712  if (map_drb(ipix, iphibar) < 0.0) {
1713  map_drb(ipix, iphibar) = 0.0;
1714  }
1715  }
1716  }
1717 
1718  // Return
1719  return;
1720 }
1721 
1722 
1723 /***********************************************************************//**
1724  * @brief Compute DRB cube using BGDLIXE method
1725  *
1726  * @param[in] drm DRM cube.
1727  * @param[in] nrunav Number of bins used for running average.
1728  * @param[in] navgr Number of bins used for averaging.
1729  * @param[in] nincl Number of Phibar layers to include.
1730  * @param[in] nexcl Number of Phibar layers to exclude.
1731  *
1732  * @exception GException::invalid_value
1733  * Observation does not contain an event cube
1734  * @exception GException::invalid_argument
1735  * DRM cube is incompatible with DRE
1736  *
1737  * Computes a DRB cube using the BGDLIXE method. This method differs from
1738  * the BGDLIXA method in the last step.
1739  ***************************************************************************/
1741  const int& nrunav,
1742  const int& navgr,
1743  const int& nincl,
1744  const int& nexcl)
1745 {
1746  // Extract COMPTEL event cube
1747  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
1748  if (cube == NULL) {
1749  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
1750  "does not contain a COMPTEL event cube. Please "
1751  "specify a COMPTEL observation containing and event "
1752  "cube.";
1754  }
1755 
1756  // Check DRM
1757  if (!check_dri(drm)) {
1758  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
1759  "specify a DRM with a data-space definition that is "
1760  "identical to that of the DRE.";
1762  }
1763 
1764  // Initialise DRB and scratch DRI by cloning DRG
1765  m_drb = m_drg;
1766  GCOMDri dri = m_drg;
1767 
1768  // Get references to relevant sky maps
1769  const GSkyMap& map_dre = cube->dre().map();
1770  const GSkyMap& map_drm = drm.map();
1771  GSkyMap map_drg = get_weighted_drg_map();
1772  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
1773  GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map());
1774 
1775  // Get data space dimensions
1776  int nchi = m_drg.nchi();
1777  int npsi = m_drg.npsi();
1778  int nphibar = m_drg.nphibar();
1779  int npix = nchi * npsi;
1780 
1781  // Precompute half running average lengths
1782  int navgr2 = int(navgr/2);
1783 
1784  // Initialise DRB and scratch DRI
1785  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1786  for (int ipix = 0; ipix < npix; ++ipix) {
1787  map_drb(ipix, iphibar) = 0.0;
1788  map_dri(ipix, iphibar) = 0.0;
1789  }
1790  }
1791 
1792  // Phibar normalise DRG (Equation 3.12 in Rob van Dijk's PhD thesis).
1793  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1794  double sum_dre = 0.0;
1795  double sum_drm = 0.0;
1796  double sum_drg = 0.0;
1797  for (int ipix = 0; ipix < npix; ++ipix) {
1798  sum_dre += map_dre(ipix, iphibar);
1799  sum_drm += map_drm(ipix, iphibar);
1800  sum_drg += map_drg(ipix, iphibar);
1801  }
1802  if (sum_drg > 0.0) {
1803  double norm = (sum_dre - sum_drm) / sum_drg;
1804  for (int ipix = 0; ipix < npix; ++ipix) {
1805  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1806  }
1807  }
1808  }
1809 
1810  // Fit Phibar normalised DRG to DRE-DRM
1811  for (int ichi = 0; ichi < nchi; ++ichi) {
1812 
1813  // Compute running average window in Chi
1814  int kchi_min = ichi - navgr2;
1815  int kchi_max = ichi + navgr2;
1816  if (kchi_min < 0) {
1817  kchi_min = 0;
1818  }
1819  if (kchi_max >= nchi) {
1820  kchi_max = nchi - 1;
1821  }
1822 
1823  // Loop over Psi pixels
1824  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
1825 
1826  // Compute running average window in Psi
1827  int kpsi_min = ipsi - navgr2;
1828  int kpsi_max = ipsi + navgr2;
1829  if (kpsi_min < 0) {
1830  kpsi_min = 0;
1831  }
1832  if (kpsi_max >= npsi) {
1833  kpsi_max = npsi - 1;
1834  }
1835 
1836  // Loop over Phibar layers
1837  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1838 
1839  // Get Phibar index range for sums
1840  int ksel1 = 0;
1841  int kex1 = 0;
1842  int kex2 = 0;
1843  int ksel2 = 0;
1844  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
1845  &ksel1, &kex1, &kex2, &ksel2);
1846 
1847  // Initialise sums
1848  double sum_dre = 0.0;
1849  double sum_drm = 0.0;
1850  double sum_dri = 0.0;
1851 
1852  // Compute running average
1853  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
1854  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
1855 
1856  // Get index
1857  int kpix = kchi + kpsi * nchi;
1858 
1859  // Take sum over [ksel1, kex1]
1860  if (kex1 >= 0) {
1861  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
1862  sum_dre += map_dre(kpix, kphibar);
1863  sum_drm += map_drm(kpix, kphibar);
1864  sum_dri += map_dri(kpix, kphibar);
1865  }
1866  }
1867 
1868  // Take sum over [kxe2, ksel2]
1869  if (kex2 < nphibar) {
1870  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
1871  sum_dre += map_dre(kpix, kphibar);
1872  sum_drm += map_drm(kpix, kphibar);
1873  sum_dri += map_dri(kpix, kphibar);
1874  }
1875  }
1876 
1877  } // endfor: looped over kpsi
1878  } // endfor: looped over kchi
1879 
1880  // Renormalize DRI locally to DRE-DRM
1881  int ipix = ichi + ipsi * nchi;
1882  if (sum_dri > 0.0) {
1883  double norm = (sum_dre - sum_drm) / sum_dri;
1884  map_drb(ipix, iphibar) = map_dri(ipix, iphibar) * norm;
1885  }
1886  else {
1887  map_drb(ipix, iphibar) = 0.0;
1888  }
1889 
1890  } // endfor: looped over Phibar layers
1891 
1892  } // endfor: looped over Psi pixels
1893 
1894  } // endfor: looped over Chi pixels
1895 
1896  // Phibar normalise DRB
1897  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1898  double sum_dre = 0.0;
1899  double sum_drm = 0.0;
1900  double sum_drb = 0.0;
1901  for (int ipix = 0; ipix < npix; ++ipix) {
1902  sum_dre += map_dre(ipix, iphibar);
1903  sum_drm += map_drm(ipix, iphibar);
1904  sum_drb += map_drb(ipix, iphibar);
1905  }
1906  if (sum_drb > 0.0) {
1907  double norm = (sum_dre - sum_drm) / sum_drb;
1908  for (int ipix = 0; ipix < npix; ++ipix) {
1909  map_drb(ipix, iphibar) *= norm;
1910  }
1911  }
1912  else {
1913  for (int ipix = 0; ipix < npix; ++ipix) {
1914  map_drb(ipix, iphibar) = 0.0;
1915  }
1916  }
1917  }
1918 
1919  // Make sure that DRB is non-negative
1920  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1921  for (int ipix = 0; ipix < npix; ++ipix) {
1922  if (map_drb(ipix, iphibar) < 0.0) {
1923  map_drb(ipix, iphibar) = 0.0;
1924  }
1925  }
1926  }
1927 
1928  // Return
1929  return;
1930 }
1931 
1932 
1933 /***********************************************************************//**
1934  * @brief Return weighted DRG map
1935  *
1936  * @return Weighted DRG map.
1937  *
1938  * Returns a DRG as sky map where each pixel of the map is multiplied by the
1939  * solidangle of the pixel.
1940  ***************************************************************************/
1942 {
1943  // Initialise
1944  GSkyMap drg = m_drg.map();
1945 
1946  // Get data space dimensions
1947  int npix = drg.npix();
1948  int nphibar = drg.nmaps();
1949 
1950  // Weight map
1951  for (int ipix = 0; ipix < npix; ++ipix) {
1952  double omega = drg.solidangle(ipix);
1953  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1954  drg(ipix,iphibar) *= omega;
1955  }
1956  }
1957 
1958  // Return weighted DRG map
1959  return drg;
1960 }
1961 
1962 
1963 /***********************************************************************//**
1964  * @brief Compute Phibar index range for BGDLIXA background method
1965  *
1966  * @param[in] iphibar Phibar layer index.
1967  * @param[in] nincl Number of Phibar layers to include.
1968  * @param[in] nexcl Number of Phibar layers to exclude.
1969  * @param[out] isel1 Start index for first sum.
1970  * @param[out] iex1 Stop index for first sum.
1971  * @param[out] iex2 Start index for second sum.
1972  * @param[out] isel2 Stop index for second sum.
1973  *
1974  * This method is a helper method for the BGDLIXA background method. It
1975  * computes the Phibar index range for the third step of the background
1976  * model computation. The third step corresponds to Equation (3.14) in Rob
1977  * van Dijk's PhD thesis.
1978  *
1979  * The Phibar sum will be taken over the index ranges [isel1, iex1] and
1980  * [ixe2, isel2].
1981  ***************************************************************************/
1983  const int& nincl,
1984  const int& nexcl,
1985  int* isel1,
1986  int* iex1,
1987  int* iex2,
1988  int* isel2) const
1989 {
1990  // Get number of Phibar layers
1991  int nphibar = m_drg.nphibar();
1992  int imax = nphibar - 1;
1993 
1994  // Precompute half running average lengths
1995  int nexcl2 = int(nexcl/2);
1996  int nincl2 = int(nincl/2);
1997 
1998  // Compute Phibar index range without respecting boundaries
1999  *iex1 = iphibar - nexcl2 - 1;
2000  *iex2 = iphibar + nexcl2 + 1;
2001  *isel1 = iphibar - nincl2;
2002  *isel2 = iphibar + nincl2;
2003 
2004  // If no Phibar layers are to be excluded then make sure that the
2005  // Phibar layer range is continuous
2006  if (nexcl == 0) {
2007  (*iex2)--;
2008  }
2009 
2010  // Make sure that start index of first sum and stop index of second
2011  // some are within the validity range
2012  if (*isel1 < 0) {
2013  *isel1 = 0;
2014  }
2015  if (*isel2 > imax) {
2016  *isel2 = imax;
2017  }
2018 
2019  // Make sure that the sums use always ncincl Phibar layers, also near
2020  // the edges
2021  if (*isel1 == 0) {
2022  *isel2 = nincl - 1;
2023  if (nincl > imax) {
2024  *isel2 = imax;
2025  }
2026 
2027  }
2028  if (*isel2 == imax) {
2029  *isel1 = nphibar - nincl;
2030  if (*isel1 < 0) {
2031  *isel1 = 0;
2032  }
2033  }
2034 
2035  // Return
2036  return;
2037 }
2038 
2039 
2040 /***********************************************************************//**
2041  * @brief Check whether bin should be used for likelihood analysis
2042  *
2043  * @param[in] index Event index.
2044  * @return True if event with specified @p index should be used.
2045  *
2046  * Implements the Phibar event selection.
2047  ***************************************************************************/
2048 bool GCOMObservation::use_event_for_likelihood(const int& index) const
2049 {
2050  // Initialise usage flag
2051  bool use = true;
2052 
2053  // Compute Phibar layer
2054  int iphi = index / m_drg.map().npix();
2055 
2056  // Test first Phibar layer selection
2057  if ((m_phi_first != -1) && (iphi < m_phi_first)) {
2058  use = false;
2059  }
2060  else {
2061  // Test last Phibar layer selection
2062  if ((m_phi_last != -1) && (iphi > m_phi_last)) {
2063  use = false;
2064  }
2065  }
2066 
2067  // Return usage flag
2068  return use;
2069 }
#define G_LOAD_DRB
virtual void clear(void)
Clear COMPTEL observation.
const std::string & statistic(void) const
Return optimizer statistic.
double eval(const GEvent &event, const GObservation &obs, const bool &gradients=false) const
Evaluate sum of all models.
Definition: GModels.cpp:911
const std::string & rspname(void) const
Return response name.
COMPTEL instrument status class definition.
Sky map class.
Definition: GSkyMap.hpp:89
Abstract FITS image base class.
Definition: GFitsImage.hpp:43
void compute_drb(const std::string &method, const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=13, const int &nexcl=0)
Compute DRB cube.
virtual void clear(void)
Clear instance.
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
const GSkyProjection * projection(void) const
Returns pointer to sky projection.
Definition: GSkyMap.hpp:463
void get_bgdlixa_phibar_indices(const int &iphibar, const int &nincl, const int &nexcl, int *isel1, int *iex1, int *iex2, int *isel2) const
Compute Phibar index range for BGDLIXA background method.
std::string m_name
Observation name.
double m_obs_id
Observation ID.
#define G_RESPONSE
GFilename m_bvcname
BVC filename.
XML element node class interface definition.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print COMPTEL Good Time Intervals.
Definition: GCOMTim.cpp:408
void copy_members(const GCOMObservation &obs)
Copy class members.
Model container class definition.
GFilename m_drbname
DRB filename.
void init_members(void)
Initialise class members.
Abstract FITS extension base class.
Definition: GFitsHDU.hpp:51
double m_deadc
Deadtime correction.
GFilename m_timname
TIM filename.
const GCOMDri & drx(void) const
Return exposure.
std::vector< GFilename > m_oadnames
OAD filenames.
GEvents * m_events
Pointer to event container.
const GFilename & drxname(void) const
Return DRX filename.
virtual int size(void) const
Return number of bins in event cube.
const GFilename & drbname(void) const
Return DRB filename.
virtual double ontime(void) const
Return ontime.
GFilename m_evpname
EVP filename.
bool is_empty(void) const
Signal if filename is empty.
Definition: GFilename.hpp:160
#define G_DRM
void caldb(const GCaldb &caldb)
Set calibration database.
COMPTEL observation class interface definition.
XML element node class.
Definition: GXmlElement.hpp:48
GCOMDri m_drx
Exposure map.
void gti(const GGti &gti)
Set Good Time Intervals.
Definition: GEvents.cpp:154
bool is_unbinned(void) const
Check whether observation is unbinned.
const GCOMDri & drb(void) const
Return background model.
bool is_empty(void) const
Signals if there are no Orbit Aspect Data in container.
Definition: GCOMOads.hpp:156
#define G_WRITE
GCOMDri m_drg
Geometry factors.
Interface for the COMPTEL instrument response function.
double MeV(void) const
Return energy in MeV.
Definition: GEnergy.cpp:321
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:586
void load_dre(const GFilename &drename)
Load event cube data from DRE file.
std::string print(const GChatter &chatter=NORMAL) const
Print COMPTEL Orbit Aspect Data container.
Definition: GCOMOads.cpp:496
Gammalib tools definition.
void free_members(void)
Delete class members.
int size(void) const
Return number of Orbit Aspect Data in container.
Definition: GCOMOads.hpp:141
FITS file class.
Definition: GFits.hpp:63
#define G_COMPUTE_DRB_BGDLIXA
void clear(void)
Clear COMPTEL Orbit Aspect Data container.
Definition: GCOMOads.cpp:167
const int & phi_first(void) const
Return index of first Phibar layer to be used for likelihood fitting.
FITS file class interface definition.
int nchi(void) const
Return number of Chi bins.
Definition: GCOMDri.hpp:231
#define G_COMPUTE_DRB_BGDLIXE
COMPTEL event bin class.
GCOMTim m_tim
COMPTEL Good Time Intervals.
GFilename xml_file_reduce(const GXmlElement &xml, const std::string &filename)
Reduce file name provided for writing as XML attribute.
Definition: GTools.cpp:1946
const GFilename & drgname(void) const
Return DRG filename.
Source class definition.
bool is_empty(void) const
Signals if there are no Solar System Barycentre Data in container.
Definition: GCOMBvcs.hpp:163
Implementation of support function used by COMPTEL classes.
int size(void) const
Return number of Good Time Intervals.
Definition: GGti.hpp:154
const GCOMObservation g_obs_com_seed
virtual std::string print(const GChatter &chatter=NORMAL) const
Print observation information.
#define G_COMPUTE_DRB
COMPTEL event bin class interface definition.
void free_members(void)
Delete class members.
void load(const GFilename &drename, const GFilename &drbname, const GFilename &drgname, const GFilename &drxname)
Load data for a binned observation.
GCOMDri m_drb
Background model.
virtual const GCOMResponse * response(void) const
Return response function.
GCOMDri drm(const GModels &models) const
Compute DRM cube.
Abstract FITS extension base class definition.
double real(const std::string &keyname) const
Return card value as double precision.
Definition: GFitsHDU.hpp:423
const GCOMDri & drg(void) const
Return geometry factors.
Model container class.
Definition: GModels.hpp:152
Calibration database class.
Definition: GCaldb.hpp:66
virtual void read(const GFits &file)=0
GCOMBvcs m_bvcs
Solar System Barycentre Data.
const std::string & id(void) const
Return observation identifier.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
const int & nmaps(void) const
Returns number of maps.
Definition: GSkyMap.hpp:389
void compute_drb_phinor(const GCOMDri &drm)
Compute DRB cube using PHINOR method.
const GFilename & drename(void) const
Return DRE filename.
virtual void write(GXmlElement &xml) const
Write observation into XML element.
virtual void read(const GXmlElement &xml)
Read observation from XML element.
Filename class.
Definition: GFilename.hpp:62
virtual double model(const GModels &models, const GEvent &event, GVector *gradients=NULL) const
Return model value and (optionally) gradients.
void com_wcs_mer2car(GSkyMap &map)
Changes Mercator&#39;s projection to cartesian projection.
Definition: GCOMSupport.cpp:56
void load_drb(const GFilename &drbname)
Load background model from DRB file.
const GSkyMap & map(void) const
Return DRI sky map.
Definition: GCOMDri.hpp:267
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
double m_ontime
Ontime (sec)
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition: GTools.cpp:1637
bool is_binned(void) const
Check whether observation is binned.
Constant spectral model class interface definition.
Interface definition for the observation registry class.
const std::string & name(void) const
Return observation name.
#define G_READ
void read_attributes(const GFitsHDU *hdu)
Read observation attributes.
Observation registry class definition.
void compute_drb_bgdlixa(const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=13, const int &nexcl=0)
Compute DRB cube using BGDLIXA method.
virtual void clear(void)
Clear COMPTEL good time intervals.
Definition: GCOMTim.cpp:185
virtual std::string instrument(void) const
Return instrument.
GChatter
Definition: GTypemaps.hpp:33
bool is_fits(void) const
Checks whether file is a FITS file.
Definition: GFilename.cpp:313
double m_livetime
Livetime (sec)
void init_members(void)
Initialise class members.
Abstract observation base class.
virtual GCOMObservation * clone(void) const
Clone COMPTEL observation.
COMPTEL event bin container class.
void extend(const GCOMOads &oads)
Append Orbit Aspect Data container.
Definition: GCOMOads.cpp:329
#define G_COMPUTE_DRB_PHINOR
Calibration database class interface definition.
int nphibar(void) const
Return number of Phibar bins.
Definition: GCOMDri.hpp:255
bool xml_has_par(const GXmlElement &xml, const std::string &name)
Checks if parameter with given name in XML element exists.
Definition: GTools.cpp:1596
const GCOMDri & dre(void) const
Return reference to DRE data.
GFitsImage * image(const int &extno)
Get pointer to image HDU.
Definition: GFits.cpp:368
void compute_drb_bgdlixe(const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=13, const int &nexcl=0)
Compute DRB cube using BGDLIXE method.
std::string print(const GChatter &chatter=NORMAL) const
Print COMPTEL Solar System Barycentre Data container.
Definition: GCOMBvcs.cpp:692
double m_ewidth
Energy width (MeV)
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition: GXmlNode.cpp:640
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
Sky model class interface definition.
virtual double counts(void) const
Return number of counts in event bin.
virtual void clear(void)
Clear COMPTEL Data Space.
Definition: GCOMDri.cpp:228
const GEnergy & emin(void) const
Return minimum energy.
Definition: GEvents.hpp:170
GCOMOads m_oads
Orbit Aspect Data.
void load_drx(const GFilename &drxname)
Load exposure from DRX file.
void read(const GFitsImage &image)
Read COMPTEL Data Space from DRI FITS image.
Definition: GCOMDri.cpp:942
Interface class for COMPTEL observations.
GChatter reduce(const GChatter &chatter)
Reduce chattiness by one level.
Definition: GTypemaps.hpp:65
GSkyMap get_weighted_drg_map(void) const
Return weighted DRG map.
int npsi(void) const
Return number of Psi bins.
Definition: GCOMDri.hpp:243
void clear(void)
Clear COMPTEL Solar System Barycentre Data container.
Definition: GCOMBvcs.cpp:170
virtual bool use_event_for_likelihood(const int &index) const
Check whether bin should be used for likelihood analysis.
void load(const GFilename &filename, const std::string &usage="YES", const std::string &mode="NORMAL")
Load COMPTEL Good Time Intervals from FITS file.
Definition: GCOMTim.cpp:218
virtual GObservation & operator=(const GObservation &obs)
Assignment operator.
virtual GEvents * events(void)
Return events.
std::string string(const std::string &keyname) const
Return card value as string.
Definition: GFitsHDU.hpp:410
Exception handler interface definition.
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
virtual double livetime(void) const
Return livetime.
COMPTEL Orbit Aspect Data container class.
Definition: GCOMOads.hpp:51
int m_phi_last
Last Phibar layer to use for likelihood.
std::string xml_get_attr(const std::string &origin, const GXmlElement &xml, const std::string &name, const std::string &attribute)
Return attribute value for a given parameter in XML element.
Definition: GTools.cpp:1738
int toint(const std::string &arg)
Convert string into integer value.
Definition: GTools.cpp:821
void write_attributes(GFitsHDU *hdu) const
Write observation attributes.
Vector class.
Definition: GVector.hpp:46
double solidangle(const int &index) const
Returns solid angle of pixel.
Definition: GSkyMap.cpp:1858
Abstract sky projection base class.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:287
Abstract instrument response base class.
Definition: GResponse.hpp:77
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
virtual double size(void) const
Return size of event bin.
virtual GCOMObservation & operator=(const GCOMObservation &obs)
Assignment operator.
const int & npix(void) const
Returns number of pixels.
Definition: GSkyMap.hpp:345
void load(const GFilename &filename)
Load COMPTEL Solar System Barycentre Data FITS file.
Definition: GCOMBvcs.cpp:370
bool check_dri(const GCOMDri &map) const
Check if DRI is compatible with event cube.
GCOMObservation(void)
Void constructor.
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
int m_phi_first
First Phibar layer to use for likelihood.
const int & phi_last(void) const
Return index of last Phibar layer to be used for likelihood fitting.
const GEnergy & emax(void) const
Return maximum energy.
Definition: GEvents.hpp:182
GFilename m_drxname
DRX filename.
virtual ~GCOMObservation(void)
Destructor.
const GGti & gti(void) const
Return Good Time Intervals.
Definition: GCOMTim.hpp:144
void load_drg(const GFilename &drgname)
Load geometry factors from DRG file.
const double & ontime(void) const
Returns ontime.
Definition: GGti.hpp:240
GCOMResponse m_response
Response functions.
GFilename m_drgname
DRG filename.
virtual std::string print(const GChatter &chatter=NORMAL) const =0
Print content of object.
std::string m_instrument
Instrument name.
Mathematical function definitions.
GFilename m_drename
DRE filename.
void load(const std::string &rspname)
Load COMPTEL response.
GFilename xml_file_expand(const GXmlElement &xml, const std::string &filename)
Expand file name provided as XML attribute for loading.
Definition: GTools.cpp:1889
virtual void remove(const int &index)
Remove XML child node.
Definition: GXmlNode.cpp:481
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489