Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-07 08:51:30

0001 /// \file ROOT/RNTupleInspector.hxx
0002 /// \ingroup NTuple ROOT7
0003 /// \author Florine de Geus <florine.de.geus@cern.ch>
0004 /// \date 2023-01-09
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT7_RNTupleInspector
0017 #define ROOT7_RNTupleInspector
0018 
0019 #include <ROOT/RError.hxx>
0020 #include <ROOT/RNTupleDescriptor.hxx>
0021 
0022 #include <TFile.h>
0023 #include <TH1D.h>
0024 #include <THStack.h>
0025 
0026 #include <cstdlib>
0027 #include <iostream>
0028 #include <memory>
0029 #include <numeric>
0030 #include <optional>
0031 #include <regex>
0032 #include <vector>
0033 
0034 namespace ROOT {
0035 class RNTuple;
0036 
0037 namespace Internal {
0038 class RPageSource;
0039 } // namespace Internal
0040 
0041 namespace Experimental {
0042 
0043 enum class ENTupleInspectorPrintFormat {
0044    kTable,
0045    kCSV
0046 };
0047 enum class ENTupleInspectorHist {
0048    kCount,
0049    kNElems,
0050    kCompressedSize,
0051    kUncompressedSize
0052 };
0053 
0054 // clang-format off
0055 /**
0056 \class ROOT::Experimental::RNTupleInspector
0057 \ingroup NTuple
0058 \brief Inspect on-disk and storage-related information of an RNTuple.
0059 
0060 The RNTupleInspector can be used for studying an RNTuple in terms of its storage efficiency. It provides information on
0061 the level of the RNTuple itself, on the (sub)field level and on the column level.
0062 
0063 Example usage:
0064 
0065 ~~~ {.cpp}
0066 #include <ROOT/RNTuple.hxx>
0067 #include <ROOT/RNTupleInspector.hxx>
0068 
0069 #include <iostream>
0070 
0071 using ROOT::Experimental::RNTupleInspector;
0072 
0073 auto file = TFile::Open("data.rntuple");
0074 auto rntuple = std::unique_ptr<ROOT::RNTuple>(file->Get<RNTuple>("NTupleName"));
0075 auto inspector = RNTupleInspector::Create(*rntuple);
0076 
0077 std::cout << "The compression factor is " << inspector->GetCompressionFactor()
0078           << " using compression settings " << inspector->GetCompressionSettingsAsString()
0079           << std::endl;
0080 ~~~
0081 */
0082 // clang-format on
0083 class RNTupleInspector {
0084 public:
0085    /////////////////////////////////////////////////////////////////////////////
0086    /// \brief Provides column-level storage information.
0087    ///
0088    /// The RColumnInspector class provides storage information for an individual column. This information is partly
0089    /// collected during the construction of the RNTupleInspector object, and can partly be accessed using the
0090    /// RColumnInspector that belongs to this field.
0091    class RColumnInspector {
0092    private:
0093       const ROOT::RColumnDescriptor &fColumnDescriptor;
0094       const std::vector<std::uint64_t> fCompressedPageSizes = {};
0095       std::uint32_t fElementSize = 0;
0096       std::uint64_t fNElements = 0;
0097 
0098    public:
0099       RColumnInspector(const ROOT::RColumnDescriptor &colDesc, const std::vector<std::uint64_t> &compressedPageSizes,
0100                        std::uint32_t elemSize, std::uint64_t nElems)
0101          : fColumnDescriptor(colDesc),
0102            fCompressedPageSizes(compressedPageSizes),
0103            fElementSize(elemSize),
0104            fNElements(nElems){};
0105       ~RColumnInspector() = default;
0106 
0107       const ROOT::RColumnDescriptor &GetDescriptor() const { return fColumnDescriptor; }
0108       const std::vector<std::uint64_t> &GetCompressedPageSizes() const { return fCompressedPageSizes; }
0109       std::uint64_t GetNPages() const { return fCompressedPageSizes.size(); }
0110       std::uint64_t GetCompressedSize() const
0111       {
0112          return std::accumulate(fCompressedPageSizes.begin(), fCompressedPageSizes.end(),
0113                                 static_cast<std::uint64_t>(0));
0114       }
0115       std::uint64_t GetUncompressedSize() const { return fElementSize * fNElements; }
0116       std::uint64_t GetElementSize() const { return fElementSize; }
0117       std::uint64_t GetNElements() const { return fNElements; }
0118       ROOT::ENTupleColumnType GetType() const { return fColumnDescriptor.GetType(); }
0119    };
0120 
0121    /////////////////////////////////////////////////////////////////////////////
0122    /// \brief Provides field-level storage information.
0123    ///
0124    /// The RFieldTreeInspector class provides storage information for a field **and** its subfields. This information is
0125    /// partly collected during the construction of the RNTupleInspector object, and can partly be accessed using
0126    /// the RFieldDescriptor that belongs to this field.
0127    class RFieldTreeInspector {
0128    private:
0129       const ROOT::RFieldDescriptor &fRootFieldDescriptor;
0130       std::uint64_t fCompressedSize = 0;
0131       std::uint64_t fUncompressedSize = 0;
0132 
0133    public:
0134       RFieldTreeInspector(const ROOT::RFieldDescriptor &fieldDesc, std::uint64_t onDiskSize, std::uint64_t inMemSize)
0135          : fRootFieldDescriptor(fieldDesc), fCompressedSize(onDiskSize), fUncompressedSize(inMemSize){};
0136       ~RFieldTreeInspector() = default;
0137 
0138       const ROOT::RFieldDescriptor &GetDescriptor() const { return fRootFieldDescriptor; }
0139       std::uint64_t GetCompressedSize() const { return fCompressedSize; }
0140       std::uint64_t GetUncompressedSize() const { return fUncompressedSize; }
0141    };
0142 
0143 private:
0144    std::unique_ptr<ROOT::Internal::RPageSource> fPageSource;
0145    ROOT::RNTupleDescriptor fDescriptor;
0146    std::optional<std::uint32_t> fCompressionSettings; ///< The compression settings are unknown for an empty ntuple
0147    std::uint64_t fCompressedSize = 0;
0148    std::uint64_t fUncompressedSize = 0;
0149 
0150    std::unordered_map<int, RColumnInspector> fColumnInfo;
0151    std::unordered_map<int, RFieldTreeInspector> fFieldTreeInfo;
0152 
0153    RNTupleInspector(std::unique_ptr<ROOT::Internal::RPageSource> pageSource);
0154 
0155    /////////////////////////////////////////////////////////////////////////////
0156    /// \brief Gather column-level and RNTuple-level information.
0157    ///
0158    /// \note This method is called when the RNTupleInspector is initially created. This means that anything unexpected
0159    /// about the RNTuple itself (e.g. inconsistent compression settings across clusters) will be detected here.
0160    /// Therefore, any related exceptions will be thrown on creation of the inspector.
0161    void CollectColumnInfo();
0162 
0163    /////////////////////////////////////////////////////////////////////////////
0164    /// \brief Recursively gather field-level information.
0165    ///
0166    /// \param[in] fieldId The ID of the field from which to start the recursive traversal. Typically this is the "zero
0167    /// ID", i.e. the logical parent of all top-level fields.
0168    ///
0169    /// \return The RFieldTreeInspector for the provided field ID.
0170    ///
0171    /// This method is called when the RNTupleInspector is initially created.
0172    RFieldTreeInspector CollectFieldTreeInfo(ROOT::DescriptorId_t fieldId);
0173 
0174 public:
0175    RNTupleInspector(const RNTupleInspector &other) = delete;
0176    RNTupleInspector &operator=(const RNTupleInspector &other) = delete;
0177    RNTupleInspector(RNTupleInspector &&other) = delete;
0178    RNTupleInspector &operator=(RNTupleInspector &&other) = delete;
0179    ~RNTupleInspector();
0180 
0181    /////////////////////////////////////////////////////////////////////////////
0182    /// \brief Create a new RNTupleInspector.
0183    ///
0184    /// \param[in] sourceNTuple A pointer to the RNTuple to be inspected.
0185    ///
0186    /// \return A pointer to the newly created RNTupleInspector.
0187    ///
0188    /// \note When this factory method is called, all required static information is collected from the RNTuple's fields
0189    /// and underlying columns are collected at ones. This means that when any inconsistencies are encountered (e.g.
0190    /// inconsistent compression across clusters), it will throw an error here.
0191    static std::unique_ptr<RNTupleInspector> Create(const RNTuple &sourceNTuple);
0192 
0193    /////////////////////////////////////////////////////////////////////////////
0194    /// \brief Create a new RNTupleInspector.
0195    ///
0196    /// \param[in] ntupleName The name of the RNTuple to be inspected.
0197    /// \param[in] storage The path or URI to the RNTuple to be inspected.
0198    ///
0199    /// \see Create(RNTuple *sourceNTuple)
0200    static std::unique_ptr<RNTupleInspector> Create(std::string_view ntupleName, std::string_view storage);
0201 
0202    /////////////////////////////////////////////////////////////////////////////
0203    /// \brief Get the descriptor for the RNTuple being inspected.
0204    ///
0205    /// \return A static copy of the ROOT::RNTupleDescriptor belonging to the inspected RNTuple.
0206    const ROOT::RNTupleDescriptor &GetDescriptor() const { return fDescriptor; }
0207 
0208    /////////////////////////////////////////////////////////////////////////////
0209    /// \brief Get the compression settings of the RNTuple being inspected.
0210    ///
0211    /// \return The integer representation (\f$algorithm * 10 + level\f$, where \f$algorithm\f$ follows
0212    /// ROOT::RCompressionSetting::ELevel::EValues) of the compression settings used for the inspected RNTuple.
0213    /// Empty for an empty ntuple.
0214    ///
0215    /// \note Here, we assume that the compression settings are consistent across all clusters and columns. If this is
0216    /// not the case, an exception will be thrown when RNTupleInspector::Create is called.
0217    std::optional<std::uint32_t> GetCompressionSettings() const { return fCompressionSettings; }
0218 
0219    /////////////////////////////////////////////////////////////////////////////
0220    /// \brief Get a string describing compression settings of the RNTuple being inspected.
0221    ///
0222    /// \return A string describing the compression used for the inspected RNTuple. The format of the string is
0223    /// `"A (level L)"`, where `A` is the name of the compression algorithm and `L` the compression level.
0224    ///
0225    /// \note Here, we assume that the compression settings are consistent across all clusters and columns. If this is
0226    /// not the case, an exception will be thrown when RNTupleInspector::Create is called.
0227    std::string GetCompressionSettingsAsString() const;
0228 
0229    /////////////////////////////////////////////////////////////////////////////
0230    /// \brief Get the compressed, on-disk size of the RNTuple being inspected.
0231    ///
0232    /// \return The compressed size of the inspected RNTuple, in bytes, excluding the size of the header and footer.
0233    std::uint64_t GetCompressedSize() const { return fCompressedSize; }
0234 
0235    /////////////////////////////////////////////////////////////////////////////
0236    /// \brief Get the uncompressed total size of the RNTuple being inspected.
0237    ///
0238    /// \return The uncompressed size of the inspected RNTuple, in bytes, excluding the size of the header and footer.
0239    std::uint64_t GetUncompressedSize() const { return fUncompressedSize; }
0240 
0241    /////////////////////////////////////////////////////////////////////////////
0242    /// \brief Get the compression factor of the RNTuple being inspected.
0243    ///
0244    /// \return The compression factor of the inspected RNTuple.
0245    ///
0246    /// The compression factor shows how well the data present in the RNTuple is compressed by the compression settings
0247    /// that were used. The compression factor is calculated as \f$size_{uncompressed} / size_{compressed}\f$.
0248    float GetCompressionFactor() const { return (float)fUncompressedSize / (float)fCompressedSize; }
0249 
0250    /////////////////////////////////////////////////////////////////////////////
0251    /// \brief Get storage information for a given column.
0252    ///
0253    /// \param[in] physicalColumnId The physical ID of the column for which to get the information.
0254    ///
0255    /// \return The storage information for the provided column.
0256    const RColumnInspector &GetColumnInspector(ROOT::DescriptorId_t physicalColumnId) const;
0257 
0258    /////////////////////////////////////////////////////////////////////////////
0259    /// \brief Get the number of columns of a given type present in the RNTuple.
0260    ///
0261    /// \param[in] colType The column type to count, as defined by ROOT::ENTupleColumnType.
0262    ///
0263    /// \return The number of columns present in the inspected RNTuple of the provided type.
0264    size_t GetColumnCountByType(ROOT::ENTupleColumnType colType) const;
0265 
0266    /////////////////////////////////////////////////////////////////////////////
0267    /// \brief Get the IDs of all columns with the given type.
0268    ///
0269    /// \param[in] colType The column type to collect, as defined by ROOT::ENTupleColumnType.
0270    ///
0271    /// \return A vector containing the physical IDs of columns of the provided type.
0272    std::vector<ROOT::DescriptorId_t> GetColumnsByType(ROOT::ENTupleColumnType colType);
0273 
0274    /////////////////////////////////////////////////////////////////////////////
0275    /// \brief Get the columns that make up the given field, including its subfields.
0276    ///
0277    /// \param [in] fieldId The ID of the field for which to collect the columns.
0278    ///
0279    /// \return A vector containing the IDs of all columns for the provided field ID.
0280    std::vector<ROOT::DescriptorId_t> GetAllColumnsOfField(ROOT::DescriptorId_t fieldId) const;
0281 
0282    /////////////////////////////////////////////////////////////////////////////
0283    /// \brief Get all column types present in the RNTuple being inspected.
0284    ///
0285    /// \return A vector containing all column types present in the RNTuple.
0286    std::vector<ROOT::ENTupleColumnType> GetColumnTypes();
0287 
0288    /////////////////////////////////////////////////////////////////////////////
0289    /// \brief Print storage information per column type.
0290    ///
0291    /// \param[in] format Whether to print the information as a (markdown-parseable) table or in CSV format.
0292    /// \param[in] output Where to write the output to. Default is `stdout`.
0293    ///
0294    /// The output includes for each column type its count, the total number of elements, the compressed size and the
0295    /// uncompressed size.
0296    ///
0297    /// **Example: printing the column type information of an RNTuple as a table**
0298    /// ~~~ {.cpp}
0299    /// #include <ROOT/RNTupleInspector.hxx>
0300    /// using ROOT::Experimental::RNTupleInspector;
0301    /// using ROOT::Experimental::ENTupleInspectorPrintFormat;
0302    ///
0303    /// auto inspector = RNTupleInspector::Create("myNTuple", "some/file.root");
0304    /// inspector->PrintColumnTypeInfo();
0305    /// ~~~
0306    /// Output:
0307    /// ~~~
0308    ///  column type    | count   | # elements      | compressed bytes  | uncompressed bytes
0309    /// ----------------|---------|-----------------|-------------------|--------------------
0310    ///    SplitIndex64 |       2 |             150 |                72 |               1200
0311    ///     SplitReal32 |       4 |             300 |               189 |               1200
0312    ///     SplitUInt32 |       3 |             225 |               123 |                900
0313    /// ~~~
0314    ///
0315    /// **Example: printing the column type information of an RNTuple in CSV format**
0316    /// ~~~ {.cpp}
0317    /// #include <ROOT/RNTupleInspector.hxx>
0318    /// using ROOT::Experimental::RNTupleInspector;
0319    /// using ROOT::Experimental::ENTupleInspectorPrintFormat;
0320    ///
0321    /// auto inspector = RNTupleInspector::Create("myNTuple", "some/file.root");
0322    /// inspector->PrintColumnTypeInfo();
0323    /// ~~~
0324    /// Output:
0325    /// ~~~
0326    /// columnType,count,nElements,compressedSize,uncompressedSize
0327    /// SplitIndex64,2,150,72,1200
0328    /// SplitReal32,4,300,189,1200
0329    /// SplitUInt32,3,225,123,900
0330    /// ~~~
0331    void PrintColumnTypeInfo(ENTupleInspectorPrintFormat format = ENTupleInspectorPrintFormat::kTable,
0332                             std::ostream &output = std::cout);
0333 
0334    /////////////////////////////////////////////////////////////////////////////
0335    /// \brief Get a histogram showing information for each column type present,
0336    ///
0337    /// \param[in] histKind Which type of information should be returned.
0338    /// \param[in] histName The name of the histogram. An empty string means a default name will be used.
0339    /// \param[in] histTitle The title of the histogram. An empty string means a default title will be used.
0340    ///
0341    /// \return A pointer to a `TH1D` containing the specified kind of information.
0342    ///
0343    /// Get a histogram showing the count, number of elements, size on disk, or size in memory for each column
0344    /// type present in the inspected RNTuple.
0345    std::unique_ptr<TH1D> GetColumnTypeInfoAsHist(ENTupleInspectorHist histKind, std::string_view histName = "",
0346                                                  std::string_view histTitle = "");
0347 
0348    /////////////////////////////////////////////////////////////////////////////
0349    /// \brief Get a histogram containing the size distribution of the compressed pages for an individual column.
0350    ///
0351    /// \param[in] physicalColumnId The physical ID of the column for which to get the page size distribution.
0352    /// \param[in] histName The name of the histogram. An empty string means a default name will be used.
0353    /// \param[in] histTitle The title of the histogram. An empty string means a default title will be used.
0354    /// \param[in] nBins The desired number of histogram bins.
0355    ///
0356    /// \return A pointer to a `TH1D` containing the page size distribution.
0357    ///
0358    /// The x-axis will range from the smallest page size, to the largest (inclusive).
0359    std::unique_ptr<TH1D> GetPageSizeDistribution(ROOT::DescriptorId_t physicalColumnId, std::string histName = "",
0360                                                  std::string histTitle = "", size_t nBins = 64);
0361 
0362    /////////////////////////////////////////////////////////////////////////////
0363    /// \brief Get a histogram containing the size distribution of the compressed pages for all columns of a given type.
0364    ///
0365    /// \param[in] colType The column type for which to get the size distribution, as defined by ROOT::ENTupleColumnType.
0366    /// \param[in] histName The name of the histogram. An empty string means a default name will be used.
0367    /// \param[in] histTitle The title of the histogram. An empty string means a default title will be used.
0368    /// \param[in] nBins The desired number of histogram bins.
0369    ///
0370    /// \return A pointer to a `TH1D` containing the page size distribution.
0371    ///
0372    /// The x-axis will range from the smallest page size, to the largest (inclusive).
0373    std::unique_ptr<TH1D> GetPageSizeDistribution(ROOT::ENTupleColumnType colType, std::string histName = "",
0374                                                  std::string histTitle = "", size_t nBins = 64);
0375 
0376    /////////////////////////////////////////////////////////////////////////////
0377    /// \brief Get a histogram containing the size distribution of the compressed pages for a collection columns.
0378    ///
0379    /// \param[in] colIds The physical IDs of the columns for which to get the page size distribution.
0380    /// \param[in] histName The name of the histogram. An empty string means a default name will be used.
0381    /// \param[in] histTitle The title of the histogram. An empty string means a default title will be used.
0382    /// \param[in] nBins The desired number of histogram bins.
0383    ///
0384    /// \return A pointer to a `TH1D` containing the (cumulative) page size distribution.
0385    ///
0386    /// The x-axis will range from the smallest page size, to the largest (inclusive).
0387    std::unique_ptr<TH1D> GetPageSizeDistribution(std::initializer_list<ROOT::DescriptorId_t> colIds,
0388                                                  std::string histName = "", std::string histTitle = "",
0389                                                  size_t nBins = 64);
0390 
0391    /////////////////////////////////////////////////////////////////////////////
0392    /// \brief Get a histogram containing the size distribution of the compressed pages for all columns of a given list
0393    /// of types.
0394    ///
0395    /// \param[in] colTypes The column types for which to get the size distribution, as defined by
0396    /// ROOT::ENTupleColumnType. The default is an empty vector, which indicates that the distribution
0397    /// for *all* physical columns will be returned.
0398    /// \param[in] histName The name of the histogram. An empty string means a default name will be used. The name of
0399    /// each histogram inside the `THStack` will be `histName + colType`.
0400    /// \param[in] histTitle The title of the histogram. An empty string means a default title will be used.
0401    /// \param[in] nBins The desired number of histogram bins.
0402    ///
0403    /// \return A pointer to a `THStack` with one histogram for each column type.
0404    ///
0405    /// The x-axis will range from the smallest page size, to the largest (inclusive).
0406    ///
0407    /// **Example: Drawing a non-stacked page size distribution with a legend**
0408    /// ~~~ {.cpp}
0409    /// auto canvas = std::make_unique<TCanvas>();
0410    /// auto inspector = RNTupleInspector::Create("myNTuple", "ntuple.root");
0411    ///
0412    /// // We want to show the page size distributions of columns with type `kSplitReal32` and `kSplitReal64`.
0413    /// auto hist = inspector->GetPageSizeDistribution(
0414    ///     {ROOT::ENTupleColumnType::kSplitReal32, ROOT::ENTupleColumnType::kSplitReal64});
0415    /// // The "PLC" option automatically sets the line color for each histogram in the `THStack`.
0416    /// // The "NOSTACK" option will draw the histograms on top of each other instead of stacked.
0417    /// hist->DrawClone("PLC NOSTACK");
0418    /// canvas->BuildLegend(0.7, 0.8, 0.89, 0.89);
0419    /// canvas->DrawClone();
0420    /// ~~~
0421    std::unique_ptr<THStack> GetPageSizeDistribution(std::initializer_list<ROOT::ENTupleColumnType> colTypes = {},
0422                                                     std::string histName = "", std::string histTitle = "",
0423                                                     size_t nBins = 64);
0424 
0425    /////////////////////////////////////////////////////////////////////////////
0426    /// \brief Get storage information for a given (sub)field by ID.
0427    ///
0428    /// \param[in] fieldId The ID of the (sub)field for which to get the information.
0429    ///
0430    /// \return The storage information inspector for the provided (sub)field tree.
0431    const RFieldTreeInspector &GetFieldTreeInspector(ROOT::DescriptorId_t fieldId) const;
0432 
0433    /////////////////////////////////////////////////////////////////////////////
0434    /// \brief Get a storage information inspector for a given (sub)field by name, including its subfields.
0435    ///
0436    /// \param[in] fieldName The name of the (sub)field for which to get the information.
0437    ///
0438    /// \return The storage information inspector for the provided (sub)field tree.
0439    const RFieldTreeInspector &GetFieldTreeInspector(std::string_view fieldName) const;
0440 
0441    /////////////////////////////////////////////////////////////////////////////
0442    /// \brief Get the number of fields of a given type or class present in the RNTuple.
0443    ///
0444    /// \param[in] typeNamePattern The type or class name to count. May contain regular expression patterns for grouping
0445    /// multiple kinds of types or classes.
0446    /// \param[in] searchInSubfields If set to `false`, only top-level fields will be considered.
0447    ///
0448    /// \return The number of fields that matches the provided type.
0449    size_t GetFieldCountByType(const std::regex &typeNamePattern, bool searchInSubfields = true) const;
0450 
0451    /////////////////////////////////////////////////////////////////////////////
0452    /// \brief Get the number of fields of a given type or class present in the RNTuple.
0453    ///
0454    /// \see GetFieldCountByType(const std::regex &typeNamePattern, bool searchInSubfields) const
0455    size_t GetFieldCountByType(std::string_view typeNamePattern, bool searchInSubfields = true) const
0456    {
0457       return GetFieldCountByType(std::regex{std::string(typeNamePattern)}, searchInSubfields);
0458    }
0459 
0460    /////////////////////////////////////////////////////////////////////////////
0461    /// \brief Get the IDs of (sub-)fields whose name matches the given string.
0462    ///
0463    /// \param[in] fieldNamePattern The name of the field name to get. Because field names are unique by design,
0464    /// providing a single field name will return a vector containing just the ID of that field. However, regular
0465    /// expression patterns are supported in order to get the IDs of all fields whose name follow a certain structure.
0466    /// \param[in] searchInSubfields If set to `false`, only top-level fields will be considered.
0467    ///
0468    /// \return A vector containing the IDs of fields that match the provided name.
0469    std::vector<ROOT::DescriptorId_t>
0470    GetFieldsByName(const std::regex &fieldNamePattern, bool searchInSubfields = true) const;
0471 
0472    /////////////////////////////////////////////////////////////////////////////
0473    /// \brief Get the IDs of (sub-)fields whose name matches the given string.
0474    ///
0475    /// \see GetFieldsByName(const std::regex &fieldNamePattern, bool searchInSubfields) const
0476    std::vector<ROOT::DescriptorId_t> GetFieldsByName(std::string_view fieldNamePattern, bool searchInSubfields = true)
0477    {
0478       return GetFieldsByName(std::regex{std::string(fieldNamePattern)}, searchInSubfields);
0479    }
0480    /////////////////////////////////////////////////////////////////////////////
0481    /// \brief Print a .dot string that represents the tree of the (sub)fields of an RNTuple
0482    ///
0483    /// \param[in] fieldDescriptor The descriptor of the root field (this method works recursively)
0484    ///
0485 
0486    void PrintFieldTreeAsDot(const ROOT::RFieldDescriptor &fieldDescriptor, std::ostream &output = std::cout) const;
0487 
0488    /////////////////////////////////////////////////////////////////////////////
0489    /// \brief Print the tree of all the (sub)fields of an RNTuple
0490    /// \param[in] output
0491    ///
0492    /// \see PrintFieldTreeAsDot(const ROOT::RFieldDescriptor &fieldDescriptor, std::ostream &output=std::cout) const
0493    void PrintFieldTreeAsDot(std::ostream &output = std::cout) const
0494    {
0495       PrintFieldTreeAsDot(GetDescriptor().GetFieldZero(), output);
0496    }
0497 };
0498 } // namespace Experimental
0499 } // namespace ROOT
0500 
0501 #endif // ROOT7_RNTupleInspector