Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFUtils.cxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 03/2017
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "RConfigure.h" // R__USE_IMT
12#include "ROOT/RDataSource.hxx"
15#include "ROOT/RDF/RSample.hxx"
17#include "ROOT/RDF/Utils.hxx"
18#include "ROOT/RLogger.hxx"
19#include "RtypesCore.h"
20#include "TBranch.h"
21#include "TBranchElement.h"
22#include "TClass.h"
23#include "TClassEdit.h"
24#include "TClassRef.h"
25#include "TError.h" // Info
26#include "TInterpreter.h"
27#include "TLeaf.h"
28#include "TROOT.h" // IsImplicitMTEnabled, GetThreadPoolSize
29#include "TTree.h"
30
31#include <fstream>
32#include <mutex>
33#include <nlohmann/json.hpp> // nlohmann::json::parse
34#include <stdexcept>
35#include <string>
36#include <cstring>
37#include <typeinfo>
38#include <cstdint>
39
40using namespace ROOT::Detail::RDF;
41using namespace ROOT::RDF;
42
44{
45 static RLogChannel c("ROOT.RDF");
46 return c;
47}
48
49// A static function, not in an anonymous namespace, because the function name is included in the user-visible message.
50static void WarnHist()
51{
52 R__LOG_WARNING(RDFLogChannel()) << "Filling RHist is experimental and still under development.";
53}
54
56{
57 static std::once_flag once;
58 std::call_once(once, ::WarnHist);
59}
60
61// A static function, not in an anonymous namespace, because the function name is included in the user-visible message.
62static void WarnProfile()
63{
64 R__LOG_WARNING(RDFLogChannel()) << "Filling RProfile is experimental and still under development.";
65}
66
68{
69 static std::once_flag once;
70 std::call_once(once, ::WarnProfile);
71}
72
73namespace {
74using TypeInfoRef = std::reference_wrapper<const std::type_info>;
75struct TypeInfoRefHash {
76 std::size_t operator()(TypeInfoRef id) const { return id.get().hash_code(); }
77};
78
79struct TypeInfoRefEqualComp {
80 bool operator()(TypeInfoRef left, TypeInfoRef right) const { return left.get() == right.get(); }
81};
82} // namespace
83
84namespace ROOT {
85namespace Internal {
86namespace RDF {
87
88unsigned int &NThreadPerTH3()
89{
90 static unsigned int nThread = 1;
91 return nThread;
92}
93
94/// Return the type_info associated to a name. If the association fails, an
95/// exception is thrown.
96/// References and pointers are not supported since those cannot be stored in
97/// columns.
98const std::type_info &TypeName2TypeID(const std::string &name)
99{
100 // This map includes all relevant C++ fundamental types found at
101 // https://en.cppreference.com/w/cpp/language/types.html and the associated
102 // ROOT portable types when available.
103 const static std::unordered_map<std::string, TypeInfoRef> typeName2TypeIDMap{
104 // Integral types
105 // Standard integer types
106 {"short", typeid(short)},
107 {"short int", typeid(short int)},
108 {"signed short", typeid(signed short)},
109 {"signed short int", typeid(signed short int)},
110 {"unsigned short", typeid(unsigned short)},
111 {"unsigned short int", typeid(unsigned short int)},
112 {"int", typeid(int)},
113 {"signed", typeid(signed)},
114 {"signed int", typeid(signed int)},
115 {"unsigned", typeid(unsigned)},
116 {"unsigned int", typeid(unsigned int)},
117 {"long", typeid(long)},
118 {"long int", typeid(long int)},
119 {"signed long", typeid(signed long)},
120 {"signed long int", typeid(signed long int)},
121 {"unsigned long", typeid(unsigned long)},
122 {"unsigned long int", typeid(unsigned long int)},
123 {"long long", typeid(long long)},
124 {"long long int", typeid(long long int)},
125 {"signed long long", typeid(signed long long)},
126 {"signed long long int", typeid(signed long long int)},
127 {"unsigned long long", typeid(unsigned long long)},
128 {"unsigned long long int", typeid(unsigned long long int)},
129 {"std::size_t", typeid(std::size_t)},
130 // Extended standard integer types
131#ifdef INT8_MAX
132 {"std::int8_t", typeid(std::int8_t)},
133#endif
134#ifdef INT16_MAX
135 {"std::int16_t", typeid(std::int16_t)},
136#endif
137#ifdef INT32_MAX
138 {"std::int32_t", typeid(std::int32_t)},
139#endif
140#ifdef INT64_MAX
141 {"std::int64_t", typeid(std::int64_t)},
142#endif
143#ifdef UINT8_MAX
144 {"std::uint8_t", typeid(std::uint8_t)},
145#endif
146#ifdef UINT16_MAX
147 {"std::uint16_t", typeid(std::uint16_t)},
148#endif
149#ifdef UINT32_MAX
150 {"std::uint32_t", typeid(std::uint32_t)},
151#endif
152#ifdef UINT64_MAX
153 {"std::uint64_t", typeid(std::uint64_t)},
154#endif
155 // ROOT integer types
156 {"Int_t", typeid(Int_t)},
157 {"UInt_t", typeid(UInt_t)},
158 {"Short_t", typeid(Short_t)},
159 {"UShort_t", typeid(UShort_t)},
160 {"Long_t", typeid(Long_t)},
161 {"ULong_t", typeid(ULong_t)},
162 {"Long64_t", typeid(Long64_t)},
163 {"ULong64_t", typeid(ULong64_t)},
164 // Boolean type
165 {"bool", typeid(bool)},
166 {"Bool_t", typeid(bool)},
167 // Character types
168 {"char", typeid(char)},
169 {"Char_t", typeid(char)},
170 {"signed char", typeid(signed char)},
171 {"unsigned char", typeid(unsigned char)},
172 {"UChar_t", typeid(unsigned char)},
173 {"char16_t", typeid(char16_t)},
174 {"char32_t", typeid(char32_t)},
175 // Floating-point types
176 // Standard floating-point types
177 {"float", typeid(float)},
178 {"double", typeid(double)},
179 {"long double", typeid(long double)},
180 // ROOT floating-point types
181 {"Float_t", typeid(float)},
182 {"Double_t", typeid(double)}};
183
184 if (auto it = typeName2TypeIDMap.find(name); it != typeName2TypeIDMap.end())
185 return it->second.get();
186
187 if (auto c = TClass::GetClass(name.c_str()); c && c->GetTypeInfo()) {
188 return *c->GetTypeInfo();
189 }
190
191 // When the type_info cannot be retrieved with TClass, it might be that the interpreter still knows about it. This
192 // happens for example when a class has been declared to the interpreter in the same program where this
193 // RDataFrame is running, but has no dictionary. We attempt to retrieve the type_info via the interpreter before
194 // giving up.
195 std::unique_ptr<TInterpreterValue> v = gInterpreter->MakeInterpreterValue();
196 if (gInterpreter->Evaluate(("typeid(" + name + ')').c_str(), *v)) {
197 auto *typeIdAsVoidPtr = v->GetAsPointer();
198 const std::type_info *ti = reinterpret_cast<const std::type_info *>(typeIdAsVoidPtr);
199 if (ti)
200 return *ti;
201 }
202
203 throw std::runtime_error("Cannot extract type_info of type " + name + ".");
204}
205
206/// Returns the name of a type starting from its type_info
207/// An empty string is returned in case of failure
208/// References and pointers are not supported since those cannot be stored in
209/// columns.
210/// Note that this function will take a lock and may be a potential source of
211/// contention in multithreaded execution.
212std::string TypeID2TypeName(const std::type_info &id)
213{
214 const static std::unordered_map<TypeInfoRef, std::string, TypeInfoRefHash, TypeInfoRefEqualComp> typeID2TypeNameMap{
215 {typeid(char), "char"},
216 {typeid(unsigned char), "unsigned char"},
217 {typeid(signed char), "signed char"},
218 {typeid(int), "int"},
219 {typeid(unsigned int), "unsigned int"},
220 {typeid(short), "short"},
221 {typeid(unsigned short), "unsigned short"},
222 {typeid(long), "long"},
223 {typeid(unsigned long), "unsigned long"},
224 {typeid(double), "double"},
225 {typeid(float), "float"},
226 {typeid(Long64_t), "Long64_t"},
227 {typeid(ULong64_t), "ULong64_t"},
228 {typeid(bool), "bool"}};
229
230 if (auto it = typeID2TypeNameMap.find(id); it != typeID2TypeNameMap.end())
231 return it->second;
232
233 if (auto c = TClass::GetClass(id)) {
234 return c->GetName();
235 }
236
237 return "";
238}
239
240char TypeID2ROOTTypeName(const std::type_info &tid)
241{
242 const static std::unordered_map<TypeInfoRef, char, TypeInfoRefHash, TypeInfoRefEqualComp> typeID2ROOTTypeNameMap{
243 {typeid(char), 'B'}, {typeid(Char_t), 'B'}, {typeid(unsigned char), 'b'}, {typeid(UChar_t), 'b'},
244 {typeid(int), 'I'}, {typeid(Int_t), 'I'}, {typeid(unsigned int), 'i'}, {typeid(UInt_t), 'i'},
245 {typeid(short), 'S'}, {typeid(Short_t), 'S'}, {typeid(unsigned short), 's'}, {typeid(UShort_t), 's'},
246 {typeid(long), 'G'}, {typeid(Long_t), 'G'}, {typeid(unsigned long), 'g'}, {typeid(ULong_t), 'g'},
247 {typeid(long long), 'L'}, {typeid(Long64_t), 'L'}, {typeid(unsigned long long), 'l'}, {typeid(ULong64_t), 'l'},
248 {typeid(float), 'F'}, {typeid(Float_t), 'F'}, {typeid(Double_t), 'D'}, {typeid(double), 'D'},
249 {typeid(bool), 'O'}, {typeid(Bool_t), 'O'}};
250
251 if (auto it = typeID2ROOTTypeNameMap.find(tid); it != typeID2ROOTTypeNameMap.end())
252 return it->second;
253
254 return ' ';
255}
256
257std::string ComposeRVecTypeName(const std::string &valueType)
258{
259 return "ROOT::VecOps::RVec<" + valueType + ">";
260}
261
262std::string GetLeafTypeName(TLeaf *leaf, const std::string &colName)
263{
264 const char *colTypeCStr = leaf->GetTypeName();
265 std::string colType = colTypeCStr == nullptr ? "" : colTypeCStr;
266 if (colType.empty())
267 throw std::runtime_error("Could not deduce type of leaf " + colName);
268 if (leaf->GetLeafCount() != nullptr && leaf->GetLenStatic() == 1) {
269 // this is a variable-sized array
270 colType = ComposeRVecTypeName(colType);
271 } else if (leaf->GetLeafCount() == nullptr && leaf->GetLenStatic() > 1) {
272 // this is a fixed-sized array (we do not differentiate between variable- and fixed-sized arrays)
273 colType = ComposeRVecTypeName(colType);
274 } else if (leaf->GetLeafCount() != nullptr && leaf->GetLenStatic() > 1) {
275 // This case is encountered when a branch is a collection (e.g. std::vector) of a user-defined class which has
276 // a data member that is a fixed-size array. Here, 'leaf' is said data member, and the user could read it
277 // partially as std::vector<std::array<T, N>>. We expose it as ROOT::RVec<std::array<T, N>> for consistency with
278 // other collection types.
279 // WARNING: Currently this considers only the possibility of a 1-dim array, as TLeaf does not expose information
280 // to get all dimension lengths of a multi-dim array in a straightforward way (e.g. with one API call).
281 auto valueType = colType;
282 colType = "ROOT::VecOps::RVec<std::array<" + valueType + ", " + std::to_string(leaf->GetLenStatic()) + ">>";
283 }
284
285 return colType;
286}
287
288/// Return the typename of object colName stored in t, if any. Return an empty string if colName is not in t.
289/// Supported cases:
290/// - leaves corresponding to single values, variable- and fixed-length arrays, with following syntax:
291/// - "leafname", as long as TTree::GetLeaf resolves it
292/// - "b1.b2...leafname", as long as TTree::GetLeaf("b1.b2....", "leafname") resolves it
293/// - TBranchElements, as long as TTree::GetBranch resolves their names
294std::string GetBranchOrLeafTypeName(TTree &t, const std::string &colName)
295{
296 // look for TLeaf either with GetLeaf(colName) or with GetLeaf(branchName, leafName) (splitting on last dot)
297 auto *leaf = t.GetLeaf(colName.c_str());
298 if (!leaf)
299 leaf = t.FindLeaf(colName.c_str()); // try harder
300 if (!leaf) {
301 // try splitting branchname and leafname
302 const auto dotPos = colName.find_last_of('.');
303 const auto hasDot = dotPos != std::string::npos;
304 if (hasDot) {
305 const auto branchName = colName.substr(0, dotPos);
306 const auto leafName = colName.substr(dotPos + 1);
307 leaf = t.GetLeaf(branchName.c_str(), leafName.c_str());
308 }
309 }
310 if (leaf)
311 return GetLeafTypeName(leaf, std::string(leaf->GetFullName()));
312
313 // we could not find a leaf named colName, so we look for a branch called like this
314 auto branch = t.GetBranch(colName.c_str());
315 if (!branch)
316 branch = t.FindBranch(colName.c_str()); // try harder
317 if (branch) {
318 static const TClassRef tbranchelement("TBranchElement");
319 if (branch->InheritsFrom(tbranchelement)) {
320 auto be = static_cast<TBranchElement *>(branch);
321 if (auto currentClass = be->GetCurrentClass())
322 return currentClass->GetName();
323 else {
324 // Here we have a special case for getting right the type of data members
325 // of classes sorted in TClonesArrays: ROOT-9674
326 auto mother = be->GetMother();
327 if (mother && mother->InheritsFrom(tbranchelement) && mother != be) {
328 auto beMom = static_cast<TBranchElement *>(mother);
329 auto beMomClass = beMom->GetClass();
330 if (beMomClass && 0 == std::strcmp("TClonesArray", beMomClass->GetName()))
331 return be->GetTypeName();
332 }
333 return be->GetClassName();
334 }
335 } else if (branch->IsA() == TBranch::Class() && branch->GetListOfLeaves()->GetEntriesUnsafe() == 1) {
336 // normal branch (not a TBranchElement): if it has only one leaf, we pick the type of the leaf:
337 // RDF and TTreeReader allow referring to branch.leaf as just branch if branch has only one leaf
338 leaf = static_cast<TLeaf *>(branch->GetListOfLeaves()->UncheckedAt(0));
339 return GetLeafTypeName(leaf, std::string(leaf->GetFullName()));
340 }
341 }
342
343 // we could not find a branch or a leaf called colName
344 return std::string();
345}
346
347/// Return a string containing the type of the given branch. Works both with real TTree branches and with temporary
348/// column created by Define. Throws if type name deduction fails.
349/// Note that for fixed- or variable-sized c-style arrays the returned type name will be RVec<T>.
350/// vector2RVec specifies whether typename 'std::vector<T>' should be converted to 'RVec<T>' or returned as is
351std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *tree, RDataSource *ds, RDefineBase *define,
352 bool vector2RVec)
353{
354 std::string colType;
355
356 // must check defines first: we want Redefines to have precedence over everything else
357 if (define) {
358 colType = define->GetTypeName();
359 } else if (ds && ds->HasColumn(colName)) {
360 colType = ROOT::Internal::RDF::GetTypeNameWithOpts(*ds, colName, vector2RVec);
361 } else if (tree) {
362 colType = GetBranchOrLeafTypeName(*tree, colName);
363 if (vector2RVec && TClassEdit::IsSTLCont(colType) == ROOT::ESTLType::kSTLvector) {
364 std::vector<std::string> split;
365 int dummy;
366 TClassEdit::GetSplit(colType.c_str(), split, dummy);
367 auto &valueType = split[1];
368 colType = ComposeRVecTypeName(valueType);
369 }
370 }
371
372 if (colType.empty())
373 throw std::runtime_error("Column \"" + colName +
374 "\" is not in a dataset and is not a custom column been defined.");
375
376 return colType;
377}
378
379/// Convert type name (e.g. "Float_t") to ROOT type code (e.g. 'F') -- see TBranch documentation.
380/// Return a space ' ' in case no match was found.
381char TypeName2ROOTTypeName(const std::string &b)
382{
383 const static std::unordered_map<std::string, char> typeName2ROOTTypeNameMap{{"char", 'B'},
384 {"Char_t", 'B'},
385 {"unsigned char", 'b'},
386 {"UChar_t", 'b'},
387 {"int", 'I'},
388 {"Int_t", 'I'},
389 {"unsigned", 'i'},
390 {"unsigned int", 'i'},
391 {"UInt_t", 'i'},
392 {"short", 'S'},
393 {"short int", 'S'},
394 {"Short_t", 'S'},
395 {"unsigned short", 's'},
396 {"unsigned short int", 's'},
397 {"UShort_t", 's'},
398 {"long", 'G'},
399 {"long int", 'G'},
400 {"Long_t", 'G'},
401 {"unsigned long", 'g'},
402 {"unsigned long int", 'g'},
403 {"ULong_t", 'g'},
404 {"double", 'D'},
405 {"Double_t", 'D'},
406 {"float", 'F'},
407 {"Float_t", 'F'},
408 {"long long", 'L'},
409 {"long long int", 'L'},
410 {"Long64_t", 'L'},
411 {"unsigned long long", 'l'},
412 {"unsigned long long int", 'l'},
413 {"ULong64_t", 'l'},
414 {"bool", 'O'},
415 {"Bool_t", 'O'}};
416
417 if (auto it = typeName2ROOTTypeNameMap.find(b); it != typeName2ROOTTypeNameMap.end())
418 return it->second;
419
420 return ' ';
421}
422
423unsigned int GetNSlots()
424{
425 unsigned int nSlots = 1;
426#ifdef R__USE_IMT
428 nSlots = ROOT::GetThreadPoolSize();
429#endif // R__USE_IMT
430 return nSlots;
431}
432
433/// Replace occurrences of '.' with '_' in each string passed as argument.
434/// An Info message is printed when this happens. Dots at the end of the string are not replaced.
435/// An exception is thrown in case the resulting set of strings would contain duplicates.
436std::vector<std::string> ReplaceDotWithUnderscore(const std::vector<std::string> &columnNames)
437{
438 auto newColNames = columnNames;
439 for (auto &col : newColNames) {
440 const auto dotPos = col.find('.');
441 if (dotPos != std::string::npos && dotPos != col.size() - 1 && dotPos != 0u) {
442 auto oldName = col;
443 std::replace(col.begin(), col.end(), '.', '_');
444 if (std::find(columnNames.begin(), columnNames.end(), col) != columnNames.end())
445 throw std::runtime_error("Column " + oldName + " would be written as " + col +
446 " but this column already exists. Please use Alias to select a new name for " +
447 oldName);
448 Info("Snapshot", "Column %s will be saved as %s", oldName.c_str(), col.c_str());
449 }
450 }
451
452 return newColNames;
453}
454
455void InterpreterDeclare(const std::string &code)
456{
457 R__LOG_DEBUG(10, RDFLogChannel()) << "Declaring the following code to cling:\n\n" << code << '\n';
458
459 if (!gInterpreter->Declare(code.c_str())) {
460 const auto msg =
461 "\nRDataFrame: An error occurred during just-in-time compilation. The lines above might indicate the cause of "
462 "the crash\n All RDF objects that have not run an event loop yet should be considered in an invalid state.\n";
463 throw std::runtime_error(msg);
464 }
465}
466
467void InterpreterCalc(const std::string &code, const std::string &context)
468{
469 if (code.empty())
470 return;
471
472 R__LOG_DEBUG(10, RDFLogChannel()) << "Jitting and executing the following code:\n\n" << code << '\n';
473
474 TInterpreter::EErrorCode errorCode(TInterpreter::kNoError); // storage for cling errors
475
476 auto callCalc = [&errorCode, &context](const std::string &codeSlice) {
477 gInterpreter->Calc(codeSlice.c_str(), &errorCode);
478 if (errorCode != TInterpreter::EErrorCode::kNoError) {
479 std::string msg = "\nAn error occurred during just-in-time compilation";
480 if (!context.empty())
481 msg += " in " + context;
482 msg +=
483 ". The lines above might indicate the cause of the crash\nAll RDF objects that have not run their event "
484 "loop yet should be considered in an invalid state.\n";
485 throw std::runtime_error(msg);
486 }
487 };
488
489 // Call Calc every 1000 newlines in order to avoid jitting a very large function body, which is slow:
490 // see https://github.com/root-project/root/issues/9312 and https://github.com/root-project/root/issues/7604
491 std::size_t substr_start = 0;
492 std::size_t substr_end = 0;
493 while (substr_end != std::string::npos && substr_start != code.size() - 1) {
494 for (std::size_t i = 0u; i < 1000u && substr_end != std::string::npos; ++i) {
495 substr_end = code.find('\n', substr_end + 1);
496 }
497 const std::string subs = code.substr(substr_start, substr_end - substr_start);
498 substr_start = substr_end;
499
500 callCalc(subs);
501 }
502}
503
504bool IsInternalColumn(std::string_view colName)
505{
506 const auto str = colName.data();
507 const auto goodPrefix = colName.size() > 3 && // has at least more characters than {r,t}df
508 ('r' == str[0] || 't' == str[0]) && // starts with r or t
509 0 == strncmp("df", str + 1, 2); // 2nd and 3rd letters are df
510 return goodPrefix && '_' == colName.back(); // also ends with '_'
511}
512
513unsigned int GetColumnWidth(const std::vector<std::string>& names, const unsigned int minColumnSpace)
514{
515 auto columnWidth = 0u;
516 for (const auto& name : names) {
517 const auto length = name.length();
518 if (length > columnWidth)
519 columnWidth = length;
520 }
521 columnWidth = (columnWidth / minColumnSpace + 1) * minColumnSpace;
522 return columnWidth;
523}
524
525void CheckReaderTypeMatches(const std::type_info &colType, const std::type_info &requestedType,
526 const std::string &colName)
527{
528 // We explicitly support certain type conversions
529 const bool explicitlySupported = [&colType, &requestedType]() {
530 // bool as unsigned char is common to circumvent the std::vector<bool> specialization.
531 if (colType == typeid(bool) && requestedType == typeid(unsigned char))
532 return true;
533 // char as unsigned char allows reading a vector of char as a Python numpy array of integers, avoiding the
534 // automatic conversion of 'char *' to string in Python. For more info, see
535 // https://github.com/root-project/root/issues/22554
536 if (colType == typeid(char) && requestedType == typeid(unsigned char))
537 return true;
538
539 return false;
540 }();
541
542 // Here we compare names and not typeinfos since they may come from two different contexts: a compiled
543 // and a jitted one.
544 const auto diffTypes = (0 != std::strcmp(colType.name(), requestedType.name()));
545 auto inheritedType = [&]() {
546 auto colTClass = TClass::GetClass(colType);
547 return colTClass && colTClass->InheritsFrom(TClass::GetClass(requestedType));
548 };
549
550 if (!explicitlySupported && diffTypes && !inheritedType()) {
551 const auto tName = TypeID2TypeName(requestedType);
552 const auto colTypeName = TypeID2TypeName(colType);
553 std::string errMsg = "RDataFrame: type mismatch: column \"" + colName + "\" is being used as ";
554 if (tName.empty()) {
555 errMsg += requestedType.name();
556 errMsg += " (extracted from type info)";
557 } else {
558 errMsg += tName;
559 }
560 errMsg += " but the Define or Vary node advertises it as ";
561 if (colTypeName.empty()) {
562 auto &id = colType;
563 errMsg += id.name();
564 errMsg += " (extracted from type info)";
565 } else {
566 errMsg += colTypeName;
567 }
568 throw std::runtime_error(errMsg);
569 }
570}
571
572bool IsStrInVec(const std::string &str, const std::vector<std::string> &vec)
573{
574 return std::find(vec.cbegin(), vec.cend(), str) != vec.cend();
575}
576
577auto RStringCache::Insert(const std::string &string) -> decltype(fStrings)::const_iterator
578{
579 {
580 std::shared_lock l{fMutex};
581 if (auto it = fStrings.find(string); it != fStrings.end())
582 return it;
583 }
584
585 // TODO: Would be nicer to use a lock upgrade strategy a-la TVirtualRWMutex
586 // but that is unfortunately not usable outside the already available ROOT mutexes
587 std::unique_lock l{fMutex};
588 if (auto it = fStrings.find(string); it != fStrings.end())
589 return it;
590
591 return fStrings.insert(string).first;
592}
593
595{
596 const nlohmann::ordered_json fullData = nlohmann::ordered_json::parse(std::ifstream(jsonFile));
597 if (!fullData.contains("samples") || fullData["samples"].empty()) {
598 throw std::runtime_error(
599 R"(The input specification does not contain any samples. Please provide the samples in the specification like:
600{
601 "samples": {
602 "sampleA": {
603 "trees": ["tree1", "tree2"],
604 "files": ["file1.root", "file2.root"],
605 "metadata": {"lumi": 1.0, }
606 },
607 "sampleB": {
608 "trees": ["tree3", "tree4"],
609 "files": ["file3.root", "file4.root"],
610 "metadata": {"lumi": 0.5, }
611 },
612 ...
613 },
614})");
615 }
616
618 for (const auto &keyValue : fullData["samples"].items()) {
619 const std::string &sampleName = keyValue.key();
620 const auto &sample = keyValue.value();
621 // TODO: if requested in https://github.com/root-project/root/issues/11624
622 // allow union-like types for trees and files, see: https://github.com/nlohmann/json/discussions/3815
623 if (!sample.contains("trees")) {
624 throw std::runtime_error("A list of tree names must be provided for sample " + sampleName + ".");
625 }
626 std::vector<std::string> trees = sample["trees"];
627 if (!sample.contains("files")) {
628 throw std::runtime_error("A list of files must be provided for sample " + sampleName + ".");
629 }
630 std::vector<std::string> files = sample["files"];
631 if (!sample.contains("metadata")) {
632 spec.AddSample( ROOT::RDF::Experimental::RSample{sampleName, trees, files});
633 } else {
635 for (const auto &metadata : sample["metadata"].items()) {
636 const auto &val = metadata.value();
637 if (val.is_string())
638 m.Add(metadata.key(), val.get<std::string>());
639 else if (val.is_number_integer())
640 m.Add(metadata.key(), val.get<int>());
641 else if (val.is_number_float())
642 m.Add(metadata.key(), val.get<double>());
643 else
644 throw std::logic_error("The metadata keys can only be of type [string|int|double].");
645 }
646 spec.AddSample( ROOT::RDF::Experimental::RSample{sampleName, trees, files, m});
647 }
648 }
649 if (fullData.contains("friends")) {
650 for (const auto &friends : fullData["friends"].items()) {
651 std::string alias = friends.key();
652 std::vector<std::string> trees = friends.value()["trees"];
653 std::vector<std::string> files = friends.value()["files"];
654 if (files.size() != trees.size() && trees.size() > 1)
655 throw std::runtime_error("Mismatch between trees and files in a friend.");
656 spec.WithGlobalFriends(trees, files, alias);
657 }
658 }
659
660 if (fullData.contains("range")) {
661 std::vector<int> range = fullData["range"];
662
663 if (range.size() == 1)
664 spec.WithGlobalRange({range[0]});
665 else if (range.size() == 2)
666 spec.WithGlobalRange({range[0], range[1]});
667 }
668 return spec;
669};
670
671} // end NS RDF
672} // end NS Internal
673} // end NS ROOT
674
675std::string
676ROOT::Internal::RDF::GetTypeNameWithOpts(const ROOT::RDF::RDataSource &df, std::string_view colName, bool vector2RVec)
677{
678 return df.GetTypeNameWithOpts(colName, vector2RVec);
679}
680
682{
683 return df.GetTopLevelFieldNames();
684}
685
687{
688 return df.GetColumnNamesNoDuplicates();
689}
690
692 const std::set<std::string> &suppressErrorsForMissingColumns)
693{
694 ds.InitializeWithOpts(suppressErrorsForMissingColumns);
695}
696
701
703 const ROOT::RDF::RDataSource &ds, unsigned int slot,
704 const std::unordered_map<std::string, ROOT::RDF::Experimental::RSample *> &sampleMap)
705{
706 return ds.CreateSampleInfo(slot, sampleMap);
707}
708
710{
711 ds.RunFinalChecks(nodesLeftNotRun);
712}
713
718
719std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>
720ROOT::Internal::RDF::CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col,
721 const std::type_info &tid, TTreeReader *treeReader)
722{
723 return ds.CreateColumnReader(slot, col, tid, treeReader);
724}
725
726std::vector<ROOT::RDF::Experimental::RSample> ROOT::Internal::RDF::MoveOutSamples(ROOT::RDF::Experimental::RDatasetSpec &spec)
727{
728 return std::move(spec.fSamples);
729}
static void WarnProfile()
Definition RDFUtils.cxx:62
static void WarnHist()
Definition RDFUtils.cxx:50
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define R__LOG_DEBUG(DEBUGLEVEL,...)
Definition RLogger.hxx:359
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
Basic types used by ROOT and required by TInterpreter.
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
unsigned short UShort_t
Unsigned Short integer 2 bytes (unsigned short)
Definition RtypesCore.h:55
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:53
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:52
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:70
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:69
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:54
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
char name[80]
Definition TGX11.cxx:142
#define gInterpreter
std::string GetTypeName() const
The head node of a RDF computation graph.
auto Insert(const std::string &string) -> decltype(fStrings)::const_iterator
Inserts the input string in the cache and returns an iterator to the cached string.
Definition RDFUtils.cxx:577
The dataset specification for RDataFrame.
RDatasetSpec & WithGlobalFriends(const std::string &treeName, const std::string &fileNameGlob, const std::string &alias="")
Add friend tree to RDatasetSpec object.
RDatasetSpec & AddSample(RSample sample)
Add sample (RSample class object) to the RDatasetSpec object.
RDatasetSpec & WithGlobalRange(const RDatasetSpec::REntryRange &entryRange={})
Create an RDatasetSpec object for a given range of entries.
std::vector< RSample > fSamples
List of samples.
Class behaving as a heterogenuous dictionary to store the metadata of a dataset.
Definition RMetaData.hxx:57
Class representing a sample which is a grouping of trees and their fileglobs, and,...
Definition RSample.hxx:39
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
virtual bool HasColumn(std::string_view colName) const =0
Checks if the dataset has a certain column.
virtual void ProcessMT(ROOT::Detail::RDF::RLoopManager &)
virtual std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *)
Creates a column reader for the requested column.
virtual std::string DescribeDataset()
virtual void InitializeWithOpts(const std::set< std::string > &)
virtual ROOT::RDF::RSampleInfo CreateSampleInfo(unsigned int, const std::unordered_map< std::string, ROOT::RDF::Experimental::RSample * > &) const
virtual void RunFinalChecks(bool) const
This type represents a sample identifier, to be used in conjunction with RDataFrame features such as ...
A log configuration for a channel, e.g.
Definition RLogger.hxx:97
A Branch for the case of an object.
virtual TClass * GetClass() const
static TClass * Class()
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
const std::type_info * GetTypeInfo() const
Definition TClass.h:512
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2999
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual const char * GetTypeName() const
Definition TLeaf.h:142
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition TLeaf.h:124
virtual Int_t GetLenStatic() const
Return the fixed length of this leaf.
Definition TLeaf.h:135
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:46
A TTree represents a columnar dataset.
Definition TTree.h:95
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
Definition TTree.cxx:4971
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5459
virtual TLeaf * GetLeaf(const char *branchname, const char *leafname)
Searches in this tree and any of its friends for a leaf named leafname in branch branchname ,...
Definition TTree.cxx:6327
virtual TLeaf * FindLeaf(const char *name)
Find first leaf containing searchname.
Definition TTree.cxx:4994
ROOT::RLogChannel & RDFLogChannel()
Definition RDFUtils.cxx:43
void RunFinalChecks(const ROOT::RDF::RDataSource &ds, bool nodesLeftNotRun)
Definition RDFUtils.cxx:709
std::vector< std::string > ReplaceDotWithUnderscore(const std::vector< std::string > &columnNames)
Replace occurrences of '.
Definition RDFUtils.cxx:436
const std::type_info & TypeName2TypeID(const std::string &name)
Return the type_info associated to a name.
Definition RDFUtils.cxx:98
ROOT::RDF::RSampleInfo CreateSampleInfo(const ROOT::RDF::RDataSource &ds, unsigned int slot, const std::unordered_map< std::string, ROOT::RDF::Experimental::RSample * > &sampleMap)
Definition RDFUtils.cxx:702
ROOT::RDF::Experimental::RDatasetSpec RetrieveSpecFromJson(const std::string &jsonFile)
Function to retrieve RDatasetSpec from JSON file provided.
Definition RDFUtils.cxx:594
unsigned int GetNSlots()
Definition RDFUtils.cxx:423
std::string ComposeRVecTypeName(const std::string &valueType)
Definition RDFUtils.cxx:257
void CallInitializeWithOpts(ROOT::RDF::RDataSource &ds, const std::set< std::string > &suppressErrorsForMissingColumns)
Definition RDFUtils.cxx:691
std::string GetLeafTypeName(TLeaf *leaf, const std::string &colName)
Definition RDFUtils.cxx:262
const std::vector< std::string > & GetTopLevelFieldNames(const ROOT::RDF::RDataSource &ds)
Definition RDFUtils.cxx:681
char TypeName2ROOTTypeName(const std::string &b)
Convert type name (e.g.
Definition RDFUtils.cxx:381
std::string TypeID2TypeName(const std::type_info &id)
Returns the name of a type starting from its type_info An empty string is returned in case of failure...
Definition RDFUtils.cxx:212
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:572
unsigned int GetColumnWidth(const std::vector< std::string > &names, const unsigned int minColumnSpace=8u)
Get optimal column width for printing a table given the names and the desired minimal space between c...
Definition RDFUtils.cxx:513
std::string GetBranchOrLeafTypeName(TTree &t, const std::string &colName)
Return the typename of object colName stored in t, if any.
Definition RDFUtils.cxx:294
std::string DescribeDataset(ROOT::RDF::RDataSource &ds)
Definition RDFUtils.cxx:697
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *treeReader)
Definition RDFUtils.cxx:720
std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *, RDataSource *, RDefineBase *, bool vector2RVec=true)
Return a string containing the type of the given branch.
Definition RDFUtils.cxx:351
void InterpreterCalc(const std::string &code, const std::string &context="")
Jit code in the interpreter with TInterpreter::Calc, throw in case of errors.
Definition RDFUtils.cxx:467
void CheckReaderTypeMatches(const std::type_info &colType, const std::type_info &requestedType, const std::string &colName)
Definition RDFUtils.cxx:525
void WarnProfile()
Warn once about experimental filling of RProfile.
Definition RDFUtils.cxx:67
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
Definition RDFUtils.cxx:504
std::vector< ROOT::RDF::Experimental::RSample > MoveOutSamples(ROOT::RDF::Experimental::RDatasetSpec &spec)
Definition RDFUtils.cxx:726
void ProcessMT(ROOT::RDF::RDataSource &ds, ROOT::Detail::RDF::RLoopManager &lm)
Definition RDFUtils.cxx:714
void WarnHist()
Warn once about experimental filling of RHist.
Definition RDFUtils.cxx:55
std::string GetTypeNameWithOpts(const ROOT::RDF::RDataSource &ds, std::string_view colName, bool vector2RVec)
Definition RDFUtils.cxx:676
void InterpreterDeclare(const std::string &code)
Declare code in the interpreter via the TInterpreter::Declare method, throw in case of errors.
Definition RDFUtils.cxx:455
const std::vector< std::string > & GetColumnNamesNoDuplicates(const ROOT::RDF::RDataSource &ds)
Definition RDFUtils.cxx:686
unsigned int & NThreadPerTH3()
Obtain or set the number of threads that will share a clone of a thread-safe 3D histogram.
Definition RDFUtils.cxx:88
char TypeID2ROOTTypeName(const std::type_info &tid)
Definition RDFUtils.cxx:240
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:673
UInt_t GetThreadPoolSize()
Returns the size of ROOT's thread pool.
Definition TROOT.cxx:680
@ kSTLvector
Definition ESTLType.h:30
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4