GammaLib 2.0.0
Loading...
Searching...
No Matches
GSPIObservation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSPIObservation.cpp - INTEGRAL/SPI observation class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2020 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 GSPIObservation.cpp
23 * @brief INTEGRAL/SPI observation class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <typeinfo>
32#include "GException.hpp"
34#include "GSPIObservation.hpp"
35#include "GSPITools.hpp"
36#include "GSPIEventCube.hpp"
37
38/* __ Globals ____________________________________________________________ */
40const GObservationRegistry g_obs_spi_registry(&g_obs_spi_seed);
41
42/* __ Method name definitions ____________________________________________ */
43#define G_RESPONSE "GSPIObservation::response(GResponse&)"
44#define G_READ "GSPIObservation::read(GXmlElement&)"
45#define G_READ_FITS "GSPIObservation::read(GFits&)"
46#define G_WRITE "GSPIObservation::write(GXmlElement&)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51
52/* __ Debug definitions __________________________________________________ */
53
54
55/*==========================================================================
56 = =
57 = Constructors/destructors =
58 = =
59 ==========================================================================*/
60
61/***********************************************************************//**
62 * @brief Void constructor
63 *
64 * Creates an empty INTEGRAL/SPI observation.
65 ***************************************************************************/
67{
68 // Initialise members
70
71 // Return
72 return;
73}
74
75
76/***********************************************************************//**
77 * @brief XML constructor
78 *
79 * @param[in] xml XML element.
80 *
81 * Constructs an INTEGRAL/SPI observation from the information that is found
82 * in the XML element.
83 ***************************************************************************/
85{
86 // Initialise members
88
89 // Read XML
90 read(xml);
91
92 // Return
93 return;
94}
95
96
97/***********************************************************************//**
98 * @brief Observation Group constructor
99 *
100 * @param[in] filename Observation Group FITS file name.
101 *
102 * Constructs an INTEGRAL/SPI observation from an Observation Group.
103 ***************************************************************************/
105{
106 // Initialise members
107 init_members();
108
109 // Load data
110 load(filename);
111
112 // Return
113 return;
114}
115
116
117/***********************************************************************//**
118 * @brief Copy constructor
119 *
120 * @param[in] obs INTEGRAL/SPI observation.
121 *
122 * Creates INTEGRAL/SPI observation by copying from an existing INTEGRAL/SPI
123 * observation.
124 ***************************************************************************/
126{
127 // Initialise members
128 init_members();
129
130 // Copy members
131 copy_members(obs);
132
133 // Return
134 return;
135}
136
137
138/***********************************************************************//**
139 * @brief Destructor
140 ***************************************************************************/
142{
143 // Free members
144 free_members();
145
146 // Return
147 return;
148}
149
150
151/*==========================================================================
152 = =
153 = Operators =
154 = =
155 ==========================================================================*/
156
157/***********************************************************************//**
158 * @brief Assignment operator
159 *
160 * @param[in] obs INTEGRAL/SPI observation.
161 * @return INTEGRAL/SPI observation.
162 *
163 * Assign INTEGRAL/SPI observation to this object. The assignment performs
164 * a deep copy of all information, hence the original object from which the
165 * assignment was made can be destroyed after this operation without any loss
166 * of information.
167 ***************************************************************************/
169{
170 // Execute only if object is not identical
171 if (this != &obs) {
172
173 // Copy base class members
174 this->GObservation::operator=(obs);
175
176 // Free members
177 free_members();
178
179 // Initialise members
180 init_members();
181
182 // Copy members
183 copy_members(obs);
184
185 } // endif: object was not identical
186
187 // Return this object
188 return *this;
189}
190
191
192/*==========================================================================
193 = =
194 = Public methods =
195 = =
196 ==========================================================================*/
197
198/***********************************************************************//**
199 * @brief Clear INTEGRAL/SPI observation
200 *
201 * Clears INTEGRAL/SPI observation by resetting all class members to an
202 * initial state. Any information that was present before will be lost.
203 ***************************************************************************/
205{
206 // Free members
207 free_members();
209
210 // Initialise members
212 init_members();
213
214 // Return
215 return;
216}
217
218
219/***********************************************************************//**
220 * @brief Clone INTEGRAL/SPI observation
221 *
222 * @return Pointer to deep copy of INTEGRAL/SPI observation.
223 ***************************************************************************/
225{
226 return new GSPIObservation(*this);
227}
228
229
230/***********************************************************************//**
231 * @brief Set INTEGRAL/SPI response function
232 *
233 * @param[in] rsp INTEGRAL/SPI response function.
234 *
235 * @exception GException::invalid_argument
236 * Specified response is not a INTEGRAL/SPI response.
237 *
238 * Sets the response function for the observation.
239 ***************************************************************************/
241{
242 // Get pointer on INTEGRAL/SPI response
243 const GSPIResponse* spirsp = dynamic_cast<const GSPIResponse*>(&rsp);
244 if (spirsp == NULL) {
245 std::string cls = std::string(typeid(&rsp).name());
246 std::string msg = "Response of type \""+cls+"\" is "
247 "not a INTEGRAL/SPI response. Please specify a "
248 "INTEGRAL/SPI response as argument.";
250 }
251
252 // Clone response function
253 m_response = *spirsp;
254
255 // Return
256 return;
257}
258
259
260/***********************************************************************//**
261 * @brief Read INTEGRAL/SPI observation from XML element
262 *
263 * @param[in] xml XML element.
264 *
265 * Reads information for a INTEGRAL/SPI observation from an XML element.
266 * The expected format of the XML element is
267 *
268 * <observation name="Crab" id="0044" instrument="SPI">
269 * <parameter name="ObservationGroup" file="og_spi.fits"/>
270 * </observation>
271 *
272 * In addition, a response group can be specified using
273 *
274 * <observation name="Crab" id="0044" instrument="SPI">
275 * <parameter name="ObservationGroup" file="og_spi.fits"/>
276 * <parameter name="ResponseGroup" file="spi_irf_grp.fits"/>
277 * </observation>
278 *
279 * If a response group is found the file is loaded and the response is set.
280 * Optionally, an energy attribute can be specified in units of keV, leading
281 * to the setup of a line response
282 *
283 * <observation name="Crab" id="0044" instrument="SPI">
284 * <parameter name="ObservationGroup" file="og_spi.fits"/>
285 * <parameter name="ResponseGroup" file="spi_irf_grp.fits" energy="511"/>
286 * </observation>
287 *
288 * Alternatively, a response file can be specified, which will be directly
289 * loaded in the SPI response class.
290 *
291 * <observation name="Crab" id="0044" instrument="SPI">
292 * <parameter name="ObservationGroup" file="og_spi.fits"/>
293 * <parameter name="ResponseFile" file="irf.fits"/>
294 * </observation>
295 ***************************************************************************/
297{
298 // Clear observation
299 clear();
300
301 // Extract instrument name
302 m_instrument = xml.attribute("instrument");
303
304 // Get expanded Observation Group file name
305 m_filename = gammalib::xml_get_attr(G_READ, xml, "ObservationGroup", "file");
307
308 // Load Observation Group
310
311 // If a response group is specified then get expanded file name and
312 // load it
313 if (gammalib::xml_has_par(xml, "ResponseGroup")) {
314
315 // Get parameter
316 const GXmlElement* par = gammalib::xml_get_par(G_READ, xml, "ResponseGroup");
317
318 // Get expanded filename
319 m_rsp_grpname = par->attribute("file");
321
322 // Set response group name
324
325 // If we have an energy attribute then extract line energy and set
326 // response as line response
327 if (par->has_attribute("energy")) {
328 double value = gammalib::todouble(par->attribute("energy"));
329 GEnergy energy(value, "keV");
330 m_response.set(*this, energy);
331 }
332
333 // ... otherwise set response as continnum response
334 else {
335 m_response.set(*this);
336 }
337
338 } // endif: reponse group specified
339
340 // ... otherwise if a response file is specified then load the response
341 // from the response file
342 else if (gammalib::xml_has_par(xml, "ResponseFile")) {
343
344 // Get expanded response file name
345 m_rsp_filename = gammalib::xml_get_attr(G_READ, xml, "ResponseFile", "file");
347
348 // Load response
350
351 } // endelse: reponse file was specified
352
353 // Return
354 return;
355}
356
357
358/***********************************************************************//**
359 * @brief Write INTEGRAL/SPI observation into XML element
360 *
361 * @param[in] xml XML element.
362 *
363 * Writes information for a INTEGRAL/SPI observation into an XML element.
364 * In case that no response information is available the method writes the
365 * format
366 *
367 * <observation name="Crab" id="0044" instrument="SPI">
368 * <parameter name="ObservationGroup" file="og_spi.fits"/>
369 * </observation>
370 *
371 * If a response group file is defined the method writes the format
372 *
373 * <observation name="Crab" id="0044" instrument="SPI">
374 * <parameter name="ObservationGroup" file="og_spi.fits"/>
375 * <parameter name="ResponseGroup" file="spi_irf_grp.fits" energy="511"/>
376 * </observation>
377 *
378 * The energy attribute is optional, and is only written in case that the
379 * IRF is a line IRF.
380 *
381 * Otherwise, if a response file is defined the method writes the format
382 *
383 * <observation name="Crab" id="0044" instrument="SPI">
384 * <parameter name="ObservationGroup" file="og_spi.fits"/>
385 * <parameter name="ResponseFile" file="irf.fits"/>
386 * </observation>
387 ***************************************************************************/
389{
390 // Allocate XML element pointer
391 GXmlElement* par;
392
393 // Set ObservationGroup parameter
394 par = gammalib::xml_need_par(G_WRITE, xml, "ObservationGroup");
396
397 // If we have a response group filename then write it as response
398 // group
399 if (!m_rsp_grpname.is_empty()) {
400 par = gammalib::xml_need_par(G_WRITE, xml, "ResponseGroup");
402 if (m_response.energy_keV() > 0.0) {
403 par->attribute("energy", gammalib::str(m_response.energy_keV()));
404 }
405 }
406
407 // ... otherwise if we have a response file then write the response
408 // file
409 else if (!m_rsp_filename.is_empty()) {
410 par = gammalib::xml_need_par(G_WRITE, xml, "ResponseFile");
412 }
413
414 // Return
415 return;
416}
417
418
419/***********************************************************************//**
420 * @brief Read Observation Group from FITS file
421 *
422 * @param[in] fits FITS file.
423 *
424 * Reads Observation Group from a FITS file.
425 ***************************************************************************/
427{
428 // Delete any existing event container (do not call clear() as we do not
429 // want to delete the response function)
430 if (m_events != NULL) delete m_events;
431
432 // Allocate new event cube
434
435 // Assign event cube as the observation's event container
437
438 // Read in Observation Group
439 events->read(fits);
440
441 // Store ontime and livetime and compute deadtime correction
442 m_ontime = events->ontime();
443 m_livetime = events->livetime();
444 m_deadc = (m_ontime > 0.0) ? m_livetime/m_ontime : 1.0;
445
446 // Return
447 return;
448}
449
450
451/***********************************************************************//**
452 * @brief Load Observation Group
453 *
454 * @param[in] filename Observation Group FITS file name.
455 *
456 * Loads data from an Observation Group FITS file into an INTEGRAL/SPI
457 * observation.
458 ***************************************************************************/
459void GSPIObservation::load(const GFilename& filename)
460{
461 #pragma omp critical(GSPIObservation_load)
462 {
463 // Store event filename
464 m_filename = filename;
465
466 // Open FITS file
467 GFits fits(filename);
468
469 // Read data
470 read(fits);
471
472 // Close FITS file
473 fits.close();
474 }
475
476 // Return
477 return;
478}
479
480
481/***********************************************************************//**
482 * @brief Print observation information
483 *
484 * @param[in] chatter Chattiness.
485 * @return String containing INTEGRAL/SPI observation information.
486 ***************************************************************************/
487std::string GSPIObservation::print(const GChatter& chatter) const
488{
489 // Initialise result string
490 std::string result;
491
492 // Continue only if chatter is not silent
493 if (chatter != SILENT) {
494
495 // Append header
496 result.append("=== GSPIObservation ===");
497
498 // Append standard information for observation
499 result.append("\n"+gammalib::parformat("Name")+name());
500 result.append("\n"+gammalib::parformat("Observation group filename"));
501 result.append(m_filename.url());
502 if (!m_rsp_grpname.is_empty()) {
503 result.append("\n"+gammalib::parformat("Response group filename"));
504 result.append(m_rsp_grpname.url());
505 }
506 if (!m_rsp_filename.is_empty()) {
507 result.append("\n"+gammalib::parformat("Response filename"));
508 result.append(m_rsp_filename.url());
509 }
510 result.append("\n"+gammalib::parformat("Identifier")+id());
511 result.append("\n"+gammalib::parformat("Instrument")+instrument());
512 result.append("\n"+gammalib::parformat("Statistic")+statistic());
513 result.append("\n"+gammalib::parformat("Ontime"));
514 result.append(gammalib::str(ontime())+" sec");
515 result.append("\n"+gammalib::parformat("Livetime"));
516 result.append(gammalib::str(livetime())+" sec");
517 result.append("\n"+gammalib::parformat("Deadtime correction"));
518 result.append(gammalib::str(m_deadc));
519
520 // Append detailed information
521 GChatter reduced_chatter = gammalib::reduce(chatter);
522 if (reduced_chatter > SILENT) {
523
524 // Append response
525 result.append("\n"+m_response.print(reduced_chatter));
526
527 // Append events
528 if (m_events != NULL) {
529 result.append("\n"+m_events->print(reduced_chatter));
530 }
531
532 } // endif: appended detailed information
533
534 } // endif: chatter was not silent
535
536 // Return result
537 return result;
538}
539
540
541/*==========================================================================
542 = =
543 = Private methods =
544 = =
545 ==========================================================================*/
546
547/***********************************************************************//**
548 * @brief Initialise class members
549 ***************************************************************************/
551{
552 // Initialise members
553 m_instrument = "SPI";
558 m_ontime = 0.0;
559 m_livetime = 0.0;
560 m_deadc = 0.0;
561
562 // Return
563 return;
564}
565
566
567/***********************************************************************//**
568 * @brief Copy class members
569 *
570 * @param[in] obs INTEGRAL/SPI observation.
571 ***************************************************************************/
573{
574 // Copy members
580 m_ontime = obs.m_ontime;
582 m_deadc = obs.m_deadc;
583
584 // Return
585 return;
586}
587
588
589/***********************************************************************//**
590 * @brief Delete class members
591 ***************************************************************************/
593{
594 // Return
595 return;
596}
#define G_WRITE
#define G_READ
#define G_RESPONSE
Exception handler interface definition.
Observation registry class definition.
INTEGRAL/SPI event bin container class definition.
const GSPIObservation g_obs_spi_seed
INTEGRAL/SPI observation class definition.
Definition of INTEGRAL/SPI tools.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
virtual void read(const GFits &file)=0
virtual std::string print(const GChatter &chatter=NORMAL) const =0
Print content of object.
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
bool is_empty(void) const
Signal if filename is empty.
void clear(void)
Clear file name.
FITS file class.
Definition GFits.hpp:63
void close(void)
Close FITS file.
Definition GFits.cpp:1342
Interface definition for the observation registry class.
Abstract observation base class.
const std::string & statistic(void) const
Return optimizer statistic.
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.
Abstract instrument response base class.
Definition GResponse.hpp:77
INTEGRAL/SPI event bin container class.
INTEGRAL/SPI observation class.
double m_deadc
Deadtime correction.
double m_ontime
Ontime (sec)
void load(const GFilename &filename)
Load Observation Group.
GSPIObservation(void)
Void constructor.
void copy_members(const GSPIObservation &obs)
Copy class members.
virtual double ontime(void) const
Return ontime.
virtual void read(const GXmlElement &xml)
Read INTEGRAL/SPI observation from XML element.
virtual ~GSPIObservation(void)
Destructor.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print observation information.
void init_members(void)
Initialise class members.
virtual double livetime(void) const
Return livetime.
GFilename m_rsp_filename
Response FITS filename (optional)
virtual void write(GXmlElement &xml) const
Write INTEGRAL/SPI observation into XML element.
virtual GSPIObservation * clone(void) const
Clone INTEGRAL/SPI observation.
GSPIResponse m_response
Response functions.
virtual GSPIObservation & operator=(const GSPIObservation &obs)
Assignment operator.
GFilename m_rsp_grpname
Response group FITS filename (optional)
virtual const GSPIResponse * response(void) const
Return pointer to response function.
virtual void clear(void)
Clear INTEGRAL/SPI observation.
double m_livetime
Livetime (sec)
std::string m_instrument
Instrument name.
GFilename m_filename
OG FITS filename.
virtual std::string instrument(void) const
Return instrument.
void free_members(void)
Delete class members.
INTEGRAL/SPI instrument response function class.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print INTEGRAL/SPI response information.
void load(const GFilename &filename)
Load SPI response from file.
void rspname(const GFilename &rspname)
Set response name.
virtual void clear(void)
Clear instance.
const double & energy_keV(void) const
Return line IRF energy in keV.
void set(const GSPIObservation &obs, const GEnergy &energy=GEnergy())
Set response for a specific observation.
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.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1689
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:926
std::string xml_get_attr(const std::string &origin, const GXmlElement &xml, const std::string &name, const std::string &attribute)
Return attribute value for a given parameter in XML element.
Definition GTools.cpp:1738
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1637
GFilename xml_file_reduce(const GXmlElement &xml, const std::string &filename)
Reduce file name provided for writing as XML attribute.
Definition GTools.cpp:1946
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:1596
GFilename xml_file_expand(const GXmlElement &xml, const std::string &filename)
Expand file name provided as XML attribute for loading.
Definition GTools.cpp:1889