Commit bb8039af995d0c7d527da9962f401c3084dd6234
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& GFitsTable::operator[](const std::string& colname) | @@ -262,20 +261,8 @@ GFitsTableCol& GFitsTable::operator[](const std::string& 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& GFitsTable::operator[](const std::string& colname) const | @@ -304,20 +291,8 @@ const GFitsTableCol& GFitsTable::operator[](const std::string& 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& colname) | @@ -585,37 +560,6 @@ GFitsTableCol* GFitsTable::column(const std::string& 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 = |