Program Listing for File Writer.cxx

Return to documentation for file (Root/Writer.cxx)

#include <EventLoop/Job.h>
#include <EventLoop/StatusCode.h>
#include <EventLoop/Worker.h>
#include <xAODAnaHelpers/Writer.h>

#include "EventLoop/OutputStream.h"
#include "xAODCore/ShallowCopy.h"
#include "xAODJet/JetContainer.h"
#include "xAODJet/JetAuxContainer.h"

#include <xAODAnaHelpers/HelperFunctions.h>

// this is needed to distribute the algorithm to the workers
ClassImp(Writer)



Writer :: Writer () :
    Algorithm("Writer")
{
}

EL::StatusCode Writer :: setupJob (EL::Job& job)
{
  // Here you put code that sets up the job on the submission object
  // so that it is ready to work with your algorithm, e.g. you can
  // request the D3PDReader service or add output files.  Any code you
  // put here could instead also go into the submission script.  The
  // sole advantage of putting it here is that it gets automatically
  // activated/deactivated when you add/remove the algorithm from your
  // job, which may or may not be of value to you.
  // let's initialize the algorithm to use the xAODRootAccess package
  job.useXAOD ();
  xAOD::Init( "Writer" ).ignore(); // call before opening first file

  m_jetContainerNames       = HelperFunctions::SplitString( m_jetContainerNamesStr,      ',' );
  m_electronContainerNames  = HelperFunctions::SplitString( m_electronContainerNamesStr, ',' );
  m_muonContainerNames      = HelperFunctions::SplitString( m_muonContainerNamesStr,     ',' );

  if ( m_outputLabel.Length() == 0 ) {
    ANA_MSG_ERROR( "No OutputLabel specified!");
    return EL::StatusCode::FAILURE;
  }

  // tell EventLoop about our output xAOD:
  EL::OutputStream out(m_outputLabel.Data());
  job.outputAdd (out);

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: histInitialize ()
{
  // Here you do everything that needs to be done at the very
  // beginning on each worker node, e.g. create histograms and output
  // trees.  This method gets called before any input files are
  // connected.
  ANA_CHECK( xAH::Algorithm::algInitialize());
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: fileExecute ()
{
  // Here you do everything that needs to be done exactly once for every
  // single file, e.g. collect a list of all lumi-blocks processed
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: changeInput (bool /*firstFile*/)
{
  // Here you do everything you need to do when we change input files,
  // e.g. resetting branch addresses on trees.  If you are using
  // D3PDReader or a similar service this method is not needed.
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: initialize ()
{
  // Here you do everything that you need to do after the first input
  // file has been connected and before the first event is processed,
  // e.g. create additional histograms based on which variables are
  // available in the input files.  You can also create all of your
  // histograms and trees in here, but be aware that this method
  // doesn't get called if no events are processed.  So any objects
  // you create here won't be available in the output if you have no
  // input events.
  m_event = wk()->xaodEvent();
  m_store = wk()->xaodStore();
  m_numEvent      = 0;

  // output xAOD
  TFile * file = wk()->getOutputFile (m_outputLabel.Data());
  ANA_CHECK( m_event->writeTo(file));

  //FIXME add this as well
// Set which variables not to write out:
// event->setAuxItemList( "AntiKt4LCTopoJetsAux.", "-NumTrkPt1000.-NumTrkPt500" );
// // Set which variable to do write out:
// event->setAuxItemList( "GoodJetsAux.", "JetGhostArea.TrackCount" );


  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: execute ()
{
  // Here you do everything that needs to be done on every single
  // events, e.g. read input variables, apply cuts, and fill
  // histograms and trees.  This is where most of your actual analysis
  // code will go.
  m_numEvent++;

  // try to find the containers in m_event - if there then copy entire container directly
  // if not found in m_event, look in m_store - user created - write aux store as well
  for( auto contName : m_jetContainerNames ) {

    const xAOD::JetContainer* inJetsConst(nullptr);
    // look in event
    if ( HelperFunctions::retrieve(inJetsConst, contName.Data(), m_event, 0, msg()).isSuccess() ) {
      // without modifying the contents of it:
      ANA_MSG_INFO( " Write a collection " << contName.Data() << inJetsConst->size() );
      m_event->copy( contName.Data() );
      ANA_MSG_INFO( " Wrote a collection " << contName.Data());
      continue;
    }

    // look in store
    xAOD::JetContainer* inJets(nullptr);
    if ( HelperFunctions::retrieve(inJets, contName.Data(), 0, m_store, msg()).isSuccess() ){
//      // FIXME add something like this
//      jets_shallowCopy.second->setShallowIO( false ); // true = shallow copy, false = deep copy
//      // if true should have something like this line somewhere:

      // Record the objects into the output xAOD:
      ANA_MSG_INFO( " Write a collection " << contName.Data() << inJets->size() );
      if( ! m_event->record( inJets, contName.Data() ) ) {
        ANA_MSG_ERROR(m_name << ": Could not record " << contName.Data());
        return EL::StatusCode::FAILURE;
      }
      ANA_MSG_INFO( " Wrote a collection " << contName.Data());

      // get pointer to associated aux container
      xAOD::JetAuxContainer* inJetsAux = 0;
      ANA_MSG_INFO( " Wrote a aux store " << contName.Data());
      TString auxName( contName + "Aux." );
      if ( HelperFunctions::retrieve(inJetsAux, auxName.Data(), 0, m_store, msg()).isSuccess() ){
        ANA_MSG_ERROR(m_name << ": Could not get Aux data for " << contName.Data());
        return EL::StatusCode::FAILURE;
      }
      ANA_MSG_INFO( " Wrote a aux store " << contName.Data());

      if( ! m_event->record( inJetsAux, auxName.Data() ) ) {
        ANA_MSG_ERROR( m_name << ": Could not record aux store for " << contName.Data());
        return EL::StatusCode::FAILURE;
      }
    }
    // could not find the container - problems
    else {
      ANA_MSG_ERROR( m_name << ": Could not find " << contName.Data());
      return EL::StatusCode::FAILURE;
    }
  }

  // add similar loop for electron and muons

  m_event->fill();

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: postExecute ()
{
  // Here you do everything that needs to be done after the main event
  // processing.  This is typically very rare, particularly in user
  // code.  It is mainly used in implementing the NTupleSvc.
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: finalize ()
{
  // This method is the mirror image of initialize(), meaning it gets
  // called after the last event has been processed on the worker node
  // and allows you to finish up any objects you created in
  // initialize() before they are written to disk.  This is actually
  // fairly rare, since this happens separately for each worker node.
  // Most of the time you want to do your post-processing on the
  // submission node after all your histogram outputs have been
  // merged.  This is different from histFinalize() in that it only
  // gets called on worker nodes that processed input events.

  // finalize and close our output xAOD file ( and write MetaData tree )
  TFile * file = wk()->getOutputFile(m_outputLabel.Data());
  ANA_CHECK( m_event->finishWritingTo( file ));

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode Writer :: histFinalize ()
{
  // This method is the mirror image of histInitialize(), meaning it
  // gets called after the last event has been processed on the worker
  // node and allows you to finish up any objects you created in
  // histInitialize() before they are written to disk.  This is
  // actually fairly rare, since this happens separately for each
  // worker node.  Most of the time you want to do your
  // post-processing on the submission node after all your histogram
  // outputs have been merged.  This is different from finalize() in
  // that it gets called on all worker nodes regardless of whether
  // they processed input events.
  ANA_CHECK( xAH::Algorithm::algFinalize());
  return EL::StatusCode::SUCCESS;
}