GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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"
33 #include "GObservationRegistry.hpp"
34 #include "GSPIObservation.hpp"
35 #include "GSPITools.hpp"
36 #include "GSPIEventCube.hpp"
37 
38 /* __ Globals ____________________________________________________________ */
40 const 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
69  init_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
87  init_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
309  load(m_filename);
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");
395  par->attribute("file", gammalib::xml_file_reduce(xml, m_filename));
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  ***************************************************************************/
426 void GSPIObservation::read(const GFits& fits)
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
436  m_events = events;
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  ***************************************************************************/
459 void 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  ***************************************************************************/
487 std::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";
554  m_filename.clear();
557  m_response.clear();
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
576  m_filename = obs.m_filename;
579  m_response = obs.m_response;
580  m_ontime = obs.m_ontime;
581  m_livetime = obs.m_livetime;
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 }
virtual double ontime(void) const
Return ontime.
const std::string & statistic(void) const
Return optimizer statistic.
virtual void read(const GFits &file)
Read INTEGRAL/SPI event cube from Observation Group FITS file.
virtual GSPIObservation * clone(void) const
Clone INTEGRAL/SPI observation.
virtual void clear(void)
Clear instance.
void rspname(const GFilename &rspname)
Set response name.
virtual void clear(void)
Clear INTEGRAL/SPI observation.
virtual ~GSPIObservation(void)
Destructor.
GEvents * m_events
Pointer to event container.
GFilename m_filename
OG FITS filename.
double m_ontime
Ontime (sec)
bool is_empty(void) const
Signal if filename is empty.
Definition: GFilename.hpp:160
XML element node class.
Definition: GXmlElement.hpp:48
INTEGRAL/SPI event bin container class definition.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print INTEGRAL/SPI response information.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print observation information.
GSPIObservation(void)
Void constructor.
FITS file class.
Definition: GFits.hpp:63
GFilename xml_file_reduce(const GXmlElement &xml, const std::string &filename)
Reduce file name provided for writing as XML attribute.
Definition: GTools.cpp:1946
void free_members(void)
Delete class members.
virtual void write(GXmlElement &xml) const
Write INTEGRAL/SPI observation into XML element.
void free_members(void)
Delete class members.
const GSPIObservation g_obs_spi_seed
INTEGRAL/SPI event bin container class.
GFilename m_rsp_filename
Response FITS filename (optional)
const GXmlAttribute * attribute(const int &index) const
Return attribute.
double m_livetime
Livetime (sec)
Filename class.
Definition: GFilename.hpp:62
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
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
Interface definition for the observation registry class.
GSPIResponse m_response
Response functions.
const std::string & name(void) const
Return observation name.
void copy_members(const GSPIObservation &obs)
Copy class members.
Observation registry class definition.
double livetime(void) const
Return total livetime.
virtual std::string instrument(void) const
Return instrument.
GChatter
Definition: GTypemaps.hpp:33
void init_members(void)
Initialise class members.
void init_members(void)
Initialise class members.
Abstract observation base class.
virtual const GSPIResponse * response(void) const
Return pointer to response function.
void load(const GFilename &filename)
Load Observation Group.
virtual GSPIObservation & operator=(const GSPIObservation &obs)
Assignment operator.
#define G_RESPONSE
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
INTEGRAL/SPI observation class.
double m_deadc
Deadtime correction.
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
INTEGRAL/SPI observation class definition.
GFilename m_rsp_grpname
Response group FITS filename (optional)
GChatter reduce(const GChatter &chatter)
Reduce chattiness by one level.
Definition: GTypemaps.hpp:65
#define G_WRITE
virtual GObservation & operator=(const GObservation &obs)
Assignment operator.
virtual GEvents * events(void)
Return events.
Exception handler interface definition.
std::string m_instrument
Instrument name.
INTEGRAL/SPI instrument response function class.
double ontime(void) const
Return total ontime.
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
virtual void read(const GXmlElement &xml)
Read INTEGRAL/SPI observation from XML element.
void load(const GFilename &filename)
Load SPI response from file.
Abstract instrument response base class.
Definition: GResponse.hpp:77
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
Definition of INTEGRAL/SPI tools.
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
virtual double livetime(void) const
Return livetime.
const double & energy_keV(void) const
Return line IRF energy in keV.
virtual std::string print(const GChatter &chatter=NORMAL) const =0
Print content of object.
double todouble(const std::string &arg)
Convert string into double precision value.
Definition: GTools.cpp:926
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
GFilename xml_file_expand(const GXmlElement &xml, const std::string &filename)
Expand file name provided as XML attribute for loading.
Definition: GTools.cpp:1889
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
void set(const GSPIObservation &obs, const GEnergy &energy=GEnergy())
Set response for a specific observation.
#define G_READ