SFrame 3.6
|
00001 // Dear emacs, this is -*- c++ -*- 00002 // $Id: SCycleBaseNTuple.icc 333 2012-11-21 09:19:50Z krasznaa $ 00003 /*************************************************************************** 00004 * @Project: SFrame - ROOT-based analysis framework for ATLAS 00005 * @Package: Core 00006 * 00007 * @author Stefan Ask <Stefan.Ask@cern.ch> - Manchester 00008 * @author David Berge <David.Berge@cern.ch> - CERN 00009 * @author Johannes Haller <Johannes.Haller@cern.ch> - Hamburg 00010 * @author A. Krasznahorkay <Attila.Krasznahorkay@cern.ch> - CERN/Debrecen 00011 * 00012 ***************************************************************************/ 00013 00014 #ifndef SFRAME_CORE_SCycleBaseNTuple_ICC 00015 #define SFRAME_CORE_SCycleBaseNTuple_ICC 00016 00017 // System include(s): 00018 #include <string.h> 00019 #include <cxxabi.h> 00020 #include <cstdlib> 00021 00022 // STL include(s): 00023 #include <sstream> 00024 #include <typeinfo> 00025 00026 // ROOT include(s): 00027 #include <TTree.h> 00028 #include <TBranch.h> 00029 #include <TLeaf.h> 00030 #include <TString.h> 00031 00032 // Local include(s): 00033 #include "SPointer.h" 00034 00057 template< typename T > 00058 bool SCycleBaseNTuple::ConnectVariable( const char* treeName, const char* branchName, 00059 T& variable ) throw ( SError ) { 00060 00061 REPORT_VERBOSE( "Called with treeName = \"" << treeName 00062 << "\", branchName = \"" << branchName << "\"" ); 00063 00064 // Access the TTree. The function will throw an exception if unsuccessful 00065 TTree* tree = GetInputTree( treeName ); 00066 TBranch* br = 0; 00067 00068 // Check if the branch actually exists: 00069 TBranch* branch_info; 00070 if( ! ( branch_info = tree->GetBranch( branchName ) ) ) { 00071 REPORT_ERROR( "Branch \"" << branchName << "\" doesn't exist in TTree \"" 00072 << treeName << "\"" ); 00073 return false; 00074 } 00075 00076 // 00077 // Detect what kind of variable we're dealing with: 00078 // 00079 const char* type_name = typeid( variable ).name(); 00080 REPORT_VERBOSE( "Type ID: " << type_name ); 00081 if( strlen( type_name ) == 1 ) { 00082 00083 // Check whether the branch matches the type of the variable given to this 00084 // function: 00085 REPORT_VERBOSE( "Type of the variable held by the branch: " 00086 << branch_info->GetTitle() ); 00087 00088 // Try to determine if the user is trying to connect a variable of the correct 00089 // type to the branch. Let's first assume that there is only one leaf, which 00090 // is called the same as the branch. This is the ATLAS convention. 00091 TLeaf* leaf = branch_info->GetLeaf( branchName ); 00092 Bool_t simple_branch = kFALSE; 00093 if( ! leaf ) { 00094 // If there isn't a leaf with the name of the branch, try to look for all the 00095 // leaves. It could be that there is a single leaf with some other name, or that 00096 // there are a number of leaves. 00097 std::vector< TLeaf* > leaves; 00098 TObjArray* tleaves = branch_info->GetListOfLeaves(); 00099 for( Int_t i = 0; i < tleaves->GetSize(); ++i ) { 00100 // In my experience not all objects in the array are actual TLeaf 00101 // objects... 00102 TLeaf* local_leaf = dynamic_cast< TLeaf* >( tleaves->At( i ) ); 00103 if( local_leaf ) { 00104 leaves.push_back( local_leaf ); 00105 } 00106 } 00107 // If there is a single leaf, then the type checking can continue: 00108 if( leaves.size() == 1 ) { 00109 leaf = leaves[ 0 ]; 00110 simple_branch = kTRUE; 00111 } 00112 // If there are multiple leaves, then we'll have to skip the type checking: 00113 else if( leaves.size() > 1 ) { 00114 simple_branch = kFALSE; 00115 } 00116 // If we didn't find any leaves, then something is definitely wrong: 00117 else { 00118 REPORT_ERROR( "Couldn't interrogate branch: " << branchName ); 00119 REPORT_ERROR( "Are you trying to connect a primitive to a branch describing " 00120 "an object?" ); 00121 throw SError( "Couldn't interrogate branch: " + TString( branchName ), 00122 SError::SkipFile ); 00123 } 00124 } else { 00125 simple_branch = kTRUE; 00126 } 00127 // 00128 // Only do the type checking if there is a single leaf: 00129 // 00130 if( simple_branch ) { 00131 REPORT_VERBOSE( "Leaf type: " << leaf->GetTypeName() ); 00132 00133 // Now check if the leaf has the correct type: 00134 if( strcmp( type_name, TypeidType( leaf->GetTypeName() ) ) ) { 00135 REPORT_ERROR( "Trying to connect a wrong type of primitive to the branch: " 00136 << branchName ); 00137 REPORT_ERROR( " Use variable of type: " << leaf->GetTypeName() ); 00138 throw SError( "Wrong variable type given for branch: " + TString( branchName ), 00139 SError::SkipCycle ); 00140 } else { 00141 REPORT_VERBOSE( "The branch and variable types seem to match" ); 00142 } 00143 } else { 00144 // Let the user know that we can't do any type checking... 00145 m_logger << INFO << "Connecting to a branch with multiple leaves." 00146 << "Type correctness can't be checked!" << SLogger::endmsg; 00147 } 00148 00149 // For primitive types nothing fancy needs to be done 00150 REPORT_VERBOSE( "The supplied variable is a \"primitive\"" ); 00151 tree->SetBranchStatus( branchName, 1 ); 00152 tree->SetBranchAddress( branchName, &variable, &br ); 00153 00154 } else { 00155 00156 throw SError( "ConnectVariable(...) called with an unknown variable type", 00157 SError::SkipCycle ); 00158 00159 } 00160 00161 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 26, 0 ) 00162 tree->AddBranchToCache( br, kTRUE ); 00163 #endif // ROOT_VERSION... 00164 this->RegisterInputBranch( br ); 00165 m_logger << DEBUG << "Connected branch \"" << branchName << "\" in tree \"" 00166 << treeName << "\"" << SLogger::endmsg; 00167 00168 return true; 00169 } 00170 00203 template< typename T, size_t size > 00204 bool SCycleBaseNTuple::ConnectVariable( const char* treeName, const char* branchName, 00205 T ( &variable )[ size ] ) throw( SError ) { 00206 00207 // Access the TTree. The function will throw an exception if unsuccessful 00208 TTree* tree = GetInputTree( treeName ); 00209 TBranch* br = 0; 00210 00211 // Check if the branch actually exists: 00212 if( ! tree->GetBranch( branchName ) ) { 00213 REPORT_ERROR( "Branch \"" << branchName << "\" doesn't exist in TTree \"" 00214 << treeName << "\"" ); 00215 return false; 00216 } 00217 00218 // 00219 // Print what kind of variable we're dealing with: 00220 // 00221 const char* type_name = typeid( variable ).name(); 00222 REPORT_VERBOSE( "Type ID: " << type_name ); 00223 00224 REPORT_VERBOSE( "The supplied variable is a \"primitive array\"" ); 00225 tree->SetBranchStatus( branchName, 1 ); 00226 tree->SetBranchAddress( branchName, variable, &br ); 00227 00228 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 26, 0 ) 00229 tree->AddBranchToCache( br, kTRUE ); 00230 #endif // ROOT_VERSION... 00231 this->RegisterInputBranch( br ); 00232 m_logger << DEBUG << "Connected branch \"" << branchName << "\" in tree \"" 00233 << treeName << "\"" << SLogger::endmsg; 00234 00235 return true; 00236 } 00237 00267 template< typename T > 00268 bool SCycleBaseNTuple::ConnectVariable( const char* treeName, const char* branchName, 00269 T*& variable ) throw ( SError ) { 00270 00271 // Access the TTree. The function will throw an exception if unsuccessful 00272 TTree* tree = GetInputTree( treeName ); 00273 TBranch* br = 0; 00274 00275 // Check if the branch actually exists: 00276 if( ! tree->GetBranch( branchName ) ) { 00277 REPORT_ERROR( "Branch \"" << branchName << "\" doesn't exist in TTree \"" 00278 << treeName << "\"" ); 00279 return false; 00280 } 00281 00282 // To make sure that typeid(...) will succeed. All classes that can be written out 00283 // by ROOT have to have a default constructor anyway... 00284 variable = new T(); 00285 00286 // 00287 // Detect what kind of variable we're dealing with: 00288 // 00289 const char* type_name = typeid( *variable ).name(); 00290 REPORT_VERBOSE( "Type ID: " << type_name ); 00291 delete variable; // now let's dispose of the object 00292 if( strlen( type_name ) == 1 ) { 00293 00294 throw SError( "ConnectVariable(...) specialised for object pointers called " 00295 "with a simple variable.", SError::SkipCycle ); 00296 00297 } else { 00298 00299 // The object pointers have to be initialised to zero before 00300 // connecting them to the branches 00301 REPORT_VERBOSE( "The supplied variable is an object pointer" ); 00302 variable = 0; 00303 tree->SetBranchStatus( TString( branchName ) + "*", 1 ); 00304 tree->SetBranchAddress( branchName, &variable, &br ); 00305 // Take ownership of this new object: 00306 m_inputVarPointers.push_back( new SPointer< T >( variable ) ); 00307 00308 } 00309 00310 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 26, 0 ) 00311 tree->AddBranchToCache( br, kTRUE ); 00312 #endif // ROOT_VERSION... 00313 this->RegisterInputBranch( br ); 00314 m_logger << DEBUG << "Connected branch \"" << branchName << "\" in tree \"" 00315 << treeName << "\"" << SLogger::endmsg; 00316 00317 return true; 00318 } 00319 00345 template < class T > 00346 TBranch* SCycleBaseNTuple::DeclareVariable( T& obj, const char* name, 00347 const char* treeName ) throw( SError ) { 00348 00349 TTree* tree = 0; 00350 TBranch* branch = 0; 00351 00352 // 00353 // Find the pointer to the output tree: 00354 // 00355 if( treeName ) { 00356 00357 // Consider both "normal" and metadata trees: 00358 try { 00359 tree = GetOutputTree( treeName ); 00360 } catch( const SError& error ) { 00361 if( error.request() <= SError::SkipFile ) { 00362 // Try to find a metadata tree if a regular tree is not found 00363 // with this name: 00364 REPORT_VERBOSE( "Output tree with name \"" << name 00365 << "\" not found. Trying to find a metadata tree " 00366 << "instead." ); 00367 tree = GetOutputMetadataTree( treeName ); 00368 } else { 00369 REPORT_ERROR( "Exception message caught with message: " 00370 << error.what() ); 00371 throw; 00372 } 00373 } 00374 00375 } else { 00376 00377 if( m_outputTrees.size() != 1 ) { 00378 SError error( SError::SkipInputData ); 00379 error << "There can't be other than 1 output tree defined in order not to\n"; 00380 error << "define a tree name in SCycleBaseNTuple::DeclareVariable(...)!"; 00381 throw error; 00382 } 00383 00384 tree = m_outputTrees.front(); 00385 00386 } 00387 00388 // 00389 // Check if the tree has been found: 00390 // 00391 if( ! tree ) { 00392 SError error( SError::SkipInputData ); 00393 if( treeName ) { 00394 error << "Couldn't find output tree with name: " << treeName; 00395 } else { 00396 error << "Couldn't find default output tree"; 00397 } 00398 throw error; 00399 } 00400 00401 REPORT_VERBOSE( "Found output tree with name: " << tree->GetName() ); 00402 00403 // Check if the branch exists already: 00404 branch = tree->GetBranch( name ); 00405 if( ! branch ) { 00406 00407 // 00408 // This branch doesn't exist yet. We have to (try to) create it. 00409 // 00410 m_logger << DEBUG << "Creating new output branch with name: " << name 00411 << SLogger::endmsg; 00412 00413 // First of all, lets figure out what kind of object we're dealing with 00414 const char* type_name = typeid( obj ).name(); 00415 00416 if( strlen( type_name ) == 1 ) { 00417 00418 // 00419 // This is a simple variable: 00420 // 00421 REPORT_VERBOSE( "The supplied variable is a \"primitive\"" ); 00422 00423 std::ostringstream leaflist; 00424 leaflist << name << "/" << RootType( type_name ); 00425 branch = tree->Branch( name, &obj, leaflist.str().c_str() ); 00426 00427 } else { 00428 00429 // 00430 // This is an object: 00431 // 00432 REPORT_VERBOSE( "The supplied variable is an object" ); 00433 00434 int status; 00435 char* real_type_name = abi::__cxa_demangle( type_name, 0, 0, &status ); 00436 if( status ) { 00437 SError error( SError::StopExecution ); 00438 error << "Couldn't demangle type name: " << type_name; 00439 throw error; 00440 } 00441 00442 REPORT_VERBOSE( "Mangled name of object: " << type_name ); 00443 REPORT_VERBOSE( "De-mangled name of object: " << real_type_name ); 00444 00445 // 00446 // Then try to add the object to the TTree. We have to do it in such a weird way, 00447 // since the "pointer" variable is going to disappear at the end of this function 00448 // so giving "&pointer" to TTree::Bronch would cause quite a crash when you're 00449 // writing out the event. (Trust me, I *know*... :-)) I'm storing the pointers 00450 // in an std::list, since lists don't move their elements around. 00451 // (vectors are allowed to do that. This one I've just read... :-)) 00452 // 00453 T* pointer = &obj; 00454 m_outputVarPointers.push_back( pointer ); 00455 branch = tree->Bronch( name, real_type_name, &m_outputVarPointers.back() ); 00456 00457 free( real_type_name ); 00458 00459 } 00460 00461 if( ! branch ) { 00462 SError error( SError::SkipInputData ); 00463 error << "Couldn't create branch with name: " << name; 00464 throw error; 00465 } 00466 00467 REPORT_VERBOSE( "Successfully added branch" ); 00468 00469 } else { 00470 00471 m_logger << WARNING << "A branch with the name \"" << name << "\" already exists" 00472 << SLogger::endmsg; 00473 m_logger << WARNING << "New object not added to tree!" << SLogger::endmsg; 00474 00475 } 00476 00477 return branch; 00478 } 00479 00480 #endif // SFRAME_CORE_SCycleBaseNTuple_ICC