Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:39:00

0001 // -*- C++ -*-
0002 //
0003 // Package:     FWLite
0004 // Class  :     MultiChainEvent
0005 //
0006 // Implementation:
0007 //     <Notes on implementation>
0008 //
0009 // Original Author:  Salvatore Rappoccio
0010 //         Created:  Thu Jul  9 22:05:56 CDT 2009
0011 //
0012 
0013 // system include files
0014 #include <iostream>
0015 
0016 // user include files
0017 #include "DataFormats/FWLite/interface/MultiChainEvent.h"
0018 #include "DataFormats/Common/interface/EDProductGetter.h"
0019 #include "DataFormats/FWLite/interface/Handle.h"
0020 #include "DataFormats/Common/interface/TriggerResults.h"
0021 #include "DataFormats/Provenance/interface/ProcessHistory.h"
0022 #include "FWCore/Common/interface/TriggerResultsByName.h"
0023 
0024 #include <algorithm>
0025 
0026 namespace fwlite {
0027 
0028   namespace internal {
0029 
0030     class MultiProductGetter : public edm::EDProductGetter {
0031     public:
0032       MultiProductGetter(MultiChainEvent const* iEvent) : event_(iEvent) {}
0033 
0034       edm::WrapperBase const* getIt(edm::ProductID const& iID) const override { return event_->getByProductID(iID); }
0035 
0036       std::optional<std::tuple<edm::WrapperBase const*, unsigned int>> getThinnedProduct(
0037           edm::ProductID const& pid, unsigned int key) const override {
0038         return event_->getThinnedProduct(pid, key);
0039       }
0040 
0041       void getThinnedProducts(edm::ProductID const& pid,
0042                               std::vector<edm::WrapperBase const*>& foundContainers,
0043                               std::vector<unsigned int>& keys) const override {
0044         event_->getThinnedProducts(pid, foundContainers, keys);
0045       }
0046 
0047       edm::OptionalThinnedKey getThinnedKeyFrom(edm::ProductID const& parent,
0048                                                 unsigned int key,
0049                                                 edm::ProductID const& thinned) const override {
0050         return event_->getThinnedKeyFrom(parent, key, thinned);
0051       }
0052 
0053     private:
0054       unsigned int transitionIndex_() const override { return 0U; }
0055 
0056       MultiChainEvent const* event_;
0057     };
0058   }  // namespace internal
0059 
0060   //
0061   // constants, enums and typedefs
0062   //
0063 
0064   //
0065   // static data member definitions
0066   //
0067 
0068   //
0069   // constructors and destructor
0070   //
0071   MultiChainEvent::MultiChainEvent(std::vector<std::string> const& iFileNames1,
0072                                    std::vector<std::string> const& iFileNames2,
0073                                    bool useSecFileMapSorted) {
0074     event1_ = std::make_shared<ChainEvent>(iFileNames1);
0075     event2_ = std::make_shared<ChainEvent>(iFileNames2);
0076 
0077     getter_ = std::make_shared<internal::MultiProductGetter>(this);
0078 
0079     if (event1_->size() == 0) {
0080       std::cout << "------------------------------------------------------------------------" << std::endl;
0081       std::cout << "WARNING! MultiChainEvent: all primary files have zero events." << std::endl;
0082       std::cout << "Trying to access the events may lead to a crash.  " << std::endl;
0083       std::cout << "------------------------------------------------------------------------" << std::endl;
0084     } else {
0085       event1_->setGetter(getter_);
0086       event2_->setGetter(getter_);
0087     }
0088 
0089     useSecFileMapSorted_ = useSecFileMapSorted;
0090 
0091     if (!useSecFileMapSorted_) {
0092       std::cout << "------------------------------------------------------------------------" << std::endl;
0093       std::cout << "WARNING! What you are about to do may be very slow." << std::endl;
0094       std::cout << "The 2-file solution in FWLite works with very simple assumptions." << std::endl;
0095       std::cout << "It will linearly search through the files in the secondary file list for Products." << std::endl;
0096       std::cout << "There are speed improvements available to make this run faster." << std::endl;
0097       std::cout << "***If your secondary files are sorted with a run-range within a file, (almost always the case) "
0098                 << std::endl;
0099       std::cout << "***please use the option useSecFileMapSorted=true in this constructor. " << std::endl;
0100       std::cout << "    > usage: MultiChainEvent(primaryFiles, secondaryFiles, true);" << std::endl;
0101       std::cout << "------------------------------------------------------------------------" << std::endl;
0102     }
0103 
0104     if (useSecFileMapSorted_) {
0105       std::cout << "------------------------------------------------------------------------" << std::endl;
0106       std::cout << "This MultiChainEvent is now creating a (run_range)_2 ---> file_index_2 map" << std::endl;
0107       std::cout << "for the 2-file solution. " << std::endl;
0108       std::cout
0109           << "This is assuming the files you are giving me are sorted by run,event pairs within each secondary file."
0110           << std::endl;
0111       std::cout << "If this is not true (rarely the case), set this option to false." << std::endl;
0112       std::cout << "    > usage: MultiChainEvent(primaryFiles, secondaryFiles, false);" << std::endl;
0113       std::cout << "------------------------------------------------------------------------" << std::endl;
0114       // speed up secondary file access with a (run,event)_1 ---> index_2 map
0115 
0116       // Loop over events, when a new file is encountered, store the first run number from this file,
0117       // and the last run number from the last file.
0118       TFile* lastFile = nullptr;
0119       std::pair<event_id_range, Long64_t> eventRange;
0120       bool firstFile = true;
0121 
0122       bool foundAny = false;
0123 
0124       for (event2_->toBegin(); !event2_->atEnd(); ++(*event2_)) {
0125         // if we have a new file, cache the "first"
0126         if (lastFile != event2_->getTFile()) {
0127           // if this is not the first file, we have an entry.
0128           // Add it to the list.
0129           if (!firstFile) {
0130             foundAny = true;
0131             event_id_range toAdd = eventRange.first;
0132             secFileMapSorted_[toAdd] = eventRange.second;
0133           }
0134           // always add the "first" event id to the cached event range
0135           eventRange.first.first = event2_->event()->id();
0136           lastFile = event2_->getTFile();
0137         }
0138         // otherwise, cache the "second" event id in the cached event range.
0139         // Upon the discovery of a new file, this will be used as the
0140         // "last" event id in the cached event range.
0141         else {
0142           eventRange.first.second = event2_->event()->id();
0143           eventRange.second = event2_->eventIndex();
0144         }
0145         firstFile = false;
0146       }
0147       // due to the invailability of a "look ahead" operation, we have one additional "put" to make
0148       // after the loop (which puts the "last" event, not "this" event.
0149       if (foundAny) {
0150         event_id_range toAdd = eventRange.first;
0151         secFileMapSorted_[toAdd] = eventRange.second;
0152       }
0153       //     std::cout << "Dumping run range to event id list:" << std::endl;
0154       //     for (sec_file_range_index_map::const_iterator mBegin = secFileMapSorted_.begin(),
0155       //          mEnd = secFileMapSorted_.end(),
0156       //          mit = mBegin;
0157       //        mit != mEnd; ++mit) {
0158       //       char buff[1000];
0159       //       event2_->to(mit->second);
0160       //       sprintf(buff, "[%10d,%10d - %10d,%10d] ---> %10d",
0161       //            mit->first.first.run(),
0162       //            mit->first.first.event(),
0163       //            mit->first.second.run(),
0164       //            mit->first.second.event(),
0165       //            mit->second);
0166       //       std::cout << buff << std::endl;
0167       //     }
0168     }
0169   }
0170 
0171   // MultiChainEvent::MultiChainEvent(const MultiChainEvent& rhs)
0172   // {
0173   //    // do actual copying here;
0174   // }
0175 
0176   MultiChainEvent::~MultiChainEvent() {}
0177 
0178   //
0179   // assignment operators
0180   //
0181   // const MultiChainEvent& MultiChainEvent::operator=(const MultiChainEvent& rhs)
0182   // {
0183   //   //An exception safe implementation is
0184   //   MultiChainEvent temp(rhs);
0185   //   swap(rhs);
0186   //
0187   //   return *this;
0188   // }
0189 
0190   //
0191   // member functions
0192   //
0193 
0194   const MultiChainEvent& MultiChainEvent::operator++() {
0195     event1_->operator++();
0196     return *this;
0197   }
0198 
0199   ///Go to the event at index iIndex
0200   bool MultiChainEvent::to(Long64_t iIndex) { return event1_->to(iIndex); }
0201 
0202   ///Go to event with event id "id"
0203   bool MultiChainEvent::to(edm::EventID id) { return to(id.run(), id.luminosityBlock(), id.event()); }
0204 
0205   ///Go to event with given run , lumi (if non-zero), and event number
0206   bool MultiChainEvent::to(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi, edm::EventNumber_t event) {
0207     return event1_->to(run, lumi, event);
0208   }
0209 
0210   ///Go to event with given run and event number
0211   bool MultiChainEvent::to(edm::RunNumber_t run, edm::EventNumber_t event) { return to(run, 0U, event); }
0212 
0213   ///Go to the event at index iIndex
0214   bool MultiChainEvent::toSec(Long64_t iIndex) { return event2_->to(iIndex); }
0215 
0216   // Go to event with event id "id"
0217   bool MultiChainEvent::toSec(const edm::EventID& id) {
0218     // First try this file.
0219     if (event2_->event_->to(id)) {
0220       // Found it, return.
0221       return true;
0222     }
0223     // Second, assume that the secondary files are each in run/event
0224     // order.  So, let's loop over all files and see if we can figure
0225     // out where the event ought to be.
0226     for (sec_file_range_index_map::const_iterator mBegin = secFileMapSorted_.begin(),
0227                                                   mEnd = secFileMapSorted_.end(),
0228                                                   mit = mBegin;
0229          mit != mEnd;
0230          ++mit) {
0231       if (id < mit->first.first || id > mit->first.second) {
0232         // We don't expect this event to be in this file, so don't
0233         // bother checking it right now.
0234         continue;
0235       }
0236       // If we're here, then we have a reasonable belief that this
0237       // event is in this secondary file.  This part is
0238       // expensive. switchToFile does memory allocations and opens the
0239       // files which becomes very time consuming. This should be done
0240       // as infrequently as possible.
0241       event2_->switchToFile(mit->second);
0242       // Is it here?
0243       if (event2_->to(id)) {
0244         // Yes!
0245         return true;
0246       }
0247       // if we assumed that the secondary files were not each in
0248       // order, but were non-overlapping, we could break here.  But at
0249       // this point, we might as well keep going.
0250     }  // for loop over files
0251 
0252     // if we are still here, then we did not find the id in question,
0253     // do it the old fashioned way.  This will open up each secondary
0254     // file and explicitly check to see if the event is there.
0255     if (event2_->to(id)) {
0256       return true;
0257     }
0258     // if we're still here, then there really is no matching event in
0259     // the secondary files.  Throw.
0260     throw cms::Exception("ProductNotFound")
0261         << "Cannot find id " << id.run() << ", " << id.event() << " in secondary list. Exiting." << std::endl;
0262     // to make the compiler happy
0263     return false;
0264   }
0265 
0266   ///Go to event with given run, lumi, and event number
0267   bool MultiChainEvent::toSec(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi, edm::EventNumber_t event) {
0268     return toSec(edm::EventID(run, lumi, event));
0269   }
0270 
0271   // Go to the very first Event
0272   ///Go to event with given run and event number
0273   bool MultiChainEvent::toSec(edm::RunNumber_t run, edm::EventNumber_t event) {
0274     return toSec(edm::EventID(run, 0U, event));
0275   }
0276 
0277   // Go to the very first Event
0278   const MultiChainEvent& MultiChainEvent::toBegin() {
0279     event1_->toBegin();
0280     return *this;
0281   }
0282 
0283   //
0284   // const member functions
0285   //
0286   std::string const MultiChainEvent::getBranchNameFor(std::type_info const& iType,
0287                                                       char const* iModule,
0288                                                       char const* iInstance,
0289                                                       char const* iProcess) const {
0290     return event1_->getBranchNameFor(iType, iModule, iInstance, iProcess);
0291   }
0292 
0293   std::vector<edm::BranchDescription> const& MultiChainEvent::getBranchDescriptions() const {
0294     return event1_->getBranchDescriptions();
0295   }
0296 
0297   std::vector<std::string> const& MultiChainEvent::getProcessHistory() const { return event1_->getProcessHistory(); }
0298 
0299   edm::ProcessHistory const& MultiChainEvent::processHistory() const { return event1_->processHistory(); }
0300 
0301   edm::EventAuxiliary const& MultiChainEvent::eventAuxiliary() const { return event1_->eventAuxiliary(); }
0302 
0303   bool MultiChainEvent::getByLabel(std::type_info const& iType,
0304                                    char const* iModule,
0305                                    char const* iInstance,
0306                                    char const* iProcess,
0307                                    void* iValue) const {
0308     bool ret1 = event1_->getByLabel(iType, iModule, iInstance, iProcess, iValue);
0309     if (!ret1) {
0310       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0311       bool ret2 = event2_->getByLabel(iType, iModule, iInstance, iProcess, iValue);
0312       if (!ret2)
0313         return false;
0314     }
0315     return true;
0316   }
0317 
0318   bool MultiChainEvent::getByTokenImp(edm::EDGetToken iToken, edm::WrapperBase const*& iValue) const {
0319     bool ret1 = event1_->getByTokenImp(iToken, iValue);
0320     if (!ret1) {
0321       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0322       bool ret2 = event2_->getByTokenImp(iToken, iValue);
0323       if (!ret2)
0324         return false;
0325     }
0326     return true;
0327   }
0328 
0329   edm::WrapperBase const* MultiChainEvent::getByProductID(edm::ProductID const& iID) const {
0330     // First try the first file
0331     edm::WrapperBase const* edp = event1_->getByProductID(iID);
0332     // Did not find the product, try secondary file
0333     if (edp == nullptr) {
0334       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0335       edp = event2_->getByProductID(iID);
0336     }
0337     return edp;
0338   }
0339 
0340   std::optional<std::tuple<edm::WrapperBase const*, unsigned int>> MultiChainEvent::getThinnedProduct(
0341       edm::ProductID const& pid, unsigned int key) const {
0342     // First try the first file
0343     auto edp = event1_->getThinnedProduct(pid, key);
0344     // Did not find the product, try secondary file
0345     if (not edp.has_value()) {
0346       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0347       edp = event2_->getThinnedProduct(pid, key);
0348     }
0349     return edp;
0350   }
0351 
0352   void MultiChainEvent::getThinnedProducts(edm::ProductID const& pid,
0353                                            std::vector<edm::WrapperBase const*>& wrappers,
0354                                            std::vector<unsigned int>& keys) const {
0355     // First try the first file
0356     event1_->getThinnedProducts(pid, wrappers, keys);
0357     // Did not find all the products, try secondary file
0358     if (std::find(wrappers.begin(), wrappers.end(), nullptr) != wrappers.end()) {
0359       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0360       event2_->getThinnedProducts(pid, wrappers, keys);
0361     }
0362   }
0363 
0364   edm::OptionalThinnedKey MultiChainEvent::getThinnedKeyFrom(edm::ProductID const& parent,
0365                                                              unsigned int key,
0366                                                              edm::ProductID const& thinned) const {
0367     // First try the first file
0368     auto edp = event1_->getThinnedKeyFrom(parent, key, thinned);
0369     // Did not find the product, try secondary file
0370     if (std::holds_alternative<std::monostate>(edp)) {
0371       (const_cast<MultiChainEvent*>(this))->toSec(event1_->id());
0372       edp = event2_->getThinnedKeyFrom(parent, key, thinned);
0373     }
0374     return edp;
0375   }
0376 
0377   bool MultiChainEvent::isValid() const { return event1_->isValid(); }
0378   MultiChainEvent::operator bool() const { return *event1_; }
0379 
0380   bool MultiChainEvent::atEnd() const { return event1_->atEnd(); }
0381 
0382   Long64_t MultiChainEvent::size() const { return event1_->size(); }
0383 
0384   edm::TriggerNames const& MultiChainEvent::triggerNames(edm::TriggerResults const& triggerResults) const {
0385     edm::TriggerNames const* names = triggerNames_(triggerResults);
0386     if (names != nullptr)
0387       return *names;
0388 
0389     event1_->fillParameterSetRegistry();
0390     names = triggerNames_(triggerResults);
0391     if (names != nullptr)
0392       return *names;
0393 
0394     // If we cannot find it in the primary file, this probably will
0395     // not help but try anyway
0396     event2_->to(event1_->id());
0397     event2_->fillParameterSetRegistry();
0398     names = triggerNames_(triggerResults);
0399     if (names != nullptr)
0400       return *names;
0401 
0402     throw cms::Exception("TriggerNamesNotFound") << "TriggerNames not found in ParameterSet registry";
0403     return *names;
0404   }
0405 
0406   edm::TriggerResultsByName MultiChainEvent::triggerResultsByName(edm::TriggerResults const& triggerResults) const {
0407     edm::TriggerNames const* names = triggerNames_(triggerResults);
0408 
0409     if (names == nullptr) {
0410       event1_->fillParameterSetRegistry();
0411       names = triggerNames_(triggerResults);
0412     }
0413 
0414     if (names == nullptr) {
0415       event2_->to(event1_->id());
0416       event2_->fillParameterSetRegistry();
0417       names = triggerNames_(triggerResults);
0418     }
0419 
0420     return edm::TriggerResultsByName(&triggerResults, names);
0421   }
0422 
0423   edm::ParameterSet const* MultiChainEvent::parameterSet(edm::ParameterSetID const& psID) const {
0424     auto pset = event1_->parameterSet(psID);
0425     if (nullptr == pset) {
0426       pset = event2_->parameterSet(psID);
0427     }
0428     return pset;
0429   }
0430   //
0431   // static member functions
0432   //
0433   void MultiChainEvent::throwProductNotFoundException(std::type_info const& iType,
0434                                                       char const* iModule,
0435                                                       char const* iInstance,
0436                                                       char const* iProcess) {
0437     ChainEvent::throwProductNotFoundException(iType, iModule, iInstance, iProcess);
0438   }
0439 }  // namespace fwlite