The Gaudi Framework  master (37c0b60a)
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>
18 #include <TFile.h>
19 #include <TTree.h>
20 #include <fmt/format.h>
21 #include <gsl/pointers>
22 #include <gsl/span>
23 #include <mutex>
24 #include <numeric>
25 #include <tuple>
26 #include <utility>
27 
28 namespace Gaudi::NTuple {
29 
35  template <typename Signature>
36  struct WriterMixin {
37  WriterMixin() = 0; // This function has to be implemented with this speialization:
38  // WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )>
39  };
40 
50  template <typename... OUTPUTs, typename... INPUTs>
51  struct WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
52  TTree* m_tree = nullptr; // Pointer to the TTree being written to
53  std::array<std::string, sizeof...( OUTPUTs )> m_branchNames; // Names of the branches to be created
54  mutable std::vector<details::BranchWrapper> m_branchWrappers{}; // Container for BranchWrapper objects
55 
61  virtual std::tuple<OUTPUTs...> transform( const INPUTs&... inputs ) const = 0;
62 
63  // Initialize the TTree and creates branches
64  void initTree( const std::shared_ptr<TFile>& file, const std::string& ntupleName,
65  const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames, const std::string& algName ) {
66  file->cd();
67  m_tree = std::make_unique<TTree>( ntupleName.c_str(), "Tree of Writer Algorithm" ).release();
68  m_branchWrappers.reserve( m_branchWrappers.size() + sizeof...( OUTPUTs ) );
69  createBranchesForOutputs( branchNames, std::make_index_sequence<sizeof...( OUTPUTs )>{}, algName );
70  }
71 
72  // Create branches in the TTree based on the provided names and output data types
73  template <std::size_t... Is>
74  void createBranchesForOutputs( const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames,
75  const std::index_sequence<Is...>, const std::string& algName ) const {
76  ( ..., m_branchWrappers.emplace_back(
77  m_tree, System::typeinfoName( typeid( std::tuple_element_t<Is, std::tuple<OUTPUTs...>> ) ),
78  branchNames[Is], "", algName ) );
79  }
80 
81  // Fill the TTree with transformed data from the input
82  void fillTree( const INPUTs&... inputs ) const {
83  auto transformedData = transform( inputs... );
84  std::apply(
85  [&]( const auto&... elems ) {
86  size_t index = 0;
87  ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
88  },
89  transformedData );
90  m_tree->Fill();
91  }
92 
93  // Write the TTree to the associated ROOT file
94  void writeTree( const std::shared_ptr<TFile>& file, const std::string& algName ) {
95  file->cd();
96  if ( m_tree->Write() <= 0 ) {
97  throw GaudiException( "Failed to write TTree to ROOT file.", algName, StatusCode::FAILURE );
98  }
99  m_tree = nullptr;
100  }
101 
102  virtual ~WriterMixin() = default;
103  };
104 
110  template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
111  struct Writer {
112  Writer() = 0; // If you wish to not provide any transformation for your data, please use the NTuple::GenericWriter
113  // algorithm
114  };
115 
124  template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
125  struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
126  : Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>,
127  WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
128  using Consumer_t = Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>;
129  using Consumer_t::Consumer_t;
130 
131  Gaudi::Property<std::string> m_fileId{ this, "OutputFile", "NTuple", "Identifier for the TFile to write to." };
132  Gaudi::Property<std::string> m_ntupleTname{ this, "NTupleName", this->name(), "Name of the TTree." };
133  Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
134  this, "BranchNames", {}, "Names of the tree branches." }; // Names for the tree branches
135  std::shared_ptr<TFile> m_file = nullptr; // Pointer to the ROOT file
137  mutable std::mutex m_mtx; // Mutex for thread-safe operations
138 
139  // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
140  virtual StatusCode initialize() override {
141  return Consumer_t::initialize().andThen( [this]() {
142  m_fileSvc = this->template service<Gaudi::Interfaces::IFileSvc>( "FileSvc" );
143  if ( !m_fileSvc ) {
144  this->error() << "Failed to retrieve FileSvc." << endmsg;
145  return StatusCode::FAILURE;
146  }
147 
148  m_file = m_fileSvc->getFile( m_fileId );
149  if ( !m_file ) {
150  this->error() << "Failed to retrieve TFile." << endmsg;
151  return StatusCode::FAILURE;
152  }
153 
154  this->initTree( m_file, m_ntupleTname.value(), m_branchNames.value(), this->name() );
155 
156  return StatusCode::SUCCESS;
157  } );
158  }
159 
160  // Execute the algorithm for each event, retrieving data from the event store and writing it to the TTree
161  void operator()( const INPUTs&... args ) const override {
162  std::scoped_lock lock{ m_mtx };
163  this->fillTree( args... );
164  }
165 
166  // Finalize the algorithm by writing the TTree to the file and closing it
167  virtual StatusCode finalize() override {
168  this->writeTree( m_file, this->name() );
169  return Consumer_t::finalize();
170  }
171  };
172 } // namespace Gaudi::NTuple
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::m_fileSvc
Gaudi::Interfaces::IFileSvc * m_fileSvc
Definition: Writer.h:136
std::string
STL class.
std::shared_ptr< TFile >
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:163
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::initialize
virtual StatusCode initialize() override
Definition: Writer.h:140
std::vector
STL class.
StdArrayAsProperty.h
GaudiException
Definition: GaudiException.h:31
Gaudi::NTuple::WriterMixin::WriterMixin
WriterMixin()=0
std::tuple
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:315
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::writeTree
void writeTree(const std::shared_ptr< TFile > &file, const std::string &algName)
Definition: Writer.h:94
Gaudi::Functional::details::Consumer
Definition: Consumer.h:24
Gaudi::NTuple::WriterMixin< std::tuple< OUTPUTs... >(const INPUTs &...)>::initTree
void initTree(const std::shared_ptr< TFile > &file, const std::string &ntupleName, const gsl::span< std::string, sizeof...(OUTPUTs)> branchNames, const std::string &algName)
Definition: Writer.h:64
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::operator()
void operator()(const INPUTs &... args) const override
Definition: Writer.h:161
StatusCode
Definition: StatusCode.h:65
Consumer.h
IFileSvc.h
std::string::c_str
T c_str(T... args)
Gaudi::NTuple
Definition: Writer.h:28
std::array
STL class.
Algorithm.h
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::m_mtx
std::mutex m_mtx
Definition: Writer.h:137
Gaudi::NTuple::Writer::Writer
Writer()=0
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
gaudirun.args
args
Definition: gaudirun.py:336
Gaudi::NTuple::Writer< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ >::finalize
virtual StatusCode finalize() override
Definition: Writer.h:167
BranchWrapper.h
std
STL namespace.
Gaudi::Interfaces::IFileSvc::getFile
virtual std::shared_ptr< TFile > getFile(const std::string &identifier)=0
std::mutex
STL class.
Gaudi::NTuple::WriterMixin
Base template for NTuple::WriterMixin. Actual specializations of this template provide the functional...
Definition: Writer.h:36
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.
Gaudi::Interfaces::IFileSvc
Interface for a component that manages file access within Gaudi applications.
Definition: IFileSvc.h:27
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 std::string &algName) const
Definition: Writer.h:74
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:82
Gaudi::NTuple::Writer
Base template for NTuple::Writer. Actual specializations of this template provide the functionality.
Definition: Writer.h:111
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