The Gaudi Framework  master (b9786168)
Loading...
Searching...
No Matches
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
28namespace 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
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.
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Define general base for Gaudi exception.
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.
Interface for a component that manages file access within Gaudi applications.
Definition IFileSvc.h:27
Gaudi::Functional::Consumer< void(const INPUTs &...), Traits_ > Consumer_t
Definition Writer.h:128
Gaudi::Property< std::array< std::string, sizeof...(OUTPUTs)> > m_branchNames
Definition Writer.h:133
void writeTree(const std::shared_ptr< TFile > &file, const std::string &algName)
Definition Writer.h:94
std::array< std::string, sizeof...(OUTPUTs)> m_branchNames
Definition Writer.h:53
void createBranchesForOutputs(const gsl::span< std::string, sizeof...(OUTPUTs)> branchNames, const std::index_sequence< Is... >, const std::string &algName) const
Definition Writer.h:74
virtual std::tuple< OUTPUTs... > transform(const INPUTs &... inputs) const =0
Transform input data to the desired output format.
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