diff --git a/DataFormats/VertexReco/BuildFile.xml b/DataFormats/VertexReco/BuildFile.xml index a8c7cac35828d..6f868dcc00bcf 100644 --- a/DataFormats/VertexReco/BuildFile.xml +++ b/DataFormats/VertexReco/BuildFile.xml @@ -1,6 +1,7 @@ - + + diff --git a/DataFormats/VertexReco/interface/TrackTimeLifeInfo.h b/DataFormats/VertexReco/interface/TrackTimeLifeInfo.h new file mode 100644 index 0000000000000..71f69ad4d41fe --- /dev/null +++ b/DataFormats/VertexReco/interface/TrackTimeLifeInfo.h @@ -0,0 +1,81 @@ +#ifndef DataFormats_VertexReco_TrackTimeLifeInfo_h +#define DataFormats_VertexReco_TrackTimeLifeInfo_h + +/** + \class TrackTimeLifeInfo + \brief Structure to hold time-life information + + \author Michal Bluj, NCBJ, Warsaw +*/ + +#include "DataFormats/GeometryCommonDetAlgo/interface/GlobalError.h" +#include "DataFormats/GeometryCommonDetAlgo/interface/Measurement1D.h" +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "DataFormats/GeometryVector/interface/GlobalVector.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/VertexReco/interface/Vertex.h" + +class TrackTimeLifeInfo { +public: + TrackTimeLifeInfo(); + ~TrackTimeLifeInfo() {} + + // Secondary vertex + void setSV(reco::Vertex sv) { + sv_ = sv; + hasSV_ = true; + } + const reco::Vertex& sv() const { return sv_; } + bool hasSV() const { return hasSV_; } + void setFlightVector(GlobalVector flight_vec, GlobalError flight_cov) { + flight_vec_ = flight_vec; + flight_cov_ = flight_cov; + } + // Flight-path + const GlobalVector& flightVector() const { return flight_vec_; } + const GlobalError& flightCovariance() const { return flight_cov_; } + void setFlightLength(Measurement1D flightLength) { flightLength_ = flightLength; } + const Measurement1D& flightLength() const { return flightLength_; } + // Point of closest approach + void setPCA(GlobalPoint pca, GlobalError pca_cov) { + pca_ = pca; + pca_cov_ = pca_cov; + } + const GlobalPoint& pca() const { return pca_; } + const GlobalError& pcaCovariance() const { return pca_cov_; } + // Impact parameter + void setIP(GlobalVector ip_vec, GlobalError ip_cov) { + ip_vec_ = ip_vec; + ip_cov_ = ip_cov; + } + const GlobalVector& ipVector() const { return ip_vec_; } + const GlobalError& ipCovariance() const { return ip_cov_; } + void setIPLength(Measurement1D ipLength) { ipLength_ = ipLength; } + const Measurement1D& ipLength() const { return ipLength_; } + // Track + void setTrack(const reco::Track* track) { + if (track != nullptr) { + track_ = *track; + hasTrack_ = true; + } else { + track_ = reco::Track(); + hasTrack_ = false; + } + } + const reco::Track* track() const { return &track_; } + bool hasTrack() const { return hasTrack_; } + void setBField_z(float bField_z) { bField_z_ = bField_z; } + float bField_z() const { return bField_z_; } + +private: + bool hasSV_, hasTrack_; + reco::Vertex sv_; + GlobalVector flight_vec_, ip_vec_; + GlobalPoint pca_; + GlobalError flight_cov_, pca_cov_, ip_cov_; + Measurement1D flightLength_, ipLength_; + reco::Track track_; + float bField_z_; +}; + +#endif diff --git a/DataFormats/VertexReco/src/TrackTimeLifeInfo.cc b/DataFormats/VertexReco/src/TrackTimeLifeInfo.cc new file mode 100644 index 0000000000000..75228227dae21 --- /dev/null +++ b/DataFormats/VertexReco/src/TrackTimeLifeInfo.cc @@ -0,0 +1,16 @@ +#include "DataFormats/VertexReco/interface/TrackTimeLifeInfo.h" + +TrackTimeLifeInfo::TrackTimeLifeInfo() + : hasSV_(false), + hasTrack_(false), + sv_(reco::Vertex()), + flight_vec_(GlobalVector()), + ip_vec_(GlobalVector()), + pca_(GlobalPoint()), + flight_cov_(GlobalError()), + pca_cov_(GlobalError()), + ip_cov_(GlobalError()), + flightLength_(Measurement1D()), + ipLength_(Measurement1D()), + track_(reco::Track()), + bField_z_(0.){}; diff --git a/DataFormats/VertexReco/src/classes.h b/DataFormats/VertexReco/src/classes.h index 9260d5d86d8c4..6a807d89b9434 100644 --- a/DataFormats/VertexReco/src/classes.h +++ b/DataFormats/VertexReco/src/classes.h @@ -15,5 +15,7 @@ #include "DataFormats/TrackReco/interface/Track.h" #include "DataFormats/TrackReco/interface/TrackFwd.h" +#include "DataFormats/VertexReco/interface/TrackTimeLifeInfo.h" + #include #include diff --git a/DataFormats/VertexReco/src/classes_def.xml b/DataFormats/VertexReco/src/classes_def.xml index fe68ada1742fe..f20693ec82af6 100755 --- a/DataFormats/VertexReco/src/classes_def.xml +++ b/DataFormats/VertexReco/src/classes_def.xml @@ -48,4 +48,9 @@ + + + + + diff --git a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h index 2e5c20452f8e0..a544f4b484d56 100644 --- a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h +++ b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h @@ -101,7 +101,7 @@ class ValueMapVariableBase : public ExtVariable { if (vmap.isValid() || !skipNonExistingSrc_) { vals.resize(selptrs.size()); for (unsigned int i = 0, n = vals.size(); i < n; ++i) { - // calls the overloade method to either get the valuemap value directly, or a function of the object value. + // calls the overloaded method to either get the valuemap value directly, or a function of the object value. vals[i] = this->eval(vmap, selptrs[i]); } } @@ -121,7 +121,7 @@ class ValueMapVariable : public ValueMapVariableBase { edm::ConsumesCollector &&cc, bool skipNonExistingSrc = false) : ValueMapVariableBase(aname, cfg, std::move(cc), skipNonExistingSrc) {} - ValType eval(const edm::Handle> &vmap, const edm::Ptr &op) const { + ValType eval(const edm::Handle> &vmap, const edm::Ptr &op) const override { ValType val = (*vmap)[op]; return val; } @@ -139,7 +139,7 @@ class TypedValueMapVariable : public ValueMapVariableBase precisionFunc_(cfg.existsAs("precision") ? cfg.getParameter("precision") : "23", true) {} - ValType eval(const edm::Handle> &vmap, const edm::Ptr &op) const { + ValType eval(const edm::Handle> &vmap, const edm::Ptr &op) const override { ValType val = func_((*vmap)[op]); if constexpr (std::is_same()) { if (this->precision_ == -2) { @@ -333,7 +333,7 @@ class SimpleFlatTableProducer : public SimpleFlatTableProducerBase("precision", true, edm::Comment("the precision with which to store the value in the " - "flat table, as a fucntion of the object evaluated")), + "flat table, as a function of the object evaluated")), false); edm::ParameterSetDescription extvariables; @@ -452,7 +452,7 @@ class SimpleTypedExternalFlatTableProducer : public SimpleFlatTableProducer { edm::ParameterDescription("precision", true, edm::Comment("the precision with which to store the value in the " - "flat table, as a fucntion of the object evaluated")), + "flat table, as a function of the object evaluated")), false); edm::ParameterSetDescription extvariables; @@ -577,7 +577,7 @@ class FirstObjectSimpleFlatTableProducer : public SimpleFlatTableProducerBase>::baseDescriptions(); + edm::ParameterSetDescription desc = SimpleFlatTableProducerBase>::baseDescriptions(); descriptions.addWithDefaultLabel(desc); } diff --git a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc index 27dbb6487a9b8..8217d13f32bab 100644 --- a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc +++ b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc @@ -60,6 +60,13 @@ typedef SimpleFlatTableProducer SimpleRun3ScoutingElectron #include "DataFormats/Scouting/interface/Run3ScoutingTrack.h" typedef SimpleFlatTableProducer SimpleRun3ScoutingTrackFlatTableProducer; +#include "DataFormats/VertexReco/interface/Vertex.h" +typedef SimpleFlatTableProducer SimpleVertexFlatTableProducer; + +#include "DataFormats/VertexReco/interface/TrackTimeLifeInfo.h" +typedef SimpleTypedExternalFlatTableProducer + SimpleCandidate2TrackTimeLifeInfoFlatTableProducer; + #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(SimpleCandidateFlatTableProducer); DEFINE_FWK_MODULE(SimpleCandidate2CandidateFlatTableProducer); @@ -81,3 +88,5 @@ DEFINE_FWK_MODULE(SimpleRun3ScoutingPhotonFlatTableProducer); DEFINE_FWK_MODULE(SimpleRun3ScoutingMuonFlatTableProducer); DEFINE_FWK_MODULE(SimpleRun3ScoutingElectronFlatTableProducer); DEFINE_FWK_MODULE(SimpleRun3ScoutingTrackFlatTableProducer); +DEFINE_FWK_MODULE(SimpleVertexFlatTableProducer); +DEFINE_FWK_MODULE(SimpleCandidate2TrackTimeLifeInfoFlatTableProducer); diff --git a/PhysicsTools/NanoAOD/python/autoNANO.py b/PhysicsTools/NanoAOD/python/autoNANO.py index 358aa6bb440ff..3938f157e2540 100644 --- a/PhysicsTools/NanoAOD/python/autoNANO.py +++ b/PhysicsTools/NanoAOD/python/autoNANO.py @@ -35,5 +35,8 @@ def expandNanoMapping(seqList, mapping, key): 'customize': 'DPGAnalysis/MuonTools/muNtupleProducerBkg_cff.muDPGNanoBkgCustomize'}, # PromptReco config: PHYS+L1 'Prompt' : {'sequence': '@PHYS', - 'customize': '@PHYS+@L1'} + 'customize': '@PHYS+@L1'}, + # Add lepton time-life info tables through customize combined with PHYS + 'LepTimeLife' : {'sequence': '@PHYS', + 'customize': '@PHYS+PhysicsTools/NanoAOD/leptonTimeLifeInfo_common_cff.addTimeLifeInfo'}, } diff --git a/PhysicsTools/NanoAOD/python/leptonTimeLifeInfo_common_cff.py b/PhysicsTools/NanoAOD/python/leptonTimeLifeInfo_common_cff.py new file mode 100644 index 0000000000000..e8001da6fbab7 --- /dev/null +++ b/PhysicsTools/NanoAOD/python/leptonTimeLifeInfo_common_cff.py @@ -0,0 +1,268 @@ +# +# Common definition of time-life variables for pat-leptons produced +# with {Electron,Muon,Tau}TimeLifeInfoTableProducer +# +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import * +from PhysicsTools.NanoAOD.nano_eras_cff import * +from PhysicsTools.PatAlgos.patRefitVertexProducer_cfi import patRefitVertexProducer +from PhysicsTools.NanoAOD.simpleVertexFlatTableProducer_cfi import simpleVertexFlatTableProducer +from PhysicsTools.PatAlgos.patElectronTimeLifeInfoProducer_cfi import patElectronTimeLifeInfoProducer +from PhysicsTools.PatAlgos.patMuonTimeLifeInfoProducer_cfi import patMuonTimeLifeInfoProducer +from PhysicsTools.PatAlgos.patTauTimeLifeInfoProducer_cfi import patTauTimeLifeInfoProducer +from PhysicsTools.NanoAOD.simpleCandidate2TrackTimeLifeInfoFlatTableProducer_cfi import simpleCandidate2TrackTimeLifeInfoFlatTableProducer +from TrackingTools.TransientTrack.TransientTrackBuilder_cfi import * +from PhysicsTools.NanoAOD.nanoDQM_tools_cff import * + +# common settings of lepton life-time info producer +prod_common = cms.PSet( + pvSource = cms.InputTag("offlineSlimmedPrimaryVerticesWithBS"), + pvChoice = cms.int32(0) #0: PV[0], 1: smallest dz +) + +# impact parameter +ipVars = cms.PSet( + ipLength = Var("ipLength().value()", float, doc="lenght of impact parameter (3d)", precision=10), + ipLengthSig = Var("ipLength().significance()", float, doc="significance of impact parameter", precision=10), + IPx = Var("ipVector().x()", float, doc="x coordinate of impact parameter vector", precision=10), + IPy = Var("ipVector().y()", float, doc="y coordinate of impact parameter vector", precision=10), + IPz = Var("ipVector().z()", float, doc="z coordinate of impact parameter vector", precision=10) +) + +# track parameters and covariance at ref. point +trackVars = cms.PSet( + track_qoverp = Var("?hasTrack()?track().parameter(0):0", float, doc="track q/p", precision=10), + track_lambda = Var("?hasTrack()?track().parameter(1):0", float, doc="track lambda", precision=10), + track_phi = Var("?hasTrack()?track().parameter(2):0", float, doc="track phi", precision=10), + #track_deltaPhi = Var("?hasTrack()?deltaPhi(track().parameter(2), phi):0", float, doc="track phi minus lepton phi", precision=10), + track_dxy = Var("?hasTrack()?track().parameter(3):0", float, doc="track dxy", precision=10), + track_dsz = Var("?hasTrack()?track().parameter(4):0", float, doc="track dsz", precision=10), + bField_z = Var("?hasTrack()?bField_z:0", float, doc="z coordinate of magnetic field at track ref. point", precision=10), +) +# track covariance elements (adding to trackVars) +for i in range(0,5): + for j in range(i,5): + jistr = str(j)+str(i) + setattr(trackVars, 'track_cov'+jistr, Var("?hasTrack()?track().covariance("+str(j)+","+str(i)+"):0", float, doc="track covariance element ("+str(j)+","+str(i)+")", precision=10)) + +# secondary vertex +svVars = cms.PSet( + # SV + hasRefitSV = Var("hasSV()", bool, doc="has SV refit using miniAOD quantities"), + refitSVx = Var("?hasSV()?sv().x():0", float, doc="x coordinate of SV", precision=10), + refitSVy = Var("?hasSV()?sv().y():0", float, doc="y coordinate of SV", precision=10), + refitSVz = Var("?hasSV()?sv().z():0", float, doc="z coordinate of SV", precision=10), + refitSVchi2 = Var("?hasSV()?sv().chi2():0", float, doc="chi2 of SV fit", precision=8), + refitSVndof = Var("?hasSV()?sv().ndof():0", float, doc="ndof of SV fit", precision=8), + # flight-length + #refitFlightLength = Var("?hasSV()?flightLength().value():0", float, doc="flight-length,i.e. the PV to SV distance", precision=10), + #refitFlightLengthSig = Var("?hasSV()?flightLength().significance():0", float, doc="Significance of flight-length", precision=10) +) +# secondary vertex covariance elements (adding to svVars) +for i in range(0,3): + for j in range(i,3): + jistr = str(j)+str(i) + setattr(svVars, 'refitSVcov'+jistr, Var("?hasSV()?sv().covariance("+str(j)+","+str(i)+"):0", float, doc="Covariance of SV ("+str(j)+","+str(i)+")", precision=10)) + +# primary vertex covariance elements +pvCovVars = cms.PSet() +for i in range(0,3): + for j in range(i,3): + jistr = str(j)+str(i) + setattr(pvCovVars, 'cov'+jistr, Var("covariance("+str(j)+","+str(i)+")", float, doc="vertex covariance ("+str(j)+","+str(i)+")", precision=10)) + +# Module to refit PV with beam-spot constraint that is not present in Run-2 samples +refittedPV = patRefitVertexProducer.clone( + srcVertices = "offlineSlimmedPrimaryVertices", +) +run2_nanoAOD_ANY.toModify( + prod_common, pvSource = "refittedPV") + +# Definition of DQM plots +ipVarsPlots = cms.VPSet( + Plot1D('ipLength', 'ipLength', 25, -0.25, 0.25, 'signed lenght of impact parameter (3d)'), + Plot1D('ipLengthSig', 'ipLengthSig', 60, -5, 10, 'signed significance of impact parameter'), + Plot1D('IPx', 'IPx', 40, -0.02, 0.02, 'x coordinate of impact parameter vector'), + Plot1D('IPy', 'IPy', 40, -0.02, 0.02, 'y coordinate of impact parameter vector'), + Plot1D('IPz', 'IPz', 40, -0.02, 0.02, 'z coordinate of impact parameter vector') +) +trackVarsPlots = cms.VPSet( + Plot1D('track_qoverp', 'track_qoverp', 40, -0.2, 0.2, 'track q/p'), + Plot1D('track_lambda', 'track_lambda', 30, -1.5, 1.5, 'track lambda'), + Plot1D('track_phi', 'track_phi', 20, -3.14159, 3.14159, 'track phi'), + Plot1D('track_dxy', 'track_dxy', 20, -0.1, 0.1, 'track dxy'), + Plot1D('track_dsz', 'track_dsz', 20, -10, 10, 'track dsz'), + NoPlot('bField_z') +) +#no plots for track covariance elements, but store placeholders +for i in range(0,5): + for j in range(i,5): + trackVarsPlots.append(NoPlot('track_cov'+str(j)+str(i))) +svVarsPlots = cms.VPSet( + Plot1D('hasRefitSV', 'hasRefitSV', 2, 0, 2, 'has SV refit using miniAOD quantities'), + Plot1D('refitSVx', 'refitSVx', 20, -0.1, 0.1, 'x coordinate of refitted SV'), + Plot1D('refitSVy', 'refitSVy', 20, -0.1, 0.1, 'y coordinate of refitted SV'), + Plot1D('refitSVz', 'refitSVz', 20, -20, 20, 'z coordinate of refitted SV'), + Plot1D('refitSVchi2', 'refitSVchi2', 20, 0, 100, 'chi2 of SV fit'), + Plot1D('refitSVndof', 'refitSVndof', 10, 0, 10, 'ndof of SV fit') +) +#no plots for SV covariance elements, but store placeholders +for i in range(0,3): + for j in range(i,3): + svVarsPlots.append(NoPlot('refitSVcov'+str(j)+str(i))) + +# +# Customization sequences and functions +# +# electrons +electronVars = cms.PSet( + ipVars, + trackVars +) +for var in electronVars.parameters_(): + setattr(getattr(electronVars, var), "src", cms.InputTag("electronTimeLifeInfos")) +def addTimeLifeInfoToElectrons(process): + process.electronTimeLifeInfos = patElectronTimeLifeInfoProducer.clone( + src = process.electronTable.src, + selection = 'pt > 15', + pvSource = prod_common.pvSource, + pvChoice = prod_common.pvChoice + ) + process.electronTimeLifeInfoTable = simpleCandidate2TrackTimeLifeInfoFlatTableProducer.clone( + name = process.electronTable.name, + src = process.electronTable.src, + doc = cms.string("Additional time-life info for non-prompt electrons"), + extension = True, + externalTypedVariables = electronVars + ) + process.electronTimeLifeInfoTask = cms.Task( + process.electronTimeLifeInfos, + process.electronTimeLifeInfoTable + ) + # refit PV with beam-spot constraint that is not present in Run-2 samples + if not hasattr(process,'refittedPV'): + setattr(process,'refittedPV',refittedPV) + _electronTimeLifeInfoTaskRun2 = process.electronTimeLifeInfoTask.copy() + _electronTimeLifeInfoTaskRun2.add(process.refittedPV) + run2_nanoAOD_ANY.toReplaceWith(process.electronTimeLifeInfoTask, + _electronTimeLifeInfoTaskRun2) + process.electronTablesTask.add(process.electronTimeLifeInfoTask) + # add DQM plots if needed + if hasattr(process,'nanoDQM'): + process.nanoDQM.vplots.Electron.plots.extend(ipVarsPlots) + process.nanoDQM.vplots.Electron.plots.extend(trackVarsPlots) + return process + +# muons +muonVars = cms.PSet( + ipVars, + trackVars +) +for var in muonVars.parameters_(): + setattr(getattr(muonVars, var), "src", cms.InputTag("muonTimeLifeInfos")) +def addTimeLifeInfoToMuons(process): + process.muonTimeLifeInfos = patMuonTimeLifeInfoProducer.clone( + src = process.muonTable.src, + selection = 'pt > 15', + pvSource = prod_common.pvSource, + pvChoice = prod_common.pvChoice + ) + process.muonTimeLifeInfoTable = simpleCandidate2TrackTimeLifeInfoFlatTableProducer.clone( + name = process.muonTable.name, + src = process.muonTable.src, + doc = cms.string("Additional time-life info for non-prompt muon"), + extension = True, + externalTypedVariables = muonVars + ) + process.muonTimeLifeInfoTask = cms.Task( + process.muonTimeLifeInfos, + process.muonTimeLifeInfoTable + ) + # refit PV with beam-spot constraint that is not present in Run-2 samples + if not hasattr(process,'refittedPV'): + setattr(process,'refittedPV',refittedPV) + _muonTimeLifeInfoTaskRun2 = process.muonTimeLifeInfoTask.copy() + _muonTimeLifeInfoTaskRun2.add(process.refittedPV) + run2_nanoAOD_ANY.toReplaceWith(process.muonTimeLifeInfoTask, + _muonTimeLifeInfoTaskRun2) + process.muonTablesTask.add(process.muonTimeLifeInfoTask) + # add DQM plots if needed + if hasattr(process,'nanoDQM'): + process.nanoDQM.vplots.Muon.plots.extend(ipVarsPlots) + process.nanoDQM.vplots.Muon.plots.extend(trackVarsPlots) + return process + +# taus +tauVars = cms.PSet( + svVars, + ipVars, + trackVars +) +for var in tauVars.parameters_(): + setattr(getattr(tauVars, var), "src", cms.InputTag("tauTimeLifeInfos")) +def addTimeLifeInfoToTaus(process): + process.tauTimeLifeInfos = patTauTimeLifeInfoProducer.clone( + src = process.tauTable.src, + pvSource = prod_common.pvSource, + pvChoice = prod_common.pvChoice + ) + process.tauTimeLifeInfoTable = simpleCandidate2TrackTimeLifeInfoFlatTableProducer.clone( + name = process.tauTable.name, + src = process.tauTable.src, + doc = cms.string("Additional tau time-life info"), + extension = True, + externalTypedVariables = tauVars + ) + process.tauTimeLifeInfoTask = cms.Task( + process.tauTimeLifeInfos, + process.tauTimeLifeInfoTable + ) + # refit PV with beam-spot constraint that is not present in Run-2 samples + if not hasattr(process,'refittedPV'): + setattr(process,'refittedPV',refittedPV) + _tauTimeLifeInfoTaskRun2 = process.tauTimeLifeInfoTask.copy() + _tauTimeLifeInfoTaskRun2.add(process.refittedPV) + run2_nanoAOD_ANY.toReplaceWith(process.tauTimeLifeInfoTask, + _tauTimeLifeInfoTaskRun2) + process.tauTablesTask.add(process.tauTimeLifeInfoTask) + # add DQM plots if needed + if hasattr(process,'nanoDQM'): + process.nanoDQM.vplots.Tau.plots.extend(ipVarsPlots) + process.nanoDQM.vplots.Tau.plots.extend(trackVarsPlots) + process.nanoDQM.vplots.Tau.plots.extend(svVarsPlots) + return process + +# Vertices +def addExtendVertexInfo(process): + process.pvbsTable = simpleVertexFlatTableProducer.clone( + src = prod_common.pvSource, + name = "PVBS", + doc = "main primary vertex with beam-spot", + maxLen = 1, + variables = cms.PSet( + pvCovVars, + x = Var("position().x()", float, doc = "position x coordinate, in cm", precision = 10), + y = Var("position().y()", float, doc = "position y coordinate, in cm", precision = 10), + z = Var("position().z()", float, doc = "position z coordinate, in cm", precision = 16), + ndof = Var("ndof()", float, doc = "number of degrees of freedom", precision = 8), + chi2 = Var("normalizedChi2()", float, doc = "reduced chi2, i.e. chi2/ndof", precision = 8), + ), + ) + process.pvbsTableTask = cms.Task(process.pvbsTable) + # refit PV with beam-spot constraint that is not present in Run-2 samples + if not hasattr(process,'refittedPV'): + setattr(process,'refittedPV',refittedPV) + _pvbsTableTaskRun2 = process.pvbsTableTask.copy() + _pvbsTableTaskRun2.add(process.refittedPV) + run2_nanoAOD_ANY.toReplaceWith(process.pvbsTableTask, + _pvbsTableTaskRun2) + process.vertexTablesTask.add(process.pvbsTableTask) + return process + +# Full +def addTimeLifeInfo(process): + addTimeLifeInfoToElectrons(process) + addTimeLifeInfoToMuons(process) + addTimeLifeInfoToTaus(process) + addExtendVertexInfo(process) + return process diff --git a/PhysicsTools/NanoAOD/python/taus_cff.py b/PhysicsTools/NanoAOD/python/taus_cff.py index 71ef53ad63ebf..d9586ed72a404 100644 --- a/PhysicsTools/NanoAOD/python/taus_cff.py +++ b/PhysicsTools/NanoAOD/python/taus_cff.py @@ -6,6 +6,8 @@ from PhysicsTools.JetMCAlgos.TauGenJets_cfi import tauGenJets from PhysicsTools.JetMCAlgos.TauGenJetsDecayModeSelectorAllHadrons_cfi import tauGenJetsSelectorAllHadrons +from PhysicsTools.PatAlgos.patTauSignalCandidatesProducer_cfi import patTauSignalCandidatesProducer + ##################### Updated tau collection with MVA-based tau-Ids rerun ####### # Used only in some eras from PhysicsTools.NanoAOD.taus_updatedMVAIds_cff import * @@ -152,9 +154,9 @@ def _tauIdWPMask(pattern, choices, doc="", from_raw=False, wp_thrs=None): from_raw=True, wp_thrs=WORKING_POINTS_v2p5["jet"]) ) -tauSignalCands = cms.EDProducer("PATTauSignalCandidatesProducer", +tauSignalCands = patTauSignalCandidatesProducer.clone( src = tauTable.src, - storeLostTracks = cms.bool(True) + storeLostTracks = True ) tauSignalCandsTable = simpleCandidateFlatTableProducer.clone( diff --git a/PhysicsTools/PatAlgos/plugins/PATLeptonTimeLifeInfoProducer.cc b/PhysicsTools/PatAlgos/plugins/PATLeptonTimeLifeInfoProducer.cc new file mode 100644 index 0000000000000..2e41063e3f298 --- /dev/null +++ b/PhysicsTools/PatAlgos/plugins/PATLeptonTimeLifeInfoProducer.cc @@ -0,0 +1,270 @@ +/** + \class PATLeptonTimeLifeInfoProducer + \brief Produces lepton life-time information + + \author Michal Bluj, NCBJ, Warsaw +*/ + +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" + +#include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/PatCandidates/interface/Electron.h" +#include "DataFormats/PatCandidates/interface/Muon.h" +#include "DataFormats/PatCandidates/interface/Tau.h" +#include "DataFormats/PatCandidates/interface/PackedCandidate.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/VertexReco/interface/Vertex.h" +#include "DataFormats/VertexReco/interface/TrackTimeLifeInfo.h" + +#include "MagneticField/Engine/interface/MagneticField.h" +#include "RecoVertex/VertexPrimitives/interface/TransientVertex.h" +#include "RecoVertex/VertexTools/interface/VertexDistance3D.h" +#include "RecoVertex/VertexPrimitives/interface/ConvertToFromReco.h" +#include "RecoVertex/KalmanVertexFit/interface/KalmanVertexFitter.h" +#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h" +#include "TrackingTools/Records/interface/TransientTrackRecord.h" +#include "TrackingTools/GeomPropagators/interface/AnalyticalTrajectoryExtrapolatorToLine.h" +#include "TrackingTools/GeomPropagators/interface/AnalyticalImpactPointExtrapolator.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" + +#include + +template +class PATLeptonTimeLifeInfoProducer : public edm::stream::EDProducer<> { +public: + explicit PATLeptonTimeLifeInfoProducer(const edm::ParameterSet&); + ~PATLeptonTimeLifeInfoProducer() override{}; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + void produce(edm::Event&, const edm::EventSetup&) override; + +private: + //--- private utility methods + const reco::Track* getTrack(const T&); + void produceAndFillIPInfo(const T&, const TransientTrackBuilder&, const reco::Vertex&, TrackTimeLifeInfo&); + void produceAndFillSVInfo(const T&, const TransientTrackBuilder&, const reco::Vertex&, TrackTimeLifeInfo&); + static bool fitVertex(const std::vector& transTrk, TransientVertex& transVtx) { + if (transTrk.size() < 2) + return false; + KalmanVertexFitter kvf(true); + transVtx = kvf.vertex(transTrk); + return transVtx.hasRefittedTracks() && transVtx.refittedTracks().size() == transTrk.size(); + } + + //--- configuration parameters + edm::EDGetTokenT> leptonsToken_; + edm::EDGetTokenT pvToken_; + edm::ESGetToken transTrackBuilderToken_; + const StringCutObjectSelector selector_; + int pvChoice_; + + enum PVChoice { useFront = 0, useClosestInDz }; + //--- value map for TrackTimeLifeInfo (to be stored into the event) + using TrackTimeLifeInfoMap = edm::ValueMap; +}; + +template +PATLeptonTimeLifeInfoProducer::PATLeptonTimeLifeInfoProducer(const edm::ParameterSet& cfg) + : leptonsToken_(consumes>(cfg.getParameter("src"))), + pvToken_(consumes(cfg.getParameter("pvSource"))), + transTrackBuilderToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))), + selector_(cfg.getParameter("selection")), + pvChoice_(cfg.getParameter("pvChoice")) { + produces(); +} + +template +void PATLeptonTimeLifeInfoProducer::produce(edm::Event& evt, const edm::EventSetup& es) { + // Get leptons + edm::Handle> leptons; + evt.getByToken(leptonsToken_, leptons); + + // Get the vertices + edm::Handle vertices; + evt.getByToken(pvToken_, vertices); + + // Get transient track builder + const TransientTrackBuilder& transTrackBuilder = es.getData(transTrackBuilderToken_); + + std::vector infos; + infos.reserve(leptons->size()); + + for (const auto& lepton : *leptons) { + TrackTimeLifeInfo info; + + // Do nothing for lepton not passing selection + if (!selector_(lepton)) { + infos.push_back(info); + continue; + } + size_t pv_idx = 0; + if (pvChoice_ == useClosestInDz && getTrack(lepton) != nullptr) { + float dz_min = 999; + size_t vtx_idx = 0; + for (const auto& vtx : *vertices) { + float dz_tmp = std::abs(getTrack(lepton)->dz(vtx.position())); + if (dz_tmp < dz_min) { + dz_min = dz_tmp; + pv_idx = vtx_idx; + } + vtx_idx++; + } + } + const reco::Vertex& pv = !vertices->empty() ? (*vertices)[pv_idx] : reco::Vertex(); + + // Obtain IP vector and set related info into lepton + produceAndFillIPInfo(lepton, transTrackBuilder, pv, info); + + // Fit SV and set related info for taus or do nothing for other lepton types + produceAndFillSVInfo(lepton, transTrackBuilder, pv, info); + infos.push_back(info); + } // end of lepton loop + + // Build the valuemap + auto infoMap = std::make_unique(); + TrackTimeLifeInfoMap::Filler filler(*infoMap); + filler.insert(leptons, infos.begin(), infos.end()); + filler.fill(); + + // Store output into the event + evt.put(std::move(infoMap)); +} + +template <> +const reco::Track* PATLeptonTimeLifeInfoProducer::getTrack(const pat::Electron& electron) { + return electron.gsfTrack().isNonnull() ? electron.gsfTrack().get() : nullptr; +} + +template <> +const reco::Track* PATLeptonTimeLifeInfoProducer::getTrack(const pat::Muon& muon) { + return muon.innerTrack().isNonnull() ? muon.innerTrack().get() : nullptr; +} + +template <> +const reco::Track* PATLeptonTimeLifeInfoProducer::getTrack(const pat::Tau& tau) { + const reco::Track* track = nullptr; + if (tau.leadChargedHadrCand().isNonnull()) + track = tau.leadChargedHadrCand()->bestTrack(); + return track; +} + +template +void PATLeptonTimeLifeInfoProducer::produceAndFillIPInfo(const T& lepton, + const TransientTrackBuilder& transTrackBuilder, + const reco::Vertex& pv, + TrackTimeLifeInfo& info) { + const reco::Track* track = getTrack(lepton); + if (track != nullptr) { + info.setTrack(track); + info.setBField_z(transTrackBuilder.field()->inInverseGeV(GlobalPoint(track->vx(), track->vy(), track->vz())).z()); + + // Extrapolate track to the point closest to PV + reco::TransientTrack transTrack = transTrackBuilder.build(track); + AnalyticalImpactPointExtrapolator extrapolator(transTrack.field()); + TrajectoryStateOnSurface closestState = + extrapolator.extrapolate(transTrack.impactPointState(), RecoVertex::convertPos(pv.position())); + GlobalPoint pca = closestState.globalPosition(); + GlobalError pca_cov = closestState.cartesianError().position(); + GlobalVector ip_vec = GlobalVector(pca.x() - pv.x(), pca.y() - pv.y(), pca.z() - pv.z()); + GlobalError ip_cov = pca_cov + GlobalError(pv.covariance()); + VertexDistance3D pca_dist; + Measurement1D ip_mes = pca_dist.distance(pv, VertexState(pca, pca_cov)); + if (ip_vec.dot(GlobalVector(lepton.px(), lepton.py(), lepton.pz())) < 0) + ip_mes = Measurement1D(-1. * ip_mes.value(), ip_mes.error()); + + // Store PCA info + info.setPCA(pca, pca_cov); + info.setIP(ip_vec, ip_cov); + info.setIPLength(ip_mes); + } +} + +template +void PATLeptonTimeLifeInfoProducer::produceAndFillSVInfo(const T& lepton, + const TransientTrackBuilder& transTrackBuilder, + const reco::Vertex& pv, + TrackTimeLifeInfo& info) {} + +template <> +void PATLeptonTimeLifeInfoProducer::produceAndFillSVInfo(const pat::Tau& tau, + const TransientTrackBuilder& transTrackBuilder, + const reco::Vertex& pv, + TrackTimeLifeInfo& info) { + // Fit SV with tracks of charged tau decay products + int fitOK = 0; + if (tau.signalChargedHadrCands().size() + tau.signalLostTracks().size() > 1) { + // Get tracks from tau signal charged candidates + std::vector transTrks; + TransientVertex transVtx; + for (const auto& cand : tau.signalChargedHadrCands()) { + if (cand.isNull()) + continue; + const reco::Track* track = cand->bestTrack(); + if (track != nullptr) + transTrks.push_back(transTrackBuilder.build(track)); + } + for (const auto& cand : tau.signalLostTracks()) { + if (cand.isNull()) + continue; + const reco::Track* track = cand->bestTrack(); + if (track != nullptr) + transTrks.push_back(transTrackBuilder.build(track)); + } + // Fit SV with KalmanVertexFitter + fitOK = fitVertex(transTrks, transVtx) ? 1 : -1; + if (fitOK > 0) { + reco::Vertex sv = transVtx; + // Get flight-length + // Full PV->SV flight vector with its covariance + GlobalVector flight_vec = GlobalVector(sv.x() - pv.x(), sv.y() - pv.y(), sv.z() - pv.z()); + GlobalError flight_cov = transVtx.positionError() + GlobalError(pv.covariance()); + //MB: can be taken from tau itself (but with different fit of PV and SV) as follows: + //tau.flightLength().mag2()); + //tau.flightLengthSig(); + VertexDistance3D sv_dist; + Measurement1D flightLength_mes = sv_dist.signedDistance(pv, sv, GlobalVector(tau.px(), tau.py(), tau.pz())); + + // Store SV info + info.setSV(sv); + info.setFlightVector(flight_vec, flight_cov); + info.setFlightLength(flightLength_mes); + } + } +} + +template +void PATLeptonTimeLifeInfoProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + // pat{Electron,Muon,Tau}TimeLifeInfoProducer + edm::ParameterSetDescription desc; + + std::string lepCollName; + if (typeid(T) == typeid(pat::Electron)) + lepCollName = "slimmedElectrons"; + else if (typeid(T) == typeid(pat::Muon)) + lepCollName = "slimmedMuons"; + else if (typeid(T) == typeid(pat::Tau)) + lepCollName = "slimmedTaus"; + desc.add("src", edm::InputTag(lepCollName)); + desc.add("pvSource", edm::InputTag("offlineSlimmedPrimaryVertices")); + desc.add("selection", "")->setComment("Selection required to produce and store time-life information"); + desc.add("pvChoice", useFront) + ->setComment( + "Define PV to compute IP: 0: first PV, 1: PV with the smallest dz of the tau leading track (default: " + + std::to_string(useFront) + ")"); + + descriptions.addWithDefaultLabel(desc); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +typedef PATLeptonTimeLifeInfoProducer PATElectronTimeLifeInfoProducer; +DEFINE_FWK_MODULE(PATElectronTimeLifeInfoProducer); +typedef PATLeptonTimeLifeInfoProducer PATMuonTimeLifeInfoProducer; +DEFINE_FWK_MODULE(PATMuonTimeLifeInfoProducer); +typedef PATLeptonTimeLifeInfoProducer PATTauTimeLifeInfoProducer; +DEFINE_FWK_MODULE(PATTauTimeLifeInfoProducer); diff --git a/PhysicsTools/PatAlgos/plugins/PATRefitVertexProducer.cc b/PhysicsTools/PatAlgos/plugins/PATRefitVertexProducer.cc new file mode 100644 index 0000000000000..a3ab1fa1120dd --- /dev/null +++ b/PhysicsTools/PatAlgos/plugins/PATRefitVertexProducer.cc @@ -0,0 +1,193 @@ +/** + \class PATRefitVertexProducer + + This producer is intended to take packedCandidates with tracks associated to + the PV and refit the PV (applying or not) BeamSpot constraint + + \autor Michal Bluj, NCBJ Warsaw (and then others) + + **/ + +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "DataFormats/PatCandidates/interface/PackedCandidate.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/VertexReco/interface/Vertex.h" +#include "DataFormats/BeamSpot/interface/BeamSpot.h" +#include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h" +#include "TrackingTools/Records/interface/TransientTrackRecord.h" +#include "RecoVertex/VertexPrimitives/interface/TransientVertex.h" +#include "RecoVertex/AdaptiveVertexFit/interface/AdaptiveVertexFitter.h" + +#include + +class PATRefitVertexProducer : public edm::stream::EDProducer<> { +public: + explicit PATRefitVertexProducer(const edm::ParameterSet&); + ~PATRefitVertexProducer() override{}; + + void produce(edm::Event&, const edm::EventSetup&) override; + static void fillDescriptions(edm::ConfigurationDescriptions&); + +private: + //--- utility methods + + //--- configuration parameters + edm::EDGetTokenT > srcCands_, srcLostTracks_, srcEleKfTracks_; + edm::EDGetTokenT srcVertices_; + edm::EDGetTokenT srcBeamSpot_; + edm::ESGetToken transTrackBuilderToken_; + bool useBeamSpot_; + bool useLostTracks_; + bool useEleKfTracks_; +}; + +PATRefitVertexProducer::PATRefitVertexProducer(const edm::ParameterSet& cfg) + : srcCands_(consumes >(cfg.getParameter("srcCands"))), + srcLostTracks_(consumes >(cfg.getParameter("srcLostTracks"))), + srcEleKfTracks_(consumes >(cfg.getParameter("srcEleKfTracks"))), + srcVertices_(consumes(cfg.getParameter("srcVertices"))), + srcBeamSpot_(consumes(cfg.getParameter("srcBeamSpot"))), + transTrackBuilderToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))), + useBeamSpot_(cfg.getParameter("useBeamSpot")), + useLostTracks_(cfg.getParameter("useLostTracks")), + useEleKfTracks_(cfg.getParameter("useEleKfTracks")) { + produces(); +} + +void PATRefitVertexProducer::produce(edm::Event& evt, const edm::EventSetup& es) { + // Obtain collections + edm::Handle > cands; + evt.getByToken(srcCands_, cands); + + edm::Handle > lostTrackCands; + if (useLostTracks_) + evt.getByToken(srcLostTracks_, lostTrackCands); + + edm::Handle > eleKfTrackCands; + if (useEleKfTracks_) + evt.getByToken(srcEleKfTracks_, eleKfTrackCands); + + edm::Handle vertices; + evt.getByToken(srcVertices_, vertices); + const reco::Vertex& pv = vertices->front(); + size_t vtxIdx = 0; + + edm::Handle beamSpot; + if (useBeamSpot_) + evt.getByToken(srcBeamSpot_, beamSpot); + + // Get transient track builder + const TransientTrackBuilder& transTrackBuilder = es.getData(transTrackBuilderToken_); + + // Output collection + auto outputVertices = std::make_unique(); + outputVertices->reserve(1); + + // Create a new track collection for vertex refit + std::vector transTracks; + + // loop over the PFCandidates + for (const auto& cand : (*cands)) { + if (cand.charge() == 0 || cand.vertexRef().isNull()) + continue; + if (cand.bestTrack() == nullptr) + continue; + auto key = cand.vertexRef().key(); + auto quality = cand.pvAssociationQuality(); + if (key != vtxIdx || + (quality != pat::PackedCandidate::UsedInFitTight && quality != pat::PackedCandidate::UsedInFitLoose)) + continue; + if (useEleKfTracks_ && std::abs(cand.pdgId()) == 11) + continue; + transTracks.push_back(transTrackBuilder.build(cand.bestTrack())); + } + + // loop over the lostTracks + if (useLostTracks_) { + for (const auto& cand : (*lostTrackCands)) { + if (cand.charge() == 0 || cand.vertexRef().isNull()) + continue; + if (cand.bestTrack() == nullptr) + continue; + auto key = cand.vertexRef().key(); + auto quality = cand.pvAssociationQuality(); + if (key != vtxIdx || + (quality != pat::PackedCandidate::UsedInFitTight && quality != pat::PackedCandidate::UsedInFitLoose)) + continue; + transTracks.push_back(transTrackBuilder.build(cand.bestTrack())); + } + } + + // loop over the electronKfTracks + if (useEleKfTracks_) { + for (const auto& cand : (*eleKfTrackCands)) { + if (cand.charge() == 0 || cand.vertexRef().isNull()) + continue; + if (cand.bestTrack() == nullptr) + continue; + auto key = cand.vertexRef().key(); + auto quality = cand.pvAssociationQuality(); + if (key != vtxIdx || + (quality != pat::PackedCandidate::UsedInFitTight && quality != pat::PackedCandidate::UsedInFitLoose)) + continue; + transTracks.push_back(transTrackBuilder.build(cand.bestTrack())); + } + } + + // Refit the vertex + TransientVertex transVtx; + reco::Vertex refitPV(pv); // initialized to the original PV + + bool fitOK = true; + if (transTracks.size() >= 3) { + AdaptiveVertexFitter avf; + avf.setWeightThreshold(0.1); // weight per track, allow almost every fit, else --> exception + if (!useBeamSpot_) { + transVtx = avf.vertex(transTracks); + } else { + transVtx = avf.vertex(transTracks, *beamSpot); + } + if (!transVtx.isValid()) { + fitOK = false; + } else { + //MB: protect against rare cases when transVtx is valid but its postion is ill-defined + if (!std::isfinite(transVtx.position().z())) //MB: it is enough to check one coordinate (?) + fitOK = false; + } + } else + fitOK = false; + if (fitOK) { + refitPV = transVtx; + } + + outputVertices->push_back(refitPV); + + evt.put(std::move(outputVertices)); +} + +void PATRefitVertexProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + // patRefitVertexProducer + edm::ParameterSetDescription desc; + + desc.add("srcVertices", edm::InputTag("offlineSlimmedPrimaryVertices")); + desc.add("srcCands", edm::InputTag("packedPFCandidates")); + desc.add("srcLostTracks", edm::InputTag("lostTracks")); + desc.add("srcEleKfTracks", edm::InputTag("lostTracks:eleTracks")); + desc.add("srcBeamSpot", edm::InputTag("offlineBeamSpot")); + desc.add("useBeamSpot", true)->setComment("Refit PV with beam-spot constraint"); + desc.add("useLostTracks", true) + ->setComment("Use collection of tracks not used by PF-candidates, aka lost-tracks"); + desc.add("useEleKfTracks", true) + ->setComment("Use collection of electron KF-tracks instead of GSF-tracks of electron PF-candidates"); + + descriptions.addWithDefaultLabel(desc); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(PATRefitVertexProducer);