ComPWA
Common Partial-Wave-Analysis Framework
RootDataIO.cpp
Go to the documentation of this file.
1 // Copyright (c) 2013, 2017 The ComPWA Team.
2 // This file is part of the ComPWA framework, check
3 // https://github.com/ComPWA/ComPWA/license.txt for details.
4 
5 #include "RootDataIO.hpp"
6 
7 #include "TChain.h"
8 #include "TClonesArray.h"
9 #include "TError.h" // for ignoring ROOT warnings
10 #include "TFile.h"
11 #include "TLorentzVector.h"
12 #include "TParticle.h"
13 
14 #include "Core/Exceptions.hpp"
15 #include "Core/Generator.hpp"
16 #include "Core/Kinematics.hpp"
17 #include "Core/Logging.hpp"
18 #include "Core/Properties.hpp"
19 
20 namespace ComPWA {
21 namespace Data {
22 namespace Root {
23 
24 std::vector<std::string> pidsToUniqueStrings(std::vector<pid> Pids) {
25  std::vector<std::string> PidStrings;
26  for (auto Pid : Pids) {
27  auto PidString = std::to_string(Pid);
28  if (PidString.front() == '-')
29  PidString.front() = '_'; // needed because TBrowser cannot handle minus
30  PidStrings.push_back(PidString);
31  }
32  for (const auto PidString : PidStrings) {
33  int Count = 1;
34  if (std::count(PidStrings.begin(), PidStrings.end(), PidString) > 1) {
35  auto Iter = PidStrings.begin();
36  while (Iter != PidStrings.end()) {
37  Iter = std::find(Iter, PidStrings.end(), PidString);
38  *Iter += "_" + std::to_string(Count);
39  ++Count;
40  }
41  }
42  }
43  return PidStrings;
44 }
45 
46 std::vector<pid> uniqueStringsToPids(std::vector<std::string> UniqueStrings) {
47  std::vector<pid> Pids;
48  for (const auto &PidString : UniqueStrings) {
49  try {
50  auto StrippedPidString = PidString.substr(0, PidString.find("_", 0));
51  Pids.push_back(std::stoi(StrippedPidString));
52  } catch (const std::invalid_argument &e) {
53  throw ComPWA::CorruptFile("Branches \"" + PidString +
54  "\" cannot be converted to a PID");
55  }
56  }
57  return Pids;
58 }
59 
60 ComPWA::EventCollection readData(const std::string &InputFilePath,
61  const std::string &TreeName,
62  long long NumberOfEventsToRead) {
64  auto temp_ErrorIgnoreLevel = gErrorIgnoreLevel;
65  gErrorIgnoreLevel = kBreak;
66 
68  TChain Chain(TreeName.c_str());
69  Chain.Add(InputFilePath.c_str());
70 
72  auto ListOfFiles = Chain.GetListOfFiles();
73  if (!ListOfFiles || !ListOfFiles->GetEntries()) {
74  throw ComPWA::BadConfig("Root::readData() | Unable to load files: " +
75  InputFilePath);
76  }
77  if (!Chain.GetEntries()) {
78  throw ComPWA::CorruptFile("Root::readData() | TTree \"" + TreeName +
79  "\" cannot be opened from file(s) " +
80  InputFilePath + "!");
81  }
82  if (NumberOfEventsToRead <= 0 || NumberOfEventsToRead > Chain.GetEntries()) {
83  NumberOfEventsToRead = Chain.GetEntries();
84  }
85  if (!Chain.GetBranch("weights")) {
86  throw ComPWA::CorruptFile("Root::readData() | TTree \"" + TreeName +
87  "\" in file \"" + InputFilePath +
88  "\" does not contain weights branch");
89  }
90 
92  std::vector<std::string> PidStrings;
93  auto Branches = Chain.GetListOfBranches();
94  for (int i = 0; i < Branches->GetEntries(); ++i) {
95  auto Branch = Branches->At(i);
96  if (!Branch)
97  continue;
98  std::string Name = Branch->GetName();
99  if (Name == "weights")
100  continue;
101  PidStrings.push_back(Name);
102  }
103  if (!PidStrings.size()) {
104  throw ComPWA::CorruptFile("Root::readData() | TTree \"" + TreeName +
105  "\" in file \"" + InputFilePath +
106  "\" does not contain any LorentzVector branches");
107  }
108  EventCollection ImportedDataSample{uniqueStringsToPids(PidStrings)};
109 
111  double Weight;
112  std::vector<TLorentzVector *> LorentzVectors(ImportedDataSample.Pids.size());
113  if (Chain.SetBranchAddress("weights", &Weight))
114  throw std::runtime_error(
115  "Could not set branch address of branch \"weights\"");
116  size_t i = 0;
117  TIter Next(Chain.GetListOfBranches());
118  while (TObject *obj = Next()) {
119  std::string BranchName = obj->GetName();
120  if (BranchName == "weights")
121  continue;
122  if (Chain.SetBranchAddress(BranchName.c_str(), &LorentzVectors.at(i)))
123  throw std::runtime_error("Could not set branch address of branch \"" +
124  BranchName + "\"");
125  ++i;
126  }
127 
129  ImportedDataSample.Events.resize(NumberOfEventsToRead);
130  for (Long64_t i = 0; i < NumberOfEventsToRead; ++i) {
131  Chain.GetEntry(i);
132  auto &Event = ImportedDataSample.Events.at(i);
133  Event.Weight = Weight;
134  for (const auto &LorentzVector : LorentzVectors) {
135  Event.FourMomenta.push_back(
136  FourMomentum(LorentzVector->Px(), LorentzVector->Py(),
137  LorentzVector->Pz(), LorentzVector->Energy()));
138  }
139  }
140 
141  gErrorIgnoreLevel = temp_ErrorIgnoreLevel;
142  return ImportedDataSample;
143 }
144 
145 void writeData(const EventCollection &OutputSample,
146  const std::string &OutputFileName, const std::string &TreeName,
147  bool OverwriteFile) {
149  auto temp_ErrorIgnoreLevel = gErrorIgnoreLevel;
150  gErrorIgnoreLevel = kBreak;
151 
153  if (OutputSample.Events.size() == 0) {
154  throw ComPWA::CorruptFile("Root::writeData(): no events given!");
155  }
156 
157  if (!OutputSample.checkPidMatchesEvents()) {
158  throw ComPWA::CorruptFile(
159  "Root::writeData(): number of PIDs in EventCollection "
160  "does not match that of the PID list!");
161  }
162 
164  std::string WriteFlag{"UPDATE"};
165  if (OverwriteFile)
166  WriteFlag = "RECREATE";
167  TFile File(OutputFileName.c_str(), WriteFlag.c_str());
168  if (File.IsZombie()) {
169  throw std::runtime_error("Root::writeData(): can't open data file: " +
170  OutputFileName);
171  }
172  LOG(INFO) << "Root::writeData(): writing vector of "
173  << OutputSample.Events.size() << " events to file "
174  << OutputFileName;
175 
177  TTree Tree(TreeName.c_str(), TreeName.c_str());
178  auto BranchNames = pidsToUniqueStrings(OutputSample.Pids);
179  std::vector<TLorentzVector> LorentzVectors(OutputSample.Pids.size());
180  double Weight;
181  Tree.Branch("weights", &Weight);
182  for (size_t i = 0; i < LorentzVectors.size(); ++i) {
183  Tree.Branch(BranchNames.at(i).c_str(), &LorentzVectors.at(i));
184  }
186  for (auto const &Event : OutputSample.Events) {
187  Weight = Event.Weight;
188  for (size_t i = 0; i < Event.FourMomenta.size(); ++i) {
189  auto &LorentzVector = LorentzVectors.at(i);
190  LorentzVector.SetPx(Event.FourMomenta.at(i).px());
191  LorentzVector.SetPy(Event.FourMomenta.at(i).py());
192  LorentzVector.SetPz(Event.FourMomenta.at(i).pz());
193  LorentzVector.SetE(Event.FourMomenta.at(i).e());
194  }
195  Tree.Fill();
196  }
197  Tree.Write();
198  File.Close();
199  gErrorIgnoreLevel = temp_ErrorIgnoreLevel;
200 }
201 
202 } // namespace Root
203 } // namespace Data
204 } // namespace ComPWA
ComPWA four momentum class.
Input data file is corrupt or incomplete.
Definition: Exceptions.hpp:86
std::vector< pid > uniqueStringsToPids(std::vector< std::string > UniqueStrings)
Definition: RootDataIO.cpp:46
ComPWA exceptions.
void writeData(const EventCollection &OutputSample, const std::string &OutputFileName, const std::string &TreeName, bool OverwriteFile)
Write a vector of Events to a ROOT file.
Definition: RootDataIO.cpp:145
std::vector< Event > Events
Definition: Event.hpp:34
std::vector< std::string > pidsToUniqueStrings(std::vector< pid > Pids)
Definition: RootDataIO.cpp:24
Config is not complete.
Definition: Exceptions.hpp:50
ComPWA::EventCollection readData(const std::string &InputFilePath, const std::string &TreeName, long long NumberOfEventsToRead)
Create a vector of Events from a ROOT file.
Definition: RootDataIO.cpp:60
double Weight
Definition: Event.hpp:22
std::vector< FourMomentum > FourMomenta
Definition: Event.hpp:21
Data structure containing all kinematic information of a physics event.
Definition: Event.hpp:20
std::vector< pid > Pids
Definition: Event.hpp:33
bool checkPidMatchesEvents() const
Definition: Event.hpp:26