BasicTypesProxy.cxx
Go to the documentation of this file.
2 
3 #include "TFormLeafInfo.h"
4 #include "TTreeFormula.h"
5 
6 #include <algorithm>
7 #include <cassert>
8 #include <iostream>
9 #include <fstream>
10 
11 namespace
12 {
13  /// Helper for CheckEquals
14  template<class T> bool AreEqual(const T& x, const T& y)
15  {
16  if constexpr(std::is_floating_point_v<T>){
17  return x == y || (std::isnan(x) && std::isnan(y));
18  }
19  else{
20  return x == y;
21  }
22  }
23 }
24 
25 namespace caf
26 {
27  std::vector<Restorer*> SRProxySystController::fRestorers;
29 
30  std::set<std::string> SRBranchRegistry::fgBranches;
31 
32  //----------------------------------------------------------------------
33  void SRBranchRegistry::Print(bool abbrev)
34  {
36  for(std::string b: fgBranches){
37  if(abbrev){
38  unsigned int cutto = 0;
39  for(unsigned int i = 0; i < std::min(b.size(), prev.size()); ++i){
40  if(b[i] != prev[i]) break;
41  if(b[i] == '.') cutto = i;
42  }
43  prev = b;
44  for(unsigned int i = 0; i < cutto; ++i) b[i] = ' ';
45  }
46  std::cout << b << std::endl;
47  }
48  }
49 
50  //----------------------------------------------------------------------
52  {
53  std::ofstream fout(fname);
54  for(const std::string& b: fgBranches) fout << b << std::endl;
55  }
56 
57  //----------------------------------------------------------------------
58  CAFType GetCAFType(const TDirectory* dir, TTree* tr)
59  {
60  if(!dir && !tr) return kCopiedRecord;
61  if(dir) return kFlatMultiTree;
62  if(tr->GetNbranches() > 1) return kFlatSingleTree;
63  return kNested;
64  }
65 
66  //----------------------------------------------------------------------
68  {
70  ret.reserve(s.size());
71  bool insub = false;
72  for(char c: s){
73  /**/ if(c == '[') insub = true;
74  else if(c == ']') insub = false;
75  else if(!insub) ret += c;
76  }
77  return ret;
78  }
79 
80  //----------------------------------------------------------------------
82  {
83  return std::count(name.begin(), name.end(), '[');
84  }
85 
86  //----------------------------------------------------------------------
87  const long kZero = 0;
88 
89  // Sigh. For multi-tree flatcafs, 'base' is being updated by the caller to
90  // give the row in the tree. But for single-tree flatcafs, this field
91  // signifies a starting position within the array for the current row, and
92  // should always be zero (ignoring the caller) for top-level fields. Enforce
93  // that here.
94  const long& AdjustBase(const long& base, CAFType type, const std::string& name)
95  {
96  if(type == kFlatSingleTree && NSubscripts(name) == 0) return kZero;
97  return base;
98  }
99 
100  //----------------------------------------------------------------------
101  template<class T> Proxy<T>::Proxy(TDirectory* d, TTree* tr, const std::string& name, const long& base, int offset)
102  : fName(name), fType(GetCAFType(d, tr)),
103  fLeaf(0), fTree(tr), fDir(d),
104  fBase(AdjustBase(base, fType, fName)), fOffset(offset),
105  fLeafInfo(0), fBranch(0), fTTF(0), fEntry(-1), fSubIdx(0)
106  {
107  }
108 
109  const long kDummyBase = -1;
110 
111  //----------------------------------------------------------------------
112  template<class T> Proxy<T>::Proxy(const Proxy<T>& p)
113  : fName("copy of "+p.fName), fType(kCopiedRecord),
114  fLeaf(0), fTree(0), fDir(0),
115  fBase(kDummyBase), fOffset(-1),
116  fLeafInfo(0), fBranch(0), fTTF(0), fEntry(-1), fSubIdx(-1)
117  {
118  // Ensure that the value is evaluated and baked in in the parent object, so
119  // that fTTF et al aren't re-evaluated in every single copy.
120  fVal = p.GetValue();
121  }
122 
123  //----------------------------------------------------------------------
124  template<class T> Proxy<T>::Proxy(const Proxy&& p)
125  : fName("move of "+p.fName), fType(kCopiedRecord),
126  fLeaf(0), fTree(0), fDir(0),
127  fBase(kDummyBase), fOffset(-1),
128  fLeafInfo(0), fBranch(0), fTTF(0), fEntry(-1), fSubIdx(-1)
129  {
130  // Ensure that the value is evaluated and baked in in the parent object, so
131  // that fTTF et al aren't re-evaluated in every single copy.
132  fVal = p.GetValue();
133  }
134 
135  //----------------------------------------------------------------------
136  template<class T> Proxy<T>::~Proxy()
137  {
138  // The other pointers aren't ours
139  delete fTTF;
140  }
141 
142  //----------------------------------------------------------------------
143  template<class T> T Proxy<T>::GetValue() const
144  {
145  switch(fType){
146  case kNested: return GetValueNested();
147  case kFlatMultiTree: return GetValueFlatMulti();
148  case kFlatSingleTree: return GetValueFlatSingle();
149  case kCopiedRecord: return (T)fVal;
150  default: abort();
151  }
152  }
153 
154  template<class T> void GetTypedValueWrapper(TLeaf* leaf, T& x, int subidx)
155  {
156  x = leaf->GetTypedValue<T>(subidx);
157  }
158 
159  void GetTypedValueWrapper(TLeaf* leaf, std::string& x, int subidx)
160  {
161  assert(subidx == 0); // Unused for flat trees at least
162  x = (char*)leaf->GetValuePointer();
163  }
164 
165  //----------------------------------------------------------------------
166  template<class T> T Proxy<T>::GetValueFlatSingle() const
167  {
168  assert(fTree);
169 
170  // Valid cached or systematically-shifted value
171  if(fEntry == fTree->GetReadEntry()) return (T)fVal;
172  fEntry = fTree->GetReadEntry();
173 
174  assert(fTree);
175 
176  if(!fLeaf){
177  const std::string sname = StripSubscripts(fName);
178  fLeaf = fTree->GetLeaf(sname.c_str());
179  if(!fLeaf){
180  std::cout << std::endl << "BasicTypeProxy: Branch '" << sname
181  << "' not found in tree '" << fTree->GetName() << "'."
182  << std::endl;
183  abort();
184  }
185 
186  fBranch = fLeaf->GetBranch();
187 
188  if(fName.find("..idx") == std::string::npos &&
189  fName.find("..length") == std::string::npos){
191  }
192  }
193 
194  fBranch->GetEntry(fEntry);
195 
197 
198  return (T)fVal;
199  }
200 
201  //----------------------------------------------------------------------
202  template<class T> T Proxy<T>::GetValueFlatMulti() const
203  {
204  // Valid cached or systematically-shifted value
205  if(fEntry == fBase+fOffset) return (T)fVal;
206  fEntry = fBase+fOffset;
207 
208  assert(fTree);
209 
210  if(!fLeaf){
211  const std::string sname = StripSubscripts(fName);
212  fLeaf = fTree->GetLeaf(sname.c_str());
213  if(!fLeaf){
214  std::cout << std::endl << "BasicTypeProxy: Branch '" << sname
215  << "' not found in tree '" << fTree->GetName() << "'."
216  << std::endl;
217  abort();
218  }
219 
220  fBranch = fLeaf->GetBranch();
221 
222  if(fName.find("_idx") == std::string::npos &&
223  fName.find("_length") == std::string::npos &&
224  fName.find(".size()") == std::string::npos){ // specific to "nested"
226  }
227  }
228 
229  fBranch->GetEntry(fBase+fOffset);
230 
232 
233  return (T)fVal;
234  }
235 
236  template<class T> void EvalInstanceWrapper(TTreeFormula* ttf, T& x)
237  {
238  // TODO is this the safest way to cast?
239  x = (T)ttf->EvalInstance(0);
240  }
241 
242  void EvalInstanceWrapper(TTreeFormula* ttf, std::string& x)
243  {
244  x = ttf->EvalStringInstance(0);
245  }
246 
247  //----------------------------------------------------------------------
248  template<class T> T Proxy<T>::GetValueNested() const
249  {
250  assert(fTree);
251 
252  // Valid cached or systematically-shifted value
253  if(fEntry == fTree->GetReadEntry()) return (T)fVal;
254  fEntry = fTree->GetReadEntry();
255 
256  // First time calling, set up the branches etc
257  if(!fTTF){
259 
260  // Leaves are attached to the TTF, must keep it
261  fTTF = new TTreeFormula(("TTFProxy-"+fName).c_str(), fName.c_str(), fTree);
262  fLeafInfo = fTTF->GetLeafInfo(0); // Can fail (for a regular branch?)
263  fLeaf = fTTF->GetLeaf(0);
264  fBranch = fLeaf->GetBranch();
265 
266  if(!fLeaf || !fBranch){
267  std::cout << "Couldn't find " << fName << " in tree. Abort."
268  << std::endl;
269 
270  abort();
271  }
272 
273  // TODO - parsing the array indices out sucks - pass in as an int somehow
274  const size_t open_idx = fName.find_first_of('[');
275  // Do we have exactly one set of [] in the name?
276  if(open_idx != std::string::npos && open_idx == fName.find_last_of('[')){
277  const size_t close_idx = fName.find_first_of(']');
278 
279  std::string numPart = fName.substr(open_idx+1, close_idx-open_idx-1);
280  fSubIdx = atoi(numPart.c_str());
281  }
282  }
283 
284  if(fLeafInfo){
285  // Using TTreeFormula always works, and is sometimes necessary
286 
287  fTTF->GetNdata(); // for some reason this is necessary for fTTF to work
288  // in all cases.
289 
291  }
292  else{
293  // But when this is possible the hope is it might be faster
294 
295  if(fBranch->GetReadEntry() != fEntry){
296  fBranch->GetEntry(fEntry);
297  }
298 
299  // This check is much quicker than what CheckIndex() does, which winds up
300  // calling a TTF, but I can't figure out a safe way to automatically
301  // elide that check.
302  if(fSubIdx > fLeaf->GetLen()){
303  std::cout << std::endl << fName << " out of range (size() == " << fLeaf->GetLen() << "). Aborting." << std::endl;
304  abort();
305  }
306 
308  }
309 
310  return (T)fVal;
311  }
312 
313  //----------------------------------------------------------------------
314  template<class T> Proxy<T>& Proxy<T>::operator=(T x)
315  {
317  fVal = x;
318 
319  switch(fType){
320  case kNested: fEntry = fTree->GetReadEntry(); break;
321  case kFlatMultiTree: fEntry = fBase+fOffset; break;
322  case kFlatSingleTree: fEntry = fTree->GetReadEntry(); break;
323  case kCopiedRecord: break;
324  default: abort();
325  }
326 
327  return *this;
328  }
329 
330  //----------------------------------------------------------------------
331  template<class T> Proxy<T>& Proxy<T>::operator+=(T x)
332  {
333  if constexpr(!std::is_same_v<T, bool>){
334  // Do it this way to re-use the systematics logic in operator=
335  *this = T(GetValue() + x);
336  }
337  else{
338  std::cout << "Proxy<bool>::operator+=() is meaningless" << std::endl;
339  (void)x;
340  abort();
341  }
342 
343  return *this;
344  }
345 
346  //----------------------------------------------------------------------
347  template<class T> Proxy<T>& Proxy<T>::operator*=(T x)
348  {
349  if constexpr(std::is_same_v<T, std::string>){
350  std::cout << "Proxy<std::string>::operator*=() is meaningless" << std::endl;
351  (void)x;
352  abort();
353  }
354  else if constexpr(std::is_same_v<T, bool>){
355  std::cout << "Proxy<bool>::operator*=() is meaningless" << std::endl;
356  (void)x;
357  abort();
358  }
359  else{
360  // Do it this way to re-use the systematics logic in operator=
361  *this = T(GetValue() * x);
362  }
363 
364  return *this;
365  }
366 
367  //----------------------------------------------------------------------
368  template<class T> void Proxy<T>::CheckEquals(const T& x) const
369  {
370  if(!AreEqual(GetValue(), x)){
371  std::cout << fName << " differs: "
372  << GetValue() << " vs " << x << std::endl;
373  }
374  }
375 
376  //----------------------------------------------------------------------
378  const std::string& name,
379  const long& base, int offset)
380  : fDir(d), fTree(tr), fName(name), fType(GetCAFType(d, tr)),
381  fBase(base), fOffset(offset),
382  fIdxP(0), fIdx(0)
383  {
384  // Only used for flat trees. For single-tree, only needed for objects not
385  // at top-level.
386  if(fType == kFlatMultiTree ||
387  (fType == kFlatSingleTree && NSubscripts(fName) > 0)){
389  }
390  }
391 
392  //----------------------------------------------------------------------
394  {
395  delete fIdxP;
396  }
397 
398  //----------------------------------------------------------------------
399  void ArrayVectorProxyBase::CheckIndex(size_t i, size_t size) const
400  {
401  // This is the only way to get good error messages. But it also seems like
402  // the call to size() here is necessary in Nested mode to trigger some
403  // side-effect within ROOT, otherwise we get some bogus index out-of-range
404  // crashes.
405  if(i >= size){
406  std::cout << std::endl << fName << "[" << (signed)i << "] out of range (size() == " << size << "). Aborting." << std::endl;
407  abort();
408  }
409  }
410 
411  //----------------------------------------------------------------------
413  {
414  const int idx = fName.find_last_of('.');
415  // foo.bar.baz -> foo.bar.nbaz
416  return fName.substr(0, idx)+".n"+fName.substr(idx+1);
417  }
418 
419  //----------------------------------------------------------------------
421  {
422  if(fType == kFlatMultiTree) return fName+"_length";
423  if(fType == kFlatSingleTree) return fName+"..length";
424 
425  // Counts exist, but with non-systematic names
426  if(fName == "rec.me.trkkalman" ) return "rec.me.nkalman";
427  if(fName == "rec.me.trkdiscrete") return "rec.me.ndiscrete";
428  if(fName == "rec.me.trkcosmic" ) return "rec.me.ncosmic";
429  if(fName == "rec.me.trkbpf" ) return "rec.me.nbpf";
430 
431  const int idx = fName.find_last_of('.');
432  // foo.bar.baz -> foo.bar.nbaz
433  const std::string nname = NName();
434 
435  if(!fTree) return nname; // doesn't matter if leaf exists or not
436 
437  int olderr = gErrorIgnoreLevel;
438  gErrorIgnoreLevel = 99999999;
439  TTreeFormula ttf(("TTFProxySize-"+fName).c_str(), nname.c_str(), fTree);
440  TString junks = nname.c_str();
441  int junki;
442  const int def = ttf.DefinedVariable(junks, junki);
443  gErrorIgnoreLevel = olderr;
444 
445  if(def >= 0) return nname;
446 
447  // Otherwise fallback and make a note to warn the first time we're accessed
448  fWarn = true;
449 
450  // foo.bar.baz -> foo.bar.@baz.size()
451  return fName.substr(0, idx+1)+"@"+fName.substr(idx+1)+".size()";
452  }
453 
454  //----------------------------------------------------------------------
456  {
457  if(fType == kFlatMultiTree) return fName+"_idx";
458  if(fType == kFlatSingleTree) return fName+"..idx";
459  abort();
460  }
461 
462  //----------------------------------------------------------------------
464  {
465  // Only have to do the at() business for the nested case for subscripts
466  // from the 3rd one on
467  if(fType != kNested || NSubscripts(fName) < 2){
468  return fName+"["+std::to_string(i)+"]";
469  }
470 
471  const int idx = fName.find_last_of('.');
472 
473  return fName.substr(0, idx)+".@"+fName.substr(idx+1)+".at("+std::to_string(i)+")";
474  }
475 
476  //----------------------------------------------------------------------
478  {
479  if(fType != kFlatMultiTree) return fTree; // all in the same tree
480 
481  const std::string sname = StripSubscripts(fName);
482  TTree* tr = (TTree*)fDir->Get(sname.c_str());
483  if(!tr){
484  std::cout << "Couldn't find TTree " << sname
485  << " in " << fDir->GetName() << std::endl;
486  abort();
487  }
488  return tr;
489  }
490 
491  //----------------------------------------------------------------------
492  VectorProxyBase::VectorProxyBase(TDirectory* d, TTree* tr,
493  const std::string& name,
494  const long& base, int offset)
495  : ArrayVectorProxyBase(d, tr, name, base, offset),
496  fSize(d, tr, LengthField(), base, offset),
497  fWarn(false)
498  {
499  }
500 
501  //----------------------------------------------------------------------
502  size_t VectorProxyBase::size() const
503  {
504  if(fWarn){
505  fWarn = false;
506 
507  // Don't emit the same warning more than once
508  static std::set<std::string> already;
509 
511  if(already.count(key) == 0){
512  already.insert(key);
513  std::cout << std::endl;
514  std::cout << "Warning: field '" << key << "' does not exist in file. "
515  << "Falling back to '" << StripSubscripts(fSize.Name()) << "' which is less efficient. "
516  << "Consider updating StandardRecord to include '" << key << "'." << std::endl;
517  std::cout << std::endl;
518  }
519  }
520 
521  return fSize;
522  }
523 
524  //----------------------------------------------------------------------
526  {
527  return size() == 0;
528  }
529 
530  //----------------------------------------------------------------------
532  {
533  fSize = i;
534  }
535 
536  // Enumerate all the variants we expect
537  template class Proxy<char>;
538  template class Proxy<short>;
539  template class Proxy<int>;
540  template class Proxy<long>;
541  template class Proxy<long long>;
542 
543  template class Proxy<unsigned char>;
544  template class Proxy<unsigned short>;
545  template class Proxy<unsigned int>;
546  template class Proxy<unsigned long>;
547  template class Proxy<unsigned long long>;
548 
549  template class Proxy<float>;
550  template class Proxy<double>;
551  template class Proxy<long double>;
552 
553  template class Proxy<bool>;
554 
555  template class Proxy<std::string>;
556 
557 } // namespace
const XML_Char * name
Definition: expat.h:151
static void ToFile(const std::string &fname)
Proxy< long long > * fIdxP
Proxy & operator=(const Proxy &)=delete
Proxy(TDirectory *d, TTree *tr, const std::string &name, const long &base, int offset)
static std::set< std::string > fgBranches
TDirectory * fDir
CAFType fType
bool AreEqual(double x1, double x2)
Definition: MathUtils.cxx:243
T GetValue() const
const char * p
Definition: xmltok.h:285
ArrayVectorProxyBase(TDirectory *d, TTree *tr, const std::string &name, const long &base, int offset)
T GetValueFlatSingle() const
VectorProxyBase(TDirectory *d, TTree *tr, const std::string &name, const long &base, int offset)
static void Backup(Proxy< T > &p)
const long & AdjustBase(const long &base, CAFType type, const std::string &name)
std::string fName
std::string LengthField() const
const XML_Char int const XML_Char int const XML_Char * base
Definition: expat.h:331
const long kZero
void GetTypedValueWrapper(TLeaf *leaf, T &x, int subidx)
CAFType GetCAFType(const TDirectory *dir, TTree *tr)
int isnan(const stan::math::var &a)
Definition: std_isnan.hpp:18
TFormLeafInfo * fLeafInfo
const XML_Char * s
Definition: expat.h:262
std::string IndexField() const
std::string StripSubscripts(const std::string &s)
void prev()
Definition: show_event.C:91
static void Print(bool abbrev=true)
int NSubscripts(const std::string &name)
Count the subscripts in the name.
std::string Name() const
const long & fBase
TLeaf * fLeaf
Proxy< T > & operator+=(T x)
T GetValueNested() const
Float_t d
Definition: plot.C:236
TTreeFormula * fTTF
std::string Subscript(int i) const
add [i], or something more complex for nested CAFs
OStream cout
Definition: OStream.cxx:6
TTree * GetTreeForName() const
Proxy< T > & operator*=(T x)
const long kDummyBase
T GetValueFlatMulti() const
TDirectory * dir
Definition: macro.C:5
std::string NName() const
Helper for LengthField()
const hit & b
Definition: hits.cxx:21
assert(nhit_max >=nhit_nbins)
static void AddBranch(const std::string &b)
static std::vector< Restorer * > fRestorers
double T
Definition: Xdiff_gwt.C:5
This module creates Common Analysis Files.
Definition: FileReducer.h:10
std::string to_string(ModuleType mt)
Definition: ModuleType.h:32
T min(const caf::Proxy< T > &a, T b)
void CheckIndex(size_t i, size_t size) const
TTree * fTree
void EvalInstanceWrapper(TTreeFormula *ttf, T &x)
static long long fGeneration
typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData
void CheckEquals(const T &x) const
TBranch * fBranch
enum BeamMode string