Skip to content
Snippets Groups Projects
TrigL2ElectronFexMT.cxx 13.6 KiB
Newer Older
// -*- C++ -*-

/*
  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
*/

/**************************************************************************
 **
 **   File: Trigger/TrigHypothesis/TrigEgammaHypo/TrigL2ElectronFexMT.cxx
 **
 **   Description: Hypothesis algorithms to be run at Level 2 after
 **                tracking algorithms: creates TrigElectrons
 **
 **   Author: R.Goncalo <r.goncalo@rhul.ac.uk> Thu Jan 20 22:02:43 BST 2005
 **            P.Urquijo <Phillip.Urquijo@cern.ch>
 **
 **   Created:      Sat Mar  1 19:55:56 GMT 2005
 **   Modified:     RG 18 Mar 06 - fix to always generate TrigElectrons
 **                              - use key2keyStore for collection names
 **                 N.Berger Dec.06 - migrate to new steering (RG)
 **************************************************************************/

#include "TrkCaloExtension/CaloExtensionHelpers.h" 
#include "TrigL2ElectronFexMT.h"
#include "xAODTrigCalo/TrigEMClusterContainer.h"
#include "xAODTrigCalo/TrigEMClusterAuxContainer.h"
class ISvcLocator;

template <class SRC>
inline const DataVector<xAOD::TrigElectron>** dvec_cast(SRC** ptr) { 
  return (const DataVector<xAOD::TrigElectron>**)(ptr); 
} 


TrigL2ElectronFexMT::TrigL2ElectronFexMT(const std::string & name, ISvcLocator* pSvcLocator)

  // TODO: Replace this with a .h property once Gaudi!385 has been merged
  declareProperty("MonTool", m_monTool=VoidMonitoringTool(this), "Monitoring tool");

    m_extrapolator_failed = 0;
}


TrigL2ElectronFexMT::~TrigL2ElectronFexMT()
{}


StatusCode TrigL2ElectronFexMT::initialize()
{
  ATH_MSG_DEBUG("Initialization:");

  if (!m_monTool.empty()) {
    ATH_MSG_DEBUG("Retrieving monTool");
    CHECK(m_monTool.retrieve());
  } else {
    ATH_MSG_INFO("No monTool configured => NO MONITOING");
  }
  // initialize error counter
  m_extrapolator_failed = 0;

  if ( m_caloExtensionTool.retrieve().isFailure() ) {  
        ATH_MSG_ERROR("Unable to locate TrackExtrapolator tool ");
        return StatusCode::FAILURE; 
  }  

  // print out settings
  ATH_MSG_DEBUG("Initialization completed successfully:"); 
  ATH_MSG_DEBUG( "AcceptAll            = "<< 
          (m_acceptAll==true ? "True" : "False")); 
  ATH_MSG_DEBUG("TrackPt              = " << m_trackPtthr);          
  ATH_MSG_DEBUG("TrackPtHighEt        = " << m_trackPtthr_highet);          
  ATH_MSG_DEBUG("ClusEt               = " << m_clusEtthr);          
  ATH_MSG_DEBUG("CaloTrackdEtaNoExtrap= " << m_calotrkdeta_noextrap);        
  ATH_MSG_DEBUG("CaloTrackdEtaNoExtrapHighEt= " << m_calotrkdeta_noextrap_highet);        
  ATH_MSG_DEBUG("CaloTrackdETA        = " << m_calotrackdeta);        
  ATH_MSG_DEBUG("CaloTrackdPHI        = " << m_calotrackdphi);        
  ATH_MSG_DEBUG("CaloTrackdEoverPLow  = " << m_calotrackdeoverp_low); 
  ATH_MSG_DEBUG("CaloTrackdEoverPHigh = " << m_calotrackdeoverp_high);

ATH_CHECK( m_roiCollectionKey.initialize() );
ATH_CHECK( m_TrigEMClusterContainerKey.initialize() );
ATH_CHECK( m_TrackParticleContainerKey.initialize() );
ATH_CHECK( m_outputElectronsKey.initialize() );

  return StatusCode::SUCCESS;
}


StatusCode TrigL2ElectronFexMT::finalize()
{
    ATH_MSG_INFO("in finalize()");

    if (m_extrapolator_failed) 
        ATH_MSG_INFO("track extrapolation failed " << m_extrapolator_failed << " times");

    return  StatusCode::SUCCESS;
}


StatusCode TrigL2ElectronFexMT::execute() {
 using namespace Monitored;   
 using namespace xAOD;   
  auto ctx = getContext();

  auto trigElecColl =   SG::makeHandle (m_outputElectronsKey, ctx);  
  ATH_CHECK( trigElecColl.record (std::make_unique<xAOD::TrigElectronContainer>(),
                           std::make_unique<xAOD::TrigEMClusterAuxContainer>()) );

  auto roiCollection = SG::makeHandle(m_roiCollectionKey, ctx);

  //JTB For the moment assume 1 RoI (as in TrigL2ElectronFex) - could change to SuperRoI later

  //TrigRoiDescriptorCollection::const_iterator roiDescriptor = roiCollection->begin();
  //TrigRoiDescriptorCollection::const_iterator roiE = roiCollection->end();

  if (roiCollection->size()==0) {
    ATH_MSG_DEBUG(" RoI collection size = 0");
    return StatusCode::SUCCESS;
  }

  const TrigRoiDescriptor* roiDescriptor = *(roiCollection->begin());

  ATH_MSG_DEBUG(" RoI ID = "   << (roiDescriptor)->roiId()
		<< ": Eta = "      << (roiDescriptor)->eta()
		<< ", Phi = "      << (roiDescriptor)->phi());
  
  float calo_eta(999), calo_phi(999), calo_et(-1);

  auto clusContainer = SG::makeHandle (m_TrigEMClusterContainerKey, ctx);
  
  
  //JTB Should only be 1 cluster in each RoI 

  const xAOD::TrigEMCluster *el_t2calo_clus=(*clusContainer->begin());
  ElementLink<xAOD::TrigEMClusterContainer> clusEL=ElementLink<xAOD::TrigEMClusterContainer> (*clusContainer,0);

  // copy relevant quantities to local variables
  calo_eta = el_t2calo_clus->eta();
  calo_phi = el_t2calo_clus->phi();
  calo_et  = el_t2calo_clus->et();


  // Transverse em energy
  ATH_MSG_DEBUG("Cluster: ET=" << calo_et);
  ATH_MSG_DEBUG("searching a matching track: loop over tracks");



  SG::ReadHandle<xAOD::TrackParticleContainer> tracks(m_TrackParticleContainerKey, ctx);


  if (tracks->size() < 1){
      ATH_MSG_ERROR("No track collection, vector < 1");
      return StatusCode::SUCCESS; //HLT::MISSING_FEATURE;
  }
  
  size_t coll_size = tracks->size();
  trigElecColl->reserve(coll_size);

  // monitoring
  std::vector<float> calotrkdeta_noextrap_mon; //!< monitor preselection between track eta and cluster before extrapolation 
  std::vector<float> calotrackdeta_mon; 
  std::vector<float> calotrackdphi_mon; 
  std::vector<float> calotrackdeoverp_mon;
  std::vector<float> trackpt_mon;
  std::vector<float> calopt_mon;

  auto mon1 = MonitoredCollection::declare("PtCalo", calopt_mon);
  auto mon2 = MonitoredCollection::declare("PtTrack", trackpt_mon);
  auto mon3 = MonitoredCollection::declare("CaloTrackdEta", calotrackdeta_mon);
  auto mon4 = MonitoredCollection::declare("CaloTrackdPhi", calotrackdphi_mon);
  auto mon5 = MonitoredCollection::declare("CaloTrackEoverP", calotrackdeoverp_mon);
  auto mon6 = MonitoredCollection::declare("CaloTrackdEtaNoExtrapMon",  calotrkdeta_noextrap_mon);

  auto mon = MonitoredScope::declare(m_monTool,  mon1, mon2, mon3, mon4, mon5, mon6);

  // loop over tracks

  unsigned int track_index=0;
  for(const auto trkIter:(*tracks)){
      ATH_MSG_VERBOSE("AlgoId = " << (trkIter)->patternRecoInfo());
      ATH_MSG_VERBOSE("At perigee:");
      ATH_MSG_VERBOSE(" Pt  = " << fabs((trkIter)->pt())); 
      ATH_MSG_VERBOSE(" phi = " << fabs((trkIter)->phi0()));
      ATH_MSG_VERBOSE(" eta = " << fabs((trkIter)->eta())); 
      ATH_MSG_VERBOSE(" z0  = " << fabs((trkIter)->z0()));  

      // ============================================= //
      // Pt cut
      float trkPt = fabs((trkIter)->pt());
      float etoverpt = fabs(calo_et/trkPt);
      float calotrkdeta_noextrap = (trkIter)->eta() - calo_eta;
      
      double etaAtCalo=999.;
      double phiAtCalo=999.;
      if(m_acceptAll){
	if(!extrapolate(el_t2calo_clus,trkIter,etaAtCalo,phiAtCalo)){
              ATH_MSG_VERBOSE("extrapolator failed");
              continue; 
          else{
              ATH_MSG_VERBOSE("REGTEST: TrigElectron: cluster index = " << clusEL.index() <<
                      " track = "     << trkIter << " eta = " << etaAtCalo << " phi = " << phiAtCalo); 
              xAOD::TrigElectron* trigElec = new xAOD::TrigElectron();
              trigElecColl->push_back(trigElec);
	      ElementLink<xAOD::TrackParticleContainer> trackEL = ElementLink<xAOD::TrackParticleContainer> (*tracks, track_index);
	      
              trigElec->init(  roiDescriptor->roiWord(),
                      etaAtCalo, phiAtCalo,  etoverpt,        
                      clusEL,
                      trackEL);
	      calotrackdeta_mon.push_back(trigElec->trkClusDeta()); 
              calotrackdphi_mon.push_back(trigElec->trkClusDphi()); 
              calotrackdeoverp_mon.push_back(trigElec->etOverPt());
              trackpt_mon.push_back(getTkPt(trigElec));
              calopt_mon.push_back(getCaloPt(trigElec));
              calotrkdeta_noextrap_mon.push_back(calotrkdeta_noextrap);
          }
      }
      else {  
          ATH_MSG_DEBUG("Apply cuts");
          if(trkPt < m_trackPtthr){
              ATH_MSG_DEBUG("Failed track pt cut " << trkPt);
              continue;
          }
          if(fabs(calotrkdeta_noextrap) > m_calotrkdeta_noextrap){
              ATH_MSG_DEBUG("Failed pre extrapolation calo track deta " << calotrkdeta_noextrap);
              continue;
          }
          if(calo_et > m_clusEtthr){
              if(trkPt < m_trackPtthr_highet){
                  ATH_MSG_DEBUG("Failed track pt cut for high et cluster");
                  continue;
              }
              if(calotrkdeta_noextrap > m_calotrkdeta_noextrap_highet){
                  ATH_MSG_DEBUG("Failed pre extrapolation calo track deta for high et");
                  continue;
              }
          } 
          if (etoverpt < m_calotrackdeoverp_low){ 
              ATH_MSG_DEBUG("failed low cut on ET/PT");
              continue;
          }
          if (etoverpt > m_calotrackdeoverp_high){ 
              ATH_MSG_DEBUG("failed high cut on ET/PT");
              continue;
          }
          if(!extrapolate(el_t2calo_clus,trkIter,etaAtCalo,phiAtCalo)){
              ATH_MSG_DEBUG("extrapolator failed 1");
              continue; 
          }
          // all ok: do track-matching cuts
          ATH_MSG_DEBUG("extrapolated eta/phi=" << etaAtCalo << "/" << phiAtCalo);
          // match in eta
          float dEtaCalo = fabs(etaAtCalo - calo_eta);
          ATH_MSG_DEBUG("deta = " << dEtaCalo); 
          if ( dEtaCalo > m_calotrackdeta){ 
              ATH_MSG_DEBUG("failed eta match cut " << dEtaCalo);
              continue;
          }

          // match in phi: deal with differences larger than Pi
          float dPhiCalo =  fabs(phiAtCalo - calo_phi);
          dPhiCalo       = ( dPhiCalo < M_PI ? dPhiCalo : 2*M_PI - dPhiCalo );
          ATH_MSG_DEBUG("dphi = " << dPhiCalo); 
          if ( dPhiCalo > m_calotrackdphi) {
              ATH_MSG_DEBUG("failed phi match cut " << dPhiCalo);
              continue;
          }
          // all cuts passed

          /** Create a TrigElectron corresponding to this candidate
            assume cluster quantities give better estimate of transverse energy
            (probably a safe assumption for large pT) and that track parameters
            at perigee give better estimates of angular quantities */

	  ElementLink<xAOD::TrackParticleContainer> trackEL = ElementLink<xAOD::TrackParticleContainer> (*tracks, track_index);
          ATH_MSG_DEBUG("REGTEST: TrigElectron: cluster index = " << clusEL.index() <<
                  " track = "     << trkIter << " eta = " << 
                  etaAtCalo << " phi = " << phiAtCalo << 
                  " deta = " << dEtaCalo << "dphi = " << dPhiCalo);

          xAOD::TrigElectron* trigElec = new xAOD::TrigElectron();
          trigElecColl->push_back(trigElec);
          trigElec->init( roiDescriptor->roiWord(),
                  etaAtCalo, phiAtCalo,  etoverpt,        
                  clusEL,
                  trackEL);
          ATH_MSG_DEBUG(" deta = " << dEtaCalo << " deta = " << trigElec->trkClusDeta() 
                  << " dphi = " << dPhiCalo << " dphi = " << trigElec->trkClusDphi()
                  << " caloEta = " << calo_eta << " caloEta = " << trigElec->caloEta()
                  << " caloPhi = " << calo_phi << " calophi = " << trigElec->caloPhi()
                  << " etaAtCalo = " << etaAtCalo << " etaAtCalo = " << trigElec->trkEtaAtCalo()
                  << " phiAtCalo = " << phiAtCalo << " phiAtCalo = " << trigElec->trkPhiAtCalo()
                  );

          calotrackdeta_mon.push_back(trigElec->trkClusDeta()); 
          calotrackdphi_mon.push_back(trigElec->trkClusDphi()); 
          calotrackdeoverp_mon.push_back(trigElec->etOverPt());
          trackpt_mon.push_back(getTkPt(trigElec));
          calopt_mon.push_back(getCaloPt(trigElec));
          calotrkdeta_noextrap_mon.push_back(calotrkdeta_noextrap);
      }
      track_index++;
  }


  ATH_MSG_DEBUG("REGTEST:  returning an xAOD::TrigElectronContainer with size "<< trigElecColl->size() << ".");
  
  return StatusCode::SUCCESS;
}

bool TrigL2ElectronFexMT::extrapolate(const xAOD::TrigEMCluster *clus, const xAOD::TrackParticle *trk, double &etaAtCalo, double &phiAtCalo){
    CaloExtensionHelpers::LayersToSelect layersToSelect; 
    layersToSelect.insert(CaloSampling::CaloSample::EMB2); 
    layersToSelect.insert(CaloSampling::CaloSample::EME2); 
    // extrapolate track using tool
    // get calo extension 
    const Trk::CaloExtension* caloExtension = 0; 
    bool useCaching = false; 

    if( !m_caloExtensionTool->caloExtension(*trk,caloExtension,useCaching) || caloExtension->caloLayerIntersections().empty() ) {
        ATH_MSG_VERBOSE("extrapolator failed 1");
        m_extrapolator_failed++;  
        return false;
    }  
    // extract eta/phi in EM2 
    CaloExtensionHelpers::EtaPhiPerLayerVector intersections; 
    CaloExtensionHelpers::midPointEtaPhiPerLayerVector( *caloExtension, intersections, &layersToSelect ); 
    if( intersections.empty() ) { 
        ATH_MSG_VERBOSE("extrapolator failed 2");
        m_extrapolator_failed++;  
        return false;
    }  
    // pick the correct sample in case of ambiguity 
    std::tuple<CaloSampling::CaloSample, double, double> etaPhiTuple = intersections.front(); 
    if( intersections.size() == 2 )  
        if ( clus->energy(CaloSampling::CaloSample::EME2) > clus->energy(CaloSampling::CaloSample::EMB2) ) 
            etaPhiTuple=intersections.back(); 
    etaAtCalo = std::get<1>(etaPhiTuple); 
    phiAtCalo = std::get<2>(etaPhiTuple); 

    return true;
}