The Gaudi Framework  master (adcf1ca6)
Loading...
Searching...
No Matches
BranchWrapper.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2024-2025 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#include <Gaudi/Algorithm.h>
13#include <TMemFile.h>
14#include <TTree.h>
15#include <format>
16#include <map>
17#include <memory>
18#include <string>
19
20namespace {
21 // Mapping from C++ type names to ROOT branch types for branch creation
22 const std::map<std::string, std::string, std::less<>> typeMap = {
23 { "char", "B" }, { "unsigned char", "b" }, { "short", "S" }, { "unsigned short", "s" },
24 { "int", "I" }, { "unsigned int", "i" }, { "float", "F" }, { "double", "D" },
25 { "long long", "L" }, { "unsigned long long", "l" }, { "long", "G" }, { "unsigned long", "g" },
26 { "bool", "O" } };
27
28 // Helper function to find the ROOT branch type corresponding to a C++ type
29 std::optional<std::string> getLeafListForType( const std::string_view& typeName ) {
30 auto it = typeMap.find( typeName );
31 return ( it != typeMap.end() ) ? std::optional<std::string>{ it->second } : std::nullopt;
32 }
33} // namespace
34
35namespace Gaudi::details {
36
37 BranchWrapper::BranchWrapper( const gsl::not_null<TTree*> tree, const std::string& className,
38 const std::string& branchName, const std::string& location, const std::string& algName,
39 unsigned int bufferSize, unsigned int splitLevel )
40 : m_className( className ), m_location( location ) {
41 auto leafListTag = getLeafListForType( m_className );
42 if ( leafListTag ) {
43 // Create a branch for fundamental types using the leaflist
44 m_branch = tree->Branch( branchName.c_str(), &m_dataBuffer,
45 ( std::format( "{}/{}", m_className, leafListTag.value() ) ).c_str(), bufferSize );
46 setBranchAddress = []( gsl::not_null<TBranch*> br, const void** wrappedDataPtr ) {
47 br->SetAddress( const_cast<void*>( *wrappedDataPtr ) );
48 };
49
50 } else if ( TClass::GetClass( m_className.c_str() ) ) {
51 // Create a branch for object types using the classname string
52 m_branch = tree->Branch( branchName.c_str(), m_className.c_str(), &m_dataBuffer, bufferSize, splitLevel );
53 setBranchAddress = []( gsl::not_null<TBranch*> br, const void** wrappedDataPtr ) {
54 br->SetAddress( wrappedDataPtr );
55 };
56
57 } else {
58 throw GaudiException( std::format( "Cannot create branch {} for unknown class: {}. Provide a dictionary please.",
59 branchName, m_className ),
60 algName, StatusCode::FAILURE );
61 }
62
63 if ( !m_branch ) {
64 throw GaudiException( std::format( "Failed to create branch {} for type {}.", branchName, m_className ), algName,
66 }
67 }
68
69 // Set the data pointer for the branch from a given address
70 // Used by Gaudi::NTuple::Writer
71 void BranchWrapper::setDataPtr( void const* dataPtr ) {
72 m_dataBuffer = dataPtr;
74 }
75
76 // Set the data for the branch from a given DataObject
77 // Used by Gaudi::NTuple::GenericWriter
78 void BranchWrapper::setBranchData( const gsl::not_null<DataObject*> pObj ) {
79 auto baseWrapper = dynamic_cast<AnyDataWrapperBase*>( pObj.get() );
80 m_dataBuffer = baseWrapper ? baseWrapper->payload() : pObj.get();
82 }
83
84 unsigned int BranchWrapper::computeOptimalBufferSize( unsigned int minBufferSize, unsigned int maxBufferSize,
85 unsigned int approxEventsPerBasket, unsigned int splitLevel ) {
86 // simply try to write one item in a dummey branch of a dummy tree im memory and measure size
87 auto dummy_file = std::make_unique<TMemFile>( "dummy.root", "CREATE" );
88 auto dummy_tree = std::make_unique<TTree>( "DummyTree", "DummyTree", splitLevel, dummy_file->GetDirectory( "/" ) );
89 auto leafListTag = getLeafListForType( m_className );
90 TBranch* dummy_branch{ nullptr };
91 if ( leafListTag ) {
92 // Create a branch for fundamental types using the leaflist
93 dummy_branch =
94 dummy_tree->Branch( "DummyBranch", &m_dataBuffer,
95 ( fmt::format( "{}/{}", m_className, leafListTag.value() ) ).c_str(), minBufferSize );
96 } else if ( TClass::GetClass( m_className.c_str() ) ) {
97 // Create a branch for object types using the classname string
98 dummy_branch = dummy_tree->Branch( "DummyBranch", m_className.c_str(), &m_dataBuffer, minBufferSize, splitLevel );
99 } // no else as unknown className would have raised an exception at constructor level
100 int nWritten = dummy_branch->Fill();
101 if ( nWritten >= 0 ) {
102 unsigned int newBasketSize = nWritten * approxEventsPerBasket;
103 // Ensure that newBasketSize doesn't wrap around
104 if ( std::numeric_limits<Int_t>::max() / approxEventsPerBasket < (unsigned int)nWritten ) {
105 newBasketSize = std::numeric_limits<Int_t>::max();
106 }
107 return std::min( maxBufferSize, std::max( minBufferSize, newBasketSize ) );
108 }
109 return minBufferSize;
110 }
111
113 if ( !m_branch ) return;
114 auto nEvents = m_branch->GetTree()->GetEntries();
115 auto nEntries = m_branch->GetEntries();
116 if ( nEntries < nEvents ) {
117 m_branch->SetAddress( nullptr );
118 for ( auto i = nEntries; i < nEvents; i++ ) { m_branch->Fill(); }
119 }
120 }
121
122} // namespace Gaudi::details
Define general base for Gaudi exception.
constexpr static const auto FAILURE
Definition StatusCode.h:100
unsigned int computeOptimalBufferSize(unsigned int minBufferSize, unsigned int maxBufferSize, unsigned int approxEventsPerBasket, unsigned int splitLevel)
compute optimal buffer size to fit given number of element per basket, respecting given min and max
void padEntries()
pad the number of item in the branch to the one of the Tree in which it leaves by adding empty entrie...
void(* setBranchAddress)(gsl::not_null< TBranch * >, const void **)
void setDataPtr(void const *dataPtr)
BranchWrapper(const gsl::not_null< TTree * > tree, const std::string &className, const std::string &branchName, const std::string &location, const std::string &algName, unsigned int bufferSize=32000, unsigned int splitLevel=99)
void setBranchData(const gsl::not_null< DataObject * > pObj)