CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
RootOutputTree.cc
Go to the documentation of this file.
1 
2 #include "RootOutputTree.h"
3 
13 
14 #include "TBranch.h"
15 #include "TBranchElement.h"
16 #include "TCollection.h"
17 #include "TFile.h"
18 #include "TTreeCloner.h"
19 #include "Rtypes.h"
20 #include "RVersion.h"
21 
22 #include "boost/bind.hpp"
23 #include <limits>
24 
25 namespace edm {
26 
28  boost::shared_ptr<TFile> filePtr,
29  BranchType const& branchType,
30  int splitLevel,
31  int treeMaxVirtualSize) :
32  filePtr_(filePtr),
33  tree_(makeTTree(filePtr.get(), BranchTypeToProductTreeName(branchType), splitLevel)),
34  producedBranches_(),
35  readBranches_(),
36  auxBranches_(),
37  unclonedReadBranches_(),
38  clonedReadBranchNames_(),
39  currentlyFastCloning_(),
40  fastCloneAuxBranches_(false) {
41 
42  if(treeMaxVirtualSize >= 0) tree_->SetMaxVirtualSize(treeMaxVirtualSize);
43  }
44 
45  TTree*
46  RootOutputTree::assignTTree(TFile* filePtr, TTree* tree) {
47  tree->SetDirectory(filePtr);
48  // Turn off autosaving because it is such a memory hog and we are not using
49  // this check-pointing feature anyway.
50  tree->SetAutoSave(std::numeric_limits<Long64_t>::max());
51  return tree;
52  }
53 
54  TTree*
55  RootOutputTree::makeTTree(TFile* filePtr, std::string const& name, int splitLevel) {
56  TTree* tree = new TTree(name.c_str(), "", splitLevel);
57  if(!tree) throw edm::Exception(errors::FatalRootError)
58  << "Failed to create the tree: " << name << "\n";
59  if(tree->IsZombie())
61  << "Tree: " << name << " is a zombie." << "\n";
62 
63  return assignTTree(filePtr, tree);
64  }
65 
66  bool
68 
69  assert (inputTree != 0);
70 
71  // Do the split level and basket size match in the input and output?
72  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
73  it != itEnd; ++it) {
74 
75  TBranch* outputBranch = *it;
76  if(outputBranch != 0) {
77  TBranch* inputBranch = inputTree->GetBranch(outputBranch->GetName());
78 
79  if(inputBranch != 0) {
80  if(inputBranch->GetSplitLevel() != outputBranch->GetSplitLevel() ||
81  inputBranch->GetBasketSize() != outputBranch->GetBasketSize()) {
82  return false;
83  }
84  }
85  }
86  }
87  return true;
88  }
89 
90  namespace {
91  bool checkMatchingBranches(TBranchElement* inputBranch, TBranchElement* outputBranch) {
92  if(inputBranch->GetStreamerType() != outputBranch->GetStreamerType()) {
93  return false;
94  }
95  TObjArray* inputArray = inputBranch->GetListOfBranches();
96  TObjArray* outputArray = outputBranch->GetListOfBranches();
97 
98  if(outputArray->GetSize() < inputArray->GetSize()) {
99  return false;
100  }
101  TIter iter(outputArray);
102  TObject* obj = 0;
103  while((obj = iter.Next()) != 0) {
104  TBranchElement* outBranch = dynamic_cast<TBranchElement*>(obj);
105  if(outBranch) {
106  TBranchElement* inBranch = dynamic_cast<TBranchElement*>(inputArray->FindObject(outBranch->GetName()));
107  if(!inBranch) {
108  return false;
109  }
110  if(!checkMatchingBranches(inBranch, outBranch)) {
111  return false;
112  }
113  }
114  }
115  return true;
116  }
117  }
118 
119  bool RootOutputTree::checkIfFastClonable(TTree* inputTree) const {
120 
121  if(inputTree == 0) return false;
122 
123  // 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.
124  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end(); it != itEnd; ++it) {
125  TBranchElement* outputBranch = dynamic_cast<TBranchElement*>(*it);
126  if(outputBranch != 0) {
127  TBranchElement* inputBranch = dynamic_cast<TBranchElement*>(inputTree->GetBranch(outputBranch->GetName()));
128  if(inputBranch != 0) {
129  // We have a matching top level branch. Do the recursive check on subbranches.
130  if(!checkMatchingBranches(inputBranch, outputBranch)) {
131  LogInfo("FastCloning")
132  << "Fast Cloning disabled because a data member has been added to split branch: " << inputBranch->GetName() << "\n.";
133  return false;
134  }
135  }
136  }
137  }
138  return true;
139  }
140 
141  bool RootOutputTree::checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const {
142  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end(); it != itEnd; ++it) {
143  if((*it)->GetEntries() != expectedNumberOfEntries) {
144  return false;
145  }
146  }
147  return true;
148  }
149 
150  void
151  RootOutputTree::fastCloneTTree(TTree* in, std::string const& option) {
152  if(in->GetEntries() != 0) {
153  TObjArray* branches = tree_->GetListOfBranches();
154  // If any products were produced (not just event products), the EventAuxiliary will be modified.
155  // In that case, don't fast copy auxiliary branches. Remove them, and add back after fast copying.
156  std::map<Int_t, TBranch *> auxIndexes;
157  bool mustRemoveSomeAuxs = false;
158  if(!fastCloneAuxBranches_) {
159  for(std::vector<TBranch *>::const_iterator it = auxBranches_.begin(), itEnd = auxBranches_.end();
160  it != itEnd; ++it) {
161  int auxIndex = branches->IndexOf(*it);
162  assert (auxIndex >= 0);
163  auxIndexes.insert(std::make_pair(auxIndex, *it));
164  branches->RemoveAt(auxIndex);
165  }
166  mustRemoveSomeAuxs = true;
167  }
168 
169  //Deal with any aux branches which can never be cloned
170  for(std::vector<TBranch *>::const_iterator it = unclonedAuxBranches_.begin(),
171  itEnd = unclonedAuxBranches_.end();
172  it != itEnd; ++it) {
173  int auxIndex = branches->IndexOf(*it);
174  assert (auxIndex >= 0);
175  auxIndexes.insert(std::make_pair(auxIndex, *it));
176  branches->RemoveAt(auxIndex);
177  mustRemoveSomeAuxs = true;
178  }
179 
180  if(mustRemoveSomeAuxs) {
181  branches->Compress();
182  }
183 
184  TTreeCloner cloner(in, tree_, option.c_str(), TTreeCloner::kNoWarnings|TTreeCloner::kIgnoreMissingTopLevel);
185 
186  if(!cloner.IsValid()) {
187  // Let's check why
188  static const char* okerror = "One of the export branch";
189  if(strncmp(cloner.GetWarning(), okerror, strlen(okerror)) == 0) {
190  // That's fine we will handle it;
191  } else {
193  << "invalid TTreeCloner (" << cloner.GetWarning() << ")\n";
194  }
195  }
196  tree_->SetEntries(tree_->GetEntries() + in->GetEntries());
197  Service<RootHandlers> rootHandler;
198  rootHandler->enableErrorHandlerWithoutWarnings();
199  cloner.Exec();
200  rootHandler->enableErrorHandler();
201  if(mustRemoveSomeAuxs) {
202  for(std::map<Int_t, TBranch *>::const_iterator it = auxIndexes.begin(), itEnd = auxIndexes.end();
203  it != itEnd; ++it) {
204  // Add the auxiliary branches back after fast copying the rest of the tree.
205  Int_t last = branches->GetLast();
206  if(last >= 0) {
207  branches->AddAtAndExpand(branches->At(last), last+1);
208  for(Int_t ind = last-1; ind >= it->first; --ind) {
209  branches->AddAt(branches->At(ind), ind+1);
210  };
211  branches->AddAt(it->second, it->first);
212  } else {
213  branches->Add(it->second);
214  }
215  }
216  }
217  }
218  }
219 
220  void
222  if(tree->GetNbranches() != 0) {
223  tree->SetEntries(-1);
224  }
225  setRefCoreStreamer(true);
226  tree->AutoSave("FlushBaskets");
227  }
228 
229  void
230  RootOutputTree::fillTTree(std::vector<TBranch*> const& branches) {
231  for_all(branches, boost::bind(&TBranch::Fill, _1));
232  }
233 
234  void
236  writeTTree(tree_);
237  }
238 
239  void
240  RootOutputTree::maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree* tree, std::string const& option) {
241  unclonedReadBranches_.clear();
242  clonedReadBranchNames_.clear();
243  currentlyFastCloning_ = canFastClone && !readBranches_.empty();
245  fastCloneAuxBranches_ = canFastCloneAux;
246  fastCloneTTree(tree, option);
247  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
248  it != itEnd; ++it) {
249  if((*it)->GetEntries() == tree_->GetEntries()) {
250  clonedReadBranchNames_.insert(std::string((*it)->GetName()));
251  } else {
252  unclonedReadBranches_.push_back(*it);
253  }
254  }
255  Service<JobReport> reportSvc;
256  reportSvc->reportFastClonedBranches(clonedReadBranchNames_, tree_->GetEntries());
257  }
258  }
259 
260  void
267  } else {
268  tree_->Fill();
269  }
270  }
271 
272  void
273  RootOutputTree::addBranch(std::string const& branchName,
274  std::string const& className,
275  WrapperInterfaceBase const* interface,
276  void const*& pProd,
277  int splitLevel,
278  int basketSize,
279  bool produced) {
280  assert(splitLevel != BranchDescription::invalidSplitLevel);
281  assert(basketSize != BranchDescription::invalidBasketSize);
282  TBranch* branch = tree_->Branch(branchName.c_str(),
283  className.c_str(),
284  &pProd,
285  basketSize,
286  splitLevel);
287  assert(branch != 0);
288  if(pProd != 0) {
289  // Delete the product that ROOT has allocated.
290  interface->deleteProduct(pProd);
291  pProd = 0;
292  }
293  if(produced) {
294  producedBranches_.push_back(branch);
295  } else {
296  readBranches_.push_back(branch);
297  }
298  }
299 
300  void
302  // The TFile was just closed.
303  // Just to play it safe, zero all pointers to quantities in the file.
304  auxBranches_.clear();
305  unclonedAuxBranches_.clear();
306  producedBranches_.clear();
307  readBranches_.clear();
308  unclonedReadBranches_.clear();
309  tree_ = 0;
310  filePtr_.reset();
311  }
312 }
std::set< std::string > clonedReadBranchNames_
void writeTree() const
static int const invalidSplitLevel
void fillTree() const
static int const invalidBasketSize
static void fillTTree(std::vector< TBranch * > const &branches)
bool checkSplitLevelsAndBasketSizes(TTree *inputTree) const
void setRefCoreStreamer(bool resetAll=false)
std::vector< TBranch * > unclonedAuxBranches_
bool checkIfFastClonable(TTree *inputTree) const
void addBranch(std::string const &branchName, std::string const &className, WrapperInterfaceBase const *interface, void const *&pProd, int splitLevel, int basketSize, bool produced)
BranchType
Definition: BranchType.h:11
std::vector< TBranch * > producedBranches_
std::vector< TBranch * > auxBranches_
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
Definition: Algorithms.h:16
boost::shared_ptr< TFile > filePtr_
static TTree * assignTTree(TFile *file, TTree *tree)
const T & max(const T &a, const T &b)
void Fill(HcalDetId &id, double val, std::vector< TH2F > &depth)
std::vector< TBranch * > unclonedReadBranches_
bool checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const
std::string const & BranchTypeToProductTreeName(BranchType const &branchType)
Definition: BranchType.cc:102
static TTree * makeTTree(TFile *filePtr, std::string const &name, int splitLevel)
void deleteProduct(void const *me) const
eventsetup::produce::Produce produced
Definition: ESProducts.cc:21
RootOutputTree(boost::shared_ptr< TFile > filePtr, BranchType const &branchType, int splitLevel, int treeMaxVirtualSize)
static void writeTTree(TTree *tree)
std::vector< TBranch * > readBranches_
TTree * tree() const
void maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree *tree, std::string const &option)
T get(const Candidate &c)
Definition: component.h:56
std::string className(const T &t)
Definition: ClassName.h:30
void fastCloneTTree(TTree *in, std::string const &option)