DAS  3.0
Das Analysis System
Flow.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPLv3-or-later
2 //
3 // SPDX-FileCopyrightText: Patrick L.S. Connor <patrick.connor@desy.de>
4 // SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
5 
6 #pragma once
7 
8 #include "exceptions.h"
9 #include "FriendUtils.h"
10 #include "Looper.h"
11 
12 #include <TChain.h>
13 #include <TFile.h>
14 #include <TH1.h>
15 #include <TTree.h>
16 
17 #include <any>
18 #include <array>
19 #include <filesystem>
20 #include <map>
21 #include <memory>
22 #include <ranges>
23 #include <source_location>
24 #include <string>
25 #include <vector>
26 
27 namespace Darwin::Tools {
28 
29 enum BranchMode {
32 };
33 
34 using enum BranchMode;
35 
69 class Flow {
70 
71  int steering;
72 
73  std::vector<std::filesystem::path> inputs;
74 
75  std::unique_ptr<ChainSlice> tIn;
76  std::shared_ptr<TFile> fOut;
77  std::unique_ptr<TTree> tOut;
78 
79  std::map<std::string, std::any> branches;
80 
83  template<typename T>
84  std::shared_ptr<T*> GetBranch (const std::string& name) const
85  try {
86  using namespace std;
87  if (steering & verbose)
88  cout << "Flow: retrieving an existing branch" << endl;
89  auto& branch = branches.at(name);
90  return any_cast<shared_ptr<T*>>(branch);
91  }
92  catch (const std::bad_any_cast& e) {
93  BOOST_THROW_EXCEPTION(e);
94  }
95 
96  template<typename T> T * NoBranch (const std::string& name, BranchMode mode)
97  {
98  if (mode == facultative)
99  return nullptr;
100 
101  namespace DE = Darwin::Exceptions;
102  std::string what = name + " branch could not be found";
103  BOOST_THROW_EXCEPTION( DE::BadInput(what.c_str(), *tIn) );
104  }
105 
106 public:
109  inline std::string DumpActiveBranches () const
110  {
111  auto keys = branches | std::views::keys;
112  return std::accumulate(keys.begin(), keys.end(), std::string(),
113  [](const std::string& str, const std::string& branch_name) {
114  return str + ' ' + branch_name;
115  });
116  }
117 
122  Flow (int = none,
123  const std::vector<std::filesystem::path>& = {}
124  );
125 
130  ~Flow ();
131 
134  [[deprecated("Give the input paths to the constructor")]]
135  ChainSlice * GetInputTree
136  (std::vector<std::filesystem::path>,
137  const Slice = {1, 0},
138  const std::string& = "events");
139 
142  ChainSlice * GetInputTree
143  (const Slice = {1, 0},
144  const std::string& = "events");
145 
151  template<typename THX = TH1, size_t N>
152  std::array<std::unique_ptr<THX>, N> GetInputHists
153  (const std::array<std::string, N>& names = {}
154  )
155  {
156  using namespace std;
157  namespace fs = filesystem;
158 
159  if (inputs.size() == 0)
160  BOOST_THROW_EXCEPTION( runtime_error("Empty input list") );
161 
162  array<unique_ptr<THX>, N> sums;
163  for (const fs::path& input: inputs) {
164  auto fIn = make_unique<TFile>(input.c_str(), "READ");
165  for (size_t i = 0; i < N; ++i) {
166  const string& name = names[i];
167  unique_ptr<THX> h(fIn->Get<THX>(name.c_str()));
168  if (!h) {
169  namespace DE = Darwin::Exceptions;
170  BOOST_THROW_EXCEPTION(
171  DE::BadInput(Form("`%s` cannot be found in (one of) the "
172  " file(s).", name.c_str()), fIn));
173  }
174  if (sums[i])
175  sums[i]->Add(h.get());
176  else {
177  sums[i] = std::move(h);
178  sums[i]->SetDirectory(nullptr);
179  }
180  }
181  }
182  return sums;
183  }
184 
190  template<typename THX = TH1, typename... Args>
191  auto GetInputHists (const Args... args)
192  {
193  constexpr const size_t N = sizeof...(args);
194  std::array<std::string, N> names {{ args... }};
195  return GetInputHists<THX, N>(names);
196  }
197 
202  template<typename THX = TH1>
203  std::unique_ptr<THX> GetInputHist
204  (const std::string& name)
205  {
206  auto hists = GetInputHists<THX,1>({name});
207  THX * hist = hists.front().release();
208  return std::unique_ptr<THX>(hist);
209  }
210 
224  TTree * GetOutputTree (std::shared_ptr<TFile> = {},
225  const std::source_location = std::source_location::current());
226 
229  TTree * GetOutputTree (const std::filesystem::path&,
230  const std::source_location = std::source_location::current());
231 
234  inline void SetOutputFile (std::shared_ptr<TFile> fOut) { this->fOut = fOut; }
235 
238  inline TFile * GetOutputFile () { return fOut.get(); }
239 
242  std::pair<TFile *, TTree *> GetOutput (const std::filesystem::path&,
243  const std::source_location = std::source_location::current());
244 
255  template<typename T>
257  const std::string& name,
258  BranchMode mode = mandatory)
259  {
260  using namespace std;
261 
262  if (!tIn)
263  BOOST_THROW_EXCEPTION( invalid_argument("`GetInputTree()` should "
264  "be called before declaring a read-only branch") );
265 
266  namespace DE = Darwin::Exceptions;
267 
268  shared_ptr<T*> t;
269 
270  if (branches.contains(name))
271  t = GetBranch<T>(name);
272  else {
273  t = make_shared<T*>();
274  if (steering & verbose)
275  cout << "Flow: loading branch `" << name << "`" << endl;
276 
277  if (tIn->GetBranch(name.c_str()) == nullptr)
278  return NoBranch<T>(name, mode);
279 
280  int err = tIn->SetBranchAddress(name.c_str(), t.get());
281  if (steering & verbose)
282  cout << "Flow: `TTree::SetBranchAddress()` returned " << to_string(err)
283  << " (check `TTree::ESetBranchAddressStatus` for the meaning)."
284  << endl;
285  if (err < 0) {
286  string what = "`"s + name + "` branch could not be set. "s;
287  if (mode == facultative) {
288  if (steering & verbose)
289  cout << orange << "Flow: " << what << def << endl;
290  return nullptr;
291  }
292  BOOST_THROW_EXCEPTION( DE::BadInput(what.c_str(), *tIn) );
293  }
294  branches.insert({name, t});
295  }
296  return *t;
297  }
298 
307  template<typename T>
308  T * GetBranchWriteOnly (const std::string& name)
309  {
310  using namespace std;
311 
312  if (!tOut)
313  BOOST_THROW_EXCEPTION( invalid_argument("`GetOutputTree()` should "
314  "be called before") );
315 
316  shared_ptr<T*> t;
317 
318  if (branches.contains(name))
319  t = GetBranch<T>(name);
320  else
321  t = make_shared<T*>();
322 
323  if (steering & verbose)
324  cout << "Flow: setting up new branch for `" << name << "`" << endl;
325  if (tOut->Branch(name.c_str(), t.get()) == nullptr) {
326  namespace DE = Darwin::Exceptions;
327  string what = name + " branch could not be set up";
328  BOOST_THROW_EXCEPTION( DE::BadInput(what.c_str(), *tOut) );
329  }
330 
331  if (!branches.contains(name))
332  branches.insert({name, t});
333  return *t;
334  }
335 
344  template<typename T>
345  T * GetBranchReadWrite (const std::string& name,
346  BranchMode mode = mandatory)
347  {
348  using namespace std;
349 
350  if (!tIn)
351  BOOST_THROW_EXCEPTION( invalid_argument("`GetInputTree()` should "
352  "be called before declaring a read-write branch") );
353 
354  if (!tOut)
355  BOOST_THROW_EXCEPTION( invalid_argument("`GetOutputTree()` should "
356  "be called before declaring a read-write branch") );
357 
358  shared_ptr<T*> t;
359 
360  if (branches.contains(name))
361  t = GetBranch<T>(name);
362  else {
363  if (GetBranchReadOnly<T>(name, mode) == nullptr)
364  return NoBranch<T>(name, mode);
365  if (steering & Friend)
366  GetBranchWriteOnly<T>(name);
367  t = any_cast<shared_ptr<T*>>(branches[name]);
368  }
369  return *t;
370  }
371 };
372 
373 } // namespace Darwin::Tools
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.name
name
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:48
Darwin::Tools::Flow::branches
std::map< std::string, std::any > branches
pointers to mounted branches
Definition: Flow.h:79
Darwin::Tools::mandatory
@ mandatory
mounting branch is mandatory
Definition: Flow.h:30
Darwin::Tools::Flow
User-friendly handling of input and output n-tuples.
Definition: Flow.h:69
exceptions.h
Step::def
static const char * def
Definition: Step.h:36
Darwin::Tools::Friend
@ Friend
activate -F to only fill the new branches
Definition: Options.h:28
Ntupliser_cfg.args
args
Definition: Ntupliser_cfg.py:11
Darwin::Tools::Flow::GetBranchWriteOnly
T * GetBranchWriteOnly(const std::string &name)
Wrapper to initialise write-only branches.
Definition: Flow.h:308
Darwin::Tools::Flow::tOut
std::unique_ptr< TTree > tOut
output tree
Definition: Flow.h:77
Darwin::Tools::Flow::fOut
std::shared_ptr< TFile > fOut
output ROOT file
Definition: Flow.h:76
Darwin::Tools::BranchMode
BranchMode
Definition: Flow.h:29
Darwin::Tools::none
@ none
default (for simple executables)
Definition: Options.h:24
Darwin::Tools::Flow::GetBranchReadWrite
T * GetBranchReadWrite(const std::string &name, BranchMode mode=mandatory)
Wrapper to initialise read-write branches.
Definition: Flow.h:345
Darwin::Tools::Flow::GetInputHists
std::array< std::unique_ptr< THX >, N > GetInputHists(const std::array< std::string, N > &names={})
Load ROOT histograms from a list of files.
Definition: Flow.h:153
Darwin::Tools::Flow::GetInputHists
auto GetInputHists(const Args... args)
Load ROOT histograms from a list of files.
Definition: Flow.h:191
Darwin::Tools::Flow::Flow
Flow(int=none, const std::vector< std::filesystem::path > &={})
Constructor.
Definition: Flow.cc:11
Looper.h
Darwin::Tools::Flow::NoBranch
T * NoBranch(const std::string &name, BranchMode mode)
Definition: Flow.h:96
Darwin::Tools::Slice
std::pair< unsigned, unsigned > Slice
current slice (>=0) / total number of slices (>0)
Definition: Looper.h:20
Darwin::Exceptions
Handling of exceptions.
Definition: darwin.h:36
Darwin::Tools::verbose
@ verbose
bit for debug mode (-v is always available)
Definition: Options.h:30
orange
static const char * orange
Definition: colours.h:6
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.input
input
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:35
FriendUtils.h
Darwin::Tools::Flow::DumpActiveBranches
std::string DumpActiveBranches() const
Returns a list of all active branches, formatted as a string.
Definition: Flow.h:109
Darwin::Tools::Flow::inputs
std::vector< std::filesystem::path > inputs
ROOT files or directories.
Definition: Flow.h:73
Darwin::Tools
Classes and functions related to the framework.
Definition: Dict_rdict.cxx:990
Darwin::Tools::Flow::GetOutputTree
TTree * GetOutputTree(std::shared_ptr< TFile >={}, const std::source_location=std::source_location::current())
Create an output TTree object.
Definition: Flow.cc:91
Darwin::Tools::Flow::GetBranch
std::shared_ptr< T * > GetBranch(const std::string &name) const
Get address of branch address in a shared pointer.
Definition: Flow.h:84
Darwin::Tools::Flow::GetOutput
std::pair< TFile *, TTree * > GetOutput(const std::filesystem::path &, const std::source_location=std::source_location::current())
Get both the output file and the output tree in one go.
Definition: Flow.cc:166
Darwin::Tools::Flow::GetBranchReadOnly
T * GetBranchReadOnly(const std::string &name, BranchMode mode=mandatory)
Wrapper to initialise read-only branches.
Definition: Flow.h:256
Darwin::Tools::Flow::GetInputTree
ChainSlice * GetInputTree(std::vector< std::filesystem::path >, const Slice={1, 0}, const std::string &="events")
Load chain from a list of files.
Definition: Flow.cc:46
Darwin::Tools::Flow::steering
int steering
steering from Options, mostly useful for friends
Definition: Flow.h:71
Darwin::Tools::Flow::~Flow
~Flow()
Destructor.
Definition: Flow.cc:19
Darwin::Tools::Flow::tIn
std::unique_ptr< ChainSlice > tIn
input chain
Definition: Flow.h:75
Darwin::Tools::Flow::GetInputHist
std::unique_ptr< THX > GetInputHist(const std::string &name)
Load a single ROOT histogram from a list of files.
Definition: Flow.h:204
Darwin::Tools::Flow::SetOutputFile
void SetOutputFile(std::shared_ptr< TFile > fOut)
Set the output file where the output TTree should be saved.
Definition: Flow.h:234
Darwin::Tools::Flow::GetOutputFile
TFile * GetOutputFile()
Get a raw pointer to the output file.
Definition: Flow.h:238
Darwin::Exceptions::BadInput
Generic exception for ill-defined input (before the event loop).
Definition: exceptions.h:83
Darwin::Tools::facultative
@ facultative
mounting branch is facultative
Definition: Flow.h:31