SFrame 3.6
|
00001 // $Id: SCycleOutput.cxx 191 2010-08-04 08:00:45Z krasznaa $ 00002 /*************************************************************************** 00003 * @Project: SFrame - ROOT-based analysis framework for ATLAS 00004 * @Package: Core 00005 * 00006 * @author Stefan Ask <Stefan.Ask@cern.ch> - Manchester 00007 * @author David Berge <David.Berge@cern.ch> - CERN 00008 * @author Johannes Haller <Johannes.Haller@cern.ch> - Hamburg 00009 * @author A. Krasznahorkay <Attila.Krasznahorkay@cern.ch> - CERN/Debrecen 00010 * 00011 ***************************************************************************/ 00012 00013 // System include(s): 00014 #include <string.h> 00015 00016 // STL include(s): 00017 #include <vector> 00018 00019 // ROOT include(s): 00020 #include <TCollection.h> 00021 #include <TList.h> 00022 #include <TMethodCall.h> 00023 #include <TDirectory.h> 00024 #include <TTree.h> 00025 #include <TKey.h> 00026 #include <TObjArray.h> 00027 #include <TObjString.h> 00028 00029 // Local include(s): 00030 #include "../include/SCycleOutput.h" 00031 #include "../include/SLogger.h" 00032 00033 #ifndef DOXYGEN_IGNORE 00034 ClassImp( SCycleOutput ); 00035 #endif // DOXYGEN_IGNORE 00036 00045 SCycleOutput::SCycleOutput( TObject* object, const char* name, 00046 const char* path ) 00047 : TNamed( name, "SFrame cycle output object" ), m_object( object ), 00048 m_path( path ), m_logger( "SCycleOutput" ) { 00049 00050 } 00051 00056 SCycleOutput::~SCycleOutput() { 00057 00058 if( m_object ) delete m_object; 00059 } 00060 00064 TObject* SCycleOutput::GetObject() const { 00065 00066 return m_object; 00067 } 00068 00072 void SCycleOutput::SetObject( TObject* object ) { 00073 00074 m_object = object; 00075 return; 00076 } 00077 00078 const TString& SCycleOutput::GetPath() const { 00079 00080 return m_path; 00081 } 00082 00083 void SCycleOutput::SetPath( const TString& path ) { 00084 00085 m_path = path; 00086 return; 00087 } 00088 00099 Int_t SCycleOutput::Merge( TCollection* coll ) { 00100 00101 // 00102 // Return right away if the input is flawed: 00103 // 00104 if( ! coll ) return 0; 00105 if( coll->IsEmpty() ) return 0; 00106 00107 // 00108 // Select the elements from the collection that can actually be merged: 00109 // 00110 TList list; 00111 TIter next( coll ); 00112 TObject* obj = 0; 00113 while( ( obj = next() ) ) { 00114 00115 // 00116 // See if it is an SCycleOutput object itself: 00117 // 00118 SCycleOutput* sobj = dynamic_cast< SCycleOutput* >( obj ); 00119 if( ! sobj ) { 00120 REPORT_ERROR( "Trying to merge \"" << obj->ClassName() 00121 << "\" object into \"" << this->ClassName() << "\"" ); 00122 continue; 00123 } 00124 00125 // 00126 // See if it holds the same kind of object as this output object: 00127 // 00128 TObject* mobj = sobj->GetObject(); 00129 if( ! mobj ) continue; 00130 if( strcmp( mobj->ClassName(), this->GetObject()->ClassName() ) ) { 00131 REPORT_ERROR( "Trying to merge \"" << mobj->ClassName() 00132 << "\" object into \"" << this->GetObject()->ClassName() ); 00133 continue; 00134 } 00135 00136 // 00137 // If everything is fine, add it to the list of objects to merge: 00138 // 00139 list.Add( mobj ); 00140 00141 } 00142 00143 // 00144 // Stop if the list is empty: 00145 // 00146 if( list.IsEmpty() ) { 00147 m_logger << WARNING << "No suitable object found for merging" << SLogger::endmsg; 00148 return 0; 00149 } 00150 00151 // 00152 // Make sure that my object supports merging: 00153 // 00154 TMethodCall mergeMethod; 00155 mergeMethod.InitWithPrototype( this->GetObject()->IsA(), "Merge", "TCollection*" ); 00156 if( ! mergeMethod.IsValid() ) { 00157 REPORT_ERROR( "Object type \"" << this->GetObject()->ClassName() 00158 << "\" doesn't support merging" ); 00159 return 0; 00160 } 00161 00162 // 00163 // Execute the merging: 00164 // 00165 mergeMethod.SetParam( ( Long_t ) &list ); 00166 mergeMethod.Execute( this->GetObject() ); 00167 00168 // 00169 // A little feedback of what we've done: 00170 // 00171 m_logger << DEBUG << "Merged objects of type \"" << this->GetObject()->ClassName() 00172 << "\"" << SLogger::endmsg; 00173 00174 return 1; 00175 00176 } 00177 00188 Int_t SCycleOutput::Write( const char* name, Int_t option, 00189 Int_t bufsize ) const { 00190 00191 // Nothing to be done with no object: 00192 if( ! m_object ) return -1; 00193 00194 // 00195 // Remember both the current directory, and create the directory for the 00196 // output object: 00197 // 00198 TDirectory* origDir = gDirectory; 00199 TDirectory* outDir = MakeDirectory( m_path ); 00200 00201 // 00202 // Check if the output directory already holds such an object: 00203 // 00204 TObject* original_obj; 00205 if( ( original_obj = outDir->Get( m_object->GetName() ) ) ) { 00206 00207 m_logger << DEBUG << "Merging object \"" << m_object->GetName() << "\" under \"" 00208 << m_path << "\" with already existing object..." << SLogger::endmsg; 00209 00210 // 00211 // Check that it's the same type as the object that we want to save: 00212 // 00213 if( strcmp( original_obj->ClassName(), m_object->ClassName() ) ) { 00214 REPORT_ERROR( "Object in file (\"" << original_obj->ClassName() 00215 << "\") is not the same type as the object in memory (\"" 00216 << m_object->ClassName() << "\")" ); 00217 return 0; 00218 } 00219 00220 // 00221 // Try to merge the new object into the old one: 00222 // 00223 TMethodCall mergeMethod; 00224 mergeMethod.InitWithPrototype( original_obj->IsA(), "Merge", "TCollection*" ); 00225 if( ! mergeMethod.IsValid() ) { 00226 REPORT_ERROR( "Object type \"" << original_obj->ClassName() 00227 << "\" doesn't support merging" ); 00228 return 0; 00229 } 00230 00231 // 00232 // Remember the key of this object, to be able to remove it after the merging: 00233 // 00234 TKey* oldKey = outDir->GetKey( m_object->GetName() ); 00235 00236 // 00237 // Execute the merging: 00238 // 00239 TList list; 00240 list.Add( m_object ); 00241 mergeMethod.SetParam( ( Long_t ) &list ); 00242 mergeMethod.Execute( original_obj ); 00243 00244 // 00245 // Remove the old object from the file: 00246 // 00247 oldKey->Delete(); 00248 delete oldKey; 00249 00250 // Return gracefully: 00251 return 1; 00252 00253 } 00254 00255 // 00256 // TTree-s have to be handled in a special way: 00257 // 00258 TTree* tobject = dynamic_cast< TTree* >( m_object ); 00259 if( tobject ) tobject->SetDirectory( outDir ); 00260 00261 // 00262 // Write out the object: 00263 // 00264 outDir->cd(); 00265 Int_t ret = m_object->Write( name, option, bufsize ); 00266 if( tobject ) tobject->AutoSave(); 00267 origDir->cd(); 00268 00269 // Remove the memory-resident TTree from the directory: 00270 if( tobject ) tobject->SetDirectory( 0 ); 00271 00272 REPORT_VERBOSE( "Written object \"" << m_object->GetName() 00273 <<"\" to: " << outDir->GetPath() ); 00274 00275 return ret; 00276 00277 } 00278 00279 Int_t SCycleOutput::Write( const char* name, Int_t option, 00280 Int_t bufsize ) { 00281 00282 return const_cast< const SCycleOutput* >( this )->Write( name, option, bufsize ); 00283 } 00284 00291 TDirectory* SCycleOutput::MakeDirectory( const TString& path ) const throw( SError ) { 00292 00293 if( ! path.Length() ) return gDirectory; 00294 00295 TDirectory* dir = 0; 00296 if( ! ( dir = gDirectory->GetDirectory( path ) ) ) { 00297 00298 REPORT_VERBOSE( "Creating directory: " 00299 << gDirectory->GetPath() << "/" << path ); 00300 00301 // 00302 // Break up the path name at the slashes: 00303 // 00304 TObjArray* directories = path.Tokenize( "/" ); 00305 00306 // 00307 // Create each necessary directory: 00308 // 00309 dir = gDirectory; 00310 TDirectory* tempDir = 0; 00311 for( Int_t i = 0; i < directories->GetSize(); ++i ) { 00312 00313 TObjString* path_element = dynamic_cast< TObjString* >( directories->At( i ) ); 00314 if( ! path_element ) continue; 00315 if( path_element->GetString() == "" ) continue; 00316 00317 REPORT_VERBOSE( "Accessing directory: " << path_element->GetString() ); 00318 if( ! ( tempDir = dir->GetDirectory( path_element->GetString() ) ) ) { 00319 REPORT_VERBOSE( "Directory doesn't exist, creating it..." ); 00320 if( ! ( tempDir = dir->mkdir( path_element->GetString(), "dummy title" ) ) ) { 00321 SError error( SError::SkipInputData ); 00322 error << "Couldn't create directory: " << path 00323 << " in the output file!"; 00324 throw error; 00325 } 00326 } 00327 dir = tempDir; 00328 00329 } 00330 00331 // Delete the object created by TString::Tokenize(...): 00332 delete directories; 00333 00334 } 00335 00336 return dir; 00337 00338 }