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  template<class T> Proxy<T>::Proxy(TDirectory* d, TTree* tr, const std::string& name, const long& base, int offset)
59  : fName(name), fLeaf(0), fTree(tr),
60  fDir(d), fBase(base), fOffset(offset),
61  fLeafInfo(0), fBranch(0), fTTF(0), fEntry(-1), fSubIdx(0)
62  {
63  }
64 
65  //----------------------------------------------------------------------
66  template<class T> Proxy<T>::Proxy(const Proxy<T>& p)
67  : fName("copy of "+p.fName), fLeaf(0), fTree(p.fDir ? 0 : p.fTree),
68  fDir(p.fDir), fBase(p.fBase), fOffset(p.fOffset),
69  fLeafInfo(0), fBranch(0), fTTF(0), fSubIdx(-1)
70  {
71  // Ensure that the value is evaluated and baked in in the parent object, so
72  // that fTTF et al aren't re-evaluated in every single copy.
73  fVal = p.GetValue();
74  fEntry = p.fEntry;
75  }
76 
77  //----------------------------------------------------------------------
78  template<class T> Proxy<T>::Proxy(const Proxy&& p)
79  : fName("move of "+p.fName), fLeaf(0), fTree(p.fDir ? 0 : p.fTree),
81  fLeafInfo(0), fBranch(0), fTTF(0), fSubIdx(-1)
82  {
83  // Ensure that the value is evaluated and baked in in the parent object, so
84  // that fTTF et al aren't re-evaluated in every single copy.
85  fVal = p.GetValue();
86  fEntry = p.fEntry;
87  }
88 
89  //----------------------------------------------------------------------
90  template<class T> Proxy<T>::~Proxy()
91  {
92  // The other pointers aren't ours
93  delete fTTF;
94  }
95 
96  //----------------------------------------------------------------------
97  template<class T> T Proxy<T>::GetValue() const
98  {
99  if(fDir) return GetValueFlat(); else return GetValueNested();
100  }
101 
102  template<class T> void GetTypedValueWrapper(TLeaf* leaf, T& x, int subidx)
103  {
104  x = leaf->GetTypedValue<T>(subidx);
105  }
106 
107  void GetTypedValueWrapper(TLeaf* leaf, std::string& x, int subidx)
108  {
109  assert(subidx == 0); // Unused for flat trees at least
110  x = (char*)leaf->GetValuePointer();
111  }
112 
113  //----------------------------------------------------------------------
114  template<class T> T Proxy<T>::GetValueFlat() const
115  {
116  // Valid cached or systematically-shifted value
117  if(fEntry == fBase+fOffset) return (T)fVal;
118 
119  assert(fTree);
120 
121  if(!fLeaf){
122  fLeaf = fTree->GetLeaf(fName.c_str());
123  if(!fLeaf){
124  std::cout << std::endl << "BasicTypeProxy: Branch '" << fName
125  << "' not found in tree '" << fTree->GetName() << "'."
126  << std::endl;
127  abort();
128  }
129 
130  if(fName.find("_idx") == std::string::npos &&
131  fName.find("_length") == std::string::npos &&
132  fName.find(".size()") == std::string::npos){ // specific to "nested"
134  }
135  }
136 
137  fLeaf->GetBranch()->GetEntry(fBase+fOffset);
138 
140 
141  fEntry = fBase+fOffset;
142 
143  return (T)fVal;
144  }
145 
146  template<class T> void EvalInstanceWrapper(TTreeFormula* ttf, T& x)
147  {
148  // TODO is this the safest way to cast?
149  x = (T)ttf->EvalInstance(0);
150  }
151 
152  void EvalInstanceWrapper(TTreeFormula* ttf, std::string& x)
153  {
154  x = ttf->EvalStringInstance(0);
155  }
156 
157  //----------------------------------------------------------------------
158  template<class T> T Proxy<T>::GetValueNested() const
159  {
160  // Magic value indicating the value has been set even in the absence of a
161  // tree
162  if(!fTree && fEntry == -100) return (T)fVal;
163 
164  assert(fTree);
165 
166  // Valid cached or systematically-shifted value
167  if(fEntry == fTree->GetReadEntry()) return (T)fVal;
168 
169  fEntry = fTree->GetReadEntry();
170 
171  // First time calling, set up the branches etc
172  if(!fTTF){
174 
175  // Leaves are attached to the TTF, must keep it
176  fTTF = new TTreeFormula(("TTFProxy-"+fName).c_str(), fName.c_str(), fTree);
177  fLeafInfo = fTTF->GetLeafInfo(0); // Can fail (for a regular branch?)
178  fLeaf = fTTF->GetLeaf(0);
179  fBranch = fLeaf->GetBranch();
180 
181  if(!fLeaf || !fBranch){
182  std::cout << "Couldn't find " << fName << " in tree. Abort."
183  << std::endl;
184 
185  abort();
186  }
187 
188  // TODO - parsing the array indices out sucks - pass in as an int somehow
189  const size_t open_idx = fName.find_first_of('[');
190  // Do we have exactly one set of [] in the name?
191  if(open_idx != std::string::npos && open_idx == fName.find_last_of('[')){
192  const size_t close_idx = fName.find_first_of(']');
193 
194  std::string numPart = fName.substr(open_idx+1, close_idx-open_idx-1);
195  fSubIdx = atoi(numPart.c_str());
196  }
197  }
198 
199  if(fLeafInfo){
200  // Using TTreeFormula always works, and is sometimes necessary
201 
202  fTTF->GetNdata(); // for some reason this is necessary for fTTF to work
203  // in all cases.
204 
206  }
207  else{
208  // But when this is possible the hope is it might be faster
209 
210  if(fBranch->GetReadEntry() != fEntry){
211  fBranch->GetEntry(fEntry);
212  }
213 
214  // This check is much quicker than what CheckIndex() does, which winds up
215  // calling a TTF, but I can't figure out a safe way to automatically
216  // elide that check.
217  if(fSubIdx > fLeaf->GetLen()){
218  std::cout << std::endl << fName << " out of range (size() == " << fLeaf->GetLen() << "). Aborting." << std::endl;
219  abort();
220  }
221 
223  }
224 
225  return (T)fVal;
226  }
227 
228  //----------------------------------------------------------------------
229  template<class T> Proxy<T>& Proxy<T>::operator=(T x)
230  {
232  fVal = x;
233 
234  if(fDir){
235  fEntry = fBase+fOffset; // flat
236  }
237  else{
238  fEntry = fTree ? fTree->GetReadEntry() : -100; // nested
239  }
240 
241  return *this;
242  }
243 
244  //----------------------------------------------------------------------
245  template<class T> Proxy<T>& Proxy<T>::operator+=(T x)
246  {
247  if constexpr(!std::is_same_v<T, bool>){
248  // Do it this way to re-use the systematics logic in operator=
249  *this = T(GetValue() + x);
250  }
251  else{
252  std::cout << "Proxy<bool>::operator+=() is meaningless" << std::endl;
253  (void)x;
254  abort();
255  }
256 
257  return *this;
258  }
259 
260  //----------------------------------------------------------------------
261  template<class T> Proxy<T>& Proxy<T>::operator*=(T x)
262  {
263  if constexpr(std::is_same_v<T, std::string>){
264  std::cout << "Proxy<std::string>::operator*=() is meaningless" << std::endl;
265  (void)x;
266  abort();
267  }
268  else if constexpr(std::is_same_v<T, bool>){
269  std::cout << "Proxy<bool>::operator*=() is meaningless" << std::endl;
270  (void)x;
271  abort();
272  }
273  else{
274  // Do it this way to re-use the systematics logic in operator=
275  *this = T(GetValue() * x);
276  }
277 
278  return *this;
279  }
280 
281  //----------------------------------------------------------------------
282  template<class T> void Proxy<T>::CheckEquals(const T& x) const
283  {
284  if(!AreEqual(GetValue(), x)){
285  std::cout << fName << " differs: "
286  << GetValue() << " vs " << x << std::endl;
287  }
288  }
289 
290  //----------------------------------------------------------------------
291  VectorProxyBase::VectorProxyBase(TDirectory* d, TTree* tr,
292  const std::string& name,
293  const long& base, int offset)
294  : fDir(d), fTree(tr), fName(name), fBase(base), fOffset(offset), fSize(d, tr, fDir ? fName+"_length" : AtSize(), base, offset), fIdxP(d, tr, name+"_idx", base, offset),
295  fSystOverrideSize(-1),
296  fSystOverrideEntry(-1),
297  fSystOverrideSeqNo(-1),
298  fWarn(false)
299  {
300  }
301 
302  //----------------------------------------------------------------------
303  void VectorProxyBase::CheckIndex(size_t i) const
304  {
305  // This is the only way to get good error messages. But it also seems like
306  // the call to size() here is necessary in Nested mode to trigger some
307  // side-effect within ROOT, otherwise we get some bogus index out-of-range
308  // crashes.
309  if(i >= size()){
310  std::cout << std::endl << fName << "[" << (signed)i << "] out of range (size() == " << size() << "). Aborting." << std::endl;
311  abort();
312  }
313  }
314 
315  //----------------------------------------------------------------------
317  {
318  const size_t idx1 = s.find_first_of('[');
319 
320  if(idx1 == std::string::npos) return s;
321 
322  const size_t idx2 = s.find_first_of(']');
323 
324  // Huh?
325  if(idx2 == std::string::npos) return s;
326 
327  // Recurse in case there are more
328  return StripIndices(s.substr(0, idx1) + s.substr(idx2+1));
329  }
330 
331  //----------------------------------------------------------------------
333  {
334  const int idx = fName.find_last_of('.');
335  // foo.bar.baz -> foo.bar.nbaz
336  return fName.substr(0, idx)+".n"+fName.substr(idx+1);
337  }
338 
339  //----------------------------------------------------------------------
340  // Used by nested variant
342  {
343  // Counts exist, but with non-systematic names
344  if(fName == "rec.me.trkkalman" ) return "rec.me.nkalman";
345  if(fName == "rec.me.trkdiscrete") return "rec.me.ndiscrete";
346  if(fName == "rec.me.trkcosmic" ) return "rec.me.ncosmic";
347  if(fName == "rec.me.trkbpf" ) return "rec.me.nbpf";
348 
349  const int idx = fName.find_last_of('.');
350  // foo.bar.baz -> foo.bar.nbaz
351  const std::string nname = NName();
352 
353  if(!fTree) return nname; // doesn't matter if leaf exists or not
354 
355  int olderr = gErrorIgnoreLevel;
356  gErrorIgnoreLevel = 99999999;
357  TTreeFormula ttf(("TTFProxySize-"+fName).c_str(), nname.c_str(), fTree);
358  TString junks = nname.c_str();
359  int junki;
360  const int def = ttf.DefinedVariable(junks, junki);
361  gErrorIgnoreLevel = olderr;
362 
363  if(def >= 0) return nname;
364 
365  // Otherwise fallback and make a note to warn the first time we're accessed
366  fWarn = true;
367 
368  // foo.bar.baz -> foo.bar.@baz.size()
369  return fName.substr(0, idx+1)+"@"+fName.substr(idx+1)+".size()";
370  }
371 
372  //----------------------------------------------------------------------
373  // Used by nested variant
375  {
376  // Only have to do the at() business for subscripts from the 3rd one on
377  const int nSubs = std::count(fName.begin(), fName.end(), '[');
378  if(nSubs < 2) return TString::Format("%s[%d]", fName.c_str(), i).Data();
379 
380  const int idx = fName.find_last_of('.');
381  return TString::Format("%s.@%s.at(%d)",
382  fName.substr(0, idx).c_str(),
383  fName.substr(idx+1).c_str(),
384  i).Data();
385  }
386 
387  //----------------------------------------------------------------------
389  {
390  TTree* tr = (TTree*)fDir->Get(fName.c_str());
391  if(!tr){
392  std::cout << "Couldn't find TTree " << fName
393  << " in " << fDir->GetName() << std::endl;
394  abort();
395  }
396  return tr;
397  }
398 
399  //----------------------------------------------------------------------
400  size_t VectorProxyBase::size() const
401  {
402  if(fWarn){
403  fWarn = false;
404 
405  // Don't emit the same warning more than once
406  static std::set<std::string> already;
407 
408  const std::string key = StripIndices(NName());
409  if(already.count(key) == 0){
410  already.insert(key);
411  std::cout << std::endl;
412  std::cout << "Warning: field '" << key << "' does not exist in file. "
413  << "Falling back to '" << StripIndices(fSize.Name()) << "' which is less efficient. "
414  << "Consider updating StandardRecord to include '" << key << "'." << std::endl;
415  std::cout << std::endl;
416  }
417  }
418 
419  return fSize;
420  }
421 
422  //----------------------------------------------------------------------
424  {
425  return size() == 0;
426  }
427 
428  //----------------------------------------------------------------------
430  {
431  fSize = i;
432  }
433 
434  // Enumerate all the variants we expect
435  template class Proxy<char>;
436  template class Proxy<short>;
437  template class Proxy<int>;
438  template class Proxy<long>;
439  template class Proxy<long long>;
440 
441  template class Proxy<unsigned char>;
442  template class Proxy<unsigned short>;
443  template class Proxy<unsigned int>;
444  template class Proxy<unsigned long>;
445  template class Proxy<unsigned long long>;
446 
447  template class Proxy<float>;
448  template class Proxy<double>;
449  template class Proxy<long double>;
450 
451  template class Proxy<bool>;
452 
453  template class Proxy<std::string>;
454 
455 } // namespace
const XML_Char * name
Definition: expat.h:151
std::string Subscript(int i) const
static void ToFile(const std::string &fname)
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
bool AreEqual(double x1, double x2)
Definition: MathUtils.cxx:243
T GetValue() const
const char * p
Definition: xmltok.h:285
VectorProxyBase(TDirectory *d, TTree *tr, const std::string &name, const long &base, int offset)
static void Backup(Proxy< T > &p)
void CheckIndex(size_t i) const
std::string fName
std::string AtSize() const
const XML_Char int const XML_Char int const XML_Char * base
Definition: expat.h:331
void GetTypedValueWrapper(TLeaf *leaf, T &x, int subidx)
int isnan(const stan::math::var &a)
Definition: std_isnan.hpp:18
TFormLeafInfo * fLeafInfo
const XML_Char * s
Definition: expat.h:262
void prev()
Definition: show_event.C:91
static void Print(bool abbrev=true)
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
OStream cout
Definition: OStream.cxx:6
Proxy< T > & operator*=(T x)
std::string StripIndices(const std::string &s)
std::string NName() const
Helper for AtSize()
const hit & b
Definition: hits.cxx:21
T GetValueFlat() const
assert(nhit_max >=nhit_nbins)
TTree * GetTreeForName() const
static void AddBranch(const std::string &b)
void Format(TGraph *gr, int lcol, int lsty, int lwid, int mcol, int msty, double msiz)
Definition: Style.cxx:154
static std::vector< Restorer * > fRestorers
double T
Definition: Xdiff_gwt.C:5
This module creates Common Analysis Files.
Definition: FileReducer.h:10
T min(const caf::Proxy< T > &a, T b)
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