CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2/src/IOPool/Input/src/RootFile.cc

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------
00002 ----------------------------------------------------------------------*/
00003 
00004 #include "RootFile.h"
00005 #include "DuplicateChecker.h"
00006 #include "InputFile.h"
00007 #include "ProvenanceAdaptor.h"
00008 
00009 #include "DataFormats/Common/interface/WrapperOwningHolder.h"
00010 #include "DataFormats/Common/interface/RefCoreStreamer.h"
00011 #include "DataFormats/Provenance/interface/BranchDescription.h"
00012 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
00013 #include "DataFormats/Provenance/interface/BranchType.h"
00014 #include "DataFormats/Provenance/interface/EventEntryInfo.h"
00015 #include "DataFormats/Provenance/interface/FullHistoryToReducedHistoryMap.h"
00016 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
00017 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
00018 #include "DataFormats/Provenance/interface/ProcessConfigurationRegistry.h"
00019 #include "DataFormats/Provenance/interface/ProcessHistoryID.h"
00020 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
00021 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00022 #include "DataFormats/Provenance/interface/StoredProductProvenance.h"
00023 #include "DataFormats/Provenance/interface/RunID.h"
00024 #include "FWCore/Framework/interface/FileBlock.h"
00025 #include "FWCore/Framework/interface/EventPrincipal.h"
00026 #include "FWCore/Framework/interface/GroupSelector.h"
00027 #include "FWCore/Framework/interface/LuminosityBlockPrincipal.h"
00028 #include "FWCore/Framework/interface/RunPrincipal.h"
00029 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00030 #include "FWCore/ParameterSet/interface/FillProductRegistryTransients.h"
00031 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00032 #include "FWCore/ParameterSet/interface/Registry.h"
00033 #include "FWCore/Sources/interface/EventSkipperByID.h"
00034 #include "FWCore/Sources/interface/DaqProvenanceHelper.h"
00035 #include "FWCore/Utilities/interface/Algorithms.h"
00036 #include "FWCore/Utilities/interface/do_nothing_deleter.h"
00037 #include "FWCore/Utilities/interface/EDMException.h"
00038 #include "FWCore/Utilities/interface/FriendlyName.h"
00039 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
00040 #include "FWCore/Utilities/interface/ReleaseVersion.h"
00041 #include "FWCore/Version/interface/GetReleaseVersion.h"
00042 
00043 //used for backward compatibility
00044 #include "DataFormats/Provenance/interface/EntryDescriptionRegistry.h"
00045 #include "DataFormats/Provenance/interface/EventAux.h"
00046 #include "DataFormats/Provenance/interface/LuminosityBlockAux.h"
00047 #include "DataFormats/Provenance/interface/RunAux.h"
00048 #include "DataFormats/Provenance/interface/RunLumiEntryInfo.h"
00049 #include "FWCore/ParameterSet/interface/ParameterSetConverter.h"
00050 
00051 #include "TROOT.h"
00052 #include "Rtypes.h"
00053 #include "TClass.h"
00054 #include "TString.h"
00055 #include "TTree.h"
00056 #include "TTreeCache.h"
00057 
00058 #include <algorithm>
00059 #include <list>
00060 
00061 namespace edm {
00062 
00063   // Algorithm classes for making ProvenanceReader:
00064   class MakeDummyProvenanceReader : public MakeProvenanceReader {
00065   public:
00066     virtual std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree, DaqProvenanceHelper const* daqProvenanceHelper) const;
00067   };
00068   class MakeOldProvenanceReader : public MakeProvenanceReader {
00069   public:
00070     virtual std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree, DaqProvenanceHelper const* daqProvenanceHelper) const;
00071   };
00072   class MakeFullProvenanceReader : public MakeProvenanceReader {
00073   public:
00074     virtual std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree, DaqProvenanceHelper const* daqProvenanceHelper) const;
00075   };
00076   class MakeReducedProvenanceReader : public MakeProvenanceReader {
00077   public:
00078     MakeReducedProvenanceReader(std::vector<ParentageID> const& parentageIDLookup) : parentageIDLookup_(parentageIDLookup) {}
00079     virtual std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree, DaqProvenanceHelper const* daqProvenanceHelper) const;
00080   private:
00081     std::vector<ParentageID> const& parentageIDLookup_;
00082   };
00083 
00084   namespace {
00085     int
00086     forcedRunOffset(RunNumber_t const& forcedRunNumber, IndexIntoFile::IndexIntoFileItr inxBegin, IndexIntoFile::IndexIntoFileItr inxEnd) {
00087       if(inxBegin == inxEnd) return 0;
00088       int defaultOffset = (inxBegin.run() != 0 ? 0 : 1);
00089       int offset = (forcedRunNumber != 0U ? forcedRunNumber - inxBegin.run() : defaultOffset);
00090       if(offset < 0) {
00091         throw Exception(errors::Configuration)
00092           << "The value of the 'setRunNumber' parameter must not be\n"
00093           << "less than the first run number in the first input file.\n"
00094           << "'setRunNumber' was " << forcedRunNumber <<", while the first run was "
00095           << forcedRunNumber - offset << ".\n";
00096       }
00097       return offset;
00098     }
00099   }
00100 
00101   // This is a helper class for IndexIntoFile.
00102   class RootFileEventFinder : public IndexIntoFile::EventFinder {
00103   public:
00104     explicit RootFileEventFinder(RootTree& eventTree) : eventTree_(eventTree) {}
00105     virtual ~RootFileEventFinder() {}
00106     virtual
00107     EventNumber_t getEventNumberOfEntry(roottree::EntryNumber entry) const {
00108       roottree::EntryNumber saveEntry = eventTree_.entryNumber();
00109       eventTree_.setEntryNumber(entry);
00110       EventAuxiliary eventAux;
00111       EventAuxiliary *pEvAux = &eventAux;
00112       eventTree_.fillAux<EventAuxiliary>(pEvAux);
00113       eventTree_.setEntryNumber(saveEntry);
00114       return eventAux.event();
00115     }
00116 
00117   private:
00118      RootTree& eventTree_;
00119   };
00120 
00121 //---------------------------------------------------------------------
00122   RootFile::RootFile(std::string const& fileName,
00123                      ProcessConfiguration const& processConfiguration,
00124                      std::string const& logicalFileName,
00125                      boost::shared_ptr<InputFile> filePtr,
00126                      boost::shared_ptr<EventSkipperByID> eventSkipperByID,
00127                      bool skipAnyEvents,
00128                      int remainingEvents,
00129                      int remainingLumis,
00130                      unsigned int treeCacheSize,
00131                      int treeMaxVirtualSize,
00132                      InputSource::ProcessingMode processingMode,
00133                      RunNumber_t const& forcedRunNumber,
00134                      bool noEventSort,
00135                      GroupSelectorRules const& groupSelectorRules,
00136                      InputType::InputType inputType,
00137                      boost::shared_ptr<BranchIDListHelper> branchIDListHelper,
00138                      boost::shared_ptr<DuplicateChecker> duplicateChecker,
00139                      bool dropDescendants,
00140                      std::vector<boost::shared_ptr<IndexIntoFile> > const& indexesIntoFiles,
00141                      std::vector<boost::shared_ptr<IndexIntoFile> >::size_type currentIndexIntoFile,
00142                      std::vector<ProcessHistoryID>& orderedProcessHistoryIDs,
00143                      bool labelRawDataLikeMC,
00144                      bool usingGoToEvent,
00145                      bool enablePrefetching) :
00146       file_(fileName),
00147       logicalFile_(logicalFileName),
00148       processConfiguration_(processConfiguration),
00149       processConfigurations_(),
00150       filePtr_(filePtr),
00151       eventSkipperByID_(eventSkipperByID),
00152       fileFormatVersion_(),
00153       fid_(),
00154       indexIntoFileSharedPtr_(new IndexIntoFile),
00155       indexIntoFile_(*indexIntoFileSharedPtr_),
00156       orderedProcessHistoryIDs_(orderedProcessHistoryIDs),
00157       indexIntoFileBegin_(indexIntoFile_.begin(noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder)),
00158       indexIntoFileEnd_(indexIntoFileBegin_),
00159       indexIntoFileIter_(indexIntoFileBegin_),
00160       eventProcessHistoryIDs_(),
00161       eventProcessHistoryIter_(eventProcessHistoryIDs_.begin()),
00162       savedRunAuxiliary_(),
00163       skipAnyEvents_(skipAnyEvents),
00164       noEventSort_(noEventSort),
00165       whyNotFastClonable_(0),
00166       hasNewlyDroppedBranch_(),
00167       branchListIndexesUnchanged_(false),
00168       eventAux_(),
00169       eventTree_(filePtr_, InEvent, treeMaxVirtualSize, treeCacheSize, roottree::defaultLearningEntries, enablePrefetching),
00170       lumiTree_(filePtr_, InLumi, treeMaxVirtualSize, roottree::defaultNonEventCacheSize, roottree::defaultNonEventLearningEntries, enablePrefetching),
00171       runTree_(filePtr_, InRun, treeMaxVirtualSize, roottree::defaultNonEventCacheSize, roottree::defaultNonEventLearningEntries, enablePrefetching),
00172       treePointers_(),
00173       lastEventEntryNumberRead_(-1LL),
00174       productRegistry_(),
00175       branchIDLists_(),
00176       branchIDListHelper_(branchIDListHelper),
00177       processingMode_(processingMode),
00178       forcedRunOffset_(0),
00179       newBranchToOldBranch_(),
00180       eventHistoryTree_(0),
00181       eventSelectionIDs_(new EventSelectionIDVector),
00182       branchListIndexes_(new BranchListIndexes),
00183       history_(),
00184       branchChildren_(new BranchChildren),
00185       duplicateChecker_(duplicateChecker),
00186       provenanceAdaptor_(),
00187       provenanceReaderMaker_(),
00188       secondaryEventPrincipal_(),
00189       eventBranchMapper_(),
00190       parentageIDLookup_(),
00191       daqProvenanceHelper_() {
00192 
00193     hasNewlyDroppedBranch_.fill(false);
00194 
00195     treePointers_[InEvent] = &eventTree_;
00196     treePointers_[InLumi]  = &lumiTree_;
00197     treePointers_[InRun]   = &runTree_;
00198 
00199     // Read the metadata tree.
00200     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
00201     std::unique_ptr<TTree> metaDataTree(dynamic_cast<TTree *>(filePtr_->Get(poolNames::metaDataTreeName().c_str())));
00202     if(0 == metaDataTree.get()) {
00203       throw Exception(errors::FileReadError) << "Could not find tree " << poolNames::metaDataTreeName()
00204                                              << " in the input file.\n";
00205     }
00206 
00207     // To keep things simple, we just read in every possible branch that exists.
00208     // We don't pay attention to which branches exist in which file format versions
00209 
00210     FileFormatVersion *fftPtr = &fileFormatVersion_;
00211     if(metaDataTree->FindBranch(poolNames::fileFormatVersionBranchName().c_str()) != 0) {
00212       TBranch *fft = metaDataTree->GetBranch(poolNames::fileFormatVersionBranchName().c_str());
00213       fft->SetAddress(&fftPtr);
00214       roottree::getEntry(fft, 0);
00215       metaDataTree->SetBranchAddress(poolNames::fileFormatVersionBranchName().c_str(), &fftPtr);
00216     }
00217 
00218     FileID *fidPtr = &fid_;
00219     if(metaDataTree->FindBranch(poolNames::fileIdentifierBranchName().c_str()) != 0) {
00220       metaDataTree->SetBranchAddress(poolNames::fileIdentifierBranchName().c_str(), &fidPtr);
00221     }
00222 
00223     IndexIntoFile *iifPtr = &indexIntoFile_;
00224     if(metaDataTree->FindBranch(poolNames::indexIntoFileBranchName().c_str()) != 0) {
00225       metaDataTree->SetBranchAddress(poolNames::indexIntoFileBranchName().c_str(), &iifPtr);
00226     }
00227 
00228     // Need to read to a temporary registry so we can do a translation of the BranchKeys.
00229     // This preserves backward compatibility against friendly class name algorithm changes.
00230     ProductRegistry inputProdDescReg;
00231     ProductRegistry *ppReg = &inputProdDescReg;
00232     metaDataTree->SetBranchAddress(poolNames::productDescriptionBranchName().c_str(), (&ppReg));
00233 
00234     typedef std::map<ParameterSetID, ParameterSetBlob> PsetMap;
00235     PsetMap psetMap;
00236     PsetMap *psetMapPtr = &psetMap;
00237     if(metaDataTree->FindBranch(poolNames::parameterSetMapBranchName().c_str()) != 0) {
00238       //backward compatibility
00239       assert(!fileFormatVersion().parameterSetsTree());
00240       metaDataTree->SetBranchAddress(poolNames::parameterSetMapBranchName().c_str(), &psetMapPtr);
00241     } else {
00242       assert(fileFormatVersion().parameterSetsTree());
00243       // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
00244       std::unique_ptr<TTree> psetTree(dynamic_cast<TTree *>(filePtr_->Get(poolNames::parameterSetsTreeName().c_str())));
00245       if(0 == psetTree.get()) {
00246         throw Exception(errors::FileReadError) << "Could not find tree " << poolNames::parameterSetsTreeName()
00247         << " in the input file.\n";
00248       }
00249 
00250       typedef std::pair<ParameterSetID, ParameterSetBlob> IdToBlobs;
00251       IdToBlobs idToBlob;
00252       IdToBlobs* pIdToBlob = &idToBlob;
00253       psetTree->SetBranchAddress(poolNames::idToParameterSetBlobsBranchName().c_str(), &pIdToBlob);
00254 
00255       std::unique_ptr<TTreeCache> psetTreeCache = roottree::trainCache(psetTree.get(), *filePtr_, roottree::defaultNonEventCacheSize, "*");
00256       psetTreeCache->SetEnablePrefetching(false);
00257       filePtr_->SetCacheRead(psetTreeCache.get());
00258       for(Long64_t i = 0; i != psetTree->GetEntries(); ++i) {
00259         psetTree->GetEntry(i);
00260         psetMap.insert(idToBlob);
00261       }
00262       filePtr_->SetCacheRead(0);
00263     }
00264 
00265     // backward compatibility
00266     ProcessHistoryRegistry::collection_type pHistMap;
00267     ProcessHistoryRegistry::collection_type *pHistMapPtr = &pHistMap;
00268     if(metaDataTree->FindBranch(poolNames::processHistoryMapBranchName().c_str()) != 0) {
00269       metaDataTree->SetBranchAddress(poolNames::processHistoryMapBranchName().c_str(), &pHistMapPtr);
00270     }
00271 
00272     ProcessHistoryRegistry::vector_type pHistVector;
00273     ProcessHistoryRegistry::vector_type *pHistVectorPtr = &pHistVector;
00274     if(metaDataTree->FindBranch(poolNames::processHistoryBranchName().c_str()) != 0) {
00275       metaDataTree->SetBranchAddress(poolNames::processHistoryBranchName().c_str(), &pHistVectorPtr);
00276     }
00277 
00278     ProcessConfigurationVector* procConfigVectorPtr = &processConfigurations_;
00279     if(metaDataTree->FindBranch(poolNames::processConfigurationBranchName().c_str()) != 0) {
00280       metaDataTree->SetBranchAddress(poolNames::processConfigurationBranchName().c_str(), &procConfigVectorPtr);
00281     }
00282 
00283     std::unique_ptr<BranchIDLists> branchIDListsAPtr(new BranchIDLists);
00284     BranchIDLists* branchIDListsPtr = branchIDListsAPtr.get();
00285     if(metaDataTree->FindBranch(poolNames::branchIDListBranchName().c_str()) != 0) {
00286       metaDataTree->SetBranchAddress(poolNames::branchIDListBranchName().c_str(), &branchIDListsPtr);
00287     }
00288 
00289     BranchChildren* branchChildrenBuffer = branchChildren_.get();
00290     if(metaDataTree->FindBranch(poolNames::productDependenciesBranchName().c_str()) != 0) {
00291       metaDataTree->SetBranchAddress(poolNames::productDependenciesBranchName().c_str(), &branchChildrenBuffer);
00292     }
00293 
00294     // backward compatibility
00295     std::vector<EventProcessHistoryID> *eventHistoryIDsPtr = &eventProcessHistoryIDs_;
00296     if(metaDataTree->FindBranch(poolNames::eventHistoryBranchName().c_str()) != 0) {
00297       metaDataTree->SetBranchAddress(poolNames::eventHistoryBranchName().c_str(), &eventHistoryIDsPtr);
00298     }
00299 
00300     if(metaDataTree->FindBranch(poolNames::moduleDescriptionMapBranchName().c_str()) != 0) {
00301       if(metaDataTree->GetBranch(poolNames::moduleDescriptionMapBranchName().c_str())->GetSplitLevel() != 0) {
00302         metaDataTree->SetBranchStatus((poolNames::moduleDescriptionMapBranchName() + ".*").c_str(), 0);
00303       } else {
00304         metaDataTree->SetBranchStatus(poolNames::moduleDescriptionMapBranchName().c_str(), 0);
00305       }
00306     }
00307 
00308     // Here we read the metadata tree
00309     roottree::getEntry(metaDataTree.get(), 0);
00310 
00311     checkReleaseVersion();
00312 
00313     eventProcessHistoryIter_ = eventProcessHistoryIDs_.begin();
00314 
00315     // Here we read the event history tree, if we have one.
00316     readEventHistoryTree();
00317 
00318     ParameterSetConverter::ParameterSetIdConverter psetIdConverter;
00319     if(!fileFormatVersion().triggerPathsTracked()) {
00320       ParameterSetConverter converter(psetMap, psetIdConverter, fileFormatVersion().parameterSetsByReference());
00321     } else {
00322       // Merge into the parameter set registry.
00323       pset::Registry& psetRegistry = *pset::Registry::instance();
00324       for(PsetMap::const_iterator i = psetMap.begin(), iEnd = psetMap.end(); i != iEnd; ++i) {
00325         ParameterSet pset(i->second.pset());
00326         pset.setID(i->first);
00327         psetRegistry.insertMapped(pset);
00328       }
00329     }
00330     if(!fileFormatVersion().splitProductIDs()) {
00331       // Old provenance format input file.  Create a provenance adaptor.
00332       provenanceAdaptor_.reset(new ProvenanceAdaptor(
00333             inputProdDescReg, pHistMap, pHistVector, processConfigurations_, psetIdConverter, true));
00334       // Fill in the branchIDLists branch from the provenance adaptor
00335       branchIDLists_ = provenanceAdaptor_->branchIDLists();
00336     } else {
00337       if(!fileFormatVersion().triggerPathsTracked()) {
00338         // New provenance format, but change in ParameterSet Format. Create a provenance adaptor.
00339         provenanceAdaptor_.reset(new ProvenanceAdaptor(
00340             inputProdDescReg, pHistMap, pHistVector, processConfigurations_, psetIdConverter, false));
00341       }
00342       // New provenance format input file. The branchIDLists branch was read directly from the input file.
00343       if(metaDataTree->FindBranch(poolNames::branchIDListBranchName().c_str()) == 0) {
00344         throw Exception(errors::EventCorruption)
00345           << "Failed to find branchIDLists branch in metaData tree.\n";
00346       }
00347       branchIDLists_.reset(branchIDListsAPtr.release());
00348     }
00349 
00350     if(labelRawDataLikeMC) {
00351       std::string const rawData("FEDRawDataCollection");
00352       std::string const source("source");
00353       ProductRegistry::ProductList& pList = inputProdDescReg.productListUpdator();
00354       BranchKey finder(rawData, source, "", "");
00355       ProductRegistry::ProductList::iterator it = pList.lower_bound(finder);
00356       if(it != pList.end() && it->first.friendlyClassName_ == rawData && it->first.moduleLabel_ == source) {
00357         // We found raw data with a module label of source.
00358         // We need to change the module label and process name.
00359         // Create helper.
00360         it->second.init();
00361         daqProvenanceHelper_.reset(new DaqProvenanceHelper(it->second.unwrappedTypeID()));
00362         // Create the new branch description
00363         BranchDescription const& newBD = daqProvenanceHelper_->constBranchDescription_.me();
00364         // Save info from the old and new branch descriptions
00365         daqProvenanceHelper_->saveInfo(it->second, newBD);
00366         // Map the new branch name to the old branch name.
00367         it->second.init();
00368         newBranchToOldBranch_.insert(std::make_pair(newBD.branchName(), it->second.branchName()));
00369         // Remove the old branch description from the product Registry.
00370         pList.erase(it);
00371         // Check that there was only one.
00372         it = pList.lower_bound(finder);
00373         assert(!(it != pList.end() && it->first.friendlyClassName_ == rawData && it->first.moduleLabel_ == source));
00374         // Insert the new branch description into the product registry.
00375         inputProdDescReg.copyProduct(newBD);
00376         // Fix up other per file metadata.
00377         daqProvenanceHelper_->fixMetaData(processConfigurations_);
00378         daqProvenanceHelper_->fixMetaData(pHistVector);
00379         daqProvenanceHelper_->fixMetaData(*branchIDLists_);
00380         daqProvenanceHelper_->fixMetaData(*branchChildren_);
00381       }
00382     }
00383 
00384     ProcessHistoryRegistry::instance()->insertCollection(pHistVector);
00385     ProcessConfigurationRegistry::instance()->insertCollection(processConfigurations_);
00386 
00387     eventTree_.trainCache(BranchTypeToAuxiliaryBranchName(InEvent).c_str());
00388 
00389     validateFile(inputType, usingGoToEvent);
00390 
00391     // Read the parentage tree.  Old format files are handled internally in readParentageTree().
00392     readParentageTree();
00393 
00394     // Merge into the hashed registries.
00395     if(eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
00396       whyNotFastClonable_ += FileBlock::EventsOrLumisSelectedByID;
00397     }
00398 
00399     initializeDuplicateChecker(indexesIntoFiles, currentIndexIntoFile);
00400     indexIntoFileIter_ = indexIntoFileBegin_ = indexIntoFile_.begin(noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder);
00401     indexIntoFileEnd_ = indexIntoFile_.end(noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder);
00402     forcedRunOffset_ = forcedRunOffset(forcedRunNumber, indexIntoFileBegin_, indexIntoFileEnd_);
00403     eventProcessHistoryIter_ = eventProcessHistoryIDs_.begin();
00404 
00405     // Set product presence information in the product registry.
00406     ProductRegistry::ProductList const& pList = inputProdDescReg.productList();
00407     for(ProductRegistry::ProductList::const_iterator it = pList.begin(), itEnd = pList.end();
00408         it != itEnd; ++it) {
00409       BranchDescription const& prod = it->second;
00410       prod.init();
00411       treePointers_[prod.branchType()]->setPresence(prod, newBranchToOldBranch(prod.branchName()));
00412     }
00413 
00414     fillProductRegistryTransients(processConfigurations_, inputProdDescReg);
00415 
00416     std::unique_ptr<ProductRegistry> newReg(new ProductRegistry);
00417 
00418     // Do the translation from the old registry to the new one
00419     {
00420       ProductRegistry::ProductList const& prodList = inputProdDescReg.productList();
00421       for(ProductRegistry::ProductList::const_iterator it = prodList.begin(), itEnd = prodList.end();
00422            it != itEnd; ++it) {
00423         BranchDescription const& prod = it->second;
00424         std::string newFriendlyName = friendlyname::friendlyName(prod.className());
00425         if(newFriendlyName == prod.friendlyClassName()) {
00426           newReg->copyProduct(prod);
00427         } else {
00428           if(fileFormatVersion().splitProductIDs()) {
00429             throw Exception(errors::UnimplementedFeature)
00430               << "Cannot change friendly class name algorithm without more development work\n"
00431               << "to update BranchIDLists.  Contact the framework group.\n";
00432           }
00433           BranchDescription newBD(prod);
00434           newBD.updateFriendlyClassName();
00435           newReg->copyProduct(newBD);
00436           newBranchToOldBranch_.insert(std::make_pair(newBD.branchName(), prod.branchName()));
00437         }
00438       }
00439       dropOnInput(*newReg, groupSelectorRules, dropDescendants, inputType);
00440       // freeze the product registry
00441       newReg->setFrozen(inputType != InputType::Primary);
00442       productRegistry_.reset(newReg.release());
00443     }
00444 
00445     // Here, we make the class that will make the ProvenanceReader
00446     provenanceReaderMaker_.reset(makeProvenanceReaderMaker().release());
00447 
00448     // Set up information from the product registry.
00449     ProductRegistry::ProductList const& prodList = productRegistry()->productList();
00450     for(ProductRegistry::ProductList::const_iterator it = prodList.begin(), itEnd = prodList.end();
00451         it != itEnd; ++it) {
00452       BranchDescription const& prod = it->second;
00453       treePointers_[prod.branchType()]->addBranch(it->first, prod,
00454                                                   newBranchToOldBranch(prod.branchName()));
00455     }
00456 
00457     // Event Principal cache for secondary input source
00458     if(inputType == InputType::SecondarySource) {
00459       secondaryEventPrincipal_.reset(new EventPrincipal(productRegistry(), branchIDListHelper_, processConfiguration));
00460     }
00461 
00462     // Determine if this file is fast clonable.
00463     setIfFastClonable(remainingEvents, remainingLumis);
00464 
00465     // Update the branch id info.
00466     if(inputType == InputType::Primary) {
00467       branchListIndexesUnchanged_ = branchIDListHelper_->updateFromInput(*branchIDLists_);
00468     }
00469 
00470     setRefCoreStreamer(true);  // backward compatibility
00471 
00472     // We are done with our initial reading of EventAuxiliary.
00473     indexIntoFile_.doneFileInitialization();
00474 
00475     // Tell the event tree to begin training at the next read.
00476     eventTree_.resetTraining();
00477 
00478     // Train the run and lumi trees.
00479     runTree_.trainCache("*");
00480     lumiTree_.trainCache("*");
00481   }
00482 
00483   RootFile::~RootFile() {
00484   }
00485 
00486   void
00487   RootFile::readEntryDescriptionTree() {
00488     // Called only for old format files.
00489     if(!fileFormatVersion().perEventProductIDs()) return;
00490     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
00491     std::unique_ptr<TTree> entryDescriptionTree(dynamic_cast<TTree*>(filePtr_->Get(poolNames::entryDescriptionTreeName().c_str())));
00492     if(0 == entryDescriptionTree.get()) {
00493       throw Exception(errors::FileReadError) << "Could not find tree " << poolNames::entryDescriptionTreeName()
00494                                              << " in the input file.\n";
00495     }
00496 
00497     EntryDescriptionID idBuffer;
00498     EntryDescriptionID* pidBuffer = &idBuffer;
00499     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionIDBranchName().c_str(), &pidBuffer);
00500 
00501     EntryDescriptionRegistry& oldregistry = *EntryDescriptionRegistry::instance();
00502 
00503     EventEntryDescription entryDescriptionBuffer;
00504     EventEntryDescription *pEntryDescriptionBuffer = &entryDescriptionBuffer;
00505     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionBranchName().c_str(), &pEntryDescriptionBuffer);
00506 
00507     // Fill in the parentage registry.
00508     ParentageRegistry& registry = *ParentageRegistry::instance();
00509 
00510     for(Long64_t i = 0, numEntries = entryDescriptionTree->GetEntries(); i < numEntries; ++i) {
00511       roottree::getEntry(entryDescriptionTree.get(), i);
00512       if(idBuffer != entryDescriptionBuffer.id()) {
00513         throw Exception(errors::EventCorruption) << "Corruption of EntryDescription tree detected.\n";
00514       }
00515       oldregistry.insertMapped(entryDescriptionBuffer);
00516       Parentage parents;
00517       parents.parents() = entryDescriptionBuffer.parents();
00518       if(daqProvenanceHelper_) {
00519         ParentageID const oldID = parents.id();
00520         daqProvenanceHelper_->fixMetaData(parents.parents());
00521         ParentageID newID = parents.id();
00522         if(newID != oldID) {
00523           daqProvenanceHelper_->parentageIDMap_.insert(std::make_pair(oldID, newID));
00524         }
00525       }
00526       registry.insertMapped(parents);
00527     }
00528     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionIDBranchName().c_str(), 0);
00529     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionBranchName().c_str(), 0);
00530   }
00531 
00532   void
00533   RootFile::readParentageTree() {
00534     if(!fileFormatVersion().splitProductIDs()) {
00535       // Old format file.
00536       readEntryDescriptionTree();
00537       return;
00538     }
00539     // New format file
00540     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
00541     std::unique_ptr<TTree> parentageTree(dynamic_cast<TTree*>(filePtr_->Get(poolNames::parentageTreeName().c_str())));
00542     if(0 == parentageTree.get()) {
00543       throw Exception(errors::FileReadError) << "Could not find tree " << poolNames::parentageTreeName()
00544                                              << " in the input file.\n";
00545     }
00546 
00547     Parentage parents;
00548     Parentage *pParentageBuffer = &parents;
00549     parentageTree->SetBranchAddress(poolNames::parentageBranchName().c_str(), &pParentageBuffer);
00550 
00551     ParentageRegistry& registry = *ParentageRegistry::instance();
00552 
00553     parentageIDLookup_.reserve(parentageTree->GetEntries());
00554     for(Long64_t i = 0, numEntries = parentageTree->GetEntries(); i < numEntries; ++i) {
00555       roottree::getEntry(parentageTree.get(), i);
00556       if(daqProvenanceHelper_) {
00557         ParentageID const oldID = parents.id();
00558         daqProvenanceHelper_->fixMetaData(parents.parents());
00559         ParentageID newID = parents.id();
00560         if(newID != oldID) {
00561           daqProvenanceHelper_->parentageIDMap_.insert(std::make_pair(oldID, newID));
00562         }
00563       }
00564       registry.insertMapped(parents);
00565       parentageIDLookup_.push_back(parents.id());
00566     }
00567     parentageTree->SetBranchAddress(poolNames::parentageBranchName().c_str(), 0);
00568   }
00569 
00570   void
00571   RootFile::setIfFastClonable(int remainingEvents, int remainingLumis) {
00572     if(fileFormatVersion().noMetaDataTrees() and !fileFormatVersion().storedProductProvenanceUsed()) {
00573       //we must avoid copying the old branch which stored the per product per event provenance
00574       whyNotFastClonable_ += FileBlock::FileTooOld;
00575       return;
00576     }
00577     if(!fileFormatVersion().splitProductIDs()) {
00578       whyNotFastClonable_ += FileBlock::FileTooOld;
00579       return;
00580     }
00581     if(processingMode_ != InputSource::RunsLumisAndEvents) {
00582       whyNotFastClonable_ += FileBlock::NotProcessingEvents;
00583       return;
00584     }
00585     // Find entry for first event in file
00586     IndexIntoFile::IndexIntoFileItr it = indexIntoFileBegin_;
00587     while(it != indexIntoFileEnd_ && it.getEntryType() != IndexIntoFile::kEvent) {
00588       ++it;
00589     }
00590     if(it == indexIntoFileEnd_) {
00591       whyNotFastClonable_ += FileBlock::NoEventsInFile;
00592       return;
00593     }
00594 
00595     // From here on, record all reasons we can't fast clone.
00596     IndexIntoFile::SortOrder sortOrder = (noEventSort_ ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder);
00597     if(!indexIntoFile_.iterationWillBeInEntryOrder(sortOrder)) {
00598       whyNotFastClonable_ += (noEventSort_ ? FileBlock::RunOrLumiNotContiguous : FileBlock::EventsToBeSorted);
00599     }
00600     if(skipAnyEvents_) {
00601       whyNotFastClonable_ += FileBlock::InitialEventsSkipped;
00602     }
00603     if(remainingEvents >= 0 && eventTree_.entries() > remainingEvents) {
00604       whyNotFastClonable_ += FileBlock::MaxEventsTooSmall;
00605     }
00606     if(remainingLumis >= 0 && lumiTree_.entries() > remainingLumis) {
00607       whyNotFastClonable_ += FileBlock::MaxLumisTooSmall;
00608     }
00609     // We no longer fast copy the EventAuxiliary branch, so there
00610     // is no longer any need to disable fast copying because the run
00611     // number is being modified.   Also, this check did not work anyway
00612     // because this function is called before forcedRunOffset_ is set.
00613 
00614     // if(forcedRunOffset_ != 0) {
00615     //   whyNotFastClonable_ += FileBlock::RunNumberModified;
00616     // }
00617     if(duplicateChecker_ &&
00618       !duplicateChecker_->checkDisabled() &&
00619       !duplicateChecker_->noDuplicatesInFile()) {
00620       whyNotFastClonable_ += FileBlock::DuplicateEventsRemoved;
00621     }
00622   }
00623 
00624   boost::shared_ptr<FileBlock>
00625   RootFile::createFileBlock() const {
00626     return boost::shared_ptr<FileBlock>(new FileBlock(fileFormatVersion(),
00627                                                      eventTree_.tree(),
00628                                                      eventTree_.metaTree(),
00629                                                      lumiTree_.tree(),
00630                                                      lumiTree_.metaTree(),
00631                                                      runTree_.tree(),
00632                                                      runTree_.metaTree(),
00633                                                      whyNotFastClonable(),
00634                                                      hasNewlyDroppedBranch(),
00635                                                      file_,
00636                                                      branchListIndexesUnchanged(),
00637                                                      modifiedIDs(),
00638                                                      branchChildren_,
00639                                                      branchIDLists_));
00640   }
00641 
00642   std::string const&
00643   RootFile::newBranchToOldBranch(std::string const& newBranch) const {
00644     std::map<std::string, std::string>::const_iterator it = newBranchToOldBranch_.find(newBranch);
00645     if(it != newBranchToOldBranch_.end()) {
00646       return it->second;
00647     }
00648     return newBranch;
00649   }
00650 
00651   IndexIntoFile::IndexIntoFileItr
00652   RootFile::indexIntoFileIter() const {
00653     return indexIntoFileIter_;
00654   }
00655 
00656   void
00657   RootFile::setPosition(IndexIntoFile::IndexIntoFileItr const& position) {
00658     indexIntoFileIter_.copyPosition(position);
00659   }
00660 
00661   bool
00662   RootFile::skipThisEntry() {
00663     if(indexIntoFileIter_ == indexIntoFileEnd_) {
00664         return false;
00665     }
00666     if(eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
00667 
00668       // See first if the entire lumi or run is skipped, so we won't have to read the event Auxiliary in that case.
00669       if(eventSkipperByID_->skipIt(indexIntoFileIter_.run(), indexIntoFileIter_.lumi(), 0U)) {
00670         return true;
00671       }
00672 
00673       // The Lumi is not skipped.  If this is an event, see if the event is skipped.
00674       if(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent) {
00675         fillEventAuxiliary();
00676         if(eventSkipperByID_->skipIt(indexIntoFileIter_.run(),
00677                                       indexIntoFileIter_.lumi(),
00678                                       eventAux_.id().event())) {
00679           return true;
00680         }
00681       }
00682 
00683       // Skip runs with no lumis if either lumisToSkip or lumisToProcess have been set to select lumis
00684       if(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun &&
00685           eventSkipperByID_->skippingLumis()) {
00686         IndexIntoFile::IndexIntoFileItr iterLumi = indexIntoFileIter_;
00687 
00688         // There are no lumis in this run, not even ones we will skip
00689         if(iterLumi.peekAheadAtLumi() == IndexIntoFile::invalidLumi) {
00690           return true;
00691         }
00692         // If we get here there are lumis in the run, check to see if we are skipping all of them
00693         do {
00694           if(!eventSkipperByID_->skipIt(iterLumi.run(), iterLumi.peekAheadAtLumi(), 0U)) {
00695             return false;
00696           }
00697         }
00698         while(iterLumi.skipLumiInRun());
00699         return true;
00700       }
00701     }
00702     return false;
00703   }
00704 
00705   IndexIntoFile::EntryType
00706   RootFile::getEntryTypeWithSkipping() {
00707     while(skipThisEntry()) {
00708       if(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun) {
00709         indexIntoFileIter_.advanceToNextRun();
00710       }
00711       else if(indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi) {
00712         indexIntoFileIter_.advanceToNextLumiOrRun();
00713       }
00714       else {
00715         ++indexIntoFileIter_;
00716       }
00717     }
00718     return indexIntoFileIter_.getEntryType();
00719   }
00720 
00721   bool
00722   RootFile::isDuplicateEvent() {
00723     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent);
00724     if(duplicateChecker_.get() == 0) {
00725       return false;
00726     }
00727     fillEventAuxiliary();
00728     return duplicateChecker_->isDuplicateAndCheckActive(indexIntoFileIter_.processHistoryIDIndex(),
00729         indexIntoFileIter_.run(), indexIntoFileIter_.lumi(), eventAux_.id().event(), file_);
00730   }
00731 
00732   IndexIntoFile::EntryType
00733   RootFile::getNextEntryTypeWanted() {
00734     IndexIntoFile::EntryType entryType = getEntryTypeWithSkipping();
00735     if(entryType == IndexIntoFile::kEnd) {
00736       return IndexIntoFile::kEnd;
00737     }
00738     if(entryType == IndexIntoFile::kRun) {
00739       return IndexIntoFile::kRun;
00740     } else if(processingMode_ == InputSource::Runs) {
00741       indexIntoFileIter_.advanceToNextRun();
00742       return getNextEntryTypeWanted();
00743     }
00744     if(entryType == IndexIntoFile::kLumi) {
00745       return IndexIntoFile::kLumi;
00746     } else if(processingMode_ == InputSource::RunsAndLumis) {
00747       indexIntoFileIter_.advanceToNextLumiOrRun();
00748       return getNextEntryTypeWanted();
00749     }
00750     if(isDuplicateEvent()) {
00751       ++indexIntoFileIter_;
00752       return getNextEntryTypeWanted();
00753     }
00754     return IndexIntoFile::kEvent;
00755   }
00756 
00757   bool
00758   RootFile::wasLastEventJustRead() const {
00759     IndexIntoFile::IndexIntoFileItr itr(indexIntoFileIter_);
00760     itr.advanceToEvent();
00761     return itr.getEntryType() == IndexIntoFile::kEnd;
00762   }
00763 
00764   bool
00765   RootFile::wasFirstEventJustRead() const {
00766     IndexIntoFile::IndexIntoFileItr itr(indexIntoFileIter_);
00767     int phIndex;
00768     RunNumber_t run;
00769     LuminosityBlockNumber_t lumi;
00770     IndexIntoFile::EntryNumber_t eventEntry;
00771     itr.skipEventBackward(phIndex,
00772                           run,
00773                           lumi,
00774                           eventEntry);
00775     itr.skipEventBackward(phIndex,
00776                           run,
00777                           lumi,
00778                           eventEntry);
00779     return eventEntry == IndexIntoFile::invalidEntry;
00780   }
00781 
00782   namespace {
00783     typedef IndexIntoFile::EntryNumber_t  EntryNumber_t;
00784     struct RunItem {
00785       RunItem(ProcessHistoryID const& phid, RunNumber_t const& run) :
00786         phid_(phid), run_(run) {}
00787       ProcessHistoryID phid_;
00788       RunNumber_t run_;
00789     };
00790     struct RunItemSortByRun {
00791       bool operator()(RunItem const& a, RunItem const& b) const {
00792         return a.run_ < b.run_;
00793       }
00794     };
00795     struct RunItemSortByRunPhid {
00796       bool operator()(RunItem const& a, RunItem const& b) const {
00797         return a.run_ < b.run_ || (!(b.run_ < a.run_) && a.phid_ < b.phid_);
00798       }
00799     };
00800     struct LumiItem {
00801       LumiItem(ProcessHistoryID const& phid, RunNumber_t const& run,
00802                  LuminosityBlockNumber_t const& lumi, EntryNumber_t const& entry) :
00803         phid_(phid), run_(run), lumi_(lumi), firstEventEntry_(entry),
00804         lastEventEntry_(entry == -1LL ? -1LL : entry + 1) {}
00805       ProcessHistoryID phid_;
00806       RunNumber_t run_;
00807       LuminosityBlockNumber_t lumi_;
00808       EntryNumber_t firstEventEntry_;
00809       EntryNumber_t lastEventEntry_;
00810     };
00811     struct LumiItemSortByRunLumi {
00812       bool operator()(LumiItem const& a, LumiItem const& b) const {
00813         return a.run_ < b.run_ || (!(b.run_ < a.run_) && a.lumi_ < b.lumi_);
00814       }
00815     };
00816     struct LumiItemSortByRunLumiPhid {
00817       bool operator()(LumiItem const& a, LumiItem const& b) const {
00818         if(a.run_ < b.run_) return true;
00819         if(b.run_ < a.run_) return false;
00820         if(a.lumi_ < b.lumi_) return true;
00821         if(b.lumi_ < a.lumi_) return false;
00822         return a.phid_ < b.phid_;
00823       }
00824     };
00825   }
00826 
00827   void
00828   RootFile::fillIndexIntoFile() {
00829     // This function is for backward compatibility.
00830     // If reading a current format file, indexIntoFile_ is read from the input
00831     // file and should always be there. Note that the algorithm below will work
00832     // sometimes but often fail with the new format introduced in release 3_8_0.
00833     // If it ever becomes necessary to rebuild IndexIntoFile from the new format,
00834     // probably a separate function should be written to deal with the task.
00835     // This is possible just not implemented yet.
00836     assert(!fileFormatVersion().hasIndexIntoFile());
00837 
00838     typedef std::list<LumiItem> LumiList;
00839     LumiList lumis; // (declare 1)
00840 
00841     typedef std::set<LuminosityBlockID> RunLumiSet;
00842     RunLumiSet runLumiSet; // (declare 2)
00843 
00844     typedef std::list<RunItem> RunList;
00845     RunList runs; // (declare 5)
00846 
00847     typedef std::set<RunNumber_t> RunSet;
00848     RunSet runSet; // (declare 4)
00849 
00850     typedef std::set<RunItem, RunItemSortByRunPhid> RunItemSet;
00851     RunItemSet runItemSet; // (declare 3)
00852 
00853     typedef std::map<RunNumber_t, ProcessHistoryID> PHIDMap;
00854     PHIDMap phidMap;
00855 
00856     RunNumber_t prevRun = 0;
00857     LuminosityBlockNumber_t prevLumi = 0;
00858     ProcessHistoryID prevPhid;
00859     bool iFirst = true;
00860 
00861     indexIntoFile_.unsortedEventNumbers().clear(); // should already be empty, just being careful
00862     indexIntoFile_.unsortedEventNumbers().reserve(eventTree_.entries());
00863 
00864     // First, loop through the event tree.
00865     while(eventTree_.next()) {
00866       bool newRun = false;
00867       bool newLumi = false;
00868       fillThisEventAuxiliary();
00869       fillHistory();
00870 
00871       // Save the event numbers as we loop through the event auxiliary to avoid
00872       // having to read through the event auxiliary again later. These event numbers
00873       // are not actually used in this function, but could be needed elsewhere.
00874       indexIntoFile_.unsortedEventNumbers().push_back(eventAux().event());
00875 
00876       ProcessHistoryID reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(eventAux().processHistoryID());
00877 
00878       if(iFirst || prevPhid != reducedPHID || prevRun != eventAux().run()) {
00879         iFirst = false;
00880         newRun = newLumi = true;
00881       } else if(prevLumi != eventAux().luminosityBlock()) {
00882         newLumi = true;
00883       }
00884       prevPhid = reducedPHID;
00885       prevRun = eventAux().run();
00886       prevLumi = eventAux().luminosityBlock();
00887       if(newLumi) {
00888         lumis.emplace_back(reducedPHID,
00889           eventAux().run(), eventAux().luminosityBlock(), eventTree_.entryNumber()); // (insert 1)
00890         runLumiSet.insert(LuminosityBlockID(eventAux().run(), eventAux().luminosityBlock())); // (insert 2)
00891       } else {
00892         LumiItem& currentLumi = lumis.back();
00893         assert(currentLumi.lastEventEntry_ == eventTree_.entryNumber());
00894         ++currentLumi.lastEventEntry_;
00895       }
00896       if(newRun) {
00897         // Insert run in list if it is not already there.
00898         RunItem item(reducedPHID, eventAux().run());
00899         if(runItemSet.insert(item).second) { // (check 3, insert 3)
00900           runs.push_back(std::move(item)); // (insert 5)
00901           runSet.insert(eventAux().run()); // (insert 4)
00902           phidMap.insert(std::make_pair(eventAux().run(), reducedPHID));
00903         }
00904       }
00905     }
00906     // now clean up.
00907     eventTree_.setEntryNumber(-1);
00908     eventAux_ = EventAuxiliary();
00909     lastEventEntryNumberRead_ = -1LL;
00910 
00911     // Loop over run entries and fill information.
00912 
00913     typedef std::map<RunNumber_t, EntryNumber_t> RunMap;
00914     RunMap runMap; // (declare 11)
00915 
00916     typedef std::vector<RunItem> RunVector;
00917     RunVector emptyRuns; // (declare 12)
00918 
00919     if(runTree_.isValid()) {
00920       while(runTree_.next()) {
00921         // Note: adjacent duplicates will be skipped without an explicit check.
00922 
00923         boost::shared_ptr<RunAuxiliary> runAux = fillRunAuxiliary();
00924         ProcessHistoryID reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(runAux->processHistoryID());
00925 
00926         if(runSet.insert(runAux->run()).second) { // (check 4, insert 4)
00927           // This run was not associated with any events.
00928           emptyRuns.emplace_back(reducedPHID, runAux->run()); // (insert 12)
00929         }
00930         runMap.insert(std::make_pair(runAux->run(), runTree_.entryNumber())); // (insert 11)
00931         phidMap.insert(std::make_pair(runAux->run(), reducedPHID));
00932       }
00933       // now clean up.
00934       runTree_.setEntryNumber(-1);
00935     }
00936 
00937     // Insert the ordered empty runs into the run list.
00938     RunItemSortByRun runItemSortByRun;
00939     stable_sort_all(emptyRuns, runItemSortByRun);
00940 
00941     RunList::iterator itRuns = runs.begin(), endRuns = runs.end();
00942     for(RunVector::const_iterator i = emptyRuns.begin(), iEnd = emptyRuns.end(); i != iEnd; ++i) {
00943       for(; itRuns != endRuns; ++itRuns) {
00944         if(runItemSortByRun(*i, *itRuns)) {
00945           break;
00946         }
00947       }
00948       runs.insert(itRuns, *i);
00949     }
00950 
00951     // Loop over luminosity block entries and fill information.
00952 
00953     typedef std::vector<LumiItem> LumiVector;
00954     LumiVector emptyLumis; // (declare 7)
00955 
00956     typedef std::map<LuminosityBlockID, EntryNumber_t> RunLumiMap;
00957     RunLumiMap runLumiMap; // (declare 6)
00958 
00959     if(lumiTree_.isValid()) {
00960       while(lumiTree_.next()) {
00961         // Note: adjacent duplicates will be skipped without an explicit check.
00962         boost::shared_ptr<LuminosityBlockAuxiliary> lumiAux = fillLumiAuxiliary();
00963         LuminosityBlockID lumiID = LuminosityBlockID(lumiAux->run(), lumiAux->luminosityBlock());
00964         if(runLumiSet.insert(lumiID).second) { // (check 2, insert 2)
00965           // This lumi was not associated with any events.
00966           // Use the process history ID from the corresponding run.  In cases of practical
00967           // importance, this should be the correct process history ID,  but it is possible
00968           // to construct files where this is not the correct process history ID ...
00969           PHIDMap::const_iterator iPhidMap = phidMap.find(lumiAux->run());
00970           assert(iPhidMap != phidMap.end());
00971           emptyLumis.emplace_back(iPhidMap->second, lumiAux->run(), lumiAux->luminosityBlock(), -1LL); // (insert 7)
00972         }
00973         runLumiMap.insert(std::make_pair(lumiID, lumiTree_.entryNumber()));
00974       }
00975       // now clean up.
00976       lumiTree_.setEntryNumber(-1);
00977     }
00978 
00979     // Insert the ordered empty lumis into the lumi list.
00980     LumiItemSortByRunLumi lumiItemSortByRunLumi;
00981     stable_sort_all(emptyLumis, lumiItemSortByRunLumi);
00982 
00983     LumiList::iterator itLumis = lumis.begin(), endLumis = lumis.end();
00984     for(LumiVector::const_iterator i = emptyLumis.begin(), iEnd = emptyLumis.end(); i != iEnd; ++i) {
00985       for(; itLumis != endLumis; ++itLumis) {
00986         if(lumiItemSortByRunLumi(*i, *itLumis)) {
00987           break;
00988         }
00989       }
00990       lumis.insert(itLumis, *i);
00991     }
00992 
00993     // Create a map of RunItems that gives the order of first appearance in the list.
00994     // Also fill in the vector of process history IDs
00995     typedef std::map<RunItem, int, RunItemSortByRunPhid> RunCountMap;
00996     RunCountMap runCountMap; // Declare (17)
00997     std::vector<ProcessHistoryID>& phids = indexIntoFile_.setProcessHistoryIDs();
00998     assert(phids.empty());
00999     std::vector<IndexIntoFile::RunOrLumiEntry>& entries = indexIntoFile_.setRunOrLumiEntries();
01000     assert(entries.empty());
01001     int rcount = 0;
01002     for(RunList::iterator it = runs.begin(), itEnd = runs.end(); it != itEnd; ++it) {
01003       RunCountMap::const_iterator countMapItem = runCountMap.find(*it);
01004       if(countMapItem == runCountMap.end()) {
01005         countMapItem = runCountMap.insert(std::make_pair(*it, rcount)).first; // Insert (17)
01006         assert(countMapItem != runCountMap.end());
01007         ++rcount;
01008       }
01009       std::vector<ProcessHistoryID>::const_iterator phidItem = find_in_all(phids, it->phid_);
01010       if(phidItem == phids.end()) {
01011         phids.push_back(it->phid_);
01012         phidItem = phids.end() - 1;
01013       }
01014       entries.emplace_back(
01015         countMapItem->second, // use (17)
01016         -1LL,
01017         runMap[it->run_], // use (11)
01018         phidItem - phids.begin(),
01019         it->run_,
01020         0U,
01021         -1LL,
01022         -1LL);
01023     }
01024 
01025     // Create a map of LumiItems that gives the order of first appearance in the list.
01026     typedef std::map<LumiItem, int, LumiItemSortByRunLumiPhid> LumiCountMap;
01027     LumiCountMap lumiCountMap; // Declare (19)
01028     int lcount = 0;
01029     for(LumiList::iterator it = lumis.begin(), itEnd = lumis.end(); it != itEnd; ++it) {
01030       RunCountMap::const_iterator runCountMapItem = runCountMap.find(RunItem(it->phid_, it->run_));
01031       assert(runCountMapItem != runCountMap.end());
01032       LumiCountMap::const_iterator countMapItem = lumiCountMap.find(*it);
01033       if(countMapItem == lumiCountMap.end()) {
01034         countMapItem = lumiCountMap.insert(std::make_pair(*it, lcount)).first; // Insert (17)
01035         assert(countMapItem != lumiCountMap.end());
01036         ++lcount;
01037       }
01038       std::vector<ProcessHistoryID>::const_iterator phidItem = find_in_all(phids, it->phid_);
01039       assert(phidItem != phids.end());
01040       entries.emplace_back(
01041         runCountMapItem->second,
01042         countMapItem->second,
01043         runLumiMap[LuminosityBlockID(it->run_, it->lumi_)],
01044         phidItem - phids.begin(),
01045         it->run_,
01046         it->lumi_,
01047         it->firstEventEntry_,
01048         it->lastEventEntry_);
01049     }
01050     stable_sort_all(entries);
01051   }
01052 
01053   void
01054   RootFile::validateFile(InputType::InputType inputType, bool usingGoToEvent) {
01055     if(!fid_.isValid()) {
01056       fid_ = FileID(createGlobalIdentifier());
01057     }
01058     if(!eventTree_.isValid()) {
01059       throw Exception(errors::EventCorruption) <<
01060          "'Events' tree is corrupted or not present\n" << "in the input file.\n";
01061     }
01062 
01063     if(fileFormatVersion().hasIndexIntoFile()) {
01064       if(runTree().entries() > 0) {
01065         assert(!indexIntoFile_.empty());
01066       }
01067       if(!fileFormatVersion().useReducedProcessHistoryID()) {
01068         if(daqProvenanceHelper_) {
01069           std::vector<ProcessHistoryID>& phidVec = indexIntoFile_.setProcessHistoryIDs();
01070           for(std::vector<ProcessHistoryID>::iterator it = phidVec.begin(), itEnd = phidVec.end();
01071               it != itEnd;
01072               ++it) {
01073             *it = daqProvenanceHelper_->mapProcessHistoryID(*it);
01074           }
01075         }
01076         indexIntoFile_.reduceProcessHistoryIDs();
01077       }
01078     }
01079     else {
01080       assert(indexIntoFile_.empty());
01081       fillIndexIntoFile();
01082     }
01083 
01084     indexIntoFile_.fixIndexes(orderedProcessHistoryIDs_);
01085     indexIntoFile_.setNumberOfEvents(eventTree_.entries());
01086     indexIntoFile_.setEventFinder(boost::shared_ptr<IndexIntoFile::EventFinder>(new RootFileEventFinder(eventTree_)));
01087     // We fill the event numbers explicitly if we need to find events in closed files,
01088     // such as for secondary files (or secondary sources) or if duplicate checking across files.
01089     bool needEventNumbers = false;
01090     bool needIndexesForDuplicateChecker = duplicateChecker_ && duplicateChecker_->checkingAllFiles() && !duplicateChecker_->checkDisabled();
01091     if(inputType != InputType::Primary || needIndexesForDuplicateChecker || usingGoToEvent) {
01092       needEventNumbers = true;
01093     }
01094     bool needEventEntries = false;
01095     if(inputType != InputType::Primary || !noEventSort_) {
01096       // We need event entries for sorting or for secondary files or sources.
01097       needEventEntries = true;
01098     }
01099     indexIntoFile_.fillEventNumbersOrEntries(needEventNumbers, needEventEntries);
01100   }
01101 
01102   void
01103   RootFile::reportOpened(std::string const& inputType) {
01104     // Report file opened.
01105     std::string const label = "source";
01106     std::string moduleName = "PoolSource";
01107     filePtr_->inputFileOpened(
01108               logicalFile_,
01109               inputType,
01110               moduleName,
01111               label,
01112               fid_.fid(),
01113               eventTree_.branchNames());
01114   }
01115 
01116   void
01117   RootFile::close() {
01118     // Just to play it safe, zero all pointers to objects in the InputFile to be closed.
01119     eventHistoryTree_ = 0;
01120     for(RootTreePtrArray::iterator it = treePointers_.begin(), itEnd = treePointers_.end(); it != itEnd; ++it) {
01121       (*it)->close();
01122       (*it) = 0;
01123     }
01124     filePtr_->Close();
01125     filePtr_.reset();
01126   }
01127 
01128   void
01129   RootFile::fillThisEventAuxiliary() {
01130     if(lastEventEntryNumberRead_ == eventTree_.entryNumber()) {
01131       // Already read.
01132       return;
01133     }
01134     if(fileFormatVersion().newAuxiliary()) {
01135       EventAuxiliary *pEvAux = &eventAux_;
01136       eventTree_.fillAux<EventAuxiliary>(pEvAux);
01137     } else {
01138       // for backward compatibility.
01139       EventAux eventAux;
01140       EventAux *pEvAux = &eventAux;
01141       eventTree_.fillAux<EventAux>(pEvAux);
01142       conversion(eventAux, eventAux_);
01143     }
01144     lastEventEntryNumberRead_ = eventTree_.entryNumber();
01145   }
01146 
01147   void
01148   RootFile::fillEventAuxiliary() {
01149     eventTree_.setEntryNumber(indexIntoFileIter_.entry());
01150     fillThisEventAuxiliary();
01151   }
01152 
01153   void
01154   RootFile::fillHistory() {
01155     // We could consider doing delayed reading, but because we have to
01156     // store this History object in a different tree than the event
01157     // data tree, this is too hard to do in this first version.
01158 
01159     if(fileFormatVersion().eventHistoryBranch()) {
01160       // Lumi block number was not in EventID for the relevant releases.
01161       EventID id(eventAux().id().run(), 0, eventAux().id().event());
01162       if(eventProcessHistoryIter_->eventID() != id) {
01163         EventProcessHistoryID target(id, ProcessHistoryID());
01164         eventProcessHistoryIter_ = lower_bound_all(eventProcessHistoryIDs_, target);
01165         assert(eventProcessHistoryIter_->eventID() == id);
01166       }
01167       eventAux_.setProcessHistoryID(eventProcessHistoryIter_->processHistoryID());
01168       ++eventProcessHistoryIter_;
01169     } else if(fileFormatVersion().eventHistoryTree()) {
01170       // for backward compatibility.
01171       History* pHistory = history_.get();
01172       TBranch* eventHistoryBranch = eventHistoryTree_->GetBranch(poolNames::eventHistoryBranchName().c_str());
01173       if(!eventHistoryBranch) {
01174         throw Exception(errors::EventCorruption)
01175           << "Failed to find history branch in event history tree.\n";
01176       }
01177       eventHistoryBranch->SetAddress(&pHistory);
01178       roottree::getEntry(eventHistoryTree_, eventTree_.entryNumber());
01179       eventAux_.setProcessHistoryID(history_->processHistoryID());
01180       eventSelectionIDs_.reset(&history_->eventSelectionIDs(), do_nothing_deleter());
01181       branchListIndexes_.reset(&history_->branchListIndexes(), do_nothing_deleter());
01182     } else if(fileFormatVersion().noMetaDataTrees()) {
01183       // Current format
01184       EventSelectionIDVector* pESV = eventSelectionIDs_.get();
01185       TBranch* eventSelectionIDBranch = eventTree_.tree()->GetBranch(poolNames::eventSelectionsBranchName().c_str());
01186       assert(eventSelectionIDBranch != 0);
01187       eventTree_.fillBranchEntry(eventSelectionIDBranch, pESV);
01188       BranchListIndexes* pBLI = branchListIndexes_.get();
01189       TBranch* branchListIndexesBranch = eventTree_.tree()->GetBranch(poolNames::branchListIndexesBranchName().c_str());
01190       assert(branchListIndexesBranch != 0);
01191       eventTree_.fillBranchEntry(branchListIndexesBranch, pBLI);
01192     }
01193     if(provenanceAdaptor_) {
01194       eventAux_.setProcessHistoryID(provenanceAdaptor_->convertID(eventAux().processHistoryID()));
01195       for(EventSelectionIDVector::iterator i = eventSelectionIDs_->begin(), e = eventSelectionIDs_->end(); i != e; ++i) {
01196         (*i) = provenanceAdaptor_->convertID(*i);
01197       }
01198     }
01199     if(daqProvenanceHelper_) {
01200       eventAux_.setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(eventAux_.processHistoryID()));
01201     }
01202     if(!fileFormatVersion().splitProductIDs()) {
01203       // old format.  branchListIndexes_ must be filled in from the ProvenanceAdaptor.
01204       provenanceAdaptor_->branchListIndexes(*branchListIndexes_);
01205     }
01206     branchIDListHelper_->fixBranchListIndexes(*branchListIndexes_);
01207   }
01208 
01209   boost::shared_ptr<LuminosityBlockAuxiliary>
01210   RootFile::fillLumiAuxiliary() {
01211     boost::shared_ptr<LuminosityBlockAuxiliary> lumiAuxiliary(new LuminosityBlockAuxiliary);
01212     if(fileFormatVersion().newAuxiliary()) {
01213       LuminosityBlockAuxiliary *pLumiAux = lumiAuxiliary.get();
01214       lumiTree_.fillAux<LuminosityBlockAuxiliary>(pLumiAux);
01215     } else {
01216       LuminosityBlockAux lumiAux;
01217       LuminosityBlockAux *pLumiAux = &lumiAux;
01218       lumiTree_.fillAux<LuminosityBlockAux>(pLumiAux);
01219       conversion(lumiAux, *lumiAuxiliary);
01220     }
01221     if(provenanceAdaptor_) {
01222       lumiAuxiliary->setProcessHistoryID(provenanceAdaptor_->convertID(lumiAuxiliary->processHistoryID()));
01223     }
01224     if(daqProvenanceHelper_) {
01225       lumiAuxiliary->setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(lumiAuxiliary->processHistoryID()));
01226     }
01227     if(lumiAuxiliary->luminosityBlock() == 0 && !fileFormatVersion().runsAndLumis()) {
01228       lumiAuxiliary->id() = LuminosityBlockID(RunNumber_t(1), LuminosityBlockNumber_t(1));
01229     }
01230     return lumiAuxiliary;
01231   }
01232 
01233   boost::shared_ptr<RunAuxiliary>
01234   RootFile::fillRunAuxiliary() {
01235     boost::shared_ptr<RunAuxiliary> runAuxiliary(new RunAuxiliary);
01236     if(fileFormatVersion().newAuxiliary()) {
01237       RunAuxiliary *pRunAux = runAuxiliary.get();
01238       runTree_.fillAux<RunAuxiliary>(pRunAux);
01239     } else {
01240       RunAux runAux;
01241       RunAux *pRunAux = &runAux;
01242       runTree_.fillAux<RunAux>(pRunAux);
01243       conversion(runAux, *runAuxiliary);
01244     }
01245     if(provenanceAdaptor_) {
01246       runAuxiliary->setProcessHistoryID(provenanceAdaptor_->convertID(runAuxiliary->processHistoryID()));
01247     }
01248     if(daqProvenanceHelper_) {
01249       runAuxiliary->setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(runAuxiliary->processHistoryID()));
01250     }
01251     return runAuxiliary;
01252   }
01253 
01254   bool
01255   RootFile::skipEvents(int& offset) {
01256     while(offset > 0 && indexIntoFileIter_ != indexIntoFileEnd_) {
01257 
01258       int phIndexOfSkippedEvent = IndexIntoFile::invalidIndex;
01259       RunNumber_t runOfSkippedEvent = IndexIntoFile::invalidRun;
01260       LuminosityBlockNumber_t lumiOfSkippedEvent = IndexIntoFile::invalidLumi;
01261       IndexIntoFile::EntryNumber_t skippedEventEntry = IndexIntoFile::invalidEntry;
01262 
01263       indexIntoFileIter_.skipEventForward(phIndexOfSkippedEvent,
01264                                           runOfSkippedEvent,
01265                                           lumiOfSkippedEvent,
01266                                           skippedEventEntry);
01267 
01268       // At the end of the file and there were no more events to skip
01269       if(skippedEventEntry == IndexIntoFile::invalidEntry) break;
01270 
01271       if(eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
01272         eventTree_.setEntryNumber(skippedEventEntry);
01273         fillThisEventAuxiliary();
01274         if(eventSkipperByID_->skipIt(runOfSkippedEvent, lumiOfSkippedEvent, eventAux_.id().event())) {
01275             continue;
01276         }
01277       }
01278       if(duplicateChecker_ &&
01279          !duplicateChecker_->checkDisabled() &&
01280          !duplicateChecker_->noDuplicatesInFile()) {
01281 
01282         eventTree_.setEntryNumber(skippedEventEntry);
01283         fillThisEventAuxiliary();
01284         if(duplicateChecker_->isDuplicateAndCheckActive(phIndexOfSkippedEvent,
01285                                                          runOfSkippedEvent,
01286                                                          lumiOfSkippedEvent,
01287                                                          eventAux_.id().event(),
01288                                                          file_)) {
01289           continue;
01290         }
01291       }
01292       --offset;
01293     }
01294 
01295     while(offset < 0) {
01296 
01297       if(duplicateChecker_) {
01298         duplicateChecker_->disable();
01299       }
01300 
01301       int phIndexOfEvent = IndexIntoFile::invalidIndex;
01302       RunNumber_t runOfEvent =  IndexIntoFile::invalidRun;
01303       LuminosityBlockNumber_t lumiOfEvent = IndexIntoFile::invalidLumi;
01304       EntryNumber_t eventEntry = IndexIntoFile::invalidEntry;
01305 
01306       indexIntoFileIter_.skipEventBackward(phIndexOfEvent,
01307                                            runOfEvent,
01308                                            lumiOfEvent,
01309                                            eventEntry);
01310 
01311       if(eventEntry == IndexIntoFile::invalidEntry) break;
01312 
01313       if(eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
01314         eventTree_.setEntryNumber(eventEntry);
01315         fillEventAuxiliary();
01316         if(eventSkipperByID_->skipIt(runOfEvent, lumiOfEvent, eventAux_.id().event())) {
01317           continue;
01318         }
01319       }
01320       ++offset;
01321     }
01322     return(indexIntoFileIter_ == indexIntoFileEnd_);
01323   }
01324 
01325   bool
01326   RootFile::goToEvent(EventID const& eventID) {
01327 
01328     indexIntoFile_.fillEventNumbers();
01329 
01330     if(duplicateChecker_) {
01331       duplicateChecker_->disable();
01332     }
01333 
01334     IndexIntoFile::SortOrder sortOrder = IndexIntoFile::numericalOrder;
01335     if(noEventSort_) sortOrder = IndexIntoFile::firstAppearanceOrder;
01336 
01337     IndexIntoFile::IndexIntoFileItr iter =
01338       indexIntoFile_.findPosition(sortOrder, eventID.run(), eventID.luminosityBlock(), eventID.event());
01339 
01340     if(iter == indexIntoFile_.end(sortOrder)) {
01341       return false;
01342     }
01343     indexIntoFileIter_ = iter;
01344     return true;
01345   }
01346 
01347   // readEvent() is responsible for creating, and setting up, the
01348   // EventPrincipal.
01349   //
01350   //   1. create an EventPrincipal with a unique EventID
01351   //   2. For each entry in the provenance, put in one Group,
01352   //      holding the Provenance for the corresponding EDProduct.
01353   //   3. set up the caches in the EventPrincipal to know about this
01354   //      Group.
01355   //
01356   // We do *not* create the EDProduct instance (the equivalent of reading
01357   // the branch containing this EDProduct. That will be done by the Delayed Reader,
01358   //  when it is asked to do so.
01359   //
01360   EventPrincipal*
01361   RootFile::readEvent(EventPrincipal& cache) {
01362     assert(indexIntoFileIter_ != indexIntoFileEnd_);
01363     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent);
01364     // Set the entry in the tree, and read the event at that entry.
01365     eventTree_.setEntryNumber(indexIntoFileIter_.entry());
01366     EventPrincipal* ep = readCurrentEvent(cache);
01367 
01368     assert(ep != 0);
01369     assert(eventAux().run() == indexIntoFileIter_.run() + forcedRunOffset_);
01370     assert(eventAux().luminosityBlock() == indexIntoFileIter_.lumi());
01371 
01372     // If this next assert shows up in performance profiling or significantly affects memory, then these three lines should be deleted.
01373     // The IndexIntoFile should guarantee that it never fails.
01374     ProcessHistoryID idToCheck = (daqProvenanceHelper_ && fileFormatVersion().useReducedProcessHistoryID() ? *daqProvenanceHelper_->oldProcessHistoryID_ : eventAux().processHistoryID());
01375     ProcessHistoryID const& reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(idToCheck);
01376     assert(reducedPHID == indexIntoFile_.processHistoryID(indexIntoFileIter_.processHistoryIDIndex()));
01377 
01378     ++indexIntoFileIter_;
01379     return ep;
01380   }
01381 
01382   // Reads event at the current entry in the event tree
01383   EventPrincipal*
01384   RootFile::readCurrentEvent(EventPrincipal& cache) {
01385     if(!eventTree_.current()) {
01386       return 0;
01387     }
01388     fillThisEventAuxiliary();
01389     if(!fileFormatVersion().lumiInEventID()) {
01390         //ugly, but will disappear when the backward compatibility is done with schema evolution.
01391         const_cast<EventID&>(eventAux_.id()).setLuminosityBlockNumber(eventAux_.oldLuminosityBlock());
01392         eventAux_.resetObsoleteInfo();
01393     }
01394     fillHistory();
01395     overrideRunNumber(eventAux_.id(), eventAux().isRealData());
01396 
01397     // We're not done ... so prepare the EventPrincipal
01398     cache.fillEventPrincipal(eventAux(),
01399                              eventSelectionIDs_,
01400                              branchListIndexes_,
01401                              makeBranchMapper(),
01402                              eventTree_.rootDelayedReader());
01403 
01404     // report event read from file
01405     filePtr_->eventReadFromFile(eventID().run(), eventID().event());
01406     return &cache;
01407   }
01408 
01409   EventPrincipal*
01410   RootFile::clearAndReadCurrentEvent(EventPrincipal& cache) {
01411     cache.clearEventPrincipal();
01412     return readCurrentEvent(cache);
01413   }
01414 
01415   void
01416   RootFile::setAtEventEntry(IndexIntoFile::EntryNumber_t entry) {
01417     eventTree_.setEntryNumber(entry);
01418   }
01419 
01420   boost::shared_ptr<RunAuxiliary>
01421   RootFile::readRunAuxiliary_() {
01422     assert(indexIntoFileIter_ != indexIntoFileEnd_);
01423     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun);
01424 
01425     // Begin code for backward compatibility before the existence of run trees.
01426     if(!runTree_.isValid()) {
01427 
01428       // prior to the support of run trees.
01429       // RunAuxiliary did not contain a valid timestamp.  Take it from the next event.
01430       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisRun();
01431       assert(eventEntry != IndexIntoFile::invalidEntry);
01432       RootTree::EntryNumber savedEntry = eventTree_.entryNumber();
01433       eventTree_.setEntryNumber(eventEntry);
01434       assert(eventTree_.current());
01435       fillThisEventAuxiliary();
01436       eventTree_.setEntryNumber(savedEntry);
01437 
01438       RunID run = RunID(indexIntoFileIter_.run());
01439       overrideRunNumber(run);
01440       return boost::shared_ptr<RunAuxiliary>(new RunAuxiliary(run.run(), eventAux().time(), Timestamp::invalidTimestamp()));
01441     }
01442     // End code for backward compatibility before the existence of run trees.
01443     runTree_.setEntryNumber(indexIntoFileIter_.entry());
01444     boost::shared_ptr<RunAuxiliary> runAuxiliary = fillRunAuxiliary();
01445     assert(runAuxiliary->run() == indexIntoFileIter_.run());
01446     overrideRunNumber(runAuxiliary->id());
01447     filePtr_->reportInputRunNumber(runAuxiliary->run());
01448     // If RunAuxiliary did not contain a valid begin timestamp, invalidate any end timestamp.
01449     if(runAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
01450       runAuxiliary->setEndTime(Timestamp::invalidTimestamp());
01451     }
01452 
01453     // If RunAuxiliary did not contain a valid timestamp, or if this an old format file from
01454     // when the Run's ProcessHistory included only processes where products were added to the Run itself,
01455     // we attempt to read the first event in the run to get appropriate info.
01456     if(runAuxiliary->beginTime() == Timestamp::invalidTimestamp() ||
01457        !fileFormatVersion().processHistorySameWithinRun()) {
01458 
01459       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisRun();
01460       // If we have a valid event, use its information.
01461       if(eventEntry != IndexIntoFile::invalidEntry) {
01462         RootTree::EntryNumber savedEntry = eventTree_.entryNumber();
01463         eventTree_.setEntryNumber(eventEntry);
01464         assert(eventTree_.current());
01465         fillThisEventAuxiliary();
01466 
01467         // RunAuxiliary did not contain a valid timestamp.  Take it from the next event in this run if there is one.
01468         if(runAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
01469           runAuxiliary->setBeginTime(eventAux().time());
01470         }
01471 
01472         // For backwards compatibility when the Run's ProcessHistory included only processes where products were added to the
01473         // Run, and then the Run and Event auxiliaries could be different.  Use the event ProcessHistoryID if there is one. It should
01474         // almost always be correct by the current definition (processes included if any products are added. This makes the run, lumi,
01475         // and event ProcessHistory's always be the same if no file merging occurs).
01476         if(!fileFormatVersion().processHistorySameWithinRun()) {
01477           fillHistory();
01478           runAuxiliary->setProcessHistoryID(eventAux().processHistoryID());
01479           savedRunAuxiliary_ = runAuxiliary;
01480         }
01481         eventTree_.setEntryNumber(savedEntry);
01482       } else {
01483         // No valid event, just use what is there, because it is the best we can do.
01484         savedRunAuxiliary_ = runAuxiliary;
01485       }
01486     }
01487     return runAuxiliary;
01488   }
01489 
01490   boost::shared_ptr<RunPrincipal>
01491   RootFile::readRun_(boost::shared_ptr<RunPrincipal> runPrincipal) {
01492     assert(indexIntoFileIter_ != indexIntoFileEnd_);
01493     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun);
01494     // Begin code for backward compatibility before the existence of run trees.
01495     if(!runTree_.isValid()) {
01496       ++indexIntoFileIter_;
01497       return runPrincipal;
01498     }
01499     // End code for backward compatibility before the existence of run trees.
01500     runPrincipal->fillRunPrincipal(runTree_.rootDelayedReader());
01501     // Read in all the products now.
01502     runPrincipal->readImmediate();
01503     ++indexIntoFileIter_;
01504     return runPrincipal;
01505   }
01506 
01507   boost::shared_ptr<LuminosityBlockAuxiliary>
01508   RootFile::readLuminosityBlockAuxiliary_() {
01509     assert(indexIntoFileIter_ != indexIntoFileEnd_);
01510     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi);
01511     // Begin code for backward compatibility before the existence of lumi trees.
01512     if(!lumiTree_.isValid()) {
01513       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisLumi();
01514       assert(eventEntry != IndexIntoFile::invalidEntry);
01515       RootTree::EntryNumber savedEntry = eventTree_.entryNumber();
01516       eventTree_.setEntryNumber(eventEntry);
01517       assert(eventTree_.current());
01518       fillThisEventAuxiliary();
01519       eventTree_.setEntryNumber(savedEntry);
01520 
01521       LuminosityBlockID lumi = LuminosityBlockID(indexIntoFileIter_.run(), indexIntoFileIter_.lumi());
01522       overrideRunNumber(lumi);
01523       return boost::shared_ptr<LuminosityBlockAuxiliary>(new LuminosityBlockAuxiliary(lumi.run(), lumi.luminosityBlock(), eventAux().time(), Timestamp::invalidTimestamp()));
01524     }
01525     // End code for backward compatibility before the existence of lumi trees.
01526     lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
01527     boost::shared_ptr<LuminosityBlockAuxiliary> lumiAuxiliary = fillLumiAuxiliary();
01528     assert(lumiAuxiliary->run() == indexIntoFileIter_.run());
01529     assert(lumiAuxiliary->luminosityBlock() == indexIntoFileIter_.lumi());
01530     overrideRunNumber(lumiAuxiliary->id());
01531     filePtr_->reportInputLumiSection(lumiAuxiliary->run(), lumiAuxiliary->luminosityBlock());
01532     if(lumiAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
01533       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisLumi();
01534       if(eventEntry != IndexIntoFile::invalidEntry) {
01535         RootTree::EntryNumber savedEntry = eventTree_.entryNumber();
01536         eventTree_.setEntryNumber(eventEntry);
01537         assert(eventTree_.current());
01538         fillThisEventAuxiliary();
01539         eventTree_.setEntryNumber(savedEntry);
01540 
01541         lumiAuxiliary->setBeginTime(eventAux().time());
01542       }
01543       lumiAuxiliary->setEndTime(Timestamp::invalidTimestamp());
01544     }
01545     if(!fileFormatVersion().processHistorySameWithinRun() && savedRunAuxiliary_) {
01546       lumiAuxiliary->setProcessHistoryID(savedRunAuxiliary_->processHistoryID());
01547     }
01548     return lumiAuxiliary;
01549   }
01550 
01551   boost::shared_ptr<LuminosityBlockPrincipal>
01552   RootFile::readLumi(boost::shared_ptr<LuminosityBlockPrincipal> lumiPrincipal) {
01553     assert(indexIntoFileIter_ != indexIntoFileEnd_);
01554     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi);
01555     // Begin code for backward compatibility before the existence of lumi trees.
01556     if(!lumiTree_.isValid()) {
01557       ++indexIntoFileIter_;
01558       return lumiPrincipal;
01559     }
01560     // End code for backward compatibility before the existence of lumi trees.
01561     lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
01562     lumiPrincipal->fillLuminosityBlockPrincipal(lumiTree_.rootDelayedReader());
01563     // Read in all the products now.
01564     lumiPrincipal->readImmediate();
01565     ++indexIntoFileIter_;
01566     return lumiPrincipal;
01567   }
01568 
01569   bool
01570   RootFile::setEntryAtEvent(RunNumber_t run, LuminosityBlockNumber_t lumi, EventNumber_t event) {
01571     indexIntoFileIter_ = indexIntoFile_.findEventPosition(run, lumi, event);
01572     if(indexIntoFileIter_ == indexIntoFileEnd_) return false;
01573     eventTree_.setEntryNumber(indexIntoFileIter_.entry());
01574     return true;
01575   }
01576 
01577   bool
01578   RootFile::setEntryAtLumi(RunNumber_t run, LuminosityBlockNumber_t lumi) {
01579     indexIntoFileIter_ = indexIntoFile_.findLumiPosition(run, lumi);
01580     if(indexIntoFileIter_ == indexIntoFileEnd_) return false;
01581     lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
01582     return true;
01583   }
01584 
01585   bool
01586   RootFile::setEntryAtRun(RunNumber_t run) {
01587     indexIntoFileIter_ = indexIntoFile_.findRunPosition(run);
01588     if(indexIntoFileIter_ == indexIntoFileEnd_) return false;
01589     runTree_.setEntryNumber(indexIntoFileIter_.entry());
01590     return true;
01591   }
01592 
01593   bool
01594   RootFile::setEntryAtNextEventInLumi(RunNumber_t run, LuminosityBlockNumber_t lumi) {
01595     if(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent) {
01596       ++indexIntoFileIter_;
01597     }
01598     indexIntoFileIter_.advanceToEvent();
01599     if(indexIntoFileIter_.getEntryType() != IndexIntoFile::kEvent) return false;
01600     if(run != indexIntoFileIter_.run()) return false;
01601     if(lumi != indexIntoFileIter_.lumi()) return false;
01602     eventTree_.setEntryNumber(indexIntoFileIter_.entry());
01603     return true;
01604   }
01605 
01606   void
01607   RootFile::overrideRunNumber(RunID& id) {
01608     if(forcedRunOffset_ != 0) {
01609       id = RunID(id.run() + forcedRunOffset_);
01610     }
01611     if(id < RunID::firstValidRun()) id = RunID::firstValidRun();
01612   }
01613 
01614   void
01615   RootFile::overrideRunNumber(LuminosityBlockID& id) {
01616     if(forcedRunOffset_ != 0) {
01617       id = LuminosityBlockID(id.run() + forcedRunOffset_, id.luminosityBlock());
01618     }
01619     if(RunID(id.run()) < RunID::firstValidRun()) id = LuminosityBlockID(RunID::firstValidRun().run(), id.luminosityBlock());
01620   }
01621 
01622   void
01623   RootFile::overrideRunNumber(EventID& id, bool isRealData) {
01624     if(forcedRunOffset_ != 0) {
01625       if(isRealData) {
01626         throw Exception(errors::Configuration, "RootFile::RootFile()")
01627           << "The 'setRunNumber' parameter of PoolSource cannot be used with real data.\n";
01628       }
01629       id = EventID(id.run() + forcedRunOffset_, id.luminosityBlock(), id.event());
01630     }
01631     if(RunID(id.run()) < RunID::firstValidRun()) {
01632       id = EventID(RunID::firstValidRun().run(), LuminosityBlockID::firstValidLuminosityBlock().luminosityBlock(), id.event());
01633     }
01634   }
01635 
01636 
01637   void
01638   RootFile::readEventHistoryTree() {
01639     // Read in the event history tree, if we have one...
01640     if(fileFormatVersion().eventHistoryTree()) {
01641       history_.reset(new History);
01642       eventHistoryTree_ = dynamic_cast<TTree*>(filePtr_->Get(poolNames::eventHistoryTreeName().c_str()));
01643       if(!eventHistoryTree_) {
01644         throw Exception(errors::EventCorruption)
01645           << "Failed to find the event history tree.\n";
01646       }
01647     }
01648   }
01649 
01650   void
01651   RootFile::checkReleaseVersion() {
01652     std::string releaseVersion = getReleaseVersion();
01653     releaseversion::DecomposedReleaseVersion currentRelease(releaseVersion);
01654     for(ProcessConfigurationVector::const_iterator it = processConfigurations_.begin(), itEnd = processConfigurations_.end();
01655         it != itEnd; ++it) {
01656       if(releaseversion::isEarlierRelease(currentRelease, it->releaseVersion())) {
01657         throw Exception(errors::FormatIncompatibility)
01658           << "The release you are using, " << getReleaseVersion() << " , predates\n"
01659           << "a release (" << it->releaseVersion() << ") used in writing the input file, " << file() <<".\n"
01660           << "Forward compatibility cannot be supported.\n";
01661       }
01662     }
01663   }
01664 
01665   void
01666   RootFile::initializeDuplicateChecker(
01667     std::vector<boost::shared_ptr<IndexIntoFile> > const& indexesIntoFiles,
01668     std::vector<boost::shared_ptr<IndexIntoFile> >::size_type currentIndexIntoFile) {
01669     if(duplicateChecker_) {
01670       if(eventTree_.next()) {
01671         fillThisEventAuxiliary();
01672         duplicateChecker_->inputFileOpened(eventAux().isRealData(),
01673                                            indexIntoFile_,
01674                                            indexesIntoFiles,
01675                                            currentIndexIntoFile);
01676       }
01677       eventTree_.setEntryNumber(-1);
01678     }
01679   }
01680 
01681   void
01682   RootFile::dropOnInput (ProductRegistry& reg, GroupSelectorRules const& rules, bool dropDescendants, InputType::InputType inputType) {
01683     // This is the selector for drop on input.
01684     GroupSelector groupSelector;
01685     groupSelector.initialize(rules, reg.allBranchDescriptions());
01686 
01687     ProductRegistry::ProductList& prodList = reg.productListUpdator();
01688     // Do drop on input. On the first pass, just fill in a set of branches to be dropped.
01689     std::set<BranchID> branchesToDrop;
01690     for(ProductRegistry::ProductList::const_iterator it = prodList.begin(), itEnd = prodList.end();
01691         it != itEnd; ++it) {
01692       BranchDescription const& prod = it->second;
01693       if(!groupSelector.selected(prod)) {
01694         if(dropDescendants) {
01695           branchChildren_->appendToDescendants(prod.branchID(), branchesToDrop);
01696         } else {
01697           branchesToDrop.insert(prod.branchID());
01698         }
01699       }
01700     }
01701 
01702     // On this pass, actually drop the branches.
01703     std::set<BranchID>::const_iterator branchesToDropEnd = branchesToDrop.end();
01704     for(ProductRegistry::ProductList::iterator it = prodList.begin(), itEnd = prodList.end(); it != itEnd;) {
01705       BranchDescription const& prod = it->second;
01706       bool drop = branchesToDrop.find(prod.branchID()) != branchesToDropEnd;
01707       if(drop) {
01708         if(groupSelector.selected(prod)) {
01709           LogWarning("RootFile")
01710             << "Branch '" << prod.branchName() << "' is being dropped from the input\n"
01711             << "of file '" << file_ << "' because it is dependent on a branch\n"
01712             << "that was explicitly dropped.\n";
01713         }
01714         treePointers_[prod.branchType()]->dropBranch(newBranchToOldBranch(prod.branchName()));
01715         hasNewlyDroppedBranch_[prod.branchType()] = true;
01716         ProductRegistry::ProductList::iterator icopy = it;
01717         ++it;
01718         prodList.erase(icopy);
01719       } else {
01720         ++it;
01721       }
01722     }
01723 
01724     // Drop on input mergeable run and lumi products, this needs to be invoked for secondary file input
01725     if(inputType == InputType::SecondaryFile) {
01726       TString tString;
01727       for(ProductRegistry::ProductList::iterator it = prodList.begin(), itEnd = prodList.end(); it != itEnd;) {
01728         BranchDescription const& prod = it->second;
01729         if(prod.branchType() != InEvent) {
01730           TClass *cp = gROOT->GetClass(prod.wrappedName().c_str());
01731           WrapperOwningHolder edp(cp->New(), prod.getInterface());
01732           if(edp.isMergeable()) {
01733             treePointers_[prod.branchType()]->dropBranch(newBranchToOldBranch(prod.branchName()));
01734             ProductRegistry::ProductList::iterator icopy = it;
01735             ++it;
01736             prodList.erase(icopy);
01737           } else {
01738             ++it;
01739           }
01740         }
01741         else ++it;
01742       }
01743     }
01744   }
01745 
01746   std::unique_ptr<MakeProvenanceReader>
01747   RootFile::makeProvenanceReaderMaker() const {
01748     if(fileFormatVersion_.storedProductProvenanceUsed()) {
01749       return std::unique_ptr<MakeProvenanceReader>(new MakeReducedProvenanceReader(parentageIDLookup_));
01750     } else if(fileFormatVersion_.splitProductIDs()) {
01751       return std::unique_ptr<MakeProvenanceReader>(new MakeFullProvenanceReader);
01752     } else if(fileFormatVersion_.perEventProductIDs()) {
01753       return std::unique_ptr<MakeProvenanceReader>(new MakeOldProvenanceReader);
01754     } else {
01755       return std::unique_ptr<MakeProvenanceReader>(new MakeDummyProvenanceReader);
01756     }
01757   }
01758 
01759   boost::shared_ptr<BranchMapper>
01760   RootFile::makeBranchMapper() {
01761     if(!eventBranchMapper_) {
01762       eventBranchMapper_.reset(new BranchMapper(provenanceReaderMaker_->makeReader(eventTree_, daqProvenanceHelper_.get())));
01763     }
01764     eventBranchMapper_->reset();
01765     return eventBranchMapper_;
01766   }
01767 
01768   class ReducedProvenanceReader : public ProvenanceReaderBase {
01769   public:
01770     ReducedProvenanceReader(RootTree* iRootTree, std::vector<ParentageID> const& iParentageIDLookup, DaqProvenanceHelper const* daqProvenanceHelper);
01771   private:
01772     virtual void readProvenance(BranchMapper const& mapper) const;
01773     RootTree* rootTree_;
01774     TBranch* provBranch_;
01775     StoredProductProvenanceVector provVector_;
01776     StoredProductProvenanceVector* pProvVector_;
01777     std::vector<ParentageID> const& parentageIDLookup_;
01778     DaqProvenanceHelper const* daqProvenanceHelper_;
01779   };
01780 
01781   ReducedProvenanceReader::ReducedProvenanceReader(
01782                                               RootTree* iRootTree,
01783                                               std::vector<ParentageID> const& iParentageIDLookup,
01784                                               DaqProvenanceHelper const* daqProvenanceHelper) :
01785       ProvenanceReaderBase(),
01786       rootTree_(iRootTree),
01787       pProvVector_(&provVector_),
01788       parentageIDLookup_(iParentageIDLookup),
01789       daqProvenanceHelper_(daqProvenanceHelper) {
01790     provBranch_ = rootTree_->tree()->GetBranch(BranchTypeToProductProvenanceBranchName(rootTree_->branchType()).c_str());
01791   }
01792 
01793   void
01794   ReducedProvenanceReader::readProvenance(BranchMapper const& mapper) const {
01795     ReducedProvenanceReader* me = const_cast<ReducedProvenanceReader*>(this);
01796     me->rootTree_->fillBranchEntry(me->provBranch_, me->pProvVector_);
01797     setRefCoreStreamer(true);
01798     if(daqProvenanceHelper_) {
01799       for(StoredProductProvenanceVector::const_iterator it = provVector_.begin(), itEnd = provVector_.end();
01800            it != itEnd; ++it) {
01801         BranchID bid(it->branchID_);
01802         mapper.insertIntoSet(ProductProvenance(daqProvenanceHelper_->mapBranchID(BranchID(it->branchID_)),
01803                                                daqProvenanceHelper_->mapParentageID(parentageIDLookup_[it->parentageIDIndex_])));
01804       }
01805     } else {
01806       for(StoredProductProvenanceVector::const_iterator it = provVector_.begin(), itEnd = provVector_.end();
01807            it != itEnd; ++it) {
01808         if(it->parentageIDIndex_ >= parentageIDLookup_.size()) {
01809           throw edm::Exception(errors::LogicError)
01810             << "ReducedProvenanceReader::ReadProvenance\n"
01811             << "The parentage ID index value " << it->parentageIDIndex_ << " is out of bounds.  The maximum value is " << parentageIDLookup_.size()-1 << ".\n"
01812             << "This should never happen.\n"
01813             << "Please report this to the framework hypernews forum 'hn-cms-edmFramework@cern.ch'.\n";
01814         }
01815         mapper.insertIntoSet(ProductProvenance(BranchID(it->branchID_), parentageIDLookup_[it->parentageIDIndex_]));
01816       }
01817     }
01818   }
01819 
01820   class FullProvenanceReader : public ProvenanceReaderBase {
01821   public:
01822     explicit FullProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper);
01823     virtual ~FullProvenanceReader() {}
01824   private:
01825     virtual void readProvenance(BranchMapper const& mapper) const;
01826     RootTree* rootTree_;
01827     ProductProvenanceVector infoVector_;
01828     mutable ProductProvenanceVector* pInfoVector_;
01829     DaqProvenanceHelper const* daqProvenanceHelper_;
01830   };
01831 
01832   FullProvenanceReader::FullProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper) :
01833          ProvenanceReaderBase(),
01834          rootTree_(rootTree),
01835          infoVector_(),
01836          pInfoVector_(&infoVector_),
01837          daqProvenanceHelper_(daqProvenanceHelper) {
01838   }
01839 
01840   void
01841   FullProvenanceReader::readProvenance(BranchMapper const& mapper) const {
01842     rootTree_->fillBranchEntryMeta(rootTree_->branchEntryInfoBranch(), pInfoVector_);
01843     setRefCoreStreamer(true);
01844     if(daqProvenanceHelper_) {
01845       for(ProductProvenanceVector::const_iterator it = infoVector_.begin(), itEnd = infoVector_.end();
01846           it != itEnd; ++it) {
01847         mapper.insertIntoSet(ProductProvenance(daqProvenanceHelper_->mapBranchID(it->branchID()),
01848                                                daqProvenanceHelper_->mapParentageID(it->parentageID())));
01849       }
01850     } else {
01851       for(ProductProvenanceVector::const_iterator it = infoVector_.begin(), itEnd = infoVector_.end();
01852           it != itEnd; ++it) {
01853         mapper.insertIntoSet(*it);
01854       }
01855     }
01856   }
01857 
01858   class OldProvenanceReader : public ProvenanceReaderBase {
01859   public:
01860     explicit OldProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper);
01861     virtual ~OldProvenanceReader() {}
01862   private:
01863     virtual void readProvenance(BranchMapper const& mapper) const;
01864     RootTree* rootTree_;
01865     std::vector<EventEntryInfo> infoVector_;
01866     mutable std::vector<EventEntryInfo> *pInfoVector_;
01867     DaqProvenanceHelper const* daqProvenanceHelper_;
01868   };
01869 
01870   OldProvenanceReader::OldProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper) :
01871          ProvenanceReaderBase(),
01872          rootTree_(rootTree),
01873          infoVector_(),
01874          pInfoVector_(&infoVector_),
01875          daqProvenanceHelper_(daqProvenanceHelper) {
01876   }
01877 
01878   void
01879   OldProvenanceReader::readProvenance(BranchMapper const& mapper) const {
01880     rootTree_->branchEntryInfoBranch()->SetAddress(&pInfoVector_);
01881     roottree::getEntry(rootTree_->branchEntryInfoBranch(), rootTree_->entryNumber());
01882     setRefCoreStreamer(true);
01883     for(std::vector<EventEntryInfo>::const_iterator it = infoVector_.begin(), itEnd = infoVector_.end();
01884         it != itEnd; ++it) {
01885       EventEntryDescription eed;
01886       EntryDescriptionRegistry::instance()->getMapped(it->entryDescriptionID(), eed);
01887       Parentage parentage(eed.parents());
01888       if(daqProvenanceHelper_) {
01889         ProductProvenance entry(daqProvenanceHelper_->mapBranchID(it->branchID()),
01890                                 daqProvenanceHelper_->mapParentageID(parentage.id()));
01891         mapper.insertIntoSet(entry);
01892       } else {
01893         ProductProvenance entry(it->branchID(), parentage.id());
01894         mapper.insertIntoSet(entry);
01895       }
01896     
01897     }
01898   }
01899 
01900   class DummyProvenanceReader : public ProvenanceReaderBase {
01901   public:
01902     DummyProvenanceReader();
01903     virtual ~DummyProvenanceReader() {}
01904   private:
01905     virtual void readProvenance(BranchMapper const& mapper) const;
01906   };
01907 
01908   DummyProvenanceReader::DummyProvenanceReader() :
01909       ProvenanceReaderBase() {
01910   }
01911 
01912   void
01913   DummyProvenanceReader::readProvenance(BranchMapper const&) const {
01914     // Not providing parentage!!!
01915   }
01916 
01917   std::unique_ptr<ProvenanceReaderBase>
01918   MakeDummyProvenanceReader::makeReader(RootTree&, DaqProvenanceHelper const*) const {
01919      return std::unique_ptr<ProvenanceReaderBase>(new DummyProvenanceReader);
01920   }
01921 
01922   std::unique_ptr<ProvenanceReaderBase>
01923   MakeOldProvenanceReader::makeReader(RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
01924     return std::unique_ptr<ProvenanceReaderBase>(new OldProvenanceReader(&rootTree, daqProvenanceHelper));
01925   }
01926 
01927   std::unique_ptr<ProvenanceReaderBase>
01928   MakeFullProvenanceReader::makeReader(RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
01929     return std::unique_ptr<ProvenanceReaderBase>(new FullProvenanceReader(&rootTree, daqProvenanceHelper));
01930   }
01931 
01932   std::unique_ptr<ProvenanceReaderBase>
01933   MakeReducedProvenanceReader::makeReader(RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
01934     return std::unique_ptr<ProvenanceReaderBase>(new ReducedProvenanceReader(&rootTree, parentageIDLookup_, daqProvenanceHelper));
01935   }
01936 }