GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GRmf.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GRmf.cpp - XSPEC Redistribution Matrix File class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2013-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 GRmf.cpp
23  * @brief XSPEC Redistribution Matrix File 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 "GMath.hpp"
33 #include "GRmf.hpp"
34 #include "GException.hpp"
35 #include "GFits.hpp"
36 #include "GFitsTable.hpp"
37 #include "GFitsBinTable.hpp"
38 #include "GFitsTableShortCol.hpp"
39 #include "GFitsTableFloatCol.hpp"
40 
41 /* __ Method name definitions ____________________________________________ */
42 #define G_OPERATOR_PLUS "GRmf::operator+=(GRmf&)"
43 #define G_OPERATOR_MINUS "GRmf::operator-=(GRmf&)"
44 #define G_AT "GRmf::at(int&, int&)"
45 
46 /* __ Macros _____________________________________________________________ */
47 
48 /* __ Coding definitions _________________________________________________ */
49 
50 /* __ Debug definitions __________________________________________________ */
51 
52 
53 /*==========================================================================
54  = =
55  = Constructors/destructors =
56  = =
57  ==========================================================================*/
58 
59 /***********************************************************************//**
60  * @brief Void constructor
61  ***************************************************************************/
63 {
64  // Initialise members
65  init_members();
66 
67  // Return
68  return;
69 }
70 
71 
72 /***********************************************************************//**
73  * @brief File constructor
74  *
75  * @param[in] filename File name.
76  ***************************************************************************/
77 GRmf::GRmf(const GFilename& filename)
78 {
79  // Initialise members
80  init_members();
81 
82  // Load RMF file
83  load(filename);
84 
85  // Return
86  return;
87 }
88 
89 
90 /***********************************************************************//**
91  * @brief Energy boundary constructor
92  *
93  * @param[in] etrue True energy boundaries.
94  * @param[in] emeasured Measured energy boundaries.
95  ***************************************************************************/
96 GRmf::GRmf(const GEbounds& etrue, const GEbounds& emeasured)
97 {
98  // Initialise members
99  init_members();
100 
101  // Set energy boundaries
102  m_ebds_true = etrue;
104 
105  // Initialize matrix
107 
108  // Return
109  return;
110 }
111 
112 
113 /***********************************************************************//**
114  * @brief Copy constructor
115  *
116  * @param[in] rmf Redistribution Matrix File.
117  ***************************************************************************/
118 GRmf::GRmf(const GRmf& rmf)
119 {
120  // Initialise members
121  init_members();
122 
123  // Copy members
124  copy_members(rmf);
125 
126  // Return
127  return;
128 }
129 
130 
131 /***********************************************************************//**
132  * @brief Destructor
133  ***************************************************************************/
135 {
136  // Free members
137  free_members();
138 
139  // Return
140  return;
141 }
142 
143 
144 /*==========================================================================
145  = =
146  = Operators =
147  = =
148  ==========================================================================*/
149 
150 /***********************************************************************//**
151  * @brief Assignment operator
152  *
153  * @param[in] rmf Redistribution Matrix File.
154  * @return Redistribution Matrix File.
155  ***************************************************************************/
157 {
158  // Execute only if object is not identical
159  if (this != &rmf) {
160 
161  // Free members
162  free_members();
163 
164  // Initialise members
165  init_members();
166 
167  // Copy members
168  copy_members(rmf);
169 
170  } // endif: object was not identical
171 
172  // Return
173  return *this;
174 }
175 
176 
177 /***********************************************************************//**
178  * @brief Add Redistribution Matrix File
179  *
180  * @param[in] rmf Redistribution Matrix File.
181  * @return Sum of Redistribution Matrix File.
182  *
183  * @exception GException::invalid_value
184  * Incompatible Redistribution Matrix Files.
185  *
186  * Adds the RMF values of an Redistribution Matrix File to the current
187  * values.
188  *
189  * The operator only works if the provide Redistribution Matrix File has the
190  * same energy binning than the current Redistribution Matrix File.
191  ***************************************************************************/
193 {
194  // Throw an exception if the RMF are not compatible
195  if (this->etrue() != rmf.etrue()) {
196  std::string msg = "Incompatible true energy binning of "
197  "Redistribution Matrix File.";
199  }
200  if (this->emeasured() != rmf.emeasured()) {
201  std::string msg = "Incompatible measured energy binning of "
202  "Redistribution Matrix File.";
204  }
205 
206  // Add RMF values
207  for (int itrue = 0; itrue < ntrue(); ++itrue) {
208  for (int imeasured = 0; imeasured < nmeasured(); ++imeasured) {
209  m_matrix(itrue, imeasured) += rmf.m_matrix(itrue, imeasured);
210  }
211  }
212 
213  // Return
214  return *this;
215 }
216 
217 
218 /***********************************************************************//**
219  * @brief Subtract Redistribution Matrix File
220  *
221  * @param[in] rmf Redistribution Matrix File.
222  * @return Difference of Redistribution Matrix File.
223  *
224  * @exception GException::invalid_value
225  * Incompatible Redistribution Matrix Files.
226  *
227  * Subtracts the RMF values of an Redistribution Matrix File from the current
228  * values.
229  *
230  * The operator only works if the provide Redistribution Matrix File has the
231  * same energy binning than the current Redistribution Matrix File.
232  ***************************************************************************/
234 {
235  // Throw an exception if the RMF are not compatible
236  if (this->etrue() != rmf.etrue()) {
237  std::string msg = "Incompatible true energy binning of "
238  "Redistribution Matrix File.";
240  }
241  if (this->emeasured() != rmf.emeasured()) {
242  std::string msg = "Incompatible measured energy binning of "
243  "Redistribution Matrix File.";
245  }
246 
247  // Subtract RMF values
248  for (int itrue = 0; itrue < ntrue(); ++itrue) {
249  for (int imeasured = 0; imeasured < nmeasured(); ++imeasured) {
250  m_matrix(itrue, imeasured) -= rmf.m_matrix(itrue, imeasured);
251  }
252  }
253 
254  // Return
255  return *this;
256 }
257 
258 
259 /***********************************************************************//**
260  * @brief Scale Redistribution Matrix File values
261  *
262  * @param[in] scale Scale factor.
263  * @return Scaled Redistribution Matrix File.
264  *
265  * Multiplies the values of the Redistribution Matrix File with a scale
266  * factor.
267  ***************************************************************************/
268 GRmf& GRmf::operator*=(const double& scale)
269 {
270  // Scale RMF values
271  for (int itrue = 0; itrue < ntrue(); ++itrue) {
272  for (int imeasured = 0; imeasured < nmeasured(); ++imeasured) {
273  m_matrix(itrue, imeasured) *= scale;
274  }
275  }
276 
277  // Return
278  return *this;
279 }
280 
281 
282 /***********************************************************************//**
283  * @brief Divide Redistribution Matrix File values
284  *
285  * @param[in] scale Division factor.
286  * @return Divided Redistribution Matrix File.
287  *
288  * Divides the values of the Redistribution Matrix File by a division factor.
289  ***************************************************************************/
290 GRmf& GRmf::operator/=(const double& scale)
291 {
292  // Divide RMF values
293  for (int itrue = 0; itrue < ntrue(); ++itrue) {
294  for (int imeasured = 0; imeasured < nmeasured(); ++imeasured) {
295  m_matrix(itrue, imeasured) /= scale;
296  }
297  }
298 
299  // Return
300  return *this;
301 }
302 
303 
304 /*==========================================================================
305  = =
306  = Public methods =
307  = =
308  ==========================================================================*/
309 
310 /***********************************************************************//**
311  * @brief Clear object.
312  *
313  * Reset object to a clean initial state.
314  ***************************************************************************/
315 void GRmf::clear(void)
316 {
317  // Free memory and initialise members
318  free_members();
319  init_members();
320 
321  // Return
322  return;
323 }
324 
325 
326 /***********************************************************************//**
327  * @brief Clone object
328  *
329  * @return Redistribution Matrix File.
330  ***************************************************************************/
331 GRmf* GRmf::clone(void) const
332 {
333  // Clone object
334  return new GRmf(*this);
335 }
336 
337 
338 /***********************************************************************//**
339  * @brief Return content of redistribution matrix bin
340  *
341  * @param[in] itrue True energy index [0,...,ntrue()[.
342  * @param[in] imeasured Measured energy index [0,...,nmeasured()[.
343  *
344  * @exception GException::out_of_range
345  * True or measured energy index is out of range.
346  *
347  * Returns reference to content of redistribution matrix bin bin with true
348  * energy index @p itrue and measured energy index @p imeasured.
349  ***************************************************************************/
350 double& GRmf::at(const int& itrue, const int& imeasured)
351 {
352  // Throw exception if indices are out of range
353  if (itrue < 0 || itrue >= ntrue()) {
354  throw GException::out_of_range(G_AT, "True energy index",
355  itrue, ntrue());
356  }
357  // Throw exception if indices are out of range
358  if (imeasured < 0 || imeasured >= nmeasured()) {
359  throw GException::out_of_range(G_AT, "Measured energy index",
360  imeasured, nmeasured());
361  }
362 
363  // Return reference
364  return (m_matrix(itrue, imeasured));
365 }
366 
367 
368 /***********************************************************************//**
369  * @brief Return content of redistribution matrix bin (const version)
370  *
371  * @param[in] itrue True energy index [0,...,ntrue()[.
372  * @param[in] imeasured Measured energy index [0,...,nmeasured()[.
373  *
374  * @exception GException::out_of_range
375  * True or measured energy index is out of range.
376  *
377  * Returns reference to content of redistribution matrix bin bin with true
378  * energy index @p itrue and measured energy index @p imeasured.
379  ***************************************************************************/
380 const double& GRmf::at(const int& itrue, const int& imeasured) const
381 {
382  // Throw exception if indices are out of range
383  if (itrue < 0 || itrue >= ntrue()) {
384  throw GException::out_of_range(G_AT, "True energy index",
385  itrue, ntrue());
386  }
387  // Throw exception if indices are out of range
388  if (imeasured < 0 || imeasured >= nmeasured()) {
389  throw GException::out_of_range(G_AT, "Measured energy index",
390  imeasured, nmeasured());
391  }
392 
393  // Return reference
394  return (m_matrix(itrue, imeasured));
395 }
396 
397 
398 /***********************************************************************//**
399  * @brief Return true energy boundaries for specified measured energy
400  *
401  * @param[in] emeasured Measured energy.
402  * @return True energy boundaries for specified measured energy.
403  *
404  * Returns the true energy boundaries for the specified measured energy
405  * @p emeasured. If the RMF is not covering the specified measured energy,
406  * an empty energy boundary object is returned.
407  ***************************************************************************/
408 GEbounds GRmf::etrue(const GEnergy& emeasured) const
409 {
410  // Initialise empty energy boundaries
411  GEbounds ebounds;
412 
413  // Determine matrix column that corresponds to specified measured energy
414  int column = m_ebds_measured.index(emeasured);
415 
416  // If matrix column was found then determine the boundaries for this
417  // column
418  if (column != -1) {
419 
420  // Determine first and last non-zero indices
421  int row_start = -1;
422  int row_stop = -1;
423  for (int row = 0; row < m_matrix.rows(); ++row) {
424  if (m_matrix(row, column) > 0.0) {
425  row_start = row;
426  break;
427  }
428  }
429  for (int row = m_matrix.rows()-1; row >= 0; --row) {
430  if (m_matrix(row, column) > 0.0) {
431  row_stop = row;
432  break;
433  }
434  }
435 
436  // Set energy boundaries if valid indices have been found
437  if (row_start != -1 && row_stop != -1) {
438  ebounds = GEbounds(m_ebds_true.emin(row_start),
439  m_ebds_true.emax(row_stop));
440  }
441 
442  } // endif: row containing true energy was found
443 
444  // Return energy boundaries
445  return ebounds;
446 }
447 //m_matrix(itrue, imeasured) (row, column)
448 
449 
450 /***********************************************************************//**
451  * @brief Return measured energy boundaries for specified true energy
452  *
453  * @param[in] etrue True energy.
454  * @return Measured energy boundaries for specified true energy.
455  *
456  * Returns the measured energy boundaries for the specified true energy
457  * @p etrue. If the RMF is not covering the specified true energy,
458  * an empty energy boundary object is returned.
459  ***************************************************************************/
460 GEbounds GRmf::emeasured(const GEnergy& etrue) const
461 {
462  // Initialise empty energy boundaries
463  GEbounds ebounds;
464 
465  // Determine matrix row that corresponds to specified true energy
466  int row = m_ebds_true.index(etrue);
467 
468  // If matrix row was found then determine the boundaries for this
469  // row
470  if (row != -1) {
471 
472  // Determine first and last non-zero indices
473  int column_start = -1;
474  int column_stop = -1;
475  for (int column = 0; column < m_matrix.columns(); ++column) {
476  if (m_matrix(row, column) > 0.0) {
477  column_start = column;
478  break;
479  }
480  }
481  for (int column = m_matrix.columns()-1; column >= 0; --column) {
482  if (m_matrix(row, column) > 0.0) {
483  column_stop = column;
484  break;
485  }
486  }
487 
488  // Set energy boundaries if valid indices have been found
489  if (column_start != -1 && column_stop != -1) {
490  ebounds = GEbounds(m_ebds_measured.emin(column_start),
491  m_ebds_measured.emax(column_stop));
492  }
493 
494  } // endif: row containing true energy was found
495 
496  // Return energy boundaries
497  return ebounds;
498 }
499 
500 
501 /***********************************************************************//**
502  * @brief Load Redistribution Matrix File
503  *
504  * @param[in] filename File name.
505  *
506  * Loads the Redistribution Matrix File from the `MATRIX` extension of the
507  * FITS file and the reconstructed energy boundaries from the `EBOUNDS`
508  * extension.
509  ***************************************************************************/
510 void GRmf::load(const GFilename& filename)
511 {
512  // Clear matrix
513  clear();
514 
515  // Open FITS file (without extension name as the user is not allowed
516  // to modify the extension names)
517  GFits fits(filename.url());
518 
519  // Read data
520  read(fits);
521 
522  // Close FITS file
523  fits.close();
524 
525  // Store filename
526  m_filename = filename.url();
527 
528  // Return
529  return;
530 }
531 
532 
533 /***********************************************************************//**
534  * @brief Save Redistribution Matrix File
535  *
536  * @param[in] filename File name.
537  * @param[in] clobber Overwrite existing file?
538  * @param[in] unit Energy unit.
539  *
540  * Saves the Redistribution Matrix File into a FITS file. If a file with the
541  * given @p filename does not yet exist it will be created. If the file
542  * exists it can be overwritten if the @p clobber flag is set to `true`.
543  * Otherwise an exception is thrown.
544  *
545  * The method will save two binary FITS tables into the FITS file: a
546  * `MATRIX` extension that contains the Redistribution Matrix File elements,
547  * and an `EBOUNDS` extension that contains the measured energy boundaries
548  * for all matrix. The @p unit argument specifies the unit of the true
549  * energies that will be saved in the `MATRIX` extension.
550  ***************************************************************************/
551 void GRmf::save(const GFilename& filename,
552  const bool& clobber,
553  const std::string& unit) const
554 {
555  // Create FITS file
556  GFits fits;
557 
558  // Write RMF into file
559  write(fits, unit);
560 
561  // Save to file (without extension name since the requested extension
562  // may not yet exist in the file)
563  fits.saveto(filename.url(), clobber);
564 
565  // Store filename
566  m_filename = filename.url();
567 
568  // Return
569  return;
570 }
571 
572 
573 /***********************************************************************//**
574  * @brief Read Redistribution Matrix File
575  *
576  * @param[in] fits File file.
577  *
578  * Reads the Redistribution Matrix File from the `MATRIX` extension of the
579  * FITS file and the reconstructed energy boundaries from the `EBOUNDS`
580  * extension.
581  ***************************************************************************/
582 void GRmf::read(const GFits& fits)
583 {
584  // Clear spectrum
585  clear();
586 
587  // Get energy boundary table
588  const GFitsTable& ebounds = *fits.table(gammalib::extname_ebounds);
589 
590  // Read measured energy boundaries
591  m_ebds_measured.read(ebounds);
592 
593  // Get RMF table
594  const GFitsTable& rmf = *fits.table(gammalib::extname_rmf);
595 
596  // Read RMF data
597  read(rmf);
598 
599  // Return
600  return;
601 }
602 
603 
604 /***********************************************************************//**
605  * @brief Read Redistribution Matrix File
606  *
607  * @param[in] table RMF FITS table.
608  *
609  * Reads the Redistribution Matrix File from a FITS table. The true energy
610  * bins are expected in the `ENERG_LO` and `ENERG_HI` columns. Information
611  * for matrix compression are stored in the `N_GRP`, `F_CHAN` and `N_CHAN`
612  * columns, and the matrix elements are stored in the `MATRIX` column.
613  *
614  * The method automatically decompresses the Redistribution Matrix File and
615  * stores the matrix elements in a spare matrix.
616  *
617  * See
618  * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3
619  * for details about the Redistribution Matrix File file format.
620  ***************************************************************************/
621 void GRmf::read(const GFitsTable& table)
622 {
623  // Initialise members
624  m_ebds_true.clear();
625 
626  // Get pointer to data columns
627  const GFitsTableCol* energy_lo = table["ENERG_LO"];
628  const GFitsTableCol* energy_hi = table["ENERG_HI"];
629  const GFitsTableCol* n_grp = table["N_GRP"];
630  const GFitsTableCol* f_chan = table["F_CHAN"];
631  const GFitsTableCol* n_chan = table["N_CHAN"];
632  const GFitsTableCol* matrix = table["MATRIX"];
633 
634  // Set matrix rows and columns
635  int rows = energy_lo->nrows();
636  int columns = m_ebds_measured.size();
637 
638  // Initialize matrix
639  m_matrix = GMatrixSparse(rows, columns);
640 
641  // Initialize matrix maximum
642  double max = 0.0;
643 
644  // Set true energy bins
645  for (int itrue = 0; itrue < rows; ++itrue) {
646 
647  // Append energy bin
648  GEnergy emin(energy_lo->real(itrue), energy_lo->unit());
649  GEnergy emax(energy_hi->real(itrue), energy_hi->unit());
650  m_ebds_true.append(emin, emax);
651 
652  // Loop over groups
653  int icolumn = 0;
654  int ngroups = n_grp->integer(itrue);
655  for (int igroup = 0; igroup < ngroups; ++igroup) {
656 
657  // Get start column index and number of columns
658  int imeasured = f_chan->integer(itrue, igroup);
659  int nvalues = n_chan->integer(itrue, igroup);
660 
661  // Get values
662  for (int i = 0; i < nvalues; ++i, ++imeasured, ++icolumn) {
663 
664  // Set matrix value
665  m_matrix(itrue, imeasured) = matrix->real(itrue, icolumn);
666 
667  // Update fmax
668  if (max < m_matrix(itrue, imeasured)) {
669  max = m_matrix(itrue, imeasured);
670  m_itruemax = itrue;
671  m_imeasmax = imeasured;
672  }
673 
674  } // endfor: looped over measured energy bins
675 
676  } // endfor: looped over groups
677 
678  } // endfor: looped over true energy bins
679 
680  // Store FITS header
681  m_header = table.header();
682 
683  // Return
684  return;
685 }
686 
687 
688 /***********************************************************************//**
689  * @brief Write Redistribution Matrix File
690  *
691  * @param[in] fits FITS file.
692  * @param[in] unit Energy unit.
693  *
694  * Writes the Redistribution Matrix File into `MATRIX` and `EBOUNDS`
695  * extensions of the FITS file. Extensions with these names will be removed
696  * from the FITS file before writing.
697  *
698  * The true energy bins are written into the `ENERG_LO` and `ENERG_HI`
699  * columns. The units of the energies in these columns is specified by the
700  * @p unit argument. Information for matrix compression are stored in the
701  * `N_GRP`, `F_CHAN` and `N_CHAN` columns, and the matrix elements are
702  * written into the `MATRIX` column.
703  *
704  * The measured energy bins are written into the `EBOUNDS` extension.
705  *
706  * See
707  * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3
708  * for details about the Redistribution Matrix File file format.
709  ***************************************************************************/
710 void GRmf::write(GFits& fits, const std::string& unit) const
711 {
712  // Remove extensions if they exist already
713  if (fits.contains(gammalib::extname_rmf)) {
715  }
718  }
719 
720  // Set table length
721  int length = ntrue();
722 
723  // Continue only if there are true energies
724  if (length > 0) {
725 
726  // Compute maximum number of matrix elements
727  int maxcolumns = 1;
728  for (int i = 0; i < length; i++) {
729 
730  // Search first non-zero element
731  int ifirst = 0;
732  for (; ifirst < nmeasured(); ++ifirst) {
733  if (m_matrix(i, ifirst) != 0.0) {
734  break;
735  }
736  }
737 
738  // Search last non-zero element
739  int ilast = nmeasured() - 1;
740  for (; ilast >= 0; --ilast) {
741  if (m_matrix(i, ilast) != 0.0) {
742  break;
743  }
744  }
745 
746  // Compute number of non-zero matrix elements
747  int num = ilast - ifirst + 1;
748 
749  // Set maximum
750  if (num > maxcolumns) {
751  maxcolumns = num;
752  }
753 
754  } // endfor: looped over true energies
755 
756  // Create new binary table
757  GFitsBinTable hdu;
758 
759  // Allocate columns
760  GFitsTableFloatCol energy_lo("ENERG_LO", length);
761  GFitsTableFloatCol energy_hi("ENERG_HI", length);
762  GFitsTableShortCol n_grp("N_GRP", length);
763  GFitsTableShortCol f_chan("F_CHAN", length);
764  GFitsTableShortCol n_chan("N_CHAN", length);
765  GFitsTableFloatCol matrix("MATRIX", length, maxcolumns);
766 
767  // Fill columns
768  for (int itrue = 0; itrue < length; ++itrue) {
769 
770  // Search first non-zero element
771  int ifirst = 0;
772  for (; ifirst < nmeasured(); ++ifirst) {
773  if (m_matrix(itrue, ifirst) != 0.0) {
774  break;
775  }
776  }
777 
778  // Search last non-zero element
779  int ilast = nmeasured() - 1;
780  for (; ilast >= 0; --ilast) {
781  if (m_matrix(itrue, ilast) != 0.0) {
782  break;
783  }
784  }
785 
786  // Compute number of non-zero matrix elements
787  int num = ilast - ifirst + 1;
788  if (num < 0) {
789  ifirst = 0;
790  num = 0;
791  }
792 
793  // Set energy bin
794  energy_lo(itrue) = m_ebds_true.emin(itrue)(unit);
795  energy_hi(itrue) = m_ebds_true.emax(itrue)(unit);
796 
797  // Set group information
798  n_grp(itrue) = 1;
799  f_chan(itrue) = ifirst;
800  n_chan(itrue) = num;
801 
802  // Set matrix elements
803  for (int i = 0; i < num; ++i, ++ifirst) {
804  matrix(itrue, i) = m_matrix(itrue, ifirst);
805  }
806 
807  } // endfor: looped over true energy bins
808 
809  // Set column units
810  energy_lo.unit(unit);
811  energy_hi.unit(unit);
812 
813  // Set table attributes
815 
816  // Append columns to table
817  hdu.append(energy_lo);
818  hdu.append(energy_hi);
819  hdu.append(n_grp);
820  hdu.append(f_chan);
821  hdu.append(n_chan);
822  hdu.append(matrix);
823 
824  // Write mandatory header keywords for RMF matrix
825  hdu.card("TELESCOP", "unknown", "Telescope");
826  hdu.card("INSTRUME", "unknown", "Instrument");
827  hdu.card("FILTER", "none", "Filter");
828  hdu.card("CHANTYPE", "PI", "Channel type");
829  hdu.card("DETCHANS", nmeasured(), "Total number of possible channels");
830  hdu.card("HDUCLASS", "OGIP", "Format conforms to OGIP standard");
831  hdu.card("HDUCLAS1", "RESPONSE", "Extension contains response data");
832  hdu.card("HDUCLAS2", "RSP_MATRIX", "Extension contains a RMF");
833  hdu.card("HDUVERS", "1.3.0", "Version of the file format");
834  hdu.card("TLMIN4", 0, "Minimum value allowed in column 4");
835 
836  // Write additional header keywords (do not overwrite any existing
837  // keywords, except of "TELESCOP", "INSTRUME" and "FILTER")
838  for (int i = 0; i < m_header.size(); ++i) {
839  if ((!hdu.contains(m_header[i].keyname())) ||
840  (m_header[i].keyname() == "TELESCOP") ||
841  (m_header[i].keyname() == "INSTRUME") ||
842  (m_header[i].keyname() == "FILTER")) {
843  hdu.card(m_header[i]);
844  }
845  }
846 
847  // Append HDU to FITS file
848  fits.append(hdu);
849 
850  // Append measured energy boundaries
851  m_ebds_measured.write(fits);
852 
853  } // endif: there were data to write
854 
855  // Return
856  return;
857 }
858 
859 
860 /***********************************************************************//**
861  * @brief Print Redistribution Matrix File
862  *
863  * @param[in] chatter Chattiness.
864  * @return String containing Redistribution Matrix File information.
865  ***************************************************************************/
866 std::string GRmf::print(const GChatter& chatter) const
867 {
868  // Initialise result string
869  std::string result;
870 
871  // Continue only if chatter is not silent
872  if (chatter != SILENT) {
873 
874  // Append header
875  result.append("=== GRmf ===");
876 
877  // Append energy boundary information
878  result.append("\n"+gammalib::parformat("Number of true energy bins"));
879  result.append(gammalib::str(m_ebds_true.size()));
880  result.append("\n"+gammalib::parformat("Number of measured bins"));
881  result.append(gammalib::str(m_ebds_measured.size()));
882  result.append("\n"+gammalib::parformat("True energy range"));
883  result.append(m_ebds_true.emin().print());
884  result.append(" - ");
885  result.append(m_ebds_true.emax().print());
886  result.append("\n"+gammalib::parformat("Measured energy range"));
887  result.append(m_ebds_measured.emin().print());
888  result.append(" - ");
889  result.append(m_ebds_measured.emax().print());
890 
891  } // endif: chatter was not silent
892 
893  // Return result
894  return result;
895 }
896 
897 
898 /*==========================================================================
899  = =
900  = Private methods =
901  = =
902  ==========================================================================*/
903 
904 /***********************************************************************//**
905  * @brief Initialise class members
906  ***************************************************************************/
908 {
909  // Initialise members
910  m_filename.clear();
911  m_ebds_true.clear();
913  m_matrix.clear();
914  m_itruemax = 0;
915  m_imeasmax = 0;
916  m_header.clear();
917 
918  // Return
919  return;
920 }
921 
922 
923 /***********************************************************************//**
924  * @brief Copy class members
925  *
926  * @param[in] rmf Redistribution Matrix File.
927  ***************************************************************************/
928 void GRmf::copy_members(const GRmf& rmf)
929 {
930  // Copy members
931  m_filename = rmf.m_filename;
932  m_ebds_true = rmf.m_ebds_true;
934  m_matrix = rmf.m_matrix;
935  m_itruemax = rmf.m_itruemax;
936  m_imeasmax = rmf.m_imeasmax;
937  m_header = rmf.m_header;
938 
939  // Return
940  return;
941 }
942 
943 
944 /***********************************************************************//**
945  * @brief Delete class members
946  ***************************************************************************/
948 {
949  // Return
950  return;
951 }
std::string print(const GChatter &chatter=NORMAL) const
Print Redistribution Matrix File.
Definition: GRmf.cpp:866
int m_imeasmax
Index of measured maximum.
Definition: GRmf.hpp:121
void unit(const std::string &unit)
Set column unit.
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:482
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition: GFits.hpp:282
GRmf(void)
Void constructor.
Definition: GRmf.cpp:62
void free_members(void)
Delete class members.
Definition: GRmf.cpp:947
Sparse matrix class interface definition.
int size(void) const
Return number of energy boundaries.
Definition: GEbounds.hpp:163
void append(const GEnergy &emin, const GEnergy &emax)
Append energy interval.
Definition: GEbounds.cpp:301
bool contains(const std::string &colname) const
Checks the presence of a column in table.
Definition: GFitsTable.cpp:759
void nrows(const int &nrows)
Set number of rows in column.
#define G_AT
Definition: GRmf.cpp:44
Redistribution Matrix File class.
Definition: GRmf.hpp:55
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
Definition: GFitsTable.hpp:147
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition: GEbounds.cpp:761
int nmeasured(void) const
Return number of measured energy bins in redistribution matrix.
Definition: GRmf.hpp:207
Gammalib tools definition.
double & at(const int &itrue, const int &imeasured)
Return content of redistribution matrix bin.
Definition: GRmf.cpp:350
GFilename m_filename
Filename of origin.
Definition: GRmf.hpp:117
FITS table float column class interface definition.
FITS file class.
Definition: GFits.hpp:63
const GFitsHeader & header(void) const
Return extension header.
Definition: GFitsHDU.hpp:205
FITS file class interface definition.
GRmf & operator=(const GRmf &rmf)
Assignment operator.
Definition: GRmf.cpp:156
virtual void clear(void)
Clear matrix.
void copy_members(const GRmf &rmf)
Copy class members.
Definition: GRmf.cpp:928
void write(GFits &file, const std::string &extname=gammalib::extname_ebounds, const std::string &unit="keV") const
Write energy boundaries into FITS object.
Definition: GEbounds.cpp:816
void init_members(void)
Initialise class members.
Definition: GRmf.cpp:907
int index(const GEnergy &eng) const
Returns energy bin index for a given energy.
Definition: GEbounds.cpp:948
GRmf & operator+=(const GRmf &rmf)
Add Redistribution Matrix File.
Definition: GRmf.cpp:192
const GEbounds & emeasured(void) const
Return measured energy boundaries.
Definition: GRmf.hpp:265
#define G_OPERATOR_PLUS
Definition: GRmf.cpp:42
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition: GFits.cpp:1293
int m_itruemax
Index of true maximum.
Definition: GRmf.hpp:122
GRmf & operator-=(const GRmf &rmf)
Subtract Redistribution Matrix File.
Definition: GRmf.cpp:233
XSPEC Redistribution Matrix File class definition.
Energy boundaries container class.
Definition: GEbounds.hpp:60
void remove(const int &extno)
Remove HDU from FITS file.
Definition: GFits.cpp:862
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition: GEnergy.cpp:748
GRmf * clone(void) const
Clone object.
Definition: GRmf.cpp:331
Filename class.
Definition: GFilename.hpp:62
const int & rows(void) const
Return number of matrix rows.
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition: GEbounds.hpp:187
Abstract interface for FITS table column.
#define G_OPERATOR_MINUS
Definition: GRmf.cpp:43
GMatrixSparse m_matrix
Sparse redistribution matrix.
Definition: GRmf.hpp:120
const std::string extname_ebounds
Definition: GEbounds.hpp:44
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
GEbounds m_ebds_measured
Measured energy boundaries.
Definition: GRmf.hpp:119
int ntrue(void) const
Return number of true energy bins in redistribution matrix.
Definition: GRmf.hpp:193
int size(void) const
Return number of cards in header.
GChatter
Definition: GTypemaps.hpp:33
void clear(void)
Clear object.
Definition: GRmf.cpp:315
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
void clear(void)
Clear energy boundaries.
Definition: GEbounds.cpp:268
void save(const GFilename &filename, const bool &clobber=false, const std::string &unit="keV") const
Save Redistribution Matrix File.
Definition: GRmf.cpp:551
double max(const GVector &vector)
Computes maximum vector element.
Definition: GVector.cpp:915
GFitsHeader m_header
FITS header cards.
Definition: GRmf.hpp:123
GRmf & operator/=(const double &scale)
Divide Redistribution Matrix File values.
Definition: GRmf.cpp:290
GRmf & operator*=(const double &scale)
Scale Redistribution Matrix File values.
Definition: GRmf.cpp:268
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
virtual int integer(const int &row, const int &inx=0) const =0
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
virtual double real(const int &row, const int &inx=0) const =0
FITS binary table class.
Exception handler interface definition.
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition: GFits.cpp:678
FITS binary table class definition.
FITS table short integer column class interface definition.
FITS table float column.
void read(const GFits &fits)
Read Redistribution Matrix File.
Definition: GRmf.cpp:582
FITS table short integer column.
const GEnergy & emax(void) const
Return maximum energy of all intervals.
Definition: GEbounds.hpp:199
void clear(void)
Clear header.
const GEbounds & etrue(void) const
Return true energy boundaries.
Definition: GRmf.hpp:251
GEbounds m_ebds_true
True energy boundaries.
Definition: GRmf.hpp:118
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition: GFitsHDU.hpp:259
virtual ~GRmf(void)
Destructor.
Definition: GRmf.cpp:134
const int & columns(void) const
Return number of matrix columns.
void write(GFits &fits, const std::string &unit="keV") const
Write Redistribution Matrix File.
Definition: GRmf.cpp:710
void load(const GFilename &filename)
Load Redistribution Matrix File.
Definition: GRmf.cpp:510
const GMatrixSparse & matrix(void) const
Return redistribution matrix.
Definition: GRmf.hpp:277
Mathematical function definitions.
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
FITS table abstract base class interface definition.
const std::string extname_rmf
Definition: GRmf.hpp:44