GammaLib  1.7.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-2017 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 "GFitsCfitsio.hpp"
34 #include "GFitsTableCol.hpp"
35 #include "GTools.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 
50 /* __ Debug definitions __________________________________________________ */
51 //#define G_CALL_GRAPH //!< Dump call graph in console
52 #define G_PRINT_CONTENT //!< Print column content
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 index.
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, "Row index", row, nrows());
209  }
210 
211  // Check that elements is non-negative
212  if (elements < 0) {
213  std::string msg = "Number of elements " + gammalib::str(elements) +
214  " can not be negative.\nPlease specify a"
215  " non-negative number of elements.";
217  }
218 
219  // First handle the case of a variable-length column
220  if (is_variable()) {
221 
222  // Determine number of elements to add or to remove
223  int difference = elements - (m_rowstart[row+1] - m_rowstart[row]);
224 
225  // If difference is positive, then add elements at the end of
226  // the vector. This is done using resize_data() which will insert
227  // "difference" elements at the index specified as first argument
228  if (difference > 0) {
229  resize_data(m_rowstart[row+1], difference);
230  }
231 
232  // ... else if difference is negative then remove elements from
233  // the end of the array. This is done using resize_data() which
234  // will remove "difference" element from the index on specified as
235  // first argument
236  else if (difference < 0) {
237  resize_data(m_rowstart[row+1]+difference, difference);
238  }
239 
240  // Update row start indices
241  for (int i = row + 1; i <= nrows(); ++i) {
242  m_rowstart[i] += difference;
243  }
244 
245  // Update maximum column length
246  m_varlen = 0;
247  for (int i = 0; i < nrows(); ++i) {
248  int len = m_rowstart[row+1] - m_rowstart[row];
249  if (len > m_varlen) {
250  m_varlen = len;
251  }
252  }
253 
254  } // endif: we had a variable-length column
255 
256  // Return
257  return;
258 }
259 
260 
261 /***********************************************************************//**
262  * @brief Returns number of elements in column for specific row
263  *
264  * @param[in] row Row index.
265  * @return Number of elements in column at @p row.
266  *
267  * @exception GException::out_of_range
268  * Row index out of valid range.
269  *
270  * Returns the number of elements in the column for a specific @p row. For a
271  * fixed-length column the returned number is independent of the row. For a
272  * variable-length column the returned number is then length of the column
273  * for the specified row.
274  ***************************************************************************/
275 int GFitsTableCol::elements(const int& row) const
276 {
277  // Check row value
278  if (row < 0 || row >= nrows()) {
279  throw GException::out_of_range(G_ELEMENTS2, "Row index", row, nrows());
280  }
281 
282  // Get number of elements
283  int number = (m_variable) ? m_rowstart[row+1] - m_rowstart[row]
284  : m_number;
285 
286  // Return number
287  return number;
288 }
289 
290 
291 /***********************************************************************//**
292  * @brief Returns TFORM code for binary table column
293  *
294  * Constructs the TFORM code for a binary table column, supporting
295  * fixed-length and variable-length column types.
296  ***************************************************************************/
297 std::string GFitsTableCol::tform_binary(void) const
298 {
299  // Set type code string
300  std::string typecode = "";
301  switch (std::abs(type())) {
302  case __TBIT:
303  typecode = "X";
304  break;
305  case __TBYTE:
306  typecode = "B";
307  break;
308  case __TLOGICAL:
309  typecode = "L";
310  break;
311  case __TSTRING:
312  // If there are substrings then add width of substring
313  typecode = "A";
314  if (repeat() > width()) {
315  typecode.append(gammalib::str(width()));
316  }
317  break;
318  case __TUSHORT:
319  typecode = "U";
320  break;
321  case __TSHORT:
322  typecode = "I";
323  break;
324  case __TULONG:
325  typecode = "V";
326  break;
327  case __TLONG:
328  typecode = "J";
329  break;
330  case __TUINT:
331  typecode = "V";
332  break;
333  case __TINT:
334  typecode = "J";
335  break;
336  case __TFLOAT:
337  typecode = "E";
338  break;
339  case __TLONGLONG:
340  typecode = "K";
341  break;
342  case __TDOUBLE:
343  typecode = "D";
344  break;
345  case __TCOMPLEX:
346  typecode = "C";
347  break;
348  case __TDBLCOMPLEX:
349  typecode = "M";
350  break;
351  default:
352  break;
353  }
354 
355  // Build TFORM code
356  std::string tform;
357  if (std::abs(type()) == __TSTRING) {
358  tform.append(gammalib::str(repeat()));
359  }
360  else {
361  tform.append(gammalib::str(number()));
362  }
363  if (is_variable()) {
364  tform.append("P");
365  }
366  tform.append(typecode);
367  if (is_variable() && m_varlen > 0) {
368  tform.append("("+gammalib::str(m_varlen)+")");
369  }
370 
371  // Return TFORM code
372  return tform;
373 }
374 
375 
376 /***********************************************************************//**
377  * @brief Set table column scale value
378  *
379  * @param[in] tscale Table column scale value.
380  * @param[in] tzero Table column scale value.
381  *
382  * Sets the table column scale values @p tscale and @p tzero. When reading
383  * FITS table column values, the true value is computed using
384  *
385  * \f[
386  * {\rm true value} = {\rm FITS value} \times {\tm tscale} + {\tm tzero}
387  * \f]
388  *
389  * Setting of the @p tscale and @p tzero values will only be effective if
390  * this is done before the first reading of a table column value. Also, the
391  * setting will not affect the TSCALE and TZERO keywords that may exist in
392  * the FITS header.
393  ***************************************************************************/
394 void GFitsTableCol::scale(const double& tscale, const double& tzero) const
395 {
396  // Set tscale and tzero values
397  int status = 0;
398  status = __fftscl(FPTR(m_fitsfile), m_colnum, tscale, tzero, &status);
399 
400  // Return
401  return;
402 }
403 
404 
405 /***********************************************************************//**
406  * @brief Print column information
407  *
408  * @param[in] chatter Chattiness.
409  * @return String containing column information.
410  *
411  * @todo Format and cfitsio information is mainly for debugging. This could
412  * vanish in a more stable version of the code, or it could be compiled-in
413  * conditionally using a debug option. Alternatively, a higher chatter level
414  * may be required to see this information.
415  ***************************************************************************/
416 std::string GFitsTableCol::print(const GChatter& chatter) const
417 {
418  // Initialise result string
419  std::string result;
420 
421  // Continue only if chatter is not silent
422  if (chatter != SILENT) {
423 
424  // Append formatted column name. Optionally add units
425  if (unit().length() > 0) {
426  result.append(gammalib::parformat(name()+" ("+unit()+")"));
427  }
428  else {
429  result.append(gammalib::parformat(name()));
430  }
431 
432  // Append column number. This will be "-" if the column does not exist
433  // in the FITS file.
434  if (m_colnum > 0) {
435  result.append(gammalib::right(gammalib::str(m_colnum),4)+" ");
436  }
437  else {
438  result.append(gammalib::right("[-]",4)+" ");
439  }
440 
441  // Append loading information
442  if (is_loaded()) {
443  result.append("[loaded] ");
444  }
445  else {
446  result.append("[not loaded] ");
447  }
448 
449  // Append format information
450  result.append("["+tform_binary()+","+ascii_format()+"]");
451 
452  // Append dimensions (if available)
453  if (!dim().empty()) {
454 
455  // Build TDIM string
456  std::string value = "("+gammalib::str(dim()[0]);
457  for (int k = 1; k < dim().size(); ++k) {
458  value += ","+gammalib::str(dim()[k]);
459  }
460  value += ")";
461 
462  // Append
463  result.append(" "+value);
464  }
465 
466  // Append cfitsio information
467  if (is_variable()) {
468  result.append(" repeat=" + gammalib::str(repeat()));
469  result.append(" width=" + gammalib::str(width()));
470  result.append(" number=" + gammalib::str(number()));
471  result.append(" rows=" + gammalib::str(nrows()));
472  result.append(" size=" + gammalib::str(m_size));
473  result.append(" varlen=");
474  if (m_varlen > 0) {
475  result.append(gammalib::str(m_varlen));
476  }
477  else {
478  result.append("undetermined");
479  }
480  }
481  else {
482  result.append(" repeat=" + gammalib::str(repeat()));
483  result.append(" width=" + gammalib::str(width()));
484  result.append(" number=" + gammalib::str(number()));
485  result.append(" rows=" + gammalib::str(nrows()));
486  result.append(" size=" + gammalib::str(m_size));
487  }
488 
489  } // endif: chatter was not silent
490 
491  // Compile option: print content
492  #if defined(G_PRINT_CONTENT)
493  if (chatter != SILENT) {
494 
495  // Fetch data if necessary
496  if (!is_loaded()) fetch_data();
497 
498  // Loop over all rows
499  for (int row = 0; row < nrows(); ++row) {
500  result.append("\n");
501  if (is_variable()) {
502  result.append("start=");
503  result.append(gammalib::str(m_rowstart[row]));
504  result.append(":");
505  }
506  for (int inx = 0; inx < elements(row); ++inx) {
507  result.append(" "+string(row, inx));
508  }
509  }
510  if (is_variable()) {
511  result.append("\nend=");
512  result.append(gammalib::str(m_rowstart[nrows()]));
513  }
514  }
515  #endif
516 
517  // Return result
518  return result;
519 }
520 
521 
522 /*==========================================================================
523  = =
524  = Protected methods =
525  = =
526  ==========================================================================*/
527 
528 /***********************************************************************//**
529  * @brief Save table column into FITS file
530  *
531  * Refer to GFitsTableCol::save_column() for more information.
532  ***************************************************************************/
534 {
535  // Save column
536  save_column();
537 
538  // Return
539  return;
540 }
541 
542 
543 /***********************************************************************//**
544  * @brief Load table column from FITS file
545  *
546  * Loads table column from FITS file by calling the load_column_variable()
547  * method for variable-length columns and load_column_fixed() for fixed-
548  * length columns.
549  ***************************************************************************/
551 {
552  // Load variable-length or fixed-length column from FITS file
553  if (is_variable()) {
555  }
556  else {
558  }
559 
560  // Return
561  return;
562 }
563 
564 
565 /***********************************************************************//**
566  * @brief Load fixed-length column from FITS file
567  *
568  * @exception GException::fits_hdu_not_found
569  * Specified HDU not found in FITS file.
570  * @exception GException::fits_error
571  * An error occured while loading column data from FITS file.
572  *
573  * If a FITS file is attached to the column the data are loaded into memory
574  * from the FITS file. If no FITS file is attached, memory is allocated
575  * to hold the column data and all cells are set to 0.
576  *
577  * The method makes use of the virtual methods
578  * GFitsTableCol::alloc_data,
579  * GFitsTableCol::init_data,
580  * GFitsTableCol::ptr_data, and
581  * GFitsTableCol::ptr_nulval.
582  * These methods are implemented by the derived column classes which
583  * implement a specific storage class (i.e. float, double, short, ...).
584  ***************************************************************************/
586 {
587  // Calculate size of memory
589 
590  // Load only if the column has a positive size
591  if (m_size > 0) {
592 
593  // Allocate and initialise fresh memory
594  alloc_data();
595  init_data();
596 
597  // If a FITS file is attached then try loading column data from the
598  // FITS file. This may fail in case that no data has yet been written
599  // to the FITS file. In that case we just skip loading and return
600  // the initalised column ...
601  if (FPTR(m_fitsfile)->Fptr != NULL) {
602 
603  // Move to the HDU
604  int status = 0;
605  status = __ffmahd(FPTR(m_fitsfile),
606  (FPTR(m_fitsfile)->HDUposition)+1,
607  NULL, &status);
608 
609  // If this failed because:
610  // - the primary HDU was not found (status 252)
611  // - we moved past the file (status 107)
612  // we assume that no data have yet been written to the file and
613  // we skip the loading.
614  if (status != 252 && status != 107) {
615 
616  // Break on any other cfitsio error
617  if (status != 0) {
619  (FPTR(m_fitsfile)->HDUposition)+1,
620  status);
621  }
622 
623  // Load data
624  status = __ffgcv(FPTR(m_fitsfile), m_type, m_colnum,
625  1, 1, m_size, ptr_nulval(), ptr_data(),
626  &m_anynul, &status);
627  if (status != 0) {
629  "for column '"+m_name+"'.");
630  }
631 
632  } // endif: no primary HDU found
633 
634  } // endif: there was a FITS file attached
635 
636  } // endif: column has a positive size
637 
638  // Return
639  return;
640 }
641 
642 
643 /***********************************************************************//**
644  * @brief Load variable-length column from FITS file
645  *
646  * @exception GException::fits_hdu_not_found
647  * Specified HDU not found in FITS file.
648  * @exception GException::fits_error
649  * An error occured while loading column data from FITS file.
650  *
651  * If a FITS file is attached to the column the data are loaded into memory
652  * from the FITS file. If no FITS file is attached, memory is allocated
653  * to hold the column data and all cells are set to 0.
654  *
655  * The method makes use of the virtual methods
656  * GFitsTableCol::alloc_data,
657  * GFitsTableCol::init_data,
658  * GFitsTableCol::ptr_data, and
659  * GFitsTableCol::ptr_nulval.
660  * These methods are implemented by the derived column classes which
661  * implement a specific storage class (i.e. float, double, short, ...).
662  ***************************************************************************/
664 {
665  // If a FITS file is attached then try loading column data from the
666  // FITS file. This may fail in case that no data has yet been written
667  // to the FITS file. In that case we just skip loading and return
668  // the initalised column ...
669  if (FPTR(m_fitsfile)->Fptr != NULL) {
670 
671  // Move to the HDU
672  int status = 0;
673  status = __ffmahd(FPTR(m_fitsfile),
674  (FPTR(m_fitsfile)->HDUposition)+1,
675  NULL,
676  &status);
677 
678  // If this failed because:
679  // - the primary HDU was not found (status 252)
680  // - we moved past the file (status 107)
681  // we assume that no data have yet been written to the file and
682  // we skip the loading.
683  if (status != 252 && status != 107) {
684 
685  // Break on any other cfitsio error
686  if (status != 0) {
688  (FPTR(m_fitsfile)->HDUposition)+1,
689  status);
690  }
691 
692  // Allocate rowstart array
693  m_rowstart.assign(m_length+1, 0);
694 
695  // Determine the column length for each row by looping over
696  // all rows and derive the total memory requirement
697  m_size = 0;
698  m_varlen = 0;
699  m_rowstart[0] = 0;
700  for (int row = 0; row < m_length; ++row) {
701 
702  // Initialise offset and repeat
703  long offset(0);
704  long repeat(0);
705 
706  // Get variable-length of row in repeat
707  status = __ffgdes(FPTR(m_fitsfile),
708  m_colnum,
709  row+1,
710  &repeat,
711  &offset,
712  &status);
713  if (status != 0) {
714  std::string msg = "Unable to get descriptor of row "+
715  gammalib::str(row+1)+" of column '"+
716  name()+"' from FITS file.";
718  msg);
719  }
720 
721  // Store start of next row
722  m_rowstart[row+1] = m_rowstart[row] + repeat;
723  m_size += repeat;
724  if (repeat > m_varlen) {
725  m_varlen = repeat;
726  }
727 
728  } // endfor: looped over all rows
729 
730  // Allocate and initialise fresh memory
731  alloc_data();
732  init_data();
733 
734  // Load data for each row
735  for (int row = 0; row < m_length; ++row) {
736 
737  // Initialise anynul
738  int anynul(0);
739 
740  // Load data
741  status = __ffgcv(FPTR(m_fitsfile),
742  std::abs(m_type),
743  m_colnum,
744  row+1,
745  1,
746  elements(row),
747  ptr_nulval(),
748  ptr_data(m_rowstart[row]),
749  &anynul,
750  &status);
751  if (status != 0) {
752  std::string msg = "Unable to load row "+gammalib::str(row+1)+""
753  " of column '"+name()+"' from FITS file.";
755  msg);
756  }
757 
758  // Increment anynul
759  m_anynul += anynul;
760 
761  } // endfor: looped over all rows
762 
763  } // endif: no primary HDU found
764 
765  } // endif: there was a FITS file attached
766 
767  // Return
768  return;
769 }
770 
771 
772 /***********************************************************************//**
773  * @brief Save table column into FITS file
774  *
775  * Save table column into FITS file by calling the save_column_variable()
776  * method for variable-length columns and save_column_fixed() for fixed-
777  * length columns.
778  ***************************************************************************/
780 {
781  // Save variable-length or fixed-length column into FITS file
782  if (is_variable()) {
784  }
785  else {
787  }
788 
789  // Return
790  return;
791 }
792 
793 
794 /***********************************************************************//**
795  * @brief Save table column into FITS file
796  *
797  * @exception GException::fits_hdu_not_found
798  * Specified HDU not found in FITS file.
799  * @exception GException::fits_error
800  * Error occured during writing of the column data.
801  *
802  * The table column is only saved if it is linked to a FITS file and if the
803  * data are indeed present in the class instance. This avoids saving of data
804  * that have not been modified.
805  *
806  * The method make use of the virtual methods
807  * GFitsTableCol::ptr_data and
808  * GFitsTableCol::ptr_nulval.
809  * These methods are implemented by the derived column classes which
810  * implement a specific storage class (i.e. float, double, short, ...).
811  ***************************************************************************/
813 {
814  // Continue only if a FITS file is connected and data have been loaded
815  if (FPTR(m_fitsfile)->Fptr != NULL && m_colnum > 0 && ptr_data() != NULL) {
816 
817  // Move to the HDU
818  int status = 0;
819  status = __ffmahd(FPTR(m_fitsfile),
820  (FPTR(m_fitsfile)->HDUposition)+1, NULL,
821  &status);
822  if (status != 0) {
824  (FPTR(m_fitsfile)->HDUposition)+1,
825  status);
826  }
827 
828  // Save the column data
829  status = __ffpcn(FPTR(m_fitsfile), m_type, m_colnum, 1, 1,
830  m_size, ptr_data(), ptr_nulval(), &status);
831  if (status != 0) {
832  std::string msg = "Unable to save column '"+name()+"' to"
833  " FITS file.";
834  throw GException::fits_error(G_SAVE_COLUMN_FIXED, status, msg);
835  }
836 
837  } // endif: FITS file was connected
838 
839  // Return
840  return;
841 }
842 
843 
844 /***********************************************************************//**
845  * @brief Save table column into FITS file
846  *
847  * @exception GException::fits_hdu_not_found
848  * Specified HDU not found in FITS file.
849  * @exception GException::fits_error
850  * Error occured during writing of the column data.
851  *
852  * The table column is only saved if it is linked to a FITS file and if the
853  * data are indeed present in the class instance. This avoids saving of data
854  * that have not been modified.
855  *
856  * The method make use of the virtual methods
857  * GFitsTableCol::ptr_data and
858  * GFitsTableCol::ptr_nulval.
859  * These methods are implemented by the derived column classes which
860  * implement a specific storage class (i.e. float, double, short, ...).
861  ***************************************************************************/
863 {
864  // Continue only if a FITS file is connected and data have been loaded
865  if (FPTR(m_fitsfile)->Fptr != NULL && m_colnum > 0 && ptr_data() != NULL) {
866 
867  // Move to the HDU
868  int status = 0;
869  status = __ffmahd(FPTR(m_fitsfile),
870  (FPTR(m_fitsfile)->HDUposition)+1, NULL,
871  &status);
872  if (status != 0) {
874  (FPTR(m_fitsfile)->HDUposition)+1,
875  status);
876  }
877 
878  // Save the column data row-by-row
879  for (int row = 0; row < m_length; ++row) {
880 
881  // Save row data
882  status = __ffpcn(FPTR(m_fitsfile),
883  std::abs(m_type),
884  m_colnum,
885  row+1,
886  1,
887  elements(row),
888  ptr_data(m_rowstart[row]),
889  ptr_nulval(),
890  &status);
891  if (status != 0) {
892  std::string msg = "Unable to save row "+gammalib::str(row+1)+""
893  " of column '"+name()+"' to FITS file.";
895  msg);
896  }
897 
898  } // endfor: looped over rows
899 
900  } // endif: FITS file was connected
901 
902  // Return
903  return;
904 }
905 
906 
907 /***********************************************************************//**
908  * @brief Compute offset of column element in memory
909  *
910  * @param[in] row Row of column.
911  * @param[in] inx Vector index in column row.
912  *
913  * @exception GException::out_of_range
914  * Table row or vector index are out of valid range.
915  *
916  * Computes the offset of a column element in the storage array from the
917  * @p row number and the vector index. The method also supports both
918  * variable-length and fixed-length columns.
919  ***************************************************************************/
920 int GFitsTableCol::offset(const int& row, const int& inx) const
921 {
922  // Check row value
923  #if defined(G_RANGE_CHECK)
924  if (row < 0 || row >= m_length) {
925  throw GException::out_of_range(G_OFFSET, row, 0, m_length-1);
926  }
927  #endif
928 
929  // Check inx value
930  #if defined(G_RANGE_CHECK)
931  if (inx < 0 || inx >= elements(row)) {
932  throw GException::out_of_range(G_OFFSET, inx, 0, elements(row));
933  }
934  #endif
935 
936  // Calculate pixel offset
937  int offset = (is_variable()) ? m_rowstart[row] + inx : row * m_number + inx;
938 
939  // Return offset
940  return offset;
941 }
942 
943 
944 /*==========================================================================
945  = =
946  = Private methods =
947  = =
948  ==========================================================================*/
949 
950 /***********************************************************************//**
951  * @brief Initialise class members
952  ***************************************************************************/
954 {
955  // Optionally print call graph
956  #if defined(G_CALL_GRAPH)
957  printf("GFitsTableCol::init_members\n");
958  #endif
959 
960  // Allocate FITS file pointer
961  m_fitsfile = new __fitsfile;
962  FPTR(m_fitsfile)->HDUposition = 0;
963  FPTR(m_fitsfile)->Fptr = NULL;
964 
965  // Initialise members
966  m_name.clear();
967  m_unit.clear();
968  m_dim.clear();
969  m_rowstart.clear();
970  m_colnum = 0;
971  m_type = 0;
972  m_repeat = 0;
973  m_width = 0;
974  m_number = 0;
975  m_length = 0;
976  m_variable = false;
977  m_varlen = 0;
978  m_size = 0;
979  m_anynul = 0;
980 
981  // Optionally print call graph
982  #if defined(G_CALL_GRAPH)
983  printf("exit GFitsTableCol::init_members\n");
984  #endif
985 
986  // Return
987  return;
988 }
989 
990 
991 /***********************************************************************//**
992  * @brief Copy class members
993  *
994  * @param[in] column Column to be copied.
995  ***************************************************************************/
997 {
998  // Copy attributes
999  m_name = column.m_name;
1000  m_unit = column.m_unit;
1001  m_dim = column.m_dim;
1002  m_colnum = column.m_colnum;
1003  m_type = column.m_type;
1004  m_repeat = column.m_repeat;
1005  m_width = column.m_width;
1006  m_number = column.m_number;
1007  m_length = column.m_length;
1008  m_variable = column.m_variable;
1009  m_varlen = column.m_varlen;
1010  m_rowstart = column.m_rowstart;
1011  m_size = column.m_size;
1012  m_anynul = column.m_anynul;
1013  FPTR_COPY(m_fitsfile, column.m_fitsfile);
1014 
1015  // Return
1016  return;
1017 }
1018 
1019 
1020 /***********************************************************************//**
1021  * @brief Delete class members
1022  ***************************************************************************/
1024 {
1025  // Optionally print call graph
1026  #if defined(G_CALL_GRAPH)
1027  printf("GFitsTableCol::free_members\n");
1028  #endif
1029 
1030  // Free memory
1031  if (m_fitsfile != NULL) delete FPTR(m_fitsfile);
1032 
1033  // Mark memory as free
1034  m_fitsfile = NULL;
1035 
1036  // Optionally print call graph
1037  #if defined(G_CALL_GRAPH)
1038  printf("exit GFitsTableCol::free_members\n");
1039  #endif
1040 
1041  // Return
1042  return;
1043 }
1044 
1045 
1046 /***********************************************************************//**
1047  * @brief Connect table column to FITS file
1048  *
1049  * @param[in] vptr Column file void pointer.
1050  *
1051  * A table column is connected to a FITS file when the m_fitsfile holds a
1052  * FITS file pointer. In that way, the column knows to which file it belongs.
1053  ***************************************************************************/
1054 void GFitsTableCol::connect(void* vptr)
1055 {
1056  // Connect table column by copying the column file pointer
1057  FPTR_COPY(m_fitsfile, vptr);
1058 
1059  // Return
1060  return;
1061 }
#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
Returns 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:1046
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:1163
void scale(const double &tscale, const double &tzero) const
Set table column scale value.
int m_number
Number of elements in column.
virtual ~GFitsTableCol(void)
Destructor.
void free_members(void)
Delete class members.
#define G_LOAD_COLUMN_VARIABLE
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:973
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.
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:1022
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:413