Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
ntpl003_lhcbOpenData.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_ntuple
3 /// \notebook
4 /// Convert LHCb run 1 open data from a TTree to RNTuple.
5 /// This tutorial illustrates data conversion for a simple, tabular data model.
6 /// For reading, the tutorial shows the use of an ntuple View, which selectively accesses specific fields.
7 /// If a view is used for reading, there is no need to define the data model as an RNTupleModel first.
8 /// The advantage of a view is that it directly accesses RNTuple's data buffers without making an additional
9 /// memory copy.
10 ///
11 /// \macro_image
12 /// \macro_code
13 ///
14 /// \date April 2019
15 /// \author The ROOT Team
16 
17 // NOTE: The RNTuple classes are experimental at this point.
18 // Functionality, interface, and data format is still subject to changes.
19 // Do not use for real data!
20 
21 #include <ROOT/RField.hxx>
22 #include <ROOT/RNTuple.hxx>
23 #include <ROOT/RNTupleModel.hxx>
24 
25 #include <TBranch.h>
26 #include <TCanvas.h>
27 #include <TFile.h>
28 #include <TH1F.h>
29 #include <TLeaf.h>
30 #include <TTree.h>
31 
32 #include <cassert>
33 #include <memory>
34 #include <vector>
35 
36 // Import classes from experimental namespace for the time being
37 using RNTupleModel = ROOT::Experimental::RNTupleModel;
38 using RFieldBase = ROOT::Experimental::Detail::RFieldBase;
39 using RNTupleReader = ROOT::Experimental::RNTupleReader;
40 using RNTupleWriter = ROOT::Experimental::RNTupleWriter;
41 
42 constexpr char const* kTreeFileName = "http://root.cern.ch/files/LHCb/lhcb_B2HHH_MagnetUp.root";
43 constexpr char const* kNTupleFileName = "ntpl003_lhcbOpenData.root";
44 
45 
46 void Convert() {
47  std::unique_ptr<TFile> f(TFile::Open(kTreeFileName));
48  assert(f && ! f->IsZombie());
49 
50  // Get a unique pointer to an empty RNTuple model
51  auto model = RNTupleModel::Create();
52 
53  // We create RNTuple fields based on the types found in the TTree
54  // This simple approach only works for trees with simple branches and only one leaf per branch
55  auto tree = f->Get<TTree>("DecayTree");
56  for (auto b : TRangeDynCast<TBranch>(*tree->GetListOfBranches())) {
57  // The dynamic cast to TBranch should never fail for GetListOfBranches()
58  assert(b);
59 
60  // We assume every branch has a single leaf
61  TLeaf *l = static_cast<TLeaf*>(b->GetListOfLeaves()->First());
62 
63  // Create an ntuple field with the same name and type than the tree branch
64  auto field = RFieldBase::Create(l->GetName(), l->GetTypeName());
65  std::cout << "Convert leaf " << l->GetName() << " [" << l->GetTypeName() << "]"
66  << " --> " << "field " << field->GetName() << " [" << field->GetType() << "]" << std::endl;
67 
68  // Hand over ownership of the field to the ntuple model. This will also create a memory location attached
69  // to the model's default entry, that will be used to place the data supposed to be written
70  model->AddField(std::unique_ptr<RFieldBase>(field));
71 
72  // We connect the model's default entry's memory location for the new field to the branch, so that we can
73  // fill the ntuple with the data read from the TTree
74  void *fieldDataPtr = model->GetDefaultEntry()->GetValue(l->GetName()).GetRawPtr();
75  tree->SetBranchAddress(b->GetName(), fieldDataPtr);
76  }
77 
78  // The new ntuple takes ownership of the model
79  auto ntuple = RNTupleWriter::Recreate(std::move(model), "DecayTree", kNTupleFileName);
80 
81  auto nEntries = tree->GetEntries();
82  for (decltype(nEntries) i = 0; i < nEntries; ++i) {
83  tree->GetEntry(i);
84  ntuple->Fill();
85 
86  if (i && i % 100000 == 0)
87  std::cout << "Wrote " << i << " entries" << std::endl;
88  }
89 }
90 
91 
92 void ntpl003_lhcbOpenData()
93 {
94  Convert();
95 
96  // Create histogram of the flight distance
97 
98  // We open the ntuple without specifiying an explicit model first, but instead use a view on the field we are
99  // interested in
100  auto ntuple = RNTupleReader::Open("DecayTree", kNTupleFileName);
101 
102  // The view wraps a read-only double value and accesses directly the ntuple's data buffers
103  auto viewFlightDistance = ntuple->GetView<double>("B_FlightDistance");
104 
105  auto c = new TCanvas("c", "B Flight Distance", 200, 10, 700, 500);
106  TH1F h("h", "B Flight Distance", 200, 0, 140);
107  h.SetFillColor(48);
108 
109  for (auto i : ntuple->GetViewRange()) {
110  // Note that we do not load an entry in this loop, i.e. we avoid the memory copy of loading the data into
111  // the memory location given by the entry
112  h.Fill(viewFlightDistance(i));
113  }
114 
115  h.DrawCopy();
116 }