// // Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration // // System include(s): #include <regex> // ROOT include(s): #include <TClass.h> #include <TFile.h> // Core include(s): #include "AthContainers/normalizedTypeinfoName.h" #include "EventLoop/Worker.h" // Local include(s): #include "StandaloneAnalysisAlgorithms/xAODWriterAlg.h" namespace CP { xAODWriterAlg::xAODWriterAlg( const std::string& name, ISvcLocator* svcLoc ) : EL::AnaAlgorithm( name, svcLoc ) { // Declare the algorithm's properties. declareProperty( "OutputStreamName", m_outputStreamName = "ANALYSIS", "Stream name of the output file to use" ); declareProperty( "ItemList", m_itemList, "Objects to write to the output file" ); declareProperty( "BasketSize", m_basketSize = 32000, "(Starter) Basket size for the created branches" ); declareProperty( "SplitLevel", m_splitLevel = 0, "Split level for the created branches" ); } StatusCode xAODWriterAlg::initialize() { // Make sure that the xAOD::TEvent object managed by EventLoop is the // "active" one. evtStore()->event()->setActive(); // Set up the systematics list. ATH_CHECK( m_systematicsList.initialize() ); // Access the file of the output stream. TFile* ofile = wk()->getOutputFile( m_outputStreamName ); if( ! ofile ) { ATH_MSG_FATAL( "Couldn't access output file for stream \"" << m_outputStreamName << "\"" ); return StatusCode::FAILURE; } // Write to this output file. ANA_CHECK( m_event.writeTo( ofile ) ); // Reset the internal flag(s). m_itemListInitialized = false; // Return gracefully. return StatusCode::SUCCESS; } StatusCode xAODWriterAlg::execute() { // If this is the first event, figure out which objects can actually be // written out. if( ! m_itemListInitialized ) { ANA_CHECK( setup() ); m_itemListInitialized = true; } // Write all objects to the output file. xAOD::TEvent* event = evtStore()->event(); for( const Item& item : m_writtenItemList ) { // Get the object. See the description in @c xAOD::TEvent::retrieve // (the const version) for an explanation of this implementation. static const bool SILENT = true; static const bool METADATA = false; const void* obj = event->getOutputObject( item.name, *( item.type ), METADATA ); if( ! obj ) { obj = event->getInputObject( item.name, *( item.type ), SILENT, METADATA ); } else { event->getInputObject( item.name, *( item.type ), SILENT, METADATA ); } // Check that we succeeded. if( ! obj ) { ATH_MSG_FATAL( "Couldn't retrieve object \"" << item.name << "\"" ); return StatusCode::FAILURE; } // Record it to the output for the current event. ANA_CHECK( m_event.record( const_cast< void* >( obj ), item.typeName, item.name, m_basketSize, m_splitLevel ) ); } // Write the event. if( m_event.fill() <= 0 ) { ATH_MSG_FATAL( "There was an error writing out the event" ); return StatusCode::FAILURE; } // Return gracefully. return StatusCode::SUCCESS; } StatusCode xAODWriterAlg::finalize() { // Access the file of the output stream. TFile* ofile = wk()->getOutputFile( m_outputStreamName ); if( ! ofile ) { ATH_MSG_FATAL( "Couldn't access output file for stream \"" << m_outputStreamName << "\"" ); return StatusCode::FAILURE; } // Finish writing to this output file. ANA_CHECK( m_event.finishWritingTo( ofile ) ); // Return gracefully. return StatusCode::SUCCESS; } StatusCode xAODWriterAlg::setup() { // Loop over all of the declared items. for( const std::string& stringItem : m_itemList ) { // Interpret the item string. static const std::regex itemRegex( "([^#]+)#([^\\.]+\\.?)(.*)" ); std::smatch itemMatch; if( ! std::regex_match( stringItem, itemMatch, itemRegex ) ) { ATH_MSG_FATAL( "Item \"" << stringItem << "\" is not of the form: \"Type#Name\"" ); return StatusCode::FAILURE; } ATH_MSG_VERBOSE( "Found item: " << itemMatch[ 1 ] << "#" << itemMatch[ 2 ] << itemMatch[ 3 ] ); // Consider all systematics. Not usin CP::SysListHandle::foreach, to // be able to exit the for-loop early if necessary. auto sysVector = m_systematicsList.systematicsVector(); for( const auto& sys : sysVector ) { // Event store key for the object under consideration. std::string key; ANA_CHECK (m_systematicsList.service().makeSystematicsName( key, itemMatch[ 2 ], sys )); // Whether or not the object will be available, as long as // variable selection rules were set up for it, let xAOD::TEvent // know about them. if( itemMatch[ 3 ] != "" ) { ATH_MSG_DEBUG( "Calling setAuxItemList( \"" << key << "\"" << ", \"" << itemMatch[ 3 ] << "\" )" ); m_event.setAuxItemList( key, itemMatch[ 3 ] ); } // Construct an Item object. Item item; item.name = key; TClass* cl = TClass::GetClass( itemMatch[ 1 ].str().c_str() ); if( ! cl ) { ATH_MSG_FATAL( "Type \"" << itemMatch[ 1 ] << "\" not found" ); return StatusCode::FAILURE; } item.type = cl->GetTypeInfo(); if( ! item.type ) { ATH_MSG_FATAL( "No compiled dictionary found for \"" << itemMatch[ 1 ] << "\"" ); return StatusCode::FAILURE; } item.typeName = SG::normalizedTypeinfoName( *( item.type ) ); // Check if the item is available. static const bool SILENT = true; static const bool METADATA = false; xAOD::TEvent* event = evtStore()->event(); if( event->getOutputObject( item.name, *( item.type ), METADATA ) || event->getInputObject( item.name, *( item.type ), SILENT, METADATA ) ) { m_writtenItemList.push_back( item ); ATH_MSG_DEBUG( "Scheduling \"" << itemMatch[ 1 ] << "#" << key << "\" for writing" ); } // If there was no %SYS% pattern in the object name, stop the loop // over the systematics now. if( key == itemMatch[ 2 ] ) { break; } } } // Return gracefully. return StatusCode::SUCCESS; } } // namespace CP