The Gaudi Framework master (1fbcc22a)
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 <tuple>
21#include <utility>
22
23#include <TFile.h>
24#include <TTree.h>
25
26#include <gsl/pointers>
27
28namespace Gaudi::NTuple {
29
43 template <typename... COLUMNS>
44 class Wrapper {
45 public:
46 // Initialize the TTree and creates branches
47 void initTree( TFile& file, std::string const& algName, std::string name,
48 std::array<std::string, sizeof...( COLUMNS )> const& branchNames ) {
49 // handle the case where the name given includes '/', then it's actually a directory and a name
50 auto pos = name.rfind( '/' );
51 if ( pos != std::string::npos ) {
52 m_dir = name.substr( 0, pos );
53 name = name.substr( pos + 1 );
54 }
55 // create directory if needed
56 if ( m_dir != "" ) file.mkdir( m_dir.c_str(), "", true );
57 // Needed for ROOT to write data of the TTree in the right file
58 file.cd( m_dir.c_str() );
59 // create TTree and branches
60 m_tree = std::make_unique<TTree>( name.c_str(), "Tree of Writer Algorithm" ).release();
61 m_branchWrappers.reserve( m_branchWrappers.size() + sizeof...( COLUMNS ) );
62 createBranches( std::make_index_sequence<sizeof...( COLUMNS )>{}, algName, branchNames );
63 }
64
69 void fillTree( std::tuple<COLUMNS...> const& data ) const {
70 std::scoped_lock lock{ m_mtx };
71 std::apply(
72 [&]( const auto&... elems ) {
73 size_t index = 0;
74 ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
75 },
76 data );
77 m_tree->Fill();
78 }
79
80 // Write the TTree to the given ROOT file
81 void writeTree( TFile& file, std::string const& algName ) {
82 // Change to the proper directory in the ROOT file
83 file.cd( m_dir.c_str() );
84 if ( m_tree->Write() <= 0 ) {
85 throw GaudiException( "Failed to write TTree to ROOT file.", algName, StatusCode::FAILURE );
86 }
87 m_tree = nullptr;
88 }
89
90 private:
91 TTree* m_tree{ nullptr }; // Pointer to the TTree being written to
92 std::string m_dir{}; // Directory where to create m_tree
93 mutable std::vector<Gaudi::details::BranchWrapper> m_branchWrappers{}; // Container for BranchWrapper objects
94 mutable std::mutex m_mtx; // Mutex for thread-safe operations
95
96 // Create branches in the TTree based on the provided names and output data types
97 template <std::size_t... Is>
98 void createBranches( std::index_sequence<Is...> const, std::string const& algName,
99 std::array<std::string, sizeof...( COLUMNS )> const& branchNames ) const {
100 ( ..., m_branchWrappers.emplace_back(
101 m_tree, System::typeinfoName( typeid( std::tuple_element_t<Is, std::tuple<COLUMNS...>> ) ),
102 branchNames[Is], "", algName ) );
103 }
104 };
105
114 template <typename Base>
115 struct FileHolder : Base {
116 using Base::Base;
117 TFile* file() { return m_file.get(); }
118 // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
119 virtual StatusCode initialize() override {
120 return Base::initialize().andThen( [this]() {
122 if ( !m_file ) {
123 this->error() << "Failed to retrieve TFile." << endmsg;
124 return StatusCode::FAILURE;
125 }
126 return StatusCode::SUCCESS;
127 } );
128 }
129
130 private:
131 Gaudi::Property<std::string> m_fileId{ this, "OutputFile", "NTuple", "Identifier for the TFile to write to." };
133 std::shared_ptr<TFile> m_file = nullptr; // Pointer to the ROOT file
134 };
135
140 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
142 SimpleWriter() = delete;
143 };
144
163 template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
164 struct SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
165 : FileHolder<Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>> {
166 using Consumer_t = FileHolder<Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>>;
167 using Consumer_t::Consumer_t;
168
169 Gaudi::Property<std::string> m_ntupleTname{ this, "NTupleName", this->name(), "Name of the TTree." };
170 Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
171 this, "BranchNames", {}, "Names of the tree branches." }; // Names for the tree branches
172
173 // Initialize the algorithm, set up the ROOT file and a TTree branch for each input location
174 virtual StatusCode initialize() override {
175 return Consumer_t::initialize().andThen( [this]() {
176 m_ntuple.initTree( *this->file(), this->name(), m_ntupleTname.value(), m_branchNames.value() );
177 return StatusCode::SUCCESS;
178 } );
179 }
180
181 // Fill the TTree with transformed data
182 void fillTree( const std::tuple<OUTPUTs...>& data ) const { m_ntuple.fillTree( data ); }
183
184 // Finalize the algorithm by writing the TTree to the file and closing it
185 virtual StatusCode finalize() override {
186 m_ntuple.writeTree( *this->file(), this->name() );
187 return Consumer_t::finalize();
188 }
189
190 private:
191 Wrapper<OUTPUTs...> m_ntuple;
192 };
193
198 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
199 struct Writer {
200 Writer() = delete; // If you wish to not provide any transformation for your data, please use the
201 // NTuple::GenericWriter
202 // algorithm
203 };
204
216 template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
217 struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
218 : SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_> {
219
220 using SimpleWriter_t = SimpleWriter<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>;
221 using SimpleWriter_t::SimpleWriter_t;
222
228 virtual std::tuple<OUTPUTs...> transform( const INPUTs&... inputs ) const = 0;
229
230 // Execute the algorithm for each event, retrieving data from the event store and writing it to the TTree
231 void operator()( const INPUTs&... inputs ) const override {
232 auto transformedData = transform( inputs... );
233 this->fillTree( transformedData );
234 }
235 };
236
237} // 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.
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
make_integer_sequence< size_t, _Num > make_index_sequence
constexpr auto data(_Container &__cont) noexcept(noexcept(__cont.data())) -> decltype(__cont.data())
integer_sequence< size_t, _Idx... > index_sequence
const _CharT * c_str() const noexcept
static const size_type npos
constexpr void reserve(size_type __n)
constexpr size_type size() const noexcept
Wrapper around a given NTuple.
Definition Writer.h:44
std::mutex m_mtx
Definition Writer.h:94
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:69
std::vector< Gaudi::details::BranchWrapper > m_branchWrappers
Definition Writer.h:93
void writeTree(TFile &file, std::string const &algName)
Definition Writer.h:81
void createBranches(std::index_sequence< Is... > const, std::string const &algName, std::array< std::string, sizeof...(COLUMNS)> const &branchNames) const
Definition Writer.h:98
std::string m_dir
Definition Writer.h:92
void initTree(TFile &file, std::string const &algName, std::string name, std::array< std::string, sizeof...(COLUMNS)> const &branchNames)
Definition Writer.h:47
Implementation of property with value of concrete type.
Definition Property.h:35
const ValueType & value() const
Definition Property.h:246
GaudiException(std::string Message, std::string Tag, StatusCode Code)
Constructor (1).
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:151
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:47
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition System.cpp:254
STL namespace.
virtual std::shared_ptr< TFile > getFile(const std::string &identifier)=0
Get a shared pointer to a TFile based on an identifier.
Small class wrapping an algorithm and adding management of a Root File via the FileSvc.
Definition Writer.h:115
virtual StatusCode initialize() override
Definition Writer.h:119
FileHolder< Gaudi::Functional::Consumer< void(const INPUTs &...), Traits_ > > Consumer_t
Definition Writer.h:166
Gaudi::Property< std::array< std::string, sizeof...(OUTPUTs)> > m_branchNames
Definition Writer.h:170
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:220