Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
InternalTreeUtils.cxx
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
3 * All rights reserved. *
4 * *
5 * For the licensing terms see $ROOTSYS/LICENSE. *
6 * For the list of contributors see $ROOTSYS/README/CREDITS. *
7 *************************************************************************/
8
10#include "TTree.h"
11#include "TChain.h"
12#include "TFile.h"
13#include "TFriendElement.h"
14
15#include <utility> // std::pair
16#include <vector>
17#include <stdexcept> // std::runtime_error
18#include <string>
19
20namespace ROOT {
21namespace Internal {
22namespace TreeUtils {
23
24////////////////////////////////////////////////////////////////////////////////
25/// \brief Add information of a single friend.
26///
27/// \param[in] treeName Name of the tree.
28/// \param[in] fileNameGlob Path to the file. Refer to TChain::Add for globbing rules.
29/// \param[in] alias Alias for this friend.
30void RFriendInfo::AddFriend(const std::string &treeName, const std::string &fileNameGlob, const std::string &alias)
31{
32 fFriendNames.emplace_back(std::make_pair(treeName, alias));
33 fFriendFileNames.emplace_back(std::vector<std::string>{fileNameGlob});
34 fFriendChainSubNames.emplace_back();
35}
36
37////////////////////////////////////////////////////////////////////////////////
38/// \brief Add information of a single friend.
39///
40/// \param[in] treeName Name of the tree.
41/// \param[in] fileNameGlobs Paths to the files. Refer to TChain::Add for globbing rules.
42/// \param[in] alias Alias for this friend.
43void RFriendInfo::AddFriend(const std::string &treeName, const std::vector<std::string> &fileNameGlobs,
44 const std::string &alias)
45{
46 fFriendNames.emplace_back(std::make_pair(treeName, alias));
47 fFriendFileNames.emplace_back(fileNameGlobs);
48 fFriendChainSubNames.emplace_back(std::vector<std::string>(fileNameGlobs.size(), treeName));
49}
50
51////////////////////////////////////////////////////////////////////////////////
52/// \brief Add information of a single friend.
53///
54/// \param[in] treeAndFileNameGlobs Pairs of (treename, filename). Refer to TChain::Add for globbing rules.
55/// \param[in] alias Alias for this friend.
56void RFriendInfo::AddFriend(const std::vector<std::pair<std::string, std::string>> &treeAndFileNameGlobs,
57 const std::string &alias)
58{
59 fFriendNames.emplace_back(std::make_pair("", alias));
60
61 fFriendFileNames.emplace_back();
62 fFriendChainSubNames.emplace_back();
63
64 auto &theseFileNames = fFriendFileNames.back();
65 auto &theseChainSubNames = fFriendChainSubNames.back();
66 auto nPairs = treeAndFileNameGlobs.size();
67 theseFileNames.reserve(nPairs);
68 theseChainSubNames.reserve(nPairs);
69
70 auto fSubNamesIt = std::back_inserter(theseChainSubNames);
71 auto fNamesIt = std::back_inserter(theseFileNames);
72
73 for (const auto &names : treeAndFileNameGlobs) {
74 *fSubNamesIt = names.first;
75 *fNamesIt = names.second;
76 }
77}
78
79////////////////////////////////////////////////////////////////////////////////
80/// \fn std::vector<std::string> GetFileNamesFromTree(const TTree &tree)
81/// \ingroup tree
82/// \brief Get and store the file names associated with the input tree.
83/// \param[in] tree The tree from which friends information will be gathered.
84/// \throws std::runtime_error If no files could be associated with the input tree.
85std::vector<std::string> GetFileNamesFromTree(const TTree &tree)
86{
87 std::vector<std::string> filenames;
88
89 // If the input tree is a TChain, traverse its list of associated files.
90 if (auto chain = dynamic_cast<const TChain *>(&tree)) {
91 const auto *chainFiles = chain->GetListOfFiles();
92 if (!chainFiles) {
93 throw std::runtime_error("Could not retrieve a list of files from the input TChain.");
94 }
95 // Store this in a variable so it can be later used in `filenames.reserve`
96 // if it passes the check.
97 const auto nfiles = chainFiles->GetEntries();
98 if (nfiles == 0) {
99 throw std::runtime_error("The list of files associated with the input TChain is empty.");
100 }
101 filenames.reserve(nfiles);
102 for (const auto *f : *chainFiles)
103 filenames.emplace_back(f->GetTitle());
104 } else {
105 const TFile *f = tree.GetCurrentFile();
106 if (!f) {
107 throw std::runtime_error("The input TTree is not linked to any file, "
108 "in-memory-only trees are not supported.");
109 }
110
111 filenames.emplace_back(f->GetName());
112 }
113
114 return filenames;
115}
116
117////////////////////////////////////////////////////////////////////////////////
118/// \fn RFriendInfo GetFriendInfo(const TTree &tree)
119/// \ingroup tree
120/// \brief Get and store the names, aliases and file names of the direct friends of the tree.
121/// \param[in] tree The tree from which friends information will be gathered.
122/// \throws std::runtime_error If the input tree has a list of friends, but any
123/// of them could not be associated with any file.
124///
125/// Calls TTree::GetListOfFriends and parses its result for the names, aliases
126/// and file names, with different methodologies depending on whether the
127/// parameter is a TTree or a TChain.
128///
129/// \note This function only retrieves information about <b>direct friends</b>
130/// of the input tree. It will not recurse through friends of friends and
131/// does not take into account circular references in the list of friends
132/// of the input tree.
133///
134/// \returns An RFriendInfo struct, containing the information parsed from the
135/// list of friends. The struct will contain three vectors, which elements at
136/// position `i` represent the `i`-th friend of the input tree. If this friend
137/// is a TTree, the `i`-th element of each of the three vectors will contain
138/// respectively:
139/// - A pair with the name and alias of the tree (the alias might not be
140/// present, in which case it will be just an empty string).
141/// - A vector with a single string representing the path to current file where
142/// the tree is stored.
143/// - An empty vector.
144/// .
145/// If the `i`-th friend is a TChain instead, the `i`-th element of each of the
146/// three vectors will contain respectively:
147/// - A pair with the name and alias of the chain (if present, both might be
148/// empty strings).
149/// - A vector with all the paths to the files contained in the chain.
150/// - A vector with all the the names of the trees making up the chain,
151/// associated with the file names of the previous vector.
153{
154 std::vector<NameAlias> friendNames;
155 std::vector<std::vector<std::string>> friendFileNames;
156 std::vector<std::vector<std::string>> friendChainSubNames;
157
158 // Typically, the correct way to call GetListOfFriends would be `tree.GetTree()->GetListOfFriends()`
159 // (see e.g. the discussion at https://github.com/root-project/root/issues/6741).
160 // However, in this case, in case we are dealing with a TChain we really only care about the TChain's
161 // list of friends (which will need to be rebuilt in each processing task) while friends of the TChain's
162 // internal TTree, if any, will be automatically loaded in each task just like they would be automatically
163 // loaded here if we used tree.GetTree()->GetListOfFriends().
164 const auto *friends = tree.GetListOfFriends();
165 if (!friends)
166 return RFriendInfo();
167
168 for (auto fr : *friends) {
169 // Can't pass fr as const TObject* because TFriendElement::GetTree is not const.
170 // Also, we can't retrieve frTree as const TTree* because of TTree::GetFriendAlias(TTree *) a few lines later
171 auto frTree = static_cast<TFriendElement *>(fr)->GetTree();
172
173 // The vector of (name,alias) pairs of the current friend
174 friendFileNames.emplace_back();
175 auto &fileNames = friendFileNames.back();
176
177 // The vector of names of sub trees of the current friend, if it is a TChain.
178 // Otherwise, just an empty vector.
179 friendChainSubNames.emplace_back();
180 auto &chainSubNames = friendChainSubNames.back();
181
182 // Check if friend tree/chain has an alias
183 const auto *alias_c = tree.GetFriendAlias(frTree);
184 const std::string alias = alias_c != nullptr ? alias_c : "";
185
186 // If the current tree is a TChain
187 if (auto frChain = dynamic_cast<const TChain *>(frTree)) {
188 // Note that each TChainElement returned by TChain::GetListOfFiles has a name
189 // equal to the tree name of this TChain and a title equal to the filename.
190 // Accessing the information like this ensures that we get the correct
191 // filenames and treenames if the treename is given as part of the filename
192 // via chain.AddFile(file.root/myTree) and as well if the tree name is given
193 // in the constructor via TChain(myTree) and a file is added later by chain.AddFile(file.root).
194 // Caveat: The chain may be made of sub-trees with different names. All
195 // tree names need to be retrieved separately, see below.
196
197 // Get filelist of the current chain
198 const auto *chainFiles = frChain->GetListOfFiles();
199 if (!chainFiles || chainFiles->GetEntries() == 0) {
200 throw std::runtime_error("A TChain in the list of friends does not contain any file. "
201 "Friends with no associated files are not supported.");
202 }
203
204 // Retrieve the name of the chain and add a (name, alias) pair
205 friendNames.emplace_back(std::make_pair(frChain->GetName(), alias));
206 // Each file in the chain can contain a TTree with a different name wrt
207 // the main TChain. Retrieve the name of the file through `GetTitle`
208 // and the name of the tree through `GetName`
209 for (const auto *f : *chainFiles) {
210 chainSubNames.emplace_back(f->GetName());
211 fileNames.emplace_back(f->GetTitle());
212 }
213 } else {
214 // Get name of the tree
215 const auto realName = GetTreeFullPaths(*frTree)[0];
216 friendNames.emplace_back(std::make_pair(realName, alias));
217
218 // Get filename
219 const auto *f = frTree->GetCurrentFile();
220 if (!f)
221 throw std::runtime_error("A TTree in the list of friends is not linked to any file. "
222 "Friends with no associated files are not supported.");
223 fileNames.emplace_back(f->GetName());
224 }
225 }
226
227 return RFriendInfo{std::move(friendNames), std::move(friendFileNames), std::move(friendChainSubNames)};
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// \fn std::vector<std::string> GetTreeFullPaths(const TTree &tree)
232/// \ingroup tree
233/// \brief Retrieve the full path(s) to a TTree or the trees in a TChain.
234/// \param[in] tree The tree or chain from which the paths will be retrieved.
235/// \throws std::runtime_error If the input tree is a TChain but no files could
236/// be found associated with it.
237/// \return If the input argument is a TChain, returns a vector of strings with
238/// the name of the tree of each file in the chain. If the input
239/// argument is a TTree, returns a vector with a single element that is
240/// the full path of the tree in the file (e.g. the name of the tree
241/// itself or the path with the directories inside the file). Finally,
242/// the function returns a vector with just the name of the tree if it
243/// couldn't do any better.
244std::vector<std::string> GetTreeFullPaths(const TTree &tree)
245{
246 // Case 1: this is a TChain. For each file it contains, GetName returns the name of the tree in that file
247 if (auto chain = dynamic_cast<const TChain *>(&tree)) {
248 const auto *chainFiles = chain->GetListOfFiles();
249 if (!chainFiles || chainFiles->GetEntries() == 0) {
250 throw std::runtime_error("The input TChain does not contain any file.");
251 }
252 std::vector<std::string> treeNames;
253 for (const auto *f : *chainFiles)
254 treeNames.emplace_back(f->GetName());
255
256 return treeNames;
257 }
258
259 // Case 2: this is a TTree: we get the full path of it
260 if (const auto *treeDir = tree.GetDirectory()) {
261 // We have 2 subcases (ROOT-9948):
262 // - 1. treeDir is a TFile: return the name of the tree.
263 // - 2. treeDir is a directory: reconstruct the path to the tree in the directory.
264 // Use dynamic_cast to check whether the directory is a TFile
265 if (dynamic_cast<const TFile *>(treeDir)) {
266 return {tree.GetName()};
267 }
268 std::string fullPath = treeDir->GetPath(); // e.g. "file.root:/dir"
269 fullPath = fullPath.substr(fullPath.rfind(":/") + 1); // e.g. "/dir"
270 fullPath += "/";
271 fullPath += tree.GetName(); // e.g. "/dir/tree"
272 return {fullPath};
273 }
274
275 // We do our best and return the name of the tree
276 return {tree.GetName()};
277}
278
279} // namespace TreeUtils
280} // namespace Internal
281} // namespace ROOT
#define f(i)
Definition RSha256.hxx:104
A chain is a collection of files containing TTree objects.
Definition TChain.h:33
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition TFile.h:54
A TFriendElement TF describes a TTree object TF in a file.
A TTree represents a columnar dataset.
Definition TTree.h:79
Different standalone functions to work with trees and tuples, not reqiuired to be a member of any cla...
std::vector< std::string > GetTreeFullPaths(const TTree &tree)
RFriendInfo GetFriendInfo(const TTree &tree)
std::vector< std::string > GetFileNamesFromTree(const TTree &tree)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition tree.py:1
Information about friend trees of a certain TTree or TChain object.
std::vector< NameAlias > fFriendNames
Pairs of names and aliases of friend trees/chains.
std::vector< std::vector< std::string > > fFriendFileNames
Names of the files where each friend is stored.
void AddFriend(const std::string &treeName, const std::string &fileNameGlob, const std::string &alias="")
Add information of a single friend.
std::vector< std::vector< std::string > > fFriendChainSubNames
Names of the subtrees of a friend TChain.