emcDB.C

Go to the documentation of this file.
00001 #include "emcDB.h"
00002 
00003 #include "emcDataManager.h"
00004 #include "emcDefines.h"
00005 #include "emcGains.h"
00006 #include "emcHLRatios.h"
00007 #include "emcPedestals.h"
00008 #include "emcLCTofs.h"
00009 #include "emcWalkTofs.h"
00010 #include "emcTofT0s.h"
00011 #include "emcQAs.h"
00012 #include "emcRawDataAccessor.h"
00013 #include "emcCalFEM.h"
00014 #include "emcCalFEMFactory.h"
00015 #include "fileEventiterator.h"
00016 #include "EmcIndexer.h"
00017 #include "emcTracedFEM.h"
00018 #include "emcTracedValue.h"
00019 #include "emcGainFEM.h"
00020 #include "emcDefines.h"
00021 #include "RunTimesFactory.h"
00022 #include "TStopwatch.h"
00023 #include "emcCalibrationData.h"
00024 #include "emcRejectList.h"
00025 #include "emcConfigurationFile.h"
00026 #include "emcOMHelper.h"
00027 #include "emcOMCalFEMT.h"
00028 #include "PHTimeStamp.h"
00029 #include <typeinfo>
00030 #include <algorithm>
00031 #include <iomanip>
00032 #include <ctime>
00033 #include <cstdlib>
00034 #include <cstdio>
00035 #include <cassert>
00036 #include <stdexcept>
00037 #include <string>
00038 #include <list>
00039 #include <vector>
00040 #include <set>
00041 #include <fstream>
00042 #include <sstream>
00043 #include <memory>
00044 #include "TROOT.h"
00045 #include "TSystem.h"
00046 
00047 #include "PdbApplication.hh"
00048 #include "PdbBankManagerFactory.hh"
00049 #include "PdbBankID.hh"
00050 #include "PdbCalBank.hh"
00051 #include "PdbCalBankIterator.hh"
00052 #include "RunToTime.hh"
00053 
00054 using namespace std;
00055 
00056 //_____________________________________________________________________________
00057 int
00058 isRunNumber(const std::string str)
00059 {
00060   // 10 digits
00061   if (str.size()!=10) return -1;
00062 
00063   for ( size_t i = 0; i < 10; ++i )
00064     {
00065       if (!isdigit(str[i])) return -1;
00066     }
00067   return atoi(str.c_str());
00068 }
00069 
00070 //_____________________________________________________________________________
00071 std::string
00072 getTofT0Flavor(const std::string filename)
00073 {
00074   std::ifstream in(filename.c_str());
00075   assert(in.good());
00076   char str[1024];
00077 
00078   in.getline(str,1024,'\n');
00079 
00080   int channel=-1;
00081   float dummy;
00082 
00083   while ( in >> channel >> dummy >> dummy >>dummy )
00084     {
00085       std::cout << channel << std::endl;
00086     }
00087 
00088   assert(channel>=144);
00089 
00090   if (channel>=146)
00091     {
00092       return "TofT0Bs";
00093     }
00094   else
00095     {
00096       return "TofT0s";
00097     }
00098 }
00099 
00100 //_____________________________________________________________________________
00101 bool isInitialCalibrationDirectory(const char* dir)
00102 {
00103   char* cdir = gSystem->ExpandPathName(dir);
00104   void* dirp = gSystem->OpenDirectory(cdir);
00105 
00106   const char* entry;
00107 
00108   bool ok = false;
00109 
00110   while ( (entry = gSystem->GetDirEntry(dirp)) )
00111     {
00112       string str = entry;
00113 
00114       if ( str.find("INICAL") < str.size() )
00115         {
00116           ok = true;
00117         }
00118     }
00119 
00120   gSystem->FreeDirectory(dirp);
00121   delete[] cdir;
00122 
00123   return ok;
00124 }
00125 
00126 //_____________________________________________________________________________
00127 bool isRejectListDirectory(const char* dir)
00128 {
00129   char* cdir = gSystem->ExpandPathName(dir);
00130   void* dirp = gSystem->OpenDirectory(cdir);
00131 
00132   const char* entry;
00133 
00134   bool ok = false;
00135 
00136   while ( (entry = gSystem->GetDirEntry(dirp)) )
00137     {
00138       string str = entry;
00139 
00140       if ( str == "reject.list" )
00141         {
00142           ok = true;
00143         }
00144     }
00145 
00146   gSystem->FreeDirectory(dirp);
00147   delete[] cdir;
00148   return ok;
00149 }
00150 
00151 //_____________________________________________________________________________
00152 emcDB::emcDB(const char* dbms,
00153              const char* dbname,
00154              bool interactive, PHTimeStamp* ts, PHTimeStamp* tsend)
00155 {
00156   fDBMS = dbms;
00157   fDbname = dbname;
00158   initDBMS(fDBMS.c_str());
00159   fInteractive = interactive;
00160   fForceDate = ts;
00161   fForceEndDate = tsend;
00162   fInsertAfter.setTics(0);
00163   fInsertBefore.setToFarFuture();
00164   fStartAfter.setTics(0);
00165   fStartBefore.setToFarFuture();
00166   fEndAfter.setTics(0);
00167   fEndBefore.setToFarFuture();
00168   fDebug = false;
00169   fStartIntervalGiven = false;
00170   fEndIntervalGiven = false;
00171   fInsertIntervalGiven = false;
00172 }
00173 
00174 //_____________________________________________________________________________
00175 emcDB::~emcDB()
00176 {}
00177 
00178 //_____________________________________________________________________________
00179 void
00180 emcDB::Abort(const string& method, const string& message)
00181 {
00182   Error(method, message);
00183   BankManager()->getApplication()->abort();
00184   exit(1);
00185 }
00186 
00187 //_____________________________________________________________________________
00188 int
00189 emcDB::AbsolutePosition(const string& femName)
00190 {
00191   Int_t rv = -1;
00192 
00193   if (femName.substr(0, 8) == "FEM.EMC.")
00194     {
00195 
00196       string sector = femName.substr(8, 2);
00197       int sn = EmcIndexer::EmcSectorNumber(sector.c_str());
00198 
00199       int sm144;
00200 
00201       if ( sn >= 0 && femName.substr(11, 2) == "SM")
00202         {
00203 
00204           sm144 = atoi(femName.substr(13, 2).c_str());
00205           rv = EmcIndexer::iSiSM144_PXSM144(sn, sm144);
00206         }
00207     }
00208 
00209   return rv;
00210 }
00211 
00212 //_____________________________________________________________________________
00213 PdbBankManager*
00214 emcDB::BankManager()
00215 {
00216   static PdbBankManager* bankManager =
00217     PdbBankManagerFactory::instance().create(fDBMS.c_str());
00218   if (!bankManager)
00219     {
00220       std::cerr << "<FATAL> Do not know how to deal with this dbms = "
00221                 << fDBMS << std::endl;
00222       exit(1);
00223     }
00224   return bankManager;
00225 }
00226 
00227 //_____________________________________________________________________________
00228 int
00229 emcDB::Compare(PdbCalBank& bank, const string& dir,
00230                const string& flavour)
00231 {
00232   // From bank, build an emcCalFEM object obj1
00233   // From dir and bank characteristics, build an emcCalFEM object obj2
00234   // Then compare obj1 and obj2
00235 
00236   initDBMS("Ascii");
00237   const int kCannotReadFromFile = -1;
00238   const int kUnknownFlavour = -2;
00239   const int kPluginNotFound = -3;
00240 
00241   const int kSame = 1;
00242   const int kDifferent = 0;
00243 
00244   // Build an emcCalFEM object from the Objy bank.
00245 
00246   int femAbsolutePosition = bank.getBankID().getInternalValue();
00247 
00248   int femPinNumber = 0;
00249 
00250   if ( flavour == "Pedestals5" || flavour == "Pedestals" )
00251     {
00252       // try to find pinNumber
00253       femPinNumber = GetPinNumber(femAbsolutePosition);
00254       cout << "FEM " << femAbsolutePosition << " has pinNumber="
00255            << femPinNumber << endl;
00256     }
00257 
00258   emcCalFEM* calfem1 = emcCalFEMFactory::Create(flavour.c_str(),
00259                                                 femAbsolutePosition);
00260 
00261   if (!calfem1)
00262     {
00263       return kUnknownFlavour;
00264     }
00265 
00266   // find the plugin able to read (0) the calfem1.
00267   calfem1->SetSource(destination());
00268   emcOMCalFEM* om = static_cast<emcOMCalFEM*>
00269     (emcOMHelper::findOM(*calfem1, 0));
00270   //FIXME : WARNING !!! The line above should really be a dynamic_cast
00271   //to be on the very safe side.
00272   //For whatever reason it does not work. Have no time right now to
00273   //look into this. But if you read this because you crash here,
00274   //well, maybe it's time to look again...
00275   
00276   if (!om)
00277     {
00278       return kPluginNotFound;
00279     }
00280 
00281   om->FromPdbCalBank(*calfem1, bank);
00282 
00283   calfem1->SetValidityPeriod(bank.getStartValTime(), bank.getEndValTime());
00284 
00285   // Build nows an emcCalFEM object from file.
00286 
00287   emcDataManager* dm = emcDataManager::GetInstance();
00288 
00289   string olddir = dm->GetSourceDir(); // save dir value.
00290 
00291   dm->SetSourceDir(dir.c_str());
00292 
00293   emcCalFEM* calfem2 = emcCalFEMFactory::Create(flavour.c_str(),
00294                                                 femAbsolutePosition);
00295 
00296   calfem2->SetSource(emcManageable::kFile_ASCII);
00297 
00298   PHTimeStamp tdummy(0);
00299 
00300   int femCode = emcCalFEM::FEMCode(femAbsolutePosition, femPinNumber, 0, 0);
00301 
00302   bool ok = dm->Read(*calfem2, tdummy, femCode);
00303 
00304   dm->SetSourceDir(olddir.c_str()); // restore old dir value.
00305 
00306   if (!ok)
00307     {
00308       return kCannotReadFromFile;
00309     }
00310 
00311   if ( *calfem1 != *calfem2 )
00312     {
00313 
00314       emcTracedFEM* tfem = dynamic_cast<emcTracedFEM*>(calfem2);
00315 
00316       if ( !tfem )
00317         {
00318           return kDifferent;
00319         }
00320 
00321       if ( EmcIndexer::isPbScFEM(femAbsolutePosition) )
00322         {
00323 
00324           // No need for tricks if they match already.
00325           if ( *calfem1 == *calfem2 )
00326             {
00327               return kSame;
00328             }
00329 
00330           std::auto_ptr<emcTracedFEM> test(tfem->clone());
00331 
00332           // Try compact only first.
00333 
00334           cout << "Performing Compact(0.02)" << endl;
00335 
00336           test->Compact(0.02);
00337 
00338           if ( *(test.get()) == *calfem1 )
00339             {
00340               return kSame;
00341             }
00342 
00343           // For traced-like objects, there have been some tricks
00344           // applied when going from File to DB.
00345           // Try to re-apply them here to give one more chance
00346           // for a match.
00347 
00348           cout << "Performing RemoveLastItems() and Compact(0.02)" << endl;
00349           tfem->RemoveLastItems();
00350           if ( tfem->GetNumberOfItems() < tfem->GetNumberOfChannels() )
00351             {
00352               return kDifferent;
00353             }
00354           else
00355             {
00356               tfem->Compact(0.02);
00357             }
00358         }
00359       else
00360         {
00361           UpdateXValue(*tfem, 0);
00362         }
00363 
00364       if ( *calfem1 != *calfem2)
00365         {
00366           return kDifferent;
00367         }
00368       else
00369         {
00370           return kSame;
00371         }
00372     }
00373 
00374   return kSame;
00375 }
00376 
00377 //_____________________________________________________________________________
00378 emcManageable::EStorage
00379 emcDB::destination() const
00380 {
00381   if ( fDBMS == "Objy" )
00382     {
00383       return emcManageable::kDB_Objy;
00384     }
00385   else if ( fDBMS == "Pg" )
00386     {
00387       return emcManageable::kDB_Pg;
00388     }
00389   else if ( fDBMS == "Ascii" )
00390     {
00391       return emcManageable::kFile_ASCII;
00392     }
00393   else
00394     {
00395       std::cerr << "emcDB::destination : unknown DBMS=" << fDBMS
00396                 << std::endl;
00397       exit(1);
00398     }
00399 }
00400 //_____________________________________________________________________________
00401 bool
00402 emcDB::Dump(const string fulldbname)
00403 {
00404   //
00405   // Basic utility to dump a given DB on screen
00406   //
00407   // fulldbname is the full database name, i.e. including dots, like in
00408   // calib.emc.Gains
00409   //
00410 
00411   PdbCalBankIterator* it = BankManager()->getIterator();
00412 
00413   if (!it)
00414     {
00415       std::cerr << "emcDB::Dump : could not get a PdbCalBankIterator!"
00416                 << std::endl;
00417       ;
00418       return 0;
00419     }
00420 
00421   string bankName = fulldbname;
00422 
00423   cout << string(80, '-') << endl;
00424   cout << Version() << endl;
00425   cout << string(80, '-') << endl;
00426   cout << "Dumping " << bankName << " calibration database " << endl;
00427 
00428   PdbBankID bankID(fBankID);
00429 
00430   it->init(fulldbname.c_str(), bankID);
00431 
00432   if ( fInsertIntervalGiven )
00433     {
00434       it->setInsertTimeLimits(fInsertAfter, fInsertBefore);
00435     }
00436   if ( fStartIntervalGiven )
00437     {
00438       it->setStartValTimeLimits(fStartAfter, fStartBefore);
00439     }
00440   if ( fEndIntervalGiven )
00441     {
00442       it->setEndValTimeLimits(fEndAfter, fEndBefore);
00443     }
00444 
00445   it->print();
00446   cout << string(80, '-') << endl;
00447 
00448   string flavour;
00449 
00450   if ( bankName.find("calib.emc.") < bankName.size() )
00451     {
00452       flavour = bankName.substr(strlen("calib.emc."));
00453     }
00454 
00455   PdbCalBank* bank;
00456 
00457   while ( (bank = it->next()) )
00458     {
00459       bank->printHeader();
00460 
00461       if ( fInteractive == true )
00462         {
00463 
00464           cout << "[# of channels] Show channels [n] Next bank "
00465                << " [q] Quit, [c] Compare to file(s) " << endl;
00466           cout << "Please enter command >  ";
00467 
00468           string sanswer;
00469           cin >> sanswer;
00470 
00471           sanswer[0] = toupper(sanswer[0]);
00472 
00473           if ( sanswer == "C" )
00474             {
00475               CompareToDirectories(*bank, flavour);
00476             }
00477 
00478           if ( sanswer == "Q" )
00479             return Quit();
00480           if ( sanswer == "N" )
00481             continue;
00482 
00483           int nchannels = atoi(sanswer.c_str());
00484 
00485           DumpContent(*bank, nchannels);
00486         }
00487 
00488       delete bank;
00489     }
00490 
00491   return Quit();
00492 }
00493 
00494 
00495 //_____________________________________________________________________________
00496 void
00497 emcDB::CompareToDirectories(PdbCalBank& bank,
00498                             const string& flavour)
00499 {
00500   for (size_t j = 0; j < fDirectories.size(); j++ )
00501     {
00502       int compare = Compare(bank, fDirectories[j], flavour);
00503 
00504       if ( compare >= 0 )
00505         {
00506           string match = "MATCHES";
00507           if ( compare == 0 )
00508             {
00509               match = "DOES NOT match";
00510             }
00511           cout << match << " the one in "
00512                << fDirectories[j] << endl;
00513         }
00514       else
00515         {
00516           cout << "emcDB::CompareToDirectories  : "
00517                << "Cannot infer equality (return code "
00518                << compare << ")" << endl;
00519         }
00520     }
00521 }
00522 
00523 //_____________________________________________________________________________
00524 void
00525 emcDB::DumpContent(PdbCalBank& bank, int nchannels)
00526 {
00527   if (nchannels > 0)
00528     {
00529       for ( int i = 0;
00530             i < static_cast<int>(bank.getLength()) &&
00531               i < static_cast<int>(nchannels); i++)
00532         {
00533           bank.printEntry(i);
00534         }
00535     }
00536 }
00537 
00538 //_____________________________________________________________________________
00539 PHTimeStamp
00540 emcDB::EndOfValidity(void) const
00541 {
00542   if ( fForceEndDate )
00543     {
00544       return PHTimeStamp(*fForceEndDate);
00545     }
00546   else
00547     {
00548       PHTimeStamp end;
00549       end.setToFarFuture();
00550       return end;
00551     }
00552 }
00553 
00554 //_____________________________________________________________________________
00555 bool emcDB::Error(const string method, const string message)
00556 {
00557   cerr << "<E> emcDB::" << method << endl;
00558   cerr << "          :" << message << endl;
00559   return false;
00560 }
00561 
00562 //_____________________________________________________________________________
00563 int
00564 emcDB::GetPinNumber(int absPosition)
00565 {
00566   if (fPinNumbers.empty())
00567     {
00568       bool ok = ReadConfiguration(false);
00569       if (!ok)
00570         {
00571           cerr << EMC_ERROR_MSG
00572                << " Could not read configuration, thus pin numbers are not available"
00573                << "(i.e. you will not be able to properly compare pedestals)"
00574                << endl;
00575           fPinNumbers.resize(EmcIndexer::MaxNumberOfFEMs(), 0);
00576         }
00577     }
00578 
00579   return fPinNumbers[absPosition];
00580 }
00581 
00582 //_____________________________________________________________________________
00583 void
00584 emcDB::initDBMS(const char* dbms)
00585 {
00586   static std::set
00587     <std::string> alreadyLoaded;
00588 
00589   std::string DBMS = dbms;
00590 
00591   if ( alreadyLoaded.find(DBMS) != alreadyLoaded.end() )
00592     {
00593       return ;
00594     }
00595 
00596   // Be sure to load the correct libraries.
00597   if ( DBMS == "Objy" )
00598     {
00599       if ( !gSystem->Load("libemcOM.so") )
00600         {
00601           alreadyLoaded.insert("Objy");
00602         }
00603     }
00604   else if ( DBMS == "Pg" )
00605     {
00606       if ( !gSystem->Load("libemcOMpg.so") )
00607         {
00608           gSystem->Load("libPgCalInstance.so");
00609           PdbApplication* app = PdbApplication::instance();
00610           app->setDBName(fDbname.c_str());
00611           alreadyLoaded.insert("Pg");
00612         }
00613     }
00614   else if ( DBMS == "Ascii" )
00615     {
00616       if (!gSystem->Load("libemcOMascii.so"))
00617         {
00618           alreadyLoaded.insert("Ascii");
00619         }
00620     }
00621   else 
00622     {
00623       std::cerr << "emcDB::initDBMS : Do not know this DBMS : "
00624                 << DBMS << std::endl;
00625       exit(1);
00626     }
00627 }
00628 
00629 //_____________________________________________________________________________
00630 void emcDB::ParseFileName(const string filename, size_t& ifem, size_t& pin)
00631 {
00632   //
00633   // Get the FEM absolute number and pin number (if available)
00634   // from the file name.
00635   //
00636 
00637   int iS; // Sector number (0-8)
00638   int iSM144; // SuperModule number (0-144), within sector
00639 
00640   // ifem will be Absolute FEM id (0-172)
00641   // Note that iS=8 (=>ifem>171) denotes reference FEM(s)
00642 
00643   int offset = 0;
00644 
00645   if ( filename.substr(0, 4) == "NONE" )
00646     {
00647       iS = 8;
00648       offset = 2;
00649     }
00650   else
00651     {
00652       iS = EmcIndexer::EmcSectorNumber(const_cast<char*>(filename.substr(0, 2).c_str()));
00653     }
00654 
00655   iSM144 = atoi(filename.substr(4 + offset, 2).c_str());
00656 
00657   ifem = EmcIndexer::iSiSM144_PXSM144(iS, iSM144);
00658 
00659   size_t pos = filename.find("FEM");
00660 
00661   if (pos < filename.size())
00662     {
00663       pin = atoi(filename.substr(pos + 3, 4).c_str());
00664     }
00665   else
00666     {
00667       pin = 0;
00668     }
00669 }
00670 
00671 //_____________________________________________________________________________
00672 int emcDB::PedestalVersion(const string csdir)
00673 {
00674   string dir = csdir;
00675 
00676   char* cdir = gSystem->ExpandPathName(dir.c_str());
00677   void* dirp = gSystem->OpenDirectory(cdir);
00678   const char* entry;
00679   string str;
00680   int n = 0;
00681   int version = 0;
00682 
00683   assert(dirp != 0);
00684 
00685   while ( (version == 0) && (entry = gSystem->GetDirEntry(dirp)) )
00686     {
00687 
00688       str = entry;
00689 
00690       if (str.find("HG_Post") < str.size())
00691         n++;
00692       else
00693         if (str.find("LG_Post") < str.size())
00694           n++;
00695         else
00696           if (str.find("HG_Pre") < str.size())
00697             n++;
00698           else
00699             if (str.find("LG_Pre") < str.size())
00700               n++;
00701             else
00702               if (str.find("TAC") < str.size())
00703                 n++;
00704               else
00705                 if (str.find("LG_Pre-Post") < str.size())
00706                   n++;
00707                 else
00708                   if (str.find("HG_Pre-Post") < str.size())
00709                     n++;
00710     }
00711 
00712   if (n > 3)
00713     version = 1;
00714 
00715   gSystem->FreeDirectory(dirp);
00716   delete[] cdir;
00717 
00718   return version;
00719 }
00720 
00721 //_____________________________________________________________________________
00722 bool
00723 emcDB::Quit(void)
00724 {
00725   BankManager()->getApplication()->commit();
00726   return true;
00727 }
00728 
00729 //_____________________________________________________________________________
00730 void
00731 emcDB::SetEndInterval(const PHTimeStamp& endAfter,
00732                       const PHTimeStamp& endBefore)
00733 {
00734   fEndAfter = endAfter;
00735   fEndBefore = endBefore;
00736   fEndIntervalGiven = true;
00737 }
00738 
00739 //_____________________________________________________________________________
00740 void
00741 emcDB::SetInsertInterval(const PHTimeStamp& insertAfter,
00742                          const PHTimeStamp& insertBefore)
00743 {
00744   fInsertAfter = insertAfter;
00745   fInsertBefore = insertBefore;
00746   fInsertIntervalGiven = true;
00747 }
00748 
00749 //_____________________________________________________________________________
00750 void
00751 emcDB::SetStartInterval(const PHTimeStamp& startAfter,
00752                         const PHTimeStamp& startBefore)
00753 {
00754   fStartAfter = startAfter;
00755   fStartBefore = startBefore;
00756   fStartIntervalGiven = true;
00757 }
00758 
00759 //_____________________________________________________________________________
00760 bool emcDB::Update(const string ctedir)
00761 {
00762   //
00763   // Reads all the FEM calib. parameter from dir and put them into DB
00764   // Calib. flavor is taken from last characters in directory name.
00765   //
00766 
00767   string dir = ctedir;
00768 
00769   // Must be in interactive mode.
00770   if ( !fInteractive )
00771     {
00772       return Error("Update", "Must be in interactive mode.");
00773     }
00774 
00775   initDBMS("Ascii");
00776 
00777   // Check that directory does exist.
00778 
00779   char* cdir = gSystem->ExpandPathName(dir.c_str());
00780   void* dirp = gSystem->OpenDirectory(cdir);
00781 
00782   if ( !dirp )
00783     {
00784       cerr << "Failed to open directory: " << dir << endl;
00785       return false;
00786     }
00787 
00788   // Find the flavor type
00789 
00790   while (dir[dir.size() - 1] == '/')
00791     {
00792       dir = dir.substr(0, dir.size() - 1);
00793     }
00794 
00795   size_t pos = dir.rfind('/');
00796 
00797   string topdir = dir.substr(0, pos + 1);
00798   string flavor = dir.substr(pos + 1, dir.size() - pos - 1);
00799 
00800   // Dir. names and flavor names have not always the same name...
00801 
00802   if (flavor.find("Gains") < flavor.size())
00803     {
00804       flavor = "Gains";
00805     }
00806   else if (flavor.find("PEDESTALS") < flavor.size())
00807     {
00808       int version = PedestalVersion(ctedir);
00809       if (version == 0)
00810         {
00811           flavor = "Pedestals";
00812         }
00813       else if (version == 1)
00814         {
00815           flavor = "Pedestals5";
00816         }
00817       else
00818         {
00819           assert(0 == 1);
00820         }
00821     }
00822   else if (flavor.find("ToF") < flavor.size())
00823     {
00824       flavor = "TOF";
00825     }
00826   else if (flavor.find("HLRatio") < flavor.size())
00827     {
00828       flavor = "HLRatios";
00829     }
00830   else if (flavor.find("QA") < flavor.size())
00831     {
00832       flavor = "QAs";
00833     }
00834   else
00835     {
00836       // Other "flavors" are not emcCalFEM object and need
00837       // special treatment.
00838 
00839       bool inical = isInitialCalibrationDirectory(cdir);
00840       bool rejectlist = isRejectListDirectory(cdir);
00841 
00842       if ( !inical && !rejectlist )
00843         {
00844           cerr << "<E> Cannot infer flavor type for this directory : "
00845                << dir << endl;
00846           return false;
00847         }
00848       else if ( inical )
00849         {
00850           if ( fForceDate )
00851             {
00852               return UpdateInitialCalibration(topdir);
00853             }
00854           else
00855             {
00856               cerr << "<E> Updating IniCal requires the forceDate option so far."
00857                    << endl;
00858               return false;
00859             }
00860         }
00861       else if ( rejectlist )
00862         {
00863           if ( fForceDate )
00864             {
00865               return UpdateRejectList(topdir);
00866             }
00867           else
00868             {
00869               cerr << "<E> Updating RejectList requires the forceDate "
00870                    << "option so far."
00871                    << endl;
00872               return false;
00873             }
00874         }
00875     }
00876 
00877   cout << string(50, '-') << endl;
00878   cout << "FLAVOUR = " << flavor << endl;
00879   cout << string(50, '-') << endl;
00880 
00881   if ( topdir.empty() )
00882     {
00883       topdir = "./";
00884     }
00885 
00886   emcDataManager* dm = emcDataManager::GetInstance();
00887   dm->SetSourceDir(topdir.c_str());
00888 
00889   // We then loop over files in this directory
00890 
00891   const char* entry;
00892   string str;
00893   size_t ifem;
00894   size_t pin;
00895 
00896   emcCalFEM* read = 0;
00897 
00898   const size_t NMAX = 200;
00899   vector<bool> kAlreadyRead(NMAX);
00900   size_t i;
00901 
00902   for ( i = 0; i < kAlreadyRead.size(); i++ )
00903     {
00904       kAlreadyRead[i] = false;
00905     }
00906 
00907   PHTimeStamp tdummy;
00908   string theflavor;
00909 
00910   while ( (entry = gSystem->GetDirEntry(dirp)) )
00911     {
00912 
00913       str = entry;
00914 
00915       if (str == "." || str == "..")
00916         continue;
00917 
00918       theflavor = flavor;
00919 
00920       ParseFileName(str, ifem, pin);
00921 
00922       delete read;
00923 
00924       if (flavor == "TOF")
00925         {
00926           int runnumber = isRunNumber(str);
00927 
00928           if ( runnumber > 0 )
00929             {
00930               UpdateTofSectorOffset(cdir,runnumber);
00931               continue;
00932             }
00933 
00934           if (str.find(".TOF_LC") < str.size())
00935             {
00936               theflavor = "LCTofs";
00937               read = emcCalFEMFactory::Create("LCTofs", ifem);
00938             }
00939           else if (str.find(".TOF_WALK") < str.size())
00940             {
00941               theflavor = "WalkTofs";
00942               read = emcCalFEMFactory::Create("WalkTofs", ifem);
00943             }
00944           else if (str.find("PED-TOWERS-TAC-DRIFT.TofT0s") < str.size())
00945             {
00946               theflavor = "TacPeds";
00947               read = emcCalFEMFactory::Create("TacPeds", ifem);
00948             }
00949           else if (str.find(".TofT0s") < str.size())
00950             {
00951               std::string filename = cdir;
00952               filename += "/";
00953               filename += str;
00954               theflavor = getTofT0Flavor(filename);         
00955               read = emcCalFEMFactory::Create(theflavor.c_str(),ifem);
00956             }
00957           else
00958             {
00959               cerr << "<W> Unknown file type " << entry << endl;
00960               continue;
00961             }
00962         }
00963       else
00964         {
00965           read = emcCalFEMFactory::Create(flavor.c_str(), ifem);
00966         }
00967 
00968       assert(read != 0);
00969 
00970       read->SetSource(emcManageable::kFile_ASCII);
00971 
00972       read->SetDestination(destination());
00973 
00974       if ( ifem < kAlreadyRead.size() && !kAlreadyRead[ifem] )
00975         {
00976 
00977           int code = emcCalFEM::FEMCode(ifem, pin, 0, 0);
00978 
00979           assert(ifem < NMAX);
00980 
00981           cout << "Reading " << theflavor << "...";
00982 
00983           bool ok = dm->Read(*read, tdummy, code);
00984 
00985           cout << "done" << endl;
00986 
00987           if (ok)
00988             {
00989 
00990               //        if ( flavor == "Gains" && EmcIndexer::isPbScFEM(ifem) ) {
00991               //          // Special treatment for PbSc Gains.
00992               //          emcTracedFEM* tfem = dynamic_cast<emcTracedFEM*>(read);
00993               //          if (!tfem) {
00994               //            cerr << EMC_ERROR_MSG << " Uh Oh ! tfem is not of the expected type ?! PbSc gains not correctly handled. No writing done" << endl;
00995               //            ok = false;
00996               //          }
00997               //          else {
00998               //            tfem->RemoveLastItems();
00999               //            const float epsilon = 0.02;
01000               //            cout << " Compact level "
01001               //                 << tfem->Compact(epsilon)
01002               //              // merge items consistent within epsilon
01003               //                 << endl;
01004               //          }
01005               //        }
01006 
01007             }
01008 
01009           if (ok)
01010             {
01011               if (flavor != "TOF")
01012                 {
01013                   kAlreadyRead[ifem] = true;
01014                 }
01015 
01016               // Update the start validity time if requested
01017               if (fForceDate)
01018                 {
01019                   if ( fForceEndDate )
01020                     {
01021                       read->SetValidityPeriod(*fForceDate, *fForceEndDate);
01022                     }
01023                   else
01024                     {
01025                       read->SetValidityPeriod(*fForceDate, read->GetEndValTime());
01026                     }
01027                 }
01028 
01029               read->Print();
01030 
01031               cout << "Writing...";
01032               ok = dm->Write(*read, tdummy);
01033               if (!ok)
01034                 {
01035                   cerr << "<E> Could not dump FEM " << ifem << " into DB" << endl;
01036                   cout << "Failed" << endl;
01037                 }
01038               else
01039                 {
01040                   cout << "done" << endl;
01041                 }
01042             } // ok
01043         } // ifem valid
01044     } // while
01045 
01046   return true;
01047 }
01048 
01049 
01050 //_____________________________________________________________________
01051 void
01052 emcDB::UpdateXValue(emcTracedFEM& fem, int value)
01053 {
01054   // Replaces, for all channels, the X parameter by value.
01055   // Assumes that there only one item per channel.
01056   // Used by UpdatePbGlGains only.
01057 
01058   emcTracedValue* tv;
01059 
01060   for ( size_t i = 0; i < fem.GetNumberOfChannels(); i++ )
01061     {
01062       int n = 0;
01063       fem.FirstItem(i);
01064       while ( (tv = fem.NextItem()) != 0 )
01065         {
01066           tv->Set(value, tv->GetConstant(), tv->GetSlope());
01067           n++;
01068         }
01069       assert(n == 1);
01070     }
01071 }
01072 
01073 //_____________________________________________________________________________
01074 bool
01075 emcDB::UpdateInitialCalibration(const string top_directory)
01076 {
01077   string browsedir = top_directory;
01078 
01079   browsedir += "IniCal/";
01080 
01081   char* cdir = gSystem->ExpandPathName(browsedir.c_str());
01082   void* dirp = gSystem->OpenDirectory(cdir);
01083 
01084   cout << "<I> emcDB::UpdateInitialCalibration : dir = "
01085        << cdir << endl;
01086 
01087   const char* entry;
01088 
01089   while ( (entry = gSystem->GetDirEntry(dirp)) )
01090     {
01091       string str = entry;
01092 
01093       cout << str << endl;
01094 
01095       if ( str.find("INICAL") < str.size() )
01096         {
01097           // Get sector number out of here
01098           size_t pos = str.find('.');
01099           string sectorId = str.substr(0, pos);
01100           int iS = EmcIndexer::EmcSectorNumber(sectorId.c_str());
01101           if ( iS < 0 )
01102             {
01103               cerr << "<E> emcDB::UpdateInitialCalibration : file "
01104                    << str << " is not of InitialCalibration type, as "
01105                    << " its name suggest. I skip it."
01106                    << endl;
01107             }
01108           else
01109             {
01110               emcCalibrationData sector(emcCalibrationData::kIniCal, iS);
01111               sector.SetSource(emcManageable::kFile_ASCII);
01112               sector.SetDestination(destination());
01113               emcDataManager* dm = emcDataManager::GetInstance();
01114               dm->SetSourceDir(top_directory.c_str());
01115               PHTimeStamp dummy;
01116               bool ok = dm->Read(sector, dummy);
01117               if (ok)
01118                 {
01119                   assert(fForceDate != 0);
01120                   sector.SetValidityPeriod(*fForceDate, EndOfValidity());
01121                   sector.Print();
01122                   ok = dm->Write(sector);
01123                   if ( !ok )
01124                     {
01125                       cerr << "<E>  emcDB::UpdateInitialCalibration : "
01126                            << " Could not write sector " << iS
01127                            << " to Objy" << endl;
01128                     }
01129                 }
01130               else
01131                 {
01132                   cerr << "<E> emcDB::UpdateInitialCalibration : Could not "
01133                        << " read sector " << iS << " in "
01134                        << cdir << endl;
01135                 }
01136             }
01137         }
01138     }
01139 
01140   return true;
01141 }
01142 
01143 //_____________________________________________________________________________
01144 bool
01145 emcDB::UpdateRejectList(const string top_directory)
01146 {
01147   emcRejectList rl;
01148 
01149   emcDataManager* dm = emcDataManager::GetInstance();
01150 
01151   dm->SetSourceDir(top_directory.c_str());
01152 
01153   rl.SetSource(emcManageable::kFile_ASCII);
01154   rl.SetDestination(destination());
01155 
01156   PHTimeStamp dummy;
01157 
01158   bool ok = dm->Read(rl, dummy);
01159 
01160   if (ok)
01161     {
01162       assert(fForceDate != 0);
01163       rl.SetValidityPeriod(*fForceDate, EndOfValidity());
01164       ok = dm->Write(rl);
01165       if ( !ok )
01166         {
01167           cerr << "<E>  emcDB::UpdateRejectList : "
01168                << " Could not write rejectlist "
01169                << " to Objy" << endl;
01170         }
01171     }
01172   else
01173     {
01174       cerr << "<E> emcDB::UpdateRejectList : Could not "
01175            << " read rejectlist in "
01176            << top_directory << "/RejectList" << endl;
01177     }
01178   return true;
01179 }
01180 
01181 //_____________________________________________________________________________
01182 bool
01183 emcDB::UpdateTofSectorOffset(const std::string dir, int runnumber)
01184 {
01185   // Very first thing to check is that we do have valid start and 
01186   //  end timestamps for this run.
01187 
01188   RunToTime* rt = RunToTime::instance();
01189   if (!rt)
01190     {
01191       std::cerr << "UpdateTofSectorOffset: could not get to RunToTime object"
01192                 << std::endl;
01193       return false;
01194     }
01195 
01196   std::auto_ptr<PHTimeStamp> start(rt->getBeginTime(runnumber));
01197   std::auto_ptr<PHTimeStamp> end(rt->getEndTime(runnumber));
01198 
01199   if ( !start.get() )
01200     {
01201       std::cerr << "UpdateTofSectorOffset: could not get start time of run="
01202                 << runnumber << std::endl;
01203       return false;
01204     }
01205 
01206   if ( *(end.get()) <= *(start.get()) )
01207     {
01208       std::cout << "End time = " << *end << " of run=" << runnumber 
01209                 << " is invalid. I will use start+1 second" << std::endl;
01210       *(end.get()) = *(start.get());
01211       *(end.get()) += 1;
01212     }
01213 
01214   // Ok. We got the time stamps. Let's continue.
01215 
01216   std::ostringstream sdir;
01217   
01218   sdir << dir << "/" << std::setfill('0') << std::setw(10)
01219        << runnumber;
01220 
01221   char* cdir = gSystem->ExpandPathName(sdir.str().c_str());
01222   void* dirp = gSystem->OpenDirectory(cdir);
01223 
01224   if ( !dirp )
01225     {
01226       cerr << "Failed to open directory: " << dir << endl;
01227       return false;
01228     }
01229 
01230   const char* entry;
01231 
01232   // be very strict on the files we consider
01233   std::map<const std::string, int> validentries;
01234   validentries["W0.TOF_OFFSET"]=1;
01235   validentries["W1.TOF_OFFSET"]=1;
01236   validentries["W2.TOF_OFFSET"]=1;
01237   validentries["W3.TOF_OFFSET"]=1;
01238   validentries["E2.TOF_OFFSET"]=1;
01239   validentries["E3.TOF_OFFSET"]=1;
01240   validentries["E0.TOF_OFFSET"]=1;
01241   validentries["E1.TOF_OFFSET"]=1;
01242                                
01243   while ( (entry = gSystem->GetDirEntry(dirp)) )
01244     {
01245       std::string sentry = entry;
01246       if ( validentries[sentry] == 1 )
01247         {
01248           int isector = 
01249             EmcIndexer::EmcSectorNumber(sentry.substr(0,2).c_str());
01250           assert(isector>=0 && isector<=7);
01251 
01252           emcDataManager* dm = emcDataManager::GetInstance();
01253           emcCalibrationData sec(emcCalibrationData::kTofSectorOffset,isector);
01254           sec.SetSource(emcManageable::kFile_ASCII);
01255           bool ok = dm->Read(sec,runnumber);
01256           if (!ok)
01257             {
01258               std::cerr << "UpdateTofSectorOffset: could not read run "
01259                         << runnumber << " sector " << isector
01260                         << " from dir " << cdir
01261                         << std::endl;         
01262             }
01263           else
01264             {
01265               sec.SetValidityPeriod(*(start.get()),*(end.get()));
01266               sec.SetDestination(emcManageable::kDB_Pg);
01267               ok = dm->Write(sec);
01268               if (!ok)
01269                 {
01270                   std::cerr << "updatePbGlGains: could not upload "
01271                             << "for run " << runnumber
01272                             << " sector " << isector
01273                             << std::endl;
01274                 }
01275             }
01276         }
01277     }
01278 
01279   gSystem->FreeDirectory(dirp);
01280 
01281   return true;
01282 }
01283 
01284 //_____________________________________________________________________
01285 bool
01286 emcDB::UpdatePbGlGains(const string basedir)
01287 {
01288   // Read PbGlGain ASCII files from disk and
01289   // write them into Objy.
01290   //
01291   // Disk structure is supposed to be :
01292   //
01293   // basedir/
01294   //   | XXXXX/
01295   //   |   | Gains /
01296   //   | XXXXY/
01297   //   |   | Gains/
01298   //   | XXXXZ/
01299   //   |   | Gains/
01300   //   |   |
01301   //
01302   // etc...
01303 
01304   bool kFaultTolerant = false; // exit on any error.
01305 
01306   PHTimeStamp tdummy(0);
01307 
01308   // Reads the basedir directory to find out the list
01309   // of run number to handle.
01310   void* pdir = gSystem->OpenDirectory(basedir.c_str());
01311 
01312   if (!pdir)
01313     return false;
01314 
01315   const char* cfilename;
01316   std::vector<int> runs;
01317 
01318   while ( ( cfilename = gSystem->GetDirEntry(pdir) ) != 0 )
01319     {
01320       std::string filename = std::string(cfilename);
01321       if ( filename.find("Run") < filename.size() )
01322         {
01323           runs.push_back(atoi(filename.substr(3).c_str()));
01324         }
01325     }
01326 
01327   // Be kind with the user and tell him how many runs
01328   // were found.
01329   cout << EMC_INFO_MSG << "Number of runs in " << basedir
01330        << " = " << runs.size() << endl;
01331 
01332   if (runs.empty())
01333     {
01334       cerr << EMC_INFO_MSG << " huh ? no run found ? Is the top directory "
01335            << "correct ? " << endl;
01336       cerr << "I'm expecting something like " << endl;
01337       cerr << basedir << "/RunXXXX/Gains/..." << endl;
01338       cerr << basedir << "/RunXXXY/Gains/..." << endl;
01339       cerr << basedir << "/RunXXXZ/Gains/..." << endl;
01340       return false;
01341     }
01342 
01343   int maxrunnumber = 1500000;
01344 
01345   // Last run number put by hand.
01346   runs.push_back(maxrunnumber);
01347 
01348   // be sure run number are sorted.
01349   sort(runs.begin(), runs.end());
01350 
01351   // be sure we'll read relation run number <-> timestamp
01352   // from a file, not from DB (otherwise we might crash
01353   // if we're doing a test on a private Federation which
01354   // has no copy of the Run DB).
01355   initDBMS("Ascii");
01356   RunTimes* rt = RunTimesFactory::instance().create("Ascii");
01357   assert(rt != 0);
01358   rt->RunStart(1);
01359 
01360   // Just to ease the expert user's life, keep track
01361   // of "problematic" runs, i.e. those
01362   // whose start of validity period was not found.
01363   size_t irun;
01364   std::vector<int> pbruns;
01365   std::vector<int> pbruns_next;
01366 
01367   size_t nmax = runs.size();
01368 
01369   for ( irun = 0; irun < nmax - 1; irun++ )
01370     {
01371       PHTimeStamp start = rt->RunStart(runs[irun]);
01372       if (start.getTics() == 0)
01373         {
01374           pbruns.push_back(runs[irun]);
01375           pbruns_next.push_back(runs[irun + 1]);
01376         }
01377     }
01378 
01379   if (!pbruns.empty())
01380     {
01381       // report the problematic run numbers (with the intervals)
01382       std::cerr << "<E> Runs for which I did not find start date : ";
01383       for (irun = 0;irun < pbruns.size();irun++)
01384         {
01385           std::cerr << pbruns[irun] << "[ -" << pbruns_next[irun] << "] , ";
01386         }
01387       std::cerr << std::endl;
01388       std::cerr << " (" << pbruns.size() << " runs over "
01389                 << runs.size() << std::endl;
01390       std::cerr << "Correct this error before continuing\n"
01391         "Use emcDB --runtimes (with OO_FD_BOOT = PHENIX_FD_BOOT)\n"
01392         "to get an ASCII file containing run to timestamp relationship\n"
01393         "and complete this file for the runs mentionned above\n"
01394         "Then restart emcDB --updatePbGlGains\n" << std::endl;
01395       std::cerr << "Aborting now." << std::endl;
01396       // to avoid time gaps, we insure that we know all the dates we need.
01397       // if not, just exit.
01398       return false;
01399 
01400     }
01401 
01402   // Fine. Now to the real work.
01403   char des[80];
01404   char dirname[1024];
01405   bool ok;
01406 
01407   // Our beloved datamanager that will do the underlying work.
01408   emcDataManager* dm = emcDataManager::GetInstance();
01409 
01410   if (fDebug)
01411     {
01412       dm->SetVerboseLevel(10);
01413     }
01414 
01415   // Loop over all runs found in basedir.
01416   for ( irun = 0; irun < nmax - 1; irun++ )
01417     {
01418 
01419       sprintf(dirname, "%s/Run%d/", basedir.c_str(), runs[irun]);
01420       dm->SetSourceDir(dirname);
01421       // Let the user know where we are.
01422       std::cout << dirname << std::endl;
01423 
01424       // Loop over all PbGl fems.
01425       for ( int ifem = 108; ifem <= 171; ifem++)
01426         {
01427 
01428           // Create a gainFEM object, set the source
01429           // to file and destination to Objy.
01430           emcGainFEM gains(ifem);
01431           gains.SetSource(emcManageable::kFile_ASCII);
01432           gains.SetDestination(destination());
01433 
01434           // ask the DataManager to read this object for us.
01435           ok = dm->Read(gains, tdummy, ifem);
01436 
01437           if (ok)
01438             {
01439               // We got it from file, we now sets its validity
01440               // period, change its X parameter for all channels
01441               // (see emcTracedValue class.)
01442               // and write it into DB.
01443 
01444               PHTimeStamp start = rt->RunStart(runs[irun]);
01445               // end-of-validity of this set is the beginning
01446               // of next set, so there's no time-gap.
01447               PHTimeStamp end = rt->RunStart(runs[irun + 1]);
01448 
01449               assert(start.getTics() != 0);
01450 
01451               if ( runs[irun + 1] != maxrunnumber )
01452                 {
01453                   gains.SetValidityPeriod(start, end);
01454                   sprintf(des, "RUNS[%06d-%06d[", runs[irun], runs[irun + 1]);
01455                 }
01456               else
01457                 {
01458                   end.setToFarFuture();
01459                   gains.SetValidityPeriod(start, end);
01460                   sprintf(des, "RUNS[%06d-[", runs[irun]);
01461                 }
01462 
01463               if (fDebug)
01464                 {
01465                   cout << des << " " << start << " " << end << endl;
01466                   cout << rt->RunStart(runs[irun]) << endl;
01467                 }
01468               // Sets the description field of the gain
01469               // so that the description field of the pdbcalbank
01470               // will be meaningfull (e.g. when browsing the DB).
01471               gains.SetDescription(des);
01472 
01473               // Xmin and Xmax are the run number boundaries
01474               // for this calibration set.
01475               gains.SetXmin(runs[irun]);
01476               gains.SetXmax(runs[irun + 1]);
01477 
01478               // Short fix.
01479               UpdateXValue(static_cast<emcTracedFEM&>(gains), 0);
01480 
01481               // Let the DM do the job.
01482               ok = dm->Write(gains, tdummy);
01483               assert(ok == true);
01484             }
01485           else
01486             {
01487               std::cerr << "<E> Cannot read fem " << ifem << " for directory "
01488                         << dirname << std::endl;
01489               if (!kFaultTolerant)
01490                 return false;
01491             }
01492         }
01493 
01494       if (!ok)
01495         {
01496           std::cerr << "<E> Cannot write"
01497                     << " into DB " << std::endl;
01498           if (!kFaultTolerant)
01499             return false;
01500         }
01501     }
01502 
01503   return true;
01504 }
01505 
01506 //_____________________________________________________________________________
01507 void
01508 emcDB::MakeRunTimes(int minrunnumber)
01509 {
01510   initDBMS("Ascii");
01511   RunTimes* rt = RunTimesFactory::instance().create(fDBMS.c_str());
01512   if (!rt)
01513     {
01514       std::cerr << "emcDB::RunTimes: "
01515                 << "Could not get RunTimes object for DBMS="
01516                 << fDBMS
01517                 << std::endl;
01518       exit(1);
01519     }
01520   else
01521     {
01522       rt->MinRunNumber(minrunnumber);
01523       rt->Output();
01524     }
01525 }
01526 
01527 //_____________________________________________________________________________
01528 bool
01529 emcDB::ReadConfiguration(bool debug)
01530 {
01531   char str[200];
01532 
01533   emcConfigurationFile config(fConfigurationFile.c_str());
01534 
01535   if (!config.IsValid())
01536     return false;
01537 
01538   config.Rewind();
01539 
01540   fPinNumbers.resize(EmcIndexer::MaxNumberOfFEMs(), 0);
01541 
01542   string s;
01543   string fem;
01544   string pinNumber;
01545   vector<string> split;
01546   int absPosition;
01547 
01548   while ( config.GetLine(str, 200) )
01549     {
01550 
01551       s = str;
01552 
01553       // skip comments
01554       if ( s.substr(0, 2) == "//" || s.substr(0, 1) == "#" )
01555         continue;
01556 
01557       if ( s.find("FEM.EMC") < s.size() )
01558         {
01559 
01560           Split(s, split);
01561 
01562           if (split.size() == 4)
01563             {
01564               fem = split[0];
01565               absPosition = AbsolutePosition(fem);
01566               pinNumber = split[3];
01567               if (absPosition >= 0)
01568                 {
01569                   fPinNumbers[absPosition] = atoi(pinNumber.c_str());
01570                 }
01571               if (debug)
01572                 {
01573                   cout << fem << ":absPosition=" << absPosition
01574                        << ":pinNumber=" << fPinNumbers[absPosition] << endl;
01575                 }
01576 
01577             }
01578         }
01579 
01580     }
01581   return true;
01582 }
01583 
01584 //_____________________________________________________________________________
01585 void
01586 emcDB::Split(const string& str, vector<string>& split)
01587 {
01588   split.clear();
01589   string s = str;
01590 
01591   size_t i = 0;
01592 
01593   // Erase TABs and ,
01594   do
01595     {
01596 
01597       if (s[i] == '\t' || s[i] == ',')
01598         {
01599           s.erase(i, 1);
01600         }
01601       else
01602         {
01603           i++;
01604         }
01605     }
01606   while (i < s.size());
01607 
01608   // Erase multiple blanks
01609   i = 0;
01610   if (s.size() > 2)
01611     {
01612       do
01613         {
01614           if (s[i] == ' ' && s[i + 1] == ' ')
01615             {
01616               s.erase(i, 1);
01617             }
01618           else
01619             {
01620               i++;
01621             }
01622         }
01623       while (i < s.size() - 1);
01624     }
01625 
01626   // Now split on blanks
01627 
01628   vector<int> pos;
01629 
01630   for (i = 0;i < s.size();i++)
01631     {
01632       if (s[i] == ' ')
01633         pos.push_back(i);
01634     }
01635 
01636   pos.push_back(s.size());
01637 
01638   size_t p = 0;
01639 
01640   for (i = 0;i < pos.size();i++)
01641     {
01642       split.push_back(s.substr(p, pos[i] - p));
01643       p = pos[i] + 1;
01644     }
01645 }
01646 
01647 //_____________________________________________________________________________
01648 string
01649 emcDB::Version(void)
01650 {
01651   //  return string("emcDB 1.25 (11 February 2003)");
01652 
01653   // fix emcOMCalFEM:: and emcOMCalibrationData::Write memory leak
01654   // fix emcOMCalFEM::getRealName memory leak.
01655 
01656   //  return string("emcDB 1.26 (14 February 2003)");
01657   // fix the compare for emcTracedFEM.
01658 
01659   //  return string("emcDB 1.27 (07 March 2003)");
01660   // fix the update to work even if source directory is not fully
01661   // specified (i.e. in cases like emcDB --update directory : previouly
01662   // it had to be speficied ./directory. Now the ./ is added by emcDB itself
01663 
01664   //  return string("emcDB 1.4 (26 January 2004)");
01665   // externalize Objy specifics (so we get plug/unplug them, as well
01666   // as postgres ones).
01667 
01668   //  return string("emcDB 1.5 (04 February 2004)");
01669   // revive --runtimes option.
01670 
01671   //  return string("emcDB 1.6 (13 February 2004)");
01672   // handle TofT0Bs flavour (together with old TofT0s)
01673 
01674   //  return string("emcDB 1.7 (23 March 2004)");
01675   // reconnect --updatePbGlGains
01676 
01677   //  return string("emcDB 2.0 (10 June 2004)");
01678   // make Postgres the default DBMS
01679 
01680   //  return string("emcDB 2.01 (01 September 2004)");
01681   // fixing --update for rejectlist
01682 
01683   // return string("emcDB 2.02 (05 October 2004)");
01684   // adding --update for TofSectorOffsets
01685 
01686   return string("emcDB 2.1 (27 January 2005)");
01687   // adding --dbname option
01688 }