The Gaudi Framework  v38r2 (5b3c9e4d)
Writer.h
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #pragma once
12 
13 #include <Gaudi/Algorithm.h>
17 #include <TFile.h>
18 #include <TTree.h>
19 #include <fmt/format.h>
20 #include <gsl/pointers>
21 #include <gsl/span>
22 #include <mutex>
23 #include <numeric>
24 #include <tuple>
25 #include <utility>
26 
27 namespace Gaudi::NTuple {
28 
34  template <typename Signature>
35  struct WriterMixin {
36  WriterMixin() = 0; // This function has to be implemented with this speialization:
37  // WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )>
38  };
39 
49  template <typename... OUTPUTs, typename... INPUTs>
50  struct WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
51  TTree* m_tree = nullptr; // Pointer to the TTree being written to
52  std::array<std::string, sizeof...( OUTPUTs )> m_branchNames; // Names of the branches to be created
53  mutable std::vector<details::BranchWrapper> m_branchWrappers{}; // Container for BranchWrapper objects
54 
60  virtual std::tuple<OUTPUTs...> transform( const INPUTs&... inputs ) const = 0;
61 
62  // Initialize the TTree and creates branches
63  void initTree( const std::unique_ptr<TFile>& file, const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames,
64  const Gaudi::Algorithm& algRef ) {
65  file->cd();
66  m_tree = std::make_unique<TTree>( "WriterTree", "Tree of Writer Algorithm" ).release();
67  if ( !m_tree ) {
68  throw GaudiException( "Failed to create TTree. Ensure sufficient resources and permissions.", algRef.name(),
70  }
71  m_branchWrappers.reserve( m_branchWrappers.size() + sizeof...( OUTPUTs ) );
72  createBranchesForOutputs( branchNames, std::make_index_sequence<sizeof...( OUTPUTs )>{}, algRef );
73  }
74 
75  // Create branches in the TTree based on the provided names and output data types
76  template <std::size_t... Is>
77  void createBranchesForOutputs( const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames,
78  const std::index_sequence<Is...>, const Gaudi::Algorithm& algRef ) const {
79  ( ...,
80  m_branchWrappers.emplace_back(
81  m_tree, System::typeinfoName( typeid( typename std::tuple_element<Is, std::tuple<OUTPUTs...>>::type ) ),
82  branchNames[Is], "", algRef ) );
83  }
84 
85  // Fill the TTree with transformed data from the input
86  void fillTree( const INPUTs&... inputs ) const {
87  auto transformedData = transform( inputs... );
88  std::apply(
89  [&]( const auto&... elems ) {
90  size_t index = 0;
91  ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
92  },
93  transformedData );
94  m_tree->Fill();
95  }
96 
97  // Write the TTree to the associated ROOT file
98  void writeTree( const std::unique_ptr<TFile>& file, const Gaudi::Algorithm& algRef ) {
99  file->cd();
100  if ( m_tree->Write() <= 0 ) {
101  throw GaudiException( "Failed to write TTree to ROOT file.", algRef.name(), StatusCode::FAILURE );
102  }
103  m_tree = nullptr;
104  algRef.info() << "TTree written to TFile." << endmsg;
105  }
106 
107  virtual ~WriterMixin() = default;
108  };
109 
115  template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
116  struct Writer {
117  Writer() = 0; // If you wish to not provide any transformation for your data, please use the NTuple::GenericWriter
118  // algorithm
119  };
120 
129  template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
130  struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
131  : Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>,
132  WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
133  using Consumer_t = Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>;
134  using Consumer_t::Consumer_t;
135 
136  Gaudi::Property<std::string> m_filename{ this, "TreeFilename", "ntuple_writer_ts_tree.root",
137  "Filename for the TTree." }; // Filename for the TTree
138  Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
139  this, "BranchNames", {}, "Names of the tree branches." }; // Names for the tree branches
140  std::unique_ptr<TFile> m_file = nullptr; // Pointer to the ROOT file
141  mutable std::mutex m_mtx; // Mutex for thread-safe operations
142 
143  // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
144  virtual StatusCode initialize() override {
145  return Consumer_t::initialize().andThen( [this]() {
146  m_file = std::make_unique<TFile>( m_filename.value().c_str(), "RECREATE" );
147  if ( !m_file || m_file->IsZombie() ) {
148  throw GaudiException(
149  fmt::format( "Failed to open file '{}'. Check file path and permissions.", m_filename.value() ),
150  this->name(), StatusCode::FAILURE );
151  }
152 
153  this->initTree( m_file, m_branchNames.value(), *this );
154 
155  return StatusCode::SUCCESS;
156  } );
157  }
158 
159  // Execute the algorithm for each event, retrieving data from the event store and writing it to the TTree
160  void operator()( const INPUTs&... args ) const override {
161  std::lock_guard<std::mutex> lock( m_mtx );
162  this->fillTree( args... );
163  }
164 
165  // Finalize the algorithm by writing the TTree to the file and closing it
166  virtual StatusCode finalize() override {
167  this->writeTree( m_file, *this );
168  return Consumer_t::finalize();
169  }
170  };
171 } // namespace Gaudi::NTuple
std::string
STL class.
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:163
Gaudi::Algorithm::name
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:528
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::initialize
virtual StatusCode initialize() override
Definition: Writer.h:144
std::vector
STL class.
StdArrayAsProperty.h
GaudiException
Definition: GaudiException.h:31
std::lock_guard
STL class.
std::unique_ptr::release
T release(T... args)
Gaudi::NTuple::WriterMixin::WriterMixin
WriterMixin()=0
std::tuple
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::writeTree
void writeTree(const std::unique_ptr< TFile > &file, const Gaudi::Algorithm &algRef)
Definition: Writer.h:98
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::~WriterMixin
virtual ~WriterMixin()=default
System::typeinfoName
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:313
Gaudi::Functional::details::Consumer
Definition: Consumer.h:23
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::operator()
void operator()(const INPUTs &... args) const override
Definition: Writer.h:160
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::initTree
void initTree(const std::unique_ptr< TFile > &file, const gsl::span< std::string, sizeof...(OUTPUTs)> branchNames, const Gaudi::Algorithm &algRef)
Definition: Writer.h:63
StatusCode
Definition: StatusCode.h:65
Gaudi::Algorithm
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:90
Gaudi::NTuple
Definition: Writer.h:27
std::array
STL class.
Algorithm.h
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:203
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::m_mtx
std::mutex m_mtx
Definition: Writer.h:141
Gaudi::NTuple::Writer::Writer
Writer()=0
gaudirun.type
type
Definition: gaudirun.py:160
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
gaudirun.args
args
Definition: gaudirun.py:336
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::finalize
virtual StatusCode finalize() override
Definition: Writer.h:166
Consumer.h
BranchWrapper.h
std
STL namespace.
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::createBranchesForOutputs
void createBranchesForOutputs(const gsl::span< std::string, sizeof...(OUTPUTs)> branchNames, const std::index_sequence< Is... >, const Gaudi::Algorithm &algRef) const
Definition: Writer.h:77
std::mutex
STL class.
Gaudi::NTuple::WriterMixin
Base template for NTuple::WriterMixin. Actual specializations of this template provide the functional...
Definition: Writer.h:35
std::size_t
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::transform
virtual std::tuple< OUTPUTs... > transform(const INPUTs &... inputs) const =0
Transform input data to the desired output format.
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:101
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::fillTree
void fillTree(const INPUTs &... inputs) const
Definition: Writer.h:86
Gaudi::NTuple::Writer
Base template for NTuple::Writer. Actual specializations of this template provide the functionality.
Definition: Writer.h:116
std::unique_ptr< TFile >
Gaudi::Property< std::string >
Gaudi::ParticleProperties::index
size_t index(const Gaudi::ParticleProperty *property, const Gaudi::Interfaces::IParticlePropertySvc *service)
helper utility for mapping of Gaudi::ParticleProperty object into non-negative integral sequential id...
Definition: IParticlePropertySvc.cpp:39