File indexing completed on 2025-04-26 09:01:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #pragma once
0012
0013 #include <Gaudi/Algorithm.h>
0014 #include <Gaudi/Functional/Consumer.h>
0015 #include <Gaudi/Interfaces/IFileSvc.h>
0016 #include <Gaudi/details/BranchWrapper.h>
0017 #include <GaudiKernel/StdArrayAsProperty.h>
0018 #include <TFile.h>
0019 #include <TTree.h>
0020 #include <fmt/format.h>
0021 #include <gsl/pointers>
0022 #include <gsl/span>
0023 #include <mutex>
0024 #include <numeric>
0025 #include <tuple>
0026 #include <utility>
0027
0028 namespace Gaudi::NTuple {
0029
0030
0031
0032
0033
0034
0035 template <typename Signature>
0036 struct WriterMixin {
0037 WriterMixin() = 0;
0038
0039 };
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 template <typename... OUTPUTs, typename... INPUTs>
0051 struct WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
0052 TTree* m_tree = nullptr;
0053 std::array<std::string, sizeof...( OUTPUTs )> m_branchNames;
0054 mutable std::vector<details::BranchWrapper> m_branchWrappers{};
0055
0056
0057
0058
0059
0060
0061 virtual std::tuple<OUTPUTs...> transform( const INPUTs&... inputs ) const = 0;
0062
0063
0064 void initTree( const std::shared_ptr<TFile>& file, const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames,
0065 const Gaudi::Algorithm& algRef ) {
0066 file->cd();
0067 m_tree = std::make_unique<TTree>( "WriterTree", "Tree of Writer Algorithm" ).release();
0068 m_branchWrappers.reserve( m_branchWrappers.size() + sizeof...( OUTPUTs ) );
0069 createBranchesForOutputs( branchNames, std::make_index_sequence<sizeof...( OUTPUTs )>{}, algRef );
0070 }
0071
0072
0073 template <std::size_t... Is>
0074 void createBranchesForOutputs( const gsl::span<std::string, sizeof...( OUTPUTs )> branchNames,
0075 const std::index_sequence<Is...>, const Gaudi::Algorithm& algRef ) const {
0076 ( ..., m_branchWrappers.emplace_back(
0077 m_tree, System::typeinfoName( typeid( std::tuple_element_t<Is, std::tuple<OUTPUTs...>> ) ),
0078 branchNames[Is], "", algRef ) );
0079 }
0080
0081
0082 void fillTree( const INPUTs&... inputs ) const {
0083 auto transformedData = transform( inputs... );
0084 std::apply(
0085 [&]( const auto&... elems ) {
0086 size_t index = 0;
0087 ( ..., m_branchWrappers[index++].setDataPtr( const_cast<void*>( static_cast<const void*>( &elems ) ) ) );
0088 },
0089 transformedData );
0090 m_tree->Fill();
0091 }
0092
0093
0094 void writeTree( const std::shared_ptr<TFile>& file, const Gaudi::Algorithm& algRef ) {
0095 file->cd();
0096 if ( m_tree->Write() <= 0 ) {
0097 throw GaudiException( "Failed to write TTree to ROOT file.", algRef.name(), StatusCode::FAILURE );
0098 }
0099 m_tree = nullptr;
0100 algRef.info() << "TTree written to TFile." << endmsg;
0101 }
0102
0103 virtual ~WriterMixin() = default;
0104 };
0105
0106
0107
0108
0109
0110
0111 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>>
0112 struct Writer {
0113 Writer() = 0;
0114
0115 };
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 template <typename... OUTPUTs, typename... INPUTs, typename Traits_>
0126 struct Writer<std::tuple<OUTPUTs...>( const INPUTs&... ), Traits_>
0127 : Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>,
0128 WriterMixin<std::tuple<OUTPUTs...>( const INPUTs&... )> {
0129 using Consumer_t = Gaudi::Functional::Consumer<void( const INPUTs&... ), Traits_>;
0130 using Consumer_t::Consumer_t;
0131
0132 Gaudi::Property<std::string> m_fileId{ this, "OutputFile", "NTuple", "Identifier for the TFile to write to." };
0133 Gaudi::Property<std::array<std::string, sizeof...( OUTPUTs )>> m_branchNames{
0134 this, "BranchNames", {}, "Names of the tree branches." };
0135 std::shared_ptr<TFile> m_file = nullptr;
0136 Gaudi::Interfaces::IFileSvc* m_fileSvc;
0137 mutable std::mutex m_mtx;
0138
0139
0140 virtual StatusCode initialize() override {
0141 return Consumer_t::initialize().andThen( [this]() {
0142 m_fileSvc = this->template service<Gaudi::Interfaces::IFileSvc>( "FileSvc" );
0143 if ( !m_fileSvc ) {
0144 this->error() << "Failed to retrieve FileSvc." << endmsg;
0145 return StatusCode::FAILURE;
0146 }
0147
0148 m_file = m_fileSvc->getFile( m_fileId );
0149 if ( !m_file ) {
0150 this->error() << "Failed to retrieve TFile." << endmsg;
0151 return StatusCode::FAILURE;
0152 }
0153
0154 this->initTree( m_file, m_branchNames.value(), *this );
0155
0156 return StatusCode::SUCCESS;
0157 } );
0158 }
0159
0160
0161 void operator()( const INPUTs&... args ) const override {
0162 std::lock_guard<std::mutex> lock( m_mtx );
0163 this->fillTree( args... );
0164 }
0165
0166
0167 virtual StatusCode finalize() override {
0168 this->writeTree( m_file, *this );
0169 return Consumer_t::finalize();
0170 }
0171 };
0172 }