Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFGraphUtils.cxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo, CERN, Massimo Tumolo Politecnico di Torino 08/2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2020, 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
13
14#include <algorithm> // std::find
15
16namespace ROOT {
17namespace Internal {
18namespace RDF {
19namespace GraphDrawing {
20
21std::string GraphCreatorHelper::FromGraphLeafToDot(std::shared_ptr<GraphNode> leaf)
22{
23 // Only the mapping between node id and node label (i.e. name)
24 std::stringstream dotStringLabels;
25 // Representation of the relationships between nodes
26 std::stringstream dotStringGraph;
27
28 // Explore the graph bottom-up and store its dot representation.
29 while (leaf) {
30 dotStringLabels << "\t" << leaf->fCounter << " [label=\"" << leaf->fName << "\", style=\"filled\", fillcolor=\""
31 << leaf->fColor << "\", shape=\"" << leaf->fShape << "\"];\n";
32 if (leaf->fPrevNode) {
33 dotStringGraph << "\t" << leaf->fPrevNode->fCounter << " -> " << leaf->fCounter << ";\n";
34 }
35 leaf = leaf->fPrevNode;
36 }
37
38 return "digraph {\n" + dotStringLabels.str() + dotStringGraph.str() + "}";
39}
40
41std::string GraphCreatorHelper::FromGraphActionsToDot(std::vector<std::shared_ptr<GraphNode>> leaves)
42{
43 // Only the mapping between node id and node label (i.e. name)
44 std::stringstream dotStringLabels;
45 // Representation of the relationships between nodes
46 std::stringstream dotStringGraph;
47
48 for (auto leaf : leaves) {
49 while (leaf && !leaf->fIsExplored) {
50 dotStringLabels << "\t" << leaf->fCounter << " [label=\"" << leaf->fName
51 << "\", style=\"filled\", fillcolor=\"" << leaf->fColor << "\", shape=\"" << leaf->fShape
52 << "\"];\n";
53 if (leaf->fPrevNode) {
54 dotStringGraph << "\t" << leaf->fPrevNode->fCounter << " -> " << leaf->fCounter << ";\n";
55 }
56 // Multiple branches may share the same nodes. It is wrong to explore them more than once.
57 leaf->fIsExplored = true;
58 leaf = leaf->fPrevNode;
59 }
60 }
61 return "digraph {\n" + dotStringLabels.str() + dotStringGraph.str() + "}";
62}
63
65{
66 auto loopManager = rDataFrame.GetLoopManager();
67 // Jitting is triggered because nodes must not be empty at the time of the calling in order to draw the graph.
68 loopManager->Jit();
69
70 return RepresentGraph(loopManager);
71}
72
74{
75 const auto actions = loopManager->GetAllActions();
76 const auto edges = loopManager->GetGraphEdges();
77
78 std::vector<std::shared_ptr<GraphNode>> nodes;
79 nodes.reserve(actions.size() + edges.size());
80
81 for (auto *action : actions)
82 nodes.emplace_back(action->GetGraph());
83 for (auto *edge : edges)
84 nodes.emplace_back(edge->GetGraph());
85
86 return FromGraphActionsToDot(nodes);
87}
88
89std::shared_ptr<GraphNode>
90CreateDefineNode(const std::string &columnName, const ROOT::Detail::RDF::RDefineBase *columnPtr)
91{
92 // If there is already a node for this define (recognized by the custom column it is defining) return it. If there is
93 // not, return a new one.
94 auto &sColumnsMap = GraphCreatorHelper::GetStaticColumnsMap();
95 auto duplicateDefineIt = sColumnsMap.find(columnPtr);
96 if (duplicateDefineIt != sColumnsMap.end()) {
97 auto duplicateDefine = duplicateDefineIt->second.lock();
98 return duplicateDefine;
99 }
100
101 auto node = std::make_shared<GraphNode>("Define\n" + columnName);
102 node->SetDefine();
103
104 sColumnsMap[columnPtr] = node;
105 return node;
106}
107
108std::shared_ptr<GraphNode> CreateFilterNode(const ROOT::Detail::RDF::RFilterBase *filterPtr)
109{
110 // If there is already a node for this filter return it. If there is not, return a new one.
111 auto &sFiltersMap = GraphCreatorHelper::GetStaticFiltersMap();
112 auto duplicateFilterIt = sFiltersMap.find(filterPtr);
113 if (duplicateFilterIt != sFiltersMap.end()) {
114 auto duplicateFilter = duplicateFilterIt->second.lock();
115 duplicateFilter->SetIsNew(false);
116 return duplicateFilter;
117 }
118 auto filterName = (filterPtr->HasName() ? filterPtr->GetName() : "Filter");
119 auto node = std::make_shared<GraphNode>(filterName);
120
121 sFiltersMap[filterPtr] = node;
122 node->SetFilter();
123 return node;
124}
125
126std::shared_ptr<GraphNode> CreateRangeNode(const ROOT::Detail::RDF::RRangeBase *rangePtr)
127{
128 // If there is already a node for this range return it. If there is not, return a new one.
129 auto &sRangesMap = GraphCreatorHelper::GetStaticRangesMap();
130 auto duplicateRangeIt = sRangesMap.find(rangePtr);
131 if (duplicateRangeIt != sRangesMap.end()) {
132 auto duplicateRange = duplicateRangeIt->second.lock();
133 duplicateRange->SetIsNew(false);
134 return duplicateRange;
135 }
136 auto node = std::make_shared<GraphNode>("Range");
137 node->SetRange();
138
139 sRangesMap[rangePtr] = node;
140 return node;
141}
142
143std::shared_ptr<GraphNode> AddDefinesToGraph(std::shared_ptr<GraphNode> node, const RColumnRegister &colRegister,
144 const std::vector<std::string> &prevNodeDefines)
145{
146 auto upmostNode = node;
147 const auto &defineNames = colRegister.GetNames();
148 const auto &defineMap = colRegister.GetColumns();
149 for (auto i = int(defineNames.size()) - 1; i >= 0; --i) { // walk backwards through the names of defined columns
150 const auto colName = defineNames[i];
151 const bool isAlias = defineMap.find(colName) == defineMap.end();
152 if (isAlias || IsInternalColumn(colName))
153 continue; // aliases appear in the list of defineNames but we don't support them yet
154 const bool isANewDefine =
155 std::find(prevNodeDefines.begin(), prevNodeDefines.end(), colName) == prevNodeDefines.end();
156 if (!isANewDefine)
157 break; // we walked back through all new defines, the rest is stuff that was already in the graph
158
159 // create a node for this new Define
160 auto defineNode = RDFGraphDrawing::CreateDefineNode(colName, defineMap.at(colName).get());
161 upmostNode->SetPrevNode(defineNode);
162 upmostNode = defineNode;
163 }
164
165 return upmostNode;
166}
167
168} // namespace GraphDrawing
169} // namespace RDF
170} // namespace Internal
171} // namespace ROOT
std::string GetName() const
The head node of a RDF computation graph.
std::vector< RDFInternal::RActionBase * > GetAllActions() const
Return all actions, either booked or already run.
std::vector< RNodeBase * > GetGraphEdges() const
Return all graph edges known to RLoopManager This includes Filters and Ranges but not Defines.
void Jit()
Add RDF nodes that require just-in-time compilation to the computation graph.
static FiltersNodesMap_t & GetStaticFiltersMap()
Stores the filters defined and which node in the graph defined them.
static DefinesNodesMap_t & GetStaticColumnsMap()
Stores the columns defined and which node in the graph defined them.
std::string FromGraphLeafToDot(std::shared_ptr< GraphNode > leaf)
Starting from any leaf (Action, Filter, Range) it draws the dot representation of the branch.
std::string FromGraphActionsToDot(std::vector< std::shared_ptr< GraphNode > > leaves)
Starting by an array of leaves, it draws the entire graph.
std::string RepresentGraph(ROOT::RDataFrame &rDataFrame)
Starting from the root node, prints the entire graph.
static RangesNodesMap_t & GetStaticRangesMap()
Stores the ranges defined and which node in the graph defined them.
A binder for user-defined columns and aliases.
const DefinesMap_t & GetColumns() const
Returns a map of pointers to the defined columns.
ColumnNames_t GetNames() const
Returns the list of the names of the defined columns (Defines + Aliases).
RLoopManager * GetLoopManager() const
ROOT's RDataFrame offers a high level interface for analyses of data stored in TTree,...
std::shared_ptr< GraphNode > CreateDefineNode(const std::string &columnName, const ROOT::Detail::RDF::RDefineBase *columnPtr)
std::shared_ptr< GraphNode > CreateRangeNode(const ROOT::Detail::RDF::RRangeBase *rangePtr)
std::shared_ptr< GraphNode > AddDefinesToGraph(std::shared_ptr< GraphNode > node, const RColumnRegister &colRegister, const std::vector< std::string > &prevNodeDefines)
Add the Defines that have been added between this node and the previous to the graph.
std::shared_ptr< GraphNode > CreateFilterNode(const ROOT::Detail::RDF::RFilterBase *filterPtr)
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
Definition RDFUtils.cxx:365
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...