Program Listing for File TruthSelector.cxx

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

/************************************
 *
 * Truth selector tool
 *
 * J.Alison (john.alison@cern.ch)
 *
 ************************************/

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

// EL include(s):
#include <EventLoop/Job.h>
#include <EventLoop/StatusCode.h>
#include <EventLoop/Worker.h>

// EDM include(s):
#include "xAODTruth/TruthParticleContainer.h"
#include "xAODCore/ShallowCopy.h"
#include "AthContainers/ConstDataVector.h"
#include "PATInterfaces/SystematicVariation.h"
#include "PATInterfaces/SystematicRegistry.h"

// package include(s):
#include "xAODEventInfo/EventInfo.h"
#include "xAODAnaHelpers/TruthSelector.h"
#include "xAODAnaHelpers/HelperClasses.h"
#include "xAODAnaHelpers/HelperFunctions.h"

// external tools include(s):

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

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

TruthSelector :: TruthSelector () :
    Algorithm("TruthSelector")
{
}

EL::StatusCode TruthSelector :: setupJob (EL::Job& job)
{
  ANA_MSG_INFO( "Calling setupJob");

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

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: histInitialize ()
{
  ANA_MSG_INFO( "Calling histInitialize");
  ANA_CHECK( xAH::Algorithm::algInitialize());
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: fileExecute ()
{
  ANA_MSG_INFO( "Calling fileExecute");
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: changeInput (bool /*firstFile*/)
{
  ANA_MSG_INFO( "Calling changeInput");
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: initialize ()
{
  ANA_MSG_INFO( "Calling initialize");

  if ( m_useCutFlow ) {

   // retrieve the file in which the cutflow hists are stored
    //
    TFile *file     = wk()->getOutputFile (m_cutFlowStreamName);

    // retrieve the event cutflows
    //
    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());

    // retrieve the object cutflow
    //
    m_truth_cutflowHist_1 = (TH1D*)file->Get("cutflow_truths_1");

    m_truth_cutflow_all             = m_truth_cutflowHist_1->GetXaxis()->FindBin("all");
    m_truth_cutflow_ptmax_cut       = m_truth_cutflowHist_1->GetXaxis()->FindBin("ptmax_cut");
    m_truth_cutflow_ptmin_cut       = m_truth_cutflowHist_1->GetXaxis()->FindBin("ptmin_cut");
    m_truth_cutflow_eta_cut         = m_truth_cutflowHist_1->GetXaxis()->FindBin("eta_cut");

  }

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

  m_decor   = "passSel";

  if ( m_decorateSelectedObjects ) {
    ANA_MSG_INFO(" Decorate Jets with " << m_decor);
  }


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

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

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

  ANA_MSG_INFO( "TruthSelector Interface succesfully initialized!" );

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: execute ()
{
  ANA_MSG_DEBUG( "Applying Jet Selection... ");

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

  // MC event weight
  float mcEvtWeight(1.0);
  static SG::AuxElement::Accessor< float > mcEvtWeightAcc("mcEventWeight");
  if ( ! mcEvtWeightAcc.isAvailable( *eventInfo ) ) {
    ANA_MSG_ERROR( "mcEventWeight is not available as decoration! Aborting" );
    return EL::StatusCode::FAILURE;
  }
  mcEvtWeight = mcEvtWeightAcc( *eventInfo );

  m_numEvent++;

  // did any collection pass the cuts?
  bool pass(false);
  bool count(true); // count for the 1st collection in the container - could be better as
                    // shoudl only count for the nominal
  const xAOD::TruthParticleContainer* inTruthParts(nullptr);

  // if input comes from xAOD, or just running one collection,
  // then get the one collection and be done with it

  // this will be the collection processed - no matter what!!
  ANA_CHECK( HelperFunctions::retrieve(inTruthParts, m_inContainerName, m_event, m_store, msg()) );

  pass = executeSelection( inTruthParts, mcEvtWeight, count, m_outContainerName);

  // look what we have in TStore
  if(msgLvl(MSG::VERBOSE)) m_store->print();

  if ( !pass ) {
    wk()->skipEvent();
  }

  return EL::StatusCode::SUCCESS;

}

bool TruthSelector :: executeSelection ( const xAOD::TruthParticleContainer* inTruthParts,
                     float mcEvtWeight,
                     bool count,
                     std::string outContainerName
                     )
{

  // create output container (if requested)
  ConstDataVector<xAOD::TruthParticleContainer>* selectedTruthParts(nullptr);
  if ( m_createSelectedContainer ) {
    selectedTruthParts = new ConstDataVector<xAOD::TruthParticleContainer>(SG::VIEW_ELEMENTS);
  }

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

  static SG::AuxElement::Decorator< char > passSelDecor( m_decor );

  for ( auto truth_itr : *inTruthParts ) { // duplicated of basic loop

    // if only looking at a subset of jets make sure all are decorated
    if ( m_nToProcess > 0 && nObj >= m_nToProcess ) {
      if ( m_decorateSelectedObjects ) {
        passSelDecor( *truth_itr ) = -1;
      } else {
        break;
      }
      continue;
    }

    nObj++;
    int passSel = this->PassCuts( truth_itr );
    if ( m_decorateSelectedObjects ) {
      passSelDecor( *truth_itr ) = passSel;
    }

    if ( passSel ) {
      nPass++;
      if ( m_createSelectedContainer ) {
        selectedTruthParts->push_back( truth_itr );
      }
    }
  }

  if ( count ) {
    m_numObject     += nObj;
    m_numObjectPass += nPass;
  }

  // add ConstDataVector to TStore
  if ( m_createSelectedContainer ) {
    ANA_CHECK( m_store->record( selectedTruthParts, outContainerName ));
  }

  // 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 ) {
    return false;
  }
  if ( m_pass_max >= 0 && nPass > m_pass_max ) {
    return false;
  }

  if ( count ) {
    m_numEventPass++;
    m_weightNumEventPass += mcEvtWeight;
  }

  return true;
}


EL::StatusCode TruthSelector :: postExecute ()
{
  ANA_MSG_DEBUG( "Calling postExecute");
  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: finalize ()
{
  ANA_MSG_INFO( m_name );

  if ( m_useCutFlow ) {
    ANA_MSG_INFO( "Filling cutflow");
    m_cutflowHist ->SetBinContent( m_cutflow_bin, m_numEventPass        );
    m_cutflowHistW->SetBinContent( m_cutflow_bin, m_weightNumEventPass  );
  }

  return EL::StatusCode::SUCCESS;
}



EL::StatusCode TruthSelector :: histFinalize ()
{
  ANA_MSG_INFO( "Calling histFinalize");
  ANA_CHECK( xAH::Algorithm::algFinalize());
  return EL::StatusCode::SUCCESS;
}

int TruthSelector :: PassCuts( const xAOD::TruthParticle* truthPart ) {

  // fill cutflow bin 'all' before any cut
  if(m_useCutFlow) m_truth_cutflowHist_1->Fill( m_truth_cutflow_all, 1 );

  // pT
  if ( m_pT_max != 1e8 ) {
    if ( truthPart->pt() > m_pT_max ) { return 0; }
  }
  if(m_useCutFlow) m_truth_cutflowHist_1->Fill( m_truth_cutflow_ptmax_cut, 1 );

  if ( m_pT_min != 1e8 ) {
    if ( truthPart->pt() < m_pT_min ) { return 0; }
  }
  if(m_useCutFlow) m_truth_cutflowHist_1->Fill( m_truth_cutflow_ptmin_cut, 1 );

  // eta
  if ( m_eta_max != 1e8 ) {
    if ( fabs(truthPart->eta()) > m_eta_max ) { return 0; }
  }
  if ( m_eta_min != 1e8 ) {
    if ( fabs(truthPart->eta()) < m_eta_min ) { return 0; }
  }
  if(m_useCutFlow) m_truth_cutflowHist_1->Fill( m_truth_cutflow_eta_cut, 1 );

  // mass
  if ( m_mass_max != 1e8 ) {
    if ( truthPart->m() > m_mass_max ) { return 0; }
  }
  if ( m_mass_min != 1e8 ) {
    if ( truthPart->m() < m_mass_min ) { return 0; }
  }

  // rapidity
  if ( m_rapidity_max != 1e8 ) {
    if ( truthPart->rapidity() > m_rapidity_max ) { return 0; }
  }

  if ( m_rapidity_min != 1e8 ) {
    if ( truthPart->rapidity() < m_rapidity_min ) { return 0; }
  }

  // selections for particles from MCTruthClassifier

  // type
  if ( !m_typeOptions.empty() ) { // check w.r.t. multiple possible type values
    if ( m_type != 1000 ) { ANA_MSG_WARNING( "single and multiple type conditions were selected, only the former will be used" );
    } else {
      std::string token;
      std::vector<unsigned int> typeVec;
      std::istringstream ss(m_typeOptions);
      while ( std::getline(ss, token, '|') ) typeVec.push_back(std::stoi(token));
      bool found = false;
      if( truthPart->isAvailable<unsigned int>("classifierParticleType") ){
        unsigned int type = truthPart->auxdata<unsigned int>("classifierParticleType");
        for (unsigned int i=0;i<typeVec.size();++i){
          if (type == typeVec.at(i)) found = true;
        }
        if (!found) { return 0; }
      } else {
        ANA_MSG_WARNING( "classifierParticleType is not available" );
      }
    }
  }
  if ( m_type != 1000 ) { // single type value
    if( truthPart->isAvailable<unsigned int>("classifierParticleType") ){
      unsigned int type = truthPart->auxdata<unsigned int>("classifierParticleType");
      if ( type != m_type ) { return 0; }
    } else {
      ANA_MSG_WARNING( "classifierParticleType is not available" );
    }
  }

  // origin
  if ( !m_originOptions.empty() ) { // check w.r.t. multiple possible origin values
    if ( m_origin != 1000 ) { ANA_MSG_WARNING( "single and multiple origin conditions were selected, only the former will be used" );
    } else {
      std::string token;
      std::vector<unsigned int> originVec;
      std::istringstream ss(m_originOptions);
      while ( std::getline(ss, token, '|') ) originVec.push_back(std::stoi(token));
      bool found = false;
      if( truthPart->isAvailable<unsigned int>("classifierParticleOrigin") ){
        unsigned int origin = truthPart->auxdata<unsigned int>("classifierParticleOrigin");
        for (unsigned int i=0;i<originVec.size();++i){
          if (origin == originVec.at(i)) found = true;
        }
        if (!found) { return 0; }
      } else {
        ANA_MSG_WARNING( "classifierParticleOrigin is not available" );
      }
    }
  }
  if ( m_origin != 1000 ) { // single origin value
    if( truthPart->isAvailable<unsigned int>("classifierParticleOrigin") ){
      unsigned int origin = truthPart->auxdata<unsigned int>("classifierParticleOrigin");
      if ( origin != m_origin ) { return 0; }
    } else {
      ANA_MSG_WARNING( "classifierParticleOrigin is not available" );
    }
  }

  // pt_dressed
  if ( m_pT_dressed_min != 1e8 ) {
    if( truthPart->isAvailable<float>("pt_dressed") ){
      float pT_dressed = truthPart->auxdata<float>("pt_dressed");
      if ( pT_dressed < m_pT_dressed_min ) { return 0; }
    } else {
      ANA_MSG_WARNING( "pt_dressed is not available" );
    }
  }

  // eta_dressed
  if ( m_eta_dressed_min != 1e8 ) {
    if( truthPart->isAvailable<float>("eta_dressed") ){
      float eta_dressed = truthPart->auxdata<float>("eta_dressed");
      if ( eta_dressed < m_eta_dressed_min ) { return 0; }
    } else {
      ANA_MSG_WARNING( "eta_dressed is not available" );
    }
  }
  if ( m_eta_dressed_max != 1e8 ) {
    if( truthPart->isAvailable<float>("eta_dressed") ){
      float eta_dressed = truthPart->auxdata<float>("eta_dressed");
      if ( eta_dressed > m_eta_dressed_max ) { return 0; }
    } else {
      ANA_MSG_WARNING( "eta_dressed is not available" );
    }
  }

  return 1;
}