Changeset 11716 for trunk/FACT++/src/Fits.cc
- Timestamp:
- 07/30/11 16:09:27 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/FACT++/src/Fits.cc
r11593 r11716 37 37 void Fits::AddStandardColumn(const Description& desc, const string &dataFormat, void* dataPointer, long unsigned int numDataBytes) 38 38 { 39 //check if entry already exist 40 for (vector<Description>::const_iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++) 41 if (it->name == desc.name) 42 return; 43 fStandardColDesc.push_back(desc); 44 fStandardFormats.push_back(dataFormat); 45 fStandardPointers.push_back(dataPointer); 46 fStandardNumBytes.push_back(numDataBytes); 47 } 39 //check if entry already exist 40 for (vector<Description>::const_iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++) 41 if (it->name == desc.name) 42 return; 43 44 fStandardColDesc.push_back(desc); 45 fStandardFormats.push_back(dataFormat); 46 fStandardPointers.push_back(dataPointer); 47 fStandardNumBytes.push_back(numDataBytes); 48 } 49 48 50 // -------------------------------------------------------------------------- 49 51 // … … 54 56 //! @param numDataBytes the number of bytes taken by the DIM data. 55 57 // 56 void Fits::InitDataColumns(const vector<Description> &desc, vector<string>& dataFormat, void* dataPointer, int numDataBytes) 57 {//we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now 58 if (desc.size() == dataFormat.size()) 59 { 60 fDataColDesc = desc; 61 } 62 else 63 { 64 fDataColDesc.clear(); 65 for (unsigned int i=0;i<dataFormat.size();i++) 66 { 67 ostringstream stt; 68 stt << "Data" << i; 69 fDataColDesc.push_back(Description(stt.str(), "comment", "unit")); 70 } 71 } 72 fDataFormats = dataFormat; 73 fDataPointer = dataPointer; 74 fDataNumBytes = numDataBytes; 75 } 76 // -------------------------------------------------------------------------- 77 // 78 //! This looks for a suitable table in the fits file, i.e. that corresponds to the name and column names. (no format check yet) 79 //! @param tableName. the base table name to be obtained. If not suitable, numbers are appened to the name 80 //! @param allNames. the name of all columns 81 //! @param allDataTypes. the data types of all columns 82 //! @param allUnits. the units of the columns 83 //! @return a pointer to the newly retrieved/created table 84 // 85 CCfits::Table* Fits::findSuitableTableInFitsFile(const string& tableName,const vector<string>& allNames, const vector<string>& allDataTypes, const vector<string>& allUnits) 86 { 87 const multimap< string, CCfits::ExtHDU * >& extMap = fFile->extension(); 88 for (int i=0;i<100;i++) 89 { 90 if (i==10) 91 fMess->Error("Already 10 different tables with different formats exist in this file. Please consider re-creating the file entirely (i.e. delete it please)"); 92 ostringstream cTableName; 93 cTableName << tableName; 94 if (i != 0) 95 cTableName << "-" << i; 96 //current table name does not exist yet. return its associated fits table newly created 97 if (extMap.find(cTableName.str()) == extMap.end()) 98 { 99 for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it!= extMap.end(); it++) 100 fMess->Debug(it->first); 101 return fFile->addTable(cTableName.str(), 0, allNames, allDataTypes, allUnits); 102 } 103 CCfits::Table* cTable; 104 cTable = dynamic_cast<CCfits::Table*>(extMap.find(cTableName.str())->second); 105 106 if (!cTable) 107 return NULL;//something wrong happened while getting the table pointer 108 109 //now check that the table columns are the same as the service columns 110 cTable->makeThisCurrent(); 111 const map<string, Column*> cMap = cTable->column(); 112 for (unsigned int j=0;j<allNames.size();j++) 113 if (cMap.find(allNames[j]) == cMap.end()) 114 continue; 115 116 return cTable; 117 } 118 fMess->Error("One hundred trials for new table format failed. aborting"); 119 return NULL; 120 } 58 void Fits::InitDataColumns(const vector<Description> &desc, const vector<string>& dataFormat, void* dataPointer) 59 { 60 fDataFormats = dataFormat; 61 fDataPointer = dataPointer; 62 63 //we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now 64 if (desc.size() == dataFormat.size()) 65 { 66 fDataColDesc = desc; 67 return; 68 } 69 70 fDataColDesc.clear(); 71 for (unsigned int i=0;i<dataFormat.size();i++) 72 { 73 ostringstream stt; 74 stt << "Data" << i; 75 fDataColDesc.push_back(Description(stt.str(), "comment", "unit")); 76 } 77 } 78 121 79 // -------------------------------------------------------------------------- 122 80 // … … 129 87 //! @param runNumber the runNumber for which this file is opened. 0 means nightly file. 130 88 // 131 bool Fits::Open(const string& fileName, const string& tableName, FITS* file, uint32_t* fitsCounter, MessageImp* out, int runNumber) 132 { 133 // if (fMess) 134 // delete fMess; 135 // fMess = new MessageImp(out); 89 bool Fits::Open(const string& fileName, const string& tableName, uint32_t* fitsCounter, MessageImp* out, int runNumber, FITS* file) 90 { 136 91 fRunNumber = runNumber; 137 fMess = out; 138 fFileName = fileName; 139 if (file == NULL) 140 { 141 try 142 { 143 fFile = new FITS(fileName, RWmode::Write); 144 } 145 catch (CCfits::FitsException e) 146 { 147 ostringstream str; 148 str << "Opening FITS file " << fileName << ": " << e.message(); 149 fMess->Error(str); 150 fFile = NULL; 151 return false; 152 } 153 fOwner = true; 154 fNumOpenFitsFiles = fitsCounter; 155 (*fNumOpenFitsFiles)++; 156 } 157 else 158 { 159 fFile = file; 160 fOwner = false; 161 } 162 //concatenate the standard and data columns 163 //do it the inneficient way first: its easier and faster to code. 164 vector<string> allNames; 165 vector<string> allDataTypes; 166 vector<string> allUnits; 167 fTotalNumBytes = 0; 168 for (unsigned int i=0;i<fStandardColDesc.size();i++) 169 { 170 allNames.push_back(fStandardColDesc[i].name); 171 allDataTypes.push_back(fStandardFormats[i]); 172 allUnits.push_back(fStandardColDesc[i].unit); 173 fTotalNumBytes += fStandardNumBytes[i]; 174 } 175 //for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--) 176 for (unsigned int i=0; i<fDataColDesc.size(); i++) 177 { 178 if (fDataColDesc[i].name != "") 179 allNames.push_back(fDataColDesc[i].name); 180 else 181 { 182 ostringstream stt; 183 stt << "Data" << i; 184 allNames.push_back(stt.str()); 185 } 186 allDataTypes.push_back(fDataFormats[i]); 187 allUnits.push_back(fDataColDesc[i].unit); 188 } 189 fTotalNumBytes += fDataNumBytes; 190 191 bool updating = false; 192 try 193 { 194 //first, let's check if the table already exist in the file 195 vector<string> tryToLoadName; 196 tryToLoadName.push_back(tableName); 197 fFile->read(tryToLoadName); 198 199 // const multimap< string, CCfits::ExtHDU * >& extMap = fFile->extension(); 200 // if (extMap.find(tableName) == extMap.end()) 201 // { 202 // for (multimap<string, CCfits::ExtHDU*>::const_iterator it=extMap.begin(); it!= extMap.end(); it++) 203 // fMess->Debug(it->first); 204 // fTable = fFile->addTable(tableName, 0, allNames, allDataTypes, allUnits); 205 // } 206 // else 207 // { 208 // fTable = dynamic_cast<CCfits::Table*>(extMap.find(tableName)->second); 209 // } 210 fTable = findSuitableTableInFitsFile(tableName, allNames, allDataTypes, allUnits); 211 212 if (!fTable) 213 { 214 fMess->Error("Table " + tableName + " could not be created nor loaded from "+fileName); 215 Close(); 216 return false; 217 } 218 fTable->makeThisCurrent(); 219 fCopyBuffer = new unsigned char[fTotalNumBytes]; 220 fNumRows = fTable->rows(); 221 if (fNumRows !=0) 222 {//If the file already existed, then we must load its data to memory before writing to it. 223 BinTable* bTable = dynamic_cast<BinTable*>(fTable); 224 if (!bTable) 225 { 226 fMess->Error("Table " + tableName + " in "+fileName+" could not be converted to a binary table."); 227 Close(); 228 return false; 229 } 230 //read the table binary data. 231 vector<string> colName; 232 bTable->readData(true, colName); 233 234 //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !) 235 const map<string, Column*> cMap = fTable->column(); 236 237 for (map<string, Column*>::const_iterator cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++) 238 { 239 if (!cMapIt->second->isRead()) 240 { 241 fMess->Error("Reading column " + cMapIt->first + " back from "+fileName+" failed."); 242 Close(); 243 return false; 244 } 245 } 246 updating = true; 247 } 248 249 } 250 catch(CCfits::FitsException e) 251 { 252 ostringstream str; 253 str << "Opening or creating table " << tableName << " in " << fileName << ": " << e.message(); 254 fMess->Error(str); 255 fTable = NULL; 256 Close(); 257 return false; 258 } 259 260 if (!updating) 261 return WriteHeaderKeys(); 262 263 return true; 264 } 265 // -------------------------------------------------------------------------- 266 // 267 //!This writes a single header key in the currently open file. 268 //!@param name the key 269 //!@param value the key value 270 //!@param a comment explaining the meaning of the key 271 template <typename T> 272 bool Fits::WriteSingleHeaderKey(const string &name, const T &value, const string &comment) 273 { 274 try 275 { 276 fTable->addKey(name, value, comment); 277 } 278 catch (CCfits::FitsException e) 279 { 280 ostringstream str; 281 str << "Could not add header keys in file " << fFileName << " reason: " << e.message(); 282 fMess->Error(str); 283 return false; 284 } 285 return true; 286 } 92 fMess = out; 93 94 if (fFile) 95 { 96 fMess->Error("File already open..."); 97 return false; 98 } 99 100 fFile = new FitsFile(*fMess); 101 102 if (file == NULL) 103 { 104 if (!fFile->OpenFile(fileName, true)) 105 return false; 106 107 fNumOpenFitsFiles = fitsCounter; 108 (*fNumOpenFitsFiles)++; 109 } 110 else 111 { 112 if (!fFile->SetFile(file)) 113 return false; 114 } 115 116 //concatenate the standard and data columns 117 //do it the inneficient way first: its easier and faster to code. 118 for (unsigned int i=0;i<fStandardColDesc.size();i++) 119 { 120 fFile->AddColumn(fStandardColDesc[i].name, fStandardFormats[i], 121 fStandardColDesc[i].unit); 122 } 123 124 for (unsigned int i=0; i<fDataColDesc.size(); i++) 125 { 126 string name = fDataColDesc[i].name; 127 if (name.empty()) 128 { 129 ostringstream stt; 130 stt << "Data" << i; 131 name = stt.str(); 132 } 133 134 fFile->AddColumn(name, fDataFormats[i], fDataColDesc[i].unit); 135 } 136 137 try 138 { 139 if (!fFile->OpenNewTable(tableName, 100)) 140 { 141 Close(); 142 return false; 143 } 144 145 fCopyBuffer.resize(fFile->GetDataSize()); 146 147 return fFile->GetNumRows()==0 ? true : WriteHeaderKeys(); 148 } 149 catch (const CCfits::FitsException &e) 150 { 151 fMess->Error("Opening or creating table '"+tableName+"' in '"+fileName+"': "+e.message()); 152 153 fFile->fTable = NULL; 154 Close(); 155 return false; 156 } 157 } 158 287 159 // -------------------------------------------------------------------------- 288 160 // … … 291 163 bool Fits::WriteHeaderKeys() 292 164 { 293 if (!fTable) 294 return false; 295 296 const Time now; 297 if (!WriteSingleHeaderKey("EXTREL", 1.0f, "Release Number")) return false; 298 if (!WriteSingleHeaderKey("TELESCOP", "FACT", "Telescope that acquired this data")) return false; 299 if (!WriteSingleHeaderKey("ORIGIN", "ISDC", "Institution that wrote the file")) return false; 300 if (!WriteSingleHeaderKey("CREATOR", "fadctrl", "Program that wrote this file (FACT++ datalogger)")) return false; 301 if (!WriteSingleHeaderKey("PACKAGE", PACKAGE_NAME, "Package name")) return false; 302 if (!WriteSingleHeaderKey("VERSION", PACKAGE_VERSION, "Package description")) return false; 303 if (!WriteSingleHeaderKey("COMPILED", __DATE__" "__TIME__, "Compile time")) return false; 304 if (!WriteSingleHeaderKey("REVISION", REVISION, "SVN revision")) return false; 305 if (!WriteSingleHeaderKey("DATE", now.Iso(), "File creation date")) return false; 306 if (!WriteSingleHeaderKey("NIGHT", now.NightAsInt(), "Night as int")) return false; 307 if (!WriteSingleHeaderKey("TIMESYS", "UTC", "Time systen")) return false; 308 if (!WriteSingleHeaderKey("TSTART", "", "Time of the first receied data")) return false; 309 if (!WriteSingleHeaderKey("TSTOP", "", "Time of the last receied data")) return false; 165 if (!fFile->fTable) 166 return false; 167 168 if (!fFile->WriteDefaultKeys("datalogger")) 169 return false; 170 171 if (!fFile->WriteKeyNT("TSTART", "", "Time of the first receied data")) 172 return false; 173 174 if (!fFile->WriteKeyNT("TSTOP", "", "Time of the last receied data")) 175 return false; 176 310 177 return true; 311 178 } 179 312 180 // -------------------------------------------------------------------------- 313 181 // … … 322 190 { 323 191 const char *charSrc = reinterpret_cast<char*>(fStandardPointers[i]); 324 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], &fCopyBuffer[shift]);192 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], fCopyBuffer.data()+shift); 325 193 shift += fStandardNumBytes[i]; 326 194 } … … 329 197 { 330 198 //now take care of the DIM data. The Converter is here for that purpose 331 conv.ToFits( &fCopyBuffer[shift], fDataPointer, fDataNumBytes);199 conv.ToFits(fCopyBuffer.data()+shift, fDataPointer, fCopyBuffer.size()-shift); 332 200 } 333 201 catch (const runtime_error &e) 334 202 { 335 203 ostringstream str; 336 str << fFile Name<< ": " << e.what();204 str << fFile->GetName() << ": " << e.what(); 337 205 fMess->Error(str); 338 206 return false; 339 207 } 340 208 341 fTable->makeThisCurrent(); 342 343 int status(0); 344 if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status)) 345 { 346 ostringstream str; 347 char text[30]; 348 fits_get_errstatus(status, text); 349 str << "Inserting row into " << fFileName << ": " << text << " (fits_insert_rows, rc=" << status << ")"; 350 fMess->Error(str); 209 // This is not necessary, is it? 210 // fFile->fTable->makeThisCurrent(); 211 212 if (!fFile->AddRow()) 213 { 351 214 Close(); 352 215 return false; 353 216 } 354 217 355 fNumRows++; 218 if (!fFile->WriteData(fCopyBuffer)) 219 { 220 Close(); 221 return false; 222 } 356 223 357 224 //the first standard variable is the current MjD 358 225 if (fEndMjD==0) 359 226 { 227 // FIXME: Check error? 360 228 const double doubleValue = *reinterpret_cast<double*>(fStandardPointers[0]); 361 WriteSingleHeaderKey("TSTART", Time(doubleValue).Iso(),362 229 fFile->WriteKeyNT("TSTART", Time(doubleValue).Iso(), 230 "Time of the first received data"); 363 231 } 364 232 fEndMjD = *reinterpret_cast<double*>(fStandardPointers[0]); 365 233 366 //data copied to buffer, can write to fits367 if (fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status))368 {369 char text[30];//max length of cfitsio error strings (from doc)370 fits_get_errstatus(status, text);371 ostringstream str;372 str << "Writing FITS row " << fNumRows << " in " << fFileName << ": " << text << " (file_write_tblbytes, rc=" << status << ")";373 fMess->Error(str);374 Close();375 return false;376 }377 234 return true; 378 235 } … … 385 242 void Fits::Close() 386 243 { 387 //WARNING: do NOT delete the table as it gets deleted by the fFile object 388 // if (fTable != NULL) 389 // delete fTable; 390 if (fFile != NULL && fOwner) 391 { 392 // CCfits::FITS* backupFits = fFile; 393 // fFile = NULL; 394 WriteSingleHeaderKey("TSTOP", Time(fEndMjD).Iso(), "Time of the last receied data"); 395 delete fFile; 396 397 fMess->Info("Closed: "+fFileName); 244 if (!fFile) 245 return; 246 247 if (fFile->IsOpen() && fFile->IsOwner()) 248 { 249 // FIMXE: Check for error? (It is allowed that fFile is NULL) 250 fFile->WriteKeyNT("TSTOP", Time(fEndMjD).Iso(), 251 "Time of the last receied data"); 252 } 253 254 if (fFile->IsOwner()) 255 { 398 256 if (fNumOpenFitsFiles != NULL) 399 257 (*fNumOpenFitsFiles)--; 400 } 401 fFile = NULL; 402 if (fCopyBuffer != NULL) 403 delete [] fCopyBuffer; 404 fCopyBuffer = NULL; 405 406 //fMess is the MessageImp part of the dataLogger itself. Thus it should NOT be deleted by the Fits files destructor. 407 // if (fMess) 408 // delete fMess; 409 fMess = NULL; 258 } 259 260 delete fFile; 261 fFile = NULL; 262 263 fMess = NULL; 410 264 } 411 265 … … 414 268 int Fits::GetWrittenSize() const 415 269 { 416 if (!IsOpen()) 417 return 0; 418 419 struct stat st; 420 if (stat(fFileName.c_str(), &st)) 421 return 0; 422 423 return st.st_size; 424 } 270 if (!IsOpen()) 271 return 0; 272 273 struct stat st; 274 if (stat(fFile->GetName().c_str(), &st)) 275 return 0; 276 277 return st.st_size; 278 } 279 280 /* 281 To be done: 282 - Check the check for column names in opennewtable 283 - If Open return false we end in an infinite loop (at least if 284 the dynamic cats to Bintable fails. 285 286 */
Note:
See TracChangeset
for help on using the changeset viewer.