// Astrophysics Science Division, // NASA/ Goddard Space Flight Center // HEASARC // http://heasarc.gsfc.nasa.gov // e-mail: ccfits@legacy.gsfc.nasa.gov // // Original author: Ben Dorman #ifndef COLUMNDATA_H #define COLUMNDATA_H 1 #include "CCfits.h" // vector #include // Column #include "Column.h" #ifdef _MSC_VER #include "MSconfig.h" #endif #include #include #include #include "FITSUtil.h" using std::complex; #include "FITS.h" namespace CCfits { template class ColumnData : public Column //## Inherits: %385E51565EE8 { public: ColumnData(const ColumnData< T > &right); ColumnData (Table* p = 0); ColumnData (int columnIndex, const string &columnName, ValueType type, const String &format, const String &unit, Table* p, int rpt = 1, long w = 1, const String &comment = ""); ~ColumnData(); virtual ColumnData* clone () const; virtual void readData (long firstRow, long nelements, long firstElem = 1); void setDataLimits (T* limits); const T minLegalValue () const; void minLegalValue (T value); const T maxLegalValue () const; void maxLegalValue (T value); const T minDataValue () const; void minDataValue (T value); const T maxDataValue () const; void maxDataValue (T value); const std::vector& data () const; void setData (const std::vector& value); T data (int i); void data (int i, T value); // Additional Public Declarations friend class Column; protected: // Additional Protected Declarations private: ColumnData< T > & operator=(const ColumnData< T > &right); void readColumnData (long firstRow, long nelements, T* nullValue = 0); virtual bool compare (const Column &right) const; virtual std::ostream& put (std::ostream& s) const; void writeData (T* indata, long nRows = 1, long firstRow = 1, T* nullValue = 0); void writeData (const std::vector& indata, long firstRow = 1, T* nullValue = 0); // Insert one or more blank rows into a FITS column. virtual void insertRows (long first, long number = 1); virtual void deleteRows (long first, long number = 1); // Additional Private Declarations private: //## implementation // Data Members for Class Attributes T m_minLegalValue; T m_maxLegalValue; T m_minDataValue; T m_maxDataValue; // Data Members for Associations std::vector m_data; // Additional Implementation Declarations }; // Parameterized Class CCfits::ColumnData template inline void ColumnData::readData (long firstRow, long nelements, long firstElem) { readColumnData(firstRow,nelements,static_cast(0)); } template inline const T ColumnData::minLegalValue () const { return m_minLegalValue; } template inline void ColumnData::minLegalValue (T value) { m_minLegalValue = value; } template inline const T ColumnData::maxLegalValue () const { return m_maxLegalValue; } template inline void ColumnData::maxLegalValue (T value) { m_maxLegalValue = value; } template inline const T ColumnData::minDataValue () const { return m_minDataValue; } template inline void ColumnData::minDataValue (T value) { m_minDataValue = value; } template inline const T ColumnData::maxDataValue () const { return m_maxDataValue; } template inline void ColumnData::maxDataValue (T value) { m_maxDataValue = value; } template inline const std::vector& ColumnData::data () const { return m_data; } template inline void ColumnData::setData (const std::vector& value) { m_data = value; } template inline T ColumnData::data (int i) { // return data stored in the ith row, which is in the i-1 th location in the array. return m_data[i - 1]; } template inline void ColumnData::data (int i, T value) { // assign data to i-1 th location in the array, representing the ith row. m_data[i - 1] = value; } // Parameterized Class CCfits::ColumnData template ColumnData::ColumnData(const ColumnData &right) :Column(right), m_minLegalValue(right.m_minLegalValue), m_maxLegalValue(right.m_maxLegalValue), m_minDataValue(right.m_minDataValue), m_maxDataValue(right.m_maxDataValue), m_data(right.m_data) { } template ColumnData::ColumnData (Table* p) : Column(p), m_minLegalValue(), m_maxLegalValue(), m_minDataValue(), m_maxDataValue(), m_data() { } template ColumnData::ColumnData (int columnIndex, const string &columnName, ValueType type, const String &format, const String &unit, Table* p, int rpt, long w, const String &comment) : Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment), m_minLegalValue(), m_maxLegalValue(), m_minDataValue(), m_maxDataValue(), m_data() { } template ColumnData::~ColumnData() { } template void ColumnData::readColumnData (long firstRow, long nelements, T* nullValue) { if ( rows() < nelements ) { std::cerr << "CCfits: More data requested than contained in table. "; std::cerr << "Extracting complete column.\n"; nelements = rows(); } int status(0); int anynul(0); FITSUtil::auto_array_ptr array(new T[nelements]); makeHDUCurrent(); if ( fits_read_col(fitsPointer(),type(), index(), firstRow, 1, nelements, nullValue, array.get(), &anynul, &status) ) throw FitsError(status); if (m_data.size() != static_cast( rows() ) ) m_data.resize(rows()); std::copy(&array[0],&array[nelements],m_data.begin()+firstRow-1); if (nelements == rows()) isRead(true); } template bool ColumnData::compare (const Column &right) const { if ( !Column::compare(right) ) return false; const ColumnData& that = static_cast&>(right); unsigned int n = m_data.size(); if ( that.m_data.size() != n ) return false; for (unsigned int i = 0; i < n ; i++) { if (m_data[i] != that.m_data[i]) return false; } return true; } template ColumnData* ColumnData::clone () const { return new ColumnData(*this); } template std::ostream& ColumnData::put (std::ostream& s) const { Column::put(s); if (FITS::verboseMode() && type() != Tstring) { s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n" << " Column Data limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n"; } if (!m_data.empty()) { std::ostream_iterator output(s,"\n"); // output each row on a separate line. // user can supply manipulators to stream for formatting. std::copy(m_data.begin(),m_data.end(),output); } return s; } template void ColumnData::writeData (T* indata, long nRows, long firstRow, T* nullValue) { // set columnData's data member to equal what's written to file. // indata has size nRows: elements firstRow to firstRow + nRows - 1 will be written. // if this exceeds the current rowlength of the HDU, update the return value for // rows() in the parent after the fitsio call. int status(0); long elementsToWrite(nRows + firstRow -1); // get a copy for restorative action. std::vector __tmp(m_data); if (elementsToWrite > static_cast(m_data.size())) { m_data.resize(elementsToWrite,T()); } std::copy(&indata[0],&indata[nRows],m_data.begin()+firstRow-1); // if successful, write to disk. try { if (nullValue) { if (fits_write_colnull(fitsPointer(), type(), index(), firstRow, 1, nRows, indata, nullValue, &status) != 0) throw FitsError(status); } else { if (fits_write_col(fitsPointer(), type(), index(), firstRow, 1, nRows, indata, &status) != 0) throw FitsError(status); } // tell the Table that the number of rows has changed parent()->updateRows(); } catch (FitsError) // the only thing that can throw here. { // reset to original content and rethrow the exception. m_data = __tmp; if (status == NO_NULL) throw NoNullValue(name()); else throw; } } template void ColumnData::writeData (const std::vector& indata, long firstRow, T* nullValue) { FITSUtil::CVarray convert; FITSUtil::auto_array_ptr pcolData (convert(indata)); T* columnData = pcolData.get(); writeData(columnData,indata.size(),firstRow,nullValue); } template void ColumnData::insertRows (long first, long number) { FITSUtil::FitsNullValue blank; typename std::vector::iterator in; if (first !=0) { in = m_data.begin()+first; } else { in = m_data.begin(); } // non-throwing operations. m_data.insert(in,number,blank()); } template void ColumnData::deleteRows (long first, long number) { m_data.erase(m_data.begin()+first-1,m_data.begin()+first-1+number); } template void ColumnData::setDataLimits (T* limits) { m_minLegalValue = limits[0]; m_maxLegalValue = limits[1]; m_minDataValue = std::max(limits[2],limits[0]); m_maxDataValue = std::min(limits[3],limits[1]); } // Additional Declarations // all functions that operate on strings or complex data that call cfitsio // need to be specialized. #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::setDataLimits (complex* limits) { m_minLegalValue = limits[0]; m_maxLegalValue = limits[1]; m_minDataValue = limits[2]; m_maxDataValue = limits[3]; } #else template <> void ColumnData >::setDataLimits (complex* limits); #endif #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::setDataLimits (complex* limits) { m_minLegalValue = limits[0]; m_maxLegalValue = limits[1]; m_minDataValue = limits[2]; m_maxDataValue = limits[3]; } #else template <> void ColumnData >::setDataLimits (complex* limits); #endif #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData::readColumnData (long firstRow, long nelements, string* nullValue) { // nelements = nrows to read. if (nelements < 1) throw Column::InvalidNumberOfRows((int)nelements); if (firstRow < 1 || (firstRow+nelements-1)>rows()) throw Column::InvalidRowNumber(name()); int status = 0; int anynul = 0; char** array = new char*[nelements]; // Initialize pointers to NULL so we can safely delete // during error handling, even if they haven't been allocated. for (long i=0; i(0); bool isError = false; // Strings are unusual. The variable length case is still // handled by a ColumnData class, not a ColumnVectorData. char* nulval = 0; if (nullValue) { nulval = const_cast(nullValue->c_str()); } else { nulval = new char; *nulval = '\0'; } makeHDUCurrent(); if (varLength()) { long* strLengths = new long[nelements]; long* offsets = new long[nelements]; if (fits_read_descripts(fitsPointer(), index(), firstRow, nelements, strLengths, offsets, &status)) { isError = true; } else { // For variable length cols, must read 1 and only 1 row // at a time into array. for (long j=0; j(rows())) setData(std::vector(rows(),String(nulval))); for (long j=0; j void ColumnData::readColumnData (long firstRow, long nelements, string* nullValue); #endif #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::readColumnData (long firstRow, long nelements, complex* nullValue) { // specialization for ColumnData int status(0); int anynul(0); FITSUtil::auto_array_ptr pArray(new float[nelements*2]); float* array = pArray.get(); float nulval(0); makeHDUCurrent(); if (fits_read_col_cmp(fitsPointer(),index(), firstRow,1,nelements, nulval,array, &anynul,&status) ) throw FitsError(status); if (m_data.size() != rows()) m_data.resize(rows()); // the 'j -1 ' converts to zero based indexing. for (int j = 0; j < nelements; ++j) { m_data[j - 1 + firstRow] = std::complex(array[2*j],array[2*j+1]); } if (nelements == rows()) isRead(true); } #else template <> void ColumnData >::readColumnData (long firstRow, long nelements,complex* nullValue ); #endif #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::readColumnData (long firstRow, long nelements, complex* nullValue) { // specialization for ColumnData > int status(0); int anynul(0); FITSUtil::auto_array_ptr pArray(new double[nelements*2]); double* array = pArray.get(); double nulval(0); makeHDUCurrent(); if (fits_read_col_dblcmp(fitsPointer(), index(), firstRow,1,nelements, nulval,array, &anynul,&status) ) throw FitsError(status); if (m_data.size() != rows()) setData(std::vector >(rows(),nulval)); // the 'j -1 ' converts to zero based indexing. for (int j = 0; j < nelements; j++) { m_data[j - 1 + firstRow] = std::complex(array[2*j],array[2*j+1]); } if (nelements == rows()) isRead(true); } #else template <> void ColumnData >::readColumnData (long firstRow, long nelements,complex* nullValue); #endif #if SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData::writeData (const std::vector& indata, long firstRow, string* nullValue) { int status=0; char** columnData=FITSUtil::CharArray(indata); if ( fits_write_colnull(fitsPointer(), TSTRING, index(), firstRow, 1, indata.size(), columnData, 0, &status) != 0 ) throw FitsError(status); unsigned long elementsToWrite (indata.size() + firstRow - 1); std::vector __tmp(m_data); if (m_data.size() < elementsToWrite) { m_data.resize(elementsToWrite,""); std::copy(__tmp.begin(),__tmp.end(),m_data.begin()); } std::copy(indata.begin(),indata.end(),m_data.begin()+firstRow-1); for (size_t i = 0; i < indata.size(); ++i) { delete [] columnData[i]; } delete [] columnData; } #else template <> void ColumnData::writeData (const std::vector& inData, long firstRow, string* nullValue); #endif #ifdef SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::writeData (const std::vector >& inData, long firstRow, complex* nullValue) { int status(0); int nRows (inData.size()); FITSUtil::auto_array_ptr pData(new float[nRows*2]); float* Data = pData.get(); std::vector > __tmp(m_data); for (int j = 0; j < nRows; ++j) { Data[ 2*j] = inData[j].real(); Data[ 2*j + 1] = inData[j].imag(); } try { if (fits_write_col_cmp(fitsPointer(), index(), firstRow, 1, nRows,Data, &status) != 0) throw FitsError(status); long elementsToWrite(nRows + firstRow -1); if (elementsToWrite > static_cast(m_data.size())) { m_data.resize(elementsToWrite); } std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1); // tell the Table that the number of rows has changed parent()->updateRows(); } catch (FitsError) // the only thing that can throw here. { // reset to original content and rethrow the exception. m_data.resize(__tmp.size()); m_data = __tmp; } } #else template <> void ColumnData >::writeData (const std::vector >& inData, long firstRow, complex* nullValue); #endif #ifdef SPEC_TEMPLATE_DECL_DEFECT template <> inline void ColumnData >::writeData (const std::vector >& inData, long firstRow, complex* nullValue) { int status(0); int nRows (inData.size()); FITSUtil::auto_array_ptr pData(new double[nRows*2]); double* Data = pData.get(); std::vector > __tmp(m_data); for (int j = 0; j < nRows; ++j) { pData[ 2*j] = inData[j].real(); pData[ 2*j + 1] = inData[j].imag(); } try { if (fits_write_col_dblcmp(fitsPointer(), index(), firstRow, 1, nRows,Data, &status) != 0) throw FitsError(status); long elementsToWrite(nRows + firstRow -1); if (elementsToWrite > static_cast(m_data.size())) { m_data.resize(elementsToWrite); } std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1); // tell the Table that the number of rows has changed parent()->updateRows(); } catch (FitsError) // the only thing that can throw here. { // reset to original content and rethrow the exception. m_data.resize(__tmp.size()); m_data = __tmp; } } #else template <> void ColumnData >::writeData (const std::vector >& inData, long firstRow, complex* nullValue); #endif } // namespace CCfits #endif