Skip to content

Commit

Permalink
Module to refit PV with beam-spot constraint with miniAOD inputs (for…
Browse files Browse the repository at this point in the history
… lepton time-life info in nanoAOD with run-2 samples)
  • Loading branch information
mbluj committed Dec 7, 2023
1 parent 7b6d0be commit e16b1e3
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 21 deletions.
14 changes: 9 additions & 5 deletions PhysicsTools/NanoAOD/python/electrons_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,12 @@ def _get_bitmapVIDForEle_docstring(modules,WorkingPoints):

# Produce and add time-life info (e.g. for electrons from tau decays)
from PhysicsTools.PatAlgos.patElectronTimeLifeInfoUpdater_cfi import patElectronTimeLifeInfoUpdater
from PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff import *
import PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff as tli
from TrackingTools.TransientTrack.TransientTrackBuilder_cfi import *
electronsWithTimeLifeInfo = patElectronTimeLifeInfoUpdater.clone(
src = electronTable.src,
pvSource = "offlineSlimmedPrimaryVerticesWithBS",
pvChoice = 0 #0: PV[0], 1: smallest dz
pvSource = tli.prod_common.pvSource,
pvChoice = tli.prod_common.pvChoice
)

electronTimeLifeInfoTable = simpleCandidateFlatTableProducer.clone(
Expand All @@ -409,8 +409,8 @@ def _get_bitmapVIDForEle_docstring(modules,WorkingPoints):
doc = cms.string("Additional time-life info for non-prompt electrons"),
extension = True,
variables = cms.PSet(
ipVars,
trackVars
tli.ipVars,
tli.trackVars
)
)

Expand Down Expand Up @@ -477,3 +477,7 @@ def _get_bitmapVIDForEle_docstring(modules,WorkingPoints):
# Revert back to AK4 CHS jets for Run2 inputs
run2_nanoAOD_ANY.toModify(
ptRatioRelForEle,srcJet="updatedJets")
# Refit PV with beam-spot constraint that is not present in Run-2 samples
_electronTimeLifeInfoTaskRun2 = electronTimeLifeInfoTask.copy()
_electronTimeLifeInfoTaskRun2.add(tli.refittedPV)
run2_nanoAOD_ANY.toReplaceWith(electronTimeLifeInfoTask,_electronTimeLifeInfoTaskRun2)
15 changes: 15 additions & 0 deletions PhysicsTools/NanoAOD/python/leptonTimeLifeInfo_common_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
#
import FWCore.ParameterSet.Config as cms
from PhysicsTools.NanoAOD.common_cff import *
from PhysicsTools.NanoAOD.nano_eras_cff import *
from PhysicsTools.PatAlgos.miniAODRefitVertexProducer_cfi import miniAODRefitVertexProducer

# 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(
Expand Down Expand Up @@ -48,3 +56,10 @@
flightLength = Var("?hasUserFloat('flightLength')?userFloat('flightLength'):0", float, doc="flight-length,i.e. the PV to SV distance", precision=16),
flightLengthSig = Var("?hasUserFloat('flightLength_sig')?userFloat('flightLength_sig'):0", float, doc="Significance of flight-length", precision=16)
)

# Module to refit PV with beam-spot constraint that is not present in Run-2 samples
refittedPV = miniAODRefitVertexProducer.clone(
srcVertices = "offlineSlimmedPrimaryVertices",
)
run2_nanoAOD_ANY.toModify(
prod_common, pvSource = "refittedPV")
14 changes: 9 additions & 5 deletions PhysicsTools/NanoAOD/python/muons_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import PhysicsTools.PatAlgos.producersLayer1.muonProducer_cfi
from PhysicsTools.PatAlgos.patMuonTimeLifeInfoUpdater_cfi import patMuonTimeLifeInfoUpdater
from PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff import *
import PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff as tli

# this below is used only in some eras
slimmedMuonsUpdated = cms.EDProducer("PATMuonUpdater",
Expand Down Expand Up @@ -191,8 +191,8 @@
# Produce and add time-life info (e.g. for muons from tau decays)
muonsWithTimeLifeInfo = patMuonTimeLifeInfoUpdater.clone(
src = muonTable.src,
pvSource = "offlineSlimmedPrimaryVerticesWithBS",
pvChoice = 0 #0: PV[0], 1: smallest dz
pvSource = tli.prod_common.pvSource,
pvChoice = tli.prod_common.pvChoice
)

muonTimeLifeInfoTable = simpleCandidateFlatTableProducer.clone(
Expand All @@ -201,8 +201,8 @@
doc = cms.string("Additional time-life info for non-prompt muons"),
extension = True,
variables = cms.PSet(
ipVars,
trackVars
tli.ipVars,
tli.trackVars
)
)

Expand Down Expand Up @@ -245,5 +245,9 @@
muonMCTask = cms.Task(muonsMCMatchForTable,muonMCTable)
muonTablesTask = cms.Task(muonMVATTH,muonMVALowPt,muonBSConstrain,muonTable,muonMVAID)
muonTimeLifeInfoTask = cms.Task(muonsWithTimeLifeInfo,muonTimeLifeInfoTable)
# Refit PV with beam-spot constraint that is not present in Run-2 samples
_muonTimeLifeInfoTaskRun2 = muonTimeLifeInfoTask.copy()
_muonTimeLifeInfoTaskRun2.add(tli.refittedPV)
run2_nanoAOD_ANY.toReplaceWith(muonTimeLifeInfoTask,_muonTimeLifeInfoTaskRun2)
muonTablesTask.add(muonTimeLifeInfoTask)

18 changes: 11 additions & 7 deletions PhysicsTools/NanoAOD/python/taus_cff.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import FWCore.ParameterSet.Config as cms
from PhysicsTools.NanoAOD.common_cff import *
from PhysicsTools.NanoAOD.nano_eras_cff import run3_nanoAOD_124
from PhysicsTools.NanoAOD.nano_eras_cff import *
from PhysicsTools.NanoAOD.simpleCandidateFlatTableProducer_cfi import simpleCandidateFlatTableProducer

from PhysicsTools.JetMCAlgos.TauGenJets_cfi import tauGenJets
from PhysicsTools.JetMCAlgos.TauGenJetsDecayModeSelectorAllHadrons_cfi import tauGenJetsSelectorAllHadrons

from PhysicsTools.PatAlgos.patTauSignalCandidatesProducer_cfi import patTauSignalCandidatesProducer
from PhysicsTools.PatAlgos.patTauTimeLifeInfoUpdater_cfi import patTauTimeLifeInfoUpdater
from PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff import *
import PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff as tli

##################### Updated tau collection with MVA-based tau-Ids rerun #######
# Used only in some eras
Expand Down Expand Up @@ -178,8 +178,8 @@ def _tauIdWPMask(pattern, choices, doc="", from_raw=False, wp_thrs=None):
from TrackingTools.TransientTrack.TransientTrackBuilder_cfi import *
tausWithTimeLifeInfo = patTauTimeLifeInfoUpdater.clone(
src = tauTable.src,
pvSource = "offlineSlimmedPrimaryVerticesWithBS",
pvChoice = 0 #0: PV[0], 1: smallest dz
pvSource = tli.prod_common.pvSource,
pvChoice = tli.prod_common.pvChoice
)

tauTimeLifeInfoTable = simpleCandidateFlatTableProducer.clone(
Expand All @@ -188,9 +188,9 @@ def _tauIdWPMask(pattern, choices, doc="", from_raw=False, wp_thrs=None):
doc = cms.string("Additional tau time-life info"),
extension = True,
variables = cms.PSet(
svVars,
ipVars,
trackVars
tli.svVars,
tli.ipVars,
tli.trackVars
)
)

Expand Down Expand Up @@ -264,6 +264,10 @@ def _tauIdWPMask(pattern, choices, doc="", from_raw=False, wp_thrs=None):
tauSignalCandsTask = cms.Task(tauSignalCands,tauSignalCandsTable)
tauTablesTask.add(tauSignalCandsTask)
tauTimeLifeInfoTask = cms.Task(tausWithTimeLifeInfo,tauTimeLifeInfoTable)
# Refit PV with beam-spot constraint that is not present in Run-2 samples
_tauTimeLifeInfoTaskRun2 = tauTimeLifeInfoTask.copy()
_tauTimeLifeInfoTaskRun2.add(tli.refittedPV)
run2_nanoAOD_ANY.toReplaceWith(tauTimeLifeInfoTask,_tauTimeLifeInfoTaskRun2)
tauTablesTask.add(tauTimeLifeInfoTask)


Expand Down
14 changes: 10 additions & 4 deletions PhysicsTools/NanoAOD/python/vertices_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from PhysicsTools.NanoAOD.common_cff import *
from PhysicsTools.NanoAOD.simpleCandidateFlatTableProducer_cfi import simpleCandidateFlatTableProducer
from PhysicsTools.NanoAOD.simpleVertexFlatTableProducer_cfi import simpleVertexFlatTableProducer
from PhysicsTools.NanoAOD.nano_eras_cff import *
from PhysicsTools.NanoAOD.leptonTimeLifeInfo_common_cff import prod_common, refittedPV


##################### User floats producers, selectors ##########################
Expand Down Expand Up @@ -47,7 +49,7 @@

vertexTable.optionalPvVariables = covarianceVars

verticesWithBS = "offlineSlimmedPrimaryVerticesWithBS"
verticesWithBS = prod_common.pvSource
pvbsTable = simpleVertexFlatTableProducer.clone(
src = verticesWithBS,
name = "PVBS",
Expand All @@ -61,12 +63,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),
),
externalVariables = cms.PSet(
score = ExtVar(cms.InputTag(verticesWithBS), float, doc="vertex score, i.e. sum pt2 of clustered objects", precision = 8)
)
)

#before cross linking
vertexTask = cms.Task()
#after cross linkining
vertexTablesTask = cms.Task( vertexTable, svCandidateTable, pvbsTable )

#refit PV with beam-spot constraint that is not present in Run-2 samples
_vertexTablesTaskRun2 = vertexTablesTask.copy()
_vertexTablesTaskRun2.add( refittedPV )
run2_nanoAOD_ANY.toReplaceWith(
vertexTablesTask, _vertexTablesTaskRun2
)
189 changes: 189 additions & 0 deletions PhysicsTools/PatAlgos/plugins/MiniAODRefitVertexProducer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
\class MiniAODRefitVertexProducer
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 <memory>

class MiniAODRefitVertexProducer : public edm::stream::EDProducer<> {
public:
explicit MiniAODRefitVertexProducer(const edm::ParameterSet&);
~MiniAODRefitVertexProducer() override{};

void produce(edm::Event&, const edm::EventSetup&) override;
static void fillDescriptions(edm::ConfigurationDescriptions&);

private:
//--- utility methods

//--- configuration parameters
edm::EDGetTokenT<std::vector<pat::PackedCandidate> > srcCands_, srcLostTracks_, srcEleKfTracks_;
edm::EDGetTokenT<reco::VertexCollection> srcVertices_;
edm::EDGetTokenT<reco::BeamSpot> srcBeamSpot_;
edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> transTrackBuilderToken_;
bool useBeamSpot_;
bool useLostTracks_;
bool useEleKfTracks_;
};

MiniAODRefitVertexProducer::MiniAODRefitVertexProducer(const edm::ParameterSet& cfg)
: srcCands_(consumes<std::vector<pat::PackedCandidate> >(cfg.getParameter<edm::InputTag>("srcCands"))),
srcLostTracks_(consumes<std::vector<pat::PackedCandidate> >(cfg.getParameter<edm::InputTag>("srcLostTracks"))),
srcEleKfTracks_(consumes<std::vector<pat::PackedCandidate> >(cfg.getParameter<edm::InputTag>("srcEleKfTracks"))),
srcVertices_(consumes<reco::VertexCollection>(cfg.getParameter<edm::InputTag>("srcVertices"))),
srcBeamSpot_(consumes<reco::BeamSpot>(cfg.getParameter<edm::InputTag>("srcBeamSpot"))),
transTrackBuilderToken_(esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))),
useBeamSpot_(cfg.getParameter<bool>("useBeamSpot")),
useLostTracks_(cfg.getParameter<bool>("useLostTracks")),
useEleKfTracks_(cfg.getParameter<bool>("useEleKfTracks")) {
produces<reco::VertexCollection>();
}

void MiniAODRefitVertexProducer::produce(edm::Event& evt, const edm::EventSetup& es) {
// Obtain collections
edm::Handle<std::vector<pat::PackedCandidate> > cands;
evt.getByToken(srcCands_, cands);

edm::Handle<std::vector<pat::PackedCandidate> > lostTrackCands;
if (useLostTracks_)
evt.getByToken(srcLostTracks_, lostTrackCands);

edm::Handle<std::vector<pat::PackedCandidate> > eleKfTrackCands;
if (useEleKfTracks_)
evt.getByToken(srcEleKfTracks_, eleKfTrackCands);

edm::Handle<reco::VertexCollection> vertices;
evt.getByToken(srcVertices_, vertices);
const reco::Vertex& pv = vertices->front();
size_t vtxIdx = 0;

edm::Handle<reco::BeamSpot> beamSpot;
if (useBeamSpot_)
evt.getByToken(srcBeamSpot_, beamSpot);

// Get transient track builder
const TransientTrackBuilder& transTrackBuilder = es.getData(transTrackBuilderToken_);

// Output collection
auto outputVertices = std::make_unique<reco::VertexCollection>();
outputVertices->reserve(1);

// Create a new track collection for vertex refit
std::vector<reco::TransientTrack> 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
try {
if (!useBeamSpot_) {
transVtx = avf.vertex(transTracks);
} else {
transVtx = avf.vertex(transTracks, *beamSpot);
}
} catch (...) {
fitOK = false;
}
} else
fitOK = false;
if (fitOK) {
refitPV = transVtx;
}

outputVertices->push_back(refitPV);

evt.put(std::move(outputVertices));
}

void MiniAODRefitVertexProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
// miniAODRefitVertexProducer
edm::ParameterSetDescription desc;

desc.add<edm::InputTag>("srcVertices", edm::InputTag("offlineSlimmedPrimaryVertices"));
desc.add<edm::InputTag>("srcCands", edm::InputTag("packedPFCandidates"));
desc.add<edm::InputTag>("srcLostTracks", edm::InputTag("lostTracks"));
desc.add<edm::InputTag>("srcEleKfTracks", edm::InputTag("lostTracks:eleTracks"));
desc.add<edm::InputTag>("srcBeamSpot", edm::InputTag("offlineBeamSpot"));
desc.add<bool>("useBeamSpot", true);
desc.add<bool>("useLostTracks", true);
desc.add<bool>("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(MiniAODRefitVertexProducer);

0 comments on commit e16b1e3

Please sign in to comment.