REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestAnalysisTree.cxx
1 /*************************************************************************
2  * This file is part of the REST software framework. *
3  * *
4  * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5  * For more information see http://gifna.unizar.es/trex *
6  * *
7  * REST is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * REST is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have a copy of the GNU General Public License along with *
18  * REST in $REST_PATH/LICENSE. *
19  * If not, see http://www.gnu.org/licenses/. *
20  * For the list of contributors see $REST_PATH/CREDITS. *
21  *************************************************************************/
22 
85 
86 #include "TRestAnalysisTree.h"
87 
88 #include <TFile.h>
89 #include <TH1F.h>
90 #include <TLeaf.h>
91 #include <TObjArray.h>
92 
93 #include "TRestStringHelper.h"
94 #include "TRestStringOutput.h"
95 
96 using namespace std;
97 
98 ClassImp(TRestAnalysisTree) using namespace std;
99 
100 TRestAnalysisTree::TRestAnalysisTree() : TTree() {
101  SetName("AnalysisTree");
102  SetTitle("REST Analysis tree");
103 
104  Initialize();
105 }
106 
107 TRestAnalysisTree::TRestAnalysisTree(TTree* tree) : TTree() {
108  SetName("AnalysisTree");
109  SetTitle("Linked to " + (TString)tree->GetName());
110 
111  Initialize();
112 
113  tree->GetEntry(0);
114 
115  TObjArray* lfs = tree->GetListOfLeaves();
116  for (int i = 0; i < lfs->GetLast() + 1; i++) {
117  TLeaf* lf = (TLeaf*)lfs->UncheckedAt(i);
118  RESTValue obs;
119  ReadLeafValueToObservable(lf, obs);
120  obs.name = lf->GetName();
121  SetObservable(-1, obs);
122  }
123 }
124 
125 TRestAnalysisTree* TRestAnalysisTree::ConvertFromTTree(TTree* tree) {
126  if (tree->ClassName() == (TString) "TRestAnalysisTree") {
127  return (TRestAnalysisTree*)tree;
128  }
129 
130  return new TRestAnalysisTree(tree);
131 }
132 
133 TRestAnalysisTree::TRestAnalysisTree(const TString& name, const TString& title) : TTree(name, title) {
134  SetName(name);
135  SetTitle(title);
136 
137  Initialize();
138 }
139 
140 void TRestAnalysisTree::Initialize() {
141  fRunOrigin = 0;
142  fSubRunOrigin = 0;
143  fEventID = 0;
144  fSubEventID = 0;
145  fSubEventTag = new TString();
146  fTimeStamp = 0;
147 
148  fStatus = 0;
149  fNObservables = 0;
150  fChain = nullptr;
151 
152  fObservableIdMap.clear();
153  fObservableIdSearchMap.clear();
154  fObservableDescriptions.clear();
155  fObservableNames.clear();
156  fObservables.clear();
157 }
158 
165 Int_t TRestAnalysisTree::GetObservableID(const string& obsName) {
167  auto iter = fObservableIdMap.find(obsName);
168  if (iter != fObservableIdMap.end()) {
169  return iter->second;
170  } else {
171  return -1;
172  }
173 }
174 
181 Int_t TRestAnalysisTree::GetMatchedObservableID(const string& obsName) {
182  // if (ObservableExists(obsName)) return GetObservableID(obsName);
183  auto iter = fObservableIdSearchMap.find(obsName);
184  if (iter != fObservableIdSearchMap.end()) {
185  return iter->second;
186  } else {
187  vector<int> diffs;
188  for (auto& fObservableName : fObservableNames) {
189  string obs = (string)fObservableName;
190  int diff1 = DiffString(obs, obsName);
191 
192  obs = obs.substr(obs.find('_') + 1, -1);
193  int diff2 = DiffString(obs, obsName);
194 
195  diffs.push_back(min(diff1, diff2));
196  }
197 
198  int matchedCount = 0;
199  int minPos = 0;
200  int min = 1e5;
201  for (unsigned int i = 0; i < diffs.size(); i++) {
202  if (min > diffs[i]) {
203  min = diffs[i];
204  minPos = i;
205  }
206  if (diffs[i] == 0) {
207  matchedCount++;
208  }
209  }
210 
211  if (matchedCount == 1) {
212  cout << "TRestAnalysisTree::GetObservableID(): Find observable " << fObservableNames[minPos]
213  << " for obs name: " << obsName << endl;
214  fObservableIdSearchMap[obsName] = minPos;
215  return minPos;
216  } else if (matchedCount == 0) {
217  RESTError << "TRestAnalysisTree::GetObservableID(): No Matching observable found" << RESTendl;
218  if (min <= 2) {
219  RESTError << "did you mean \"" << fObservableNames[minPos] << "\" ?" << RESTendl;
220  fObservableIdSearchMap[obsName] = -1;
221  return -1;
222  }
223  } else {
224  RESTWarning << "TRestAnalysisTree::GetObservableID(): Multiple observables found" << RESTendl;
225  RESTWarning
226  << "Please specify the full observable name (e.g, sAna_ThresholdIntegral) in your code. "
227  << RESTendl;
228  RESTWarning << "Returning the first matched observable : " << fObservableNames[minPos]
229  << RESTendl;
230  fObservableIdSearchMap[obsName] = minPos;
231  return minPos;
232  }
233  }
234  fObservableIdSearchMap[obsName] = -1;
235  return -1;
236 }
237 
243 Bool_t TRestAnalysisTree::ObservableExists(const string& obsName) {
245  return fObservableIdMap.count(obsName) > 0;
246 }
247 
252 // Status | Nbranches | NObservables | Entries | Description
253 // 1. Created | 0 | 0 | 0 | The AnalysisTree is just created in code
254 // 2. Retrieved | >=6 | 0 | >0 | The AnalysisTree is just retrieved from file
255 // 3. EmptyCloned | >=6 | 0 | 0 | The AnalysisTree is cloned from another
256 // tree, it is empty
257 // 4. Connected | >=6 | >=Nbranches-6 | 0 | Local observables are created and connected
258 // to the branches. We can still modify observables in this case.
259 // 5. Filled | >=6 | =NObs | >0 | Local observables are created and connected
260 // to the branches, and entry > 0. We cannot modify observables in this case. if Nbranches == 6, We regard the
261 // tree as Connected/Filled
262 //
263 // Status | AddObs Logic | Fill Logic | GetEntry Logic
264 // 1. Created | Allowed | ->4, ->5 | ->4
265 // 2. Retrieved | Denied | ->5 | ->5
266 // 3. EmptyCloned | ->4 | ->4, ->5 | ->4
267 // 4. Connected | Allowed | ->5 | Allowed
268 // 5. Filled | Denied | Allowed | Allowed
269 //
271  int NBranches = GetListOfBranches()->GetEntriesFast();
272  int NObsInList = fObservables.size();
273  int Entries = GetEntriesFast();
274 
275  // if (fROOTTree != nullptr) {
276  // return TRestAnalysisTree_Status::ROOTTree;
277  //}
278 
279  if (NBranches == 0) {
280  return TRestAnalysisTree_Status::Created;
281  }
282 
283  if (NBranches > 6) {
284  if (NObsInList == 0) {
285  if (Entries > 0) {
286  return TRestAnalysisTree_Status::Retrieved;
287  } else {
288  return TRestAnalysisTree_Status::EmptyCloned;
289  }
290  } else {
291  if (Entries > 0) {
292  return TRestAnalysisTree_Status::Filled;
293  } else {
294  return TRestAnalysisTree_Status::Connected;
295  }
296  }
297  } else if (NBranches == 6) {
298  auto br = (TBranch*)GetListOfBranches()->UncheckedAt(0);
299  if ((int*)br->GetAddress() != &fRunOrigin) {
300  if (Entries > 0) {
301  return TRestAnalysisTree_Status::Retrieved;
302  } else {
303  return TRestAnalysisTree_Status::EmptyCloned;
304  }
305  } else {
306  if (Entries > 0) {
307  return TRestAnalysisTree_Status::Filled;
308  } else {
309  return TRestAnalysisTree_Status::Connected;
310  }
311  }
312  } else {
313  return TRestAnalysisTree_Status::Error;
314  }
315 
316  return TRestAnalysisTree_Status::Error;
317 }
318 
328  // connect basic event branches
329  TBranch* br1 = GetBranch("runOrigin");
330  TBranch* br2 = GetBranch("subRunOrigin");
331  TBranch* br3 = GetBranch("eventID");
332  TBranch* br4 = GetBranch("subEventID");
333  TBranch* br5 = GetBranch("timeStamp");
334  TBranch* br6 = GetBranch("subEventTag");
335 
336  if (br1 && br2 && br3 && br4 && br5 && br6) {
337  br1->SetAddress(&fRunOrigin);
338  br2->SetAddress(&fSubRunOrigin);
339  br3->SetAddress(&fEventID);
340  br4->SetAddress(&fSubEventID);
341  br5->SetAddress(&fTimeStamp);
342  br6->SetAddress(&fSubEventTag);
343  } else {
344  cout << "REST Error: TRestAnalysisTree::ConnectBranches(): event branches does not exist!" << endl;
345  exit(1);
346  }
347 
348  // create observables(no assembly) from stored observable info.
349  fObservables = std::vector<RESTValue>(GetNumberOfObservables());
350  for (int i = 0; i < GetNumberOfObservables(); i++) {
351  fObservables[i] = REST_Reflection::WrapType((string)fObservableTypes[i]);
352  fObservables[i].name = fObservableNames[i];
353  }
355 
356  if (fChain) {
357  fChain->GetEntry(0);
358  } else {
359  TTree::GetEntry(0);
360  }
361 
362  for (int i = 0; i < GetNumberOfObservables(); i++) {
363  TBranch* branch = GetBranch(fObservableNames[i]);
364  if (branch != nullptr) {
365  if (branch->GetAddress() != nullptr) {
366  if ((string)branch->ClassName() != "TBranch") {
367  // for TBranchElement the saved address is char**
368  fObservables[i].address = *(char**)branch->GetAddress();
369  } else {
370  // for TBranch the saved address is char*
371  fObservables[i].address = branch->GetAddress();
372  }
373  } else {
374  fObservables[i].Assembly();
375  branch->SetAddress(fObservables[i].address);
376  }
377  }
378  }
379 
380  fStatus = EvaluateStatus();
381 }
382 
392  if (!GetBranch("runOrigin")) Branch("runOrigin", &fRunOrigin);
393  if (!GetBranch("subRunOrigin")) Branch("subRunOrigin", &fSubRunOrigin);
394  if (!GetBranch("eventID")) Branch("eventID", &fEventID);
395  if (!GetBranch("subEventID")) Branch("subEventID", &fSubEventID);
396  if (!GetBranch("timeStamp")) Branch("timeStamp", &fTimeStamp);
397  if (!GetBranch("subEventTag")) Branch("subEventTag", fSubEventTag);
398 
399  for (int n = 0; n < GetNumberOfObservables(); n++) {
400  TString typeName = fObservableTypes[n];
401  TString brName = fObservableNames[n];
402  char* ref = fObservables[n].address;
403 
404  TBranch* branch = GetBranch(brName);
405  if (branch == nullptr) {
406  if (typeName == "double") {
407  this->Branch(brName, (double*)ref);
408  } else if (typeName == "float") {
409  this->Branch(brName, (float*)ref);
410  } else if (typeName == "long double") {
411  this->Branch(brName, (long double*)ref);
412  } else if (typeName == "bool") {
413  this->Branch(brName, (bool*)ref);
414  } else if (typeName == "char") {
415  this->Branch(brName, (char*)ref);
416  } else if (typeName == "int") {
417  this->Branch(brName, (int*)ref);
418  } else if (typeName == "short") {
419  this->Branch(brName, (short*)ref);
420  } else if (typeName == "unsigned char") {
421  this->Branch(brName, (unsigned char*)ref);
422  } else if (typeName == "unsigned int") {
423  this->Branch(brName, (unsigned int*)ref);
424  } else if (typeName == "unsigned short") {
425  this->Branch(brName, (unsigned short*)ref);
426  } else if (typeName == "long") {
427  this->Branch(brName, (long*)ref);
428  } else if (typeName == "long long") {
429  this->Branch(brName, (long long*)ref);
430  } else if (typeName == "unsigned long") {
431  this->Branch(brName, (unsigned long*)ref);
432  } else if (typeName == "unsigned long long") {
433  this->Branch(brName, (unsigned long long*)ref);
434  } else {
435  this->Branch(brName, typeName, ref);
436  }
437 
438  this->GetBranch(brName)->SetTitle("(" + typeName + ") " + fObservableDescriptions[n]);
439  }
440  }
441 
442  fStatus = EvaluateStatus();
443 }
444 
445 void TRestAnalysisTree::InitObservables() {
446  fObservables = std::vector<RESTValue>(GetNumberOfObservables());
447  for (int i = 0; i < GetNumberOfObservables(); i++) {
448  fObservables[i] = REST_Reflection::WrapType((string)fObservableTypes[i]);
449  fObservables[i].name = fObservableNames[i];
450  }
452 }
453 
460  if (fObservableIdMap.size() != fObservableNames.size()) {
461  fObservableIdMap.clear();
462  for (unsigned int i = 0; i < fObservableNames.size(); i++) {
463  fObservableIdMap[(string)fObservableNames[i]] = i;
464  }
465  if (fObservableIdMap.size() != fObservableNames.size()) {
466  cout << "REST ERROR! duplicated or blank observable name!" << endl;
467  }
468  }
469 }
470 
471 void TRestAnalysisTree::ReadLeafValueToObservable(TLeaf* lf, RESTValue& obs) {
472  if (lf == nullptr || lf->GetLen() == 0) return;
473 
474  if (obs.IsZombie()) {
475  // this means we need to determine the observable type first
476  string type;
477  string leafdef(lf->GetBranch()->GetTitle());
478  if (leafdef.find("[") == string::npos) {
479  // there is no [] mark in the leaf. The leaf is a single values
480  switch (leafdef[leafdef.size() - 1]) {
481  case 'C':
482  type = "string";
483  break;
484  case 'B':
485  type = "char";
486  break;
487  case 'S':
488  type = "stort";
489  break;
490  case 'I':
491  type = "int";
492  break;
493  case 'F':
494  type = "float";
495  break;
496  case 'D':
497  type = "double";
498  break;
499  case 'L':
500  type = "long long";
501  break;
502  case 'O':
503  type = "bool";
504  break;
505  default:
506  RESTError << "Unsupported leaf definition: " << leafdef << "! Assuming int" << RESTendl;
507  type = "int";
508  }
509  } else {
510  switch (leafdef[leafdef.size() - 1]) {
511  case 'I':
512  type = "vector<int>";
513  break;
514  case 'F':
515  type = "vector<float>";
516  break;
517  case 'D':
518  type = "vector<double>";
519  break;
520  default:
521  RESTError << "Unsupported leaf definition: " << leafdef << "! Assuming vector<int>"
522  << RESTendl;
523  type = "vector<int>";
524  }
525  }
526  obs = REST_Reflection::Assembly(type);
527  }
528 
529  // start to fill value
530  if (obs.is_data_type) {
531  // the observable is basic type, we directly set it address from leaf
532  obs.address = (char*)lf->GetValuePointer();
533  } else if (obs.type == "vector<double>") {
534  auto ptr = (double*)lf->GetValuePointer();
535  vector<double> val(ptr, ptr + lf->GetLen());
536  obs.SetValue(val);
537  } else if (obs.type == "vector<int>") {
538  int* ptr = (int*)lf->GetValuePointer();
539  vector<int> val(ptr, ptr + lf->GetLen());
540  obs.SetValue(val);
541  } else if (obs.type == "vector<float>") {
542  auto ptr = (float*)lf->GetValuePointer();
543  vector<float> val(ptr, ptr + lf->GetLen());
544  obs.SetValue(val);
545  } else if (obs.type == "string") {
546  char* ptr = (char*)lf->GetValuePointer();
547  string val(ptr, lf->GetLen());
548  obs.SetValue(val);
549  } else {
550  RESTWarning << "Unsupported observable type to convert from TLeaf!" << RESTendl;
551  }
552 }
553 
554 RESTValue TRestAnalysisTree::GetObservable(const string& obsName) {
555  Int_t id = GetObservableID(obsName);
556  if (id == -1) return {};
557  return GetObservable(id);
558 }
559 
562 RESTValue TRestAnalysisTree::GetObservable(Int_t n) {
563  if (n >= fNObservables) {
564  cout << "Error! TRestAnalysisTree::GetObservable(): index outside limits!" << endl;
565  return {};
566  }
567 
568  if (fChain != nullptr) {
569  return ((TRestAnalysisTree*)fChain->GetTree())->GetObservable(n);
570  }
571 
572  return fObservables[n];
573 }
577  if (n >= fNObservables) {
578  cout << "Error! TRestAnalysisTree::GetObservableName(): index outside limits!" << endl;
579  return "";
580  }
581  return fObservableNames[n];
582 }
586  if (n >= fNObservables) {
587  cout << "Error! TRestAnalysisTree::GetObservableDescription(): index outside limits!" << endl;
588  return "";
589  }
590  return fObservableDescriptions[n];
591 }
595  if (n >= fNObservables) {
596  cout << "Error! TRestAnalysisTree::GetObservableType(): index outside limits!" << endl;
597  return "double";
598  }
599  return fObservableTypes[n];
600 }
603 TString TRestAnalysisTree::GetObservableType(const string& obsName) {
604  Int_t id = GetObservableID(obsName);
605  if (id == -1) return "NotFound";
606  return GetObservableType(id);
607 }
612 Double_t TRestAnalysisTree::GetDblObservableValue(const string& obsName) {
613  return GetDblObservableValue(GetObservableID(obsName));
614 }
620  if (n >= fNObservables) {
621  cout << "Error! TRestAnalysisTree::GetDblObservableValue(): index outside limits!" << endl;
622  return 0;
623  }
624 
625  if (GetObservableType(n) == "int") return GetObservableValue<int>(n);
626  if (GetObservableType(n) == "float") return GetObservableValue<float>(n);
627  if (GetObservableType(n) == "double") return GetObservableValue<double>(n);
628 
629  cout << "TRestAnalysisTree::GetDblObservableValue. Type " << GetObservableType(n)
630  << " not supported! Returning zero" << endl;
631  return 0.;
632 }
633 
634 RESTValue TRestAnalysisTree::AddObservable(const TString& observableName, const TString& observableType,
635  const TString& description) {
636  if (fStatus == None) fStatus = EvaluateStatus();
637 
638  if (fStatus == Created) {
639  } else if (fStatus == Retrieved) {
640  cout << "REST_Warning: cannot add observable for retrieved tree with data!" << endl;
641  return -1;
642  } else if (fStatus == EmptyCloned) {
644  } else if (fStatus == Connected) {
645  } else if (fStatus == Filled) {
646  cout << "REST_Warning: cannot add observable! AnalysisTree is already filled" << endl;
647  return -1;
648  } else if (fChain != nullptr) {
649  cout << "Error! cannot add observable! AnalysisTree is in chain state" << endl;
650  return -1;
651  }
652 
653  if (GetObservableID((string)observableName) == -1) {
654  RESTValue ptr = REST_Reflection::Assembly((string)observableType);
655  ptr.name = observableName;
656  if (!ptr.IsZombie()) {
657  fObservableNames.push_back(observableName);
658  fObservableIdMap[(string)observableName] = fObservableNames.size() - 1;
659  fObservableDescriptions.push_back(description);
660  fObservableTypes.push_back(observableType);
661  fObservables.push_back(ptr);
662 
663  fNObservables++;
664  } else {
665  cout << "Error adding observable \"" << observableName << "\" with type \"" << observableType
666  << "\", type not found!" << endl;
667  return -1;
668  }
669  } else {
670  return GetObservableID((string)observableName);
671  }
672 
673  return fObservables[fNObservables - 1];
674 }
675 
676 void TRestAnalysisTree::PrintObservables() {
677  if (fStatus == None) fStatus = EvaluateStatus();
678 
679  if (fStatus == Created) {
680  } else if (fStatus == Retrieved) {
681  cout << "TRestAnalysisTree::PrintObservables(): Reading entry 0" << endl;
682  GetEntry(0);
683  } else if (fStatus == EmptyCloned) {
684  cout << "REST_Warning: AnalysisTree is empty" << endl;
686  } else if (fStatus == Connected) {
687  cout << "REST_Warning: AnalysisTree is empty" << endl;
688  } else if (fStatus == Filled) {
689  }
690 
691  cout.precision(15);
692  std::cout << "Entry : " << GetReadEntry() << std::endl;
693  std::cout << "> Event ID : " << GetEventID() << std::endl;
694  std::cout << "> Event Time : " << GetTimeStamp() << std::endl;
695  std::cout << "> Event Tag : " << GetSubEventTag() << std::endl;
696  std::cout << "-----------------------------------------" << std::endl;
697  cout.precision(6);
698 
699  for (int n = 0; n < GetNumberOfObservables(); n++) {
700  PrintObservable(n);
701  }
702 }
703 
704 // print the Nth observable in the observal list
705 void TRestAnalysisTree::PrintObservable(int n) {
706  if (n < 0 || n >= fNObservables) {
707  return;
708  }
709  string obsVal = GetObservable(n).ToString();
710  int lengthRemaining = Console::GetWidth() - 14 - 45 - 13;
711 
712  std::cout << "Observable : " << ToString(fObservableNames[n], 45)
713  << " Value : " << ToString(obsVal, lengthRemaining) << std::endl;
714 }
715 
716 Int_t TRestAnalysisTree::GetEntry(Long64_t entry, Int_t getall) {
717  if (fStatus == None) fStatus = EvaluateStatus();
718 
719  if (fStatus == Created) {
720  UpdateBranches();
721  } else if (fStatus == Retrieved) {
723  } else if (fStatus == EmptyCloned) {
725  } else if (fStatus == Connected) {
726  } else if (fStatus == Filled) {
727  }
728 
729  if (fChain != nullptr) {
730  return fChain->GetEntry(entry, getall);
731  } else {
732  return TTree::GetEntry(entry, getall);
733  }
734 }
735 
736 void TRestAnalysisTree::SetEventInfo(TRestAnalysisTree* tree) {
737  if (fChain != nullptr) {
738  cout << "Error! cannot fill tree. AnalysisTree is in chain state" << endl;
739  return;
740  }
741 
742  if (tree != nullptr) {
743  fEventID = tree->GetEventID();
744  fSubEventID = tree->GetSubEventID();
745  fTimeStamp = tree->GetTimeStamp();
746  *fSubEventTag = tree->GetSubEventTag();
747  fRunOrigin = tree->GetRunOrigin();
748  fSubRunOrigin = tree->GetSubRunOrigin();
749  }
750 }
751 
752 void TRestAnalysisTree::SetEventInfo(TRestEvent* evt) {
753  if (fChain != nullptr) {
754  cout << "Error! cannot fill tree. AnalysisTree is in chain state" << endl;
755  return;
756  }
757 
758  if (evt != nullptr) {
759  fEventID = evt->GetID();
760  fSubEventID = evt->GetSubID();
761  fTimeStamp = evt->GetTimeStamp().AsDouble();
762  *fSubEventTag = evt->GetSubEventTag();
763  fRunOrigin = evt->GetRunOrigin();
764  fSubRunOrigin = evt->GetSubRunOrigin();
765  }
766 }
767 
768 Int_t TRestAnalysisTree::Fill() {
769  if (fStatus == None) fStatus = EvaluateStatus();
770 
771  if (fChain != nullptr) {
772  cout << "Error! cannot fill tree. AnalysisTree is in chain state" << endl;
773  return -1;
774  }
775 
776  fSetObservableIndex = 0;
777 
778  if (fStatus == Filled) {
779  return TTree::Fill();
780  } else if (fStatus == Created) {
781  UpdateBranches();
782  int a = TTree::Fill();
783  fStatus = EvaluateStatus();
784  return a;
785  } else if (fStatus == Retrieved) {
787  int a = TTree::Fill();
788  fStatus = EvaluateStatus();
789  return a;
790  } else if (fStatus == EmptyCloned) {
792  int a = TTree::Fill();
793  fStatus = EvaluateStatus();
794  return a;
795  } else if (fStatus == Connected) {
796  UpdateBranches();
797  int a = TTree::Fill();
798  fStatus = EvaluateStatus();
799  return a;
800  }
801  return -1;
802 }
803 
808  if (fChain != nullptr) {
809  cout << "Error! cannot set observable! AnalysisTree is in chain state" << endl;
810  return;
811  }
812  if (id == -1) {
813  // this means we want to find observable id by its name
814  id = GetObservableID(obs.name);
815  // if not found, we have a chance to create observable
816  if (id == -1) {
817  AddObservable(obs.name, obs.type);
818  id = GetObservableID(obs.name);
819  }
820  } else if (id == (int)fObservables.size()) {
821  // this means we want to add observable directly
822  AddObservable(obs.name, obs.type);
823  id = GetObservableID(obs.name);
824  }
825  if (id != -1) {
826  if (obs.type != fObservables[id].type) {
827  // if the observable branches are not created, and the type doesn't match,
828  // we still have the chance to fix. We reset fObservableTypes and fObservableMemory
829  // according to the input type value.
830  cout << "Warning: SetObservableValue(): setting value with different type. Observable : "
831  << obs.name << ", existing type: " << fObservables[id].type
832  << ", value to add is in type: " << obs.type << ", trying to update to the new type."
833  << endl;
834  fObservableTypes[id] = obs.type;
835  string name = fObservables[id].name;
836  fObservables[id].Destroy();
837  fObservables[id] = REST_Reflection::Assembly(obs.type);
838  fObservables[id].name = name;
839  }
840  obs >> fObservables[id];
841  }
842 }
843 
870 void TRestAnalysisTree::SetObservable(string name, RESTValue value) {
871  value.name = name;
872  SetObservable(-1, value);
873 }
874 
882 Bool_t TRestAnalysisTree::EvaluateCuts(const string& cut) {
883  std::vector<string> cuts = Split(cut, "&&", false, true);
884 
885  for (auto& cut : cuts) {
886  if (!EvaluateCut(cut)) {
887  return false;
888  }
889  }
890 
891  return true;
892 }
893 
900 Bool_t TRestAnalysisTree::EvaluateCut(const string& cut) {
901  const std::vector<string> validOperators = {"==", "<=", ">=", "!=", "=", ">", "<"};
902 
903  if (cut.find("&&") != string::npos) return EvaluateCuts(cut);
904 
905  string operation, observable;
906  Double_t value = -1;
907  for (const auto& validOperator : validOperators) {
908  if (cut.find(validOperator) != string::npos) {
909  operation = validOperator;
910  observable = (string)cut.substr(0, cut.find(operation));
911  value = std::stod((string)cut.substr(cut.find(operation) + operation.length(), string::npos));
912  break;
913  }
914  }
915 
916  if (operation.empty())
917  cout << "TRestAnalysisTree::EvaluateCut. Invalid operator in cut definition! " << cut << endl;
918 
919  Double_t val = GetDblObservableValue(observable);
920  if (operation == "==" && value == val) return true;
921  if (operation == "!=" && value != val) return true;
922  if (operation == "<=" && val <= value) return true;
923  if (operation == ">=" && val >= value) return true;
924  if (operation == "=" && val == value) return true;
925  if (operation == ">" && val > value) return true;
926  if (operation == "<" && val < value) return true;
927 
928  return false;
929 }
930 
935 vector<string> TRestAnalysisTree::GetCutObservables(const string& cut_str) {
936  const std::vector<string> validOperators = {"==", "<=", ">=", "!=", "=", ">", "<"};
937 
938  std::vector<string> cuts = Split(cut_str, "&&", false, true);
939 
940  vector<string> obsNames;
941  for (auto& cut : cuts) {
942  string operation, observable;
943  for (const auto& validOperator : validOperators) {
944  if (cut.find(validOperator) != string::npos) {
945  obsNames.push_back((string)cut.substr(0, cut.find(validOperator)));
946  break;
947  }
948  }
949  }
950  return obsNames;
951 }
952 
956 void TRestAnalysisTree::EnableBranches(vector<string> obsNames) {
957  for (auto& obsName : obsNames) this->SetBranchStatus(obsName.c_str(), true);
958 }
959 
963 void TRestAnalysisTree::DisableBranches(vector<string> obsNames) {
964  for (auto& obsName : obsNames) this->SetBranchStatus(obsName.c_str(), false);
965 }
966 
970 void TRestAnalysisTree::EnableAllBranches() { this->SetBranchStatus("*", true); }
971 
975 void TRestAnalysisTree::DisableAllBranches() { this->SetBranchStatus("*", false); }
976 
984 void TRestAnalysisTree::EnableQuickObservableValueSetting() { this->fQuickSetObservableValue = true; }
985 
988 void TRestAnalysisTree::DisableQuickObservableValueSetting() { this->fQuickSetObservableValue = false; }
989 
994 Double_t TRestAnalysisTree::GetObservableIntegral(const TString& obsName, Double_t xLow, Double_t xHigh) {
995  Int_t id = GetObservableID((std::string)obsName);
996 
997  if (id < 0) {
998  RESTError << "TRestAnalysisTree::GetObservableIntegral. Observable not found! : " << obsName
999  << RESTendl;
1000  return 0;
1001  }
1002 
1003  Double_t sum = 0;
1004  for (Int_t n = 0; n < TTree::GetEntries(); n++) {
1005  TTree::GetEntry(n);
1006  Double_t value = GetDblObservableValue(id);
1007 
1008  if (xLow != -1 && xHigh != -1 && (value < xLow || value > xHigh)) continue;
1009  sum += value;
1010  }
1011 
1012  return sum;
1013 }
1014 
1019 Double_t TRestAnalysisTree::GetObservableAverage(const TString& obsName, Double_t xLow, Double_t xHigh) {
1020  Int_t id = GetObservableID((std::string)obsName);
1021 
1022  if (id < 0) {
1023  RESTError << "TRestAnalysisTree::GetObservableAverage. Observable not found! : " << obsName
1024  << RESTendl;
1025  return 0;
1026  }
1027 
1028  Double_t sum = 0;
1029  Int_t N = 0;
1030  for (Int_t n = 0; n < TTree::GetEntries(); n++) {
1031  TTree::GetEntry(n);
1032  Double_t value = GetDblObservableValue(id);
1033 
1034  if (xLow != -1 && xHigh != -1 && (value < xLow || value > xHigh)) continue;
1035  N++;
1036  sum += value;
1037  }
1038 
1039  if (N <= 0) return 0;
1040 
1041  return sum / N;
1042 }
1043 
1048 Double_t TRestAnalysisTree::GetObservableRMS(const TString& obsName, Double_t xLow, Double_t xHigh) {
1049  Double_t mean = GetObservableAverage(obsName, xLow, xHigh);
1050 
1051  Int_t id = GetObservableID((std::string)obsName);
1052 
1053  Double_t sum = 0;
1054  Int_t N = 0;
1055  for (Int_t n = 0; n < TTree::GetEntries(); n++) {
1056  TTree::GetEntry(n);
1057  Double_t value = GetDblObservableValue(id);
1058 
1059  if (xLow != -1 && xHigh != -1 && (value < xLow || value > xHigh)) continue;
1060  N++;
1061 
1062  sum += (value - mean) * (value - mean);
1063  }
1064 
1065  if (N <= 0) return 0;
1066 
1067  return TMath::Sqrt(sum / N);
1068 }
1069 
1074 Double_t TRestAnalysisTree::GetObservableMaximum(const TString& obsName, Double_t xLow, Double_t xHigh) {
1075  Int_t id = GetObservableID((std::string)obsName);
1076 
1077  if (id < 0) {
1078  RESTError << "TRestAnalysisTree::GetObservableMaximum. Observable not found! : " << obsName
1079  << RESTendl;
1080  return 0;
1081  }
1082 
1083  Double_t max = -DBL_MAX;
1084  for (Int_t n = 0; n < TTree::GetEntries(); n++) {
1085  TTree::GetEntry(n);
1086  Double_t value = GetDblObservableValue(id);
1087 
1088  if (xLow != -1 && xHigh != -1 && (value < xLow || value > xHigh)) continue;
1089  if (value > max) max = value;
1090  }
1091 
1092  return max;
1093 }
1094 
1099 Double_t TRestAnalysisTree::GetObservableMinimum(const TString& obsName, Double_t xLow, Double_t xHigh) {
1100  Int_t id = GetObservableID((std::string)obsName);
1101 
1102  if (id < 0) {
1103  RESTError << "TRestAnalysisTree::GetObservableMinimum. Observable not found! : " << obsName
1104  << RESTendl;
1105  return 0;
1106  }
1107 
1108  Double_t min = DBL_MAX;
1109  for (Int_t n = 0; n < TTree::GetEntries(); n++) {
1110  TTree::GetEntry(n);
1111  Double_t value = GetDblObservableValue(id);
1112 
1113  if (xLow != -1 && xHigh != -1 && (value < xLow || value > xHigh)) continue;
1114  if (value < min) min = value;
1115  }
1116 
1117  return min;
1118 }
1119 
1144 Double_t TRestAnalysisTree::GetObservableContour(const TString& obsName, const TString& obsWeight,
1145  Double_t level, Int_t nBins, Double_t xLow, Double_t xHigh) {
1146  if (level > 1 || level < 0) {
1147  RESTWarning << "Level is : " << level << RESTendl;
1148  RESTWarning << "Level must be between 0 and 1" << RESTendl;
1149  return 0;
1150  }
1151 
1152  Double_t integral = this->GetIntegral(obsWeight, xLow, xHigh);
1153 
1154  TString histDefinition = Form("hc(%5d,%lf,%lf)", nBins, xLow, xHigh);
1155  if (xHigh == -1)
1156  this->Draw(obsName + ">>hc", obsWeight);
1157  else
1158  this->Draw(obsName + ">>" + histDefinition, obsWeight);
1159 
1160  TH1F* htemp = (TH1F*)gPad->GetPrimitive("hc");
1161 
1162  Double_t sum = 0;
1163  for (int i = 0; i < htemp->GetNbinsX(); i++) {
1164  sum += htemp->GetBinContent(i + 1);
1165 
1166  if (sum > level * integral) return htemp->GetBinCenter(i + 1);
1167  }
1168  return 0;
1169 }
1170 
1175 
1176 std::vector<std::string> TRestAnalysisTree::GetObservableNames() {
1177  std::vector<std::string> names;
1178 
1179  auto branches = GetListOfBranches();
1180  for (int i = 0; i < branches->GetEntries(); i++) {
1181  names.push_back((string)branches->At(i)->GetName());
1182  }
1183 
1184  return names;
1185 }
1186 
1190 Int_t TRestAnalysisTree::WriteAsTTree(const char* name, Int_t option, Int_t bufsize) {
1191  TTree* tree = new TTree();
1192 
1193  char* dest = (char*)tree + sizeof(TObject);
1194  char* from = (char*)this + sizeof(TObject);
1195 
1196  constexpr size_t n = sizeof(TTree) - sizeof(TObject);
1197 
1198  // copy the data of the created TTree to a temporary location
1199  char* temp = (char*)malloc(n);
1200  memcpy(temp, dest, n);
1201 
1202  // copy the data of this TRestAnalysisTree to TTree, and call the new TTree to write
1203  memcpy(dest, from, n);
1204  int result = tree->Write(name, option, bufsize);
1205 
1206  // restore the data of the created TTree, then we can free it!
1207  memcpy(dest, temp, n);
1208  free(temp);
1209  delete tree;
1210 
1211  return result;
1212 }
1213 
1219 Bool_t TRestAnalysisTree::AddChainFile(const string& _file) {
1220  auto file = std::unique_ptr<TFile>{TFile::Open(_file.c_str(), "update")};
1221  if (!file->IsOpen()) {
1222  RESTWarning << "TRestAnalysisTree::AddChainFile(): failed to open file " << _file << RESTendl;
1223  return false;
1224  }
1225 
1226  if (this->GetRunOrigin() == 0) {
1227  this->GetEntry(0);
1228  }
1229 
1230  auto tree = (TRestAnalysisTree*)file->Get("AnalysisTree");
1231  if (tree != nullptr && tree->GetEntry(0)) {
1232  if (tree->GetEntry(0) > 0) {
1233  if (tree->GetRunOrigin() == this->GetRunOrigin()) {
1234  // this is a valid tree
1235  delete tree;
1236 
1237  if (fChain == nullptr) {
1238  fChain = new TChain("AnalysisTree", "Chained AnalysisTree");
1239  fChain->Add(this->GetCurrentFile()->GetName());
1240  }
1241  return fChain->Add(_file.c_str()) == 1;
1242  }
1243  RESTWarning
1244  << "TRestAnalysisTree::AddChainFile(): invalid file, AnalysisTree in file has different "
1245  "run id!"
1246  << RESTendl;
1247  }
1248  RESTWarning << "TRestAnalysisTree::AddChainFile(): invalid file, AnalysisTree in file is empty!"
1249  << RESTendl;
1250  delete tree;
1251  }
1252  RESTWarning << "TRestAnalysisTree::AddChainFile(): invalid file, file does not contain an AnalysisTree!"
1253  << RESTendl;
1254 
1255  return false;
1256 }
1257 
1264  if (fChain == nullptr) {
1265  return TTree::GetTree();
1266  }
1267  return (TTree*)fChain;
1268 }
1269 
1276 Long64_t TRestAnalysisTree::LoadTree(Long64_t entry) {
1277  if (fChain == nullptr) {
1278  return TTree::LoadTree(entry);
1279  } else {
1280  return fChain->LoadTree(entry);
1281  }
1282 
1283  return -2;
1284 }
1285 
1286 Long64_t TRestAnalysisTree::GetEntries() const {
1287  if (fChain == nullptr) {
1288  return TTree::GetEntries();
1289  }
1290  return fChain->GetEntries();
1291 }
1292 
1293 Long64_t TRestAnalysisTree::GetEntries(const char* sel) {
1294  if (fChain == nullptr) {
1295  return TTree::GetEntries(sel);
1296  }
1297  return fChain->GetEntries(sel);
1298 }
1299 
1300 TRestAnalysisTree::~TRestAnalysisTree() { delete fSubEventTag; }
void SetValue(const T &val)
Set the value of the wrapped type.
std::string type
Type of the wrapped object.
char * address
Address of the wrapped object.
bool is_data_type
Pointer to the corresponding TDataType helper, if the wrapped object is in data type.
bool IsZombie() const
If this object type wrapper is invalid.
std::string ToString() const
Convert the wrapped object to std::string.
std::string name
Name field.
REST core data-saving helper based on TTree.
TString GetObservableDescription(Int_t n)
Get the observable description according to id.
void DisableQuickObservableValueSetting()
It will disable quick observable value setting.
std::vector< std::string > GetCutObservables(const std::string &cut_str)
It will return a list with the names found in a string with conditions, as given in methods as Evalua...
void UpdateObservables()
Update observables stored in the tree.
Double_t GetObservableContour(const TString &obsName, const TString &obsIndexer, Double_t level=0.5, Int_t nBins=-1, Double_t xLow=-1, Double_t xHigh=-1)
This method generates a histogram of the the observable obsName given in the argument weighting it wi...
void EnableAllBranches()
It will enable all branches in the tree.
void EnableQuickObservableValueSetting()
It will enable quick observable value setting.
Long64_t LoadTree(Long64_t entry)
Overrides TTree::LoadTree(), to set current tree according to the given entry number,...
Bool_t AddChainFile(const std::string &file)
Add a series output file like TChain.
TString GetObservableName(Int_t n)
Get the observable name according to id.
void UpdateBranches()
Update branches in the tree.
Double_t GetObservableIntegral(const TString &obsName, Double_t xLow=-1, Double_t xHigh=-1)
It returns the integral of the observable considering the given range. If no range is given the full ...
TChain * fChain
used for quick search of certain observables
Bool_t EvaluateCuts(const std::string &expression)
This method will receive a string with several analysis observables/cuts in the same fashion as used ...
TTree * GetTree() const
Overrides TTree::GetTree(), to get the actual tree used in case of chain operation(fCurrentTree !...
Double_t GetObservableMaximum(const TString &obsName, Double_t xLow=-1, Double_t xHigh=-1)
It returns the maximum value of obsName considering the given range. If no range is given the full hi...
Int_t GetObservableID(const std::string &obsName)
Get the index of the specified observable.
void MakeObservableIdMap()
Update the map of observable name to observable id.
Int_t GetMatchedObservableID(const std::string &obsName)
Get the index of the observable, erasing the prefix if exists.
Double_t GetObservableAverage(const TString &obsName, Double_t xLow=-1, Double_t xHigh=-1)
It returns the average of the observable considering the given range. If no range is given the full h...
void DisableBranches(std::vector< std::string > obsNames)
It will disable the branches given by argument.
Double_t GetObservableRMS(const TString &obsName, Double_t xLow=-1, Double_t xHigh=-1)
It returns the RMS of the observable considering the given range. If no range is given the full histo...
Double_t GetDblObservableValue(const std::string &obsName)
Get double value of the observable, according to the name.
TString GetObservableType(Int_t n)
Get the observable type according to id.
std::vector< std::string > GetObservableNames()
It returns a vector with strings containing all the observables that exist in the analysis tree.
void DisableAllBranches()
It will disable all branches in the tree.
Double_t GetObservableMinimum(const TString &obsName, Double_t xLow=-1, Double_t xHigh=-1)
It returns the minimum value of obsName considering the given range. If no range is given the full hi...
int EvaluateStatus()
Evaluate the Status of this tree.
Bool_t ObservableExists(const std::string &obsName)
Get if the specified observable exists.
Int_t fNObservables
in case multiple files for reading
void EnableBranches(std::vector< std::string > obsNames)
It will enable the branches given by argument.
Bool_t EvaluateCut(const std::string &expression)
This method will evaluate a condition on one analysis observable constructed as "observable>value"....
void SetObservable(Int_t id, RESTValue obs)
Set the value of observable whose id is as specified.
Int_t WriteAsTTree(const char *name=0, Int_t option=0, Int_t bufsize=0)
It writes TRestAnalysisTree as TTree, in order to migrate files to pure ROOT users.
A base class for any REST event.
Definition: TRestEvent.h:38
TRestReflector WrapType(const std::string &typeName)
Wrap information an object of type: typeName, memory is not allocated.
TRestReflector Assembly(const std::string &typeName)
Assembly an object of type: typeName, returning the allocated memory address and size.
std::vector< std::string > Split(std::string in, std::string separator, bool allowBlankString=false, bool removeWhiteSpaces=false, int startPos=-1)
Split the input string according to the given separator. Returning a vector of fragments.
Int_t DiffString(const std::string &source, const std::string &target)
Returns the number of different characters between two strings.