CCfits
2.5
|
00001 // Astrophysics Science Division, 00002 // NASA/ Goddard Space Flight Center 00003 // HEASARC 00004 // http://heasarc.gsfc.nasa.gov 00005 // e-mail: ccfits@legacy.gsfc.nasa.gov 00006 // 00007 // Original author: Ben Dorman 00008 00009 #ifndef COLUMNDATA_H 00010 #define COLUMNDATA_H 1 00011 #include "CCfits.h" 00012 00013 // vector 00014 #include <vector> 00015 // Column 00016 #include "Column.h" 00017 #ifdef _MSC_VER 00018 #include "MSconfig.h" 00019 #endif 00020 00021 #include <complex> 00022 #include <memory> 00023 #include <iterator> 00024 #include "FITSUtil.h" 00025 using std::complex; 00026 #include "FITS.h" 00027 00028 00029 namespace CCfits { 00030 00031 00032 00033 template <typename T> 00034 class ColumnData : public Column //## Inherits: <unnamed>%385E51565EE8 00035 { 00036 00037 public: 00038 ColumnData(const ColumnData< T > &right); 00039 ColumnData (Table* p = 0); 00040 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 = ""); 00041 ~ColumnData(); 00042 00043 virtual ColumnData<T>* clone () const; 00044 virtual void readData (long firstRow, long nelements, long firstElem = 1); 00045 void setDataLimits (T* limits); 00046 const T minLegalValue () const; 00047 void minLegalValue (T value); 00048 const T maxLegalValue () const; 00049 void maxLegalValue (T value); 00050 const T minDataValue () const; 00051 void minDataValue (T value); 00052 const T maxDataValue () const; 00053 void maxDataValue (T value); 00054 const std::vector<T>& data () const; 00055 void setData (const std::vector<T>& value); 00056 T data (int i); 00057 void data (int i, T value); 00058 00059 // Additional Public Declarations 00060 friend class Column; 00061 protected: 00062 // Additional Protected Declarations 00063 00064 private: 00065 ColumnData< T > & operator=(const ColumnData< T > &right); 00066 00067 void readColumnData (long firstRow, long nelements, T* nullValue = 0); 00068 virtual bool compare (const Column &right) const; 00069 virtual std::ostream& put (std::ostream& s) const; 00070 void writeData (T* indata, long nRows = 1, long firstRow = 1, T* nullValue = 0); 00071 void writeData (const std::vector<T>& indata, long firstRow = 1, T* nullValue = 0); 00072 // Insert one or more blank rows into a FITS column. 00073 virtual void insertRows (long first, long number = 1); 00074 virtual void deleteRows (long first, long number = 1); 00075 00076 // Additional Private Declarations 00077 00078 private: //## implementation 00079 // Data Members for Class Attributes 00080 T m_minLegalValue; 00081 T m_maxLegalValue; 00082 T m_minDataValue; 00083 T m_maxDataValue; 00084 00085 // Data Members for Associations 00086 std::vector<T> m_data; 00087 00088 // Additional Implementation Declarations 00089 00090 }; 00091 00092 // Parameterized Class CCfits::ColumnData 00093 00094 template <typename T> 00095 inline void ColumnData<T>::readData (long firstRow, long nelements, long firstElem) 00096 { 00097 readColumnData(firstRow,nelements,static_cast<T*>(0)); 00098 } 00099 00100 template <typename T> 00101 inline const T ColumnData<T>::minLegalValue () const 00102 { 00103 return m_minLegalValue; 00104 } 00105 00106 template <typename T> 00107 inline void ColumnData<T>::minLegalValue (T value) 00108 { 00109 m_minLegalValue = value; 00110 } 00111 00112 template <typename T> 00113 inline const T ColumnData<T>::maxLegalValue () const 00114 { 00115 return m_maxLegalValue; 00116 } 00117 00118 template <typename T> 00119 inline void ColumnData<T>::maxLegalValue (T value) 00120 { 00121 m_maxLegalValue = value; 00122 } 00123 00124 template <typename T> 00125 inline const T ColumnData<T>::minDataValue () const 00126 { 00127 return m_minDataValue; 00128 } 00129 00130 template <typename T> 00131 inline void ColumnData<T>::minDataValue (T value) 00132 { 00133 m_minDataValue = value; 00134 } 00135 00136 template <typename T> 00137 inline const T ColumnData<T>::maxDataValue () const 00138 { 00139 return m_maxDataValue; 00140 } 00141 00142 template <typename T> 00143 inline void ColumnData<T>::maxDataValue (T value) 00144 { 00145 m_maxDataValue = value; 00146 } 00147 00148 template <typename T> 00149 inline const std::vector<T>& ColumnData<T>::data () const 00150 { 00151 return m_data; 00152 } 00153 00154 template <typename T> 00155 inline void ColumnData<T>::setData (const std::vector<T>& value) 00156 { 00157 m_data = value; 00158 } 00159 00160 template <typename T> 00161 inline T ColumnData<T>::data (int i) 00162 { 00163 // return data stored in the ith row, which is in the i-1 th location in the array. 00164 return m_data[i - 1]; 00165 } 00166 00167 template <typename T> 00168 inline void ColumnData<T>::data (int i, T value) 00169 { 00170 // assign data to i-1 th location in the array, representing the ith row. 00171 m_data[i - 1] = value; 00172 } 00173 00174 // Parameterized Class CCfits::ColumnData 00175 00176 template <typename T> 00177 ColumnData<T>::ColumnData(const ColumnData<T> &right) 00178 :Column(right), 00179 m_minLegalValue(right.m_minLegalValue), 00180 m_maxLegalValue(right.m_maxLegalValue), 00181 m_minDataValue(right.m_minDataValue), 00182 m_maxDataValue(right.m_maxDataValue), 00183 m_data(right.m_data) 00184 { 00185 } 00186 00187 template <typename T> 00188 ColumnData<T>::ColumnData (Table* p) 00189 : Column(p), 00190 m_minLegalValue(), 00191 m_maxLegalValue(), 00192 m_minDataValue(), 00193 m_maxDataValue(), 00194 m_data() 00195 { 00196 } 00197 00198 template <typename T> 00199 ColumnData<T>::ColumnData (int columnIndex, const string &columnName, ValueType type, const String &format, const String &unit, Table* p, int rpt, long w, const String &comment) 00200 : Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment), 00201 m_minLegalValue(), 00202 m_maxLegalValue(), 00203 m_minDataValue(), 00204 m_maxDataValue(), 00205 m_data() 00206 { 00207 } 00208 00209 00210 template <typename T> 00211 ColumnData<T>::~ColumnData() 00212 { 00213 } 00214 00215 00216 template <typename T> 00217 void ColumnData<T>::readColumnData (long firstRow, long nelements, T* nullValue) 00218 { 00219 if ( rows() < nelements ) 00220 { 00221 std::cerr << "CCfits: More data requested than contained in table. "; 00222 std::cerr << "Extracting complete column.\n"; 00223 nelements = rows(); 00224 } 00225 00226 int status(0); 00227 int anynul(0); 00228 00229 FITSUtil::auto_array_ptr<T> array(new T[nelements]); 00230 00231 makeHDUCurrent(); 00232 00233 if ( fits_read_col(fitsPointer(),type(), index(), firstRow, 1, 00234 nelements, nullValue, array.get(), &anynul, &status) ) throw FitsError(status); 00235 00236 00237 if (m_data.size() != static_cast<size_t>( rows() ) ) m_data.resize(rows()); 00238 00239 std::copy(&array[0],&array[nelements],m_data.begin()+firstRow-1); 00240 if (nelements == rows()) isRead(true); 00241 } 00242 00243 template <typename T> 00244 bool ColumnData<T>::compare (const Column &right) const 00245 { 00246 if ( !Column::compare(right) ) return false; 00247 const ColumnData<T>& that = static_cast<const ColumnData<T>&>(right); 00248 unsigned int n = m_data.size(); 00249 if ( that.m_data.size() != n ) return false; 00250 for (unsigned int i = 0; i < n ; i++) 00251 { 00252 if (m_data[i] != that.m_data[i]) return false; 00253 } 00254 return true; 00255 } 00256 00257 template <typename T> 00258 ColumnData<T>* ColumnData<T>::clone () const 00259 { 00260 return new ColumnData<T>(*this); 00261 } 00262 00263 template <typename T> 00264 std::ostream& ColumnData<T>::put (std::ostream& s) const 00265 { 00266 Column::put(s); 00267 if (FITS::verboseMode() && type() != Tstring) 00268 { 00269 s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n" 00270 << " Column Data limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n"; 00271 } 00272 if (!m_data.empty()) 00273 { 00274 std::ostream_iterator<T> output(s,"\n"); 00275 // output each row on a separate line. 00276 // user can supply manipulators to stream for formatting. 00277 std::copy(m_data.begin(),m_data.end(),output); 00278 } 00279 00280 return s; 00281 } 00282 00283 template <typename T> 00284 void ColumnData<T>::writeData (T* indata, long nRows, long firstRow, T* nullValue) 00285 { 00286 00287 // set columnData's data member to equal what's written to file. 00288 // indata has size nRows: elements firstRow to firstRow + nRows - 1 will be written. 00289 // if this exceeds the current rowlength of the HDU, update the return value for 00290 // rows() in the parent after the fitsio call. 00291 int status(0); 00292 long elementsToWrite(nRows + firstRow -1); 00293 // get a copy for restorative action. 00294 std::vector<T> __tmp(m_data); 00295 00296 00297 if (elementsToWrite > static_cast<long>(m_data.size())) 00298 { 00299 00300 m_data.resize(elementsToWrite,T()); 00301 } 00302 00303 std::copy(&indata[0],&indata[nRows],m_data.begin()+firstRow-1); 00304 00305 // if successful, write to disk. 00306 00307 try 00308 { 00309 if (nullValue) 00310 { 00311 if (fits_write_colnull(fitsPointer(), type(), index(), firstRow, 1, nRows, 00312 indata, nullValue, &status) != 0) throw FitsError(status); 00313 } 00314 else 00315 { 00316 if (fits_write_col(fitsPointer(), type(), index(), firstRow, 1, nRows, 00317 indata, &status) != 0) throw FitsError(status); 00318 } 00319 00320 // tell the Table that the number of rows has changed 00321 parent()->updateRows(); 00322 } 00323 catch (FitsError) // the only thing that can throw here. 00324 { 00325 // reset to original content and rethrow the exception. 00326 m_data = __tmp; 00327 if (status == NO_NULL) throw NoNullValue(name()); 00328 else throw; 00329 } 00330 } 00331 00332 template <typename T> 00333 void ColumnData<T>::writeData (const std::vector<T>& indata, long firstRow, T* nullValue) 00334 { 00335 FITSUtil::CVarray<T> convert; 00336 FITSUtil::auto_array_ptr<T> pcolData (convert(indata)); 00337 T* columnData = pcolData.get(); 00338 writeData(columnData,indata.size(),firstRow,nullValue); 00339 } 00340 00341 template <typename T> 00342 void ColumnData<T>::insertRows (long first, long number) 00343 { 00344 FITSUtil::FitsNullValue<T> blank; 00345 typename std::vector<T>::iterator in; 00346 if (first !=0) 00347 { 00348 in = m_data.begin()+first; 00349 } 00350 else 00351 { 00352 in = m_data.begin(); 00353 } 00354 00355 // non-throwing operations. 00356 m_data.insert(in,number,blank()); 00357 } 00358 00359 template <typename T> 00360 void ColumnData<T>::deleteRows (long first, long number) 00361 { 00362 m_data.erase(m_data.begin()+first-1,m_data.begin()+first-1+number); 00363 } 00364 00365 template <typename T> 00366 void ColumnData<T>::setDataLimits (T* limits) 00367 { 00368 m_minLegalValue = limits[0]; 00369 m_maxLegalValue = limits[1]; 00370 m_minDataValue = std::max(limits[2],limits[0]); 00371 m_maxDataValue = std::min(limits[3],limits[1]); 00372 } 00373 00374 // Additional Declarations 00375 00376 // all functions that operate on strings or complex data that call cfitsio 00377 // need to be specialized. 00378 00379 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT 00380 template <> 00381 inline void ColumnData<complex<float> >::setDataLimits (complex<float>* limits) 00382 { 00383 m_minLegalValue = limits[0]; 00384 m_maxLegalValue = limits[1]; 00385 m_minDataValue = limits[2]; 00386 m_maxDataValue = limits[3]; 00387 } 00388 #else 00389 template <> 00390 void ColumnData<complex<float> >::setDataLimits (complex<float>* limits); 00391 #endif 00392 00393 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT 00394 template <> 00395 inline void ColumnData<complex<double> >::setDataLimits (complex<double>* limits) 00396 { 00397 m_minLegalValue = limits[0]; 00398 m_maxLegalValue = limits[1]; 00399 m_minDataValue = limits[2]; 00400 m_maxDataValue = limits[3]; 00401 } 00402 #else 00403 template <> 00404 void ColumnData<complex<double> >::setDataLimits (complex<double>* limits); 00405 #endif 00406 00407 00408 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT 00409 template <> 00410 inline void ColumnData<string>::readColumnData (long firstRow, 00411 long nelements, 00412 string* nullValue) 00413 { 00414 // nelements = nrows to read. 00415 if (nelements < 1) 00416 throw Column::InvalidNumberOfRows((int)nelements); 00417 if (firstRow < 1 || (firstRow+nelements-1)>rows()) 00418 throw Column::InvalidRowNumber(name()); 00419 00420 int status = 0; 00421 int anynul = 0; 00422 00423 char** array = new char*[nelements]; 00424 // Initialize pointers to NULL so we can safely delete 00425 // during error handling, even if they haven't been allocated. 00426 for (long i=0; i<nelements; ++i) 00427 array[i]=static_cast<char*>(0); 00428 bool isError = false; 00429 00430 // Strings are unusual. The variable length case is still 00431 // handled by a ColumnData class, not a ColumnVectorData. 00432 char* nulval = 0; 00433 if (nullValue) 00434 { 00435 nulval = const_cast<char*>(nullValue->c_str()); 00436 } 00437 else 00438 { 00439 nulval = new char; 00440 *nulval = '\0'; 00441 } 00442 makeHDUCurrent(); 00443 if (varLength()) 00444 { 00445 long* strLengths = new long[nelements]; 00446 long* offsets = new long[nelements]; 00447 if (fits_read_descripts(fitsPointer(), index(), firstRow, 00448 nelements, strLengths, offsets, &status)) 00449 { 00450 isError = true; 00451 } 00452 else 00453 { 00454 // For variable length cols, must read 1 and only 1 row 00455 // at a time into array. 00456 for (long j=0; j<nelements; ++j) 00457 { 00458 array[j] = new char[strLengths[j] + 1]; 00459 } 00460 00461 const long lastRow = firstRow+nelements-1; 00462 for (long iRow=firstRow; !isError && iRow<=lastRow; ++iRow) 00463 { 00464 if (fits_read_col_str(fitsPointer(),index(), iRow, 1, 1, 00465 nulval, &array[iRow-firstRow], &anynul,&status) ) 00466 isError=true; 00467 } 00468 } 00469 delete [] strLengths; 00470 delete [] offsets; 00471 } 00472 else 00473 { 00474 // Fixed length strings, length is stored in Column's m_width. 00475 for (long j=0; j<nelements; ++j) 00476 { 00477 array[j] = new char[width() + 1]; 00478 } 00479 if (fits_read_col_str(fitsPointer(),index(), firstRow,1,nelements, 00480 nulval,array, &anynul,&status)) 00481 isError=true; 00482 } 00483 00484 if (isError) 00485 { 00486 // It's OK to do this even if error occurred before 00487 // array rows were allocated. In that case their pointers 00488 // were set to NULL. 00489 for (long j = 0; j < nelements; ++j) 00490 { 00491 delete [] array[j]; 00492 } 00493 delete [] array; 00494 delete nulval; 00495 throw FitsError(status); 00496 } 00497 00498 if (m_data.size() != static_cast<size_t>(rows())) 00499 setData(std::vector<String>(rows(),String(nulval))); 00500 00501 for (long j=0; j<nelements; ++j) 00502 { 00503 m_data[j - 1 + firstRow] = String(array[j]); 00504 } 00505 00506 for (long j=0; j<nelements; j++) 00507 { 00508 delete [] array[j]; 00509 } 00510 delete [] array; 00511 delete nulval; 00512 if (nelements == rows()) isRead(true); 00513 00514 } 00515 #else 00516 template <> 00517 void ColumnData<string>::readColumnData (long firstRow, long nelements, string* nullValue); 00518 #endif 00519 00520 00521 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT 00522 template <> 00523 inline void ColumnData<complex<float> >::readColumnData (long firstRow, 00524 long nelements, 00525 complex<float>* nullValue) 00526 { 00527 // specialization for ColumnData<string> 00528 int status(0); 00529 int anynul(0); 00530 FITSUtil::auto_array_ptr<float> pArray(new float[nelements*2]); 00531 float* array = pArray.get(); 00532 float nulval(0); 00533 makeHDUCurrent(); 00534 00535 00536 if (fits_read_col_cmp(fitsPointer(),index(), firstRow,1,nelements, 00537 nulval,array, &anynul,&status) ) throw FitsError(status); 00538 00539 00540 if (m_data.size() != rows()) m_data.resize(rows()); 00541 00542 // the 'j -1 ' converts to zero based indexing. 00543 00544 for (int j = 0; j < nelements; ++j) 00545 { 00546 00547 m_data[j - 1 + firstRow] = std::complex<float>(array[2*j],array[2*j+1]); 00548 } 00549 if (nelements == rows()) isRead(true); 00550 00551 } 00552 #else 00553 template <> 00554 void ColumnData<complex<float> >::readColumnData (long firstRow, long nelements,complex<float>* nullValue ); 00555 #endif 00556 00557 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT 00558 template <> 00559 inline void ColumnData<complex<double> >::readColumnData (long firstRow, 00560 long nelements, 00561 complex<double>* nullValue) 00562 { 00563 // specialization for ColumnData<complex<double> > 00564 int status(0); 00565 int anynul(0); 00566 FITSUtil::auto_array_ptr<double> pArray(new double[nelements*2]); 00567 double* array = pArray.get(); 00568 double nulval(0); 00569 makeHDUCurrent(); 00570 00571 00572 if (fits_read_col_dblcmp(fitsPointer(), index(), firstRow,1,nelements, 00573 nulval,array, &anynul,&status) ) throw FitsError(status); 00574 00575 00576 00577 00578 if (m_data.size() != rows()) setData(std::vector<complex<double> >(rows(),nulval)); 00579 00580 // the 'j -1 ' converts to zero based indexing. 00581 00582 for (int j = 0; j < nelements; j++) 00583 { 00584 00585 m_data[j - 1 + firstRow] = std::complex<double>(array[2*j],array[2*j+1]); 00586 } 00587 if (nelements == rows()) isRead(true); 00588 00589 } 00590 #else 00591 template <> 00592 void ColumnData<complex<double> >::readColumnData (long firstRow, long nelements,complex<double>* nullValue); 00593 #endif 00594 00595 #if SPEC_TEMPLATE_DECL_DEFECT 00596 template <> 00597 inline void ColumnData<string>::writeData (const std::vector<string>& indata, 00598 long firstRow, string* nullValue) 00599 { 00600 int status=0; 00601 char** columnData=FITSUtil::CharArray(indata); 00602 00603 if ( fits_write_colnull(fitsPointer(), TSTRING, index(), firstRow, 1, indata.size(), 00604 columnData, 0, &status) != 0 ) 00605 throw FitsError(status); 00606 unsigned long elementsToWrite (indata.size() + firstRow - 1); 00607 std::vector<string> __tmp(m_data); 00608 if (m_data.size() < elementsToWrite) 00609 { 00610 m_data.resize(elementsToWrite,""); 00611 std::copy(__tmp.begin(),__tmp.end(),m_data.begin()); 00612 } 00613 std::copy(indata.begin(),indata.end(),m_data.begin()+firstRow-1); 00614 00615 00616 for (size_t i = 0; i < indata.size(); ++i) 00617 { 00618 delete [] columnData[i]; 00619 } 00620 delete [] columnData; 00621 } 00622 #else 00623 template <> 00624 void ColumnData<string>::writeData (const std::vector<string>& inData, long firstRow, string* nullValue); 00625 #endif 00626 00627 #ifdef SPEC_TEMPLATE_DECL_DEFECT 00628 template <> 00629 inline void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData, 00630 long firstRow, 00631 complex<float>* nullValue) 00632 { 00633 int status(0); 00634 int nRows (inData.size()); 00635 FITSUtil::auto_array_ptr<float> pData(new float[nRows*2]); 00636 float* Data = pData.get(); 00637 std::vector<complex<float> > __tmp(m_data); 00638 for (int j = 0; j < nRows; ++j) 00639 { 00640 Data[ 2*j] = inData[j].real(); 00641 Data[ 2*j + 1] = inData[j].imag(); 00642 } 00643 00644 try 00645 { 00646 00647 if (fits_write_col_cmp(fitsPointer(), index(), firstRow, 1, 00648 nRows,Data, &status) != 0) throw FitsError(status); 00649 long elementsToWrite(nRows + firstRow -1); 00650 if (elementsToWrite > static_cast<long>(m_data.size())) 00651 { 00652 00653 m_data.resize(elementsToWrite); 00654 } 00655 00656 std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1); 00657 00658 // tell the Table that the number of rows has changed 00659 parent()->updateRows(); 00660 } 00661 catch (FitsError) // the only thing that can throw here. 00662 { 00663 // reset to original content and rethrow the exception. 00664 m_data.resize(__tmp.size()); 00665 m_data = __tmp; 00666 } 00667 00668 } 00669 00670 #else 00671 template <> 00672 void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData, long firstRow, 00673 complex<float>* nullValue); 00674 #endif 00675 00676 #ifdef SPEC_TEMPLATE_DECL_DEFECT 00677 template <> 00678 inline void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData, 00679 long firstRow, 00680 complex<double>* nullValue) 00681 { 00682 int status(0); 00683 int nRows (inData.size()); 00684 FITSUtil::auto_array_ptr<double> pData(new double[nRows*2]); 00685 double* Data = pData.get(); 00686 std::vector<complex<double> > __tmp(m_data); 00687 for (int j = 0; j < nRows; ++j) 00688 { 00689 pData[ 2*j] = inData[j].real(); 00690 pData[ 2*j + 1] = inData[j].imag(); 00691 } 00692 00693 try 00694 { 00695 00696 if (fits_write_col_dblcmp(fitsPointer(), index(), firstRow, 1, 00697 nRows,Data, &status) != 0) throw FitsError(status); 00698 long elementsToWrite(nRows + firstRow -1); 00699 if (elementsToWrite > static_cast<long>(m_data.size())) 00700 { 00701 00702 m_data.resize(elementsToWrite); 00703 } 00704 00705 std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1); 00706 00707 // tell the Table that the number of rows has changed 00708 parent()->updateRows(); 00709 } 00710 catch (FitsError) // the only thing that can throw here. 00711 { 00712 // reset to original content and rethrow the exception. 00713 m_data.resize(__tmp.size()); 00714 m_data = __tmp; 00715 } 00716 00717 } 00718 00719 #else 00720 template <> 00721 void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData, long firstRow, 00722 complex<double>* nullValue); 00723 00724 #endif 00725 } // namespace CCfits 00726 00727 00728 #endif