The Gaudi Framework  master (34daa81a)
Loading...
Searching...
No Matches
Writer.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2024-2026 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
19#include <mutex>
20#include <numeric>
21#include <ranges>
22#include <tuple>
23#include <utility>
24
25#include <TFile.h>
26#include <TTree.h>
27
28#include <fmt/format.h>
29#include <gsl/pointers>
30#include <gsl/span>
31
32namespace Gaudi::NTuple {
33
47 template <typename... COLUMNS>
48 class Wrapper {
49 public:
50 // Initialize the TTree and creates branches
51 void initTree( TFile& file, std::string const& algName, std::string name,
52 std::array<std::string, sizeof...( COLUMNS )> const& branchNames ) {
53 // handle the case where the name given includes '/', then it's actually a directory and a name
54 auto pos = name.rfind( '/' );
55 if ( pos != std::string::npos ) {
56 m_dir = name.substr( 0, pos );
57 name = name.substr( pos + 1 );
58 }
59 // create directory if needed
60 if ( m_dir != "" ) file.mkdir( m_dir.c_str(), "", true );
61 // Needed for ROOT to write data of the TTree in the right file
62 file.cd( m_dir.c_str() );
63 // create TTree and branches
64 m_tree = std::make_unique<TTree>( name.c_str(), "Tree of Writer Algorithm" ).release();
65 m_branchWrappers.reserve( m_branchWrappers.size() + sizeof...( COLUMNS ) );
66 createBranches( std::make_index_sequence<sizeof...( COLUMNS )>{}, algName, branchNames );
67 }
68
73 void fillTree( std::tuple<COLUMNS...> const& data ) const {
74 std::scoped_lock lock{ m_mtx };
75 std::apply(
76 [&]( const auto&... elems ) {
77 size_t index = 0;
78 ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
79 },
80 data );
81 m_tree->Fill();
82 }
83
84 // Write the TTree to the given ROOT file
85 void writeTree( TFile& file, std::string const& algName ) {
86 // Change to the proper directory in the ROOT file
87 file.cd( m_dir.c_str() );
88 if ( m_tree->Write() <= 0 ) {
89 throw GaudiException( "Failed to write TTree to ROOT file.", algName, StatusCode::FAILURE );
90 }
91 m_tree = nullptr;
92 }
93
94 private:
95 TTree* m_tree{ nullptr }; // Pointer to the TTree being written to
96 std::string m_dir{}; // Directory where to create m_tree
97 mutable std::vector<Gaudi::details::BranchWrapper> m_branchWrappers{}; // Container for BranchWrapper objects
98 mutable std::mutex m_mtx; // Mutex for thread-safe operations
99
100 // Create branches in the TTree based on the provided names and output data types
101 template <std::size_t... Is>
102 void createBranches( std::index_sequence<Is...> const, std::string const& algName,
103 std::array<std::string, sizeof...( COLUMNS )> const& branchNames ) const {
104 ( ..., m_branchWrappers.emplace_back(
105 m_tree, System::typeinfoName( typeid( std::tuple_element_t<Is, std::tuple<COLUMNS...>> ) ),
106 branchNames[Is], "", algName ) );
107 }
108 };
109
118 template <typename Base>
119 struct FileHolder : Base {
120 using Base::Base;
121 TFile* file() { return m_file.get(); }
122 // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
123 virtual StatusCode initialize() override {
124 return Base::initialize().andThen( [this]() {
125 m_file = m_fileSvc->getFile( m_fileId );
126 if ( !m_file ) {
127 this->error() << "Failed to retrieve TFile." << endmsg;
128 return StatusCode::FAILURE;
129 }
130 return StatusCode::SUCCESS;
131 } );
132 }
133
134 private:
135 Gaudi::Property<std::string> m_fileId{ this, "OutputFile", "NTuple", "Identifier for the TFile to write to." };
137 std::shared_ptr<TFile> m_file = nullptr; // Pointer to the ROOT file
138 };
139
144 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
146 SimpleWriter() = delete;
147 };
148
167 template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
168 struct SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
169 : FileHolder<Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>> {
170 using Consumer_t = FileHolder<Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>>;
171 using Consumer_t::Consumer_t;
172
173 Gaudi::Property<std::string> m_ntupleTname{ this, "NTupleName", this->name(), "Name of the TTree." };
174 Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
175 this, "BranchNames", {}, "Names of the tree branches." }; // Names for the tree branches
176
177 // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
178 virtual StatusCode initialize() override {
179 return Consumer_t::initialize().andThen( [this]() {
180 m_ntuple.initTree( *this->file(), this->name(), m_ntupleTname.value(), m_branchNames.value() );
181 return StatusCode::SUCCESS;
182 } );
183 }
184
185 // Fill the TTree with transformed data
186 void fillTree( const std::tuple<OUTPUTs...>& data ) const { m_ntuple.fillTree( data ); }
187
188 // Finalize the algorithm by writing the TTree to the file and closing it
189 virtual StatusCode finalize() override {
190 m_ntuple.writeTree( *this->file(), this->name() );
191 return Consumer_t::finalize();
192 }
193
194 private:
195 Wrapper<OUTPUTs...> m_ntuple;
196 };
197
202 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
203 struct Writer {
204 Writer() = delete; // If you wish to not provide any transformation for your data, please use the
205 // NTuple::GenericWriter
206 // algorithm
207 };
208
220 template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
221 struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
222 : SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_> {
223
224 using SimpleWriter_t = SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>;
225 using SimpleWriter_t::SimpleWriter_t;
226
232 virtual std::tuple<OUTPUTs...> transform( const INPUTs&... inputs ) const = 0;
233
234 // Execute the algorithm for each event, retrieving data from the event store and writing it to the TTree
235 void operator()( const INPUTs&... inputs ) const override {
236 auto transformedData = transform( inputs... );
237 this->fillTree( transformedData );
238 }
239 };
240
241} // namespace Gaudi::NTuple
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
Collection of utilities, which allows to use class std::array as property for Gaudi-components.
Wrapper around a given NTuple.
Definition Writer.h:48
std::mutex m_mtx
Definition Writer.h:98
void fillTree(std::tuple< COLUMNS... > const &data) const
fills the tree with given data this is safe to be called in the threaded context
Definition Writer.h:73
std::vector< Gaudi::details::BranchWrapper > m_branchWrappers
Definition Writer.h:97
void writeTree(TFile &file, std::string const &algName)
Definition Writer.h:85
void createBranches(std::index_sequence< Is... > const, std::string const &algName, std::array< std::string, sizeof...(COLUMNS)> const &branchNames) const
Definition Writer.h:102
std::string m_dir
Definition Writer.h:96
void initTree(TFile &file, std::string const &algName, std::string name, std::array< std::string, sizeof...(COLUMNS)> const &branchNames)
Definition Writer.h:51
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Define general base for Gaudi exception.
Handle to be used in lieu of naked pointers to services.
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition StatusCode.h:163
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
details::Consumer< Signature, Traits_, details::isLegacy< Traits_ > > Consumer
Definition Consumer.h:69
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition System.cpp:260
STL namespace.
Small class wrapping an algorithm and adding management of a Root File via the FileSvc.
Definition Writer.h:119
virtual StatusCode initialize() override
Definition Writer.h:123
FileHolder< Gaudi::Functional::Consumer< void(const INPUTs &...), Traits_ > > Consumer_t
Definition Writer.h:170
Gaudi::Property< std::array< std::string, sizeof...(OUTPUTs)> > m_branchNames
Definition Writer.h:174
virtual std::tuple< OUTPUTs... > transform(const INPUTs &... inputs) const =0
Transform input data to the desired output format.
SimpleWriter< std::tuple< OUTPUTs... >(const INPUTs &...), Traits_ > SimpleWriter_t
Definition Writer.h:224