CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/RecoHI/HiTracking/src/HICaloCompatibleTrackSelector.cc

Go to the documentation of this file.
00001 /*
00002  
00003  Based on analytical track selector   
00004  
00005  - This track selector assigns a quality bit to tracks deemed compatible with matching calo info
00006  - The default mode is to use the matching provided by particle flow,
00007    but a delta R matching to calorimeter towers is also supported
00008  - No selection is done other then selecting calo-compatible tracks.
00009  - The code always keeps all tracks in the input collection (should make configurable) 
00010  - Note that matching by PF candidate only works on the same track collection used as input to PF
00011  - Tower code not up to data
00012  
00013    Authors:  Matthew Nguyen, Andre Yoon, Frank Ma (November 4th, 2011)
00014 
00015  */
00016 
00017 
00018 // Basic inclusion
00019 #include "RecoHI/HiTracking/interface/HICaloCompatibleTrackSelector.h"
00020 
00021 #include "DataFormats/TrackReco/interface/Track.h"
00022 #include "DataFormats/TrackReco/interface/TrackFwd.h"
00023 
00024 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h"
00025 #include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
00026 #include "DataFormats/ParticleFlowReco/interface/PFClusterFwd.h"
00027 
00028 #include "DataFormats/RecoCandidate/interface/TrackAssociation.h"
00029 #include "SimTracker/Records/interface/TrackAssociatorRecord.h"
00030 #include "SimTracker/TrackAssociation/interface/TrackAssociatorByHits.h"
00031 #include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h"
00032 #include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h"
00033 
00034 #include "DataFormats/CaloTowers/interface/CaloTower.h"
00035 #include "DataFormats/CaloTowers/interface/CaloTowerFwd.h"
00036 
00037 #include "FWCore/Framework/interface/EventSetup.h"
00038 #include "FWCore/Framework/interface/ESHandle.h"
00039 
00040 #include "DataFormats/Math/interface/deltaR.h"
00041 #include <Math/DistFunc.h>
00042 #include "TMath.h"
00043 
00044 
00045 using reco::modules::HICaloCompatibleTrackSelector;
00046 
00047 HICaloCompatibleTrackSelector::HICaloCompatibleTrackSelector( const edm::ParameterSet & cfg ) :
00048   srcTracks_(cfg.getParameter<edm::InputTag>("srcTracks")),
00049   srcPFCands_(cfg.getParameter<edm::InputTag>("srcPFCands")),
00050   srcTower_(cfg.getParameter<edm::InputTag>("srcTower")),
00051   usePFCandMatching_(cfg.getUntrackedParameter<bool>("usePFCandMatching", true)),
00052   trkMatchPtMin_(cfg.getUntrackedParameter<double>("trkMatchPtMin",10.0)),
00053   trkCompPtMin_(cfg.getUntrackedParameter<double>("trkCompPtMin",35.0)),
00054   trkEtaMax_(cfg.getUntrackedParameter<double>("trkEtaMax",2.4)),
00055   towerPtMin_(cfg.getUntrackedParameter<double>("towerPtMin",5.0)),
00056   matchConeRadius_(cfg.getUntrackedParameter<double>("matchConeRadius",0.087)),
00057   keepAllTracks_(cfg.getUntrackedParameter<bool>("keepAllTracks", true)),
00058   copyExtras_(cfg.getUntrackedParameter<bool>("copyExtras", true)),
00059   copyTrajectories_(cfg.getUntrackedParameter<bool>("copyTrajectories", true)),
00060   qualityToSet_(cfg.getParameter<std::string>("qualityToSet")),
00061   qualityToSkip_(cfg.getParameter<std::string>("qualityToSkip")),
00062   qualityToMatch_(cfg.getParameter<std::string>("qualityToMatch")),
00063   minimumQuality_(cfg.getParameter<std::string>("minimumQuality")),
00064   resetQuality_(cfg.getUntrackedParameter<bool>("resetQuality", true)),
00065   passMuons_(cfg.getUntrackedParameter<bool>("passMuons", true)),
00066   passElectrons_(cfg.getUntrackedParameter<bool>("passElectrons", false)),
00067   funcDeltaRTowerMatch_(cfg.getParameter<std::string>("funcDeltaRTowerMatch")),
00068   funcCaloComp_(cfg.getParameter<std::string>("funcCaloComp"))
00069 {
00070   std::string alias( cfg.getParameter<std::string>( "@module_label" ) );
00071   produces<reco::TrackCollection>().setBranchAlias( alias + "Tracks");
00072   if (copyExtras_) {
00073     produces<reco::TrackExtraCollection>().setBranchAlias( alias + "TrackExtras");
00074     produces<TrackingRecHitCollection>().setBranchAlias( alias + "RecHits");
00075   }
00076   if (copyTrajectories_) {
00077     produces< std::vector<Trajectory> >().setBranchAlias( alias + "Trajectories");
00078     produces< TrajTrackAssociationCollection >().setBranchAlias( alias + "TrajectoryTrackAssociations");
00079   }
00080 
00081   // pt dependence of delta R matching requirement
00082   fDeltaRTowerMatch = new TF1("fDeltaRTowerMatch",funcDeltaRTowerMatch_.c_str(),0,200); 
00083   // pt dependance of calo compatibility, i.e., minimum sum Calo Et vs. track pT
00084   fCaloComp = new TF1("fCaloComp",funcCaloComp_.c_str(),0,200); // a parameterization of pt dependent cut
00085 
00086 
00087 }
00088 
00089 HICaloCompatibleTrackSelector::~HICaloCompatibleTrackSelector() {
00090 }
00091 
00092 
00093 void HICaloCompatibleTrackSelector::produce( edm::Event& evt, const edm::EventSetup& es ) 
00094 {
00095   using namespace std; 
00096   using namespace edm;
00097   using namespace reco;
00098   
00099   LogDebug("HICaloCompatibleTrackSelector")<<"min pt for selection = "<< trkMatchPtMin_<<endl;
00100   
00101   
00102   Handle<TrackCollection> hSrcTrack;
00103   Handle< vector<Trajectory> > hTraj;
00104   Handle< vector<Trajectory> > hTrajP;
00105   Handle< TrajTrackAssociationCollection > hTTAss;
00106 
00107   evt.getByLabel(srcTracks_,hSrcTrack);
00108   
00109   selTracks_ = auto_ptr<TrackCollection>(new TrackCollection());
00110   rTracks_ = evt.getRefBeforePut<TrackCollection>();      
00111   if (copyExtras_) {
00112     selTrackExtras_ = auto_ptr<TrackExtraCollection>(new TrackExtraCollection());
00113     selHits_ = auto_ptr<TrackingRecHitCollection>(new TrackingRecHitCollection());
00114     rHits_ = evt.getRefBeforePut<TrackingRecHitCollection>();
00115     rTrackExtras_ = evt.getRefBeforePut<TrackExtraCollection>();
00116   }
00117 
00118 
00119   if (copyTrajectories_) trackRefs_.resize(hSrcTrack->size());
00120 
00121 
00122   Handle<PFCandidateCollection> pfCandidates;
00123   Handle<CaloTowerCollection> towers;
00124 
00125   bool isPFThere = false;
00126   bool isTowerThere = false;
00127   
00128   if(usePFCandMatching_) isPFThere = evt.getByLabel(srcPFCands_, pfCandidates);  
00129   else isTowerThere = evt.getByLabel(srcTower_, towers);
00130   
00131   size_t current = 0;
00132   for (TI ti = hSrcTrack->begin(), ed = hSrcTrack->end(); ti != ed; ++ti, ++current) {
00133     
00134 
00135     const reco::Track& trk = *ti;
00136     
00137     bool isSelected;
00138     if(usePFCandMatching_) isSelected = selectByPFCands(ti, hSrcTrack, pfCandidates, isPFThere);
00139     else isSelected = selectByTowers(ti, hSrcTrack, towers, isTowerThere);
00140     
00141     if(!keepAllTracks_ && !isSelected) continue; 
00142 
00143     // Add all tracks to output collection, the rest of the code only sets the quality bit
00144     selTracks_->push_back( reco::Track( trk ) ); // clone and store
00145     
00146     
00147     if(isSelected) selTracks_->back().setQuality(reco::TrackBase::qualityByName(qualityToSet_.c_str()));
00148     
00149         
00150     if (copyExtras_) {
00151       // TrackExtras
00152       selTrackExtras_->push_back( TrackExtra( trk.outerPosition(), trk.outerMomentum(), trk.outerOk(),
00153                                               trk.innerPosition(), trk.innerMomentum(), trk.innerOk(),
00154                                               trk.outerStateCovariance(), trk.outerDetId(),
00155                                               trk.innerStateCovariance(), trk.innerDetId(),
00156                                               trk.seedDirection(), trk.seedRef() ) );
00157       selTracks_->back().setExtra( TrackExtraRef( rTrackExtras_, selTrackExtras_->size() - 1) );
00158       TrackExtra & tx = selTrackExtras_->back();
00159       tx.setResiduals(trk.residuals());
00160       // TrackingRecHits
00161       for( trackingRecHit_iterator hit = trk.recHitsBegin(); hit != trk.recHitsEnd(); ++ hit ) {
00162         selHits_->push_back( (*hit)->clone() );
00163         tx.add( TrackingRecHitRef( rHits_, selHits_->size() - 1) );
00164       }
00165     }
00166     if (copyTrajectories_) {
00167       trackRefs_[current] = TrackRef(rTracks_, selTracks_->size() - 1);
00168     }
00169 
00170     
00171   }  // close track loop
00172   
00173   if ( copyTrajectories_ ) {
00174     Handle< vector<Trajectory> > hTraj;
00175     Handle< TrajTrackAssociationCollection > hTTAss;
00176     evt.getByLabel(srcTracks_, hTTAss);
00177     evt.getByLabel(srcTracks_, hTraj);
00178     selTrajs_ = auto_ptr< vector<Trajectory> >(new vector<Trajectory>()); 
00179     rTrajectories_ = evt.getRefBeforePut< vector<Trajectory> >();
00180     selTTAss_ = auto_ptr< TrajTrackAssociationCollection >(new TrajTrackAssociationCollection());
00181     for (size_t i = 0, n = hTraj->size(); i < n; ++i) {
00182       Ref< vector<Trajectory> > trajRef(hTraj, i);
00183       TrajTrackAssociationCollection::const_iterator match = hTTAss->find(trajRef);
00184       if (match != hTTAss->end()) {
00185         const Ref<TrackCollection> &trkRef = match->val; 
00186         short oldKey = static_cast<short>(trkRef.key());
00187         if (trackRefs_[oldKey].isNonnull()) {
00188           selTrajs_->push_back( Trajectory(*trajRef) );
00189           selTTAss_->insert ( Ref< vector<Trajectory> >(rTrajectories_, selTrajs_->size() - 1), trackRefs_[oldKey] );
00190         }
00191       }
00192     }
00193   }
00194   
00195   static const string emptyString;
00196   evt.put(selTracks_);
00197   if (copyExtras_ ) {
00198     evt.put(selTrackExtras_); 
00199     evt.put(selHits_);
00200   }
00201   if ( copyTrajectories_ ) {
00202     evt.put(selTrajs_);
00203     evt.put(selTTAss_);
00204   }
00205 }
00206 
00207 
00208 
00209 bool 
00210 HICaloCompatibleTrackSelector::selectByPFCands(TI ti, edm::Handle<TrackCollection> hSrcTrack, edm::Handle<PFCandidateCollection> pfCandidates, bool isPFThere)
00211 {
00212 
00213   const reco::Track& trk = *ti;
00214 
00215   // If it passes this quality threshold or is under the minimum match pT, automatically save it
00216   if(trk.quality(reco::TrackBase::qualityByName(qualityToSkip_))){
00217     return true;
00218   }
00219   else if(!trk.quality(reco::TrackBase::qualityByName(minimumQuality_))){
00220     return false;
00221   }
00222   else
00223     {      
00224       
00225       double trkPt = trk.pt();
00226       //if(trkPt < trkMatchPtMin_ ) return false;
00227       
00228       double caloEt = 0.0;
00229       if(usePFCandMatching_){
00230         if(isPFThere){
00231           unsigned int trackKey = ti - hSrcTrack->begin();
00232           caloEt = matchPFCandToTrack(pfCandidates, trackKey, trkPt);      
00233         }
00234       }
00235       
00236       // Set quality bit based on calo matching
00237       if(!(caloEt>0.)) return false;
00238       
00239       
00240       if(trkPt<=trkCompPtMin_){
00241         if(trk.quality(reco::TrackBase::qualityByName(qualityToMatch_))) return true;
00242         else return false;
00243       }
00244       else{
00245         // loose cuts are implied in selectors, make configurable?
00246         float compPt = (fCaloComp->Eval(trkPt)!=fCaloComp->Eval(trkPt)) ? 0 : fCaloComp->Eval(trkPt); // protect agains NaN
00247         if(caloEt>compPt) return true;
00248         else return false;
00249       }            
00250     } // else above trkMatchPtMin_
00251 
00252   throw cms::Exception("Undefined case in HICaloCompatibleTrackSelector") << "Undefined case in HICaloCompatibleTrackSelector";
00253 }
00254 
00255 
00256 bool 
00257 HICaloCompatibleTrackSelector::selectByTowers(TI ti, edm::Handle<TrackCollection> hSrcTrack, edm::Handle<CaloTowerCollection> towers, bool isTowerThere)
00258 {
00259 
00260   // Not up to date! use PF towers instead
00261 
00262   const reco::Track& trk = *ti;
00263 
00264   // If it passes the high purity cuts, then consider it confirmed
00265   if(trk.quality(reco::TrackBase::qualityByName(qualityToSkip_))){
00266     return true;
00267   }
00268   else{
00269     if(trk.pt() <  trkMatchPtMin_ || !trk.quality(reco::TrackBase::qualityByName(qualityToMatch_))) return false;
00270     
00271     double caloEt = 0.0;
00272     if(isTowerThere){      
00273       double matchDr;
00274       matchByDrAllowReuse(trk,towers,matchDr,caloEt);
00275       float matchConeRadius_pt = (fDeltaRTowerMatch->Eval(trk.pt())!=fDeltaRTowerMatch->Eval(trk.pt())) ? 0 : fDeltaRTowerMatch->Eval(trk.pt()); // protect agains NaN
00276       if (caloEt>0 && matchDr>matchConeRadius_pt) caloEt=0.;      
00277     }
00278     
00279     if(trk.pt()<trkCompPtMin_||caloEt>0.75*(trk.pt()-trkCompPtMin_)) return true;
00280     else return false;
00281   }
00282 }
00283 
00284 double
00285 HICaloCompatibleTrackSelector::matchPFCandToTrack( const edm::Handle<reco::PFCandidateCollection> & pfCandidates, unsigned it, double trkPt)
00286 {
00287 
00288   // This function returns the sum of the calo energy in the block containing the track
00289   // There is another piece of information which could be useful which is the pT assigned to the charged hadron by PF
00290   
00291 
00292   double sum_ecal=0.0, sum_hcal=0.0;
00293     
00294   int candType = 0;
00295   reco::PFCandidate matchedCand; 
00296 
00297   // loop over the PFCandidates until you find the one whose trackRef points to the track
00298 
00299   for( CI ci  = pfCandidates->begin(); ci!=pfCandidates->end(); ++ci)  {
00300 
00301     const reco::PFCandidate& cand = *ci;
00302 
00303     int type = cand.particleId();
00304     
00305     // only charged hadrons and leptons can be asscociated with a track
00306     if(!(type == PFCandidate::h ||     //type1
00307          type == PFCandidate::e ||     //type2
00308          type == PFCandidate::mu      //type3
00309          )
00310        ) continue;
00311     
00312     
00313     unsigned candTrackRefKey = cand.trackRef().key();      
00314     
00315     if(it==candTrackRefKey) {
00316       matchedCand = cand;
00317       candType = type;
00318       break;      
00319     }
00320   }
00321   // take all muons as compatible, extend to electrons when validataed
00322   if(passMuons_ && candType==3) return 9999.;
00323   if(passElectrons_ && candType==2) return 9999.;
00324 
00325   if(trkPt < trkMatchPtMin_ ) return 0.;
00326 
00327   if(candType>0){
00328     
00329     // Now that we found the matched PF candidate, loop over the elements in the block summing the calo Et
00330     for(unsigned ib=0; ib<matchedCand.elementsInBlocks().size(); ib++) {
00331       
00332       PFBlockRef blockRef = matchedCand.elementsInBlocks()[ib].first;
00333             
00334       unsigned indexInBlock = matchedCand.elementsInBlocks()[ib].second;
00335       const edm::OwnVector<  reco::PFBlockElement>&  elements = (*blockRef).elements();
00336       
00337       //This tells you what type of element it is:
00338       //cout<<" block type"<<elements[indexInBlock].type()<<endl;
00339       
00340       switch (elements[indexInBlock].type()) {
00341         
00342       case PFBlockElement::ECAL: {
00343         reco::PFClusterRef clusterRef = elements[indexInBlock].clusterRef();
00344         sum_ecal += clusterRef->energy()/cosh(clusterRef->eta());
00345         break;
00346       }
00347         
00348       case PFBlockElement::HCAL: {
00349         reco::PFClusterRef clusterRef = elements[indexInBlock].clusterRef();
00350         sum_hcal += clusterRef->energy()/cosh(clusterRef->eta());
00351         break; 
00352       }       
00353       case PFBlockElement::TRACK: {
00354         //Do nothing since track are not normally linked to other tracks
00355         break; 
00356       }       
00357       default:
00358         break;
00359       }
00360       
00361       // We could also add in the PS, HO, ..
00362 
00363     } // end of elementsInBlocks()
00364   }  // end of isCandFound      
00365   
00366   
00367 
00368   return sum_ecal+sum_hcal;
00369   
00370 }
00371 
00372 void HICaloCompatibleTrackSelector::matchByDrAllowReuse(const reco::Track & trk, const edm::Handle<CaloTowerCollection> & towers, double & bestdr, double & bestpt)
00373 {
00374   // loop over towers
00375   bestdr=1e10;
00376   bestpt=0.;
00377   for(unsigned int i = 0; i < towers->size(); ++i){
00378     const CaloTower & tower= (*towers)[i];
00379     double pt = tower.pt();
00380     if (pt<towerPtMin_) continue;
00381     if (fabs(tower.eta())>trkEtaMax_) continue;
00382     double dr = reco::deltaR(tower,trk);
00383     if (dr<bestdr) {
00384       bestdr = dr;
00385       bestpt = pt;
00386     }
00387   }
00388 }