CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch13/src/IOPool/Output/src/RootOutputTree.cc

Go to the documentation of this file.
00001 
00002 #include "RootOutputTree.h"
00003 
00004 #include "TFile.h"
00005 #include "TBranch.h"
00006 #include "TBranchElement.h"
00007 #include "TTreeCloner.h"
00008 #include "TCollection.h"
00009 #include "Rtypes.h"
00010 #include "RVersion.h"
00011 
00012 #include "DataFormats/Common/interface/RefCoreStreamer.h"
00013 #include "DataFormats/Provenance/interface/BranchDescription.h"
00014 #include "FWCore/Framework/interface/ConstProductRegistry.h"
00015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00016 #include "FWCore/ServiceRegistry/interface/Service.h"
00017 #include "FWCore/Utilities/interface/Algorithms.h"
00018 #include "FWCore/Utilities/interface/EDMException.h"
00019 
00020 #include "boost/bind.hpp"
00021 #include <limits>
00022 
00023 namespace edm {
00024 
00025     RootOutputTree::RootOutputTree(
00026                    boost::shared_ptr<TFile> filePtr,
00027                    BranchType const& branchType,
00028                    int bufSize,
00029                    int splitLevel,
00030                    int treeMaxVirtualSize) :
00031       filePtr_(filePtr),
00032       tree_(makeTTree(filePtr.get(), BranchTypeToProductTreeName(branchType), splitLevel)),
00033       producedBranches_(),
00034       readBranches_(),
00035       auxBranches_(),
00036       unclonedReadBranches_(),
00037       unclonedReadBranchNames_(),
00038       currentlyFastCloning_(),
00039       fastCloneAuxBranches_(false) {
00040 
00041     if(treeMaxVirtualSize >= 0) tree_->SetMaxVirtualSize(treeMaxVirtualSize);
00042   }
00043 
00044   TTree*
00045   RootOutputTree::assignTTree(TFile* filePtr, TTree* tree) {
00046     tree->SetDirectory(filePtr);
00047     // Turn off autosaving because it is such a memory hog and we are not using
00048     // this check-pointing feature anyway.
00049     tree->SetAutoSave(std::numeric_limits<Long64_t>::max());
00050     return tree;
00051   }
00052 
00053   TTree*
00054   RootOutputTree::makeTTree(TFile* filePtr, std::string const& name, int splitLevel) {
00055     TTree* tree = new TTree(name.c_str(), "", splitLevel);
00056     if(!tree) throw edm::Exception(errors::FatalRootError)
00057       << "Failed to create the tree: " << name << "\n";
00058     if(tree->IsZombie())
00059       throw edm::Exception(errors::FatalRootError)
00060         << "Tree: " << name << " is a zombie." << "\n";
00061 
00062     return assignTTree(filePtr, tree);
00063   }
00064 
00065   bool
00066   RootOutputTree::checkSplitLevelsAndBasketSizes(TTree* inputTree) const {
00067 
00068     assert (inputTree != 0);
00069 
00070     // Do the split level and basket size match in the input and output?
00071     for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
00072       it != itEnd; ++it) {
00073 
00074       TBranch* outputBranch = *it;
00075       if(outputBranch != 0) {
00076         TBranch* inputBranch = inputTree->GetBranch(outputBranch->GetName());
00077 
00078         if(inputBranch != 0) {
00079           if(inputBranch->GetSplitLevel() != outputBranch->GetSplitLevel() ||
00080               inputBranch->GetBasketSize() != outputBranch->GetBasketSize()) {
00081             return false;
00082           }
00083         }
00084       }
00085     }
00086     return true;
00087   }
00088 
00089   namespace {
00090     bool checkMatchingBranches(TBranchElement* inputBranch, TBranchElement* outputBranch) {
00091       if(inputBranch->GetStreamerType() != outputBranch->GetStreamerType()) {
00092         return false;
00093       }
00094       TObjArray* inputArray = inputBranch->GetListOfBranches();
00095       TObjArray* outputArray = outputBranch->GetListOfBranches();
00096 
00097       if(outputArray->GetSize() < inputArray->GetSize()) {
00098         return false;
00099       }
00100       TIter iter(outputArray);
00101       TObject* obj = 0;
00102       while((obj = iter.Next()) != 0) {
00103         TBranchElement* outBranch = dynamic_cast<TBranchElement*>(obj);
00104         if(outBranch) {
00105           TBranchElement* inBranch = dynamic_cast<TBranchElement*>(inputArray->FindObject(outBranch->GetName()));
00106           if(!inBranch) {
00107             return false;
00108           }
00109           if(!checkMatchingBranches(inBranch, outBranch)) {
00110             return false;
00111           }
00112         }
00113       }
00114       return true;
00115     }
00116   }
00117 
00118   bool RootOutputTree::checkIfFastClonable(TTree* inputTree) const {
00119 
00120     if(inputTree == 0) return false;
00121 
00122     // Do the sub-branches match in the input and output.  Extra sub-branches in the input are OK for fast cloning, but not in the output.
00123     for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end(); it != itEnd; ++it) {
00124       TBranchElement* outputBranch = dynamic_cast<TBranchElement*>(*it);
00125       if(outputBranch != 0) {
00126         TBranchElement* inputBranch = dynamic_cast<TBranchElement*>(inputTree->GetBranch(outputBranch->GetName()));
00127         if(inputBranch != 0) {
00128           // We have a matching top level branch. Do the recursive check on subbranches.
00129           if(!checkMatchingBranches(inputBranch, outputBranch)) {
00130             LogInfo("FastCloning")
00131               << "Fast Cloning disabled because a data member has been added to  split branch: " << inputBranch->GetName() << "\n.";
00132           }
00133         }
00134       }
00135     }
00136     return true;
00137   }
00138 
00139   void
00140   RootOutputTree::fastCloneTTree(TTree* in, std::string const& option) {
00141     if(in->GetEntries() != 0) {
00142       TObjArray* branches = tree_->GetListOfBranches();
00143       // If any products were produced (not just event products), the EventAuxiliary will be modified.
00144       // In that case,  don't fast copy auxiliary branches. Remove them, and add back after fast copying.
00145       std::map<Int_t, TBranch *> auxIndexes;
00146       if (!fastCloneAuxBranches_) {
00147         for (std::vector<TBranch *>::const_iterator it = auxBranches_.begin(), itEnd = auxBranches_.end();
00148              it != itEnd; ++it) {
00149           int auxIndex = branches->IndexOf(*it);
00150           assert (auxIndex >= 0);
00151           auxIndexes.insert(std::make_pair(auxIndex, *it));
00152           branches->RemoveAt(auxIndex);
00153         }
00154         branches->Compress();
00155       }
00156 
00157 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,26,0)
00158       TTreeCloner cloner(in, tree_, option.c_str(), TTreeCloner::kNoWarnings|TTreeCloner::kIgnoreMissingTopLevel);
00159 #else
00160       TTreeCloner cloner(in, tree_, option.c_str());
00161 #endif
00162 
00163       if(!cloner.IsValid()) {
00164 
00165 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,26,0)
00166         // Let's check why
00167         static const char* okerror  = "One of the export branch";
00168         if (  strncmp(cloner.GetWarning(),okerror,strlen(okerror)) == 0 ) {
00169           // That's fine we will handle it;
00170         }
00171         else {
00172           throw edm::Exception(errors::FatalRootError)
00173             << "invalid TTreeCloner\n";
00174         }
00175 #else
00176         throw edm::Exception(errors::FatalRootError)
00177           << "invalid TTreeCloner\n";
00178 #endif
00179       }
00180       tree_->SetEntries(tree_->GetEntries() + in->GetEntries());
00181       cloner.Exec();
00182       if (!fastCloneAuxBranches_) {
00183         for (std::map<Int_t, TBranch *>::const_iterator it = auxIndexes.begin(), itEnd = auxIndexes.end();
00184              it != itEnd; ++it) {
00185           // Add the auxiliary branches back after fast copying the rest of the tree.
00186           Int_t last = branches->GetLast();
00187           if (last >= 0) {
00188             branches->AddAtAndExpand(branches->At(last), last+1);
00189             for(Int_t ind = last-1; ind >= it->first; --ind) {
00190               branches->AddAt(branches->At(ind), ind+1);
00191             };
00192             branches->AddAt(it->second, it->first);
00193           } else {
00194             branches->Add(it->second);
00195           }
00196         }
00197       }
00198     }
00199   }
00200 
00201   void
00202   RootOutputTree::writeTTree(TTree* tree) {
00203     if(tree->GetNbranches() != 0) {
00204       tree->SetEntries(-1);
00205     }
00206     setRefCoreStreamer(true);
00207     tree->AutoSave("FlushBaskets");
00208   }
00209 
00210   void
00211   RootOutputTree::fillTTree(TTree* tree, std::vector<TBranch*> const& branches) {
00212     for_all(branches, boost::bind(&TBranch::Fill, _1));
00213   }
00214 
00215   void
00216   RootOutputTree::writeTree() const {
00217     writeTTree(tree_);
00218   }
00219 
00220   void
00221   RootOutputTree::maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree* tree, std::string const& option) {
00222     unclonedReadBranches_.clear();
00223     unclonedReadBranchNames_.clear();
00224     currentlyFastCloning_ = canFastClone && !readBranches_.empty();
00225     if(currentlyFastCloning_) {
00226       fastCloneAuxBranches_ = canFastCloneAux;
00227       fastCloneTTree(tree, option);
00228       for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
00229           it != itEnd; ++it) {
00230         if((*it)->GetEntries() != tree_->GetEntries()) {
00231           unclonedReadBranches_.push_back(*it);
00232           unclonedReadBranchNames_.insert(std::string((*it)->GetName()));
00233         }
00234       }
00235     }
00236   }
00237 
00238   void
00239   RootOutputTree::fillTree() const {
00240     if (currentlyFastCloning_) {
00241       if (!fastCloneAuxBranches_)fillTTree(tree_, auxBranches_);
00242       fillTTree(tree_, producedBranches_);
00243       fillTTree(tree_, unclonedReadBranches_);
00244     } else {
00245       tree_->Fill();
00246     }
00247   }
00248 
00249   void
00250   RootOutputTree::addBranch(std::string const& branchName,
00251                             std::string const& className,
00252                             void const*& pProd,
00253                             int splitLevel,
00254                             int basketSize,
00255                             bool produced) {
00256       assert(splitLevel != BranchDescription::invalidSplitLevel);
00257       assert(basketSize != BranchDescription::invalidBasketSize);
00258       TBranch* branch = tree_->Branch(branchName.c_str(),
00259                  className.c_str(),
00260                  &pProd,
00261                  basketSize,
00262                  splitLevel);
00263       if(produced) {
00264         producedBranches_.push_back(branch);
00265       } else {
00266         readBranches_.push_back(branch);
00267       }
00268   }
00269 
00270   void
00271   RootOutputTree::close() {
00272     // The TFile was just closed.
00273     // Just to play it safe, zero all pointers to quantities in the file.
00274     auxBranches_.clear();
00275     producedBranches_.clear();
00276     readBranches_.clear();
00277     unclonedReadBranches_.clear();
00278     tree_ = 0;
00279     filePtr_.reset();
00280   }
00281 }