Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TChainIndex.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Marek Biskup 07/06/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TChainIndex
13 A Chain Index.
14 A Chain Index with majorname and minorname.
15 It uses tree indices of all the trees in the chain instead of building
16 a new index.
17 The index values from the first tree should be less then
18 all the index values from the second tree, and so on.
19 If a tree in the chain doesn't have an index the index will be created
20 and kept inside this chain index.
21 */
22 
23 #include "TChainIndex.h"
24 #include "TChain.h"
25 #include "TTreeFormula.h"
26 #include "TTreeIndex.h"
27 #include "TFile.h"
28 #include "TError.h"
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 /// \class TChainIndex::TChainIndexEntry
32 /// Holds a description of indices of trees in the chain.
33 
34 void TChainIndex::TChainIndexEntry::SetMinMaxFrom(const TTreeIndex *index )
35 {
36  fMinIndexValue = index->GetIndexValues()[0];
37  fMinIndexValMinor = index->GetIndexValuesMinor()[0];
38  fMaxIndexValue = index->GetIndexValues()[index->GetN() - 1];
39  fMaxIndexValMinor = index->GetIndexValuesMinor()[index->GetN() - 1];
40 }
41 
42 ClassImp(TChainIndex);
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 /// Default constructor for TChainIndex
46 
47 TChainIndex::TChainIndex(): TVirtualIndex()
48 {
49  fTree = 0;
50  fMajorFormulaParent = fMinorFormulaParent = 0;
51 }
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// Normal constructor for TChainIndex. See TTreeIndex::TTreeIndex for the description of the
55 /// parameters.
56 /// The tree must be a TChain.
57 /// All the index values in the first tree of the chain must be
58 /// less then any index value in the second one, and so on.
59 /// If any of those requirements isn't met the object becomes a zombie.
60 /// If some subtrees don't have indices the indices are created and stored inside this
61 /// TChainIndex.
62 
63 TChainIndex::TChainIndex(const TTree *T, const char *majorname, const char *minorname)
64  : TVirtualIndex()
65 {
66  fTree = 0;
67  fMajorFormulaParent = fMinorFormulaParent = 0;
68 
69  TChain *chain = dynamic_cast<TChain*>(const_cast<TTree*>(T));
70  if (!chain) {
71  MakeZombie();
72  Error("TChainIndex", "Cannot create a TChainIndex."
73  " The Tree passed as an argument is not a TChain");
74  return;
75  }
76 
77  fTree = (TTree*)T;
78  fMajorName = majorname;
79  fMinorName = minorname;
80  Int_t i = 0;
81 
82  // Go through all the trees and check if they have indeces. If not then build them.
83  for (i = 0; i < chain->GetNtrees(); i++) {
84  chain->LoadTree((chain->GetTreeOffset())[i]);
85  TVirtualIndex *index = chain->GetTree()->GetTreeIndex();
86 
87  TChainIndexEntry entry;
88  entry.fTreeIndex = 0;
89 
90  //if an index already exists, we must check if major/minorname correspond
91  //to the major/minor names in this function call
92  if (index) {
93  if (strcmp(majorname,index->GetMajorName()) || strcmp(minorname,index->GetMinorName())) {
94  MakeZombie();
95  Error("TChainIndex","Tree in file %s has an index built with majorname=%s and minorname=%s",chain->GetTree()->GetCurrentFile()->GetName(),index->GetMajorName(),index->GetMinorName());
96  return;
97  }
98  }
99  if (!index) {
100  chain->GetTree()->BuildIndex(majorname, minorname);
101  index = chain->GetTree()->GetTreeIndex();
102  chain->GetTree()->SetTreeIndex(0);
103  entry.fTreeIndex = index;
104  }
105  if (!index || index->IsZombie() || index->GetN() == 0) {
106  DeleteIndices();
107  MakeZombie();
108  Error("TChainIndex", "Error creating a tree index on a tree in the chain");
109  return;
110  }
111 
112  TTreeIndex *ti_index = dynamic_cast<TTreeIndex*>(index);
113  if (ti_index == 0) {
114  Error("TChainIndex", "The underlying TTree must have a TTreeIndex but has a %s.",
115  index->IsA()->GetName());
116  return;
117  }
118 
119  entry.SetMinMaxFrom(ti_index);
120  fEntries.push_back(entry);
121  }
122 
123  // Check if the indices of different trees are in order. If not then return an error.
124  for (i = 0; i < Int_t(fEntries.size() - 1); i++) {
125  if( fEntries[i].GetMaxIndexValPair() > fEntries[i+1].GetMinIndexValPair() ) {
126  DeleteIndices();
127  MakeZombie();
128  Error("TChainIndex", "The indices in files of this chain aren't sorted.");
129  }
130  }
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Add an index to this chain.
135 /// if delaySort is kFALSE (default) check if the indices of different trees are in order.
136 
137 void TChainIndex::Append(const TVirtualIndex *index, Bool_t delaySort )
138 {
139  if (index) {
140  const TTreeIndex *ti_index = dynamic_cast<const TTreeIndex*>(index);
141  if (ti_index == 0) {
142  Error("Append", "The given index is not a TTreeIndex but a %s",
143  index->IsA()->GetName());
144  }
145 
146  TChainIndexEntry entry;
147  entry.fTreeIndex = 0;
148  entry.SetMinMaxFrom(ti_index);
149  fEntries.push_back(entry);
150  }
151 
152  if (!delaySort) {
153  // Check if the indices of different trees are in order. If not then return an error.
154  for (Int_t i = 0; i < Int_t(fEntries.size() - 1); i++) {
155  if( fEntries[i].GetMaxIndexValPair() > fEntries[i+1].GetMinIndexValPair() ) {
156  DeleteIndices();
157  MakeZombie();
158  Error("Append", "The indices in files of this chain aren't sorted.");
159  }
160  }
161  }
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Delete all the indices which were built by this object.
166 
167 void TChainIndex::DeleteIndices()
168 {
169  for (unsigned int i = 0; i < fEntries.size(); i++) {
170  if (fEntries[i].fTreeIndex) {
171  if (fTree->GetTree() && fTree->GetTree()->GetTreeIndex() == fEntries[i].fTreeIndex) {
172  fTree->GetTree()->SetTreeIndex(0);
173  SafeDelete(fEntries[i].fTreeIndex);
174  }
175  SafeDelete(fEntries[i].fTreeIndex);
176  }
177  }
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// The destructor.
182 
183 TChainIndex::~TChainIndex()
184 {
185  DeleteIndices();
186  if (fTree && fTree->GetTreeIndex() == this)
187  fTree->SetTreeIndex(0);
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Returns a TVirtualIndex for a tree which holds the entry with the specified
192 /// major and minor values and the number of that tree.
193 /// If the index for that tree was created by this object it's set to the tree.
194 /// The tree index should be later released using ReleaseSubTreeIndex();
195 
196 std::pair<TVirtualIndex*, Int_t> TChainIndex::GetSubTreeIndex(Long64_t major, Long64_t minor) const
197 {
198  using namespace std;
199  if (fEntries.size() == 0) {
200  Warning("GetSubTreeIndex", "No subindices in the chain. The chain is probably empty");
201  return make_pair(static_cast<TVirtualIndex*>(0), 0);
202  }
203 
204  const TChainIndexEntry::IndexValPair_t indexValue(major, minor);
205 
206  if( indexValue < fEntries[0].GetMinIndexValPair() ) {
207  Warning("GetSubTreeIndex", "The index value is less than the smallest index values in subtrees");
208  return make_pair(static_cast<TVirtualIndex*>(0), 0);
209  }
210 
211  Int_t treeNo = fEntries.size() - 1;
212  for (unsigned int i = 0; i < fEntries.size() - 1; i++) {
213  if( indexValue < fEntries[i+1].GetMinIndexValPair() ) {
214  treeNo = i;
215  break;
216  }
217  }
218  // Double check we found the right range.
219  if( indexValue > fEntries[treeNo].GetMaxIndexValPair() ) {
220  return make_pair(static_cast<TVirtualIndex*>(0), 0);
221  }
222  TChain* chain = dynamic_cast<TChain*> (fTree);
223  R__ASSERT(chain);
224  chain->LoadTree(chain->GetTreeOffset()[treeNo]);
225  TVirtualIndex* index = fTree->GetTree()->GetTreeIndex();
226  if (index)
227  return make_pair(static_cast<TVirtualIndex*>(index), treeNo);
228  else {
229  index = fEntries[treeNo].fTreeIndex;
230  if (!index) {
231  Warning("GetSubTreeIndex", "The tree has no index and the chain index"
232  " doesn't store an index for that tree");
233  return make_pair(static_cast<TVirtualIndex*>(0), 0);
234  }
235  else {
236  fTree->GetTree()->SetTreeIndex(index);
237  return make_pair(static_cast<TVirtualIndex*>(index), treeNo);
238  }
239  }
240 }
241 
242 ////////////////////////////////////////////////////////////////////////////////
243 /// Releases the tree index got using GetSubTreeIndex. If the index was
244 /// created by this object it is removed from the current tree, so that it isn't
245 /// deleted in its destructor.
246 
247 void TChainIndex::ReleaseSubTreeIndex(TVirtualIndex* index, int treeNo) const
248 {
249  if (fEntries[treeNo].fTreeIndex == index) {
250  R__ASSERT(fTree->GetTree()->GetTreeIndex() == index);
251  fTree->GetTree()->SetTreeIndex(0);
252  }
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// See TTreeIndex::GetEntryNumberFriend for description
257 
258 Long64_t TChainIndex::GetEntryNumberFriend(const TTree *parent)
259 {
260  if (!parent) return -3;
261  GetMajorFormulaParent(parent);
262  GetMinorFormulaParent(parent);
263  if (!fMajorFormulaParent || !fMinorFormulaParent) return -1;
264  if (!fMajorFormulaParent->GetNdim() || !fMinorFormulaParent->GetNdim()) {
265  // The Tree Index in the friend has a pair majorname,minorname
266  // not available in the parent Tree T.
267  // if the friend Tree has less entries than the parent, this is an error
268  Long64_t pentry = parent->GetReadEntry();
269  if (pentry >= fTree->GetEntries()) return -2;
270  // otherwise we ignore the Tree Index and return the entry number
271  // in the parent Tree.
272  return pentry;
273  }
274 
275  // majorname, minorname exist in the parent Tree
276  // we find the current values pair majorv,minorv in the parent Tree
277  Double_t majord = fMajorFormulaParent->EvalInstance();
278  Double_t minord = fMinorFormulaParent->EvalInstance();
279  Long64_t majorv = (Long64_t)majord;
280  Long64_t minorv = (Long64_t)minord;
281  // we check if this pair exist in the index.
282  // if yes, we return the corresponding entry number
283  // if not the function returns -1
284  return fTree->GetEntryNumberWithIndex(majorv,minorv);
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 /// See TTreeIndex::GetEntryNumberWithBestIndex for details.
289 
290 Long64_t TChainIndex::GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor) const
291 {
292  std::pair<TVirtualIndex*, Int_t> indexAndNumber = GetSubTreeIndex(major, minor);
293  if (!indexAndNumber.first) {
294  // Error("GetEntryNumberWithBestIndex","no index found");
295  return -1;
296  }
297  else {
298  Long64_t rv = indexAndNumber.first->GetEntryNumberWithBestIndex(major, minor);
299  ReleaseSubTreeIndex(indexAndNumber.first, indexAndNumber.second);
300  TChain* chain = dynamic_cast<TChain*> (fTree);
301  R__ASSERT(chain);
302  return rv + chain->GetTreeOffset()[indexAndNumber.second];
303  }
304 }
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 /// Returns the entry number with given index values.
308 /// See TTreeIndex::GetEntryNumberWithIndex for details.
309 
310 Long64_t TChainIndex::GetEntryNumberWithIndex(Long64_t major, Long64_t minor) const
311 {
312  std::pair<TVirtualIndex*, Int_t> indexAndNumber = GetSubTreeIndex(major, minor);
313  if (!indexAndNumber.first) {
314  // Error("GetEntryNumberWithIndex","no index found");
315  return -1;
316  }
317  else {
318  Long64_t rv = indexAndNumber.first->GetEntryNumberWithIndex(major, minor);
319  ReleaseSubTreeIndex(indexAndNumber.first, indexAndNumber.second);
320  TChain* chain = dynamic_cast<TChain*> (fTree);
321  R__ASSERT(chain);
322  if (rv >= 0) {
323  return rv + chain->GetTreeOffset()[indexAndNumber.second];
324  } else {
325  return rv;
326  }
327  }
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Return a pointer to the TreeFormula corresponding to the majorname in parent tree T.
332 
333 TTreeFormula *TChainIndex::GetMajorFormulaParent(const TTree *parent)
334 {
335  if (!fMajorFormulaParent) {
336  TTree::TFriendLock friendlock(fTree, TTree::kFindLeaf | TTree::kFindBranch | TTree::kGetBranch | TTree::kGetLeaf);
337  fMajorFormulaParent = new TTreeFormula("MajorP",fMajorName.Data(),const_cast<TTree*>(parent));
338  fMajorFormulaParent->SetQuickLoad(kTRUE);
339  }
340  if (fMajorFormulaParent->GetTree() != parent) {
341  fMajorFormulaParent->SetTree(const_cast<TTree*>(parent));
342  fMajorFormulaParent->UpdateFormulaLeaves();
343  }
344  return fMajorFormulaParent;
345 }
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// Return a pointer to the TreeFormula corresponding to the minorname in parent tree T.
349 
350 TTreeFormula *TChainIndex::GetMinorFormulaParent(const TTree *parent)
351 {
352  if (!fMinorFormulaParent) {
353  // Prevent TTreeFormula from finding any of the branches in our TTree even if it
354  // is a friend of the parent TTree.
355  TTree::TFriendLock friendlock(fTree, TTree::kFindLeaf | TTree::kFindBranch | TTree::kGetBranch | TTree::kGetLeaf);
356  fMinorFormulaParent = new TTreeFormula("MinorP",fMinorName.Data(),const_cast<TTree*>(parent));
357  fMinorFormulaParent->SetQuickLoad(kTRUE);
358  }
359  if (fMinorFormulaParent->GetTree() != parent) {
360  fMinorFormulaParent->SetTree(const_cast<TTree*>(parent));
361  fMinorFormulaParent->UpdateFormulaLeaves();
362  }
363 
364  return fMinorFormulaParent;
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 /// Return kTRUE if index can be applied to the TTree
369 
370 Bool_t TChainIndex::IsValidFor(const TTree *parent)
371 {
372  auto *majorFormula = GetMajorFormulaParent(parent);
373  auto *minorFormula = GetMinorFormulaParent(parent);
374  if ((majorFormula == nullptr || majorFormula->GetNdim() == 0) ||
375  (minorFormula == nullptr || minorFormula->GetNdim() == 0))
376  return kFALSE;
377  return kTRUE;
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Updates the parent formulae.
382 /// Called by TChain::LoadTree when the parent chain changes it's tree.
383 
384 void TChainIndex::UpdateFormulaLeaves(const TTree *parent)
385 {
386  if (fMajorFormulaParent) {
387  // Prevent TTreeFormula from finding any of the branches in our TTree even if it
388  // is a friend of the parent TTree.
389  TTree::TFriendLock friendlock(fTree, TTree::kFindLeaf | TTree::kFindBranch | TTree::kGetBranch | TTree::kGetLeaf);
390  if (parent) fMajorFormulaParent->SetTree((TTree*)parent);
391  fMajorFormulaParent->UpdateFormulaLeaves();
392  }
393  if (fMinorFormulaParent) {
394  if (parent) fMinorFormulaParent->SetTree((TTree*)parent);
395  fMinorFormulaParent->UpdateFormulaLeaves();
396  }
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// See TTreeIndex::SetTree.
401 
402 void TChainIndex::SetTree(const TTree *T)
403 {
404  R__ASSERT(fTree == 0 || fTree == T || T==0);
405 }
406