CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/RecoBTag/SoftLepton/plugins/SoftLepton.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:    SoftLepton
00004 // Class:      SoftLepton
00005 // 
00013 // Original Author:  fwyzard
00014 //         Created:  Wed Oct 18 18:02:07 CEST 2006
00015 // $Id: SoftLepton.cc,v 1.37 2010/08/19 23:14:52 fwyzard Exp $
00016 
00017 
00018 #include <memory>
00019 #include <string>
00020 #include <utility>
00021 #include <cmath>
00022 
00023 #include "FWCore/Framework/interface/Frameworkfwd.h"
00024 #include "FWCore/Framework/interface/EDProducer.h"
00025 #include "FWCore/Framework/interface/Event.h"
00026 #include "FWCore/Framework/interface/MakerMacros.h"
00027 #include "FWCore/Framework/interface/EventSetup.h"
00028 #include "FWCore/Framework/interface/ESHandle.h"
00029 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00030 #include "FWCore/Utilities/interface/EDMException.h"
00031 #include "DataFormats/Provenance/interface/ProductID.h"
00032 #include "DataFormats/Common/interface/RefToBase.h"
00033 #include "DataFormats/Common/interface/ValueMap.h"
00034 
00035 // ROOT::Math vectors (aka math::XYZVector)
00036 #include "DataFormats/Math/interface/LorentzVector.h"
00037 #include "DataFormats/Math/interface/Vector3D.h"
00038 #include "Math/GenVector/PxPyPzM4D.h"
00039 #include "Math/GenVector/VectorUtil.h"
00040 #include "Math/GenVector/Boost.h"
00041 
00042 #include "DataFormats/GeometryVector/interface/GlobalVector.h"
00043 #include "DataFormats/VertexReco/interface/Vertex.h"
00044 #include "DataFormats/VertexReco/interface/VertexFwd.h"
00045 #include "DataFormats/BeamSpot/interface/BeamSpot.h"
00046 #include "DataFormats/TrackReco/interface/Track.h"
00047 #include "DataFormats/MuonReco/interface/Muon.h"
00048 #include "DataFormats/MuonReco/interface/MuonFwd.h"
00049 #include "DataFormats/MuonReco/interface/MuonSelectors.h"
00050 #include "DataFormats/EgammaCandidates/interface/Electron.h"
00051 #include "DataFormats/EgammaCandidates/interface/ElectronFwd.h"
00052 #include "DataFormats/EgammaCandidates/interface/GsfElectron.h"
00053 #include "DataFormats/EgammaCandidates/interface/GsfElectronFwd.h"
00054 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
00055 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00056 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h"
00057 #include "DataFormats/JetReco/interface/Jet.h"
00058 #include "DataFormats/JetReco/interface/JetTracksAssociation.h"
00059 #include "DataFormats/BTauReco/interface/SoftLeptonTagInfo.h"
00060 
00061 #include "TrackingTools/TransientTrack/interface/TransientTrack.h"
00062 #include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
00063 #include "TrackingTools/Records/interface/TransientTrackRecord.h"
00064 #include "TrackingTools/IPTools/interface/IPTools.h"
00065 #include "SoftLepton.h"
00066 
00067 enum AxisType {
00068   AXIS_CALORIMETRIC             = 0,  // use the calorimietric jet axis
00069   AXIS_CHARGED_AVERAGE          = 1,  // refine jet axis using charged tracks: use a pT-weighted average of (eta, phi)
00070   AXIS_CHARGED_AVERAGE_NOLEPTON = 2,  // as above, without the tagging lepton track
00071   AXIS_CHARGED_SUM              = 3,  // refine jet axis using charged tracks: use the sum of tracks momentum
00072   AXIS_CHARGED_SUM_NOLEPTON     = 4,  // as above, without the tagging lepton track
00073   AXIS_CALORIMETRIC_NOLEPTON    = 5   // use the calorimetric jet axis minus the lepton momentum
00074 };
00075 
00076 using namespace std;
00077 using namespace edm;
00078 using namespace reco;
00079 using namespace ROOT::Math::VectorUtil;
00080 
00081 typedef edm::View<reco::GsfElectron> GsfElectronView;
00082 typedef edm::View<reco::Electron>    ElectronView;
00083 typedef edm::View<reco::Muon>        MuonView;
00084 
00085 // ------------ static copy of the nominal beamspot --------------------------------------
00086 const reco::Vertex SoftLepton::s_nominalBeamSpot(
00087   reco::Vertex::Point( 0, 0, 0 ),
00088   reco::Vertex::Error( ROOT::Math::SVector<double,6>( 0.0015 * 0.0015, //          0.0,        0.0
00089                                                                   0.0, 0.0015 * 0.0015, //     0.0  
00090                                                                   0.0,             0.0, 15. * 15. ) ),
00091   1, 1, 0 );
00092 
00093 // ------------ c'tor --------------------------------------------------------------------
00094 SoftLepton::SoftLepton(const edm::ParameterSet & iConfig) :
00095   m_jets(          iConfig.getParameter<edm::InputTag>( "jets" ) ),
00096   m_primaryVertex( iConfig.getParameter<edm::InputTag>( "primaryVertex" ) ),
00097   m_leptons(       iConfig.getParameter<edm::InputTag>( "leptons" ) ),
00098   m_leptonCands(   iConfig.exists("leptonCands") ? iConfig.getParameter<edm::InputTag>( "leptonCands" ) : edm::InputTag() ),
00099   m_leptonId(      iConfig.exists("leptonId") ? iConfig.getParameter<edm::InputTag>( "leptonId" ) : edm::InputTag() ),
00100   m_transientTrackBuilder( 0 ),
00101   m_refineJetAxis( iConfig.getParameter<unsigned int>( "refineJetAxis" ) ),
00102   m_deltaRCut(     iConfig.getParameter<double>( "leptonDeltaRCut" ) ),
00103   m_chi2Cut(       iConfig.getParameter<double>( "leptonChi2Cut" ) ),
00104   m_muonSelection( (muon::SelectionType) iConfig.getParameter<unsigned int>( "muonSelection" ) )
00105 {
00106   produces<reco::SoftLeptonTagInfoCollection>();
00107 }
00108 
00109 // ------------ d'tor --------------------------------------------------------------------
00110 SoftLepton::~SoftLepton(void) {
00111 }
00112 
00113 // ------------ method called once per event during the event loop -----------------------
00114 void
00115 SoftLepton::produce(edm::Event & event, const edm::EventSetup & setup) {
00116 
00117   // grab a TransientTrack helper from the Event Setup
00118   edm::ESHandle<TransientTrackBuilder> builder;
00119   setup.get<TransientTrackRecord>().get( "TransientTrackBuilder", builder );
00120   m_transientTrackBuilder = builder.product();
00121 
00122   // input objects
00123 
00124   // input jets (and possibly tracks)
00125   ProductID jets_id;
00126   std::vector<edm::RefToBase<reco::Jet> > jets;
00127   std::vector<reco::TrackRefVector>       tracks;
00128   do { {
00129     // look for a JetTracksAssociationCollection
00130     edm::Handle<reco::JetTracksAssociationCollection> h_jtas;
00131     event.getByLabel(m_jets, h_jtas);
00132     if (h_jtas.isValid()) {
00133       unsigned int size = h_jtas->size();
00134       jets.resize(size);
00135       tracks.resize(size);
00136       for (unsigned int i = 0; i < size; ++i) {
00137         jets[i]   = (*h_jtas)[i].first;
00138         tracks[i] = (*h_jtas)[i].second;
00139       }
00140       break;
00141     }
00142   } { // else...
00143     // look for a View<Jet>
00144     edm::Handle<edm::View<reco::Jet> > h_jets;
00145     event.getByLabel(m_jets, h_jets);
00146     if (h_jets.isValid()) {
00147       unsigned int size = h_jets->size();
00148       jets.resize(size);
00149       tracks.resize(size);
00150       for (unsigned int i = 0; i < h_jets->size(); i++)
00151         jets[i] = h_jets->refAt(i);
00152       break;
00153     }
00154   } { // else...
00155     throw edm::Exception(edm::errors::NotFound) << "Object " << m_jets << " of type among (\"reco::JetTracksAssociationCollection\", \"edm::View<reco::Jet>\") not found";
00156   } } while (false);
00157   
00158   // input primary vetex
00159   reco::Vertex vertex;
00160   Handle<reco::VertexCollection> h_primaryVertex;
00161   event.getByLabel(m_primaryVertex, h_primaryVertex);
00162   if (h_primaryVertex.isValid() and not h_primaryVertex->empty())
00163     vertex = h_primaryVertex->front();
00164   else
00165     // fall back to nominal beam spot
00166     vertex = s_nominalBeamSpot;
00167 
00168   // input leptons (can be of different types)
00169   Leptons leptons;
00170 
00171   Handle< ValueMap<float> > h_leptonCands;
00172   bool haveLeptonCands = !(m_leptonCands == edm::InputTag());
00173   if (haveLeptonCands)
00174     event.getByLabel(m_leptonCands, h_leptonCands);
00175 
00176   // try to access the input collection as a collection of GsfElectrons, Muons or Tracks
00177 
00178   unsigned int leptonId = SoftLeptonProperties::quality::leptonId;
00179   do { {
00180     // look for View<GsfElectron>
00181     Handle<GsfElectronView> h_electrons;
00182     event.getByLabel(m_leptons, h_electrons);
00183 
00184     if (h_electrons.isValid()) {
00185       leptonId = SoftLeptonProperties::quality::egammaElectronId;
00186       for (GsfElectronView::const_iterator electron = h_electrons->begin(); electron != h_electrons->end(); ++electron) {
00187         LeptonIds &id = leptons[reco::TrackBaseRef(electron->gsfTrack())];
00188         id[SoftLeptonProperties::quality::pfElectronId] = electron->mva();
00189         if (haveLeptonCands)
00190           id[SoftLeptonProperties::quality::btagElectronCands] = (*h_leptonCands)[h_electrons->refAt(electron - h_electrons->begin())];
00191       }
00192       break;
00193     }
00194   } { // else
00195     // look for View<Electron>
00196     // FIXME: is this obsolete?
00197     Handle<ElectronView> h_electrons;
00198     event.getByLabel(m_leptons, h_electrons);
00199     if (h_electrons.isValid()) {
00200       leptonId = SoftLeptonProperties::quality::egammaElectronId;
00201       for (ElectronView::const_iterator electron = h_electrons->begin(); electron != h_electrons->end(); ++electron) {
00202         LeptonIds &id = leptons[reco::TrackBaseRef(electron->track())];
00203         if (haveLeptonCands)
00204           id[SoftLeptonProperties::quality::btagElectronCands] = (*h_leptonCands)[h_electrons->refAt(electron - h_electrons->begin())];
00205       }
00206       break;
00207     }
00208   } { // else
00209     // look for PFElectrons
00210     // FIXME: is this obsolete?
00211     Handle<reco::PFCandidateCollection> h_electrons;
00212     event.getByLabel(m_leptons, h_electrons);
00213     if (h_electrons.isValid()) {
00214       leptonId = SoftLeptonProperties::quality::egammaElectronId;
00215       for (reco::PFCandidateCollection::const_iterator electron = h_electrons->begin(); electron != h_electrons->end(); ++electron) {
00216         LeptonIds *id;
00217         if (electron->gsfTrackRef().isNonnull())
00218           id = &leptons[reco::TrackBaseRef(electron->gsfTrackRef())];
00219         else if (electron->trackRef().isNonnull())
00220           id = &leptons[reco::TrackBaseRef(electron->trackRef())];
00221         else
00222           continue;
00223         (*id)[SoftLeptonProperties::quality::pfElectronId] = electron->mva_e_pi();
00224         if (haveLeptonCands)
00225           (*id)[SoftLeptonProperties::quality::btagElectronCands] = (*h_leptonCands)[reco::PFCandidateRef(h_electrons, electron - h_electrons->begin())];
00226       }
00227       break;
00228     }
00229   } { // else
00230     // look for View<Muon>
00231     Handle<MuonView> h_muons;
00232     event.getByLabel(m_leptons, h_muons);
00233     if (h_muons.isValid()) {
00234       for (MuonView::const_iterator muon = h_muons->begin(); muon != h_muons->end(); ++muon) {
00235         // FIXME -> turn this selection into a muonCands input?
00236         if (muon::isGoodMuon( *muon, m_muonSelection )) {
00237           LeptonIds *id;
00238           if (muon->globalTrack().isNonnull())
00239             id = &leptons[reco::TrackBaseRef(muon->globalTrack())];
00240           else if (muon->innerTrack().isNonnull())
00241             id = &leptons[reco::TrackBaseRef(muon->innerTrack())];
00242           else if (muon->outerTrack().isNonnull())
00243             // does this makes sense ?
00244             id = &leptons[reco::TrackBaseRef(muon->outerTrack())];
00245           else
00246             continue;
00247           if (haveLeptonCands)
00248             (*id)[SoftLeptonProperties::quality::btagMuonCands] = (*h_leptonCands)[h_muons->refAt(muon - h_muons->begin())];
00249         }
00250       }
00251       break;
00252     }
00253   } { // else
00254     // look for edm::View<Track> 
00255     Handle<edm::View<reco::Track> > h_tracks;
00256     event.getByLabel(m_leptons, h_tracks);
00257     if (h_tracks.isValid()) {
00258       for (unsigned int i = 0; i < h_tracks->size(); i++) {
00259         LeptonIds &id = leptons[h_tracks->refAt(i)];
00260         if (haveLeptonCands)
00261           id[SoftLeptonProperties::quality::btagLeptonCands] = (*h_leptonCands)[h_tracks->refAt(i)];
00262       }
00263       break;
00264     }
00265   } { // else
00266     throw edm::Exception(edm::errors::NotFound) << "Object " << m_leptons << " of type among (\"edm::View<reco::GsfElectron>\", \"edm::View<reco::Muon>\", \"edm::View<reco::Track>\") !found";
00267   } } while (false);
00268 
00269   if (!(m_leptonId == edm::InputTag())) {
00270     Handle< ValueMap<float> > h_leptonId;
00271     event.getByLabel(m_leptonId, h_leptonId);
00272 
00273     for (Leptons::iterator lepton = leptons.begin(); lepton != leptons.end(); ++lepton)
00274       lepton->second[leptonId] = (*h_leptonId)[lepton->first];
00275   }
00276 
00277   // output collections
00278   std::auto_ptr<reco::SoftLeptonTagInfoCollection> outputCollection(  new reco::SoftLeptonTagInfoCollection() );
00279   for (unsigned int i = 0; i < jets.size(); ++i) {
00280     reco::SoftLeptonTagInfo result = tag( jets[i], tracks[i], leptons, vertex );
00281     outputCollection->push_back( result );
00282   }
00283   event.put( outputCollection );
00284 }
00285 
00286 // ---------------------------------------------------------------------------------------
00287 reco::SoftLeptonTagInfo SoftLepton::tag (
00288     const edm::RefToBase<reco::Jet> & jet,
00289     const reco::TrackRefVector      & tracks,
00290     const Leptons                   & leptons,
00291     const reco::Vertex              & primaryVertex
00292 ) const {
00293   reco::SoftLeptonTagInfo info;
00294   info.setJetRef( jet );
00295 
00296   for(Leptons::const_iterator lepton = leptons.begin(); lepton != leptons.end(); ++lepton) {
00297     const math::XYZVector & lepton_momentum = lepton->first->momentum();
00298     if (m_chi2Cut > 0.0 && lepton->first->normalizedChi2() > m_chi2Cut)
00299       continue;
00300 
00301     const GlobalVector jetAxis = refineJetAxis( jet, tracks, lepton->first );
00302     const math::XYZVector axis( jetAxis.x(), jetAxis.y(), jetAxis.z());
00303     if (DeltaR(lepton_momentum, axis) > m_deltaRCut)
00304       continue;
00305 
00306     reco::SoftLeptonProperties properties;
00307 
00308     reco::TransientTrack transientTrack = m_transientTrackBuilder->build(*lepton->first);
00309     properties.sip2d    = IPTools::signedTransverseImpactParameter( transientTrack, jetAxis, primaryVertex ).second.significance();
00310     properties.sip3d    = IPTools::signedImpactParameter3D( transientTrack, jetAxis, primaryVertex ).second.significance();
00311     properties.deltaR   = DeltaR( lepton_momentum, axis );
00312     properties.ptRel    = Perp( lepton_momentum, axis );
00313     properties.p0Par    = boostedPPar( lepton_momentum, axis );
00314     properties.etaRel   = relativeEta( lepton_momentum, axis );
00315     properties.ratio    = lepton_momentum.R() / axis.R();
00316     properties.ratioRel = lepton_momentum.Dot(axis) / axis.Mag2();
00317  
00318     for(LeptonIds::const_iterator iter = lepton->second.begin(); iter != lepton->second.end(); ++iter)
00319       properties.setQuality(static_cast<SoftLeptonProperties::quality::Generic>(iter->first), iter->second);
00320 
00321     info.insert( lepton->first, properties );
00322   }
00323 
00324   return info;
00325 }
00326 
00327 
00328 // ---------------------------------------------------------------------------------------
00329 GlobalVector SoftLepton::refineJetAxis (
00330     const edm::RefToBase<reco::Jet>   & jet,
00331     const reco::TrackRefVector        & tracks,
00332     const reco::TrackBaseRef & exclude /* = reco::TrackBaseRef() */
00333 ) const {
00334   math::XYZVector axis = jet->momentum();
00335 
00336   if (m_refineJetAxis == AXIS_CHARGED_AVERAGE or
00337       m_refineJetAxis == AXIS_CHARGED_AVERAGE_NOLEPTON) {
00338 
00339     double sum_pT        = 0.;
00340     double sum_eta_by_pT = 0.;
00341     double sum_phi_by_pT = 0.;
00342 
00343     double perp;
00344     double phi_rel;
00345     double eta_rel;
00346 
00347     // refine jet eta and phi with charged tracks measurements, if available
00348     for (reco::TrackRefVector::const_iterator track_it = tracks.begin(); track_it != tracks.end(); ++track_it ) {
00349       const reco::Track & track = **track_it;
00350 
00351       perp = track.pt();
00352       eta_rel = (double) track.eta() - axis.eta();
00353       phi_rel = (double) track.phi() - axis.phi();
00354       while (phi_rel < -M_PI) phi_rel += 2*M_PI;
00355       while (phi_rel >  M_PI) phi_rel -= 2*M_PI;
00356 
00357       sum_pT        += perp;
00358       sum_phi_by_pT += perp * phi_rel;
00359       sum_eta_by_pT += perp * eta_rel;
00360     }
00361 
00362     // "remove" excluded track
00363     if (m_refineJetAxis == AXIS_CHARGED_AVERAGE_NOLEPTON and exclude.isNonnull()) {
00364       const reco::Track & track = *exclude;
00365 
00366       perp = track.pt();
00367       eta_rel = (double) track.eta() - axis.eta();
00368       phi_rel = (double) track.phi() - axis.phi();
00369       while (phi_rel < -M_PI) phi_rel += 2*M_PI;
00370       while (phi_rel >  M_PI) phi_rel -= 2*M_PI;
00371 
00372       sum_pT        -= perp;
00373       sum_phi_by_pT -= perp * phi_rel;
00374       sum_eta_by_pT -= perp * eta_rel;
00375     }
00376 
00377     if (sum_pT > 1.)    // avoid the case of only the lepton-track with small rounding errors
00378       axis = math::RhoEtaPhiVector( axis.rho(), axis.eta() + sum_eta_by_pT / sum_pT, axis.phi() + sum_phi_by_pT / sum_pT);
00379     
00380   } else if (m_refineJetAxis == AXIS_CHARGED_SUM or
00381              m_refineJetAxis == AXIS_CHARGED_SUM_NOLEPTON) {
00382     math::XYZVector sum;
00383 
00384     // recalculate the jet direction as the sum of charget tracks momenta
00385     for (reco::TrackRefVector::const_iterator track_it = tracks.begin(); track_it != tracks.end(); ++track_it ) {
00386       const reco::Track & track = **track_it;
00387       sum += track.momentum();
00388     }
00389 
00390     // "remove" excluded track
00391     if (m_refineJetAxis == AXIS_CHARGED_SUM_NOLEPTON and exclude.isNonnull()) {
00392       const reco::Track & track = *exclude;
00393       sum -= track.momentum();
00394     }
00395 
00396     if (sum.R() > 1.) // avoid the case of only the lepton-track with small rounding errors
00397       axis = sum;
00398   } else if(m_refineJetAxis == AXIS_CALORIMETRIC_NOLEPTON) {
00399     axis -= exclude->momentum();
00400   }
00401   
00402   return GlobalVector(axis.x(), axis.y(), axis.z());
00403 }
00404 
00405 double SoftLepton::relativeEta(const math::XYZVector& vector, const math::XYZVector& axis) {
00406   double mag = vector.r() * axis.r();
00407   double dot = vector.Dot(axis); 
00408   return -log((mag - dot)/(mag + dot)) / 2;
00409 }
00410 
00411 // compute the lepton momentum along the jet axis, in the jet rest frame
00412 double SoftLepton::boostedPPar(const math::XYZVector& vector, const math::XYZVector& axis) {
00413   static const double lepton_mass = 0.00;       // assume a massless (ultrarelativistic) lepton
00414   static const double jet_mass    = 5.279;      // use B±/B0 mass as the jet rest mass [PDG 2007 updates]
00415   ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> > lepton(vector.Dot(axis) / axis.r(), Perp(vector, axis), 0., lepton_mass);
00416   ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> > jet( axis.r(), 0., 0., jet_mass );
00417   ROOT::Math::BoostX boost( -jet.Beta() );
00418   return boost(lepton).x();
00419 }