ATLAS Offline Software
d3pdReadersFromFile.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 
6 // STL include(s):
7 #include <iostream>
8 #include <vector>
9 #include <string>
10 #include <map>
11 #include <set>
12 
13 // Boost include(s):
14 #include <boost/program_options.hpp>
15 #include <boost/algorithm/string.hpp>
16 
17 // ROOT include(s):
18 #include <TFile.h>
19 #include <TList.h>
20 #include <TKey.h>
21 #include <TDirectory.h>
22 #include <TString.h>
23 #include <TObjString.h>
24 #include <TError.h>
25 
26 // Gaudi/Athena include(s):
27 #include "GaudiKernel/StatusCode.h"
28 #include "GaudiKernel/Bootstrap.h"
29 #include "GaudiKernel/IMessageSvc.h"
30 #include "GaudiKernel/ISvcLocator.h"
33 
34 // D3PD include(s):
36 
37 // Local include(s):
38 #include "../Variable.h"
39 #include "../CodeGenerator_v2.h"
40 #include "../RootObjectMetadata.h"
41 
43 static const char* const PROGRAM_DESC =
44  "This application can be used to create all the D3PDReader classes\n"
45  "from a D3PD file that stores the metadata of the D3PDObjects that\n"
46  "were used to create it";
47 
49 static const char* const PROGRAM_GREETING =
50  "*******************************************************************\n"
51  "* *\n"
52  "* D3PDReader standalone code generator *\n"
53  "* *\n"
54  "*******************************************************************";
55 
57 
67 template< typename T >
68 std::ostream& operator<<( std::ostream& out, const std::vector< T >& vec ) {
69  out << "[";
70  typename std::vector< T >::const_iterator itr = vec.begin();
71  typename std::vector< T >::const_iterator end = vec.end();
72  for( ; itr != end; ++itr ) {
73  out << *itr;
74  if( ++itr != end ) {
75  out << ", ";
76  }
77  --itr;
78  }
79  out << "]";
80  return out;
81 }
82 
84 StatusCode collectObjects( TDirectory* dir,
85  std::set< D3PD::ObjectMetadata >& objects );
87 std::vector< D3PD::ObjectMetadata >
88 mergeObjects( const std::set< D3PD::ObjectMetadata >& objects );
89 
91 namespace po = boost::program_options;
92 
93 int main ATLAS_NOT_THREAD_SAFE ( int argc, char* argv[] ) {
94  // Let's disable the ROOT warnings:
96 
97  // Force the Gaudi MessageSvc into existence. This gets rid of the
98  // warnings from getMessageSvc().
99  IMessageSvc* msvc = 0;
100  if( Gaudi::svcLocator()->service( "MessageSvc", msvc, true ).isFailure() ) {
101  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
102  << "Couldn't set up the Gaudi message service";
103  return 255;
104  }
105 
106  //
107  // Construct the object describing all the command line parameters of the
108  // application:
109  //
110  po::options_description desc( PROGRAM_DESC );
111  desc.add_options()
112  ( "help,h", "Give some help with the program usage" )
113  ( "d3pd-files,f", po::value< std::vector< std::string > >()->multitoken(),
114  "Input D3PD file(s)" )
115  ( "event-class-name,n", po::value< std::string >()->default_value( "Event" ),
116  "Name for the D3PDReader event class" )
117  ( "output,o", po::value< std::string >()->default_value( "." ),
118  "Output directory for the generated source files" )
119  ( "verbosity,v", po::value< int >()->default_value( 3 ),
120  "Verbosity level of the application. (1:VERBOSE, 2:DEBUG, 3:INFO, ...)" );
121 
122  //
123  // Interpret the command line options provided by the user:
124  //
125  po::variables_map vm;
126  try {
127  po::store( po::parse_command_line( argc, argv, desc ), vm );
128  po::notify( vm );
129  } catch( const std::exception& ex ) {
130  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
131  << "There was a problem with interpreting the command line options.";
132  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
133  << "Message: " << ex.what();
134  return 255;
135  }
136 
137  //
138  // If the user asked for some help, let's print it:
139  //
140  if( vm.count( "help" ) ) {
141  std::cout << desc << std::endl;
142  return 0;
143  }
144 
145  //
146  // Set the verbosity level of the application:
147  //
148  msvc->setOutputLevel( vm[ "verbosity" ].as< int >() );
149 
150  //
151  // Greet the user, and print all the parameters that the application
152  // received:
153  //
154  std::cout << PROGRAM_GREETING << std::endl;
155 
156  // Extract the file name(s) from the command line arguments:
157  if( ! vm.count( "d3pd-files" ) ) {
158  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
159  << "You have to specify at least one D3PD file!";
160  return 255;
161  }
162  const std::vector< std::string > file_names =
163  vm[ "d3pd-files" ].as< std::vector< std::string > >();
164  std::cout << " D3PD file(s): " << file_names << std::endl;
165 
166  // Get the event class name:
167  const std::string event_name = vm[ "event-class-name" ].as< std::string >();
168  std::cout << " Event class name: " << event_name << std::endl;
169 
170  // Get the output directory:
171  const std::string output = vm[ "output" ].as< std::string >();
172  std::cout << " Output directory: " << output << std::endl;
173 
174  //
175  // A list of all the objects collected from all the files:
176  //
177  std::set< D3PD::ObjectMetadata > objects;
178 
179  //
180  // Loop over the specified files:
181  //
182  std::vector< std::string >::const_iterator file_itr = file_names.begin();
183  std::vector< std::string >::const_iterator file_end = file_names.end();
184  for( ; file_itr != file_end; ++file_itr ) {
185 
186  // Try to open the D3PD file:
187  REPORT_MESSAGE_WITH_CONTEXT( MSG::INFO, "d3pdReadersFromFile" )
188  << "Reading file: " << *file_itr;
189  TFile* ifile = TFile::Open( file_itr->c_str(), "READ" );
190  if( ( ! ifile ) || ifile->IsZombie() ) {
191  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
192  << "Failed to open D3PD file: " << *file_itr;
193  return 255;
194  }
195 
196  // Search for the metadata directories:
197  std::vector< std::string > metaDirectories;
198  const TList* keys = ifile->GetListOfKeys();
199  for( Int_t i = 0; i < keys->GetSize(); ++i ) {
200  const TKey* key = dynamic_cast< TKey* >( keys->At( i ) );
201  if (!key) continue;
202  std::string key_name = key->GetName();
203  if( ( key_name.find( "Meta" ) != key_name.npos ) &&
204  ( key->GetClassName() == std::string( "TDirectoryFile" ) ) ) {
205  metaDirectories.push_back( key_name );
206  }
207  }
208 
209  // Collect the objects from each of these directories:
210  std::vector< std::string >::const_iterator dir_itr = metaDirectories.begin();
211  std::vector< std::string >::const_iterator dir_end = metaDirectories.end();
212  for( ; dir_itr != dir_end; ++dir_itr ) {
213  // Try to access the directory:
214  TDirectory* dir = ifile->GetDirectory( dir_itr->c_str() );
215  if( ! dir ) {
216  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
217  << "Failed to access directory: " << *dir_itr;
218  return 255;
219  }
220  // Collect the metadata from this directory:
221  if( collectObjects( dir, objects ).isFailure() ) {
222  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
223  << "Failed to collect variable definitions from metadata directory: "
224  << *dir_itr;
225  return 255;
226  }
227  }
228 
229  // Close the input file:
230  ifile->Close();
231  delete ifile;
232  }
233 
234  //
235  // Merge the objects of the same type:
236  //
237  std::vector< D3PD::ObjectMetadata > merged_objects = mergeObjects( objects );
238  if( ! merged_objects.size() ) {
239  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
240  << "Didn't find any metadata about the D3PD variables in the "
241  << "specified file(s)!";
242  return 255;
243  }
244 
245  //
246  // Generate the D3PDObjectBase class's source:
247  //
248  if( D3PD::Version2::writeD3PDObjectBase( output ).isFailure() ) {
249  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
250  << "Couldn't create the D3PDObjectBase class source";
251  return 255;
252  }
253 
254  //
255  // Generate the VarHandle class's source:
256  //
257  if( D3PD::Version2::writeVarHandle( output ).isFailure() ) {
258  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
259  << "Couldn't create the VarHandle class source";
260  return 255;
261  }
262 
263  //
264  // Generate the VarProxy class's source if needed:
265  //
266  if( D3PD::Version2::writeVarProxy( output ).isFailure() ) {
267  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
268  << "Couldn't create the VarProxy class source";
269  return 255;
270  }
271 
272  //
273  // Generate the UserD3PDObject class's source:
274  //
275  if( D3PD::Version2::writeUserD3PDObject( output ).isFailure() ) {
276  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
277  << "Couldn't create the UserD3PDObject class source";
278  return 255;
279  }
280 
281  //
282  // Generate the D3PDReadStats class's source:
283  //
284  if( D3PD::Version2::writeD3PDReadStats( output ).isFailure() ) {
285  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
286  << "Couldn't create the D3PDReadStats class source";
287  return 255;
288  }
289 
290  //
291  // Generate the D3PDPerfStats class's source:
292  //
293  if( D3PD::Version2::writeD3PDPerfStats( output ).isFailure() ) {
294  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
295  << "Couldn't create the D3PDPerfStats class source";
296  return 255;
297  }
298 
299  //
300  // Generate the Utils source:
301  //
302  if( D3PD::Version2::writeUtils( output ).isFailure() ) {
303  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
304  << "Couldn't create the Utils source";
305  return 255;
306  }
307 
308  //
309  // Generate the sources for each object:
310  //
311  std::vector< D3PD::ObjectMetadata >::const_iterator obj_itr = merged_objects.begin();
312  std::vector< D3PD::ObjectMetadata >::const_iterator obj_end = merged_objects.end();
313  for( ; obj_itr != obj_end; ++obj_itr ) {
314 
315  //
316  // Generate the header of the D3PDReader class:
317  //
318  if( D3PD::Version2::writeHeader( obj_itr->name(), output,
319  *obj_itr ).isFailure() ) {
320  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
321  << "Couldn't generate the D3PDReader class header";
322  return 255;
323  }
324 
325  //
326  // Generate the source of the D3PDReader class:
327  //
328  if( D3PD::Version2::writeSource( obj_itr->name(), output,
329  *obj_itr ).isFailure() ) {
330  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
331  << "Couldn't generate the D3PDReader class source";
332  return 255;
333  }
334  }
335 
336  //
337  // Generate the "event class":
338  //
339  if( D3PD::Version2::writeEventHeader( event_name, output,
340  objects ).isFailure() ) {
341  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
342  << "Couldn't generate the D3PDReader event class header";
343  return 255;
344  }
345  if( D3PD::Version2::writeEventSource( event_name, output,
346  objects ).isFailure() ) {
347  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
348  << "Couldn't generate the D3PDReader event class source";
349  return 255;
350  }
351 
352  return 0;
353 }
354 
365  std::set< D3PD::ObjectMetadata >& objects ) {
366 
367  // Find all the D3PDObject definitions in the directory:
368  const TList* keys = dir->GetListOfKeys();
369  for( Int_t i = 0; i < keys->GetSize(); ++i ) {
370 
371  // Look for D3PDObject definitions:
372  const TKey* key = dynamic_cast< TKey* >( keys->At( i ) );
373  if (!key) continue;
374  if( key->GetClassName() != std::string( "TObjString" ) ) continue;
375 
376  // Check whether it looks like object metadata:
377  if( ! D3PD::RootObjectMetadata::isObjectMetadata( key->GetName() ) ) {
378  continue;
379  }
380 
381  // The name of the D3PDObject:
382  const std::string objName = D3PD::ObjectMetadata::objectName( key->GetName() );
383 
384  REPORT_MESSAGE_WITH_CONTEXT( MSG::DEBUG, "d3pdReadersFromFile" )
385  << "Reading object '" << objName << "'";
386 
387  // Access the variable description:
388  TObjString* ostring =
389  dynamic_cast< TObjString* >( dir->Get( TString( key->GetName() ) + ";" +
390  TString::Format( "%hi", key->GetCycle() ) ) );
391  if( ! ostring ) {
392  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
393  << "Couldn't access object: " << key->GetName() << ";"
394  << key->GetCycle();
395  return StatusCode::FAILURE;
396  }
397 
398  // Decode the metadata:
400  metadata.setName( objName );
401  if( metadata.read( ostring->GetString().Data() ).isFailure() ) {
402  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
403  << "Couldn't collect variables from object: " << key->GetName();
404  return StatusCode::FAILURE;
405  }
406 
407  // Fix the variable names if they need fixing:
408  if( metadata.checkPrefixes().isFailure() ) {
409  REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "d3pdReadersFromFile" )
410  << "Couldn't fix prefixes in metadata object with name: "
411  << metadata.name();
412  return StatusCode::FAILURE;
413  }
414 
415  // Check if such an object has already been added:
417  objects.insert( metadata );
418  // If this object already existed, merge the two:
419  if( ! ret.second ) {
420  REPORT_MESSAGE_WITH_CONTEXT( MSG::DEBUG, "d3pdReadersFromFile" )
421  << "Merging objects with name '" << objName << "'";
422  D3PD::ObjectMetadata merged( *( ret.first ) );
423  merged.merge( metadata );
424  objects.erase( ret.first );
425  objects.insert( merged );
426  } else {
427  REPORT_MESSAGE_WITH_CONTEXT( MSG::DEBUG, "d3pdReadersFromFile" )
428  << "Added object with name '" << objName << "'";
429  }
430 
431  }
432 
433  return StatusCode::SUCCESS;
434 }
435 
444 std::vector< D3PD::ObjectMetadata >
445 mergeObjects( const std::set< D3PD::ObjectMetadata >& objects ) {
446 
447  // Internal map for executing the merging:
448  std::map< std::string, D3PD::ObjectMetadata > tmp_result;
449 
450  // Merge the objects using the temporary map:
451  std::set< D3PD::ObjectMetadata >::const_iterator set_itr = objects.begin();
452  std::set< D3PD::ObjectMetadata >::const_iterator set_end = objects.end();
453  for( ; set_itr != set_end; ++set_itr ) {
454  tmp_result[ set_itr->name() ].setName( set_itr->name() );
455  tmp_result[ set_itr->name() ].setPrefix( set_itr->prefix() );
456  tmp_result[ set_itr->name() ].setContainer( set_itr->container() );
457  tmp_result[ set_itr->name() ].merge( *set_itr );
458  }
459 
460  // Copy the objects from the temporary map into the result vector:
461  std::vector< D3PD::ObjectMetadata > result;
462  std::map< std::string, D3PD::ObjectMetadata >::const_iterator map_itr =
463  tmp_result.begin();
464  std::map< std::string, D3PD::ObjectMetadata >::const_iterator map_end =
465  tmp_result.end();
466  for( ; map_itr != map_end; ++map_itr ) {
467  result.push_back( map_itr->second );
468  }
469 
470  return result;
471 }
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
TestSUSYToolsAlg.ifile
ifile
Definition: TestSUSYToolsAlg.py:92
store
StoreGateSvc * store
Definition: fbtTestBasics.cxx:69
mergeObjects
std::vector< D3PD::ObjectMetadata > mergeObjects(const std::set< D3PD::ObjectMetadata > &objects)
Function mergint the objects of the same type.
Definition: d3pdReadersFromFile.cxx:445
D3PD::Version2::writeD3PDPerfStats
StatusCode writeD3PDPerfStats(const std::string &dir)
This function can be used to create the D3PDReader::D3PDPerfStats class's source files.
Definition: CodeGenerator_v2.cxx:528
D3PD::RootObjectMetadata::isObjectMetadata
static bool isObjectMetadata(const std::string &name)
Function guessing if an object with a given name is object metadata.
Definition: RootObjectMetadata.cxx:118
D3PD::Version2::writeUserD3PDObject
StatusCode writeUserD3PDObject(const std::string &dir)
This function can be used to create the D3PDReader::UserD3PDObject class's source files.
Definition: CodeGenerator_v2.cxx:411
D3PD::Version2::writeSource
StatusCode writeSource(const std::string &classname, const std::string &dir, const ObjectMetadata &metadata)
This function is used to generate the source file of a D3PDReader class.
Definition: CodeGenerator_v2.cxx:967
get_generator_info.result
result
Definition: get_generator_info.py:21
LArConditions2Ntuple.objects
objects
Definition: LArConditions2Ntuple.py:56
D3PD::Version2::writeD3PDObjectBase
StatusCode writeD3PDObjectBase(const std::string &dir)
This function can be used to create the D3PDReader::D3PDObjectBase class's source files.
Definition: CodeGenerator_v2.cxx:265
StateLessPT_NewConfig.Format
Format
Definition: StateLessPT_NewConfig.py:146
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
ObjectMetadata.h
athena.value
value
Definition: athena.py:122
D3PD::Version2::writeVarHandle
StatusCode writeVarHandle(const std::string &dir)
This function can be used to create the D3PDReader::VarHandle class's source files.
Definition: CodeGenerator_v2.cxx:298
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
LArCellConditions.argv
argv
Definition: LArCellConditions.py:112
D3PD::Version2::writeUtils
StatusCode writeUtils(const std::string &dir)
This function can be used to create source files containing some utility functions.
Definition: CodeGenerator_v2.cxx:577
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
ATLAS_NOT_THREAD_SAFE
int main ATLAS_NOT_THREAD_SAFE(int argc, char *argv[])
A convenience declaration to save myself some typeing.
Definition: d3pdReadersFromFile.cxx:93
D3PD::Version2::writeEventSource
StatusCode writeEventSource(const std::string &classname, const std::string &dir, const std::set< ObjectMetadata > &metadata)
Write the source of the main event class describing a D3PD tree.
Definition: CodeGenerator_v2.cxx:2037
python.checkMetadata.metadata
metadata
Definition: checkMetadata.py:175
main
int main(int, char **)
Main class for all the CppUnit test classes
Definition: CppUnit_SGtestdriver.cxx:141
CaloCondBlobAlgs_fillNoiseFromASCII.desc
desc
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:54
D3PD::ObjectMetadata::merge
ObjectMetadata & merge(const ObjectMetadata &obj)
Function merging the contents of two objects.
Definition: ObjectMetadata.cxx:375
lumiFormat.i
int i
Definition: lumiFormat.py:92
ret
T ret(T t)
Definition: rootspy.cxx:260
Analysis::kError
@ kError
Definition: CalibrationDataVariables.h:60
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
D3PD::ObjectMetadata::objectName
static std::string objectName(const std::string &metaName)
Get the D3PDObject's name from the name of the metadata object.
Definition: ObjectMetadata.cxx:213
calibdata.exception
exception
Definition: calibdata.py:496
collectObjects
StatusCode collectObjects(TDirectory *dir, std::set< D3PD::ObjectMetadata > &objects)
Function collecting the objects from a specific directory in a file.
Definition: d3pdReadersFromFile.cxx:364
DQHistogramMergeRegExp.argc
argc
Definition: DQHistogramMergeRegExp.py:20
D3PD::RootObjectMetadata
Extension of the ObjectMetadata class for reading D3PD files.
Definition: RootObjectMetadata.h:32
beamspotman.dir
string dir
Definition: beamspotman.py:623
merge.output
output
Definition: merge.py:17
REPORT_MESSAGE_WITH_CONTEXT
#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME)
Report a message, with an explicitly specified context name.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:345
D3PD::ObjectMetadata
D3PD variable metadata handling class.
Definition: ObjectMetadata.h:36
errorcheck.h
Helpers for checking error return status codes and reporting errors.
D3PD::Version2::writeD3PDReadStats
StatusCode writeD3PDReadStats(const std::string &dir)
This function can be used to create the D3PDReader::D3PDReadStats class's source files.
Definition: CodeGenerator_v2.cxx:478
gErrorIgnoreLevel
int gErrorIgnoreLevel
D3PD::Version2::writeEventHeader
StatusCode writeEventHeader(const std::string &classname, const std::string &dir, const std::set< ObjectMetadata > &metadata)
Write the header of the main event class describing a D3PD tree.
Definition: CodeGenerator_v2.cxx:1913
DEBUG
#define DEBUG
Definition: page_access.h:11
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:790
D3PD::Version2::writeHeader
StatusCode writeHeader(const std::string &classname, const std::string &dir, const ObjectMetadata &metadata)
This function is used to create the header of the class describing a set of D3PD variables.
Definition: CodeGenerator_v2.cxx:632
checker_macros.h
Define macros for attributes used to control the static checker.
D3PD::Version2::writeVarProxy
StatusCode writeVarProxy(const std::string &dir)
This function can be used to create the D3PDReader::VarProxy class's source files.
Definition: CodeGenerator_v2.cxx:363
operator<<
std::ostream & operator<<(std::ostream &out, const std::vector< T > &vec)
Formatted printing for vector objects.
Definition: d3pdReadersFromFile.cxx:68
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37