The Gaudi Framework  v38r3 (c3fc9673)
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  ( ..., m_branchWrappers.emplace_back(
80  m_tree, System::typeinfoName( typeid( std::tuple_element_t<Is, std::tuple<OUTPUTs...>> ) ),
81  branchNames[Is], "", algRef ) );
82  }
83 
84  // Fill the TTree with transformed data from the input
85  void fillTree( const INPUTs&... inputs ) const {
86  auto transformedData = transform( inputs... );
87  std::apply(
88  [&]( const auto&... elems ) {
89  size_t index = 0;
90  ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
91  },
92  transformedData );
93  m_tree->Fill();
94  }
95 
96  // Write the TTree to the associated ROOT file
97  void writeTree( const std::unique_ptr<TFile>& file, const Gaudi::Algorithm& algRef ) {
98  file->cd();
99  if ( m_tree->Write() <= 0 ) {
100  throw GaudiException( "Failed to write TTree to ROOT file.", algRef.name(), StatusCode::FAILURE );
101  }
102  m_tree = nullptr;
103  algRef.info() << "TTree written to TFile." << endmsg;
104  }
105 
106  virtual ~WriterMixin() = default;
107  };
108 
114  template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
115  struct Writer {
116  Writer() = 0; // If you wish to not provide any transformation for your data, please use the NTuple::GenericWriter
117  // algorithm
118  };
119 
128  template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
129  struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
130  : Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>,
131  WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
132  using Consumer_t = Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>;
133  using Consumer_t::Consumer_t;
134 
135  Gaudi::Property<std::string> m_filename{ this, "TreeFilename", "ntuple_writer_ts_tree.root",
136  "Filename for the TTree." }; // Filename for the TTree
137  Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
138  this, "BranchNames", {}, "Names of the tree branches." }; // Names for the tree branches
139  std::unique_ptr<TFile> m_file = nullptr; // Pointer to the ROOT file
140  mutable std::mutex m_mtx; // Mutex for thread-safe operations
141 
142  // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
143  virtual StatusCode initialize() override {
144  return Consumer_t::initialize().andThen( [this]() {
145  m_file = std::make_unique<TFile>( m_filename.value().c_str(), "RECREATE" );
146  if ( !m_file || m_file->IsZombie() ) {
147  throw GaudiException(
148  fmt::format( "Failed to open file '{}'. Check file path and permissions.", m_filename.value() ),
149  this->name(), StatusCode::FAILURE );
150  }
151 
152  this->initTree( m_file, m_branchNames.value(), *this );
153 
154  return StatusCode::SUCCESS;
155  } );
156  }
157 
158  // Execute the algorithm for each event, retrieving data from the event store and writing it to the TTree
159  void operator()( const INPUTs&... args ) const override {
160  std::lock_guard<std::mutex> lock( m_mtx );
161  this->fillTree( args... );
162  }
163 
164  // Finalize the algorithm by writing the TTree to the file and closing it
165  virtual StatusCode finalize() override {
166  this->writeTree( m_file, *this );
167  return Consumer_t::finalize();
168  }
169  };
170 } // 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:143
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:97
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:159
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:140
Gaudi::NTuple::Writer::Writer
Writer()=0
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:165
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:85
Gaudi::NTuple::Writer
Base template for NTuple::Writer. Actual specializations of this template provide the functionality.
Definition: Writer.h:115
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