GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GResponseVectorCache.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GResponseVectorCache.cpp - Response vector cache class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2020-2022 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 GResponseVectorCache.cpp
23  * @brief Response vector cache 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 "GVector.hpp"
33 #include "GFilename.hpp"
34 #include "GFits.hpp"
35 #include "GFitsTable.hpp"
36 #include "GFitsBinTable.hpp"
37 #include "GFitsTableStringCol.hpp"
38 #include "GFitsTableLongCol.hpp"
39 #include "GFitsTableDoubleCol.hpp"
40 #include "GResponseVectorCache.hpp"
41 
42 /* __ Method name definitions ____________________________________________ */
43 
44 /* __ Macros _____________________________________________________________ */
45 
46 /* __ Coding definitions _________________________________________________ */
47 
48 /* __ Debug definitions __________________________________________________ */
49 //#define G_DEBUG_VECTOR_CACHE //!< Debug vector cache
50 
51 
52 /*==========================================================================
53  = =
54  = Constructors/destructors =
55  = =
56  ==========================================================================*/
57 
58 /***********************************************************************//**
59  * @brief Void constructor
60  ***************************************************************************/
62 {
63  // Initialise class members
64  init_members();
65 
66  // Return
67  return;
68 }
69 
70 
71 /***********************************************************************//**
72  * @brief Copy constructor
73  *
74  * @param[in] cache Response vector cache.
75  ***************************************************************************/
77 {
78  // Initialise class members
79  init_members();
80 
81  // Copy members
82  copy_members(cache);
83 
84  // Return
85  return;
86 }
87 
88 
89 /***********************************************************************//**
90  * @brief Destructor
91  ***************************************************************************/
93 {
94  // Free members
95  free_members();
96 
97  // Return
98  return;
99 }
100 
101 
102 /*==========================================================================
103  = =
104  = Operators =
105  = =
106  ==========================================================================*/
107 
108 /***********************************************************************//**
109  * @brief Assignment operator
110  *
111  * @param[in] cache Response vector cache.
112  * @return Response vector cache.
113  ***************************************************************************/
115 {
116  // Execute only if object is not identical
117  if (this != &cache) {
118 
119  // Free members
120  free_members();
121 
122  // Initialise private members
123  init_members();
124 
125  // Copy members
126  copy_members(cache);
127 
128  } // endif: object was not identical
129 
130  // Return this object
131  return *this;
132 }
133 
134 
135 /*==========================================================================
136  = =
137  = Public methods =
138  = =
139  ==========================================================================*/
140 
141 /***********************************************************************//**
142  * @brief Clear response vector cache
143  ***************************************************************************/
145 {
146  // Free members
147  free_members();
148 
149  // Initialise private members
150  init_members();
151 
152  // Return
153  return;
154 }
155 
156 
157 /***********************************************************************//**
158  * @brief Clone response cache
159  *
160  * @return Pointer to deep copy of response cache.
161  ***************************************************************************/
163 {
164  return new GResponseVectorCache(*this);
165 }
166 
167 
168 /***********************************************************************//**
169  * @brief Set cache value
170  *
171  * @param[in] cache_id Cache identifier.
172  * @param[in] vector Cache vector.
173  *
174  * Set cache vector for a given @p cache_id.
175  ***************************************************************************/
176 void GResponseVectorCache::set(const std::string& cache_id,
177  const GVector& vector)
178 {
179  // Debug vector cache
180  #if defined(G_DEBUG_VECTOR_CACHE)
181  std::cout << "GResponseVectorCache::set(";
182  std::cout << cache_id << "," << vector.size() << "):";
183  #endif
184 
185  // Initialise pointers to values and indices
186  double* values = NULL;
187  int* indices = NULL;
188 
189  // Find cache index
190  int index = find_cache(cache_id);
191 
192  // Determine size of vector cache
193  int entries = vector.non_zeros();
194 
195  // Debug vector cache
196  #if defined(G_DEBUG_VECTOR_CACHE)
197  if (index != -1) {
198  std::cout << " entry found at index " << index;
199  std::cout << " with " << m_cache_entries[index] << " elements.";
200  std::cout << " Require " << entries << " elements.";
201  std::cout << std::endl;
202  }
203  else {
204  std::cout << " no entry found.";
205  std::cout << " Require " << entries << " elements.";
206  std::cout << std::endl;
207  }
208  #endif
209 
210  // If cache identifier does not yet exist then create new cache entry
211  // and allocate memory to hold cache values and indices
212  if (index == -1) {
213  if (entries > 0) {
214  values = new double[entries];
215  indices = new int[entries];
216  }
217  m_cache_ids.push_back(cache_id);
218  m_cache_entries.push_back(entries);
219  m_cache_values.push_back(values);
220  m_cache_indices.push_back(indices);
221  }
222 
223  // ... otherwise update cache existing entry by allocating new memory
224  // to hold cache values and indices in case that the number of entries
225  // have changed
226  else {
227  if (m_cache_entries[index] != entries) {
228  if (entries > 0) {
229  values = new double[entries];
230  indices = new int[entries];
231  }
232  if (m_cache_values[index] != NULL) delete [] m_cache_values[index];
233  if (m_cache_indices[index] != NULL) delete [] m_cache_indices[index];
234  m_cache_entries[index] = entries;
235  m_cache_values[index] = values;
236  m_cache_indices[index] = indices;
237  }
238  else {
239  values = m_cache_values[index];
240  indices = m_cache_indices[index];
241  }
242  }
243 
244  // Set cache vector
245  for (int i = 0; i < vector.size(); ++i) {
246  if (vector[i] != 0.0) {
247  *values++ = vector[i];
248  *indices++ = i;
249  }
250  }
251 
252  // Return
253  return;
254 }
255 
256 
257 /***********************************************************************//**
258  * @brief Remove cache
259  *
260  * @param[in] cache_id Cache identifier.
261  *
262  * Remove cache for a given @p cache_id.
263  ***************************************************************************/
264 void GResponseVectorCache::remove(const std::string& cache_id)
265 {
266  // Find cache index
267  int index = find_cache(cache_id);
268 
269  // If cache index is valid then remove corresponding cache
270  if (index != -1) {
271 
272  // Free memory
273  if (m_cache_values[index] != NULL) delete [] m_cache_values[index];
274  if (m_cache_indices[index] != NULL) delete [] m_cache_indices[index];
275 
276  // Erase entry
277  m_cache_ids.erase(m_cache_ids.begin() + index);
278  m_cache_entries.erase(m_cache_entries.begin() + index);
279  m_cache_values.erase(m_cache_values.begin() + index);
280  m_cache_indices.erase(m_cache_indices.begin() + index);
281 
282  } // endif: cache index was valid
283 
284  // Return
285  return;
286 }
287 
288 
289 /***********************************************************************//**
290  * @brief Check if cache contains a value for specific parameters
291  *
292  * @param[in] cache_id Cache identifier.
293  * @param[in,out] vector Pointer to cached vector (only if found).
294  * @return True if cached value was found, otherwise false.
295  *
296  * Check if the cache contains a value for a given @p name, reconstructed
297  * energy @p ereco, and true energy @p etrue.
298  *
299  * If the @p value pointer argument is not NULL, the method will return the
300  * cached value through this argument in case that the value exists.
301  ***************************************************************************/
302 bool GResponseVectorCache::contains(const std::string& cache_id,
303  GVector* vector) const
304 {
305  // Debug vector cache
306  #if defined(G_DEBUG_VECTOR_CACHE)
307  std::cout << "GResponseVectorCache::contains(" << cache_id;
308  if (vector == NULL) {
309  std::cout << ", NULL):";
310  }
311  else {
312  std::cout << "," << vector->size() << "):";
313  }
314  #endif
315 
316  // Find cache index
317  int index = find_cache(cache_id);
318 
319  // Set contains flag
320  bool contains = (index != -1);
321 
322  // Debug vector cache
323  #if defined(G_DEBUG_VECTOR_CACHE)
324  if (contains) {
325  std::cout << " entry found at index " << index;
326  std::cout << " with " << m_cache_entries[index] << " elements.";
327  std::cout << std::endl;
328  }
329  else {
330  std::cout << " no entry found." << std::endl;
331  }
332  #endif
333 
334  // If cache contains the identifier and a pointer to a vector was
335  // provided then fill the vector
336  if (contains && vector != NULL) {
337 
338  // Get pointer to values and indices
339  double* values = m_cache_values[index];
340  int* indices = m_cache_indices[index];
341 
342  // Fill vector
343  for (int i = 0; i < m_cache_entries[index]; ++i, ++values, ++indices) {
344  (*vector)[*indices] = *values;
345  }
346 
347  } // endif: filled vector
348 
349  // Return containment flag
350  return contains;
351 }
352 
353 
354 /***********************************************************************//**
355  * @brief Load response vector cache from FITS file
356  *
357  * @param[in] filename FITS file name.
358  *
359  * Loads the response vector cache from a FITS file. All binary tables in
360  * the FITS file are assumed to be response vector cache entries.
361  ***************************************************************************/
363 {
364  // Free members
365  free_members();
366 
367  // Initialise attributes
368  init_members();
369 
370  // Open FITS file
371  GFits fits(filename);
372 
373  // Loop over all extensions
374  for (int i = 0; i < fits.size(); ++i) {
375 
376  // Handle only binary table extensions
377  if (fits[i]->exttype() == GFitsHDU::HT_BIN_TABLE) {
378  read(*fits.table(i));
379  }
380 
381  } // endfor: looped over all extensions
382 
383  // Close FITS file
384  fits.close();
385 
386  // Return
387  return;
388 }
389 
390 
391 /***********************************************************************//**
392  * @brief Save the response vector cache into FITS file
393  *
394  * @param[in] filename FITS file name.
395  * @param[in] clobber Overwrite an response vector cache file?
396  *
397  * Saves the response vector cache into a FITS file. If a file with the given
398  * @p filename does not yet exist it will be created, otherwise the method
399  * opens the existing file. The response vector cache can only be appended
400  * to an existing file if the @p clobber flag is set to "true" (otherwise
401  * an exception is thrown).
402  *
403  * The method will append all cache entries as binary FITS tables to the
404  * FITS file. The table extension names are defined by the cache
405  * identifiers. All cache entries with identifiers exceeding 80 characters
406  * will be skipped to avoid truncation of cache identifiers.
407  ***************************************************************************/
409  const bool& clobber) const
410 {
411  // Open or create FITS file (without extension name)
412  GFits fits(filename.url(), true);
413 
414  // Loop over the cache entries
415  for (int i = 0; i < size(); ++i) {
416 
417  // Set extension name
418  std::string extname = m_cache_ids[i];
419 
420  // Skip entries with too long identifiers
421  if (extname.length() > 80) {
422  continue;
423  }
424 
425  // Get number of cache entries
426  int entries = m_cache_entries[i];
427 
428  // Create response vector cache columns
429  GFitsTableDoubleCol col_values("VALUES", entries);
430  GFitsTableLongCol col_indices("INDICES", entries);
431 
432  // Write cache values and indices in columns
433  double* values = m_cache_values[i];
434  int* indices = m_cache_indices[i];
435  for (int k = 0; k < entries; ++k, ++values, ++indices) {
436  col_values(k) = *values;
437  col_indices(k) = *indices;
438  }
439 
440  // Create binary table
441  GFitsBinTable table(entries);
442  table.append(col_values);
443  table.append(col_indices);
444  table.extname(extname);
445 
446  // Write mandatory keywords
447  table.card("HDUCLASS", "OGIP", "Format conforms to OGIP standard");
448  table.card("HDUCLAS1", "RESPONSE", "Extension contains response data");
449  table.card("HDUCLAS2", "VECTOR_CACHE", "Extension contains a response vector cache");
450  table.card("HDUVERS", "1.0.0", "Version of the file format");
451 
452  // If the FITS object contains already an extension with the same
453  // name then remove now this extension
454  if (fits.contains(extname)) {
455  fits.remove(extname);
456  }
457 
458  // Append response vector cache to FITS file
459  fits.append(table);
460 
461 
462  } // endfor: looped over cache entries
463 
464  // Save to file
465  fits.save(clobber);
466 
467  // Return
468  return;
469 }
470 
471 
472 /***********************************************************************//**
473  * @brief Read response vector cache from FITS table
474  *
475  * @param[in] table FITS table.
476  *
477  * Reads response vector cache from a FITS table. There is one cache entry
478  * in a FITS table, with the table extension name specifying the cache
479  * identifier. Only tables containing the "HDUCLAS2" keyword set to
480  * "VECTOR_CACHE" will be considered by the method, all other tables will
481  * be simply skipped.
482  ***************************************************************************/
484 {
485  // Continue only if table contains a response vector cache
486  if (table.has_card("HDUCLAS2") && table.string("HDUCLAS2") == "VECTOR_CACHE") {
487 
488  // Get number of rows in FITS table
489  int entries = table.nrows();
490 
491  // Continue only if there are rows in the FITS table
492  if (entries > 0) {
493 
494  // Set cache ID from extension name
495  std::string cache_id = table.extname();
496 
497  // Get column pointers
498  const GFitsTableCol* col_values = table["VALUES"];
499  const GFitsTableCol* col_indices = table["INDICES"];
500 
501  // Allocate memory for values and indices
502  double* values = new double[entries];
503  int* indices = new int[entries];
504 
505  // Put information and pointers into cache
506  m_cache_ids.push_back(cache_id);
507  m_cache_entries.push_back(entries);
508  m_cache_values.push_back(values);
509  m_cache_indices.push_back(indices);
510 
511  // Extact values and indices
512  for (int i = 0; i < entries; ++i) {
513  *values++ = col_values->real(i);
514  *indices++ = col_indices->integer(i);
515  }
516 
517  } // endif: there were entries in table
518 
519  } // endif: table contained a response vector cache
520 
521  // Return
522  return;
523 }
524 
525 
526 /***********************************************************************//**
527  * @brief Print response cache
528  *
529  * @param[in] chatter Chattiness.
530  * @return String containing response cache information.
531  ***************************************************************************/
532 std::string GResponseVectorCache::print(const GChatter& chatter) const
533 {
534  // Initialise result string
535  std::string result;
536 
537  // Continue only if chatter is not silent
538  if (chatter != SILENT) {
539 
540  // Append header
541  result.append("=== GResponseVectorCache ===");
542 
543  // Append total cache size
544  result.append("\n"+gammalib::parformat("Number of cached vectors"));
545  result.append(gammalib::str(size()));
546 
547  // Append cache information
548  for (int i = 0; i < size(); ++i) {
549  result.append("\n"+gammalib::parformat("Identifier"));
550  result.append(m_cache_ids[i]);
551  result.append(" ("+gammalib::str(m_cache_entries[i])+" values");
552  }
553 
554  } // endif: chatter was not silent
555 
556  // Return result
557  return result;
558 }
559 
560 
561 /*==========================================================================
562  = =
563  = Private methods =
564  = =
565  ==========================================================================*/
566 
567 /***********************************************************************//**
568  * @brief Initialise class members
569  ***************************************************************************/
571 {
572  // Initialise members
573  m_cache_ids.clear();
574  m_cache_entries.clear();
575  m_cache_values.clear();
576  m_cache_indices.clear();
577 
578  // Return
579  return;
580 }
581 
582 
583 /***********************************************************************//**
584  * @brief Copy class members
585  *
586  * @param[in] cache Response cache.
587  ***************************************************************************/
589 {
590  // Copy members
591  m_cache_ids = cache.m_cache_ids;
593 
594  // Copy values and indices
595  for (int i = 0; i < size(); ++i) {
596  double* values = NULL;
597  int* indices = NULL;
598  if (m_cache_entries[i] > 0) {
599  values = new double[m_cache_entries[i]];
600  indices = new int[m_cache_entries[i]];
601  for (int k = 0; k < m_cache_entries[i]; ++k) {
602  values[k] = cache.m_cache_values[i][k];
603  indices[k] = cache.m_cache_indices[i][k];
604  }
605  }
606  m_cache_values.push_back(values);
607  m_cache_indices.push_back(indices);
608  }
609 
610  // Return
611  return;
612 }
613 
614 
615 /***********************************************************************//**
616  * @brief Delete class members
617  ***************************************************************************/
619 {
620  // Loop over entries
621  for (int i = 0; i < size(); ++i) {
622  if (m_cache_values[i] != NULL) delete [] m_cache_values[i];
623  if (m_cache_indices[i] != NULL) delete [] m_cache_indices[i];
624  m_cache_values[i] = NULL;
625  m_cache_indices[i] = NULL;
626  }
627 
628  // Return
629  return;
630 }
631 
632 
633 /***********************************************************************//**
634  * @brief Find cache
635  *
636  * @param[in] cache_id Cache identifier.
637  * @return Cache index (-1 if no cache was found)
638  *
639  * Find cache for a given @p cache_id. If no cache was found the method
640  * returns -1.
641  ***************************************************************************/
642 int GResponseVectorCache::find_cache(const std::string& cache_id) const
643 {
644  // Initialise cache index
645  int index = -1;
646 
647  // Loop over cache
648  for (int i = 0; i < m_cache_ids.size(); ++i) {
649  if (m_cache_ids[i] == cache_id) {
650  index = i;
651  break;
652  }
653  }
654 
655  // Return index
656  return index;
657 }
658 
659 
void save(const GFilename &filename, const bool &clobber=false) const
Save the response vector cache into FITS file.
FITS table double column class interface definition.
GResponseVectorCache(void)
Void constructor.
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:482
bool has_card(const int &cardno) const
Check existence of header card.
Definition: GFitsHDU.hpp:233
Response vector cache class.
std::vector< int > m_cache_entries
std::string print(const GChatter &chatter=NORMAL) const
Print response cache.
void set(const std::string &cache_id, const GVector &vector)
Set cache value.
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
Definition: GFitsTable.hpp:147
virtual ~GResponseVectorCache(void)
Destructor.
Gammalib tools definition.
FITS file class.
Definition: GFits.hpp:63
void init_members(void)
Initialise class members.
FITS file class interface definition.
std::vector< double * > m_cache_values
int size(void) const
Returns size of vector chache.
int find_cache(const std::string &cache_id) const
Find cache.
void read(const GFitsTable &table)
Read response vector cache from FITS table.
void free_members(void)
Delete class members.
GResponseVectorCache * clone(void) const
Clone response cache.
Filename class.
Definition: GFilename.hpp:62
int non_zeros(void) const
Returns number of non-zero elements in vector.
Definition: GVector.cpp:559
Abstract interface for FITS table column.
GResponseVectorCache & operator=(const GResponseVectorCache &cache)
Assignment operator.
Response vector cache class definition.
void remove(const std::string &cache_id)
Remove cache.
FITS table string column class interface definition.
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
GChatter
Definition: GTypemaps.hpp:33
Vector class interface definition.
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
void copy_members(const GResponseVectorCache &cache)
Copy class members.
FITS table long integer column.
const int & nrows(void) const
Return number of rows in table.
Definition: GFitsTable.hpp:119
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 response vector cache.
virtual double real(const int &row, const int &inx=0) const =0
FITS binary table class.
int size(void) const
Return number of HDUs in FITS file.
Definition: GFits.hpp:237
bool contains(const std::string &cache_id, GVector *irfs=NULL) const
Check if cache contains a value for specific parameters.
std::string string(const std::string &keyname) const
Return card value as string.
Definition: GFitsHDU.hpp:410
FITS table long integer column class interface definition.
FITS binary table class definition.
std::vector< int * > m_cache_indices
const int & size(void) const
Return size of vector.
Definition: GVector.hpp:178
Vector class.
Definition: GVector.hpp:46
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
std::vector< std::string > m_cache_ids
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition: GFitsHDU.hpp:259
void load(const GFilename &filename)
Load response vector cache from FITS file.
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
FITS table double column.
Filename class interface definition.
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.