File indexing completed on 2024-04-06 12:27:55
0001 #include "RecoTauTag/RecoTau/interface/RecoTauVertexAssociator.h"
0002
0003 #include <functional>
0004
0005 #include "DataFormats/TauReco/interface/PFTau.h"
0006 #include "DataFormats/VertexReco/interface/Vertex.h"
0007 #include "DataFormats/PatCandidates/interface/PackedCandidate.h"
0008 #include "FWCore/Framework/interface/Event.h"
0009 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0011 #include "RecoTauTag/RecoTau/interface/RecoTauCommonUtilities.h"
0012 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
0013 #include "DataFormats/TrackReco/interface/Track.h"
0014
0015 namespace reco {
0016 namespace tau {
0017
0018 namespace {
0019 inline const reco::Track* getTrack(const Candidate& cand) {
0020 const PFCandidate* pfCandPtr = dynamic_cast<const PFCandidate*>(&cand);
0021 if (pfCandPtr != nullptr) {
0022 if (pfCandPtr->trackRef().isNonnull())
0023 return pfCandPtr->trackRef().get();
0024 else if (pfCandPtr->gsfTrackRef().isNonnull())
0025 return pfCandPtr->gsfTrackRef().get();
0026 else
0027 return nullptr;
0028 }
0029 const pat::PackedCandidate* packedCand = dynamic_cast<const pat::PackedCandidate*>(&cand);
0030 if (packedCand != nullptr && packedCand->hasTrackDetails())
0031 return &packedCand->pseudoTrack();
0032
0033 return nullptr;
0034 }
0035
0036 inline const reco::TrackBaseRef getTrackRef(const Candidate& cand) {
0037
0038
0039 const PFCandidate* pfCandPtr = dynamic_cast<const PFCandidate*>(&cand);
0040 if (pfCandPtr != nullptr) {
0041 if (pfCandPtr->trackRef().isNonnull())
0042 return reco::TrackBaseRef(pfCandPtr->trackRef());
0043 else if (pfCandPtr->gsfTrackRef().isNonnull())
0044 return reco::TrackBaseRef(pfCandPtr->gsfTrackRef());
0045 else
0046 return reco::TrackBaseRef();
0047 }
0048
0049 return reco::TrackBaseRef();
0050 }
0051 }
0052
0053
0054
0055 const reco::CandidatePtr RecoTauVertexAssociator::getLeadCand(const Jet& jet) const {
0056 std::vector<CandidatePtr> chargedPFCands = pfChargedCands(jet, true);
0057 if (verbosity_ >= 1) {
0058 std::cout << "<RecoTauVertexAssociator::getLeadTrack>:" << std::endl;
0059 std::cout << " jet: Pt = " << jet.pt() << ", eta = " << jet.eta() << ", phi = " << jet.phi() << std::endl;
0060 std::cout << " num. chargedPFCands = " << chargedPFCands.size() << std::endl;
0061 std::cout << " vxTrkFiltering = " << vxTrkFiltering_ << std::endl;
0062 }
0063
0064 if (chargedPFCands.empty()) {
0065 return reco::CandidatePtr(nullptr, 0);
0066 }
0067
0068 std::vector<CandidatePtr> selectedPFCands;
0069 if (vxTrkFiltering_) {
0070 selectedPFCands = qcuts_->filterCandRefs(chargedPFCands);
0071 } else {
0072 selectedPFCands = chargedPFCands;
0073 }
0074 if (verbosity_ >= 1) {
0075 std::cout << " num. selectedPFCands = " << selectedPFCands.size() << std::endl;
0076 }
0077
0078 CandidatePtr leadCand;
0079 if (!selectedPFCands.empty()) {
0080 double leadTrackPt = 0.;
0081 if (leadingTrkOrPFCandOption_ == kFirstTrack) {
0082 leadCand = selectedPFCands[0];
0083 } else {
0084 for (std::vector<CandidatePtr>::const_iterator pfCand = selectedPFCands.begin();
0085 pfCand != selectedPFCands.end();
0086 ++pfCand) {
0087 const reco::Track* track = getTrack(**pfCand);
0088 double actualTrackPt = 0., actualTrackPtError = 0.;
0089 if (track != nullptr) {
0090 actualTrackPt = track->pt();
0091 actualTrackPtError = track->ptError();
0092 }
0093 double trackPt = 0.;
0094 if (leadingTrkOrPFCandOption_ == kLeadTrack) {
0095 trackPt = actualTrackPt - 2. * actualTrackPtError;
0096 } else if (leadingTrkOrPFCandOption_ == kLeadPFCand) {
0097 trackPt = (*pfCand)->pt();
0098 } else if (leadingTrkOrPFCandOption_ == kMinLeadTrackOrPFCand) {
0099 trackPt = std::min(actualTrackPt, (double)(*pfCand)->pt());
0100 } else
0101 assert(0);
0102 if (trackPt > leadTrackPt) {
0103 leadCand = (*pfCand);
0104 leadTrackPt = trackPt;
0105 }
0106 }
0107 }
0108 }
0109 if (leadCand.isNull()) {
0110 if (recoverLeadingTrk_) {
0111 leadCand = chargedPFCands[0];
0112 } else {
0113 return reco::CandidatePtr(nullptr, 0);
0114 }
0115 }
0116 if (verbosity_ >= 1) {
0117 std::cout << "leadCand: Pt = " << leadCand->pt() << ", eta = " << leadCand->eta()
0118 << ", phi = " << leadCand->phi() << std::endl;
0119 }
0120 return leadCand;
0121 }
0122
0123 const reco::Track* RecoTauVertexAssociator::getLeadTrack(const Jet& jet) const {
0124 auto leadCand = getLeadCand(jet);
0125 if (leadCand.isNull())
0126 return nullptr;
0127 const reco::Track* track = getTrack(*leadCand);
0128 return track;
0129 }
0130
0131 const reco::TrackBaseRef RecoTauVertexAssociator::getLeadTrackRef(const Jet& jet) const {
0132 auto leadCand = getLeadCand(jet);
0133 if (leadCand.isNull())
0134 return reco::TrackBaseRef();
0135 return getTrackRef(*leadCand);
0136 }
0137
0138 namespace {
0139
0140
0141 double dzToTrack(const reco::VertexRef& vtx, const reco::Track* trk) {
0142 if (!trk || !vtx) {
0143 return std::numeric_limits<double>::infinity();
0144 }
0145 return std::abs(trk->dz(vtx->position()));
0146 }
0147
0148 double trackWeightInVertex(const reco::VertexRef& vtx, const reco::TrackBaseRef& trk) {
0149 if (!trk || !vtx) {
0150 return 0.0;
0151 }
0152 return vtx->trackWeight(trk);
0153 }
0154 }
0155
0156 RecoTauVertexAssociator::RecoTauVertexAssociator(const edm::ParameterSet& pset, edm::ConsumesCollector&& iC)
0157 : vertexSelector_(nullptr), qcuts_(nullptr), jetToVertexAssociation_(nullptr), lastEvent_(0) {
0158
0159
0160 vertexTag_ = edm::InputTag("offlinePrimaryVertices", "");
0161 algorithm_ = "highestPtInEvent";
0162
0163 if (!pset.exists("primaryVertexSrc") || !pset.exists("pvFindingAlgo")) {
0164 edm::LogWarning("NoVertexFindingMethodSpecified")
0165 << "The PSet passed to the RecoTauVertexAssociator was incorrectly configured."
0166 << " The vertex will be taken as the highest Pt vertex from the 'offlinePrimaryVertices' collection."
0167 << std::endl;
0168 } else {
0169 vertexTag_ = pset.getParameter<edm::InputTag>("primaryVertexSrc");
0170 algorithm_ = pset.getParameter<std::string>("pvFindingAlgo");
0171 }
0172
0173 if (pset.exists("vxAssocQualityCuts")) {
0174
0175 qcuts_ = std::make_unique<RecoTauQualityCuts>(pset.getParameterSet("vxAssocQualityCuts"));
0176 } else {
0177
0178 qcuts_ = std::make_unique<RecoTauQualityCuts>(pset.getParameterSet("signalQualityCuts"));
0179 }
0180 assert(qcuts_);
0181
0182 vxTrkFiltering_ = false;
0183 if (!pset.exists("vertexTrackFiltering") && pset.exists("vxAssocQualityCuts")) {
0184 edm::LogWarning("NoVertexTrackFilteringSpecified")
0185 << "The PSet passed to the RecoTauVertexAssociator was incorrectly configured."
0186 << " Please define vertexTrackFiltering in config file."
0187 << " No filtering of tracks to vertices will be applied." << std::endl;
0188 } else {
0189 vxTrkFiltering_ = pset.exists("vertexTrackFiltering") ? pset.getParameter<bool>("vertexTrackFiltering") : false;
0190 }
0191 if (pset.exists("vertexSelection")) {
0192 std::string vertexSelection = pset.getParameter<std::string>("vertexSelection");
0193 if (!vertexSelection.empty()) {
0194 vertexSelector_ = std::make_unique<StringCutObjectSelector<reco::Vertex>>(vertexSelection);
0195 }
0196 }
0197
0198 if (algorithm_ == "highestPtInEvent") {
0199 algo_ = kHighestPtInEvent;
0200 } else if (algorithm_ == "closestInDeltaZ") {
0201 algo_ = kClosestDeltaZ;
0202 } else if (algorithm_ == "highestWeightForLeadTrack") {
0203 algo_ = kHighestWeigtForLeadTrack;
0204 } else if (algorithm_ == "combined") {
0205 algo_ = kCombined;
0206 } else {
0207 throw cms::Exception("BadVertexAssociatorConfig")
0208 << "Invalid Configuration parameter 'algorithm' " << algorithm_ << "."
0209 << " Valid options are: 'highestPtInEvent', 'closestInDeltaZ', 'highestWeightForLeadTrack' and "
0210 "'combined'.\n";
0211 }
0212
0213 vxToken_ = iC.consumes<reco::VertexCollection>(vertexTag_);
0214
0215 recoverLeadingTrk_ = pset.exists("recoverLeadingTrk") ? pset.getParameter<bool>("recoverLeadingTrk") : false;
0216
0217 std::string leadingTrkOrPFCandOption_string = pset.exists("leadingTrkOrPFCandOption")
0218 ? pset.getParameter<std::string>("leadingTrkOrPFCandOption")
0219 : "firstTrack";
0220 if (leadingTrkOrPFCandOption_string == "leadTrack")
0221 leadingTrkOrPFCandOption_ = kLeadTrack;
0222 else if (leadingTrkOrPFCandOption_string == "leadPFCand")
0223 leadingTrkOrPFCandOption_ = kLeadPFCand;
0224 else if (leadingTrkOrPFCandOption_string == "minLeadTrackOrPFCand")
0225 leadingTrkOrPFCandOption_ = kMinLeadTrackOrPFCand;
0226 else if (leadingTrkOrPFCandOption_string == "firstTrack")
0227 leadingTrkOrPFCandOption_ = kFirstTrack;
0228 else
0229 throw cms::Exception("BadVertexAssociatorConfig")
0230 << "Invalid Configuration parameter 'leadingTrkOrPFCandOption' " << leadingTrkOrPFCandOption_string << "."
0231 << " Valid options are: 'leadTrack', 'leadPFCand', 'firstTrack'.\n";
0232
0233 verbosity_ = (pset.exists("verbosity")) ? pset.getParameter<int>("verbosity") : 0;
0234 }
0235
0236 void RecoTauVertexAssociator::setEvent(const edm::Event& evt) {
0237 edm::Handle<reco::VertexCollection> vertices;
0238 evt.getByToken(vxToken_, vertices);
0239 selectedVertices_.clear();
0240 selectedVertices_.reserve(vertices->size());
0241 for (size_t idxVertex = 0; idxVertex < vertices->size(); ++idxVertex) {
0242 reco::VertexRef vertex(vertices, idxVertex);
0243 if (vertexSelector_ && !(*vertexSelector_)(*vertex))
0244 continue;
0245 selectedVertices_.push_back(vertex);
0246 }
0247 if (!selectedVertices_.empty()) {
0248 qcuts_->setPV(selectedVertices_[0]);
0249 }
0250 edm::EventNumber_t currentEvent = evt.id().event();
0251 if (currentEvent != lastEvent_ || !jetToVertexAssociation_) {
0252 if (!jetToVertexAssociation_)
0253 jetToVertexAssociation_ = std::make_unique<JetToVtxAssoc>();
0254 else
0255 jetToVertexAssociation_->clear();
0256 lastEvent_ = currentEvent;
0257 }
0258 }
0259
0260 reco::VertexRef RecoTauVertexAssociator::associatedVertex(const PFTau& tau, bool useJet) const {
0261 if (!useJet) {
0262 if (tau.leadChargedHadrCand().isNonnull()) {
0263 const reco::Track* track = getTrack(*tau.leadChargedHadrCand());
0264 if (track != nullptr)
0265 return associatedVertex(track);
0266 }
0267 }
0268
0269 reco::JetBaseRef jetRef = tau.jetRef();
0270
0271 if (jetRef.isNull())
0272 jetRef = tau.pfTauTagInfoRef()->pfjetRef();
0273 return associatedVertex(*jetRef);
0274 }
0275
0276 reco::VertexRef RecoTauVertexAssociator::associatedVertex(const Track* track) const {
0277 reco::VertexRef trkVertex = (!selectedVertices_.empty()) ? selectedVertices_[0] : reco::VertexRef();
0278
0279
0280 if (algo_ == kHighestPtInEvent) {
0281 if (!selectedVertices_.empty())
0282 trkVertex = selectedVertices_[0];
0283 } else if (algo_ == kClosestDeltaZ) {
0284 if (track) {
0285 double closestDistance = 1.e+6;
0286
0287 int idxVertex = 0;
0288 for (std::vector<reco::VertexRef>::const_iterator selectedVertex = selectedVertices_.begin();
0289 selectedVertex != selectedVertices_.end();
0290 ++selectedVertex) {
0291 double dZ = dzToTrack(*selectedVertex, track);
0292 if (verbosity_) {
0293 std::cout << "vertex #" << idxVertex << ": x = " << (*selectedVertex)->position().x()
0294 << ", y = " << (*selectedVertex)->position().y()
0295 << ", z = " << (*selectedVertex)->position().z() << " --> dZ = " << dZ << std::endl;
0296 }
0297 if (dZ < closestDistance) {
0298 trkVertex = (*selectedVertex);
0299 closestDistance = dZ;
0300 }
0301 ++idxVertex;
0302 }
0303 }
0304 }
0305
0306 if (verbosity_ >= 1) {
0307 std::cout << "--> returning vertex: x = " << trkVertex->position().x() << ", y = " << trkVertex->position().y()
0308 << ", z = " << trkVertex->position().z() << std::endl;
0309 }
0310
0311 return trkVertex;
0312 }
0313
0314 reco::VertexRef RecoTauVertexAssociator::associatedVertex(const TrackBaseRef& track) const {
0315 reco::VertexRef trkVertex = (!selectedVertices_.empty()) ? selectedVertices_[0] : reco::VertexRef();
0316
0317 if (algo_ == kHighestWeigtForLeadTrack || algo_ == kCombined) {
0318 if (track.isNonnull()) {
0319 double largestWeight = -1.;
0320
0321 int idxVertex = 0;
0322 for (std::vector<reco::VertexRef>::const_iterator selectedVertex = selectedVertices_.begin();
0323 selectedVertex != selectedVertices_.end();
0324 ++selectedVertex) {
0325 double weight = trackWeightInVertex(*selectedVertex, track);
0326 if (verbosity_) {
0327 std::cout << "vertex #" << idxVertex << ": x = " << (*selectedVertex)->position().x()
0328 << ", y = " << (*selectedVertex)->position().y()
0329 << ", z = " << (*selectedVertex)->position().z() << " --> weight = " << weight << std::endl;
0330 }
0331 if (weight > largestWeight) {
0332 trkVertex = (*selectedVertex);
0333 largestWeight = weight;
0334 }
0335 ++idxVertex;
0336 }
0337
0338 if (algo_ == kCombined && largestWeight < 1.e-7) {
0339 if (verbosity_) {
0340 std::cout << "No vertex had positive weight! Trying dZ instead... " << std::endl;
0341 }
0342 double closestDistance = 1.e+6;
0343
0344 int idxVertex = 0;
0345 for (std::vector<reco::VertexRef>::const_iterator selectedVertex = selectedVertices_.begin();
0346 selectedVertex != selectedVertices_.end();
0347 ++selectedVertex) {
0348 double dZ = dzToTrack(*selectedVertex, track.get());
0349 if (verbosity_) {
0350 std::cout << "vertex #" << idxVertex << ": x = " << (*selectedVertex)->position().x()
0351 << ", y = " << (*selectedVertex)->position().y()
0352 << ", z = " << (*selectedVertex)->position().z() << " --> dZ = " << dZ << std::endl;
0353 }
0354 if (dZ < closestDistance) {
0355 trkVertex = (*selectedVertex);
0356 closestDistance = dZ;
0357 }
0358 ++idxVertex;
0359 }
0360 }
0361 }
0362 }
0363
0364 if (verbosity_ >= 1) {
0365 std::cout << "--> returning vertex: x = " << trkVertex->position().x() << ", y = " << trkVertex->position().y()
0366 << ", z = " << trkVertex->position().z() << std::endl;
0367 }
0368
0369 return trkVertex;
0370 }
0371
0372 reco::VertexRef RecoTauVertexAssociator::associatedVertex(const Jet& jet) const {
0373 if (verbosity_ >= 1) {
0374 std::cout << "<RecoTauVertexAssociator::associatedVertex>:" << std::endl;
0375 std::cout << " jet: Pt = " << jet.pt() << ", eta = " << jet.eta() << ", phi = " << jet.phi() << std::endl;
0376 std::cout << " num. Vertices = " << selectedVertices_.size() << std::endl;
0377 std::cout << " size(jetToVertexAssociation) = " << jetToVertexAssociation_->size() << std::endl;
0378 std::cout << " vertexTag = " << vertexTag_ << std::endl;
0379 std::cout << " algorithm = " << algorithm_ << std::endl;
0380 std::cout << " recoverLeadingTrk = " << recoverLeadingTrk_ << std::endl;
0381 }
0382
0383 reco::VertexRef jetVertex = (!selectedVertices_.empty()) ? selectedVertices_[0] : reco::VertexRef();
0384 const Jet* jetPtr = &jet;
0385
0386
0387 auto vertexPtr = jetToVertexAssociation_->find(jetPtr);
0388 if (vertexPtr != jetToVertexAssociation_->end()) {
0389 jetVertex = vertexPtr->second;
0390 } else {
0391
0392 if (algo_ == kHighestPtInEvent) {
0393 if (!selectedVertices_.empty())
0394 jetVertex = selectedVertices_[0];
0395 } else if (algo_ == kClosestDeltaZ) {
0396
0397 const reco::Track* leadTrack = getLeadTrack(jet);
0398 if (verbosity_) {
0399 if (leadTrack != nullptr)
0400 std::cout << "leadTrack: Pt = " << leadTrack->pt() << ", eta = " << leadTrack->eta()
0401 << ", phi = " << leadTrack->phi() << std::endl;
0402 else
0403 std::cout << "leadTrack: N/A" << std::endl;
0404 }
0405 if (leadTrack != nullptr) {
0406 jetVertex = associatedVertex(leadTrack);
0407 }
0408 } else if (algo_ == kHighestWeigtForLeadTrack || algo_ == kCombined) {
0409
0410 const reco::TrackBaseRef leadTrack = getLeadTrackRef(jet);
0411 if (verbosity_) {
0412 if (leadTrack.isNonnull())
0413 std::cout << "leadTrack: Pt = " << leadTrack->pt() << ", eta = " << leadTrack->eta()
0414 << ", phi = " << leadTrack->phi() << std::endl;
0415 else
0416 std::cout << "leadTrack: N/A" << std::endl;
0417 }
0418 if (leadTrack.isNonnull()) {
0419 jetVertex = associatedVertex(leadTrack);
0420 }
0421 }
0422
0423 jetToVertexAssociation_->insert({jetPtr, jetVertex});
0424 }
0425
0426 if (verbosity_ >= 1) {
0427 std::cout << "--> returning vertex: x = " << jetVertex->position().x() << ", y = " << jetVertex->position().y()
0428 << ", z = " << jetVertex->position().z() << std::endl;
0429 }
0430
0431 return jetVertex;
0432 }
0433
0434 }
0435 }