Belle II Software development
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
25using namespace Belle2;
26
27const std::string RootIOUtilities::c_treeNames[] = { "tree", "persistent" };
28const std::string RootIOUtilities::c_SteerBranchNames[] = { "branchNames", "branchNamesPersistent" };
29const std::string RootIOUtilities::c_SteerExcludeBranchNames[] = { "excludeBranchNames", "excludeBranchNamesPersistent" };
30const std::string RootIOUtilities::c_SteerAdditionalBranchNames[] = { "additionalBranchNames", "additionalBranchNamesPersistent" };
31
32std::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;
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 std::set<std::string> excluderelations;
60 if (!excludeBranchSet.empty()) {
61 //remove relations for excluded things
62 for (const std::string& from : branchesToFilter) {
63 for (const std::string& to : branchesToFilter) {
64 std::string branch = DataStore::relationName(from, to);
65 if (out.count(branch) == 0)
66 continue; //not selected
67 if (excludeBranchSet.count(from) == 0 and excludeBranchSet.count(to) == 0)
68 continue; //at least one side should be excluded
69 if (branchSet.count(branch) != 0)
70 continue; //specifically included
71 excluderelations.insert(branch);
72 }
73 }
74 for (const std::string& rel : excluderelations) {
75 out.erase(rel);
76 }
77 }
78 //add relations between accepted branches
79 std::set<std::string> relations;
80 for (const std::string& from : out) {
81 for (const std::string& to : out) {
82 std::string branch = DataStore::relationName(from, to);
83 if (branchesToFilter.count(branch) == 0)
84 continue; //not in input
85 if (excludeBranchSet.count(branch))
86 continue;
87 relations.insert(branch);
88 }
89 }
90 out.insert(relations.begin(), relations.end());
91 return out;
92}
93
94size_t RootIOUtilities::setBranchStatus(TBranch* branch, bool process)
95{
96 size_t found{0};
97 std::queue<TBranch*> branches;
98 branches.emplace(branch);
99 while (!branches.empty()) {
100 ++found;
101 auto* current = branches.front();
102 branches.pop();
103 // set the flag we need
104 if (process) current->ResetBit(kDoNotProcess);
105 else current->SetBit(kDoNotProcess);
106 // add all children to the queue
107 auto* children = current->GetListOfBranches();
108 const auto nchildren = children->GetEntriesFast();
109 for (int i = 0; i < nchildren; ++i) {
110 branches.emplace(dynamic_cast<TBranch*>(children->UncheckedAt(i)));
111 }
112 }
113 return found;
114}
115
116std::vector<std::string> RootIOUtilities::expandWordExpansions(const std::vector<std::string>& filenames)
117{
118 std::vector<std::string> out;
119 wordexp_t expansions;
120 wordexp("", &expansions, 0);
121 for (const std::string& pattern : filenames) {
122 if (wordexp(pattern.c_str(), &expansions, WRDE_APPEND | WRDE_NOCMD | WRDE_UNDEF) != 0) {
123 B2ERROR("Failed to expand pattern '" << pattern << "'!");
124 }
125 }
126 out.resize(expansions.we_wordc);
127 for (unsigned int i = 0; i < expansions.we_wordc; i++) {
128 out[i] = expansions.we_wordv[i];
129 }
130 wordfree(&expansions);
131 return out;
132}
133
134
135long RootIOUtilities::getEntryNumberWithEvtRunExp(TTree* tree, long event, long run, long experiment)
136{
137 const long major = 1000000 * experiment + run;
138 const long minor = event;
139
140 if (!tree->GetTreeIndex()) {
141 B2DEBUG(100, "No TTreeIndex found, rebuild it...");
142 buildIndex(tree);
143 }
144 long entry = tree->GetEntryNumberWithIndex(major, minor);
145
146 if (entry == -1) {
147 //should be handled by caller
148 B2DEBUG(100, "Couldn't find entry (" << event << ", " << run << ", " << experiment << ") in file! (major index: " << major <<
149 ", minor index: " << minor << ")");
150 }
151 return entry;
152}
153
155{
156 std::string treeName = tree->GetName();
157 TBranch* const EventMetaDataBranch = tree->GetBranch("EventMetaData");
158 if ((strcmp(treeName.c_str(), "tree") == 0) && EventMetaDataBranch) {
159 tree->BuildIndex("1000000*EventMetaData.m_experiment+EventMetaData.m_run", "EventMetaData.m_event");
160 }
161 // for ntuple trees that do not have EventMetaData branch we use the tree level branches
162 else {
163 std::string key = "1000000*" + treeName + ".__experiment__+" + treeName + ".__run__";
164 std::string event = treeName + ".__event__";
165 tree->BuildIndex(key.c_str(), event.c_str());
166 }
167}
168
169bool RootIOUtilities::hasStreamer(const TClass* cl)
170{
171 if (cl == TObject::Class())
172 return false;
173
174 if (cl->GetClassVersion() <= 0) {
175 // version number == 0 means no streamers for this class, check base classes
176 TList* baseClasses = const_cast<TClass*>(cl)->GetListOfBases(); //method might update an internal cache, but is const otherwise
177 TIter it(baseClasses);
178 while (auto* base = static_cast<TBaseClass*>(it())) {
179 if (hasStreamer(base->GetClassPointer()))
180 return true;
181 }
182 //nothing found
183 return false;
184 } else {
185 return true;
186 }
187}
188
189
191{
192 // Does this class have a custom streamer?
193 return cl->HasCustomStreamerMember();
194}
195
197{
198 std::string site;
199 char date[100];
200 auto now = time(nullptr);
201 strftime(date, 100, "%Y-%m-%d %H:%M:%S", gmtime(&now));
202 const char* belle2_site = getenv("BELLE2_SITE");
203 if (belle2_site) {
204 site = belle2_site;
205 } else {
206 char hostname[1024];
207 gethostname(hostname, 1023); //will not work well for ipv6
208 hostname[1023] = '\0'; //if result is truncated, terminating null byte may be missing
209 site = hostname;
210 }
211 const char* user = getenv("BELLE2_USER");
212 if (!user) user = getenv("USER");
213 if (!user) user = getlogin();
214 if (!user) user = "unknown";
215 auto commitid = RootIOUtilities::getCommitID();
216 metadata.setCreationData(date, site, user, commitid);
217}
218
220{
221 return GIT_COMMITID;
222}
223
224bool RootIOUtilities::isReservedTreeName(const std::string& name)
225{
226 return std::any_of(std::begin(RootIOUtilities::c_treeNames),
228 [&name](const std::string & s) { return s == name; });
229}
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.
void setCreationData(const std::string &date, const std::string &site, const std::string &user, const std::string &release)
Creation data setter.
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.
bool isReservedTreeName(const std::string &name)
Check whether a tree name is a reserved basf2 tree name as defined in RootIOUtilities::c_treeNames.
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 either EventMetaData branch exists or is a ntuple tree).
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.