Belle II Software  release-08-01-10
RootIOUtilities.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <framework/io/RootIOUtilities.h>
9 
10 #include <framework/datastore/DataStore.h>
11 #include <framework/dataobjects/FileMetaData.h>
12 #include <framework/logging/Logger.h>
13 
14 #include <RVersion.h>
15 #include <TTree.h>
16 #include <TList.h>
17 #include <TClass.h>
18 #include <TBaseClass.h>
19 #include <TSystem.h>
20 
21 #include <wordexp.h>
22 
23 #include <queue>
24 
25 using namespace Belle2;
26 
27 const std::string RootIOUtilities::c_treeNames[] = { "tree", "persistent" };
28 const std::string RootIOUtilities::c_SteerBranchNames[] = { "branchNames", "branchNamesPersistent" };
29 const std::string RootIOUtilities::c_SteerExcludeBranchNames[] = { "excludeBranchNames", "excludeBranchNamesPersistent" };
30 const std::string RootIOUtilities::c_SteerAdditionalBranchNames[] = { "additionalBranchNames", "additionalBranchNamesPersistent" };
31 
32 std::set<std::string> RootIOUtilities::filterBranches(const std::set<std::string>& branchesToFilter,
33  const std::vector<std::string>& branches,
34  const std::vector<std::string>& excludeBranches, int durability, bool quiet)
35 {
36  std::set<std::string> branchSet, excludeBranchSet;
37  for (const std::string& b : branches) {
38  if (branchesToFilter.count(b) == 0 and not quiet)
39  B2WARNING("The branch " << b << " given in " << c_SteerBranchNames[durability] << " does not exist.");
40  if (!branchSet.insert(b).second and not quiet)
41  B2WARNING(c_SteerBranchNames[durability] << " has duplicate entry " << b);
42  }
43  for (const std::string& b : excludeBranches) {
44  // FIXME: ProcessStatistics is excluded by default but not always present. We should switch that to not write it out
45  // in the first place but the info message is meaningless for almost everyone
46  if (branchesToFilter.count(b) == 0 and not quiet and b != "ProcessStatistics")
47  B2INFO("The branch " << b << " given in " << c_SteerExcludeBranchNames[durability] << " does not exist.");
48  if (!excludeBranchSet.insert(b).second and not quiet)
49  B2WARNING(c_SteerExcludeBranchNames[durability] << " has duplicate entry " << b);
50  }
51 
52  std::set<std::string> out, relations, excluderelations;
53  for (const std::string& branch : branchesToFilter) {
54  if (excludeBranchSet.count(branch))
55  continue;
56  if (branchSet.empty() or branchSet.count(branch))
57  out.insert(branch);
58  }
59  if (!excludeBranchSet.empty()) {
60  //remove relations for excluded things
61  for (const std::string& from : branchesToFilter) {
62  for (const std::string& to : branchesToFilter) {
63  std::string branch = DataStore::relationName(from, to);
64  if (out.count(branch) == 0)
65  continue; //not selected
66  if (excludeBranchSet.count(from) == 0 and excludeBranchSet.count(to) == 0)
67  continue; //at least one side should be excluded
68  if (branchSet.count(branch) != 0)
69  continue; //specifically included
70  excluderelations.insert(branch);
71  }
72  }
73  for (const std::string& rel : excluderelations) {
74  out.erase(rel);
75  }
76  }
77  //add relations between accepted branches
78  for (const std::string& from : out) {
79  for (const std::string& to : out) {
80  std::string branch = DataStore::relationName(from, to);
81  if (branchesToFilter.count(branch) == 0)
82  continue; //not in input
83  if (excludeBranchSet.count(branch))
84  continue;
85  relations.insert(branch);
86  }
87  }
88  out.insert(relations.begin(), relations.end());
89  return out;
90 }
91 
92 size_t RootIOUtilities::setBranchStatus(TBranch* branch, bool process)
93 {
94  size_t found{0};
95  std::queue<TBranch*> branches;
96  branches.emplace(branch);
97  while (!branches.empty()) {
98  ++found;
99  auto* current = branches.front();
100  branches.pop();
101  // set the flag we need
102  if (process) current->ResetBit(kDoNotProcess);
103  else current->SetBit(kDoNotProcess);
104  // add all children to the queue
105  auto* children = current->GetListOfBranches();
106  const auto nchildren = children->GetEntriesFast();
107  for (int i = 0; i < nchildren; ++i) {
108  branches.emplace(dynamic_cast<TBranch*>(children->UncheckedAt(i)));
109  }
110  }
111  return found;
112 }
113 
114 std::vector<std::string> RootIOUtilities::expandWordExpansions(const std::vector<std::string>& filenames)
115 {
116  std::vector<std::string> out;
117  wordexp_t expansions;
118  wordexp("", &expansions, 0);
119  for (const std::string& pattern : filenames) {
120  if (wordexp(pattern.c_str(), &expansions, WRDE_APPEND | WRDE_NOCMD | WRDE_UNDEF) != 0) {
121  B2ERROR("Failed to expand pattern '" << pattern << "'!");
122  }
123  }
124  out.resize(expansions.we_wordc);
125  for (unsigned int i = 0; i < expansions.we_wordc; i++) {
126  out[i] = expansions.we_wordv[i];
127  }
128  wordfree(&expansions);
129  return out;
130 }
131 
132 
133 long RootIOUtilities::getEntryNumberWithEvtRunExp(TTree* tree, long event, long run, long experiment)
134 {
135  const long major = 1000000 * experiment + run;
136  const long minor = event;
137 
138  if (!tree->GetTreeIndex()) {
139  B2DEBUG(100, "No TTreeIndex found, rebuild it...");
140  buildIndex(tree);
141  }
142  long entry = tree->GetEntryNumberWithIndex(major, minor);
143 
144  if (entry == -1) {
145  //should be handled by caller
146  B2DEBUG(100, "Couldn't find entry (" << event << ", " << run << ", " << experiment << ") in file! (major index: " << major <<
147  ", minor index: " << minor << ")");
148  }
149  return entry;
150 }
151 
153 {
154  tree->BuildIndex("1000000*EventMetaData.m_experiment+EventMetaData.m_run", "EventMetaData.m_event");
155 }
156 
157 bool RootIOUtilities::hasStreamer(const TClass* cl)
158 {
159  if (cl == TObject::Class())
160  return false;
161 
162  if (cl->GetClassVersion() <= 0) {
163  // version number == 0 means no streamers for this class, check base classes
164  TList* baseClasses = const_cast<TClass*>(cl)->GetListOfBases(); //method might update an internal cache, but is const otherwise
165  TIter it(baseClasses);
166  while (auto* base = static_cast<TBaseClass*>(it())) {
167  if (hasStreamer(base->GetClassPointer()))
168  return true;
169  }
170  //nothing found
171  return false;
172  } else {
173  return true;
174  }
175 }
176 
177 
179 {
180  //does this class have a custom streamer? (magic from from TTree.cxx)
181  return cl->TestBit(TClass::kHasCustomStreamerMember);
182 }
183 
185 {
186  std::string site;
187  char date[100];
188  auto now = time(nullptr);
189  strftime(date, 100, "%Y-%m-%d %H:%M:%S", gmtime(&now));
190  const char* belle2_site = getenv("BELLE2_SITE");
191  if (belle2_site) {
192  site = belle2_site;
193  } else {
194  char hostname[1024];
195  gethostname(hostname, 1023); //will not work well for ipv6
196  hostname[1023] = '\0'; //if result is truncated, terminating null byte may be missing
197  site = hostname;
198  }
199  const char* user = getenv("BELLE2_USER");
200  if (!user) user = getenv("USER");
201  if (!user) user = getlogin();
202  if (!user) user = "unknown";
203  auto commitid = RootIOUtilities::getCommitID();
204  metadata.setCreationData(date, site, user, commitid);
205 }
206 
208 {
209  return GIT_COMMITID;
210 }
static std::string relationName(const std::string &fromName, const std::string &toName, std::string const &namedRelation="")
Return storage name for a relation between two arrays of the given names.
Definition: DataStore.h:180
Metadata information about a file.
Definition: FileMetaData.h:29
bool hasCustomStreamer(const TClass *cl)
Returns true if and only if 'cl' has a user-defined streamer.
const std::string c_treeNames[]
Names of trees.
const std::string c_SteerExcludeBranchNames[]
Steering parameter names for m_excludeBranchNames.
std::string getCommitID()
Return git SHA1 hashes taking into account local & central release.
std::vector< std::string > expandWordExpansions(const std::vector< std::string > &filenames)
Performs wildcard expansion using wordexp(), returns matches.
const std::string c_SteerBranchNames[]
Steering parameter names for m_branchNames.
void setCreationData(FileMetaData &metadata)
Fill the creation info of a file meta data: site, user, data.
std::set< std::string > filterBranches(const std::set< std::string > &branchesToFilter, const std::vector< std::string > &branches, const std::vector< std::string > &excludeBranches, int durability, bool quiet=false)
Given a list of input branches and lists of branches to include/exclude, returns a list of branches t...
const std::string c_SteerAdditionalBranchNames[]
Steering parameter names for m_additionalBranchNames.
long getEntryNumberWithEvtRunExp(TTree *tree, long event, long run, long experiment)
return entry number with given (event, run, experiment) from tree.
void buildIndex(TTree *tree)
Build TTreeIndex on tree (assumes EventMetaData branch exists there).
bool hasStreamer(const TClass *cl)
Returns true if and only if 'cl' or one of its bases has I/O streamers.
size_t setBranchStatus(TBranch *branch, bool process)
Set Branch to be read or not.
Abstract base class for different kinds of events.