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
00048
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
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
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
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
00144
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
00167 static const char* okerror = "One of the export branch";
00168 if ( strncmp(cloner.GetWarning(),okerror,strlen(okerror)) == 0 ) {
00169
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
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
00273
00274 auxBranches_.clear();
00275 producedBranches_.clear();
00276 readBranches_.clear();
00277 unclonedReadBranches_.clear();
00278 tree_ = 0;
00279 filePtr_.reset();
00280 }
00281 }