GammaLib  2.1.0.dev
 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-2023 by Juergen Knoedlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file 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_DRW "GCOMObservation::load_drw(GFilename&)"
59 #define G_LOAD_DRG "GCOMObservation::load_drg(GFilename&)"
60 #define G_DRM "GCOMObservation::drm(GModels&)"
61 #define G_COMPUTE_DRB "GCOMObservation::compute_drb(std::string&, GCOMDri&, "\
62  "int&, int&, int&, int&"
63 #define G_COMPUTE_DRB_PHINOR "GCOMObservation::compute_drb_phinor(GCOMDri&)"
64 #define G_COMPUTE_DRB_BGDLIXA "GCOMObservation::compute_drb_bgdlixa("\
65  "GCOMDri&, int&, int&, int&, int&)"
66 #define G_COMPUTE_DRB_BGDLIXE "GCOMObservation::compute_drb_bgdlixe("\
67  "GCOMDri&, int&, int&, int&, int&)"
68 #define G_COMPUTE_DRB_BGDLIXF "GCOMObservation::compute_drb_bgdlixf("\
69  "GCOMDri&, int&, int&, int&, int&)"
70 
71 /* __ Macros _____________________________________________________________ */
72 
73 /* __ Coding definitions _________________________________________________ */
74 
75 /* __ Debug definitions __________________________________________________ */
76 
77 
78 /*==========================================================================
79  = =
80  = Constructors/destructors =
81  = =
82  ==========================================================================*/
83 
84 /***********************************************************************//**
85  * @brief Void constructor
86  *
87  * Creates an empty COMPTEL observation.
88  ***************************************************************************/
90 {
91  // Initialise members
92  init_members();
93 
94  // Return
95  return;
96 }
97 
98 
99 /***********************************************************************//**
100  * @brief XML constructor
101  *
102  * @param[in] xml XML element.
103  *
104  * Constructs a COMPTEL observation from the information that is found in an
105  * XML element.
106  ***************************************************************************/
108 {
109  // Initialise members
110  init_members();
111 
112  // Read XML
113  read(xml);
114 
115  // Return
116  return;
117 }
118 
119 
120 /***********************************************************************//**
121  * @brief Binned observation DRI constructor
122  *
123  * @param[in] dre Event cube.
124  * @param[in] drb Background cube.
125  * @param[in] drg Geometry cube.
126  * @param[in] drx Exposure map.
127  *
128  * Creates COMPTEL observation from DRI instances.
129  *
130  * The method fixes the deadtime correction factor deadc to 0.965.
131  ***************************************************************************/
133  const GCOMDri& drb,
134  const GCOMDri& drg,
135  const GCOMDri& drx) : GObservation()
136 {
137  // Initialise members
138  init_members();
139 
140  // Store DRIs
141  m_events = new GCOMEventCube(dre);
142  m_drb = drb;
143  m_drg = drg;
144  m_drx = drx;
145 
146  // Set attributes
147  m_obs_id = 0;
148  m_ontime = m_events->gti().ontime();
149  m_deadc = 0.965;
151  m_ewidth = m_events->emax().MeV() - m_events->emin().MeV();
152  m_name = "unknown";
153  m_drename = "";
154  m_drbname = "";
155  m_drwname = "";
156  m_drgname = "";
157  m_drxname = "";
158 
159  // Return
160  return;
161 }
162 
163 
164 /***********************************************************************//**
165  * @brief Binned observation DRI constructor
166  *
167  * @param[in] dre Event cube.
168  * @param[in] drb Background cube.
169  * @param[in] drw Weighting cube.
170  * @param[in] drg Geometry cube.
171  * @param[in] drx Exposure map.
172  *
173  * Creates COMPTEL observation from DRI instances.
174  *
175  * The method fixes the deadtime correction factor deadc to 0.965.
176  ***************************************************************************/
178  const GCOMDri& drb,
179  const GCOMDri& drw,
180  const GCOMDri& drg,
181  const GCOMDri& drx) : GObservation()
182 {
183  // Initialise members
184  init_members();
185 
186  // Store DRIs
187  m_events = new GCOMEventCube(dre);
188  m_drb = drb;
189  m_drw = drw;
190  m_drg = drg;
191  m_drx = drx;
192 
193  // Set attributes
194  m_obs_id = 0;
195  m_ontime = m_events->gti().ontime();
196  m_deadc = 0.965;
198  m_ewidth = m_events->emax().MeV() - m_events->emin().MeV();
199  m_name = "unknown";
200  m_drename = "";
201  m_drbname = "";
202  m_drwname = "";
203  m_drgname = "";
204  m_drxname = "";
205 
206  // Return
207  return;
208 }
209 
210 
211 /***********************************************************************//**
212  * @brief Binned observation filename constructor
213  *
214  * @param[in] drename Event cube name.
215  * @param[in] drbname Background cube name.
216  * @param[in] drwname Weighting cube name.
217  * @param[in] drgname Geometry cube name.
218  * @param[in] drxname Exposure map name.
219  *
220  * Creates COMPTEL observation by loading the following FITS files:
221  *
222  * DRE - Events cube
223  * DRB - Background model cube
224  * DRW - Weighting cube
225  * DRG - Geometry factors cube
226  * DRX - Exposure map
227  *
228  * Each of the four files is mandatory.
229  ***************************************************************************/
231  const GFilename& drbname,
232  const GFilename& drwname,
233  const GFilename& drgname,
234  const GFilename& drxname) : GObservation()
235 {
236  // Initialise members
237  init_members();
238 
239  // Load observation
240  load(drename, drbname, drwname, drgname, drxname);
241 
242  // Return
243  return;
244 }
245 
246 
247 /***********************************************************************//**
248  * @brief Unbinned observation constructor
249  *
250  * @param[in] evpname Event list FITS file name.
251  * @param[in] timname Good Time Intervals FITS file name.
252  * @param[in] oadnames List of Orbit Aspect Data FITS file names.
253  * @param[in] hkdnames List of Housekeeping Data FITS file names.
254  * @param[in] bvcname Solar System Barycentre Data FITS file name.
255  *
256  * Creates a COMPTEL unbinned observation by loading the event list, Good
257  * Time Interval, Orbit Aspect Data and optionally the Solar System
258  * Barycentre Data from FITS files.
259  *
260  * Except of the Housekeeping Data and the Solar System Barycentre Data all
261  * files are mandatory. The Housekeeping Data and the Solar System Barycentre
262  * Data will only be loaded if the file names are not empty.
263  *
264  * See load() method for more information.
265  ***************************************************************************/
267  const GFilename& timname,
268  const std::vector<GFilename>& oadnames,
269  const std::vector<GFilename>& hkdnames,
270  const GFilename& bvcname)
271 {
272  // Initialise members
273  init_members();
274 
275  // Load observation
276  load(evpname, timname, oadnames, hkdnames, bvcname);
277 
278  // Return
279  return;
280 }
281 
282 
283 /***********************************************************************//**
284  * @brief Copy constructor
285  *
286  * @param[in] obs COMPTEL observation.
287  *
288  * Creates COMPTEL observation by copying an existing COMPTEL observation.
289  ***************************************************************************/
291 {
292  // Initialise members
293  init_members();
294 
295  // Copy members
296  copy_members(obs);
297 
298  // Return
299  return;
300 }
301 
302 
303 /***********************************************************************//**
304  * @brief Destructor
305  ***************************************************************************/
307 {
308  // Free members
309  free_members();
310 
311  // Return
312  return;
313 }
314 
315 
316 /*==========================================================================
317  = =
318  = Operators =
319  = =
320  ==========================================================================*/
321 
322 /***********************************************************************//**
323  * @brief Assignment operator
324  *
325  * @param[in] obs COMPTEL observation.
326  * @return COMPTEL observation.
327  *
328  * Assign COMPTEL observation to this object.
329  ***************************************************************************/
331 {
332  // Execute only if object is not identical
333  if (this != &obs) {
334 
335  // Copy base class members
336  this->GObservation::operator=(obs);
337 
338  // Free members
339  free_members();
340 
341  // Initialise members
342  init_members();
343 
344  // Copy members
345  copy_members(obs);
346 
347  } // endif: object was not identical
348 
349  // Return this object
350  return *this;
351 }
352 
353 
354 /*==========================================================================
355  = =
356  = Public methods =
357  = =
358  ==========================================================================*/
359 
360 /***********************************************************************//**
361  * @brief Clear COMPTEL observation
362  ***************************************************************************/
364 {
365  // Free members
366  free_members();
368 
369  // Initialise members
371  init_members();
372 
373  // Return
374  return;
375 }
376 
377 
378 /***********************************************************************//**
379  * @brief Clone COMPTEL observation
380  *
381  * @return Pointer to deep copy of COMPTEL observation.
382  ***************************************************************************/
384 {
385  return new GCOMObservation(*this);
386 }
387 
388 
389 /***********************************************************************//**
390  * @brief Set response function
391  *
392  * @param[in] rsp Response function.
393  *
394  * @exception GException::invalid_argument
395  * Specified response is not a COMPTEL response.
396  *
397  * Sets the response function for the observation.
398  ***************************************************************************/
400 {
401  // Get pointer on COM response
402  const GCOMResponse* comrsp = dynamic_cast<const GCOMResponse*>(&rsp);
403  if (comrsp == NULL) {
404  std::string cls = std::string(typeid(&rsp).name());
405  std::string msg = "Response of type \""+cls+"\" is "
406  "not a COMPTEL response. Please specify a COMPTEL "
407  "response as argument.";
409  }
410 
411  // Clone response function
412  m_response = *comrsp;
413 
414  // Return
415  return;
416 }
417 
418 
419 /***********************************************************************//**
420  * @brief Set response function
421  *
422  * @param[in] caldb Calibration database.
423  * @param[in] rspname Name of COMPTEL response.
424  *
425  * Sets the response function by loading the response information from the
426  * calibration database.
427  ***************************************************************************/
428 void GCOMObservation::response(const GCaldb& caldb, const std::string& rspname)
429 {
430  // Clear COM response function
431  m_response.clear();
432 
433  // Set calibration database
434  m_response.caldb(caldb);
435 
436  // Load instrument response function
437  m_response.load(rspname);
438 
439  // Return
440  return;
441 }
442 
443 
444 /***********************************************************************//**
445  * @brief Return total number of predicted counts for one model
446  *
447  * @param[in] model Gamma-ray source model.
448  * @return Total number of predicted counts in model.
449  *
450  * Returns the total number of predicted counts in a given model component.
451  ***************************************************************************/
452 double GCOMObservation::npred(const GModel& model) const
453 {
454  // Initialise Npred
455  double npred = 0.0;
456 
457  // Setup model container
458  GModels models;
459  models.append(model);
460 
461  // Compute model vector
462  GVector model_vector = this->model(models, NULL);
463 
464  // Get number of events
465  int nevents = model_vector.size();
466 
467  // Iterate over all bins
468  for (int i = 0; i < nevents; ++i) {
469 
470  // Skip events that should not be used
471  if (!use_event_for_likelihood(i)) {
472  continue;
473  }
474 
475  // Get event pointer
476  const GEventBin* bin =
477  (*(static_cast<GEventCube*>(const_cast<GEvents*>(events()))))[i];
478 
479  // Get model value
480  double model_value = model_vector[i] * bin->size();
481 
482  // Update Npred
483  npred += model_value;
484 
485  } // endfor: looped over all bins
486 
487  // Return Npred
488  return npred;
489 }
490 
491 
492 /***********************************************************************//**
493  * @brief Read observation from XML element
494  *
495  * @param[in] xml XML element.
496  *
497  * Reads information for a COMPTEL observation from an XML element. The
498  * method supports both an unbinned and a binned observation.
499  *
500  * For an unbinned observation the XML format is
501  *
502  * <observation name="Crab" id="000001" instrument="COM">
503  * <parameter name="EVP" file="m16992_evp.fits"/>
504  * <parameter name="TIM" file="m10695_tim.fits"/>
505  * <parameter name="OAD" file="m20039_oad.fits"/>
506  * <parameter name="OAD" file="m20041_oad.fits"/>
507  * <parameter name="HKD" file="m20035_hkd.fits"/>
508  * <parameter name="HKD" file="m20037_hkd.fits"/>
509  * <parameter name="BVC" file="s10150_bvc.fits"/>
510  * ...
511  * </observation>
512  *
513  * where the observation can contain an arbitrary number of OAD file
514  * parameters. The @p file attribute provide either absolute or relative
515  * file names. If a file name includes no access path it is assumed that
516  * the file resides in the same location as the XML file. The HKD and BVC
517  * files are optional and do not need to be specified.
518  *
519  * For a binned observation the XML format is
520  *
521  * <observation name="Crab" id="000001" instrument="COM">
522  * <parameter name="DRE" file="m50438_dre.fits"/>
523  * <parameter name="DRB" file="m34997_drg.fits"/>
524  * <parameter name="DRW" file="m34997_drw.fits"/>
525  * <parameter name="DRG" file="m34997_drg.fits"/>
526  * <parameter name="DRX" file="m32171_drx.fits"/>
527  * <parameter name="IAQ" value="UNH(1.0-3.0)MeV"/>
528  * </observation>
529  *
530  * Note that the DRW parameter is optional.
531  ***************************************************************************/
533 {
534  // Clear observation
535  clear();
536 
537  // If the XML elements has a "EVP" attribute we have an unbinned
538  // observation
539  if (gammalib::xml_has_par(xml, "EVP")) {
540 
541  // Get EVP and TIM file names
542  std::string evpname = gammalib::xml_get_attr(G_READ, xml, "EVP", "file");
543  std::string timname = gammalib::xml_get_attr(G_READ, xml, "TIM", "file");
544 
545  // Expand EVP and TIM file names
546  evpname = gammalib::xml_file_expand(xml, evpname);
547  timname = gammalib::xml_file_expand(xml, timname);
548 
549  // Get OAD file names
550  std::vector<GFilename> oadnames;
551  for (int i = 0; i < xml.elements("parameter"); ++i) {
552  const GXmlElement* element = xml.element("parameter", i);
553  if (element->attribute("name") == "OAD") {
554  std::string oadname = element->attribute("file");
555  oadname = gammalib::xml_file_expand(xml, oadname);
556  oadnames.push_back(GFilename(oadname));
557  }
558  }
559 
560  // Get and expand optional HKD file names
561  std::vector<GFilename> hkdnames;
562  for (int i = 0; i < xml.elements("parameter"); ++i) {
563  const GXmlElement* element = xml.element("parameter", i);
564  if (element->attribute("name") == "HKD") {
565  std::string hkdname = element->attribute("file");
566  hkdname = gammalib::xml_file_expand(xml, hkdname);
567  hkdnames.push_back(GFilename(hkdname));
568  }
569  }
570 
571  // Get and expand optional BVC file name
572  std::string bvcname = "";
573  if (gammalib::xml_has_par(xml, "BVC")) {
574  bvcname = gammalib::xml_get_attr(G_READ, xml, "BVC", "file");
575  bvcname = gammalib::xml_file_expand(xml, bvcname);
576  }
577 
578  // Load observation
579  load(evpname, timname, oadnames, hkdnames, bvcname);
580 
581  } // endif: unbinned observation
582 
583  // ... otherwise we have a binned observation
584  else {
585 
586  // Get parameters
587  std::string drename = gammalib::xml_get_attr(G_READ, xml, "DRE", "file");
588  std::string drbname = gammalib::xml_get_attr(G_READ, xml, "DRB", "file");
589  std::string drgname = gammalib::xml_get_attr(G_READ, xml, "DRG", "file");
590  std::string drxname = gammalib::xml_get_attr(G_READ, xml, "DRX", "file");
591  std::string iaqname = gammalib::xml_get_attr(G_READ, xml, "IAQ", "value");
592 
593  // Optionally get DRW
594  std::string drwname = (gammalib::xml_has_par(xml, "DRW")) ?
595  gammalib::xml_get_attr(G_READ, xml, "DRW", "file") :
596  "";
597 
598  // Expand file names
599  drename = gammalib::xml_file_expand(xml, drename);
600  drbname = gammalib::xml_file_expand(xml, drbname);
601  drwname = gammalib::xml_file_expand(xml, drwname);
602  drgname = gammalib::xml_file_expand(xml, drgname);
603  drxname = gammalib::xml_file_expand(xml, drxname);
604  std::string iaqname_expanded = gammalib::xml_file_expand(xml, iaqname);
605 
606  // Load observation
607  load(drename, drbname, drwname, drgname, drxname);
608 
609  // Load IAQ by trying first the expanded name as a FITS file and
610  // otherwise the unexpanded name
611  GFilename filename_expanded(iaqname_expanded);
612  if (filename_expanded.is_fits()) {
613  response(GCaldb("cgro", "comptel"), iaqname_expanded);
614  }
615  else {
616  response(GCaldb("cgro", "comptel"), iaqname);
617  }
618 
619  // Get optional Phibar layer attributes
620  if (xml.has_attribute("phi_first")) {
621  m_phi_first = gammalib::toint(xml.attribute("phi_first"));
622  }
623  if (xml.has_attribute("phi_last")) {
624  m_phi_last = gammalib::toint(xml.attribute("phi_last"));
625  }
626 
627  // Optionally load response cache
628  if (gammalib::xml_has_par(xml, "RSP")) {
629 
630  // Get and expand filename
631  m_rspname = gammalib::xml_get_attr(G_READ, xml, "RSP", "file");
633 
634  // If file exists then load it
635  if (m_rspname.exists()) {
637  }
638 
639  } // endif: optionally loaded response cache
640 
641  } // endelse: binned observation
642 
643  // Extract attributes
644  m_name = xml.attribute("name");
645  m_id = xml.attribute("id");
646  m_instrument = xml.attribute("instrument");
647 
648  // Return
649  return;
650 }
651 
652 
653 /***********************************************************************//**
654  * @brief Write observation into XML element
655  *
656  * @param[in] xml XML element.
657  *
658  * Writes information for a COMPTEL observation into an XML element. The
659  * method supports both an unbinned and a binned observation.
660  *
661  * For an unbinned observation the XML format is
662  *
663  * <observation name="Crab" id="000001" instrument="COM">
664  * <parameter name="EVP" file="m16992_evp.fits"/>
665  * <parameter name="TIM" file="m10695_tim.fits"/>
666  * <parameter name="OAD" file="m20039_oad.fits"/>
667  * <parameter name="OAD" file="m20041_oad.fits"/>
668  * <parameter name="HKD" file="m20035_hkd.fits"/>
669  * <parameter name="HKD" file="m20037_hkd.fits"/>
670  * <parameter name="BVC" file="s10150_bvc.fits"/>
671  * ...
672  * </observation>
673  *
674  * where the observation can contain an arbitrary number of OAD file
675  * parameters. The @p file attribute provide either absolute or relative
676  * file names. If a file name includes no access path it is assumed that
677  * the file resides in the same location as the XML file. The HKD and BVC
678  * files are optional and are only written if HKD and BVC information is
679  * contained in the observation.
680  *
681  * For a binned observation the XML format is
682  *
683  * <observation name="Crab" id="000001" instrument="COM">
684  * <parameter name="DRE" file="m50438_dre.fits"/>
685  * <parameter name="DRB" file="m34997_drg.fits"/>
686  * <parameter name="DRW" file="m34997_drw.fits"/>
687  * <parameter name="DRG" file="m34997_drg.fits"/>
688  * <parameter name="DRX" file="m32171_drx.fits"/>
689  * <parameter name="IAQ" value="UNH(1.0-3.0)MeV"/>
690  * </observation>
691  *
692  * Note that the DRW parameter is optional.
693  ***************************************************************************/
695 {
696  // Allocate XML element pointer
697  GXmlElement* par;
698 
699  // Handle unbinned observation
700  if (is_unbinned()) {
701 
702  // Set EVP parameter
703  par = gammalib::xml_need_par(G_WRITE, xml, "EVP");
704  par->attribute("file", gammalib::xml_file_reduce(xml, m_evpname));
705 
706  // Set TIM parameter
707  par = gammalib::xml_need_par(G_WRITE, xml, "TIM");
708  par->attribute("file", gammalib::xml_file_reduce(xml, m_timname));
709 
710  // Remove all existing OAD parameters
711  for (int i = 0; i < xml.elements("parameter"); ++i) {
712  GXmlElement* element = xml.element("parameter", i);
713  if (element->attribute("name") == "OAD") {
714  xml.remove(i);
715  }
716  }
717 
718  // Set OAD parameters
719  for (int i = 0; i < m_oadnames.size(); ++i) {
720  par = static_cast<GXmlElement*>(xml.append(GXmlElement("parameter name=\"OAD\"")));
721  par->attribute("file", gammalib::xml_file_reduce(xml, m_oadnames[i]));
722  }
723 
724  // Optionally set HKD parameters
725  for (int i = 0; i < m_hkdnames.size(); ++i) {
726  par = static_cast<GXmlElement*>(xml.append(GXmlElement("parameter name=\"HKD\"")));
727  par->attribute("file", gammalib::xml_file_reduce(xml, m_hkdnames[i]));
728  }
729 
730  // Optionally set BVC parameters
731  if (!m_bvcs.is_empty()) {
732  par = gammalib::xml_need_par(G_WRITE, xml, "BVC");
733  par->attribute("file", gammalib::xml_file_reduce(xml, m_bvcname));
734  }
735 
736  } // endif: observation was unbinned
737 
738  // ... otherwise handle a binned observation
739  else if (is_binned()) {
740 
741  // Set DRE parameter
742  par = gammalib::xml_need_par(G_WRITE, xml, "DRE");
743  par->attribute("file", gammalib::xml_file_reduce(xml, m_drename));
744 
745  // Set DRB parameter
746  par = gammalib::xml_need_par(G_WRITE, xml, "DRB");
747  par->attribute("file", gammalib::xml_file_reduce(xml, m_drbname));
748 
749  // Set DRW parameter
750  if (m_drwname != "") {
751  par = gammalib::xml_need_par(G_WRITE, xml, "DRW");
752  par->attribute("file", gammalib::xml_file_reduce(xml, m_drwname));
753  }
754 
755  // Set DRG parameter
756  par = gammalib::xml_need_par(G_WRITE, xml, "DRG");
757  par->attribute("file", gammalib::xml_file_reduce(xml, m_drgname));
758 
759  // Set DRX parameter
760  par = gammalib::xml_need_par(G_WRITE, xml, "DRX");
761  par->attribute("file", gammalib::xml_file_reduce(xml, m_drxname));
762 
763  // Set IAQ parameter
764  par = gammalib::xml_need_par(G_WRITE, xml, "IAQ");
765  par->attribute("value", gammalib::xml_file_reduce(xml, m_response.rspname()));
766 
767  // If there is a first Phibar layer selection then write it into XML file
768  if (m_phi_first != -1) {
769  xml.attribute("phi_first", gammalib::str(m_phi_first));
770  }
771 
772  // If there is a last Phibar layer selection then write it into XML file
773  if (m_phi_last != -1) {
774  xml.attribute("phi_last", gammalib::str(m_phi_last));
775  }
776 
777  // Optionally set response cache parameter
778  if (!m_rspname.is_empty()) {
779 
780  // Set cache parameter
781  par = gammalib::xml_need_par(G_WRITE, xml, "RSP");
782  par->attribute("file", gammalib::xml_file_reduce(xml, m_rspname));
783 
784  // If response cache file does not yet exist then save it now
785  // Note that this code assumes that the cache will never change
786  // once it has been computed. In case that the cache may have
787  // changed, a different file name needs to be choosen
788  if (!m_rspname.exists()) {
790  }
791 
792  }
793 
794  } // endif: observation was binned
795 
796  // Return
797  return;
798 }
799 
800 
801 /***********************************************************************//**
802  * @brief Load data for a binned observation
803  *
804  * @param[in] drename Event cube name.
805  * @param[in] drbname Background cube name.
806  * @param[in] drwname Weighting cube name.
807  * @param[in] drgname Geometry cube name.
808  * @param[in] drxname Exposure map name.
809  *
810  * Load event cube from DRE file, background model from DRB file, weigthing
811  * cube from DRW file, geometry factors from DRG file and the exposure map
812  * from the DRX file. All files are mandatory.
813  ***************************************************************************/
814 void GCOMObservation::load(const GFilename& drename,
815  const GFilename& drbname,
816  const GFilename& drwname,
817  const GFilename& drgname,
818  const GFilename& drxname)
819 {
820  // Load DRE
821  load_dre(drename);
822 
823  // Load DRB
824  load_drb(drbname);
825 
826  // Load DRW
827  load_drw(drwname);
828 
829  // Load DRG
830  load_drg(drgname);
831 
832  // Load DRX
833  load_drx(drxname);
834 
835  // Return
836  return;
837 }
838 
839 
840 /***********************************************************************//**
841  * @brief Load data for an unbinned observation
842  *
843  * @param[in] evpname Event list FITS file name.
844  * @param[in] timname Good Time Intervals FITS file name.
845  * @param[in] oadnames List of Orbit Aspect Data FITS file names.
846  * @param[in] hkdnames List of Housekeeping Data FITS file names.
847  * @param[in] bvcname Solar System Barycentre Data FITS file name.
848  *
849  * Loads the event list, Good Time Interval, Orbit Aspect Data and optionally
850  * Housekeeping data and Solar System Barycentre Data for an unbinned
851  * observation.
852  *
853  * Except of the Housekeeping Data and the Solar System Barycentre Data all
854  * files are mandatory. The Housekeeping Data and the Solar System Barycentre
855  * Data will only be loaded if the file names are not empty.
856  *
857  * The method fixes the deadtime correction factor deadc to 0.965.
858  ***************************************************************************/
859 void GCOMObservation::load(const GFilename& evpname,
860  const GFilename& timname,
861  const std::vector<GFilename>& oadnames,
862  const std::vector<GFilename>& hkdnames,
863  const GFilename& bvcname)
864 {
865  // Clear object
866  clear();
867 
868  // Extract observation information from event list
869  GFits fits(evpname);
870  read_attributes(fits[1]);
871  fits.close();
872 
873  // Allocate event list
874  GCOMEventList *evp = new GCOMEventList(evpname);
875  m_events = evp;
876 
877  // Load TIM data
878  m_tim.load(timname);
879 
880  // Extract ontime from TIM and compute livetime assuming the value of
881  // 0.965 from Rob van Dijk's thesis, page 62
882  m_ontime = m_tim.gti().ontime();
883  m_deadc = 0.965;
885 
886  // Initialise intermediate vector for OADs
887  std::vector<GCOMOads> oads;
888 
889  // Load OAD data
890  for (int i = 0; i < oadnames.size(); ++i) {
891 
892  // Load OAD file
893  GCOMOads oad(oadnames[i]);
894 
895  // Skip file if it is empty
896  if (oad.size() < 1) {
897  continue;
898  }
899 
900  // Find index of where to insert OAD file
901  int index = 0;
902  for (; index < oads.size(); ++index) {
903  if (oad[0].tstop() < oads[index][oads[index].size()-1].tstart()) {
904  break;
905  }
906  }
907 
908  // Inserts Orbit Aspect Data
909  if (index < oads.size()) {
910  oads.insert(oads.begin()+index, oad);
911  }
912  else {
913  oads.push_back(oad);
914  }
915 
916  }
917 
918  // Now put all OAD into a single container
919  for (int i = 0; i < oads.size(); ++i) {
920  m_oads.extend(oads[i]);
921  }
922 
923  // Optionally load HKD data
924  for (int i = 0; i < hkdnames.size(); ++i) {
925 
926  // Load HKD file
927  GCOMHkds hdks(hkdnames[i]);
928 
929  // Skip file if it is empty
930  if (hdks.size() < 1) {
931  continue;
932  }
933 
934  // Extend housekeeping data
935  m_hkds.extend(hdks);
936 
937  }
938 
939  // Optionally load BVC data
940  if (bvcname != "") {
941  m_bvcs.load(bvcname);
942  }
943 
944  // Store filenames
945  m_evpname = evpname;
946  m_timname = timname;
947  m_oadnames = oadnames;
948  m_hkdnames = hkdnames;
949  m_bvcname = bvcname;
950 
951  // Return
952  return;
953 }
954 
955 
956 /***********************************************************************//**
957  * @brief Compute DRM cube
958  *
959  * @param[in] models Model container.
960  * @return DRM cube (units of counts)
961  *
962  * @exception GException::invalid_value
963  * Observation does not contain an event cube.
964  *
965  * Computes a COMPTEL DRM cube from the information provided in a model
966  * container. The values of the DRM cube are in units of counts.
967  ***************************************************************************/
969 {
970  // Get pointer on COMPTEL event cube
971  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(m_events);
972  if (cube == NULL) {
973  std::string cls = std::string(typeid(m_events).name());
974  std::string msg = "Events of type \""+cls+"\" is not a COMPTEL event "
975  "cube. Please specify a COMPTEL event cube when "
976  "using this method.";
977  throw GException::invalid_value(G_DRM, msg);
978  }
979 
980  // Create DRM cube as copy of DRE cube
981  GCOMEventCube drm_cube = *cube;
982 
983  // Get vector of model values
984  GVector values = models.eval(*this);
985 
986  // Loop over all cube bins
987  for (int i = 0; i < drm_cube.size(); ++i) {
988 
989  // Get pointer to cube bin
990  GCOMEventBin* bin = drm_cube[i];
991 
992  // Compute model value for cube bin
993  double model = values[i] * bin->size();
994 
995  // Store model value in cube bin
996  bin->counts(model);
997 
998  } // endfor: looped over DRM cube bins
999 
1000  // Get a copy of the DRM
1001  GCOMDri drm = drm_cube.dre();
1002 
1003  // Return DRM
1004  return drm;
1005 }
1006 
1007 
1008 /***********************************************************************//**
1009  * @brief Compute DRB cube
1010  *
1011  * @param[in] method Background method (PHINOR, BGDLIXA, BGDLIXE or BGDLIXF).
1012  * @param[in] drm DRM cube.
1013  * @param[in] nrunav BGDLIXn: number of bins used for running average.
1014  * @param[in] navgr BGDLIXn: number of bins used for averaging.
1015  * @param[in] nincl BGDLIXn: number of Phibar layers to include.
1016  * @param[in] nexcl BGDLIXn: number of Phibar layers to exclude.
1017  *
1018  * Computes a COMPTEL DRB cube using either the PHINOR or BGDLIX method.
1019  * There are three variants of the BGFLIX method (BGDLIXA, BGDLIXE and
1020  * BGDLIXF). See the protected methods
1021  * compute_drb_phinor(),
1022  * compute_drb_bgdlixa(),
1023  * compute_drb_bgdlixe(), and
1024  * compute_drb_bgdlixf()
1025  * for more information.
1026  ***************************************************************************/
1027 void GCOMObservation::compute_drb(const std::string& method,
1028  const GCOMDri& drm,
1029  const int& nrunav,
1030  const int& navgr,
1031  const int& nincl,
1032  const int& nexcl)
1033 {
1034  // Branch to relevant method based on specified background method
1035  if (method == "PHINOR") {
1036  compute_drb_phinor(drm);
1037  }
1038  else if (method == "BGDLIXA") {
1039  compute_drb_bgdlixa(drm, nrunav, navgr, nincl, nexcl);
1040  }
1041  else if (method == "BGDLIXE") {
1042  compute_drb_bgdlixe(drm, nrunav, navgr, nincl, nexcl);
1043  }
1044  else if (method == "BGDLIXF") {
1045  compute_drb_bgdlixf(drm, nrunav, navgr, nincl, nexcl);
1046  }
1047  else {
1048  std::string msg = "Unknown background method \""+method+"\". "
1049  "Specify either \"PHINOR\", \"BGDLIXA\" or "
1050  "\"BGDLIXE\".";
1052  }
1053 
1054  // Return
1055  return;
1056 }
1057 
1058 
1059 /***********************************************************************//**
1060  * @brief Print observation information
1061  *
1062  * @param[in] chatter Chattiness.
1063  * @return String containing observation information.
1064  ***************************************************************************/
1065 std::string GCOMObservation::print(const GChatter& chatter) const
1066 {
1067  // Initialise result string
1068  std::string result;
1069 
1070  // Continue only if chatter is not silent
1071  if (chatter != SILENT) {
1072 
1073  // Append header
1074  result.append("=== GCOMObservation ===");
1075 
1076  // Append information
1077  result.append("\n"+gammalib::parformat("Name")+name());
1078  result.append("\n"+gammalib::parformat("Identifier")+id());
1079  result.append("\n"+gammalib::parformat("Instrument")+instrument());
1080  result.append("\n"+gammalib::parformat("Statistic")+statistic());
1081  result.append("\n"+gammalib::parformat("Ontime"));
1082  result.append(gammalib::str(ontime())+" sec");
1083  result.append("\n"+gammalib::parformat("Livetime"));
1084  result.append(gammalib::str(livetime())+" sec");
1085  result.append("\n"+gammalib::parformat("Deadtime correction"));
1086  result.append(gammalib::str(m_deadc));
1087 
1088  // Append Phibar selection
1089  int phi_first = (m_phi_first != -1) ? m_phi_first : 0;
1090  int phi_last = (m_phi_last != -1) ? m_phi_last : m_drg.map().nmaps();
1091  if ((m_phi_first != -1) || (m_phi_last != -1)) {
1092  result.append("\n"+gammalib::parformat("Likelihood Phibar range"));
1093  result.append(gammalib::str(phi_first));
1094  result.append(" - ");
1095  result.append(gammalib::str(phi_last));
1096  }
1097 
1098  // Append response (if available)
1099  if (response()->rspname().length() > 0) {
1100  result.append("\n"+response()->print(gammalib::reduce(chatter)));
1101  if (!m_rspname.is_empty()) {
1102  result.append("\n"+gammalib::parformat("Response cache file"));
1103  result.append(m_rspname);
1104  }
1105  }
1106 
1107  // Append events
1108  if (m_events != NULL) {
1109  result.append("\n"+m_events->print(gammalib::reduce(chatter)));
1110  }
1111  else {
1112  result.append("\n"+gammalib::parformat("Events")+"undefined");
1113  }
1114 
1115  // Append TIM (if available)
1116  if (m_tim.gti().size() > 0) {
1117  result.append("\n"+m_tim.print(gammalib::reduce(chatter)));
1118  }
1119  else {
1120  result.append("\n"+gammalib::parformat("TIM")+"undefined");
1121  }
1122 
1123  // Append OADs (if available)
1124  if (!m_oads.is_empty()) {
1125  result.append("\n"+m_oads.print(gammalib::reduce(chatter)));
1126  }
1127  else {
1128  result.append("\n"+gammalib::parformat("OADs")+"undefined");
1129  }
1130 
1131  // Append HKDs (if available)
1132  if (!m_hkds.is_empty()) {
1133  result.append("\n"+m_hkds.print(gammalib::reduce(chatter)));
1134  }
1135  else {
1136  result.append("\n"+gammalib::parformat("HKDs")+"undefined");
1137  }
1138 
1139  // Append BVCs (if available)
1140  if (!m_bvcs.is_empty()) {
1141  result.append("\n"+m_bvcs.print(gammalib::reduce(chatter)));
1142  }
1143  else {
1144  result.append("\n"+gammalib::parformat("BVCs")+"undefined");
1145  }
1146 
1147  } // endif: chatter was not silent
1148 
1149  // Return result
1150  return result;
1151 }
1152 
1153 
1154 /*==========================================================================
1155  = =
1156  = Private methods =
1157  = =
1158  ==========================================================================*/
1159 
1160 /***********************************************************************//**
1161  * @brief Initialise class members
1162  ***************************************************************************/
1164 {
1165  // Initialise members
1166  m_instrument = "COM";
1167  m_response.clear();
1168  m_obs_id = 0;
1169  m_ontime = 0.0;
1170  m_livetime = 0.0;
1171  m_deadc = 0.0;
1172 
1173  // Initialise members for binned observation
1174  m_drename.clear();
1175  m_drbname.clear();
1176  m_drwname.clear();
1177  m_drgname.clear();
1178  m_drxname.clear();
1179  m_rspname.clear();
1180  m_drb.clear();
1181  m_drw.clear();
1182  m_drg.clear();
1183  m_drx.clear();
1184  m_ewidth = 0.0;
1185  m_phi_first = -1;
1186  m_phi_last = -1;
1187 
1188  // Initialise members for unbinned observation
1189  m_evpname.clear();
1190  m_timname.clear();
1191  m_oadnames.clear();
1192  m_hkdnames.clear();
1193  m_bvcname.clear();
1194  m_tim.clear();
1195  m_oads.clear();
1196  m_hkds.clear();
1197  m_bvcs.clear();
1198 
1199  // Return
1200  return;
1201 }
1202 
1203 
1204 /***********************************************************************//**
1205  * @brief Copy class members
1206  *
1207  * @param[in] obs COMPTEL observation.
1208  ***************************************************************************/
1210 {
1211  // Copy members
1212  m_instrument = obs.m_instrument;
1213  m_response = obs.m_response;
1214  m_obs_id = obs.m_obs_id;
1215  m_ontime = obs.m_ontime;
1216  m_livetime = obs.m_livetime;
1217  m_deadc = obs.m_deadc;
1218 
1219  // Copy members for binned observation
1220  m_drename = obs.m_drename;
1221  m_drbname = obs.m_drbname;
1222  m_drwname = obs.m_drwname;
1223  m_drgname = obs.m_drgname;
1224  m_drxname = obs.m_drxname;
1225  m_rspname = obs.m_rspname;
1226  m_drb = obs.m_drb;
1227  m_drw = obs.m_drw;
1228  m_drg = obs.m_drg;
1229  m_drx = obs.m_drx;
1230  m_ewidth = obs.m_ewidth;
1231  m_phi_first = obs.m_phi_first;
1232  m_phi_last = obs.m_phi_last;
1233 
1234  // Copy members for unbinned observation
1235  m_evpname = obs.m_evpname;
1236  m_timname = obs.m_timname;
1237  m_oadnames = obs.m_oadnames;
1238  m_hkdnames = obs.m_hkdnames;
1239  m_bvcname = obs.m_bvcname;
1240  m_tim = obs.m_tim;
1241  m_oads = obs.m_oads;
1242  m_hkds = obs.m_hkds;
1243  m_bvcs = obs.m_bvcs;
1244 
1245  // Return
1246  return;
1247 }
1248 
1249 
1250 /***********************************************************************//**
1251  * @brief Delete class members
1252  ***************************************************************************/
1254 {
1255  // Return
1256  return;
1257 }
1258 
1259 
1260 /***********************************************************************//**
1261  * @brief Load event cube data from DRE file
1262  *
1263  * @param[in] drename DRE filename.
1264  *
1265  * Loads the event cube from a DRE file.
1266  *
1267  * The ontime is extracted from the Good Time Intervals. The deadtime
1268  * correction factor deadc is fixed to 0.965. The livetime is computed by
1269  * multiplying the deadtime correction by the ontime, i.e.
1270  * LIVETIME = ONTIME * DEADC.
1271  ***************************************************************************/
1273 {
1274  // Delete any existing event container (do not call clear() as we do not
1275  // want to delete the response function)
1276  if (m_events != NULL) delete m_events;
1277  m_events = NULL;
1278 
1279  // Allocate event cube
1280  m_events = new GCOMEventCube;
1281 
1282  // Open FITS file
1283  GFits fits(drename);
1284 
1285  // Read event cube
1286  m_events->read(fits);
1287 
1288  // Extract ontime
1289  m_ontime = m_events->gti().ontime();
1290 
1291  // Set fixed deadtime fraction (see Rob van Dijk's thesis, page 62)
1292  m_deadc = 0.965;
1293 
1294  // Compute livetime
1296 
1297  // Compute energy width
1298  m_ewidth = m_events->emax().MeV() - m_events->emin().MeV();
1299 
1300  // Read additional observation attributes from primary extension
1301  read_attributes(fits[0]);
1302 
1303  // Close FITS file
1304  fits.close();
1305 
1306  // Store event filename
1307  m_drename = drename;
1308 
1309  // Return
1310  return;
1311 }
1312 
1313 
1314 /***********************************************************************//**
1315  * @brief Load background model from DRB file
1316  *
1317  * @param[in] drbname DRB filename.
1318  *
1319  * @exception GException::invalid_value
1320  * DRB data space incompatible with DRE data space.
1321  *
1322  * Load the background model from the primary image of the specified FITS
1323  * file. Since a DRB file is optional the method does nothing if the DRB
1324  * filename is empty.
1325  ***************************************************************************/
1327 {
1328  // Continue only if filename is not empty
1329  if (!drbname.is_empty()) {
1330 
1331  // Open FITS file
1332  GFits fits(drbname);
1333 
1334  // Get image
1335  const GFitsImage& image = *fits.image("Primary");
1336 
1337  // Read background model
1338  m_drb.read(image);
1339 
1340  // Correct WCS projection (HEASARC data format kludge)
1341  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drb.map()));
1342 
1343  // Close FITS file
1344  fits.close();
1345 
1346  // Check map dimensions
1347  if (!check_dri(m_drb)) {
1348  std::string msg = "DRB data cube \""+drbname+"\" incompatible with "
1349  "DRE data cube \""+m_drename+"\".";
1351  }
1352 
1353  // Store DRB filename
1354  m_drbname = drbname;
1355 
1356  } // endif: DRB filename was empty
1357 
1358  // Return
1359  return;
1360 }
1361 
1362 
1363 /***********************************************************************//**
1364  * @brief Load weighting cube from DRW file
1365  *
1366  * @param[in] drwname DRW filename.
1367  *
1368  * @exception GException::invalid_value
1369  * DRW data space incompatible with DRE data space.
1370  *
1371  * Load the weighting cube from the primary image of the specified FITS file.
1372  ***************************************************************************/
1374 {
1375  // Continue only if filename is not empty
1376  if (!drwname.is_empty()) {
1377 
1378  // Open FITS file
1379  GFits fits(drwname);
1380 
1381  // Get image
1382  const GFitsImage& image = *fits.image("Primary");
1383 
1384  // Read weighting cube
1385  m_drw.read(image);
1386 
1387  // Close FITS file
1388  fits.close();
1389 
1390  // Check map dimensions
1391  if (!check_dri(m_drw)) {
1392  std::string msg = "DRW data cube \""+drwname+"\" incompatible with "
1393  "DRE data cube \""+m_drename+"\".";
1395  }
1396 
1397  // Store DRW filename
1398  m_drwname = drwname;
1399 
1400  } // endif: DRW filename was empty
1401 
1402  // Return
1403  return;
1404 }
1405 
1406 
1407 /***********************************************************************//**
1408  * @brief Load geometry factors from DRG file
1409  *
1410  * @param[in] drgname DRG filename.
1411  *
1412  * @exception GException::invalid_value
1413  * DRG data space incompatible with DRE data space.
1414  *
1415  * Load the geometry factors from the primary image of the specified FITS
1416  * file.
1417  ***************************************************************************/
1419 {
1420  // Open FITS file
1421  GFits fits(drgname);
1422 
1423  // Get image
1424  const GFitsImage& image = *fits.image("Primary");
1425 
1426  // Read geometry factors
1427  m_drg.read(image);
1428 
1429  // Correct WCS projection (HEASARC data format kludge)
1430  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drg.map()));
1431 
1432  // Close FITS file
1433  fits.close();
1434 
1435  // Check map dimensions
1436  if (!check_dri(m_drg)) {
1437  std::string msg = "DRG data cube \""+drgname+"\" incompatible with "
1438  "DRE data cube \""+m_drename+"\".";
1440  }
1441 
1442  // Store DRG filename
1443  m_drgname = drgname;
1444 
1445  // Return
1446  return;
1447 }
1448 
1449 
1450 /***********************************************************************//**
1451  * @brief Load exposure from DRX file
1452  *
1453  * @param[in] drxname DRX filename.
1454  *
1455  * Load the exposure map from the primary image of the specified FITS file.
1456  ***************************************************************************/
1458 {
1459  // Open FITS file
1460  GFits fits(drxname);
1461 
1462  // Get HDU
1463  const GFitsImage& image = *fits.image("Primary");
1464 
1465  // Read exposure map
1466  m_drx.read(image);
1467 
1468  // Correct WCS projection (HEASARC data format kludge)
1469  gammalib::com_wcs_mer2car(const_cast<GSkyMap&>(m_drx.map()));
1470 
1471  // Close FITS file
1472  fits.close();
1473 
1474  // Store DRX filename
1475  m_drxname = drxname;
1476 
1477  // Return
1478  return;
1479 }
1480 
1481 
1482 /***********************************************************************//**
1483  * @brief Check if DRI is compatible with event cube
1484  *
1485  * @param[in] dri DRI.
1486  * @return True if DRI is compatible, false otherwise.
1487  *
1488  * Compares the dimension and the WCS definition of a DRI to that of the
1489  * event cube. If both are identical, true is returned, false otherwise.
1490  ***************************************************************************/
1491 bool GCOMObservation::check_dri(const GCOMDri& dri) const
1492 {
1493  // Get references to event cube map and DRI map
1494  const GSkyMap& ref = dynamic_cast<GCOMEventCube*>(m_events)->dre().map();
1495  const GSkyMap& map = dri.map();
1496 
1497  // Compare dimensions
1498  bool same_dimension = ((map.nx() == ref.nx()) &&
1499  (map.ny() == ref.ny()) &&
1500  (map.nmaps() == ref.nmaps()));
1501 
1502  // Compare projections
1503  bool same_projection = false;
1504  const GSkyProjection* proj_ref = ref.projection();
1505  const GSkyProjection* proj_map = map.projection();
1506  if ((proj_ref == NULL) && (proj_map == NULL)) {
1507  same_projection = true;
1508  }
1509  else if ((proj_ref != NULL) && (proj_map != NULL)) {
1510  same_projection = (*proj_map == *proj_ref);
1511  }
1512 
1513  // Return
1514  return (same_dimension && same_projection);
1515 }
1516 
1517 
1518 /***********************************************************************//**
1519  * @brief Read observation attributes
1520  *
1521  * @param[in] hdu FITS HDU pointer
1522  *
1523  * Reads optional attributes are
1524  *
1525  * OBS_ID - Observation identifier
1526  * OBJECT - Object
1527  *
1528  * Nothing is done if the HDU pointer is NULL.
1529  ***************************************************************************/
1531 {
1532  // Continue only if HDU is valid
1533  if (hdu != NULL) {
1534 
1535  // Read observation information
1536  m_obs_id = (hdu->has_card("OBS_ID")) ? hdu->real("OBS_ID") : 0;
1537  m_name = (hdu->has_card("OBJECT")) ? hdu->string("OBJECT") : "unknown";
1538 
1539  } // endif: HDU was valid
1540 
1541  // Return
1542  return;
1543 }
1544 
1545 
1546 /***********************************************************************//**
1547  * @brief Write observation attributes
1548  *
1549  * @param[in] hdu FITS HDU pointer
1550  *
1551  * Nothing is done if the HDU pointer is NULL.
1552  *
1553  * @todo Implement method.
1554  ***************************************************************************/
1556 {
1557  // Continue only if HDU is valid
1558  if (hdu != NULL) {
1559 
1560  } // endif: HDU was valid
1561 
1562  // Return
1563  return;
1564 }
1565 
1566 
1567 /***********************************************************************//**
1568  * @brief Compute DRB cube using PHINOR method
1569  *
1570  * @param[in] drm DRM cube.
1571  *
1572  * @exception GException::invalid_value
1573  * Observation does not contain an event cube
1574  * @exception GException::invalid_argument
1575  * DRM cube is incompatible with DRE
1576  ***************************************************************************/
1578 {
1579  // Extract COMPTEL event cube
1580  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
1581  if (cube == NULL) {
1582  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
1583  "does not contain a COMPTEL event cube. Please "
1584  "specify a COMPTEL observation containing and event "
1585  "cube.";
1587  }
1588 
1589  // Check DRM
1590  if (!check_dri(drm)) {
1591  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
1592  "specify a DRM with a data-space definition that is "
1593  "identical to that of the DRE.";
1595  }
1596 
1597  // Initialise DRB by cloning DRG
1598  m_drb = m_drg;
1599 
1600  // Get DRI sky maps
1601  const GSkyMap& map_dre = cube->dre().map();
1602  const GSkyMap& map_drm = drm.map();
1603  GSkyMap map_drg = get_weighted_drg_map();
1604  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
1605 
1606  // Get data space dimensions
1607  int npix = m_drg.map().npix();
1608  int nphibar = m_drg.nphibar();
1609 
1610  // Phibar normalise DRB
1611  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1612  double sum_dre = 0.0;
1613  double sum_drm = 0.0;
1614  double sum_drg = 0.0;
1615  for (int ipix = 0; ipix < npix; ++ipix) {
1616  sum_dre += map_dre(ipix, iphibar);
1617  sum_drm += map_drm(ipix, iphibar);
1618  sum_drg += map_drg(ipix, iphibar);
1619  }
1620  if (sum_drg > 0.0) {
1621  double norm = (sum_dre - sum_drm) / sum_drg;
1622  for (int ipix = 0; ipix < npix; ++ipix) {
1623  map_drb(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1624  }
1625  }
1626  else {
1627  for (int ipix = 0; ipix < npix; ++ipix) {
1628  map_drb(ipix, iphibar) = 0.0;
1629  }
1630  }
1631  }
1632 
1633  // Make sure that DRB is non-negative
1634  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1635  for (int ipix = 0; ipix < npix; ++ipix) {
1636  if (map_drb(ipix, iphibar) < 0.0) {
1637  map_drb(ipix, iphibar) = 0.0;
1638  }
1639  }
1640  }
1641 
1642  // Return
1643  return;
1644 }
1645 
1646 
1647 /***********************************************************************//**
1648  * @brief Compute DRB cube using BGDLIXA method
1649  *
1650  * @param[in] drm DRM cube.
1651  * @param[in] nrunav Number of bins used for running average.
1652  * @param[in] navgr Number of bins used for averaging.
1653  * @param[in] nincl Number of Phibar layers to include.
1654  * @param[in] nexcl Number of Phibar layers to exclude.
1655  *
1656  * @exception GException::invalid_value
1657  * Observation does not contain an event cube
1658  * @exception GException::invalid_argument
1659  * DRM cube is incompatible with DRE
1660  *
1661  * Computes a DRB cube using the BGDLIXA method that is documented in Rob
1662  * van Dijk's PhD thesis. The revelant equations from the thesis that are
1663  * implemented here are 3.12, 3.12 and 3.14.
1664  ***************************************************************************/
1666  const int& nrunav,
1667  const int& navgr,
1668  const int& nincl,
1669  const int& nexcl)
1670 {
1671  // Extract COMPTEL event cube
1672  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
1673  if (cube == NULL) {
1674  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
1675  "does not contain a COMPTEL event cube. Please "
1676  "specify a COMPTEL observation containing and event "
1677  "cube.";
1679  }
1680 
1681  // Check DRM
1682  if (!check_dri(drm)) {
1683  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
1684  "specify a DRM with a data-space definition that is "
1685  "identical to that of the DRE.";
1687  }
1688 
1689  // Initialise DRB and scratch DRI by cloning DRG
1690  m_drb = m_drg;
1691  GCOMDri dri = m_drg;
1692 
1693  // Get references to relevant sky maps
1694  const GSkyMap& map_dre = cube->dre().map();
1695  const GSkyMap& map_drm = drm.map();
1696  GSkyMap map_drg = get_weighted_drg_map();
1697  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
1698  GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map());
1699 
1700  // Get data space dimensions
1701  int nchi = m_drg.nchi();
1702  int npsi = m_drg.npsi();
1703  int nphibar = m_drg.nphibar();
1704  int npix = nchi * npsi;
1705 
1706  // Precompute half running average lengths
1707  int navgr2 = int(navgr/2);
1708 
1709  // Initialise DRB and scratch DRI
1710  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1711  for (int ipix = 0; ipix < npix; ++ipix) {
1712  map_drb(ipix, iphibar) = 0.0;
1713  map_dri(ipix, iphibar) = 0.0;
1714  }
1715  }
1716 
1717  // Phibar normalise DRB (Equation 3.12 in Rob van Dijk's PhD thesis).
1718  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1719  double sum_dre = 0.0;
1720  double sum_drm = 0.0;
1721  double sum_drg = 0.0;
1722  for (int ipix = 0; ipix < npix; ++ipix) {
1723  sum_dre += map_dre(ipix, iphibar);
1724  sum_drm += map_drm(ipix, iphibar);
1725  sum_drg += map_drg(ipix, iphibar);
1726  }
1727  if (sum_drg > 0.0) {
1728  double norm = (sum_dre - sum_drm) / sum_drg;
1729  for (int ipix = 0; ipix < npix; ++ipix) {
1730  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1731  }
1732  }
1733  }
1734 
1735  // Do 3D running average of DRE and Phibar normalised DRG (Equation 3.13
1736  // in Rob van Dijk's PhD thesis). The result is a Phibar normalised DRG
1737  // that is normalised over the 3D region to the DRE. The 3D region is all
1738  // Phibar layers and [-nrunav,+nrunav] Chi/Psi pixels around the pixel of
1739  // consideration.
1740  if (nrunav >= 1) {
1741 
1742  // Loop over Chi pixels
1743  for (int ichi = 0; ichi < nchi; ++ichi) {
1744 
1745  // Compute running average window in Chi
1746  int kchi_min = ichi - nrunav;
1747  int kchi_max = ichi + nrunav;
1748  if (kchi_min < 0) {
1749  kchi_min = 0;
1750  }
1751  if (kchi_max >= nchi) {
1752  kchi_max = nchi - 1;
1753  }
1754 
1755  // Loop over Psi pixels
1756  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
1757 
1758  // Compute running average window in Psi
1759  int kpsi_min = ipsi - nrunav;
1760  int kpsi_max = ipsi + nrunav;
1761  if (kpsi_min < 0) {
1762  kpsi_min = 0;
1763  }
1764  if (kpsi_max >= npsi) {
1765  kpsi_max = npsi - 1;
1766  }
1767 
1768  // Initialise sums
1769  double sum_dre = 0.0;
1770  double sum_drm = 0.0;
1771  double sum_dri = 0.0;
1772 
1773  // Compute running average
1774  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
1775  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
1776  int kpix = kchi + kpsi * nchi;
1777  for (int kphibar = 0; kphibar < nphibar; ++kphibar) {
1778  if (map_drg(kpix, kphibar) != 0.0) {
1779  sum_dre += map_dre(kpix, kphibar);
1780  sum_drm += map_drm(kpix, kphibar);
1781  sum_dri += map_dri(kpix, kphibar);
1782  }
1783  }
1784  }
1785  }
1786 
1787  // Renormalise scratch array
1788  if (sum_dri != 0.0) {
1789  int ipix = ichi + ipsi * nchi;
1790  double norm = (sum_dre - sum_drm) / sum_dri;
1791  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1792  map_dri(ipix, iphibar) *= norm;
1793  }
1794  }
1795 
1796  } // endfor: looped over Phi
1797 
1798  } // endfor: looped over Chi
1799 
1800  } // endif: running averaging was requested
1801 
1802  // First part of Equation (3.14) in Rob van Dijk's PhD thesis.
1803  // (DRB = B^0C_L / sum B^0C_L). The DRB is pre-computed by adjusting the
1804  // scratch DRI over nincl Phibar layers.
1805  int ksel1 = 0;
1806  int kex1 = 0;
1807  int kex2 = 0;
1808  int ksel2 = 0;
1809  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1810 
1811  // Get Phibar index range for sums
1812  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
1813  &ksel1, &kex1, &kex2, &ksel2);
1814 
1815  // Loop over Chi/Psi pixels
1816  for (int ipix = 0; ipix < npix; ++ipix) {
1817 
1818  // Initialise DRB value
1819  map_drb(ipix, iphibar) = 0.0;
1820 
1821  // Continue only if scratch DRI is non-zero
1822  if (map_dri(ipix, iphibar) != 0.0) {
1823 
1824  // Initialise sum
1825  double sum_dri = 0.0;
1826 
1827  // Take sum over [ksel1, kex1]
1828  if (kex1 >= 0) {
1829  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
1830  sum_dri += map_dri(ipix, kphibar);
1831  }
1832  }
1833 
1834  // Take sum over [kxe2, ksel2]
1835  if (kex2 < nphibar) {
1836  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
1837  sum_dri += map_dri(ipix, kphibar);
1838  }
1839  }
1840 
1841  // If sum is not zero then set DRB
1842  if (sum_dri != 0.0) {
1843  map_drb(ipix, iphibar) = map_dri(ipix, iphibar) / sum_dri;
1844  }
1845 
1846  } // endif: scratch DRI was non-zero
1847 
1848  } // endfor: looped over Chi/Psi pixels
1849 
1850  } // endfor: looped over Phibar
1851 
1852  // Second part of Equation (3.14) in Rob van Dijk's PhD thesis that
1853  // corresponds to G * [E / G]^s that will be stored in scratch DRI.
1854  //
1855  // NOTES:
1856  // - we replaced DRE by DRE-DRM in the nominator of the running
1857  // average since and source component should of course be
1858  // subtracted
1859  // - we implemented an alternative running average computation where
1860  // the ratio between the DRE and DRG sums is taken. This avoids
1861  // the divergence of the ratio at the edge of the DRG.
1862  for (int ichi = 0; ichi < nchi; ++ichi) {
1863 
1864  // Compute running average window in Chi
1865  int kchi_min = ichi - navgr2;
1866  int kchi_max = ichi + navgr2;
1867  if (kchi_min < 0) {
1868  kchi_min = 0;
1869  }
1870  if (kchi_max >= nchi) {
1871  kchi_max = nchi - 1;
1872  }
1873 
1874  // Loop over Psi pixels
1875  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
1876 
1877  // Compute running average window in Psi
1878  int kpsi_min = ipsi - navgr2;
1879  int kpsi_max = ipsi + navgr2;
1880  if (kpsi_min < 0) {
1881  kpsi_min = 0;
1882  }
1883  if (kpsi_max >= npsi) {
1884  kpsi_max = npsi - 1;
1885  }
1886 
1887  // Loop over Phibar layers
1888  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1889 
1890  // Initialise sums
1891  double sum_dre = 0.0;
1892  double sum_drm = 0.0;
1893  double sum_drg = 0.0;
1894 
1895  // Compute running average
1896  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
1897  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
1898  int kpix = kchi + kpsi * nchi;
1899  sum_dre += map_dre(kpix, iphibar);
1900  sum_drm += map_drm(kpix, iphibar);
1901  sum_drg += map_drg(kpix, iphibar);
1902  }
1903  }
1904 
1905  // Multiply average by DRG and store it in scratch DRI
1906  int ipix = ichi + ipsi * nchi;
1907  if (sum_drg > 0.0) {
1908  double norm = (sum_dre - sum_drm) / sum_drg;
1909  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
1910  }
1911  else {
1912  map_dri(ipix, iphibar) = 0.0;
1913  }
1914 
1915  } // endfor: looped over Phibar layers
1916 
1917  } // endfor: looped over Psi pixels
1918 
1919  } // endfor: looped over Chi pixels
1920 
1921  // Third part of Equation (3.14) in Rob van Dijk's PhD thesis that sums
1922  // G * [E / G]^s over a subset of Phibar layers (the first parenthesis)
1923  // and multplies with B^0C_L / sum B^0C_L
1924  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1925 
1926  // Get Phibar index range for sums
1927  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
1928  &ksel1, &kex1, &kex2, &ksel2);
1929 
1930  // Loop over Chi/Psi pixels
1931  for (int ipix = 0; ipix < npix; ++ipix) {
1932 
1933  // If DRB is not empty then correct it
1934  if (map_drb(ipix, iphibar) != 0.0) {
1935 
1936  // Initialise DRI sum
1937  double sum_dri = 0.0;
1938 
1939  // Take sum over [ksel1, kex1]
1940  if (kex1 >= 0) {
1941  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
1942  sum_dri += map_dri(ipix, kphibar);
1943  }
1944  }
1945 
1946  // Take sum over [kxe2, ksel2]
1947  if (kex2 < nphibar) {
1948  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
1949  sum_dri += map_dri(ipix, kphibar);
1950  }
1951  }
1952 
1953  // Correct DRB
1954  map_drb(ipix, iphibar) *= sum_dri;
1955 
1956  } // endif: DRB was not empty
1957 
1958  } // endfor: looped over Chi/Psi pixels
1959 
1960  } // endfor: looped over Phibar
1961 
1962  // Phibar normalise DRB
1963  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1964  double sum_dre = 0.0;
1965  double sum_drm = 0.0;
1966  double sum_drb = 0.0;
1967  for (int ipix = 0; ipix < npix; ++ipix) {
1968  sum_dre += map_dre(ipix, iphibar);
1969  sum_drm += map_drm(ipix, iphibar);
1970  sum_drb += map_drb(ipix, iphibar);
1971  }
1972  if (sum_drb > 0.0) {
1973  double norm = (sum_dre - sum_drm) / sum_drb;
1974  for (int ipix = 0; ipix < npix; ++ipix) {
1975  map_drb(ipix, iphibar) *= norm;
1976  }
1977  }
1978  else {
1979  for (int ipix = 0; ipix < npix; ++ipix) {
1980  map_drb(ipix, iphibar) = 0.0;
1981  }
1982  }
1983  }
1984 
1985  // Make sure that DRB is non-negative
1986  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1987  for (int ipix = 0; ipix < npix; ++ipix) {
1988  if (map_drb(ipix, iphibar) < 0.0) {
1989  map_drb(ipix, iphibar) = 0.0;
1990  }
1991  }
1992  }
1993 
1994  // Return
1995  return;
1996 }
1997 
1998 
1999 /***********************************************************************//**
2000  * @brief Compute DRB cube using BGDLIXE method
2001  *
2002  * @param[in] drm DRM cube.
2003  * @param[in] nrunav Number of bins used for running average.
2004  * @param[in] navgr Number of bins used for averaging.
2005  * @param[in] nincl Number of Phibar layers to include.
2006  * @param[in] nexcl Number of Phibar layers to exclude.
2007  *
2008  * @exception GException::invalid_value
2009  * Observation does not contain an event cube
2010  * @exception GException::invalid_argument
2011  * DRM cube is incompatible with DRE
2012  *
2013  * Computes a DRB cube using the BGDLIXE method. This method differs from
2014  * the BGDLIXA method in the last step.
2015  ***************************************************************************/
2017  const int& nrunav,
2018  const int& navgr,
2019  const int& nincl,
2020  const int& nexcl)
2021 {
2022  // Extract COMPTEL event cube
2023  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
2024  if (cube == NULL) {
2025  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
2026  "does not contain a COMPTEL event cube. Please "
2027  "specify a COMPTEL observation containing and event "
2028  "cube.";
2030  }
2031 
2032  // Check DRM
2033  if (!check_dri(drm)) {
2034  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
2035  "specify a DRM with a data-space definition that is "
2036  "identical to that of the DRE.";
2038  }
2039 
2040  // Initialise DRB and scratch DRI by cloning DRG
2041  m_drb = m_drg;
2042  GCOMDri dri = m_drg;
2043 
2044  // Get references to relevant sky maps
2045  const GSkyMap& map_dre = cube->dre().map();
2046  const GSkyMap& map_drm = drm.map();
2047  GSkyMap map_drg = get_weighted_drg_map();
2048  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
2049  GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map());
2050 
2051  // Get data space dimensions
2052  int nchi = m_drg.nchi();
2053  int npsi = m_drg.npsi();
2054  int nphibar = m_drg.nphibar();
2055  int npix = nchi * npsi;
2056 
2057  // Precompute half running average lengths
2058  int navgr2 = int(navgr/2);
2059 
2060  // Initialise DRB and scratch DRI
2061  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2062  for (int ipix = 0; ipix < npix; ++ipix) {
2063  map_drb(ipix, iphibar) = 0.0;
2064  map_dri(ipix, iphibar) = 0.0;
2065  }
2066  }
2067 
2068  // Phibar normalise DRG (Equation 3.12 in Rob van Dijk's PhD thesis).
2069  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2070  double sum_dre = 0.0;
2071  double sum_drm = 0.0;
2072  double sum_drg = 0.0;
2073  for (int ipix = 0; ipix < npix; ++ipix) {
2074  sum_dre += map_dre(ipix, iphibar);
2075  sum_drm += map_drm(ipix, iphibar);
2076  sum_drg += map_drg(ipix, iphibar);
2077  }
2078  if (sum_drg > 0.0) {
2079  double norm = (sum_dre - sum_drm) / sum_drg;
2080  for (int ipix = 0; ipix < npix; ++ipix) {
2081  map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm;
2082  }
2083  }
2084  }
2085 
2086  // Fit Phibar normalised DRG to DRE-DRM
2087  for (int ichi = 0; ichi < nchi; ++ichi) {
2088 
2089  // Compute running average window in Chi
2090  int kchi_min = ichi - navgr2;
2091  int kchi_max = ichi + navgr2;
2092  if (kchi_min < 0) {
2093  kchi_min = 0;
2094  }
2095  if (kchi_max >= nchi) {
2096  kchi_max = nchi - 1;
2097  }
2098 
2099  // Loop over Psi pixels
2100  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
2101 
2102  // Compute running average window in Psi
2103  int kpsi_min = ipsi - navgr2;
2104  int kpsi_max = ipsi + navgr2;
2105  if (kpsi_min < 0) {
2106  kpsi_min = 0;
2107  }
2108  if (kpsi_max >= npsi) {
2109  kpsi_max = npsi - 1;
2110  }
2111 
2112  // Loop over Phibar layers
2113  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2114 
2115  // Get Phibar index range for sums
2116  int ksel1 = 0;
2117  int kex1 = 0;
2118  int kex2 = 0;
2119  int ksel2 = 0;
2120  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
2121  &ksel1, &kex1, &kex2, &ksel2);
2122 
2123  // Initialise sums
2124  double sum_dre = 0.0;
2125  double sum_drm = 0.0;
2126  double sum_dri = 0.0;
2127 
2128  // Compute running average
2129  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
2130  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
2131 
2132  // Get index
2133  int kpix = kchi + kpsi * nchi;
2134 
2135  // Take sum over [ksel1, kex1]
2136  if (kex1 >= 0) {
2137  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
2138  sum_dre += map_dre(kpix, kphibar);
2139  sum_drm += map_drm(kpix, kphibar);
2140  sum_dri += map_dri(kpix, kphibar);
2141  }
2142  }
2143 
2144  // Take sum over [kxe2, ksel2]
2145  if (kex2 < nphibar) {
2146  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
2147  sum_dre += map_dre(kpix, kphibar);
2148  sum_drm += map_drm(kpix, kphibar);
2149  sum_dri += map_dri(kpix, kphibar);
2150  }
2151  }
2152 
2153  } // endfor: looped over kpsi
2154  } // endfor: looped over kchi
2155 
2156  // Renormalize DRI locally to DRE-DRM
2157  int ipix = ichi + ipsi * nchi;
2158  if (sum_dri > 0.0) {
2159  double norm = (sum_dre - sum_drm) / sum_dri;
2160  map_drb(ipix, iphibar) = map_dri(ipix, iphibar) * norm;
2161  }
2162  else {
2163  map_drb(ipix, iphibar) = 0.0;
2164  }
2165 
2166  } // endfor: looped over Phibar layers
2167 
2168  } // endfor: looped over Psi pixels
2169 
2170  } // endfor: looped over Chi pixels
2171 
2172  // Phibar normalise DRB
2173  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2174  double sum_dre = 0.0;
2175  double sum_drm = 0.0;
2176  double sum_drb = 0.0;
2177  for (int ipix = 0; ipix < npix; ++ipix) {
2178  sum_dre += map_dre(ipix, iphibar);
2179  sum_drm += map_drm(ipix, iphibar);
2180  sum_drb += map_drb(ipix, iphibar);
2181  }
2182  if (sum_drb > 0.0) {
2183  double norm = (sum_dre - sum_drm) / sum_drb;
2184  for (int ipix = 0; ipix < npix; ++ipix) {
2185  map_drb(ipix, iphibar) *= norm;
2186  }
2187  }
2188  else {
2189  for (int ipix = 0; ipix < npix; ++ipix) {
2190  map_drb(ipix, iphibar) = 0.0;
2191  }
2192  }
2193  }
2194 
2195  // Make sure that DRB is non-negative
2196  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2197  for (int ipix = 0; ipix < npix; ++ipix) {
2198  if (map_drb(ipix, iphibar) < 0.0) {
2199  map_drb(ipix, iphibar) = 0.0;
2200  }
2201  }
2202  }
2203 
2204  // Return
2205  return;
2206 }
2207 
2208 
2209 /***********************************************************************//**
2210  * @brief Compute DRB cube using BGDLIXF method
2211  *
2212  * @param[in] drm DRM cube.
2213  * @param[in] nrunav Number of bins used for running average.
2214  * @param[in] navgr Number of bins used for averaging.
2215  * @param[in] nincl Number of Phibar layers to include.
2216  * @param[in] nexcl Number of Phibar layers to exclude.
2217  *
2218  * @exception GException::invalid_value
2219  * Observation does not contain an event cube
2220  * @exception GException::invalid_argument
2221  * DRM cube is incompatible with DRE
2222  *
2223  * Computes a DRB cube using the BGDLIXF method. This method differs from
2224  * the BGDLIXE method in the DRW instead of the DRG is used for background
2225  * model computation.
2226  ***************************************************************************/
2228  const int& nrunav,
2229  const int& navgr,
2230  const int& nincl,
2231  const int& nexcl)
2232 {
2233  // Extract COMPTEL event cube
2234  const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events());
2235  if (cube == NULL) {
2236  std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") "
2237  "does not contain a COMPTEL event cube. Please "
2238  "specify a COMPTEL observation containing and event "
2239  "cube.";
2241  }
2242 
2243  // Check DRM
2244  if (!check_dri(drm)) {
2245  std::string msg = "Specified DRM cube is incompatible with DRE. Please "
2246  "specify a DRM with a data-space definition that is "
2247  "identical to that of the DRE.";
2249  }
2250 
2251  // Initialise DRB and scratch DRI by cloning DRW
2252  m_drb = m_drw;
2253  GCOMDri dri = m_drw;
2254 
2255  // Get references to relevant sky maps
2256  const GSkyMap& map_dre = cube->dre().map();
2257  const GSkyMap& map_drm = drm.map();
2258  const GSkyMap& map_drw = m_drw.map();
2259  GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map());
2260  GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map());
2261 
2262  // Get data space dimensions
2263  int nchi = m_drw.nchi();
2264  int npsi = m_drw.npsi();
2265  int nphibar = m_drw.nphibar();
2266  int npix = nchi * npsi;
2267 
2268  // Precompute half running average lengths
2269  int navgr2 = int(navgr/2);
2270 
2271  // Initialise DRB and scratch DRI
2272  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2273  for (int ipix = 0; ipix < npix; ++ipix) {
2274  map_drb(ipix, iphibar) = 0.0;
2275  map_dri(ipix, iphibar) = 0.0;
2276  }
2277  }
2278 
2279  // Phibar normalise DRW
2280  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2281  double sum_dre = 0.0;
2282  double sum_drm = 0.0;
2283  double sum_drw = 0.0;
2284  for (int ipix = 0; ipix < npix; ++ipix) {
2285  sum_dre += map_dre(ipix, iphibar);
2286  sum_drm += map_drm(ipix, iphibar);
2287  sum_drw += map_drw(ipix, iphibar);
2288  }
2289  if (sum_drw > 0.0) {
2290  double norm = (sum_dre - sum_drm) / sum_drw;
2291  for (int ipix = 0; ipix < npix; ++ipix) {
2292  map_dri(ipix, iphibar) = map_drw(ipix, iphibar) * norm;
2293  }
2294  }
2295  }
2296 
2297  // Fit Phibar normalised DRW to DRE-DRM
2298  for (int ichi = 0; ichi < nchi; ++ichi) {
2299 
2300  // Compute running average window in Chi
2301  int kchi_min = ichi - navgr2;
2302  int kchi_max = ichi + navgr2;
2303  if (kchi_min < 0) {
2304  kchi_min = 0;
2305  }
2306  if (kchi_max >= nchi) {
2307  kchi_max = nchi - 1;
2308  }
2309 
2310  // Loop over Psi pixels
2311  for (int ipsi = 0; ipsi < npsi; ++ipsi) {
2312 
2313  // Compute running average window in Psi
2314  int kpsi_min = ipsi - navgr2;
2315  int kpsi_max = ipsi + navgr2;
2316  if (kpsi_min < 0) {
2317  kpsi_min = 0;
2318  }
2319  if (kpsi_max >= npsi) {
2320  kpsi_max = npsi - 1;
2321  }
2322 
2323  // Loop over Phibar layers
2324  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2325 
2326  // Get Phibar index range for sums
2327  int ksel1 = 0;
2328  int kex1 = 0;
2329  int kex2 = 0;
2330  int ksel2 = 0;
2331  get_bgdlixa_phibar_indices(iphibar, nincl, nexcl,
2332  &ksel1, &kex1, &kex2, &ksel2);
2333 
2334  // Initialise sums
2335  double sum_dre = 0.0;
2336  double sum_drm = 0.0;
2337  double sum_dri = 0.0;
2338 
2339  // Compute running average
2340  for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) {
2341  for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) {
2342 
2343  // Get index
2344  int kpix = kchi + kpsi * nchi;
2345 
2346  // Take sum over [ksel1, kex1]
2347  if (kex1 >= 0) {
2348  for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) {
2349  sum_dre += map_dre(kpix, kphibar);
2350  sum_drm += map_drm(kpix, kphibar);
2351  sum_dri += map_dri(kpix, kphibar);
2352  }
2353  }
2354 
2355  // Take sum over [kxe2, ksel2]
2356  if (kex2 < nphibar) {
2357  for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) {
2358  sum_dre += map_dre(kpix, kphibar);
2359  sum_drm += map_drm(kpix, kphibar);
2360  sum_dri += map_dri(kpix, kphibar);
2361  }
2362  }
2363 
2364  } // endfor: looped over kpsi
2365  } // endfor: looped over kchi
2366 
2367  // Renormalize DRI locally to DRE-DRM
2368  int ipix = ichi + ipsi * nchi;
2369  if (sum_dri > 0.0) {
2370  double norm = (sum_dre - sum_drm) / sum_dri;
2371  map_drb(ipix, iphibar) = map_dri(ipix, iphibar) * norm;
2372  }
2373  else {
2374  map_drb(ipix, iphibar) = 0.0;
2375  }
2376 
2377  } // endfor: looped over Phibar layers
2378 
2379  } // endfor: looped over Psi pixels
2380 
2381  } // endfor: looped over Chi pixels
2382 
2383  // Phibar normalise DRB
2384  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2385  double sum_dre = 0.0;
2386  double sum_drm = 0.0;
2387  double sum_drb = 0.0;
2388  for (int ipix = 0; ipix < npix; ++ipix) {
2389  sum_dre += map_dre(ipix, iphibar);
2390  sum_drm += map_drm(ipix, iphibar);
2391  sum_drb += map_drb(ipix, iphibar);
2392  }
2393  if (sum_drb > 0.0) {
2394  double norm = (sum_dre - sum_drm) / sum_drb;
2395  for (int ipix = 0; ipix < npix; ++ipix) {
2396  map_drb(ipix, iphibar) *= norm;
2397  }
2398  }
2399  else {
2400  for (int ipix = 0; ipix < npix; ++ipix) {
2401  map_drb(ipix, iphibar) = 0.0;
2402  }
2403  }
2404  }
2405 
2406  // Make sure that DRB is non-negative
2407  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2408  for (int ipix = 0; ipix < npix; ++ipix) {
2409  if (map_drb(ipix, iphibar) < 0.0) {
2410  map_drb(ipix, iphibar) = 0.0;
2411  }
2412  }
2413  }
2414 
2415  // Return
2416  return;
2417 }
2418 
2419 
2420 /***********************************************************************//**
2421  * @brief Return weighted DRG map
2422  *
2423  * @return Weighted DRG map.
2424  *
2425  * Returns a DRG as sky map where each pixel of the map is multiplied by the
2426  * solidangle of the pixel.
2427  ***************************************************************************/
2429 {
2430  // Initialise
2431  GSkyMap drg = m_drg.map();
2432 
2433  // Get data space dimensions
2434  int npix = drg.npix();
2435  int nphibar = drg.nmaps();
2436 
2437  // Weight map
2438  for (int ipix = 0; ipix < npix; ++ipix) {
2439  double omega = drg.solidangle(ipix);
2440  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2441  drg(ipix,iphibar) *= omega;
2442  }
2443  }
2444 
2445  // Return weighted DRG map
2446  return drg;
2447 }
2448 
2449 
2450 /***********************************************************************//**
2451  * @brief Compute Phibar index range for BGDLIXA background method
2452  *
2453  * @param[in] iphibar Phibar layer index.
2454  * @param[in] nincl Number of Phibar layers to include.
2455  * @param[in] nexcl Number of Phibar layers to exclude.
2456  * @param[out] isel1 Start index for first sum.
2457  * @param[out] iex1 Stop index for first sum.
2458  * @param[out] iex2 Start index for second sum.
2459  * @param[out] isel2 Stop index for second sum.
2460  *
2461  * This method is a helper method for the BGDLIXA background method. It
2462  * computes the Phibar index range for the third step of the background
2463  * model computation. The third step corresponds to Equation (3.14) in Rob
2464  * van Dijk's PhD thesis.
2465  *
2466  * The Phibar sum will be taken over the index ranges [isel1, iex1] and
2467  * [ixe2, isel2].
2468  ***************************************************************************/
2470  const int& nincl,
2471  const int& nexcl,
2472  int* isel1,
2473  int* iex1,
2474  int* iex2,
2475  int* isel2) const
2476 {
2477  // Get number of Phibar layers
2478  int nphibar = m_drg.nphibar();
2479  int imax = nphibar - 1;
2480 
2481  // Precompute half running average lengths
2482  int nexcl2 = int(nexcl/2);
2483  int nincl2 = int(nincl/2);
2484 
2485  // Compute Phibar index range without respecting boundaries
2486  *iex1 = iphibar - nexcl2 - 1;
2487  *iex2 = iphibar + nexcl2 + 1;
2488  *isel1 = iphibar - nincl2;
2489  *isel2 = iphibar + nincl2;
2490 
2491  // If no Phibar layers are to be excluded then make sure that the
2492  // Phibar layer range is continuous
2493  if (nexcl == 0) {
2494  (*iex2)--;
2495  }
2496 
2497  // Make sure that start index of first sum and stop index of second
2498  // some are within the validity range
2499  if (*isel1 < 0) {
2500  *isel1 = 0;
2501  }
2502  if (*isel2 > imax) {
2503  *isel2 = imax;
2504  }
2505 
2506  // Make sure that the sums use always ncincl Phibar layers, also near
2507  // the edges
2508  if (*isel1 == 0) {
2509  *isel2 = nincl - 1;
2510  if (nincl > imax) {
2511  *isel2 = imax;
2512  }
2513 
2514  }
2515  if (*isel2 == imax) {
2516  *isel1 = nphibar - nincl;
2517  if (*isel1 < 0) {
2518  *isel1 = 0;
2519  }
2520  }
2521 
2522  // Return
2523  return;
2524 }
2525 
2526 
2527 /***********************************************************************//**
2528  * @brief Check whether bin should be used for likelihood analysis
2529  *
2530  * @param[in] index Event index.
2531  * @return True if event with specified @p index should be used.
2532  *
2533  * Implements the Phibar event selection.
2534  ***************************************************************************/
2535 bool GCOMObservation::use_event_for_likelihood(const int& index) const
2536 {
2537  // Initialise usage flag
2538  bool use = true;
2539 
2540  // Compute Phibar layer
2541  int iphi = index / m_drg.map().npix();
2542 
2543  // Test first Phibar layer selection
2544  if ((m_phi_first != -1) && (iphi < m_phi_first)) {
2545  use = false;
2546  }
2547  else {
2548  // Test last Phibar layer selection
2549  if ((m_phi_last != -1) && (iphi > m_phi_last)) {
2550  use = false;
2551  }
2552  }
2553 
2554  // Return usage flag
2555  return use;
2556 }
#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.
Abstract model class.
Definition: GModel.hpp:100
Sky map class.
Definition: GSkyMap.hpp:89
Abstract FITS image base class.
Definition: GFitsImage.hpp:43
void load(const GFilename &drename, const GFilename &drbname, const GFilename &drwname, const GFilename &drgname, const GFilename &drxname)
Load data for a binned observation.
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:379
virtual double size(void) const =0
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:465
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 compute_drb(const std::string &method, const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=15, const int &nexcl=0)
Compute DRB cube.
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.
Abstract interface for the event bin class.
Definition: GEventBin.hpp:64
const GFilename & drxname(void) const
Return DRX filename.
#define G_LOAD_DRG
virtual int size(void) const
Return number of bins in event cube.
const GFilename & drbname(void) const
Return DRB filename.
std::vector< GFilename > m_hkdnames
HKD filenames.
virtual double ontime(void) const
Return ontime.
const GCOMDri & drw(void) const
Return weighting cube.
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.
std::string m_id
Observation identifier.
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_drw(const GFilename &drwname)
Load weighting cube from DRW file.
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:500
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.
virtual double npred(const GModel &model) const
Return total number of predicted counts for one model.
FITS file class interface definition.
int nchi(void) const
Return number of Chi bins.
Definition: GCOMDri.hpp:242
#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
#define G_LOAD_DRW
const GFilename & drgname(void) const
Return DRG filename.
Source class definition.
void clear(void)
Clear Housekeeping Data collection.
Definition: GCOMHkds.cpp:233
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.
void compute_drb_bgdlixf(const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=15, const int &nexcl=0)
Compute DRB cube using BGDLIXF method.
#define G_COMPUTE_DRB
COMPTEL event bin class interface definition.
const GFilename & rspname(void) const
Return response cache filename.
void free_members(void)
Delete class members.
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.
GFilename m_rspname
Response cache filename.
void compute_drb_bgdlixa(const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=15, const int &nexcl=0)
Compute DRB cube using BGDLIXA method.
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
bool is_empty(void) const
Signals if there are no Housekeeping Data containers in collection.
Definition: GCOMHkds.hpp:166
virtual void read(const GFits &file)=0
GCOMBvcs m_bvcs
Solar System Barycentre Data.
const std::string & id(void) const
Return observation identifier.
GFilename m_drwname
DRW filename.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
const int & nmaps(void) const
Returns number of maps.
Definition: GSkyMap.hpp:391
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.
COMPTEL Housekeeping Data collection class.
Definition: GCOMHkds.hpp:51
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:278
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.
bool exists(void) const
Checks whether file exists.
Definition: GFilename.cpp:223
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 load_cache(const GFilename &filename)
Load response cache.
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
void save_cache(const GFilename &filename) const
Save response cache.
#define G_COMPUTE_DRB_BGDLIXF
void extend(const GCOMHkds &hkds)
Extend Housekeeping Data collection.
Definition: GCOMHkds.cpp:525
std::string print(const GChatter &chatter=NORMAL) const
Print Housekeeping Data collection.
Definition: GCOMHkds.cpp:639
bool is_fits(void) const
Checks whether file is a FITS file.
Definition: GFilename.cpp:313
const GFilename & drwname(void) const
Return DRW filename.
double m_livetime
Livetime (sec)
void init_members(void)
Initialise class members.
Abstract observation base class.
virtual GCOMObservation * clone(void) const
Clone COMPTEL observation.
void compute_drb_bgdlixe(const GCOMDri &drm, const int &nrunav=3, const int &navgr=3, const int &nincl=15, const int &nexcl=0)
Compute DRB cube using BGDLIXE method.
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:266
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
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
int size(void) const
Return number of Housekeeping parameters in collection.
Definition: GCOMHkds.hpp:151
Sky model class interface definition.
virtual double counts(void) const
Return number of counts in event bin.
Abstract event container class.
Definition: GEvents.hpp:66
virtual void clear(void)
Clear COMPTEL Data Space.
Definition: GCOMDri.cpp:227
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:955
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:254
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:363
COMPTEL Data Space class.
Definition: GCOMDri.hpp:62
virtual double livetime(void) const
Return livetime.
COMPTEL Orbit Aspect Data container class.
Definition: GCOMOads.hpp:51
GCOMHkds m_hkds
Housekeeping Data.
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.
const int & size(void) const
Return size of vector.
Definition: GVector.hpp:178
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.
GCOMDri m_drw
Weighting cube.
const int & npix(void) const
Returns number of pixels.
Definition: GSkyMap.hpp:347
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.
Abstract event bin container class.
Definition: GEventCube.hpp:46
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.
GModel * append(const GModel &model)
Append model to container.
Definition: GModels.cpp:420
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