Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-06-06 07:38:10

0001 //emacs settings:-*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil -*-
0002 
0003 /***************************************************
0004  * TODO:  check Matacq                             *
0005  *        add DTT                                  *
0006  *        completion of partial output file        * 
0007  ***************************************************/
0008 
0009 #include "CalibCalorimetry/EcalLaserSorting/interface/LaserSorter.h"
0010 #include "CalibCalorimetry/EcalLaserSorting/src/Majority.h"
0011 
0012 #include <iostream>
0013 #include <iomanip>
0014 #include <algorithm>
0015 #include <sys/stat.h>
0016 #include <sys/types.h>
0017 #include <unistd.h>
0018 #include <cerrno>
0019 
0020 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0021 #include "FWCore/Framework/interface/Event.h"
0022 #include "FWCore/Framework/interface/EventSetup.h"
0023 #include "FWCore/Framework/interface/Run.h"
0024 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0025 #include "DataFormats/Provenance/interface/EventID.h"
0026 #include "DataFormats/FEDRawData/interface/FEDRawData.h"
0027 #include "DataFormats/FEDRawData/interface/FEDNumbering.h"
0028 #include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
0029 #include "DataFormats/Provenance/interface/LuminosityBlockID.h"
0030 #include "DataFormats/Provenance/interface/Timestamp.h"
0031 #include "EventFilter/EcalRawToDigi/interface/MatacqRawEvent.h"
0032 
0033 using namespace std;
0034 
0035 const int LaserSorter::ecalDccFedIdMin_ = 601;
0036 const int LaserSorter::ecalDccFedIdMax_ = 654;
0037 
0038 const size_t LaserSorter::OutStreamRecord::indexReserve_ = 2000;
0039 
0040 static const struct timeval nullTime = {0, 0};
0041 
0042 static const char* const detailedTrigNames[] = {
0043     "Inv0",  //000
0044     "Inv1",  //001
0045     "Inv2",  //010
0046     "Inv3",  //011
0047     "Las",   //100
0048     "Led",   //101
0049     "TP",    //110
0050     "Ped"    //111
0051 };
0052 
0053 static const char* const colorNames[] = {"Blue", "Green", "Red", "IR"};
0054 
0055 const LaserSorter::stats_t LaserSorter::stats_init = {0, 0, 0, 0, 0};
0056 const int LaserSorter::indexOffset32_ = 1;
0057 
0058 static std::string now() {
0059   struct timeval t;
0060   gettimeofday(&t, nullptr);
0061 
0062   char buf[256];
0063   strftime(buf, sizeof(buf), "%F %R %S s", localtime(&t.tv_sec));
0064   buf[sizeof(buf) - 1] = 0;
0065 
0066   stringstream buf2;
0067   buf2 << buf << " " << ((t.tv_usec + 500) / 1000) << " ms";
0068 
0069   return buf2.str();
0070 }
0071 
0072 LaserSorter::LaserSorter(const edm::ParameterSet& pset)
0073     : lumiBlock_(0),
0074       lumiBlockPrev_(0),
0075       formatVersion_(5),
0076       outputDir_(pset.getParameter<std::string>("outputDir")),
0077       fedSubDirs_(pset.getParameter<std::vector<std::string> >("fedSubDirs")),
0078       timeLogFile_(pset.getUntrackedParameter<std::string>("timeLogFile", "")),
0079       disableOutput_(pset.getUntrackedParameter<bool>("disableOutput", false)),
0080       runNumber_(0),
0081       outputListFile_(pset.getUntrackedParameter<string>("outputListFile", "")),
0082       doOutputList_(false),
0083       verbosity_(pset.getUntrackedParameter<int>("verbosity", 0)),
0084       iNoFullReadoutDccError_(0),
0085       maxFullReadoutDccError_(pset.getParameter<int>("maxFullReadoutDccError")),
0086       iNoEcalDataMess_(0),
0087       maxNoEcalDataMess_(pset.getParameter<int>("maxNoEcalDataMess")),
0088       lumiBlockSpan_(pset.getParameter<int>("lumiBlockSpan")),
0089       fedRawDataCollectionTag_(pset.getParameter<edm::InputTag>("fedRawDataCollectionTag")),
0090       stats_(stats_init),
0091       overWriteLumiBlockId_(pset.getParameter<bool>("overWriteLumiBlockId")),
0092       orbitCountInALumiBlock_(pset.getParameter<int>("orbitCountInALumiBlock")),
0093       orbit_(-1),
0094       orbitZeroTime_(nullTime) {
0095   gettimeofday(&timer_, nullptr);
0096   logFile_.open("eventSelect.log", ios::app | ios::out);
0097 
0098   const unsigned nEcalFeds = 54;
0099   if (fedSubDirs_.size() != nEcalFeds + 1) {
0100     throw cms::Exception("LaserSorter") << "Configuration error: "
0101                                         << "fedSubDirs parameter must be a vector "
0102                                         << " of " << nEcalFeds << " strings"
0103                                         << " (subdirectory for unknown triggered FED followed by "
0104                                            "subdirectories for FED ID 601 "
0105                                            "to FED ID 654 in increasing FED ID order)";
0106   }
0107 
0108   fedRawDataCollectionToken_ = consumes<FEDRawDataCollection>(fedRawDataCollectionTag_);
0109 
0110   if (!outputListFile_.empty()) {
0111     outputList_.open(outputListFile_.c_str(), ios::app);
0112     if (outputList_.bad()) {
0113       throw cms::Exception("FileOpen") << "Failed to open file '" << outputListFile_
0114                                        << "' for logging of output file path list.";
0115     }
0116     doOutputList_ = true;
0117   }
0118 
0119   if (!timeLogFile_.empty()) {
0120     timeLog_.open(timeLogFile_.c_str());
0121     if (timeLog_.fail()) {
0122       cout << "[LaserSorter " << now() << "] "
0123            << "Failed to open file " << timeLogFile_ << " to log timing.\n";
0124       timing_ = false;
0125     } else {
0126       timing_ = true;
0127     }
0128   }
0129 
0130   struct stat fileStat;
0131   if (0 == stat(outputDir_.c_str(), &fileStat)) {
0132     if (!S_ISDIR(fileStat.st_mode)) {
0133       throw cms::Exception("[LaserSorter]") << "File " << outputDir_ << " exists but is not a directory "
0134                                             << " as expected.";
0135     }
0136   } else {  //directory does not exists, let's try to create it
0137     if (0 != mkdir(outputDir_.c_str(), 0755)) {
0138       throw cms::Exception("[LaserSorter]") << "Failed to create directory " << outputDir_ << " for writing data.";
0139     }
0140   }
0141 
0142   logFile_ << "# "
0143               "run\t"
0144               "LB\t"
0145               "event\t"
0146               "trigType\t"
0147               "FED\t"
0148               "side\t"
0149               "LB out\t"
0150               "Written\t"
0151               "ECAL data\n";
0152 }
0153 
0154 LaserSorter::~LaserSorter() {
0155   logFile_ << "Summary. Event count: " << stats_.nRead << " processed, " << stats_.nWritten << " written, "
0156            << stats_.nInvalidDccStrict << " with errors in DCC ID values, " << stats_.nInvalidDccWeak
0157            << " with unusable DCC ID values, " << stats_.nRestoredDcc << " restored DCC ID based on DCC block size\n";
0158 }
0159 
0160 // ------------ method called to analyze the data  ------------
0161 void LaserSorter::analyze(const edm::Event& event, const edm::EventSetup& es) {
0162   if (timing_) {
0163     timeval t;
0164     gettimeofday(&t, nullptr);
0165     timeLog_ << t.tv_sec << "." << setfill('0') << setw(3) << (t.tv_usec + 500) / 1000 << setfill(' ') << "\t"
0166              << (t.tv_usec - timer_.tv_usec) * 1. + (t.tv_sec - timer_.tv_sec) * 1.e6 << "\t";
0167     timer_ = t;
0168   }
0169 
0170   ++stats_.nRead;
0171 
0172   if (event.id().run() != runNumber_) {  //run changed or first event
0173     //for a new run, starts with a new output stream set.
0174     closeAllStreams();
0175     runNumber_ = event.id().run();
0176     iNoFullReadoutDccError_ = 0;
0177     iNoEcalDataMess_ = 0;
0178     lumiBlockPrev_ = 0;
0179     lumiBlock_ = 0;
0180   }
0181 
0182   edm::Handle<FEDRawDataCollection> rawdata;
0183   event.getByToken(fedRawDataCollectionToken_, rawdata);
0184 
0185   //orbit number
0186   //FIXME: orbit from edm Event is currently wrong. Forcing to use of CMS orbit until
0187   //it is fixed. See https://hypernews.cern.ch/HyperNews/CMS/get/commissioning/5343/2.html
0188 #if 0
0189   orbit_ = event.orbitNumber();
0190 #else
0191   orbit_ = -1;
0192 #endif
0193 
0194   //  std::cerr << "Orbit ID CMS, ECAL: " << orbit_ << "\t" << getOrbitFromDcc(rawdata) << "\n";
0195 
0196   if (orbit_ < 0) {  //For local run CMSSW failed to find the orbit number
0197     //    cout << "Look for orbit from DCC headers....\n";
0198     orbit_ = getOrbitFromDcc(rawdata);
0199   }
0200 
0201   //The "detailed trigger type DCC field content:
0202   double dttProba = 0;
0203   int dtt = getDetailedTriggerType(rawdata, &dttProba);
0204 
0205   if (overWriteLumiBlockId_) {
0206     edm::LuminosityBlockNumber_t lb = lumiBlock_;
0207     lumiBlock_ = orbit_ / orbitCountInALumiBlock_;
0208     if (lb != lumiBlock_) {
0209       std::cout << "[LaserSorter " << now() << "] Overwrite LB mode. LB number changed from: " << lb << " to "
0210                 << lumiBlock_ << "\n";
0211     }
0212   } else {
0213     edm::LuminosityBlockNumber_t lb = lumiBlock_;
0214     lumiBlock_ = event.luminosityBlock();
0215     if (lb != lumiBlock_) {
0216       std::cout << "[LaserSorter " << now() << "] Standard LB mode. LB number changed from: " << lb << " to "
0217                 << lumiBlock_ << "\n";
0218     }
0219   }
0220 
0221   detailedTrigType_ = dtt;
0222   const int trigType = (detailedTrigType_ >> 8) & 0x7;
0223   const int color = (detailedTrigType_ >> 6) & 0x3;
0224   const int dccId = (detailedTrigType_ >> 0) & 0x3F;
0225   int triggeredFedId = (detailedTrigType_ == -2) ? -1 : (600 + dccId);
0226   const int side = (detailedTrigType_ >> 11) & 0x1;
0227   //monitoring region extended id:
0228   //  const int lme = dcc2Lme(dccId, side);
0229 
0230   if (detailedTrigType_ > -2) {
0231     if (dttProba < 1. || triggeredFedId < ecalDccFedIdMin_ || triggeredFedId > ecalDccFedIdMax_) {
0232       ++stats_.nInvalidDccStrict;
0233     }
0234 
0235     if (triggeredFedId < ecalDccFedIdMin_ || triggeredFedId > ecalDccFedIdMax_) {
0236       if (verbosity_)
0237         cout << "[LaserSorter " << now() << "] "
0238              << "DCC ID (" << dccId << ") found in trigger type is out of range.";
0239       ++stats_.nInvalidDccWeak;
0240       vector<int> ids = getFullyReadoutDccs(*rawdata);
0241       if (ids.empty()) {
0242         if (verbosity_ && iNoFullReadoutDccError_ < maxFullReadoutDccError_) {
0243           cout << " No fully read-out DCC found\n";
0244           ++iNoFullReadoutDccError_;
0245         }
0246       } else if (ids.size() == 1) {
0247         triggeredFedId = ids[0];
0248         if (verbosity_)
0249           cout << " ID guessed from DCC payloads\n";
0250         ++stats_.nRestoredDcc;
0251       } else {  //ids.size()>1
0252         if (verbosity_) {
0253           cout << " Several fully read-out Dccs:";
0254           for (unsigned i = 0; i < ids.size(); ++i)
0255             cout << " " << ids[i];
0256           cout << "\n";
0257         }
0258       }
0259     }
0260 
0261     if (verbosity_ > 1)
0262       cout << "\n----------------------------------------------------------------------\n"
0263            << "Event id: "
0264            << " " << event.id() << "\n"
0265            << "Lumin block: " << lumiBlock_ << "\n"
0266            << "TrigType: " << detailedTrigNames[trigType & 0x7] << " Color: " << colorNames[color & 0x3]
0267            << " FED: " << triggeredFedId << " side:" << side << "\n"
0268            << "\n----------------------------------------------------------------------\n";
0269 
0270   } else {  //NO ECAL DATA
0271     if (verbosity_ > 1)
0272       cout << "\n----------------------------------------------------------------------\n"
0273            << "Event id: "
0274            << " " << event.id() << "\n"
0275            << "Lumin block: " << lumiBlock_ << "\n"
0276            << "No ECAL data\n"
0277            << "\n----------------------------------------------------------------------\n";
0278   }
0279 
0280   logFile_ << event.id().run() << "\t" << lumiBlock_ << "\t" << event.id().event() << "\t" << trigType << "\t"
0281            << triggeredFedId << "\t" << side;
0282 
0283   bool written = false;
0284   int assignedLB = -1;
0285 
0286   if (lumiBlock_ != lumiBlockPrev_) {
0287     //lumi block change => need for stream garbage collection
0288     const int lb = lumiBlock_;
0289     closeOldStreams(lb);
0290     int minLumi = lumiBlock_ - lumiBlockSpan_;
0291     int maxLumi = lumiBlock_ + lumiBlockSpan_;
0292     for (int lb1 = minLumi; lb1 <= maxLumi; ++lb1) {
0293       restoreStreamsOfLumiBlock(lb1);
0294     }
0295   }
0296 
0297   //     if(lumiBlock_ < lumiBlockPrev_){
0298   //       throw cms::Exception("LaserSorter")
0299   //         << "Process event has a lumi block (" << lumiBlock_ << ")"
0300   //         << "older than previous one (" << lumiBlockPrev_ << "). "
0301   //         << "This can be due by wrong input file ordering or bad luminosity "
0302   //         << "block indication is the event header. "
0303   //         << "Event cannot be processed";
0304   //     }
0305 
0306   if (disableOutput_) {
0307     /* NO OP*/
0308   } else {
0309     const auto& out = getStream(triggeredFedId, lumiBlock_);
0310 
0311     if (out != nullptr) {
0312       assignedLB = out->startingLumiBlock();
0313       if (out->excludedOrbit().find(orbit_) == out->excludedOrbit().end()) {
0314         if (verbosity_ > 1)
0315           cout << "[LaserSorter " << now() << "] "
0316                << "Writing out event from FED " << triggeredFedId << " LB " << lumiBlock_ << " orbit " << orbit_
0317                << "\n";
0318         int dtt = (detailedTrigType_ >= 0) ? detailedTrigType_ : -1;  //shall we use -1 or 0 for undefined value?
0319         written = written || writeEvent(*out, event, dtt, *rawdata);
0320         ++stats_.nWritten;
0321       } else {
0322         if (verbosity_)
0323           cout << "[LaserSorter " << now() << "] "
0324                << "File " << out->finalFileName() << " "
0325                << "already contains calibration event from FED " << triggeredFedId << ", LB = " << lumiBlock_
0326                << " with orbit ID " << orbit_ << ". Event skipped.\n";
0327       }
0328     }
0329   }
0330   lumiBlockPrev_ = lumiBlock_;
0331 
0332   logFile_ << "\t";
0333   if (assignedLB >= 0)
0334     logFile_ << assignedLB;
0335   else
0336     logFile_ << "-";
0337   logFile_ << "\t" << (written ? "Y" : "N") << "\n";
0338   logFile_ << "\t" << (detailedTrigType_ == -2 ? "N" : "Y") << "\n";
0339 
0340   if (timing_) {
0341     timeval t;
0342     gettimeofday(&t, nullptr);
0343     timeLog_ << (t.tv_usec - timer_.tv_usec) * 1. + (t.tv_sec - timer_.tv_sec) * 1.e6 << "\n";
0344     timer_ = t;
0345   }
0346 }
0347 
0348 int LaserSorter::dcc2Lme(int dcc, int side) {
0349   int fedid = (dcc % 600) + 600;  //to handle both FED and DCC id.
0350   vector<int> lmes;
0351   // EE -
0352   if (fedid <= 609) {
0353     if (fedid <= 607) {
0354       lmes.push_back(fedid - 601 + 83);
0355     } else if (fedid == 608) {
0356       lmes.push_back(90);
0357       lmes.push_back(91);
0358     } else if (fedid == 609) {
0359       lmes.push_back(92);
0360     }
0361   }  //EB
0362   else if (fedid >= 610 && fedid <= 645) {
0363     lmes.push_back(2 * (fedid - 610) + 1);
0364     lmes.push_back(lmes[0] + 1);
0365   }  // EE+
0366   else if (fedid >= 646) {
0367     if (fedid <= 652) {
0368       lmes.push_back(fedid - 646 + 73);
0369     } else if (fedid == 653) {
0370       lmes.push_back(80);
0371       lmes.push_back(81);
0372     } else if (fedid == 654) {
0373       lmes.push_back(82);
0374     }
0375   }
0376   return lmes.empty() ? -1 : lmes[min(lmes.size(), (size_t)side)];
0377 }
0378 
0379 int LaserSorter::getOrbitFromDcc(const edm::Handle<FEDRawDataCollection>& rawdata) const {
0380   const int orbit32 = 6;
0381   for (int id = ecalDccFedIdMin_; id <= ecalDccFedIdMax_; ++id) {
0382     if (!FEDNumbering::inRange(id))
0383       continue;
0384     const FEDRawData& data = rawdata->FEDData(id);
0385     if (data.size() >= 4 * (orbit32 + 1)) {
0386       const uint32_t* pData32 = (const uint32_t*)data.data();
0387       //      cout << "Found a DCC header: "
0388       //           << pData32[0] << " "
0389       //           << pData32[1] << " "
0390       //           << pData32[2] << " "
0391       //           << pData32[3] << " "
0392       //           << pData32[4] << " "
0393       //           << pData32[5] << " "
0394       //           << pData32[6] << " "
0395       //           << "\n";
0396       return pData32[orbit32];
0397     }
0398   }
0399   return -1;
0400 }
0401 
0402 int LaserSorter::getDetailedTriggerType(const edm::Handle<FEDRawDataCollection>& rawdata, double* proba) {
0403   Majority<int> stat;
0404   bool ecalData = false;
0405   for (int id = ecalDccFedIdMin_; id <= ecalDccFedIdMax_; ++id) {
0406     if (!FEDNumbering::inRange(id))
0407       continue;
0408     const FEDRawData& data = rawdata->FEDData(id);
0409     const int detailedTrigger32 = 5;
0410     if (verbosity_ > 3)
0411       cout << "[LaserSorter " << now() << "] "
0412            << "FED " << id << " data size: " << data.size() << "\n";
0413     if (data.size() >= 4 * (detailedTrigger32 + 1)) {
0414       ecalData = true;
0415       const uint32_t* pData32 = (const uint32_t*)data.data();
0416       int tType = pData32[detailedTrigger32] & 0xFFF;
0417       if (verbosity_ > 3)
0418         cout << "[LaserSorter " << now() << "] "
0419              << "Trigger type " << tType << "\n";
0420       stat.add(tType);
0421     }
0422   }
0423   if (!ecalData)
0424     return -2;
0425   double p;
0426   int tType = stat.result(&p);
0427   if (p < 0) {
0428     //throw cms::Exception("NotFound") << "No ECAL DCC data found\n";
0429     if (iNoEcalDataMess_ < maxNoEcalDataMess_) {
0430       edm::LogWarning("NotFound") << "No ECAL DCC data found. "
0431                                      "(This warning will be disabled for the current run after "
0432                                   << maxNoEcalDataMess_ << " occurences.)";
0433       ++iNoEcalDataMess_;
0434     }
0435     tType = -1;
0436   } else if (p < .8) {
0437     //throw cms::Exception("EventCorruption") << "Inconsitency in detailed trigger type indicated in ECAL DCC data headers\n";
0438     edm::LogWarning("EventCorruption") << "Inconsitency in detailed trigger type indicated in ECAL DCC data headers\n";
0439     tType = -1;
0440   }
0441   if (proba)
0442     *proba = p;
0443   return tType;
0444 }
0445 
0446 void LaserSorter::closeAllStreams() {
0447   for (OutStreamList::iterator it = outStreamList_.begin(); it != outStreamList_.end(); /*NOOP*/) {
0448     it = closeOutStream(it);
0449   }
0450 }
0451 
0452 void LaserSorter::closeOldStreams(edm::LuminosityBlockNumber_t lumiBlock) {
0453   const edm::LuminosityBlockNumber_t minLumiBlock = lumiBlock - lumiBlockSpan_;
0454   const edm::LuminosityBlockNumber_t maxLumiBlock = lumiBlock + lumiBlockSpan_;
0455   //If container type is ever changed, beware that
0456   //closeOutStream call in the loop removes it from outStreamList
0457   for (OutStreamList::iterator it = outStreamList_.begin(); it != outStreamList_.end();
0458        /*NOOP*/) {
0459     if ((*it)->startingLumiBlock() < minLumiBlock || (*it)->startingLumiBlock() > maxLumiBlock) {
0460       //event older than 2 lumi block => stream can be closed
0461       if (verbosity_)
0462         cout << "[LaserSorter " << now() << "] "
0463              << "Closing file for "
0464              << "FED " << (*it)->fedId() << " LB " << (*it)->startingLumiBlock() << "\n";
0465       it = closeOutStream(it);
0466     } else {
0467       ++it;
0468     }
0469   }
0470 }
0471 
0472 const std::unique_ptr<LaserSorter::OutStreamRecord>& LaserSorter::getStream(int fedId,
0473                                                                             edm::LuminosityBlockNumber_t lumiBlock) {
0474   const static std::unique_ptr<LaserSorter::OutStreamRecord> streamNotFound(nullptr);
0475 
0476   if ((fedId != -1) && (fedId < ecalDccFedIdMin_ || fedId > ecalDccFedIdMax_))
0477     fedId = -1;
0478 
0479   if (verbosity_ > 1)
0480     cout << "[LaserSorter " << now() << "] "
0481          << "Looking for an opened output file for FED " << fedId << " LB " << lumiBlock << "\n";
0482 
0483   //first look if stream is already open:
0484   for (OutStreamList::iterator it = outStreamList_.begin(); it != outStreamList_.end(); ++it) {
0485     if ((*it)->fedId() == fedId && (abs((int)(*it)->startingLumiBlock() - (int)lumiBlock) <= lumiBlockSpan_)) {
0486       //stream found!
0487       return (*it);
0488     }
0489   }
0490   //stream was not found. Let's create one
0491 
0492   if (verbosity_)
0493     cout << "[LaserSorter " << now() << "] "
0494          << "File not yet opened. Opening it.\n";
0495 
0496   OutStreamList::iterator streamRecord = createOutStream(fedId, lumiBlock);
0497   return streamRecord != outStreamList_.end() ? (*streamRecord) : streamNotFound;
0498 }
0499 
0500 bool LaserSorter::writeEvent(OutStreamRecord& outRcd,
0501                              const edm::Event& event,
0502                              int dtt,
0503                              const FEDRawDataCollection& data) {
0504   ofstream& out = *outRcd.out();
0505   bool rc = true;
0506   vector<unsigned> fedIds;
0507   getOutputFedList(event, data, fedIds);
0508 
0509   out.clear();
0510   uint32_t evtStart = out.tellp();
0511   if (out.bad())
0512     evtStart = 0;
0513   rc &= writeEventHeader(out, event, dtt, fedIds.size());
0514 
0515   if (orbitZeroTime_.tv_sec == 0 && data.FEDData(matacqFedId_).size() != 0) {
0516     struct timeval ts = {0, 0};
0517     MatacqRawEvent mre(data.FEDData(matacqFedId_).data(), data.FEDData(matacqFedId_).size());
0518     mre.getTimeStamp(ts);
0519     uint32_t orb = mre.getOrbitId();
0520     if (ts.tv_sec != 0) {
0521       div_t dt = div(orb * 89.1, 1000 * 1000);  //an orbit lasts 89.1 microseconds
0522       orbitZeroTime_.tv_sec = ts.tv_sec - dt.quot;
0523       orbitZeroTime_.tv_usec = ts.tv_usec - dt.rem;
0524       if (orbitZeroTime_.tv_usec < 0) {
0525         orbitZeroTime_.tv_usec += 1000 * 1000;
0526         orbitZeroTime_.tv_sec -= 1;
0527       }
0528     }
0529   }
0530 
0531   for (unsigned iFed = 0; iFed < fedIds.size() && rc; ++iFed) {
0532     if (verbosity_ > 3)
0533       cout << "[LaserSorter " << now() << "] "
0534            << "Writing data block of FED " << fedIds[iFed] << ". Data size: " << data.FEDData(fedIds[iFed]).size()
0535            << "\n";
0536     rc &= writeFedBlock(out, data.FEDData(fedIds[iFed]));
0537   }
0538 
0539   if (rc) {
0540     //update index table for this file:
0541     vector<IndexRecord>& indices = *outRcd.indices();
0542     if (verbosity_ > 2) {
0543       std::cout << "Event "
0544                 << " written successfully. "
0545                 << "Orbit: " << orbit_ << "\tFile index: " << evtStart << "\n";
0546     }
0547     IndexRecord indexRcd = {(uint32_t)orbit_, evtStart};
0548     indices.push_back(indexRcd);
0549   }
0550   return rc;
0551 }
0552 
0553 bool LaserSorter::writeFedBlock(std::ofstream& out, const FEDRawData& data) {
0554   bool rc = false;
0555   if (data.size() > 4) {
0556     const uint32_t* pData = reinterpret_cast<const uint32_t*>(data.data());
0557 
0558     uint32_t dccLen64 = pData[2] & 0x00FFFFFF;  //in 32-byte unit
0559 
0560     if (data.size() != dccLen64 * sizeof(uint64_t)) {
0561       //       throw cms::Exception("Bug") << "Bug found in "
0562       //                                   << __FILE__ << ":" << __LINE__ << ".";
0563       throw cms::Exception("LaserSorter") << "Mismatch between FED fragment size indicated in header "
0564                                           << "(" << dccLen64 << "*8 Byte) "
0565                                           << "and actual size (" << data.size() << " Byte) "
0566                                           << "for FED ID " << ((pData[0] >> 8) & 0xFFF) << "!\n";
0567     }
0568 
0569     if (verbosity_ > 3)
0570       cout << "[LaserSorter " << now() << "] "
0571            << "Event fragment size: " << data.size() << " Byte"
0572            << "\t From Dcc header: " << dccLen64 * 8 << " Byte\n";
0573 
0574     const size_t nBytes = data.size();
0575     //       cout << "[LaserSorter " << now() << "] "
0576     //            << "Writing " << nBytes << " byte from adress "
0577     //            << (void*) data.data() << " to file.\n";
0578     if (out.fail())
0579       cout << "[LaserSorter " << now() << "] "
0580            << "Problem with stream!\n";
0581     out.write((const char*)data.data(), nBytes);
0582     rc = true;
0583   } else {
0584     throw cms::Exception("Bug") << "Bug found in " << __FILE__ << ":" << __LINE__ << ".\n";
0585   }
0586   return rc;
0587 }
0588 
0589 bool LaserSorter::renameAsBackup(const std::string& fileName, std::string& newFileName) {
0590   int i = 0;
0591   int err;
0592   //  static int maxTries = 100;
0593   int maxTries = 20;
0594   stringstream newFileName_;
0595   do {
0596     newFileName_.str("");
0597     newFileName_ << fileName << "~";
0598     if (i > 0)
0599       newFileName_ << i;
0600     err = link(fileName.c_str(), newFileName_.str().c_str());
0601     if (err == 0) {
0602       newFileName = newFileName_.str();
0603       err = unlink(fileName.c_str());
0604     }
0605     ++i;
0606   } while ((err != 0) && (errno == EEXIST) && (i < maxTries));
0607   return err == 0;
0608 }
0609 
0610 LaserSorter::OutStreamList::iterator LaserSorter::createOutStream(int fedId, edm::LuminosityBlockNumber_t lumiBlock) {
0611   if (verbosity_)
0612     cout << "[LaserSorter " << now() << "] "
0613          << "Creating a stream for FED " << fedId << " lumi block " << lumiBlock << ".\n";
0614   std::string tmpName;
0615   std::string finalName;
0616 
0617   streamFileName(fedId, lumiBlock, tmpName, finalName);
0618 
0619   errno = 0;
0620 
0621   //checks if a file with tmpName name already exists:
0622   ofstream* out = new ofstream(tmpName.c_str(), ios::out | ios::in);
0623   if (out->is_open()) {  //temporary file already exists. Making a backup:
0624     string newName;
0625     if (!renameAsBackup(tmpName, newName)) {
0626       throw cms::Exception("LaserSorter") << "Failed to rename file " << tmpName << "  to " << newName << "\n";
0627     }
0628     if (verbosity_)
0629       cout << "[LaserSorter " << now() << "] "
0630            << "Already existing File " << tmpName << " renamed to " << newName << "\n";
0631     out->close();
0632   }
0633 
0634   out->clear();
0635   out->open(tmpName.c_str(), ios::out | ios::trunc);
0636 
0637   if (out->fail()) {  //failed to create file
0638     delete out;
0639     throw cms::Exception("LaserSorter") << "Failed to create file " << tmpName << " for writing event from FED "
0640                                         << fedId << " lumi block " << lumiBlock << ": " << strerror(errno) << "\n.";
0641   }
0642 
0643   ifstream in(finalName.c_str());
0644   bool newFile = true;
0645   if (in.good()) {  //file already exists with final name.
0646     if (verbosity_)
0647       cout << "[LaserSorter " << now() << "] "
0648            << "File " << finalName << " already exists. It will be updated if needed.\n";
0649     //Copying its contents:
0650     char buffer[256];
0651     streamsize nread = -1;
0652     int vers = readFormatVersion(in, finalName);
0653     if (vers == -1) {
0654       edm::LogWarning("LaserSorter") << "File " << tmpName.c_str() << " is not an LMF file despite its extension or "
0655                                      << "it is corrupted.\n";
0656     } else if (vers != formatVersion_) {
0657       edm::LogWarning("LaserSorter") << "Cannot include events already in file " << tmpName.c_str()
0658                                      << " because of version "
0659                                      << "mismatch (found version " << (int)vers << " while "
0660                                      << "only version " << (int)formatVersion_ << " is supported).\n";
0661     } else {
0662       newFile = false;
0663       //read index table offset value:
0664       const int indexTableOffsetPos8 = 1 * sizeof(uint32_t);
0665       uint32_t indexTableOffsetValue = 0;
0666       in.clear();
0667       in.seekg(indexTableOffsetPos8, ios::beg);
0668       in.read((char*)&indexTableOffsetValue, sizeof(indexTableOffsetValue));
0669       if (in.fail()) {
0670         cout << "[LaserSorter " << now() << "] "
0671              << "Failed to read offset of index table "
0672                 " in the existing file "
0673              << finalName << "\n";
0674       } else {
0675         if (verbosity_ > 2)
0676           cout << "[LaserSorter " << now() << "] "
0677                << "Index table offset of "
0678                   "original file "
0679                << finalName << ": 0x" << hex << setfill('0') << setw(8) << indexTableOffsetValue << dec << setfill(' ')
0680                << "\n";
0681       }
0682       in.clear();
0683       in.seekg(0, ios::beg);
0684 
0685       //copy legacy file contents except the index table
0686       uint32_t toRead = indexTableOffsetValue;
0687       cout << "[LaserSorter " << now() << "] "
0688            << "Copying " << finalName << " to " << tmpName << endl;
0689       while (!in.eof() && (toRead > 0) && (nread = in.readsome(buffer, min(toRead, (uint32_t)sizeof(buffer)))) != 0) {
0690         //         cout << "Writing " << nread << " bytes to file "
0691         //              << tmpName.c_str() << "\n";
0692         toRead -= nread;
0693         // out->seekp(0, ios::end);
0694         out->write(buffer, nread);
0695         if (out->bad()) {
0696           throw cms::Exception("LaserSorter")
0697               << "Error while writing to file " << tmpName << ". Check if there is enough "
0698               << "space on the device.\n";
0699         }
0700       }
0701 
0702       //resets index table offset field:
0703       indexTableOffsetValue = 0;
0704       out->clear();
0705       out->seekp(indexTableOffsetPos8, ios::beg);
0706       out->write((char*)&indexTableOffsetValue, sizeof(uint32_t));
0707       out->clear();
0708       out->seekp(0, ios::end);
0709     }
0710   }
0711 
0712 #if 0
0713   out->flush();
0714   cout << "Press enter... file name was " << tmpName << endl;
0715   char c;
0716   cin >> c;
0717 #endif
0718 
0719   OutStreamRecord* outRcd = new OutStreamRecord(fedId, lumiBlock, out, tmpName, finalName);
0720 
0721   if (newFile) {
0722     writeFileHeader(*out);
0723   } else {
0724     std::string errMsg;
0725     if (!readIndexTable(in, finalName, *outRcd, &errMsg)) {
0726       throw cms::Exception("LaserSorter") << errMsg << "\n";
0727     }
0728   }
0729 
0730   return outStreamList_.emplace(outStreamList_.end(), outRcd);
0731 }
0732 
0733 void LaserSorter::writeFileHeader(std::ofstream& out) {
0734   out.clear();
0735 
0736   uint32_t id = 'L' | ('M' << 8) | ('F' << 16) | (formatVersion_ << 24);
0737 
0738   out.write((char*)&id, sizeof(uint32_t));
0739 
0740   //index position (to be filled at end of writing)
0741   uint32_t zero = 0;
0742   out.write((char*)&zero, sizeof(uint32_t));
0743 
0744   if (out.fail()) {
0745     throw cms::Exception("LaserSorter") << "Failed to write file header.\n";
0746   }
0747 }
0748 
0749 bool LaserSorter::writeEventHeader(std::ofstream& out, const edm::Event& evt, int dtt, unsigned nFeds) {
0750   uint32_t data[10];
0751   timeval tt = {0, 0};
0752   if ((evt.time().value() >> 32)) {
0753     tt.tv_usec = evt.time().value() & 0xFFFFFFFF;
0754     tt.tv_sec = evt.time().value() >> 32;
0755   } else if (orbitZeroTime_.tv_sec) {
0756     div_t dt = div(orbit_ * 89.1, 1000 * 1000);  //one orbit lasts 89.1 microseconds
0757     tt.tv_sec = orbitZeroTime_.tv_sec + dt.quot;
0758     tt.tv_usec = orbitZeroTime_.tv_usec + dt.rem;
0759     if (tt.tv_usec > 1000 * 1000) {
0760       tt.tv_usec -= 1000 * 1000;
0761       tt.tv_sec += 1;
0762     }
0763   }
0764 
0765   data[0] = tt.tv_usec;
0766   data[1] = tt.tv_sec;
0767   data[2] = evt.luminosityBlock();
0768   data[3] = evt.run();
0769   data[4] = orbit_;
0770   data[5] = evt.bunchCrossing();
0771   data[6] = evt.id().event();
0772   data[7] = dtt;
0773   data[8] = nFeds;
0774   data[9] = 0;  //reserved (to be aligned on 64-bits)
0775 
0776   if (verbosity_ > 1) {
0777     cout << "[LaserSorter " << now() << "] "
0778          << "Write header of event: "
0779          << "Time: " << toString(evt.time().value()) << ", LB: " << evt.luminosityBlock() << ", Run: " << evt.run()
0780          << ", Bx: " << evt.bunchCrossing() << ", Event ID: " << evt.id().event() << ", Detailed trigger type: 0x"
0781          << hex << dtt << dec << " (" << detailedTrigNames[(dtt >> 8) & 0x7] << ", " << colorNames[(dtt >> 6) & 0x3]
0782          << ", DCC " << (dtt & 0x3f) << ", side " << ((dtt >> 10) & 0x1) << ")"
0783          << ", number of FEDs: "
0784          << "\n";
0785   }
0786 
0787   out.clear();
0788   out.write((char*)data, sizeof(data));
0789   return !out.bad();
0790 }
0791 
0792 void LaserSorter::streamFileName(int fedId,
0793                                  edm::LuminosityBlockNumber_t lumiBlock,
0794                                  std::string& tmpName,
0795                                  std::string& finalName) {
0796   int iFed;
0797   if (fedId >= ecalDccFedIdMin_ && fedId <= ecalDccFedIdMax_) {
0798     iFed = fedId - ecalDccFedIdMin_ + 1;
0799   } else if (fedId < 0) {
0800     iFed = -1;  //event w/o ECAL data
0801   } else {
0802     iFed = 0;
0803   }
0804   if (iFed < -1 || iFed >= (int)fedSubDirs_.size()) {
0805     throw cms::Exception("LaserSorter") << "Bug found at " << __FILE__ << ":" << __LINE__
0806                                         << ". FED ID is out of index!";
0807   }
0808 
0809   struct stat fileStat;
0810 
0811   stringstream buf;
0812   buf << outputDir_ << "/" << (iFed < 0 ? "Empty" : fedSubDirs_[iFed]);
0813 
0814   string dir = buf.str();
0815   if (0 == stat(dir.c_str(), &fileStat)) {
0816     if (!S_ISDIR(fileStat.st_mode)) {
0817       throw cms::Exception("[LaserSorter]") << "File " << dir << " exists but is not a directory "
0818                                             << " as expected.";
0819     }
0820   } else {  //directory does not exists, let's try to create it
0821     if (0 != mkdir(dir.c_str(), 0755)) {
0822       throw cms::Exception("[LaserSorter]") << "Failed to create directory " << dir << " for writing data.";
0823     }
0824   }
0825 
0826   buf.str("");
0827   buf << "Run" << runNumber_ << "_LB" << setfill('0') << setw(4) << lumiBlock << ".lmf";
0828   string fileName = buf.str();
0829   string tmpFileName = fileName + ".part";
0830 
0831   finalName = dir + "/" + fileName;
0832   tmpName = dir + "/" + tmpFileName;
0833 
0834   if (verbosity_ > 3)
0835     cout << "[LaserSorter " << now() << "] "
0836          << "File path: " << finalName << "\n";
0837 }
0838 
0839 LaserSorter::OutStreamList::iterator LaserSorter::closeOutStream(LaserSorter::OutStreamList::iterator streamRecord) {
0840   if (streamRecord == outStreamList_.end())
0841     return outStreamList_.end();
0842 
0843   if (verbosity_)
0844     cout << "[LaserSorter " << now() << "] "
0845          << "Writing Index table of file " << (*streamRecord)->finalFileName() << "\n";
0846   ofstream& out = *(*streamRecord)->out();
0847   out.clear();
0848   if (!writeIndexTable(out, *(*streamRecord)->indices())) {
0849     cout << "Error while writing index table for file " << (*streamRecord)->finalFileName() << ". "
0850          << "Resulting file might be corrupted. "
0851          << "The error can be due to a lack of disk space.";
0852   }
0853 
0854   if (verbosity_)
0855     cout << "[LaserSorter " << now() << "] "
0856          << "Closing file " << (*streamRecord)->finalFileName() << ".\n";
0857   out.close();
0858 
0859   const std::string& tmpFileName = (*streamRecord)->tmpFileName();
0860   const std::string& finalFileName = (*streamRecord)->finalFileName();
0861 
0862   if (verbosity_)
0863     cout << "[LaserSorter " << now() << "] "
0864          << "Renaming " << tmpFileName << " to " << finalFileName << ".\n";
0865 
0866   if (0 != rename(tmpFileName.c_str(), finalFileName.c_str())) {
0867     cout << "[LaserSorter " << now() << "] "
0868          << " Failed to rename output file from " << tmpFileName << " to " << finalFileName << ". " << strerror(errno)
0869          << "\n";
0870   }
0871 
0872   if (doOutputList_) {
0873     char buf[256];
0874     time_t t = time(nullptr);
0875     strftime(buf, sizeof(buf), "%F %R:%S", localtime(&t));
0876 
0877     ifstream f(".watcherfile");
0878     string inputFile;
0879     f >> inputFile;
0880     outputList_ << finalFileName << "\t" << buf << "\t" << inputFile << endl;
0881   }
0882 
0883   return outStreamList_.erase(streamRecord);
0884 }
0885 
0886 void LaserSorter::endJob() {
0887   //TODO: better treatement of last files:
0888   //they might be imcomplete...
0889   closeAllStreams();
0890 }
0891 
0892 void LaserSorter::beginJob() {}
0893 
0894 bool LaserSorter::isDccEventEmpty(const FEDRawData& data, size_t* dccLen, int* nTowerBlocks) const {
0895   if (nTowerBlocks)
0896     *nTowerBlocks = 0;
0897   //DCC event is considered empty if it does not contains any Tower block
0898   //( = FE data)
0899   bool rc = true;
0900   if (dccLen)
0901     *dccLen = 0;
0902   const unsigned nWord32 = data.size() / sizeof(uint32_t);
0903   if (nWord32 == 0) {
0904     //cout << "[LaserSorter " << now() << "] " << "FED block completly empty\n";
0905     return true;
0906   }
0907   for (unsigned iWord32 = 0; iWord32 < nWord32; iWord32 += 2) {
0908     const uint32_t* data32 = ((const uint32_t*)(data.data())) + iWord32;
0909     int dataType = (data32[1] >> 28) & 0xF;
0910     //     cout << hex << "0x" << setfill('0')
0911     //          << setw(8) << data32[1] << "'" << setw(8) << data32[0]
0912     //          << " dataType: 0x" << dataType
0913     //          << dec << setfill(' ') << "\n";
0914     if (0 == (dataType >> 2)) {  //in DCC header
0915       const int dccHeaderId = (data32[1] >> 24) & 0x3F;
0916       if (dccHeaderId == 1) {
0917         if (dccLen)
0918           *dccLen = ((data32[0] >> 0) & 0xFFFFFF);
0919       }
0920     }
0921     if ((dataType >> 2) == 3) {  //Tower block
0922       rc = false;
0923       if (nTowerBlocks) {  //number of tower block must be counted
0924         ++(*nTowerBlocks);
0925       } else {
0926         break;
0927       }
0928     }
0929   }
0930   //   cout << "[LaserSorter " << now() << "] " << "DCC Len: ";
0931 
0932   //   if(dccLen){
0933   //     cout << (*dccLen) << " event ";
0934   //   }
0935   //   cout << (rc?"":"non") << " empty"
0936   //        << endl;
0937   return rc;
0938 }
0939 
0940 void LaserSorter::getOutputFedList(const edm::Event& event,
0941                                    const FEDRawDataCollection& data,
0942                                    std::vector<unsigned>& fedIds) const {
0943   fedIds.erase(fedIds.begin(), fedIds.end());
0944   for (int id = ecalDccFedIdMin_; id <= ecalDccFedIdMax_; ++id) {
0945     size_t dccLen;
0946     const FEDRawData& dccEvent = data.FEDData(id);
0947     if (!isDccEventEmpty(dccEvent, &dccLen)) {
0948       fedIds.push_back(id);
0949     }
0950     if (dccLen * sizeof(uint64_t) != dccEvent.size()) {
0951       edm::LogWarning("LaserSorter") << "Length error in data of FED " << id << " in event " << event.id()
0952                                      << ", Data of this FED dropped.";
0953     }
0954   }
0955   //   cout << __FILE__ << ":" << __LINE__ << ": "
0956   //        <<  "data.FEDData(" << matacqFedId_ << ").size() = "
0957   //        <<  data.FEDData(matacqFedId_).size() << "\n";
0958   if (data.FEDData(matacqFedId_).size() > 4) {  //matacq block present
0959     //    cout << __FILE__ << ":" << __LINE__ << ": "
0960     //     <<  "Adding matacq to list of FEDs\n";
0961     fedIds.push_back(matacqFedId_);
0962   }
0963 }
0964 
0965 std::vector<int> LaserSorter::getFullyReadoutDccs(const FEDRawDataCollection& data) const {
0966   int nTowers;
0967   vector<int> result;
0968   for (int fed = ecalDccFedIdMin_; fed <= ecalDccFedIdMax_; ++fed) {
0969     const FEDRawData& fedData = data.FEDData(fed);
0970     isDccEventEmpty(fedData, nullptr, &nTowers);
0971     if (nTowers >= 68)
0972       result.push_back(fed);
0973   }
0974   return result;
0975 }
0976 
0977 bool LaserSorter::writeIndexTable(std::ofstream& out, std::vector<IndexRecord>& indices) {
0978   uint32_t indexTablePos = out.tellp();
0979   uint32_t nevts = indices.size();
0980 
0981   out.clear();
0982   out.write((char*)&nevts, sizeof(nevts));
0983   const uint32_t reserved = 0;
0984   out.write((const char*)&reserved, sizeof(reserved));
0985 
0986   if (out.bad())
0987     return false;
0988 
0989   sort(indices.begin(), indices.end());
0990 
0991   for (unsigned i = 0; i < indices.size(); ++i) {
0992     uint32_t data[2];
0993     data[0] = indices[i].orbit;
0994     data[1] = indices[i].filePos;
0995     out.write((char*)data, sizeof(data));
0996   }
0997 
0998   if (out.bad())
0999     return false;  //intial 0 valur for index table position
1000   //                            is left to indicate corrupted table.
1001 
1002   //writes index table position:x
1003   out.clear();
1004   out.seekp(indexOffset32_ * sizeof(uint32_t));
1005   //   cout << "[LaserSorter] Index table position: 0x" << hex << indexTablePos
1006   //        << dec << "\n";
1007   if (!out.bad())
1008     out.write((char*)&indexTablePos, sizeof(uint32_t));
1009 
1010   bool rc = !out.bad();
1011 
1012   //reposition pointer to eof:
1013   out.seekp(0, ios::end);
1014 
1015   return rc;
1016 }
1017 
1018 //beware this method change the pointer position in the ifstream in
1019 bool LaserSorter::readIndexTable(std::ifstream& in, std::string& inName, OutStreamRecord& outRcd, std::string* err) {
1020   stringstream errMsg;
1021 
1022   ifstream* s = &in;
1023 
1024   //streampos pos = s->tellg();
1025   s->clear();
1026   s->seekg(0);
1027 
1028   uint32_t fileHeader[2];
1029   s->read((char*)&fileHeader[0], sizeof(fileHeader));
1030   uint32_t indexTablePos = fileHeader[1];
1031 
1032   if (s->eof()) {
1033     s->clear();
1034     s->seekg(0);
1035     errMsg << "Failed to read header of file " << inName << ".";
1036     if (err)
1037       *err = errMsg.str();
1038     return false;
1039   }
1040 
1041   s->seekg(indexTablePos);
1042 
1043   uint32_t nevts = 0;
1044   s->read((char*)&nevts, sizeof(nevts));
1045   s->ignore(4);
1046   if (s->bad()) {
1047     errMsg << "Failed to read index table from file " << inName << ".";
1048     if (err)
1049       *err = errMsg.str();
1050     return false;
1051   }
1052   if (nevts > maxEvents_) {
1053     errMsg << "Number of events indicated in event index of file " << inName << " (" << nevts << ") "
1054            << "is unexpectively large.";
1055     if (err)
1056       *err = errMsg.str();
1057     return false;
1058   }
1059   outRcd.indices()->resize(nevts);
1060   s->read((char*)&(*outRcd.indices())[0], nevts * sizeof(IndexRecord));
1061   if (s->bad()) {
1062     outRcd.indices()->clear();
1063     errMsg << "Failed to read index table from file " << inName << ".";
1064     if (err)
1065       *err = errMsg.str();
1066     return false;
1067   }
1068   if (nevts > maxEvents_) {
1069     errMsg << "Number of events indicated in event index of file " << inName << " is unexpectively large.";
1070     if (err)
1071       *err = errMsg.str();
1072     outRcd.indices()->clear();
1073     return false;
1074   }
1075 
1076   if (verbosity_ > 1)
1077     cout << "[LaserSorter " << now() << "] "
1078          << "Orbit IDs of events "
1079          << "already contained in the file " << inName << ":";
1080   for (unsigned i = 0; i < outRcd.indices()->size(); ++i) {
1081     if (verbosity_ > 1) {
1082       cout << " " << setw(9) << (*outRcd.indices())[i].orbit;
1083     }
1084     outRcd.excludedOrbit().insert((*outRcd.indices())[i].orbit);
1085   }
1086   if (verbosity_ > 1)
1087     cout << "\n";
1088 
1089   return true;
1090 }
1091 
1092 int LaserSorter::readFormatVersion(std::ifstream& in, const std::string& fileName) {
1093   int vers = -1;
1094   streampos p = in.tellg();
1095 
1096   uint32_t data;
1097 
1098   in.read((char*)&data, sizeof(data));
1099 
1100   char magic[4];
1101 
1102   magic[0] = data & 0xFF;
1103   magic[1] = (data >> 8) & 0xFF;
1104   magic[2] = (data >> 16) & 0xFF;
1105   magic[3] = 0;
1106 
1107   const string lmf = string("LMF");
1108 
1109   if (in.good() && lmf == magic) {
1110     vers = (data >> 24) & 0xFF;
1111   }
1112 
1113   if (lmf != magic) {
1114     edm::LogWarning("LaserSorter") << "File " << fileName << "is not an LMF file.\n";
1115   }
1116 
1117   in.clear();
1118   in.seekg(p);
1119   return vers;
1120 }
1121 
1122 std::string LaserSorter::toString(uint64_t t) {
1123   char buf[256];
1124 
1125   time_t tsec = t >> 32;
1126 
1127   uint32_t tusec = t & 0xFFFFFFFF;
1128   strftime(buf, sizeof(buf), "%F %R %S s", localtime(&tsec));
1129   buf[sizeof(buf) - 1] = 0;
1130 
1131   stringstream buf2;
1132   buf2 << (tusec + 500) / 1000;
1133 
1134   return string(buf) + " " + buf2.str() + " ms";
1135 }
1136 
1137 void LaserSorter::restoreStreamsOfLumiBlock(int lumiBlock) {
1138   string dummy;
1139   string fileName;
1140 
1141   for (int fedId = ecalDccFedIdMin_ - 2; fedId <= ecalDccFedIdMax_; ++fedId) {
1142     int fedId_;
1143     if (fedId == ecalDccFedIdMin_ - 2)
1144       fedId_ = -1;  //stream for event w/o ECAL data
1145     else
1146       fedId_ = fedId;
1147     streamFileName(fedId_, lumiBlock, dummy, fileName);
1148     struct stat s;
1149     //TODO: could be optimized by adding an option to get stream
1150     //to open only existing file: would avoid double call to streamFileName.
1151     if (stat(fileName.c_str(), &s) == 0) {  //file exists
1152       getStream(fedId_, lumiBlock);
1153     }
1154   }
1155 }
1156 
1157 void LaserSorter::beginRun(edm::Run const& run, edm::EventSetup const& es) {}
1158 
1159 void LaserSorter::endRun(edm::Run const& run, edm::EventSetup const& es) {}