Program Listing for File TrackSelector.cxx

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

#include <EventLoop/Job.h>
#include <EventLoop/Worker.h>

#include "AthContainers/ConstDataVector.h"
#include "xAODAnaHelpers/HelperFunctions.h"
#include "xAODAnaHelpers/TrackSelector.h"
#include "InDetTrackSelectionTool/InDetTrackSelectionTool.h"

// ROOT include(s):
#include "TFile.h"
#include "TObjArray.h"
#include "TObjString.h"

// c++ include(s):
#include <iostream>
#include <typeinfo>
#include <sstream>

using std::vector;

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


TrackSelector :: TrackSelector () :
    Algorithm("TrackSelector")
{
}

EL::StatusCode TrackSelector :: 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.

  ANA_MSG_DEBUG("Calling setupJob");

  job.useXAOD ();
  xAOD::Init( "TrackSelector" ).ignore(); // call before opening first file

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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_MSG_DEBUG("Calling histInitialize");
  ANA_CHECK( xAH::Algorithm::algInitialize());
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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

  ANA_MSG_DEBUG("Calling fileExecute");

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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.

  ANA_MSG_DEBUG("Calling changeInput");

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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.

  if(m_useCutFlow) {
    TFile *file = wk()->getOutputFile (m_cutFlowStreamName);
    m_cutflowHist  = (TH1D*)file->Get("cutflow");
    m_cutflowHistW = (TH1D*)file->Get("cutflow_weighted");
    m_cutflow_bin  = m_cutflowHist->GetXaxis()->FindBin(m_name.c_str());
    m_cutflowHistW->GetXaxis()->FindBin(m_name.c_str());
  }

  // parse and split by comma
  std::string token;
  std::istringstream ss(m_passAuxDecorKeys);
  while(std::getline(ss, token, ',')){
    m_passKeys.push_back(token);
  }
  ss.clear();
  ss.str(m_failAuxDecorKeys);
  while(std::getline(ss, token, ',')){
    m_failKeys.push_back(token);
  }


  if( m_inContainerName.empty() ) {
    ANA_MSG_ERROR( "InputContainer is empty!");
    return EL::StatusCode::FAILURE;
  }

  m_event = wk()->xaodEvent();
  m_store = wk()->xaodStore();

  ANA_MSG_DEBUG("Number of events in file: " << m_event->getEntries() );

  m_numEvent      = 0;
  m_numObject     = 0;
  m_numEventPass  = 0;
  m_numObjectPass = 0;

  ANA_MSG_DEBUG( "Initializing InDetTrackSelectionTool..." );
  if(m_pT_min                           != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minPt",                           m_pT_min));
  if(m_p_min                            != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minP",                            m_p_min));
  if(m_eta_max                          != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxAbsEta",                       m_eta_max));
  if(m_d0_max                           != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxD0",                           m_d0_max));
  if(m_sigmad0_max                      != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxSigmaD0",                      m_sigmad0_max));
  if(m_d0oversigmad0_max                != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxD0overSigmaD0",                m_d0oversigmad0_max));
  if(m_z0_max                           != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxZ0",                           m_z0_max));
  if(m_z0sinT_max                       != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxZ0SinTheta",                   m_z0sinT_max));
  if(m_sigmaz0_max                      != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxSigmaZ0",                      m_sigmaz0_max));
  if(m_sigmaz0sintheta_max              != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxSigmaZ0SinTheta",              m_sigmaz0sintheta_max));
  if(m_z0oversigmaz0_max                != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxZ0overSigmaZ0",                m_z0oversigmaz0_max));
  if(m_z0sinthetaoversigmaz0sintheta_max!= 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxZ0SinThetaoverSigmaZ0SinTheta",m_z0sinthetaoversigmaz0sintheta_max));
  if(m_nInnermostPixel_min              != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNInnermostLayerHits",          m_nInnermostPixel_min));
  if(m_nNextToInnermostPixel_min        != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNNextToInnermostLayerHits",    m_nNextToInnermostPixel_min));
  if(m_nBothInnermostLayersHits_min     != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNBothInnermostLayersHits",     m_nBothInnermostLayersHits_min));
  if(m_nSi_min                          != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNSiHits",                      m_nSi_min));
  if(m_nSiPhysical_min                  != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNSiHitsPhysical",              m_nSiPhysical_min));
  if(m_nSiSharedHits_max                != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNSiSharedHits",                m_nSiSharedHits_max));
  if(m_nSiHoles_max                     != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNSiHoles",                     m_nSiHoles_max));
  if(m_nPixelHits_min                   != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNPixelHits",                   m_nPixelHits_min));
  if(m_nPixelHitsPhysical_min           != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNPixelHitsPhysical",           m_nPixelHitsPhysical_min));
  if(m_nPixelSharedHits_max             != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNPixelSharedHits",             m_nPixelSharedHits_max));
  if(m_nPixHoles_max                    != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNPixelHoles",                  m_nPixHoles_max));
  if(m_nSctHits_min                     != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNSctHits",                     m_nSctHits_min));
  if(m_nSctHitsPhysical_min             != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minNSctHitsPhysical",             m_nSctHitsPhysical_min));
  if(m_nSctSharedHits_max               != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNSctSharedHits",               m_nSctSharedHits_max));
  if(m_nSctHoles_max                    != 2e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNSctHoles",                    m_nSctHoles_max));
  if(m_nSiSharedModules_max             != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxNSiSharedModules",             m_nSiSharedModules_max));
  if(m_chi2Prob_min                     != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("minProb",                         m_chi2Prob_min));
  if(m_chi2NdofCut_max                  != 1e8)ANA_CHECK(m_trkSelTool_handle.setProperty("maxChiSqperNdf",                  m_chi2NdofCut_max));
  if(m_cutLevelString                   != "" )ANA_CHECK(m_trkSelTool_handle.setProperty("CutLevel",                        m_cutLevelString));

  ANA_CHECK( m_trkSelTool_handle.retrieve() );

  ANA_MSG_DEBUG( "TrackSelector Interface succesfully initialized!" );

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: execute ()
{

  ANA_MSG_DEBUG("Applying Track Selection... " << m_name);

  const xAOD::EventInfo* eventInfo(nullptr);
  ANA_CHECK( HelperFunctions::retrieve(eventInfo, m_eventInfoContainerName, m_event, m_store, msg()) );

  // MC event weight
  //
  float mcEvtWeight(1);
  if ( eventInfo->eventType(xAOD::EventInfo::IS_SIMULATION) )
    mcEvtWeight = eventInfo->mcEventWeight();

  if(m_doTracksInJets){
    return executeTracksInJets();
  } else{
    return executeTrackCollection(mcEvtWeight);
  }

  return EL::StatusCode::SUCCESS;
}

EL::StatusCode TrackSelector :: executeTrackCollection (float mcEvtWeight)
{
  m_numEvent++;

  // get the collection from TEvent or TStore
  const xAOD::TrackParticleContainer* inTracks(nullptr);
  ANA_CHECK( HelperFunctions::retrieve(inTracks, m_inContainerName, m_event, m_store, msg()) );

  // get primary vertex
  const xAOD::VertexContainer *vertices(nullptr);
  ANA_CHECK( HelperFunctions::retrieve(vertices, m_vertexContainerName, m_event, m_store, msg()) );
  const xAOD::Vertex *pvx = HelperFunctions::getPrimaryVertex(vertices, msg());


  // create output container (if requested) - deep copy

  ConstDataVector<xAOD::TrackParticleContainer>* selectedTracks = 0;
  if(m_createSelectedContainer) {
    selectedTracks = new ConstDataVector<xAOD::TrackParticleContainer>(SG::VIEW_ELEMENTS);
  }

  xAOD::TrackParticleContainer::const_iterator trk_itr = inTracks->begin();
  xAOD::TrackParticleContainer::const_iterator trk_end = inTracks->end();
  int nPass(0); int nObj(0);
  for( ; trk_itr != trk_end; ++trk_itr ){

    // if only looking at a subset of tracks make sure all are decorrated
    if( m_nToProcess > 0 && nObj >= m_nToProcess ) {
      if(m_decorateSelectedObjects) {
        (*trk_itr)->auxdecor< char >( "passSel" ) = -1;
      } else {
        break;
      }
      continue;
    }

    nObj++;
    int passSel = this->PassCuts( (*trk_itr), pvx );
    if(m_decorateSelectedObjects) {
      (*trk_itr)->auxdecor< char >( "passSel" ) = passSel;
    }

    if(passSel) {
      nPass++;
      if(m_createSelectedContainer) {
        selectedTracks->push_back( *trk_itr );
      }
    }
  }

  m_numObject     += nObj;
  m_numObjectPass += nPass;

  // apply event selection based on minimal/maximal requirements on the number of objects per event passing cuts
  if( m_pass_min > 0 && nPass < m_pass_min ) {
    wk()->skipEvent();
    return EL::StatusCode::SUCCESS;
  }
  if( m_pass_max >= 0 && nPass > m_pass_max ) {
    wk()->skipEvent();
    return EL::StatusCode::SUCCESS;
  }

  // add output container to TStore
  if( m_createSelectedContainer ) {
    ANA_CHECK( m_store->record( selectedTracks, m_outContainerName ));
  }

  m_numEventPass++;
  if(m_useCutFlow) {
    m_cutflowHist ->Fill( m_cutflow_bin, 1 );
    m_cutflowHistW->Fill( m_cutflow_bin, mcEvtWeight);
  }

  return EL::StatusCode::SUCCESS;
}


EL::StatusCode TrackSelector :: executeTracksInJets ()
{
  ANA_MSG_DEBUG("Applying TracksInJet Selection... " << m_inJetContainerName);
  m_numEvent++;

  // get input jet collection
  const xAOD::JetContainer* inJets(nullptr);
  ANA_CHECK( HelperFunctions::retrieve(inJets, m_inJetContainerName, m_event, m_store, msg()) );

  //const xAOD::VertexContainer *vertices(nullptr);
  //ANA_CHECK( HelperFunctions::retrieve(vertices, m_vertexContainerName, m_event, m_store, msg()) );
  //const xAOD::Vertex *pvx = HelperFunctions::getPrimaryVertex(vertices, msg());

  int nPass(0); int nObj(0);

  //
  //  Accessor for adding the output jets
  //
  xAOD::Jet::Decorator<vector<const xAOD::TrackParticle*> > m_track_decoration(m_outContainerName.c_str());
  xAOD::Jet::Decorator<const xAOD::Vertex*>                 m_vtx_decoration  ((m_outContainerName+"_vtx").c_str());

  //
  // loop on Jets
  //
  for ( auto jet_itr : *inJets ) {

    //
    //  output container with in the jet
    //
    vector<const xAOD::TrackParticle*> outputTracks;

    //
    // loop on tracks with in jet
    //
    const vector<const xAOD::TrackParticle*> inputTracks = jet_itr->auxdata< vector<const xAOD::TrackParticle*>  >(m_inContainerName);
    const xAOD::Vertex* pvx                              = jet_itr->auxdata< const xAOD::Vertex*                 >(m_inContainerName+"_vtx");
    for(const xAOD::TrackParticle* trkInJet: inputTracks){

      nObj++;

      //
      // Get cut desicion
      //
      int passSel = this->PassCuts( trkInJet, pvx );

      //
      // if
      //
      if(passSel) {
    nPass++;
    outputTracks.push_back(trkInJet);
      }
    }// tracks

    m_numObject     += nObj;
    m_numObjectPass += nPass;

    m_track_decoration(*jet_itr)  = outputTracks;
    m_vtx_decoration(*jet_itr)    = jet_itr->auxdata<const xAOD::Vertex*>(m_inContainerName+"_vtx");

  }//jets

  m_numEventPass++;
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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.

  ANA_MSG_DEBUG("Calling postExecute");

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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.

  ANA_MSG_DEBUG("Deleting tool instances...");

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TrackSelector :: 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;
}

int TrackSelector :: PassCuts( const xAOD::TrackParticle* trk, const xAOD::Vertex *pvx ) {

  // InDetTrackSelectionTool
  if ( !m_trkSelTool_handle->accept(*trk, pvx) ) { return 0; }

  // Cuts not available with the InDetTrackSelectionTool
  //
  // pT_max
  //
  if( m_pT_max != 1e8 ) {
    if ( trk->pt() > m_pT_max ) { return 0; }
  }

  //
  // eta
  //
  if( m_eta_min != 1e8 ) {
    if( fabs(trk->eta()) < m_eta_min ) { return 0; }
  }
  if( m_etaSigned_max != 1e8 ) {
    if( trk->eta() > m_etaSigned_max ) { return 0; }
  }
  if( m_etaSigned_min != 1e8 ) {
    if( trk->eta() < m_etaSigned_min ) { return 0; }
  }



  //
  //  nBLayer
  //
  uint8_t nBL       = -1;
  if( m_nBL_min != 1e8 ){
    //  xAOD::numberOfBLayerHits is deprecated, keeping it for compatibility
    if(!trk->summaryValue(nBL, xAOD::numberOfBLayerHits)) ANA_MSG_ERROR( "BLayer hits not filled");
    if( nBL < m_nBL_min ) {return 0; }
  }

  //
  //  chi2Prob_max
  //
  float        chi2        = trk->chiSquared();
  float        ndof        = trk->numberDoF();
  if( m_chi2Prob_max != 1e8 ){
    float        chi2Prob    = TMath::Prob(chi2,ndof);
    if( chi2Prob > m_chi2Prob_max) { return 0; }
  }

  //
  //  Pass Keys
  //
  for(auto& passKey : m_passKeys){
    if(!(trk->auxdata< char >(passKey) == '1')) { return 0; }
  }

  //
  //  Fail Keys
  //
  for(auto& failKey : m_failKeys){
    if(!(trk->auxdata< char >(failKey) == '0')) { return 0; }
  }


  return 1;
}