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