GammaLib 2.0.0
Loading...
Searching...
No Matches
GMWLSpectrum.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GMWLSpectrum.cpp - Multi-wavelength spectrum class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2010-2021 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 GMWLSpectrum.cpp
23 * @brief Multi-wavelength spectrum class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GTools.hpp"
32#include "GFilename.hpp"
33#include "GFits.hpp"
34#include "GFitsTable.hpp"
35#include "GEnergy.hpp"
36#include "GException.hpp"
37#include "GMWLSpectrum.hpp"
38
39/* __ Method name definitions ____________________________________________ */
40#define G_OPERATOR "GMWLSpectrum::operator[](int&)"
41#define G_READ "GMWLSpectrum::read(GFits&, int&)"
42#define G_READ_FITS "GMWLSpectrum::read_fits(GFitsTable&)"
43#define G_CONV_ENERGY "GMWLSpectrum::conv_energy(double&, std::string&)"
44#define G_CONV_FLUX "GMWLSpectrum::conv_flux(GEnergy&, double&, "\
45 "std::string&)"
46
47/* __ Macros _____________________________________________________________ */
48
49/* __ Coding definitions _________________________________________________ */
50
51/* __ Debug definitions __________________________________________________ */
52
53
54
55/*==========================================================================
56 = =
57 = Constructors/destructors =
58 = =
59 ==========================================================================*/
60
61/***********************************************************************//**
62 * @brief Void constructor
63 *
64 * Creates instance of an undefined spectrum.
65 ***************************************************************************/
67{
68 // Initialise members
70
71 // Return
72 return;
73}
74
75
76/***********************************************************************//**
77 * @brief File constructor
78 *
79 * @param[in] filename File name.
80 *
81 * Creates instance from file.
82 ***************************************************************************/
84{
85 // Initialise members
87
88 // Load spectrum
89 load(filename);
90
91 // Return
92 return;
93}
94
95
96/***********************************************************************//**
97 * @brief Copy constructor
98 *
99 * @param[in] spec Spectrum.
100 *
101 * Creates instance by copying an existing spectrum.
102 ***************************************************************************/
104{
105 // Initialise class members for clean destruction
106 init_members();
107
108 // Copy members
109 copy_members(spec);
110
111 // Return
112 return;
113}
114
115
116/***********************************************************************//**
117 * @brief Destructor
118 *
119 * Destroy instance.
120 ***************************************************************************/
122{
123 // Free members
124 free_members();
125
126 // Return
127 return;
128}
129
130
131/*==========================================================================
132 = =
133 = Operators =
134 = =
135 ==========================================================================*/
136
137/***********************************************************************//**
138 * @brief Assignment operator
139 *
140 * @param[in] spec Spectrum.
141 * @return Spectrum.
142 ***************************************************************************/
144{
145 // Execute only if object is not identical
146 if (this != &spec) {
147
148 // Copy base class members
149 this->GEventCube::operator=(spec);
150
151 // Free members
152 free_members();
153
154 // Initialise members
155 init_members();
156
157 // Copy members
158 copy_members(spec);
159
160 } // endif: object was not identical
161
162 // Return this object
163 return *this;
164}
165
166
167/***********************************************************************//**
168 * @brief Spectral point access operator
169 *
170 * @param[in] index Spectral point index [0,...,size()-1].
171 *
172 * @exception GException::out_of_range
173 * Spectral point index outside valid range.
174 ***************************************************************************/
176{
177 // Optionally check if the index is valid
178 #if defined(G_RANGE_CHECK)
179 if (index < 0 || index >= size()) {
180 throw GException::out_of_range(G_OPERATOR, "Spectral point", index, size());
181 }
182 #endif
183
184 // Return pointer
185 return &(m_data[index]);
186}
187
188
189/***********************************************************************//**
190 * @brief Spectral point access operator (const version)
191 *
192 * @param[in] index Spectral point index [0,...,size()-1].
193 *
194 * @exception GException::out_of_range
195 * Spectral point index outside valid range.
196 ***************************************************************************/
197const GMWLDatum* GMWLSpectrum::operator[](const int& index) const
198{
199 // Optionally check if the index is valid
200 #if defined(G_RANGE_CHECK)
201 if (index < 0 || index >= size()) {
202 throw GException::out_of_range(G_OPERATOR, "Spectral point", index, size());
203 }
204 #endif
205
206 // Return pointer
207 return &(m_data[index]);
208}
209
210
211/*==========================================================================
212 = =
213 = Public methods =
214 = =
215 ==========================================================================*/
216
217/***********************************************************************//**
218 * @brief Clear spectrum
219 ***************************************************************************/
221{
222 // Free class members (base and derived classes, derived class first)
223 free_members();
225 this->GEvents::free_members();
226
227 // Initialise members
228 this->GEvents::init_members();
230 init_members();
231
232 // Return
233 return;
234}
235
236
237/***********************************************************************//**
238 * @brief Clone spectrum
239 *
240 * @return Pointer to deep copy of spectrum.
241 ***************************************************************************/
243{
244 return new GMWLSpectrum(*this);
245}
246
247
248/***********************************************************************//**
249 * @brief Load spectrum
250 *
251 * @param[in] filename File name.
252 *
253 * This method loads a spectrum from a variety of file types. The method
254 * analyses the format of the file that is presented and choses then the
255 * appropriate method to load the specific format. The following file
256 * formats are supported: FITS, TBW ...
257 *
258 * @todo So far only FITS file support is implemented.
259 ***************************************************************************/
260void GMWLSpectrum::load(const GFilename& filename)
261{
262 // Clear object
263 clear();
264
265 // Open FITS file
266 GFits fits(filename);
267
268 // Read spectrum
269 if (filename.has_extno()) {
270 read(fits, filename.extno());
271 }
272 else if (filename.has_extname()) {
273 read(fits, filename.extname());
274 }
275 else {
276 read(fits);
277 }
278
279 // Close FITS file
280 fits.close();
281
282 // Return
283 return;
284}
285
286
287/***********************************************************************//**
288 * @brief Save spectrum
289 *
290 * @param[in] filename File name.
291 * @param[in] clobber Overwrite existing file (default: false).
292 *
293 * @todo To be implemented.
294 ***************************************************************************/
295void GMWLSpectrum::save(const GFilename& filename,
296 const bool& clobber) const
297{
298 // Return
299 return;
300}
301
302
303/***********************************************************************//**
304 * @brief Read spectrum from FITS file
305 *
306 * @param[in] file FITS file.
307 *
308 * Read spectrum from first extension in FITS file.
309 ***************************************************************************/
310void GMWLSpectrum::read(const GFits& file)
311{
312 // Clear object
313 clear();
314
315 // Read spectrum from first extension in FITS file
316 read(file, 0);
317
318 // Return
319 return;
320}
321
322
323/***********************************************************************//**
324 * @brief Read spectrum from FITS file
325 *
326 * @param[in] fits FITS file.
327 * @param[in] extname FITS extension name.
328 ***************************************************************************/
329void GMWLSpectrum::read(const GFits& fits, const std::string& extname)
330{
331 // Clear object
332 clear();
333
334 // Get table pointer
335 const GFitsTable& table = *fits.table(extname);
336
337 // Read spectrum from table
338 read_fits(table);
339
340 // Return
341 return;
342}
343
344
345/***********************************************************************//**
346 * @brief Read spectrum from FITS file
347 *
348 * @param[in] fits FITS file.
349 * @param[in] extno Extension number of spectrum.
350 *
351 * @exception GException::invalid_argument
352 * No table found in FITS file.
353 *
354 * Read the spectrum from a FITS table found in the specified extension.
355 * In no extension number if specified (or if extno=0) then the spectrum
356 * is loaded from the first table extension that is found in the file.
357 ***************************************************************************/
358void GMWLSpectrum::read(const GFits& fits, const int& extno)
359{
360 // Clear object
361 clear();
362
363 // Initialise extension number
364 int extension = extno;
365
366 // If the extension number is 0 then load first FITS table in file.
367 if (extension == 0) {
368 for (int i = 0; i < fits.size(); ++i) {
369 if (fits.at(i)->exttype() == GFitsHDU::HT_ASCII_TABLE ||
370 fits.at(i)->exttype() == GFitsHDU::HT_BIN_TABLE) {
371 extension = i;
372 break;
373 }
374 }
375 }
376
377 // If we found no table then throw an exception
378 if (extension == 0) {
379 std::string msg = "No table found in file \""+fits.filename().url()+
380 "\". Please specify a FITS object containing a "
381 "table.";
383 }
384
385 // Get table pointer
386 const GFitsTable& table = *fits.table(extension);
387
388 // Read spectrum from table
389 read_fits(table);
390
391 // Return
392 return;
393}
394
395
396/***********************************************************************//**
397 * @brief Write spectrum into FITS file
398 *
399 * @param[in] file FITS file.
400 *
401 * @todo To be implemented.
402 ***************************************************************************/
403void GMWLSpectrum::write(GFits& file) const
404{
405 // Return
406 return;
407}
408
409
410/***********************************************************************//**
411 * @brief Return number of points in spectrum
412 ***************************************************************************/
413int GMWLSpectrum::number(void) const
414{
415 // Return
416 return (size());
417}
418
419
420/***********************************************************************//**
421 * @brief Print spectrum
422 *
423 * @param[in] chatter Chattiness (defaults to NORMAL).
424 * @return String containing spectrum
425 ***************************************************************************/
426std::string GMWLSpectrum::print(const GChatter& chatter) const
427{
428 // Initialise result string
429 std::string result;
430
431 // Continue only if chatter is not silent
432 if (chatter != SILENT) {
433
434 // Append header
435 result.append("=== GMWLSpectrum ===");
436
437 // Append information
438 result.append("\n"+gammalib::parformat("Telescope")+m_telescope);
439 result.append("\n"+gammalib::parformat("Instrument")+m_instrument);
440 result.append("\n"+gammalib::parformat("Number of points"));
441 result.append(gammalib::str(size()));
442 result.append("\n"+gammalib::parformat("Time interval"));
443 if (m_gti.size() > 0) {
444 result.append(gammalib::str(tstart().secs())+" - ");
445 result.append(gammalib::str(tstop().secs())+" sec");
446 }
447 else {
448 result.append("not defined");
449 }
450 result.append("\n"+gammalib::parformat("Energy range"));
451 if (m_ebounds.size() > 0) {
452 result.append(emin().print()+" - "+emax().print());
453 }
454 else {
455 result.append("not defined");
456 }
457
458 // EXPLICIT: Append spectral points
459 if (chatter >= EXPLICIT) {
460 for (int i = 0; i < size(); ++i) {
461
462 // Build energy string
463 std::string energy = m_data[i].m_eng.print();
464 if (m_data[i].m_eng_err.MeV() > 0.0) {
465 energy += " +/- "+m_data[i].m_eng_err.print();
466 }
467
468 // Build flux string
469 std::string flux = gammalib::str(m_data[i].m_flux);
470 if (m_data[i].m_flux_err > 0.0) {
471 flux += " +/- "+gammalib::str(m_data[i].m_flux_err);
472 }
473 flux += " ph/cm2/s/MeV";
474
475 // Append to string
476 result.append("\n"+gammalib::parformat(energy));
477 result.append(flux);
478
479 } // endfor: looped over spectral points
480
481 } // endif: EXPLICIT level
482
483 } // endif: chatter was not silent
484
485 // Return result
486 return result;
487}
488
489
490/*==========================================================================
491 = =
492 = Private methods =
493 = =
494 ==========================================================================*/
495
496/***********************************************************************//**
497 * @brief Initialise class members
498 ***************************************************************************/
500{
501 // Initialise members
502 m_telescope.clear();
503 m_instrument.clear();
504 m_data.clear();
505
506 // Return
507 return;
508}
509
510
511/***********************************************************************//**
512 * @brief Copy class members
513 *
514 * @param[in] spec Instance to be copied.
515 ***************************************************************************/
517{
518 // Copy members
521 m_data = spec.m_data;
522
523 // Return
524 return;
525}
526
527
528/***********************************************************************//**
529 * @brief Delete class members
530 ***************************************************************************/
532{
533 // Return
534 return;
535}
536
537
538/***********************************************************************//**
539 * @brief Set energy boundaries
540 ***************************************************************************/
542{
543 // Clear energy boundaries
545
546 // Continue only if we have data
547 if (size() > 0) {
548
549 // Extract energy boundaries from spectrum
550 GEnergy emin = m_data[0].energy();
551 GEnergy emax = m_data[0].energy();
552 for (int i = 0; i < m_data.size(); ++i) {
553 if (m_data[i].energy() < emin) emin = m_data[i].energy();
554 if (m_data[i].energy() > emax) emax = m_data[i].energy();
555 }
556
557 // Set energy boundaries
559
560 } // endif: we had data
561
562 // Return
563 return;
564}
565
566
567/***********************************************************************//**
568 * @brief Read spectrum from FITS file
569 *
570 * @param[in] table FITS table.
571 *
572 * @exception GException::invalid_argument
573 * Table does not contain at least two columns.
574 *
575 * Read spectrum from FITS table. The table is expected to be in one of the
576 * three following formats:
577 * 2 columns: energy, flux
578 * 3 columns: energy, flux, e_flux
579 * 4 columns or more: energy, e_energy, flux, e_flux, ...
580 *
581 * @todo Investigate whether we can exploit UCDs for identifying the correct
582 * columns or for determining the units.
583 ***************************************************************************/
585{
586 // Reset spectrum
587 m_data.clear();
588
589 // Initialise column pointers columns
590 const GFitsTableCol* c_energy = NULL;
591 const GFitsTableCol* c_energy_err = NULL;
592 const GFitsTableCol* c_flux = NULL;
593 const GFitsTableCol* c_flux_err = NULL;
594
595 // Extract column pointers
596 if (table.ncols() == 2) {
597 c_energy = table[0];
598 c_flux = table[1];
599 }
600 else if (table.ncols() == 3) {
601 c_energy = table[0];
602 c_flux = table[1];
603 c_flux_err = table[2];
604 }
605 else if (table.ncols() > 3) {
606 c_energy = table[0];
607 c_energy_err = table[1];
608 c_flux = table[2];
609 c_flux_err = table[3];
610 }
611 else {
612 std::string msg = "At least 2 columns are expected in FITS table \""+
613 table.extname()+"\"but found "+
614 gammalib::str(table.ncols())+" columns. Please "
615 "specify a FITS table with at least two columns.";
617 }
618
619 // Read spectral points and add to spectrum
620 for (int i = 0; i < table.nrows(); ++i) {
621 GMWLDatum datum;
622 if (c_energy != NULL) {
623 datum.m_eng = conv_energy(c_energy->real(i), c_energy->unit());
624 }
625 if (c_energy_err != NULL) {
626 datum.m_eng_err = conv_energy(c_energy_err->real(i), c_energy->unit());
627 }
628 if (c_flux != NULL) {
629 datum.m_flux = conv_flux(datum.m_eng, c_flux->real(i), c_flux->unit());
630 }
631 if (c_flux_err != NULL) {
632 datum.m_flux_err = conv_flux(datum.m_eng, c_flux_err->real(i), c_flux_err->unit());
633 }
634 m_data.push_back(datum);
635 }
636
637 // Get telescope name
638 if (table.has_card("TELESCOP")) {
639 m_telescope = table.string("TELESCOP");
640 }
641 else {
642 m_telescope = "unknown";
643 }
644
645 // Get instrument name
646 if (table.has_card("INSTRUME")) {
647 m_instrument = table.string("INSTRUME");
648 }
649 else {
650 m_instrument = "unknown";
651 }
652
653 // Set energy boundaries
654 set_ebounds();
655
656 // Return
657 return;
658}
659
660
661/***********************************************************************//**
662 * @brief Convert value into energy
663 *
664 * @param[in] energy Energy value.
665 * @param[in] unit Unit of value.
666 *
667 * Converts an energy value into a GEnergy object based on the specified
668 * units. The following units are supported (case insensitive):
669 * erg, keV, MeV, GeV, and TeV.
670 ***************************************************************************/
671GEnergy GMWLSpectrum::conv_energy(const double& energy, const std::string& unit)
672{
673 // Convert energy
674 GEnergy result(energy, unit);
675
676 // Return energy
677 return result;
678}
679
680
681/***********************************************************************//**
682 * @brief Convert value into flux
683 *
684 * @param[in] energy Energy at which flux is given.
685 * @param[in] flux Flux value.
686 * @param[in] unit Unit of value.
687 *
688 * @exception GException::invalid_argument
689 * Invalid @p unit encountered.
690 *
691 * Converts a flux value into units of ph/cm2/s/MeV based on the specified
692 * units. The following units are supported (case insensitive):
693 * ph/cm2/s/MeV, ph/s/cm2/MeV, erg/cm2/s and erg/s/cm2.
694 ***************************************************************************/
695double GMWLSpectrum::conv_flux(const GEnergy& energy, const double& flux,
696 const std::string& unit)
697{
698 // Initialise energy
699 double result;
700
701 // Convert unit string to upper base without any leading/trailing
702 // whitespace
703 std::string str_unit = gammalib::strip_whitespace(gammalib::toupper(unit));
704
705 // High-energy units
706 if (str_unit == "PH/CM2/S/MEV" || str_unit == "PH/S/CM2/MEV") {
707 result = flux;
708 }
709 else if (str_unit == "ERG/CM2/S" || str_unit == "ERG/S/CM2") {
710 result = (gammalib::erg2MeV*flux) / (energy.MeV()*energy.MeV());
711 }
712
713 // ... otherwise throw exception
714 else {
715 std::string msg = "Unit \""+unit+"\" not recognised. Please specify "
716 "one of \"PH/CM2/S/MEV\", \"PH/S/CM2/MEV\", "
717 "\"ERG/CM2/S\" or \"ERG/S/CM2\".";
719 }
720
721 // Return energy
722 return result;
723}
#define G_READ
#define G_OPERATOR
Definition GArf.cpp:44
Energy value class definition.
Exception handler interface definition.
Filename class interface definition.
FITS table abstract base class interface definition.
FITS file class interface definition.
#define G_CONV_FLUX
Multi-wavelength spectrum class interface definition.
#define G_READ_FITS
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ EXPLICIT
Definition GTypemaps.hpp:37
@ SILENT
Definition GTypemaps.hpp:34
void append(const GEnergy &emin, const GEnergy &emax)
Append energy interval.
Definition GEbounds.cpp:301
int size(void) const
Return number of energy boundaries.
Definition GEbounds.hpp:163
void clear(void)
Clear energy boundaries.
Definition GEbounds.cpp:268
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:321
Abstract event bin container class.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
virtual GEventCube & operator=(const GEventCube &cube)
Assignment operator.
void free_members(void)
Delete class members.
Definition GEvents.cpp:206
GGti m_gti
Good time intervals covered by events.
Definition GEvents.hpp:112
const GTime & tstart(void) const
Return start time.
Definition GEvents.hpp:146
GEbounds m_ebounds
Energy boundaries covered by events.
Definition GEvents.hpp:111
void init_members(void)
Initialise class members.
Definition GEvents.cpp:176
const GTime & tstop(void) const
Return stop time.
Definition GEvents.hpp:158
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 has_extname(void) const
Signal if filename has an extension name.
bool has_extno(void) const
Signal if filename has an extension number.
std::string url(void) const
Return Uniform Resource Locator (URL)
std::string extname(const std::string &defaultname="") const
Return extension name.
int extno(const int &defaultno=-1) const
Return extension number.
virtual HDUType exttype(void) const =0
bool has_card(const int &cardno) const
Check existence of header card.
Definition GFitsHDU.hpp:233
const std::string & extname(void) const
Return extension name.
Definition GFitsHDU.hpp:162
@ HT_BIN_TABLE
Definition GFitsHDU.hpp:69
@ HT_ASCII_TABLE
Definition GFitsHDU.hpp:68
std::string string(const std::string &keyname) const
Return card value as string.
Definition GFitsHDU.hpp:410
Abstract interface for FITS table column.
virtual double real(const int &row, const int &inx=0) const =0
void unit(const std::string &unit)
Set column unit.
Abstract interface for FITS table.
const int & nrows(void) const
Return number of rows in table.
const int & ncols(void) const
Return number of columns in table.
FITS file class.
Definition GFits.hpp:63
int size(void) const
Return number of HDUs in FITS file.
Definition GFits.hpp:237
void close(void)
Close FITS file.
Definition GFits.cpp:1342
GFitsHDU * at(const int &extno)
Get pointer to HDU.
Definition GFits.cpp:233
const GFilename & filename(void) const
Return FITS filename.
Definition GFits.hpp:313
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
int size(void) const
Return number of Good Time Intervals.
Definition GGti.hpp:154
Multi-wavelength spectral point class.
Definition GMWLDatum.hpp:45
double m_flux_err
Uncertainty in flux (ph/cm2/s/MeV)
Definition GMWLDatum.hpp:95
GEnergy m_eng
Energy of spectral point.
Definition GMWLDatum.hpp:92
double m_flux
Flux of spectral point (ph/cm2/s/MeV)
Definition GMWLDatum.hpp:94
GEnergy m_eng_err
Uncertainty in energy.
Definition GMWLDatum.hpp:93
Multi-wavelength spectrum class interface.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print spectrum.
virtual void load(const GFilename &filename)
Load spectrum.
void free_members(void)
Delete class members.
virtual void read(const GFits &file)
Read spectrum from FITS file.
GEnergy conv_energy(const double &energy, const std::string &unit)
Convert value into energy.
std::string m_telescope
Telescope name.
virtual void save(const GFilename &filename, const bool &clobber=false) const
Save spectrum.
virtual GMWLSpectrum & operator=(const GMWLSpectrum &spec)
Assignment operator.
virtual void clear(void)
Clear spectrum.
virtual GMWLDatum * operator[](const int &index)
Spectral point access operator.
double conv_flux(const GEnergy &energy, const double &flux, const std::string &unit)
Convert value into flux.
void init_members(void)
Initialise class members.
void copy_members(const GMWLSpectrum &spec)
Copy class members.
virtual ~GMWLSpectrum(void)
Destructor.
virtual GMWLSpectrum * clone(void) const
Clone spectrum.
std::string m_instrument
Instrument name.
GMWLSpectrum(void)
Void constructor.
virtual void write(GFits &file) const
Write spectrum into FITS file.
virtual int size(void) const
Return number of spectral bins.
void set_ebounds(void)
Set energy boundaries.
virtual int number(void) const
Return number of points in spectrum.
void read_fits(const GFitsTable &table)
Read spectrum from FITS file.
std::vector< GMWLDatum > m_data
Spectral data.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
const double erg2MeV
Definition GTools.hpp:46
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:80
std::string toupper(const std::string &s)
Convert string to upper case.
Definition GTools.cpp:941