SFrame 3.6
core/include/SCycleBaseNTuple.icc
Go to the documentation of this file.
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