Commit bb8039af995d0c7d527da9962f401c3084dd6234

Authored by knodlseder
1 parent e9039de9

read and validate TDIM information in data_open() and set unit and TDIM keywords in data_save()

Showing 1 changed file with 141 additions and 68 deletions
src/fits/GFitsTable.cpp
@@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
30 #endif 30 #endif
31 #include <cstring> 31 #include <cstring>
32 #include <iostream> 32 #include <iostream>
  33 +#include <vector>
33 #include "GException.hpp" 34 #include "GException.hpp"
34 #include "GTools.hpp" 35 #include "GTools.hpp"
35 #include "GFitsCfitsio.hpp" 36 #include "GFitsCfitsio.hpp"
@@ -56,8 +57,6 @@ @@ -56,8 +57,6 @@
56 #define G_INSERT_COLUMN "GFitsTable::insert_column(int, GFitsTableCol*)" 57 #define G_INSERT_COLUMN "GFitsTable::insert_column(int, GFitsTableCol*)"
57 #define G_INSERT_ROWS "GFitsTable::insert_rows(int&, int&)" 58 #define G_INSERT_ROWS "GFitsTable::insert_rows(int&, int&)"
58 #define G_REMOVE_ROWS "GFitsTable::remove_rows(int&, int&)" 59 #define G_REMOVE_ROWS "GFitsTable::remove_rows(int&, int&)"
59 -//#define G_COLUMN1 "GFitsTable::column(std::string&)"  
60 -//#define G_COLUMN2 "GFitsTable::column(int&)"  
61 #define G_OPEN_DATA "GFitsTable::open_data(void*)" 60 #define G_OPEN_DATA "GFitsTable::open_data(void*)"
62 #define G_SAVE_DATA "GFitsTable::save_data()" 61 #define G_SAVE_DATA "GFitsTable::save_data()"
63 #define G_GET_TFORM "GFitsTable::get_tform(int&)" 62 #define G_GET_TFORM "GFitsTable::get_tform(int&)"
@@ -262,20 +261,8 @@ GFitsTableCol&amp; GFitsTable::operator[](const std::string&amp; colname) @@ -262,20 +261,8 @@ GFitsTableCol&amp; GFitsTable::operator[](const std::string&amp; colname)
262 throw GException::fits_no_data(G_ACCESS2, "No columns in table."); 261 throw GException::fits_no_data(G_ACCESS2, "No columns in table.");
263 } 262 }
264 263
265 - // Initialise pointer  
266 - GFitsTableCol* ptr = NULL;  
267 -  
268 - // Search for the specified name  
269 - for (int i = 0; i < m_cols; ++i) {  
270 - if (m_columns[i]->name() == colname) {  
271 - ptr = m_columns[i];  
272 - if (ptr == NULL) {  
273 - throw GException::fits_no_data(G_ACCESS2,  
274 - "No data for this column");  
275 - }  
276 - break;  
277 - }  
278 - } 264 + // Get column pointer
  265 + GFitsTableCol* ptr = ptr_column(colname);
279 266
280 // If column has not been found throw an exception 267 // If column has not been found throw an exception
281 if (ptr == NULL) { 268 if (ptr == NULL) {
@@ -304,20 +291,8 @@ const GFitsTableCol&amp; GFitsTable::operator[](const std::string&amp; colname) const @@ -304,20 +291,8 @@ const GFitsTableCol&amp; GFitsTable::operator[](const std::string&amp; colname) const
304 throw GException::fits_no_data(G_ACCESS2, "No columns in table."); 291 throw GException::fits_no_data(G_ACCESS2, "No columns in table.");
305 } 292 }
306 293
307 - // Initialise pointer  
308 - const GFitsTableCol* ptr = NULL;  
309 -  
310 - // If there are columns then search for the specified name  
311 - for (int i = 0; i < m_cols; ++i) {  
312 - if (m_columns[i]->name() == colname) {  
313 - ptr = m_columns[i];  
314 - if (ptr == NULL) {  
315 - throw GException::fits_no_data(G_ACCESS2,  
316 - "No data for this column");  
317 - }  
318 - break;  
319 - }  
320 - } 294 + // Get column pointer
  295 + GFitsTableCol* ptr = ptr_column(colname);
321 296
322 // If column has not been found throw an exception 297 // If column has not been found throw an exception
323 if (ptr == NULL) { 298 if (ptr == NULL) {
@@ -585,37 +560,6 @@ GFitsTableCol* GFitsTable::column(const std::string&amp; colname) @@ -585,37 +560,6 @@ GFitsTableCol* GFitsTable::column(const std::string&amp; colname)
585 } 560 }
586 */ 561 */
587 562
588 -/***********************************************************************//**  
589 - * @brief Return pointer to column with number  
590 - *  
591 - * @param[in] colnum Number of requested column (starting from 0)  
592 - *  
593 - * @exception GException::fits_no_data  
594 - * There are no column data in the table or there is not data  
595 - * for this column  
596 - * @exception GException::out_of_range  
597 - * Requested column has not been found in table.  
598 - ***************************************************************************/  
599 -/*  
600 -GFitsTableCol* GFitsTable::column(const int& colnum)  
601 -{  
602 - // If there is no data then throw an exception  
603 - if (m_columns == NULL)  
604 - throw GException::fits_no_data(G_COLUMN2, "No column data in table");  
605 -  
606 - // If column number is out of range then throw an exception  
607 - if (colnum < 0 || colnum >= m_cols)  
608 - throw GException::out_of_range(G_COLUMN2, colnum, 0, m_cols-1);  
609 -  
610 - // Get column pointer  
611 - GFitsTableCol* ptr = ptr = m_columns[colnum];  
612 - if (ptr == NULL)  
613 - throw GException::fits_no_data(G_COLUMN2, "No data for this column");  
614 -  
615 - // Return column pointer  
616 - return ptr;  
617 -}  
618 -*/  
619 563
620 /***********************************************************************//** 564 /***********************************************************************//**
621 * @brief Return number of rows in table 565 * @brief Return number of rows in table
@@ -638,6 +582,19 @@ int GFitsTable::ncols(void) const @@ -638,6 +582,19 @@ int GFitsTable::ncols(void) const
638 582
639 583
640 /***********************************************************************//** 584 /***********************************************************************//**
  585 + * @brief Checks the presence of a column in table
  586 + ***************************************************************************/
  587 +bool GFitsTable::has(const std::string& colname) const
  588 +{
  589 + // Get pointer in column
  590 + GFitsTableCol* ptr = ptr_column(colname);
  591 +
  592 + // Return state
  593 + return (ptr != NULL);
  594 +}
  595 +
  596 +
  597 +/***********************************************************************//**
641 * @brief Print table information 598 * @brief Print table information
642 ***************************************************************************/ 599 ***************************************************************************/
643 std::string GFitsTable::print(void) const 600 std::string GFitsTable::print(void) const
@@ -707,10 +664,13 @@ std::string GFitsTable::print(void) const @@ -707,10 +664,13 @@ std::string GFitsTable::print(void) const
707 * A CFITSIO error occured during loading the table. 664 * A CFITSIO error occured during loading the table.
708 * @exception GException::fits_unknown_coltype 665 * @exception GException::fits_unknown_coltype
709 * FITS column of unsupported type has been found in the FITS file. 666 * FITS column of unsupported type has been found in the FITS file.
  667 + * @exception GException::fits_inconsistent_tdim
  668 + * The TDIM information provided in the header is inconsistent
  669 + * with the size of the column.
710 * 670 *
711 - * Builds a description of the table in memory.  
712 - * Columns are not loaded but column descriptors are allocated.  
713 - * The column data will only be loaded once it needs to be accessed. 671 + * This method loads a description of the table into memory. Column data are
  672 + * not loaded at this point to save memory. They will be loaded on request
  673 + * later.
714 ***************************************************************************/ 674 ***************************************************************************/
715 void GFitsTable::data_open(void* vptr) 675 void GFitsTable::data_open(void* vptr)
716 { 676 {
@@ -799,6 +759,29 @@ void GFitsTable::data_open(void* vptr) @@ -799,6 +759,29 @@ void GFitsTable::data_open(void* vptr)
799 else 759 else
800 unit[strlen(unit)-1] = '\0'; 760 unit[strlen(unit)-1] = '\0';
801 761
  762 + // Get column dimension (optional, leave blank if not found)
  763 + char dim[80];
  764 + sprintf(keyname, "TDIM%d", i+1);
  765 + status = __ffgkey(FPTR(m_fitsfile), keyname, dim, NULL, &status);
  766 + if (status != 0) {
  767 + status = 0;
  768 + dim[0] = '\0';
  769 + dim[1] = '\0';
  770 + }
  771 + else {
  772 + dim[strlen(dim)-1] = '\0';
  773 + }
  774 +
  775 + // If found, extract column dimension into vector array of integers
  776 + std::vector<int> vdim;
  777 + std::string sdim = strip_chars(strip_whitespace(&(dim[1])),"()");
  778 + if (sdim.length() > 0) {
  779 + std::vector<std::string> elements = split(sdim, ",");
  780 + for (int k = 0; k < elements.size(); ++k) {
  781 + vdim.push_back(toint(elements[k]));
  782 + }
  783 + }
  784 +
802 // Allocate column 785 // Allocate column
803 m_columns[i] = alloc_column(typecode); 786 m_columns[i] = alloc_column(typecode);
804 if (m_columns[i] == NULL) { 787 if (m_columns[i] == NULL) {
@@ -811,6 +794,7 @@ void GFitsTable::data_open(void* vptr) @@ -811,6 +794,7 @@ void GFitsTable::data_open(void* vptr)
811 // Store column definition 794 // Store column definition
812 m_columns[i]->name(strip_whitespace(&(value[1]))); 795 m_columns[i]->name(strip_whitespace(&(value[1])));
813 m_columns[i]->unit(strip_whitespace(&(unit[1]))); 796 m_columns[i]->unit(strip_whitespace(&(unit[1])));
  797 + m_columns[i]->dim(vdim);
814 m_columns[i]->m_colnum = i+1; 798 m_columns[i]->m_colnum = i+1;
815 m_columns[i]->m_type = typecode; 799 m_columns[i]->m_type = typecode;
816 m_columns[i]->m_repeat = repeat; 800 m_columns[i]->m_repeat = repeat;
@@ -819,15 +803,36 @@ void GFitsTable::data_open(void* vptr) @@ -819,15 +803,36 @@ void GFitsTable::data_open(void* vptr)
819 m_columns[i]->connect(FPTR(m_fitsfile)); 803 m_columns[i]->connect(FPTR(m_fitsfile));
820 804
821 // Extract column vector size 805 // Extract column vector size
822 - if (m_columns[i]->m_repeat == 1) // ASCII tables 806 + if (m_columns[i]->m_repeat == 1) { // ASCII tables
823 m_columns[i]->m_number = 1; 807 m_columns[i]->m_number = 1;
  808 + }
824 else { // Binary tables 809 else { // Binary tables
825 - if (typecode == __TSTRING) 810 + if (typecode == __TSTRING) {
826 m_columns[i]->m_number = m_columns[i]->m_repeat / 811 m_columns[i]->m_number = m_columns[i]->m_repeat /
827 m_columns[i]->m_width; 812 m_columns[i]->m_width;
828 - else 813 + }
  814 + else {
829 m_columns[i]->m_number = m_columns[i]->m_repeat; 815 m_columns[i]->m_number = m_columns[i]->m_repeat;
  816 + }
830 } 817 }
  818 +
  819 + // If TDIM information was set then check its consistency
  820 + if (vdim.size() > 0) {
  821 +
  822 + // Compute expectation
  823 + int num = vdim[0];
  824 + for (int k = 1; k < vdim.size(); ++k) {
  825 + num *= vdim[k];
  826 + }
  827 +
  828 + // Compare with real size
  829 + if (num != m_columns[i]->m_number) {
  830 + throw GException::fits_inconsistent_tdim(G_OPEN_DATA,
  831 + vdim,
  832 + m_columns[i]->m_number);
  833 + }
  834 +
  835 + } // endif: Valid TDIM information was found
831 836
832 } // endfor: looped over all columns 837 } // endfor: looped over all columns
833 838
@@ -1122,7 +1127,46 @@ void GFitsTable::data_save(void) @@ -1122,7 +1127,46 @@ void GFitsTable::data_save(void)
1122 1127
1123 } // endelse: FITS table has been updated 1128 } // endelse: FITS table has been updated
1124 1129
1125 - // Now update the header 1130 + // Now update the header for all columns (unit and TDIM information)
  1131 + for (int i = 0; i < m_cols; ++i) {
  1132 +
  1133 + // Only consider valid columns
  1134 + if (m_columns[i] != NULL) {
  1135 +
  1136 + // Get column number
  1137 + int colnum = m_columns[i]->m_colnum;
  1138 +
  1139 + // Update column units if available
  1140 + if (m_columns[i]->unit().length() > 0) {
  1141 +
  1142 + // Build keyname
  1143 + std::string keyname = "TUNIT"+str(colnum);
  1144 +
  1145 + // Update header card
  1146 + card(keyname, m_columns[i]->unit(), "physical unit of field");
  1147 + }
  1148 +
  1149 + // Write TDIM keyword if available
  1150 + if (m_columns[i]->dim().size() > 0) {
  1151 +
  1152 + // Build keyname
  1153 + std::string keyname = "TDIM"+str(colnum);
  1154 +
  1155 + // Build value string
  1156 + std::string value = "("+str(m_columns[i]->dim()[0]);
  1157 + for (int k = 1; k < m_columns[i]->dim().size(); ++k) {
  1158 + value += ","+str(m_columns[i]->dim()[k]);
  1159 + }
  1160 + value += ")";
  1161 +
  1162 + // Update header card
  1163 + card(keyname, value, "dimensions of field");
  1164 +
  1165 + } // endif: wrote TDIM keyword
  1166 +
  1167 + } // endif: column was valid
  1168 +
  1169 + } // endfor: looped over all columns
1126 1170
1127 // Debug definition: Dump method exit 1171 // Debug definition: Dump method exit
1128 #if defined(G_DEBUG_SAVE) 1172 #if defined(G_DEBUG_SAVE)
@@ -1415,6 +1459,35 @@ GFitsTableCol* GFitsTable::alloc_column(int typecode) const @@ -1415,6 +1459,35 @@ GFitsTableCol* GFitsTable::alloc_column(int typecode) const
1415 } 1459 }
1416 1460
1417 1461
  1462 +/***********************************************************************//**
  1463 + * @brief Returns pointer of column with given name
  1464 + *
  1465 + * @param[in] colname Name of column.
  1466 + *
  1467 + * This method returns a pointer on the column with the specified name. It
  1468 + * returns NULL if no column with the given name was found, or if the
  1469 + * column is not allocated.
  1470 + ***************************************************************************/
  1471 +GFitsTableCol* GFitsTable::ptr_column(const std::string& colname) const
  1472 +{
  1473 + // Initialise pointer
  1474 + GFitsTableCol* ptr = NULL;
  1475 +
  1476 + // If there are columns then search for the specified name
  1477 + if (m_columns != NULL) {
  1478 + for (int i = 0; i < m_cols; ++i) {
  1479 + if (m_columns[i]->name() == colname) {
  1480 + ptr = m_columns[i];
  1481 + break;
  1482 + }
  1483 + }
  1484 + }
  1485 +
  1486 + // Return pointer
  1487 + return ptr;
  1488 +}
  1489 +
  1490 +
1418 /*========================================================================== 1491 /*==========================================================================
1419 = = 1492 = =
1420 = Friends = 1493 = Friends =