Skip to content

Commit d8f4631

Browse files
[ntuple] ADD PrintFieldsTreeAsDot in Inspector
1 parent b0275f7 commit d8f4631

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

tree/ntupleutil/v7/inc/ROOT/RNTupleInspector.hxx

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,16 @@ class RPageSource;
4040

4141
namespace Experimental {
4242

43-
enum class ENTupleInspectorPrintFormat { kTable, kCSV };
44-
enum class ENTupleInspectorHist { kCount, kNElems, kCompressedSize, kUncompressedSize };
43+
enum class ENTupleInspectorPrintFormat {
44+
kTable,
45+
kCSV
46+
};
47+
enum class ENTupleInspectorHist {
48+
kCount,
49+
kNElems,
50+
kCompressedSize,
51+
kUncompressedSize
52+
};
4553

4654
// clang-format off
4755
/**
@@ -93,15 +101,16 @@ public:
93101
: fColumnDescriptor(colDesc),
94102
fCompressedPageSizes(compressedPageSizes),
95103
fElementSize(elemSize),
96-
fNElements(nElems) {};
104+
fNElements(nElems){};
97105
~RColumnInspector() = default;
98106

99107
const ROOT::RColumnDescriptor &GetDescriptor() const { return fColumnDescriptor; }
100108
const std::vector<std::uint64_t> &GetCompressedPageSizes() const { return fCompressedPageSizes; }
101109
std::uint64_t GetNPages() const { return fCompressedPageSizes.size(); }
102110
std::uint64_t GetCompressedSize() const
103111
{
104-
return std::accumulate(fCompressedPageSizes.begin(), fCompressedPageSizes.end(), static_cast<std::uint64_t>(0));
112+
return std::accumulate(fCompressedPageSizes.begin(), fCompressedPageSizes.end(),
113+
static_cast<std::uint64_t>(0));
105114
}
106115
std::uint64_t GetUncompressedSize() const { return fElementSize * fNElements; }
107116
std::uint64_t GetElementSize() const { return fElementSize; }
@@ -123,7 +132,7 @@ public:
123132

124133
public:
125134
RFieldTreeInspector(const ROOT::RFieldDescriptor &fieldDesc, std::uint64_t onDiskSize, std::uint64_t inMemSize)
126-
: fRootFieldDescriptor(fieldDesc), fCompressedSize(onDiskSize), fUncompressedSize(inMemSize) {};
135+
: fRootFieldDescriptor(fieldDesc), fCompressedSize(onDiskSize), fUncompressedSize(inMemSize){};
127136
~RFieldTreeInspector() = default;
128137

129138
const ROOT::RFieldDescriptor &GetDescriptor() const { return fRootFieldDescriptor; }
@@ -469,6 +478,23 @@ public:
469478
{
470479
return GetFieldsByName(std::regex{std::string(fieldNamePattern)}, searchInSubfields);
471480
}
481+
/////////////////////////////////////////////////////////////////////////////
482+
/// \brief Print a .dot string that represents the tree of the (sub)fields of an RNTuple
483+
///
484+
/// \param[in] fieldDescriptor The descriptor of the root field (this method works recursively)
485+
///
486+
487+
void PrintFieldsTreeAsDot(const ROOT::RFieldDescriptor &fieldDescriptor, std::ostream &output = std::cout) const;
488+
489+
/////////////////////////////////////////////////////////////////////////////
490+
/// \brief Print the tree of all the (sub)fields of an RNTuple
491+
/// \param[in] output
492+
///
493+
/// \see PrintFieldsTreeAsDot(const ROOT::RFieldDescriptor &fieldDescriptor, std::ostream &output=std::cout) const
494+
void PrintFieldsTreeAsDot(std::ostream &output = std::cout) const
495+
{
496+
PrintFieldsTreeAsDot(GetDescriptor().GetFieldZero(), output);
497+
}
472498
};
473499
} // namespace Experimental
474500
} // namespace ROOT

tree/ntupleutil/v7/src/RNTupleInspector.cxx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,38 @@ ROOT::Experimental::RNTupleInspector::GetFieldsByName(const std::regex &fieldNam
516516

517517
return fieldIds;
518518
}
519+
520+
void ROOT::Experimental::RNTupleInspector::PrintFieldsTreeAsDot(const ROOT::RFieldDescriptor &fieldDescriptor,
521+
std::ostream &output) const
522+
{
523+
const auto &tupleDescriptor = GetDescriptor();
524+
const bool isZeroField = fieldDescriptor.GetParentId() == ROOT::kInvalidDescriptorId;
525+
if (isZeroField) {
526+
output << "digraph D {\n";
527+
output << "node[shape=box]\n";
528+
}
529+
const std::string &nodeId = (isZeroField) ? "0" : std::to_string(fieldDescriptor.GetId() + 1);
530+
const std::string &fieldName = (isZeroField) ? "RFieldZero" : fieldDescriptor.GetFieldName();
531+
const std::string &description = fieldDescriptor.GetFieldDescription();
532+
const std::uint32_t &version = fieldDescriptor.GetFieldVersion();
533+
534+
output << nodeId << "[label=<";
535+
if (!isZeroField) {
536+
output << "<b>Name: </b>" << fieldName << "<br></br>";
537+
output << "<b>Type: </b>" << fieldDescriptor.GetTypeName() << "<br></br>";
538+
output << "<b>ID: </b>" << std::to_string(fieldDescriptor.GetId()) << "<br></br>";
539+
if (description != "")
540+
output << "<b>Description: </b>" << description << "<br></br>";
541+
if (version != 0)
542+
output << "<b>Version: </b>" << version << "<br></br>";
543+
} else
544+
output << "<b>" << fieldName << "</b>";
545+
output << ">]\n";
546+
for (const auto &childFieldId : fieldDescriptor.GetLinkIds()) {
547+
const auto &childFieldDescriptor = tupleDescriptor.GetFieldDescriptor(childFieldId);
548+
output << nodeId + "->" + std::to_string(childFieldDescriptor.GetId() + 1) + "\n";
549+
PrintFieldsTreeAsDot(childFieldDescriptor, output);
550+
}
551+
if (isZeroField)
552+
output << "}";
553+
}

tree/ntupleutil/v7/test/ntuple_inspector.cxx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,3 +813,23 @@ TEST(RNTupleInspector, MultiColumnRepresentations)
813813
EXPECT_EQ(ENTupleColumnType::kReal16, px1Inspector.GetType());
814814
EXPECT_EQ(1u, px1Inspector.GetNElements());
815815
}
816+
817+
TEST(RNTupleInspector, FieldsTreeAsDot)
818+
{
819+
FileRaii fileGuard("test_ntuple_inspector_fields_tree_as_dot.root");
820+
{
821+
auto model = RNTupleModel::Create();
822+
auto fldFloat1 = model->MakeField<float>("float1");
823+
auto fldInt = model->MakeField<std::int32_t>("int");
824+
auto writer = RNTupleWriter::Recreate(std::move(model), "ntuple", fileGuard.GetPath());
825+
}
826+
auto inspector = RNTupleInspector::Create("ntuple", fileGuard.GetPath());
827+
std::ostringstream dotStream;
828+
inspector->PrintFieldsTreeAsDot(dotStream);
829+
const std::string dot = dotStream.str();
830+
831+
EXPECT_NE(dot.find("digraph D {"), std::string::npos);
832+
EXPECT_NE(dot.find("0->1"), std::string::npos);
833+
EXPECT_NE(dot.find("0->2"), std::string::npos);
834+
EXPECT_TRUE(dot.size() >= 2 && dot.substr(dot.size() - 1) == "}");
835+
}

0 commit comments

Comments
 (0)