GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GFitsTableCol.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GFitsTableCol.cpp - FITS table column abstract base class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2008-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 GFitsTableCol.cpp
23  * @brief Abstract FITS table column class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cstdlib>
32 #include "GException.hpp"
33 #include "GTools.hpp"
34 #include "GFitsCfitsio.hpp"
35 #include "GFitsTableCol.hpp"
36 
37 /* __ Method name definitions ____________________________________________ */
38 #define G_ELEMENTS1 "GFitsTableCol::elements(int&, int&)"
39 #define G_ELEMENTS2 "GFitsTableCol::elements(int&)"
40 #define G_LOAD_COLUMN_FIXED "GFitsTableCol::load_column_fixed()"
41 #define G_LOAD_COLUMN_VARIABLE "GFitsTableCol::load_column_variable()"
42 #define G_SAVE_COLUMN_FIXED "GFitsTableCol::save_column_fixed()"
43 #define G_SAVE_COLUMN_VARIABLE "GFitsTableCol::save_column_variable()"
44 #define G_OFFSET "GFitsTableCol::offset(int&, int&)"
45 
46 /* __ Macros _____________________________________________________________ */
47 
48 /* __ Coding definitions _________________________________________________ */
49 //#define G_PRINT_CONTENT //!< Print column content
50 
51 /* __ Debug definitions __________________________________________________ */
52 //#define G_CALL_GRAPH //!< Dump call graph in console
53 
54 
55 /*==========================================================================
56  = =
57  = Constructors/destructors =
58  = =
59  ==========================================================================*/
60 
61 /***********************************************************************//**
62  * @brief Void constructor
63  ***************************************************************************/
65 {
66  // Initialise class members for clean destruction
67  init_members();
68 
69  // Return
70  return;
71 }
72 
73 
74 /***********************************************************************//**
75  * @brief Column constructor
76  *
77  * @param[in] name Name of column.
78  * @param[in] nrows Number of rows in column.
79  * @param[in] number Number of elements in column (negative for variable-length).
80  * @param[in] width Width of one column element.
81  *
82  * Construct column instance from @p name, @p nrows, @p number of elements
83  * and @p width (or size) of one element. If @p number is negative, a
84  * variable-length column will be allocated. The repeat value, which is
85  * required for binary tables, is computed internally by multiplying the
86  * @p number by the @p width.
87  ***************************************************************************/
88 GFitsTableCol::GFitsTableCol(const std::string& name,
89  const int& nrows,
90  const int& number,
91  const int& width)
92 {
93  // Initialise class members for clean destruction
94  init_members();
95 
96  // Store attributes
97  if (number >= 0) { // fixed-length column
98  m_name = name;
99  m_length = nrows;
100  m_number = number;
101  m_width = width;
102  m_variable = false;
103  }
104  else { // variable-length column
105  m_name = name;
106  m_length = nrows;
107  m_number = 1;
108  m_width = width;
109  m_variable = true;
110  m_rowstart.assign(nrows+1, 0);
111  }
112 
113  // Calculate repeat value (only used for binary table!)
115 
116  // Return
117  return;
118 }
119 
120 
121 /***********************************************************************//**
122  * @brief Copy constructor
123  *
124  * @param[in] column Column.
125  ***************************************************************************/
127 {
128  // Initialise class members for clean destruction
129  init_members();
130 
131  // Copy members
132  copy_members(column);
133 
134  // Return
135  return;
136 }
137 
138 
139 /***********************************************************************//**
140  * @brief Destructor
141  ***************************************************************************/
143 {
144  // Free members
145  free_members();
146 
147  // Return
148  return;
149 }
150 
151 
152 /*==========================================================================
153  = =
154  = Operators =
155  = =
156  ==========================================================================*/
157 
158 /***********************************************************************//**
159  * @brief Assignment operator
160  *
161  * @param[in] column Column.
162  * @return Column.
163  ***************************************************************************/
165 {
166  // Execute only if object is not identical
167  if (this != &column) {
168 
169  // Free members
170  free_members();
171 
172  // Initialise private members for clean destruction
173  init_members();
174 
175  // Copy members
176  copy_members(column);
177 
178  } // endif: object was not identical
179 
180  // Return this object
181  return *this;
182 }
183 
184 
185 /*==========================================================================
186  = =
187  = Public methods =
188  = =
189  ==========================================================================*/
190 
191 /***********************************************************************//**
192  * @brief Set number of column elements for specific row
193  *
194  * @param[in] row Row number.
195  * @param[in] elements Number of elements in @p row.
196  *
197  * @exception GException::out_of_range
198  * Invalid row index specified.
199  * @exception GException::invalid_argument
200  * Invalid number of elements specified.
201  *
202  * Sets the number of elements in column for a specific @p row.
203  ***************************************************************************/
204 void GFitsTableCol::elements(const int& row, const int& elements)
205 {
206  // Check row value
207  if (row < 0 || row >= nrows()) {
208  throw GException::out_of_range(G_ELEMENTS1, "FITS table row number",
209  row, nrows());
210  }
211 
212  // Check that elements is non-negative
213  if (elements < 0) {
214  std::string msg = "Number of elements " + gammalib::str(elements) +
215  " can not be negative. Please specify a"
216  " non-negative number of elements.";
218  }
219 
220  // First handle the case of a variable-length column
221  if (is_variable()) {
222 
223  // Determine number of elements to add or to remove
224  int difference = elements - (m_rowstart[row+1] - m_rowstart[row]);
225 
226  // If difference is positive, then add elements at the end of
227  // the vector. This is done using resize_data() which will insert
228  // "difference" elements at the index specified as first argument
229  if (difference > 0) {
230  resize_data(m_rowstart[row+1], difference);
231  }
232 
233  // ... else if difference is negative then remove elements from
234  // the end of the array. This is done using resize_data() which
235  // will remove "difference" element from the index on specified as
236  // first argument
237  else if (difference < 0) {
238  resize_data(m_rowstart[row+1]+difference, difference);
239  }
240 
241  // Update row start indices
242  for (int i = row + 1; i <= nrows(); ++i) {
243  m_rowstart[i] += difference;
244  }
245 
246  // Update maximum column length
247  m_varlen = 0;
248  for (int i = 0; i < nrows(); ++i) {
249  int len = m_rowstart[row+1] - m_rowstart[row];
250  if (len > m_varlen) {
251  m_varlen = len;
252  }
253  }
254 
255  } // endif: we had a variable-length column
256 
257  // Return
258  return;
259 }
260 
261 
262 /***********************************************************************//**
263  * @brief Returns number of elements in column for specific row
264  *
265  * @param[in] row Row index.
266  * @return Number of elements in column at @p row.
267  *
268  * @exception GException::out_of_range
269  * Row index out of valid range.
270  *
271  * Returns the number of elements in the column for a specific @p row. For a
272  * fixed-length column the returned number is independent of the row. For a
273  * variable-length column the returned number is then length of the column
274  * for the specified row.
275  ***************************************************************************/
276 int GFitsTableCol::elements(const int& row) const
277 {
278  // Check row value
279  if (row < 0 || row >= nrows()) {
280  throw GException::out_of_range(G_ELEMENTS2, "FITS table row number",
281  row, nrows());
282  }
283 
284  // Get number of elements
285  int number = (m_variable) ? m_rowstart[row+1] - m_rowstart[row]
286  : m_number;
287 
288  // Return number
289  return number;
290 }
291 
292 
293 /***********************************************************************//**
294  * @brief Returns TFORM code for binary table column
295  *
296  * Constructs the TFORM code for a binary table column, supporting
297  * fixed-length and variable-length column types.
298  ***************************************************************************/
299 std::string GFitsTableCol::tform_binary(void) const
300 {
301  // Set type code string
302  std::string typecode = "";
303  switch (std::abs(type())) {
304  case __TBIT:
305  typecode = "X";
306  break;
307  case __TBYTE:
308  typecode = "B";
309  break;
310  case __TLOGICAL:
311  typecode = "L";
312  break;
313  case __TSTRING:
314  // If there are substrings then add width of substring
315  typecode = "A";
316  if (repeat() > width()) {
317  typecode.append(gammalib::str(width()));
318  }
319  break;
320  case __TUSHORT:
321  typecode = "U";
322  break;
323  case __TSHORT:
324  typecode = "I";
325  break;
326  case __TULONG:
327  typecode = "V";
328  break;
329  case __TLONG:
330  typecode = "J";
331  break;
332  case __TUINT:
333  typecode = "V";
334  break;
335  case __TINT:
336  typecode = "J";
337  break;
338  case __TFLOAT:
339  typecode = "E";
340  break;
341  case __TLONGLONG:
342  typecode = "K";
343  break;
344  case __TDOUBLE:
345  typecode = "D";
346  break;
347  case __TCOMPLEX:
348  typecode = "C";
349  break;
350  case __TDBLCOMPLEX:
351  typecode = "M";
352  break;
353  default:
354  break;
355  }
356 
357  // Build TFORM code
358  std::string tform;
359  if (std::abs(type()) == __TSTRING) {
360  tform.append(gammalib::str(repeat()));
361  }
362  else {
363  tform.append(gammalib::str(number()));
364  }
365  if (is_variable()) {
366  tform.append("P");
367  }
368  tform.append(typecode);
369  if (is_variable() && m_varlen > 0) {
370  tform.append("("+gammalib::str(m_varlen)+")");
371  }
372 
373  // Return TFORM code
374  return tform;
375 }
376 
377 
378 /***********************************************************************//**
379  * @brief Print column information
380  *
381  * @param[in] chatter Chattiness.
382  * @return String containing column information.
383  *
384  * @todo Format and cfitsio information is mainly for debugging. This could
385  * vanish in a more stable version of the code, or it could be compiled-in
386  * conditionally using a debug option. Alternatively, a higher chatter level
387  * may be required to see this information.
388  ***************************************************************************/
389 std::string GFitsTableCol::print(const GChatter& chatter) const
390 {
391  // Initialise result string
392  std::string result;
393 
394  // Continue only if chatter is not silent
395  if (chatter != SILENT) {
396 
397  // Append formatted column name. Optionally add units
398  if (unit().length() > 0) {
399  result.append(gammalib::parformat(name()+" ("+unit()+")"));
400  }
401  else {
402  result.append(gammalib::parformat(name()));
403  }
404 
405  // Append column number. This will be "-" if the column does not exist
406  // in the FITS file.
407  if (m_colnum > 0) {
408  result.append(gammalib::right(gammalib::str(m_colnum),4)+" ");
409  }
410  else {
411  result.append(gammalib::right("[-]",4)+" ");
412  }
413 
414  // Append loading information
415  if (is_loaded()) {
416  result.append("[loaded] ");
417  }
418  else {
419  result.append("[not loaded] ");
420  }
421 
422  // Append format information
423  result.append("["+tform_binary()+","+ascii_format()+"]");
424 
425  // Append dimensions (if available)
426  if (!dim().empty()) {
427 
428  // Build TDIM string
429  std::string value = "("+gammalib::str(dim()[0]);
430  for (int k = 1; k < dim().size(); ++k) {
431  value += ","+gammalib::str(dim()[k]);
432  }
433  value += ")";
434 
435  // Append
436  result.append(" "+value);
437  }
438 
439  // Append cfitsio information
440  if (is_variable()) {
441  result.append(" repeat=" + gammalib::str(repeat()));
442  result.append(" width=" + gammalib::str(width()));
443  result.append(" number=" + gammalib::str(number()));
444  result.append(" rows=" + gammalib::str(nrows()));
445  result.append(" size=" + gammalib::str(m_size));
446  result.append(" varlen=");
447  if (m_varlen > 0) {
448  result.append(gammalib::str(m_varlen));
449  }
450  else {
451  result.append("undetermined");
452  }
453  }
454  else {
455  result.append(" repeat=" + gammalib::str(repeat()));
456  result.append(" width=" + gammalib::str(width()));
457  result.append(" number=" + gammalib::str(number()));
458  result.append(" rows=" + gammalib::str(nrows()));
459  result.append(" size=" + gammalib::str(m_size));
460  }
461 
462  // Append tscale information
463  if (tscale() != 1.0) {
464  result.append(" tscale=" + gammalib::str(tscale()));
465  }
466 
467  } // endif: chatter was not silent
468 
469  // Compile option: print content
470  #if defined(G_PRINT_CONTENT)
471  if (chatter != SILENT) {
472 
473  // Fetch data if necessary
474  if (!is_loaded()) fetch_data();
475 
476  // Loop over all rows
477  for (int row = 0; row < nrows(); ++row) {
478  result.append("\n");
479  if (is_variable()) {
480  result.append("start=");
481  result.append(gammalib::str(m_rowstart[row]));
482  result.append(":");
483  }
484  for (int inx = 0; inx < elements(row); ++inx) {
485  result.append(" "+string(row, inx));
486  }
487  }
488  if (is_variable()) {
489  result.append("\nend=");
490  result.append(gammalib::str(m_rowstart[nrows()]));
491  }
492  }
493  #endif
494 
495  // Return result
496  return result;
497 }
498 
499 
500 /*==========================================================================
501  = =
502  = Protected methods =
503  = =
504  ==========================================================================*/
505 
506 /***********************************************************************//**
507  * @brief Save table column into FITS file
508  *
509  * Refer to GFitsTableCol::save_column() for more information.
510  ***************************************************************************/
512 {
513  // Save column
514  save_column();
515 
516  // Return
517  return;
518 }
519 
520 
521 /***********************************************************************//**
522  * @brief Load table column from FITS file
523  *
524  * Loads table column from FITS file by calling the load_column_variable()
525  * method for variable-length columns and load_column_fixed() for fixed-
526  * length columns.
527  *
528  * The method also makes sure that any scaled column will be read unscaled.
529  ***************************************************************************/
531 {
532  // If the column is scaled then rest the scaling so that data are read
533  // unscaled. This is necessary to avoid that information is lost when
534  // rewriting the table. Note that a call to fftscl does not alter the
535  // keywords. Also note that this implies that scaling of integer columns
536  // has to be performed by hand.
537  if (m_tscale != 1.0) {
538  int status = 0;
539  status = __fftscl(FPTR(m_fitsfile), m_colnum, 1.0, 0.0, &status);
540  }
541 
542  // Load variable-length or fixed-length column from FITS file
543  if (is_variable()) {
545  }
546  else {
548  }
549 
550  // Return
551  return;
552 }
553 
554 
555 /***********************************************************************//**
556  * @brief Load fixed-length column from FITS file
557  *
558  * @exception GException::fits_hdu_not_found
559  * Specified HDU not found in FITS file.
560  * @exception GException::fits_error
561  * An error occured while loading column data from FITS file.
562  *
563  * If a FITS file is attached to the column the data are loaded into memory
564  * from the FITS file. If no FITS file is attached, memory is allocated
565  * to hold the column data and all cells are set to 0.
566  *
567  * The method makes use of the virtual methods
568  * GFitsTableCol::alloc_data,
569  * GFitsTableCol::init_data,
570  * GFitsTableCol::ptr_data, and
571  * GFitsTableCol::ptr_nulval.
572  * These methods are implemented by the derived column classes which
573  * implement a specific storage class (i.e. float, double, short, ...).
574  ***************************************************************************/
576 {
577  // Calculate size of memory
579 
580  // Load only if the column has a positive size
581  if (m_size > 0) {
582 
583  // Allocate and initialise fresh memory
584  alloc_data();
585  init_data();
586 
587  // If a FITS file is attached then try loading column data from the
588  // FITS file. This may fail in case that no data has yet been written
589  // to the FITS file. In that case we just skip loading and return
590  // the initalised column ...
591  if (FPTR(m_fitsfile)->Fptr != NULL) {
592 
593  // Move to the HDU
594  int status = 0;
595  status = __ffmahd(FPTR(m_fitsfile),
596  (FPTR(m_fitsfile)->HDUposition)+1,
597  NULL, &status);
598 
599  // If this failed because:
600  // - the primary HDU was not found (status 252)
601  // - we moved past the file (status 107)
602  // we assume that no data have yet been written to the file and
603  // we skip the loading.
604  if (status != 252 && status != 107) {
605 
606  // Break on any other cfitsio error
607  if (status != 0) {
608  std::string msg = "FITS HDU number "+
609  gammalib::str((FPTR(m_fitsfile)->HDUposition)+1)+
610  " not found in FITS file.";
611  throw GException::fits_error(G_LOAD_COLUMN_FIXED, status, msg);
612  }
613 
614  // Load data
615  status = __ffgcv(FPTR(m_fitsfile), m_type, m_colnum,
616  1, 1, m_size, ptr_nulval(), ptr_data(),
617  &m_anynul, &status);
618  if (status != 0) {
620  "for column \""+m_name+"\".");
621  }
622 
623  } // endif: no primary HDU found
624 
625  } // endif: there was a FITS file attached
626 
627  } // endif: column has a positive size
628 
629  // Return
630  return;
631 }
632 
633 
634 /***********************************************************************//**
635  * @brief Load variable-length column from FITS file
636  *
637  * @exception GException::fits_error
638  * An error occured while loading column data from FITS file.
639  *
640  * If a FITS file is attached to the column the data are loaded into memory
641  * from the FITS file. If no FITS file is attached, memory is allocated
642  * to hold the column data and all cells are set to 0.
643  *
644  * The method makes use of the virtual methods
645  * GFitsTableCol::alloc_data,
646  * GFitsTableCol::init_data,
647  * GFitsTableCol::ptr_data, and
648  * GFitsTableCol::ptr_nulval.
649  * These methods are implemented by the derived column classes which
650  * implement a specific storage class (i.e. float, double, short, ...).
651  ***************************************************************************/
653 {
654  // If a FITS file is attached then try loading column data from the
655  // FITS file. This may fail in case that no data has yet been written
656  // to the FITS file. In that case we just skip loading and return
657  // the initalised column ...
658  if (FPTR(m_fitsfile)->Fptr != NULL) {
659 
660  // Move to the HDU
661  int status = 0;
662  status = __ffmahd(FPTR(m_fitsfile),
663  (FPTR(m_fitsfile)->HDUposition)+1,
664  NULL,
665  &status);
666 
667  // If this failed because:
668  // - the primary HDU was not found (status 252)
669  // - we moved past the file (status 107)
670  // we assume that no data have yet been written to the file and
671  // we skip the loading.
672  if (status != 252 && status != 107) {
673 
674  // Break on any other cfitsio error
675  if (status != 0) {
676  std::string msg = "FITS HDU number "+
677  gammalib::str((FPTR(m_fitsfile)->HDUposition)+1)+
678  " not found in FITS file.";
680  }
681 
682  // Allocate rowstart array
683  m_rowstart.assign(m_length+1, 0);
684 
685  // Determine the column length for each row by looping over
686  // all rows and derive the total memory requirement
687  m_size = 0;
688  m_varlen = 0;
689  m_rowstart[0] = 0;
690  for (int row = 0; row < m_length; ++row) {
691 
692  // Initialise offset and repeat
693  long offset(0);
694  long repeat(0);
695 
696  // Get variable-length of row in repeat
697  status = __ffgdes(FPTR(m_fitsfile),
698  m_colnum,
699  row+1,
700  &repeat,
701  &offset,
702  &status);
703  if (status != 0) {
704  std::string msg = "Unable to get descriptor of row "+
705  gammalib::str(row+1)+" of column '"+
706  name()+"' from FITS file.";
708  msg);
709  }
710 
711  // Store start of next row
712  m_rowstart[row+1] = m_rowstart[row] + repeat;
713  m_size += repeat;
714  if (repeat > m_varlen) {
715  m_varlen = repeat;
716  }
717 
718  } // endfor: looped over all rows
719 
720  // Allocate and initialise fresh memory
721  alloc_data();
722  init_data();
723 
724  // Load data for each row
725  for (int row = 0; row < m_length; ++row) {
726 
727  // Initialise anynul
728  int anynul(0);
729 
730  // Load data
731  status = __ffgcv(FPTR(m_fitsfile),
732  std::abs(m_type),
733  m_colnum,
734  row+1,
735  1,
736  elements(row),
737  ptr_nulval(),
738  ptr_data(m_rowstart[row]),
739  &anynul,
740  &status);
741  if (status != 0) {
742  std::string msg = "Unable to load row "+gammalib::str(row+1)+""
743  " of column '"+name()+"' from FITS file.";
745  msg);
746  }
747 
748  // Increment anynul
749  m_anynul += anynul;
750 
751  } // endfor: looped over all rows
752 
753  } // endif: no primary HDU found
754 
755  } // endif: there was a FITS file attached
756 
757  // Return
758  return;
759 }
760 
761 
762 /***********************************************************************//**
763  * @brief Save table column into FITS file
764  *
765  * Save table column into FITS file by calling the save_column_variable()
766  * method for variable-length columns and save_column_fixed() for fixed-
767  * length columns.
768  ***************************************************************************/
770 {
771  // Save variable-length or fixed-length column into FITS file
772  if (is_variable()) {
774  }
775  else {
777  }
778 
779  // Return
780  return;
781 }
782 
783 
784 /***********************************************************************//**
785  * @brief Save table column into FITS file
786  *
787  * @exception GException::fits_error
788  * Error occured during writing of the column data.
789  *
790  * The table column is only saved if it is linked to a FITS file and if the
791  * data are indeed present in the class instance. This avoids saving of data
792  * that have not been modified.
793  *
794  * The method make use of the virtual methods
795  * GFitsTableCol::ptr_data and
796  * GFitsTableCol::ptr_nulval.
797  * These methods are implemented by the derived column classes which
798  * implement a specific storage class (i.e. float, double, short, ...).
799  ***************************************************************************/
801 {
802  // Continue only if a FITS file is connected and data have been loaded
803  if (FPTR(m_fitsfile)->Fptr != NULL && m_colnum > 0 && ptr_data() != NULL) {
804 
805  // Move to the HDU
806  int status = 0;
807  status = __ffmahd(FPTR(m_fitsfile),
808  (FPTR(m_fitsfile)->HDUposition)+1, NULL,
809  &status);
810  if (status != 0) {
811  std::string msg = "FITS HDU number "+
812  gammalib::str((FPTR(m_fitsfile)->HDUposition)+1)+
813  " not found in FITS file.";
814  throw GException::fits_error(G_SAVE_COLUMN_FIXED, status, msg);
815  }
816 
817  // Save the column data
818  status = __ffpcn(FPTR(m_fitsfile), m_type, m_colnum, 1, 1,
819  m_size, ptr_data(), ptr_nulval(), &status);
820  if (status != 0) {
821  std::string msg = "Unable to save column '"+name()+"' to"
822  " FITS file.";
823  throw GException::fits_error(G_SAVE_COLUMN_FIXED, status, msg);
824  }
825 
826  } // endif: FITS file was connected
827 
828  // Return
829  return;
830 }
831 
832 
833 /***********************************************************************//**
834  * @brief Save table column into FITS file
835  *
836  * @exception GException::fits_hdu_not_found
837  * Specified HDU not found in FITS file.
838  * @exception GException::fits_error
839  * Error occured during writing of the column data.
840  *
841  * The table column is only saved if it is linked to a FITS file and if the
842  * data are indeed present in the class instance. This avoids saving of data
843  * that have not been modified.
844  *
845  * The method make use of the virtual methods
846  * GFitsTableCol::ptr_data and
847  * GFitsTableCol::ptr_nulval.
848  * These methods are implemented by the derived column classes which
849  * implement a specific storage class (i.e. float, double, short, ...).
850  ***************************************************************************/
852 {
853  // Continue only if a FITS file is connected and data have been loaded
854  if (FPTR(m_fitsfile)->Fptr != NULL && m_colnum > 0 && ptr_data() != NULL) {
855 
856  // Move to the HDU
857  int status = 0;
858  status = __ffmahd(FPTR(m_fitsfile),
859  (FPTR(m_fitsfile)->HDUposition)+1, NULL,
860  &status);
861  if (status != 0) {
862  std::string msg = "FITS HDU number "+
863  gammalib::str((FPTR(m_fitsfile)->HDUposition)+1)+
864  " not found in FITS file.";
866  }
867 
868  // Save the column data row-by-row
869  for (int row = 0; row < m_length; ++row) {
870 
871  // Save row data
872  status = __ffpcn(FPTR(m_fitsfile),
873  std::abs(m_type),
874  m_colnum,
875  row+1,
876  1,
877  elements(row),
878  ptr_data(m_rowstart[row]),
879  ptr_nulval(),
880  &status);
881  if (status != 0) {
882  std::string msg = "Unable to save row "+gammalib::str(row+1)+""
883  " of column '"+name()+"' to FITS file.";
885  msg);
886  }
887 
888  } // endfor: looped over rows
889 
890  } // endif: FITS file was connected
891 
892  // Return
893  return;
894 }
895 
896 
897 /***********************************************************************//**
898  * @brief Compute offset of column element in memory
899  *
900  * @param[in] row Row of column [0,...,m_length[.
901  * @param[in] inx Vector index in column row [0,...,elements(row)[.
902  *
903  * @exception GException::out_of_range
904  * Table row or vector index are out of valid range.
905  *
906  * Computes the offset of a column element in the storage array from the
907  * @p row number and the vector index. The method also supports both
908  * variable-length and fixed-length columns.
909  ***************************************************************************/
910 int GFitsTableCol::offset(const int& row, const int& inx) const
911 {
912  // Check row value
913  #if defined(G_RANGE_CHECK)
914  if (row < 0 || row >= m_length) {
915  throw GException::out_of_range(G_OFFSET, "Row", row, m_length);
916  }
917  #endif
918 
919  // Check inx value
920  #if defined(G_RANGE_CHECK)
921  if (inx < 0 || inx >= elements(row)) {
922  throw GException::out_of_range(G_OFFSET, "Vector index", inx,
923  elements(row));
924  }
925  #endif
926 
927  // Calculate pixel offset
928  int offset = (is_variable()) ? m_rowstart[row] + inx : row * m_number + inx;
929 
930  // Return offset
931  return offset;
932 }
933 
934 
935 /*==========================================================================
936  = =
937  = Private methods =
938  = =
939  ==========================================================================*/
940 
941 /***********************************************************************//**
942  * @brief Initialise class members
943  ***************************************************************************/
945 {
946  // Optionally print call graph
947  #if defined(G_CALL_GRAPH)
948  printf("GFitsTableCol::init_members\n");
949  #endif
950 
951  // Allocate FITS file pointer
952  m_fitsfile = new __fitsfile;
953  FPTR(m_fitsfile)->HDUposition = 0;
954  FPTR(m_fitsfile)->Fptr = NULL;
955 
956  // Initialise members
957  m_name.clear();
958  m_unit.clear();
959  m_dim.clear();
960  m_rowstart.clear();
961  m_colnum = 0;
962  m_type = 0;
963  m_repeat = 0;
964  m_width = 0;
965  m_number = 0;
966  m_length = 0;
967  m_variable = false;
968  m_varlen = 0;
969  m_size = 0;
970  m_anynul = 0;
971  m_tscale = 1.0;
972 
973  // Optionally print call graph
974  #if defined(G_CALL_GRAPH)
975  printf("exit GFitsTableCol::init_members\n");
976  #endif
977 
978  // Return
979  return;
980 }
981 
982 
983 /***********************************************************************//**
984  * @brief Copy class members
985  *
986  * @param[in] column Column to be copied.
987  ***************************************************************************/
989 {
990  // Copy attributes
991  m_name = column.m_name;
992  m_unit = column.m_unit;
993  m_dim = column.m_dim;
994  m_colnum = column.m_colnum;
995  m_type = column.m_type;
996  m_repeat = column.m_repeat;
997  m_width = column.m_width;
998  m_number = column.m_number;
999  m_length = column.m_length;
1000  m_variable = column.m_variable;
1001  m_varlen = column.m_varlen;
1002  m_rowstart = column.m_rowstart;
1003  m_size = column.m_size;
1004  m_anynul = column.m_anynul;
1005  m_tscale = column.m_tscale;
1006  FPTR_COPY(m_fitsfile, column.m_fitsfile);
1007 
1008  // Return
1009  return;
1010 }
1011 
1012 
1013 /***********************************************************************//**
1014  * @brief Delete class members
1015  ***************************************************************************/
1017 {
1018  // Optionally print call graph
1019  #if defined(G_CALL_GRAPH)
1020  printf("GFitsTableCol::free_members\n");
1021  #endif
1022 
1023  // Free memory
1024  if (m_fitsfile != NULL) delete FPTR(m_fitsfile);
1025 
1026  // Mark memory as free
1027  m_fitsfile = NULL;
1028 
1029  // Optionally print call graph
1030  #if defined(G_CALL_GRAPH)
1031  printf("exit GFitsTableCol::free_members\n");
1032  #endif
1033 
1034  // Return
1035  return;
1036 }
1037 
1038 
1039 /***********************************************************************//**
1040  * @brief Connect table column to FITS file
1041  *
1042  * @param[in] vptr Column file void pointer.
1043  *
1044  * A table column is connected to a FITS file when the m_fitsfile holds a
1045  * FITS file pointer. In that way, the column knows to which file it belongs.
1046  ***************************************************************************/
1047 void GFitsTableCol::connect(void* vptr)
1048 {
1049  // Connect table column by copying the column file pointer
1050  FPTR_COPY(m_fitsfile, vptr);
1051 
1052  // Return
1053  return;
1054 }
#define __fftscl(A, B, C, D, E)
#define __TINT
virtual void * ptr_nulval(void)=0
#define __TUSHORT
virtual void init_data(void)=0
const int & anynul(void) const
Return number of NULLs encountered.
#define __TULONG
int m_type
Column type.
#define __TLOGICAL
std::string number(const std::string &noun, const int &number)
Convert singular noun into number noun.
Definition: GTools.cpp:1167
void connect(void *vptr)
Connect table column to FITS file.
int m_colnum
Column number (starting from 1). This parameter is used to signal if a table column corresponds to a ...
#define FPTR(A)
bool m_variable
Signals if column is variable length.
int m_anynul
Number of NULLs encountered.
GVector abs(const GVector &vector)
Computes absolute of vector elements.
Definition: GVector.cpp:1253
int m_number
Number of elements in column.
virtual ~GFitsTableCol(void)
Destructor.
void free_members(void)
Delete class members.
#define G_LOAD_COLUMN_VARIABLE
double m_tscale
Optional scaling factor (1 = no scaling)
GFitsTableCol & operator=(const GFitsTableCol &column)
Assignment operator.
const std::string & name(void) const
Returns column name.
void elements(const int &row, const int &elements)
Set number of column elements for specific row.
std::vector< int > m_dim
Column dimension.
#define __TDOUBLE
int m_varlen
Maximum number of elements in variable-length.
const bool & is_variable(void) const
Signals if column is of variable length.
#define __ffgcv(A, B, C, D, E, F, G, H, I, J)
Gammalib tools definition.
virtual void save_column_fixed(void)
Save table column into FITS file.
const std::string & unit(void) const
Returns column unit.
FITS table column abstract base class definition.
#define __TDBLCOMPLEX
#define G_LOAD_COLUMN_FIXED
virtual void load_column(void)
Load table column from FITS file.
virtual void alloc_data(void)=0
#define __TBYTE
virtual void load_column_variable(void)
Load variable-length column from FITS file.
std::string right(const std::string &s, const int &n, const char &c= ' ')
Right justify string to achieve a length of n characters.
Definition: GTools.cpp:1094
const int & number(void) const
Returns number of elements in column.
std::string print(const GChatter &chatter=NORMAL) const
Print column information.
#define __ffmahd(A, B, C, D)
#define __TBIT
#define __TCOMPLEX
void init_members(void)
Initialise class members.
#define __TSHORT
CFITSIO interface header.
std::string m_unit
Column unit.
Abstract interface for FITS table column.
const double & tscale(void) const
Return TSCALE value.
std::vector< int > m_rowstart
Start index of each row.
int m_repeat
Repeat value of column.
const std::vector< int > & dim(void) const
Returns column dimension.
#define __TUINT
GChatter
Definition: GTypemaps.hpp:33
#define __TLONG
#define __TFLOAT
std::string m_name
Column name.
#define FPTR_COPY(A, B)
virtual void save(void)
Save table column into FITS file.
virtual void resize_data(const int &index, const int &number)=0
int m_length
Length of column (number of rows)
const int & repeat(void) const
Returns column repeat value (only used for binary tables)
virtual void * ptr_data(const int &index=0)=0
#define __TLONGLONG
int m_size
Size of allocated data area (0 if not loaded)
#define G_ELEMENTS2
#define __ffpcn(A, B, C, D, E, F, G, H, I)
virtual int offset(const int &row, const int &inx) const
Compute offset of column element in memory.
virtual bool is_loaded(void) const =0
void copy_members(const GFitsTableCol &column)
Copy class members.
Exception handler interface definition.
GFitsTableCol(void)
Void constructor.
#define G_SAVE_COLUMN_FIXED
virtual void save_column(void)
Save table column into FITS file.
const int & type(void) const
Returns CFITSIO column type.
virtual void fetch_data(void) const =0
virtual void save_column_variable(void)
Save table column into FITS file.
void * m_fitsfile
FITS file pointer associated with column.
const int & nrows(void) const
Returns number of rows in column.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
virtual std::string ascii_format(void) const =0
#define G_OFFSET
#define G_ELEMENTS1
virtual void load_column_fixed(void)
Load fixed-length column from FITS file.
#define __TSTRING
#define G_SAVE_COLUMN_VARIABLE
const int & width(void) const
Return width in Bytes of one column element.
int m_width
Width in Bytes of single column element.
#define __ffgdes(A, B, C, D, E, F)
std::string tform_binary(void) const
Returns TFORM code for binary table column.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489