CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
TemplatedSecondaryVertexProducer.cc
Go to the documentation of this file.
1 #include <algorithm>
2 #include <cstddef>
3 #include <functional>
4 #include <iterator>
5 #include <map>
6 #include <memory>
7 #include <set>
8 #include <string>
9 #include <vector>
10 
11 #include <boost/iterator/transform_iterator.hpp>
12 
25 
29 
34 
39 
47 
52 
58 
60 
61 #include "fastjet/JetDefinition.hh"
62 #include "fastjet/ClusterSequence.hh"
63 #include "fastjet/PseudoJet.hh"
64 
65 //
66 // constants, enums and typedefs
67 //
68 typedef std::shared_ptr<fastjet::ClusterSequence> ClusterSequencePtr;
69 typedef std::shared_ptr<fastjet::JetDefinition> JetDefPtr;
70 
71 using namespace reco;
72 
73 namespace {
74  class VertexInfo : public fastjet::PseudoJet::UserInfoBase {
75  public:
76  VertexInfo(const int vertexIndex) : m_vertexIndex(vertexIndex) {}
77 
78  inline const int vertexIndex() const { return m_vertexIndex; }
79 
80  protected:
81  int m_vertexIndex;
82  };
83 
84  template <typename T>
85  struct RefToBaseLess {
86  inline bool operator()(const edm::RefToBase<T> &r1, const edm::RefToBase<T> &r2) const {
87  return r1.id() < r2.id() || (r1.id() == r2.id() && r1.key() < r2.key());
88  }
89  };
90 } // namespace
91 
93  return GlobalVector(sv.x() - pv.x(), sv.y() - pv.y(), sv.z() - pv.z());
94 }
96  return GlobalVector(sv.vertex().x() - pv.x(), sv.vertex().y() - pv.y(), sv.vertex().z() - pv.z());
97 }
98 const math::XYZPoint &position(const reco::Vertex &sv) { return sv.position(); }
100 
101 template <class IPTI, class VTX>
103 public:
106  static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
107  typedef std::vector<TemplatedSecondaryVertexTagInfo<IPTI, VTX> > Product;
109  typedef typename IPTI::input_container input_container;
111  typedef typename std::vector<reco::btag::IndexedTrackData> TrackDataVector;
112  void produce(edm::Event &event, const edm::EventSetup &es) override;
113 
114 private:
115  template <class CONTAINER>
116  void matchReclusteredJets(const edm::Handle<CONTAINER> &jets,
117  const std::vector<fastjet::PseudoJet> &matchedJets,
118  std::vector<int> &matchedIndices,
119  const std::string &jetType = "");
120  void matchGroomedJets(const edm::Handle<edm::View<reco::Jet> > &jets,
121  const edm::Handle<edm::View<reco::Jet> > &matchedJets,
122  std::vector<int> &matchedIndices);
123  void matchSubjets(const std::vector<int> &groomedIndices,
124  const edm::Handle<edm::View<reco::Jet> > &groomedJets,
125  const edm::Handle<std::vector<IPTI> > &subjets,
126  std::vector<std::vector<int> > &matchedIndices);
127  void matchSubjets(const edm::Handle<edm::View<reco::Jet> > &fatJets,
128  const edm::Handle<std::vector<IPTI> > &subjets,
129  std::vector<std::vector<int> > &matchedIndices);
130 
131  const reco::Jet *toJet(const reco::Jet &j) { return &j; }
132  const reco::Jet *toJet(const IPTI &j) { return &(*(j.jet())); }
133 
135  CONSTRAINT_NONE = 0,
140  CONSTRAINT_PV_PRIMARIES_IN_FIT
141  };
142  static ConstraintType getConstraintType(const std::string &name);
143 
162  double rParam;
163  double jetPtMin;
172 
175 
176  void markUsedTracks(TrackDataVector &trackData,
177  const input_container &trackRefs,
178  const SecondaryVertex &sv,
179  size_t idx);
180 
181  struct SVBuilder {
182  SVBuilder(const reco::Vertex &pv, const GlobalVector &direction, bool withPVError, double minTrackWeight)
183  : pv(pv), direction(direction), withPVError(withPVError), minTrackWeight(minTrackWeight) {}
184  SecondaryVertex operator()(const TransientVertex &sv) const;
185 
186  SecondaryVertex operator()(const VTX &sv) const { return SecondaryVertex(pv, sv, direction, withPVError); }
187 
188  const Vertex &pv;
192  };
193 
194  struct SVFilter {
195  SVFilter(const VertexFilter &filter, const Vertex &pv, const GlobalVector &direction)
196  : filter(filter), pv(pv), direction(direction) {}
197 
198  inline bool operator()(const SecondaryVertex &sv) const { return !filter(pv, sv, direction); }
199 
201  const Vertex &pv;
203  };
204 };
205 template <class IPTI, class VTX>
208  if (name == "None")
209  return CONSTRAINT_NONE;
210  else if (name == "BeamSpot")
211  return CONSTRAINT_BEAMSPOT;
212  else if (name == "BeamSpot+PVPosition")
213  return CONSTRAINT_PV_BEAMSPOT_SIZE;
214  else if (name == "BeamSpotZ+PVErrorScaledXY")
215  return CONSTRAINT_PV_BS_Z_ERRORS_SCALED;
216  else if (name == "PVErrorScaled")
217  return CONSTRAINT_PV_ERROR_SCALED;
218  else if (name == "BeamSpot+PVTracksInFit")
219  return CONSTRAINT_PV_PRIMARIES_IN_FIT;
220  else
221  throw cms::Exception("InvalidArgument") << "TemplatedSecondaryVertexProducer: ``constraint'' parameter "
222  "value \""
223  << name << "\" not understood." << std::endl;
224 }
225 
227  if (name == "AlwaysWithGhostTrack")
229  else if (name == "SingleTracksWithGhostTrack")
231  else if (name == "RefitGhostTrackWithVertices")
233  else
234  throw cms::Exception("InvalidArgument") << "TemplatedSecondaryVertexProducer: ``fitType'' "
235  "parameter value \""
236  << name
237  << "\" for "
238  "GhostTrackVertexFinder settings not "
239  "understood."
240  << std::endl;
241 }
242 
243 template <class IPTI, class VTX>
245  : sortCriterium(TrackSorting::getCriterium(params.getParameter<std::string>("trackSort"))),
246  trackSelector(params.getParameter<edm::ParameterSet>("trackSelection")),
247  constraint(getConstraintType(params.getParameter<std::string>("constraint"))),
248  constraintScaling(1.0),
249  vtxRecoPSet(params.getParameter<edm::ParameterSet>("vertexReco")),
250  useGhostTrack(vtxRecoPSet.getParameter<std::string>("finder") == "gtvr"),
251  withPVError(params.getParameter<bool>("usePVError")),
252  minTrackWeight(params.getParameter<double>("minimumTrackWeight")),
253  vertexFilter(params.getParameter<edm::ParameterSet>("vertexCuts")),
254  vertexSorting(params.getParameter<edm::ParameterSet>("vertexSelection")) {
255  token_trackIPTagInfo = consumes<std::vector<IPTI> >(params.getParameter<edm::InputTag>("trackIPTagInfos"));
257  constraintScaling = params.getParameter<double>("pvErrorScaling");
258 
261  token_BeamSpot = consumes<reco::BeamSpot>(params.getParameter<edm::InputTag>("beamSpotTag"));
262  useExternalSV = false;
263  if (params.existsAs<bool>("useExternalSV"))
264  useExternalSV = params.getParameter<bool>("useExternalSV");
265  if (useExternalSV) {
266  token_extSVCollection = consumes<edm::View<VTX> >(params.getParameter<edm::InputTag>("extSVCollection"));
267  extSVDeltaRToJet = params.getParameter<double>("extSVDeltaRToJet");
268  }
269  useSVClustering = (params.existsAs<bool>("useSVClustering") ? params.getParameter<bool>("useSVClustering") : false);
270  useSVMomentum = (params.existsAs<bool>("useSVMomentum") ? params.getParameter<bool>("useSVMomentum") : false);
271  useFatJets = (useExternalSV && params.exists("fatJets"));
272  useGroomedFatJets = (useExternalSV && params.exists("groomedFatJets"));
273  if (useSVClustering) {
274  jetAlgorithm = params.getParameter<std::string>("jetAlgorithm");
275  rParam = params.getParameter<double>("rParam");
276  jetPtMin =
277  0.; // hardcoded to 0. since we simply want to recluster all input jets which already had some PtMin applied
279  (params.existsAs<double>("ghostRescaling") ? params.getParameter<double>("ghostRescaling") : 1e-18);
281  (params.existsAs<double>("relPtTolerance")
282  ? params.getParameter<double>("relPtTolerance")
283  : 1e-03); // 0.1% relative difference in Pt should be sufficient to detect possible misconfigurations
284 
285  // set jet algorithm
286  if (jetAlgorithm == "Kt")
287  fjJetDefinition = std::make_shared<fastjet::JetDefinition>(fastjet::kt_algorithm, rParam);
288  else if (jetAlgorithm == "CambridgeAachen")
289  fjJetDefinition = std::make_shared<fastjet::JetDefinition>(fastjet::cambridge_algorithm, rParam);
290  else if (jetAlgorithm == "AntiKt")
291  fjJetDefinition = std::make_shared<fastjet::JetDefinition>(fastjet::antikt_algorithm, rParam);
292  else
293  throw cms::Exception("InvalidJetAlgorithm") << "Jet clustering algorithm is invalid: " << jetAlgorithm
294  << ", use CambridgeAachen | Kt | AntiKt" << std::endl;
295  }
297  esConsumes<TransientTrackBuilder, TransientTrackRecord>(edm::ESInputTag("", "TransientTrackBuilder"));
298  if (useFatJets) {
299  token_fatJets = consumes<edm::View<reco::Jet> >(params.getParameter<edm::InputTag>("fatJets"));
300  }
301  edm::InputTag srcWeights = params.getParameter<edm::InputTag>("weights");
302  if (!srcWeights.label().empty())
303  token_weights = consumes<edm::ValueMap<float> >(srcWeights);
304  if (useGroomedFatJets) {
305  token_groomedFatJets = consumes<edm::View<reco::Jet> >(params.getParameter<edm::InputTag>("groomedFatJets"));
306  }
307  if (useFatJets && !useSVClustering)
308  rParam = params.getParameter<double>("rParam"); // will be used later as a dR cut
309 
310  produces<Product>();
311 }
312 template <class IPTI, class VTX>
314 
315 template <class IPTI, class VTX>
317  // typedef std::map<TrackBaseRef, TransientTrack,
318  // RefToBaseLess<Track> > TransientTrackMap;
319  //How about good old pointers?
320  typedef std::map<const Track *, TransientTrack> TransientTrackMap;
321 
322  edm::ESHandle<TransientTrackBuilder> trackBuilder = es.getHandle(token_trackBuilder);
323 
325  event.getByToken(token_trackIPTagInfo, trackIPTagInfos);
326 
327  // External Sec Vertex collection (e.g. for IVF usage)
328  edm::Handle<edm::View<VTX> > extSecVertex;
329  if (useExternalSV)
330  event.getByToken(token_extSVCollection, extSecVertex);
331 
332  edm::Handle<edm::View<reco::Jet> > fatJetsHandle;
333  edm::Handle<edm::View<reco::Jet> > groomedFatJetsHandle;
334  if (useFatJets) {
335  event.getByToken(token_fatJets, fatJetsHandle);
336  if (useGroomedFatJets) {
337  event.getByToken(token_groomedFatJets, groomedFatJetsHandle);
338 
339  if (groomedFatJetsHandle->size() > fatJetsHandle->size())
340  edm::LogError("TooManyGroomedJets")
341  << "There are more groomed (" << groomedFatJetsHandle->size() << ") than original fat jets ("
342  << fatJetsHandle->size() << "). Please check that the two jet collections belong to each other.";
343  }
344  }
345  edm::Handle<edm::ValueMap<float> > weightsHandle;
346  if (!token_weights.isUninitialized())
347  event.getByToken(token_weights, weightsHandle);
348 
350  unsigned int bsCovSrc[7] = {
351  0,
352  };
353  double sigmaZ = 0.0, beamWidth = 0.0;
354  switch (constraint) {
355  case CONSTRAINT_PV_BEAMSPOT_SIZE:
356  event.getByToken(token_BeamSpot, beamSpot);
357  bsCovSrc[3] = bsCovSrc[4] = bsCovSrc[5] = bsCovSrc[6] = 1;
358  sigmaZ = beamSpot->sigmaZ();
359  beamWidth = beamSpot->BeamWidthX();
360  break;
361 
362  case CONSTRAINT_PV_BS_Z_ERRORS_SCALED:
363  event.getByToken(token_BeamSpot, beamSpot);
364  bsCovSrc[0] = bsCovSrc[1] = 2;
365  bsCovSrc[3] = bsCovSrc[4] = bsCovSrc[5] = 1;
366  sigmaZ = beamSpot->sigmaZ();
367  break;
368 
369  case CONSTRAINT_PV_ERROR_SCALED:
370  bsCovSrc[0] = bsCovSrc[1] = bsCovSrc[2] = 2;
371  break;
372 
373  case CONSTRAINT_BEAMSPOT:
374  case CONSTRAINT_PV_PRIMARIES_IN_FIT:
375  event.getByToken(token_BeamSpot, beamSpot);
376  break;
377 
378  default:
379  /* nothing */;
380  }
381 
382  // ------------------------------------ SV clustering START --------------------------------------------
383  std::vector<std::vector<int> > clusteredSVs(trackIPTagInfos->size(), std::vector<int>());
384  if (useExternalSV && useSVClustering && !trackIPTagInfos->empty()) {
385  // vector of constituents for reclustering jets and "ghost" SVs
386  std::vector<fastjet::PseudoJet> fjInputs;
387  // loop over all input jets and collect all their constituents
388  if (useFatJets) {
389  for (edm::View<reco::Jet>::const_iterator it = fatJetsHandle->begin(); it != fatJetsHandle->end(); ++it) {
390  std::vector<edm::Ptr<reco::Candidate> > constituents = it->getJetConstituents();
391  std::vector<edm::Ptr<reco::Candidate> >::const_iterator m;
392  for (m = constituents.begin(); m != constituents.end(); ++m) {
393  reco::CandidatePtr constit = *m;
394  if (constit->pt() == 0) {
395  edm::LogWarning("NullTransverseMomentum") << "dropping input candidate with pt=0";
396  continue;
397  }
398  if (it->isWeighted()) {
399  if (token_weights.isUninitialized())
400  throw cms::Exception("MissingConstituentWeight")
401  << "TemplatedSecondaryVertexProducer: No weights (e.g. PUPPI) given for weighted jet collection"
402  << std::endl;
403  float w = (*weightsHandle)[constit];
404  fjInputs.push_back(
405  fastjet::PseudoJet(constit->px() * w, constit->py() * w, constit->pz() * w, constit->energy() * w));
406  } else {
407  fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
408  }
409  }
410  }
411  } else {
412  for (typename std::vector<IPTI>::const_iterator it = trackIPTagInfos->begin(); it != trackIPTagInfos->end();
413  ++it) {
414  std::vector<edm::Ptr<reco::Candidate> > constituents = it->jet()->getJetConstituents();
415  std::vector<edm::Ptr<reco::Candidate> >::const_iterator m;
416  for (m = constituents.begin(); m != constituents.end(); ++m) {
417  reco::CandidatePtr constit = *m;
418  if (constit->pt() == 0) {
419  edm::LogWarning("NullTransverseMomentum") << "dropping input candidate with pt=0";
420  continue;
421  }
422  if (it->jet()->isWeighted()) {
423  if (token_weights.isUninitialized())
424  throw cms::Exception("MissingConstituentWeight")
425  << "TemplatedSecondaryVertexProducer: No weights (e.g. PUPPI) given for weighted jet collection"
426  << std::endl;
427  float w = (*weightsHandle)[constit];
428  fjInputs.push_back(
429  fastjet::PseudoJet(constit->px() * w, constit->py() * w, constit->pz() * w, constit->energy() * w));
430  } else {
431  fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
432  }
433  }
434  }
435  }
436  // insert "ghost" SVs in the vector of constituents
437  for (typename edm::View<VTX>::const_iterator it = extSecVertex->begin(); it != extSecVertex->end(); ++it) {
438  const reco::Vertex &pv = *(trackIPTagInfos->front().primaryVertex());
439  GlobalVector dir = flightDirection(pv, *it);
440  dir = dir.unit();
441  fastjet::PseudoJet p(
442  dir.x(), dir.y(), dir.z(), dir.mag()); // using SV flight direction so treating SV as massless
443  if (useSVMomentum)
444  p = fastjet::PseudoJet(it->p4().px(), it->p4().py(), it->p4().pz(), it->p4().energy());
445  p *= ghostRescaling; // rescale SV direction/momentum
446  p.set_user_info(new VertexInfo(it - extSecVertex->begin()));
447  fjInputs.push_back(p);
448  }
449 
450  // define jet clustering sequence
451  fjClusterSeq = std::make_shared<fastjet::ClusterSequence>(fjInputs, *fjJetDefinition);
452  // recluster jet constituents and inserted "ghosts"
453  std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(fjClusterSeq->inclusive_jets(jetPtMin));
454 
455  if (useFatJets) {
456  if (inclusiveJets.size() < fatJetsHandle->size())
457  edm::LogError("TooFewReclusteredJets")
458  << "There are fewer reclustered (" << inclusiveJets.size() << ") than original fat jets ("
459  << fatJetsHandle->size()
460  << "). Please check that the jet algorithm and jet size match those used for the original jet collection.";
461 
462  // match reclustered and original fat jets
463  std::vector<int> reclusteredIndices;
464  matchReclusteredJets<edm::View<reco::Jet> >(fatJetsHandle, inclusiveJets, reclusteredIndices, "fat");
465 
466  // match groomed and original fat jets
467  std::vector<int> groomedIndices;
468  if (useGroomedFatJets)
469  matchGroomedJets(fatJetsHandle, groomedFatJetsHandle, groomedIndices);
470 
471  // match subjets and original fat jets
472  std::vector<std::vector<int> > subjetIndices;
473  if (useGroomedFatJets)
474  matchSubjets(groomedIndices, groomedFatJetsHandle, trackIPTagInfos, subjetIndices);
475  else
476  matchSubjets(fatJetsHandle, trackIPTagInfos, subjetIndices);
477 
478  // collect clustered SVs
479  for (size_t i = 0; i < fatJetsHandle->size(); ++i) {
480  if (reclusteredIndices.at(i) < 0)
481  continue; // continue if matching reclustered to original jets failed
482 
483  if (fatJetsHandle->at(i).pt() == 0) // continue if the original jet has Pt=0
484  {
485  edm::LogWarning("NullTransverseMomentum")
486  << "The original fat jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
487  continue;
488  }
489 
490  if (subjetIndices.at(i).empty())
491  continue; // continue if the original jet does not have subjets assigned
492 
493  // since the "ghosts" are extremely soft, the configuration and ordering of the reclustered and original fat jets should in principle stay the same
494  if ((std::abs(inclusiveJets.at(reclusteredIndices.at(i)).pt() - fatJetsHandle->at(i).pt()) /
495  fatJetsHandle->at(i).pt()) > relPtTolerance) {
496  if (fatJetsHandle->at(i).pt() < 10.) // special handling for low-Pt jets (Pt<10 GeV)
497  edm::LogWarning("JetPtMismatchAtLowPt")
498  << "The reclustered and original fat jet " << i << " have different Pt's ("
499  << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << fatJetsHandle->at(i).pt()
500  << " GeV, respectively).\n"
501  << "Please check that the jet algorithm and jet size match those used for the original fat jet "
502  "collection and also make sure the original fat jets are uncorrected. In addition, make sure you "
503  "are not using CaloJets which are presently not supported.\n"
504  << "Since the mismatch is at low Pt, it is ignored and only a warning is issued.\n"
505  << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine "
506  "precision in which case make sure the original jet collection is produced and reclustering is "
507  "performed in the same job.";
508  else
509  edm::LogError("JetPtMismatch")
510  << "The reclustered and original fat jet " << i << " have different Pt's ("
511  << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << fatJetsHandle->at(i).pt()
512  << " GeV, respectively).\n"
513  << "Please check that the jet algorithm and jet size match those used for the original fat jet "
514  "collection and also make sure the original fat jets are uncorrected. In addition, make sure you "
515  "are not using CaloJets which are presently not supported.\n"
516  << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine "
517  "precision in which case make sure the original jet collection is produced and reclustering is "
518  "performed in the same job.";
519  }
520 
521  // get jet constituents
522  std::vector<fastjet::PseudoJet> constituents = inclusiveJets.at(reclusteredIndices.at(i)).constituents();
523 
524  std::vector<int> svIndices;
525  // loop over jet constituents and try to find "ghosts"
526  for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end();
527  ++it) {
528  if (!it->has_user_info())
529  continue; // skip if not a "ghost"
530 
531  svIndices.push_back(it->user_info<VertexInfo>().vertexIndex());
532  }
533 
534  // loop over clustered SVs and assign them to different subjets based on smallest dR
535  for (size_t sv = 0; sv < svIndices.size(); ++sv) {
536  const reco::Vertex &pv = *(trackIPTagInfos->front().primaryVertex());
537  const VTX &extSV = (*extSecVertex)[svIndices.at(sv)];
538  GlobalVector dir = flightDirection(pv, extSV);
539  dir = dir.unit();
540  fastjet::PseudoJet p(
541  dir.x(), dir.y(), dir.z(), dir.mag()); // using SV flight direction so treating SV as massless
542  if (useSVMomentum)
543  p = fastjet::PseudoJet(extSV.p4().px(), extSV.p4().py(), extSV.p4().pz(), extSV.p4().energy());
544 
545  std::vector<double> dR2toSubjets;
546 
547  for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj)
548  dR2toSubjets.push_back(Geom::deltaR2(p.rapidity(),
549  p.phi_std(),
550  trackIPTagInfos->at(subjetIndices.at(i).at(sj)).jet()->rapidity(),
551  trackIPTagInfos->at(subjetIndices.at(i).at(sj)).jet()->phi()));
552 
553  // find the closest subjet
554  int closestSubjetIdx =
555  std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
556 
557  clusteredSVs.at(subjetIndices.at(i).at(closestSubjetIdx)).push_back(svIndices.at(sv));
558  }
559  }
560  } else {
561  if (inclusiveJets.size() < trackIPTagInfos->size())
562  edm::LogError("TooFewReclusteredJets")
563  << "There are fewer reclustered (" << inclusiveJets.size() << ") than original jets ("
564  << trackIPTagInfos->size()
565  << "). Please check that the jet algorithm and jet size match those used for the original jet collection.";
566 
567  // match reclustered and original jets
568  std::vector<int> reclusteredIndices;
569  matchReclusteredJets<std::vector<IPTI> >(trackIPTagInfos, inclusiveJets, reclusteredIndices);
570 
571  // collect clustered SVs
572  for (size_t i = 0; i < trackIPTagInfos->size(); ++i) {
573  if (reclusteredIndices.at(i) < 0)
574  continue; // continue if matching reclustered to original jets failed
575 
576  if (trackIPTagInfos->at(i).jet()->pt() == 0) // continue if the original jet has Pt=0
577  {
578  edm::LogWarning("NullTransverseMomentum")
579  << "The original jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
580  continue;
581  }
582 
583  // since the "ghosts" are extremely soft, the configuration and ordering of the reclustered and original jets should in principle stay the same
584  if ((std::abs(inclusiveJets.at(reclusteredIndices.at(i)).pt() - trackIPTagInfos->at(i).jet()->pt()) /
585  trackIPTagInfos->at(i).jet()->pt()) > relPtTolerance) {
586  if (trackIPTagInfos->at(i).jet()->pt() < 10.) // special handling for low-Pt jets (Pt<10 GeV)
587  edm::LogWarning("JetPtMismatchAtLowPt")
588  << "The reclustered and original jet " << i << " have different Pt's ("
589  << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << trackIPTagInfos->at(i).jet()->pt()
590  << " GeV, respectively).\n"
591  << "Please check that the jet algorithm and jet size match those used for the original jet collection "
592  "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
593  "CaloJets which are presently not supported.\n"
594  << "Since the mismatch is at low Pt, it is ignored and only a warning is issued.\n"
595  << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine "
596  "precision in which case make sure the original jet collection is produced and reclustering is "
597  "performed in the same job.";
598  else
599  edm::LogError("JetPtMismatch")
600  << "The reclustered and original jet " << i << " have different Pt's ("
601  << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << trackIPTagInfos->at(i).jet()->pt()
602  << " GeV, respectively).\n"
603  << "Please check that the jet algorithm and jet size match those used for the original jet collection "
604  "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
605  "CaloJets which are presently not supported.\n"
606  << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine "
607  "precision in which case make sure the original jet collection is produced and reclustering is "
608  "performed in the same job.";
609  }
610 
611  // get jet constituents
612  std::vector<fastjet::PseudoJet> constituents = inclusiveJets.at(reclusteredIndices.at(i)).constituents();
613 
614  // loop over jet constituents and try to find "ghosts"
615  for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end();
616  ++it) {
617  if (!it->has_user_info())
618  continue; // skip if not a "ghost"
619  // push back clustered SV indices
620  clusteredSVs.at(i).push_back(it->user_info<VertexInfo>().vertexIndex());
621  }
622  }
623  }
624  }
625  // case where fat jets are used to associate SVs to subjets but no SV clustering is performed
626  else if (useExternalSV && !useSVClustering && !trackIPTagInfos->empty() && useFatJets) {
627  // match groomed and original fat jets
628  std::vector<int> groomedIndices;
629  if (useGroomedFatJets)
630  matchGroomedJets(fatJetsHandle, groomedFatJetsHandle, groomedIndices);
631 
632  // match subjets and original fat jets
633  std::vector<std::vector<int> > subjetIndices;
634  if (useGroomedFatJets)
635  matchSubjets(groomedIndices, groomedFatJetsHandle, trackIPTagInfos, subjetIndices);
636  else
637  matchSubjets(fatJetsHandle, trackIPTagInfos, subjetIndices);
638 
639  // loop over fat jets
640  for (size_t i = 0; i < fatJetsHandle->size(); ++i) {
641  if (fatJetsHandle->at(i).pt() == 0) // continue if the original jet has Pt=0
642  {
643  edm::LogWarning("NullTransverseMomentum")
644  << "The original fat jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
645  continue;
646  }
647 
648  if (subjetIndices.at(i).empty())
649  continue; // continue if the original jet does not have subjets assigned
650 
651  // loop over SVs, associate them to fat jets based on dR cone and
652  // then assign them to the closets subjet in dR
653  for (typename edm::View<VTX>::const_iterator it = extSecVertex->begin(); it != extSecVertex->end(); ++it) {
654  size_t sv = (it - extSecVertex->begin());
655 
656  const reco::Vertex &pv = *(trackIPTagInfos->front().primaryVertex());
657  const VTX &extSV = (*extSecVertex)[sv];
658  GlobalVector dir = flightDirection(pv, extSV);
659  GlobalVector jetDir(fatJetsHandle->at(i).px(), fatJetsHandle->at(i).py(), fatJetsHandle->at(i).pz());
660  // skip SVs outside the dR cone
661  if (Geom::deltaR2(dir, jetDir) > rParam * rParam) // here using the jet clustering rParam as a dR cut
662  continue;
663 
664  dir = dir.unit();
665  fastjet::PseudoJet p(
666  dir.x(), dir.y(), dir.z(), dir.mag()); // using SV flight direction so treating SV as massless
667  if (useSVMomentum)
668  p = fastjet::PseudoJet(extSV.p4().px(), extSV.p4().py(), extSV.p4().pz(), extSV.p4().energy());
669 
670  std::vector<double> dR2toSubjets;
671 
672  for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj)
673  dR2toSubjets.push_back(Geom::deltaR2(p.rapidity(),
674  p.phi_std(),
675  trackIPTagInfos->at(subjetIndices.at(i).at(sj)).jet()->rapidity(),
676  trackIPTagInfos->at(subjetIndices.at(i).at(sj)).jet()->phi()));
677 
678  // find the closest subjet
679  int closestSubjetIdx =
680  std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
681 
682  clusteredSVs.at(subjetIndices.at(i).at(closestSubjetIdx)).push_back(sv);
683  }
684  }
685  }
686  // ------------------------------------ SV clustering END ----------------------------------------------
687 
688  std::unique_ptr<ConfigurableVertexReconstructor> vertexReco;
689  std::unique_ptr<GhostTrackVertexFinder> vertexRecoGT;
690  if (useGhostTrack)
691  vertexRecoGT = std::make_unique<GhostTrackVertexFinder>(
692  vtxRecoPSet.getParameter<double>("maxFitChi2"),
693  vtxRecoPSet.getParameter<double>("mergeThreshold"),
694  vtxRecoPSet.getParameter<double>("primcut"),
695  vtxRecoPSet.getParameter<double>("seccut"),
696  getGhostTrackFitType(vtxRecoPSet.getParameter<std::string>("fitType")));
697  else
698  vertexReco = std::make_unique<ConfigurableVertexReconstructor>(vtxRecoPSet);
699 
700  TransientTrackMap primariesMap;
701 
702  // result secondary vertices
703 
704  auto tagInfos = std::make_unique<Product>();
705 
706  for (typename std::vector<IPTI>::const_iterator iterJets = trackIPTagInfos->begin();
707  iterJets != trackIPTagInfos->end();
708  ++iterJets) {
709  TrackDataVector trackData;
710  // std::cout << "Jet " << iterJets-trackIPTagInfos->begin() << std::endl;
711 
712  const Vertex &pv = *iterJets->primaryVertex();
713 
714  std::set<TransientTrack> primaries;
715  if (constraint == CONSTRAINT_PV_PRIMARIES_IN_FIT) {
716  for (Vertex::trackRef_iterator iter = pv.tracks_begin(); iter != pv.tracks_end(); ++iter) {
717  TransientTrackMap::iterator pos = primariesMap.lower_bound(iter->get());
718 
719  if (pos != primariesMap.end() && pos->first == iter->get())
720  primaries.insert(pos->second);
721  else {
722  TransientTrack track = trackBuilder->build(iter->castTo<TrackRef>());
723  primariesMap.insert(pos, std::make_pair(iter->get(), track));
724  primaries.insert(track);
725  }
726  }
727  }
728 
729  edm::RefToBase<Jet> jetRef = iterJets->jet();
730 
731  GlobalVector jetDir(jetRef->momentum().x(), jetRef->momentum().y(), jetRef->momentum().z());
732 
733  std::vector<std::size_t> indices = iterJets->sortedIndexes(sortCriterium);
734 
735  input_container trackRefs = iterJets->sortedTracks(indices);
736 
737  const std::vector<reco::btag::TrackIPData> &ipData = iterJets->impactParameterData();
738 
739  // build transient tracks used for vertex reconstruction
740 
741  std::vector<TransientTrack> fitTracks;
742  std::vector<GhostTrackState> gtStates;
743  std::unique_ptr<GhostTrackPrediction> gtPred;
744  if (useGhostTrack)
745  gtPred = std::make_unique<GhostTrackPrediction>(*iterJets->ghostTrack());
746 
747  for (unsigned int i = 0; i < indices.size(); i++) {
749 
750  const input_item &trackRef = trackRefs[i];
751 
752  trackData.push_back(IndexedTrackData());
753  trackData.back().first = indices[i];
754 
755  // select tracks for SV finder
756 
757  if (!trackSelector(
758  *reco::btag::toTrack(trackRef), ipData[indices[i]], *jetRef, RecoVertex::convertPos(pv.position()))) {
760  continue;
761  }
762 
763  TransientTrackMap::const_iterator pos = primariesMap.find(reco::btag::toTrack((trackRef)));
764  TransientTrack fitTrack;
765  if (pos != primariesMap.end()) {
766  primaries.erase(pos->second);
767  fitTrack = pos->second;
768  } else
769  fitTrack = trackBuilder->build(trackRef);
770  fitTracks.push_back(fitTrack);
771 
773 
774  if (useGhostTrack) {
775  GhostTrackState gtState(fitTrack);
776  GlobalPoint pos = ipData[indices[i]].closestToGhostTrack;
777  gtState.linearize(*gtPred, true, gtPred->lambda(pos));
778  gtState.setWeight(ipData[indices[i]].ghostTrackWeight);
779  gtStates.push_back(gtState);
780  }
781  }
782 
783  std::unique_ptr<GhostTrack> ghostTrack;
784  if (useGhostTrack)
785  ghostTrack = std::make_unique<GhostTrack>(
789  GlobalVector(iterJets->ghostTrack()->px(), iterJets->ghostTrack()->py(), iterJets->ghostTrack()->pz()),
790  0.05),
791  *gtPred,
792  gtStates,
793  iterJets->ghostTrack()->chi2(),
794  iterJets->ghostTrack()->ndof());
795 
796  // perform actual vertex finding
797 
798  std::vector<VTX> extAssoCollection;
799  std::vector<TransientVertex> fittedSVs;
800  std::vector<SecondaryVertex> SVs;
801  if (!useExternalSV) {
802  switch (constraint) {
803  case CONSTRAINT_NONE:
804  if (useGhostTrack)
805  fittedSVs = vertexRecoGT->vertices(pv, *ghostTrack);
806  else
807  fittedSVs = vertexReco->vertices(fitTracks);
808  break;
809 
810  case CONSTRAINT_BEAMSPOT:
811  if (useGhostTrack)
812  fittedSVs = vertexRecoGT->vertices(pv, *beamSpot, *ghostTrack);
813  else
814  fittedSVs = vertexReco->vertices(fitTracks, *beamSpot);
815  break;
816 
817  case CONSTRAINT_PV_BEAMSPOT_SIZE:
818  case CONSTRAINT_PV_BS_Z_ERRORS_SCALED:
819  case CONSTRAINT_PV_ERROR_SCALED: {
821  for (unsigned int i = 0; i < 7; i++) {
822  unsigned int covSrc = bsCovSrc[i];
823  for (unsigned int j = 0; j < 7; j++) {
824  double v = 0.0;
825  if (!covSrc || bsCovSrc[j] != covSrc)
826  v = 0.0;
827  else if (covSrc == 1)
828  v = beamSpot->covariance(i, j);
829  else if (j < 3 && i < 3)
830  v = pv.covariance(i, j) * constraintScaling;
831  cov(i, j) = v;
832  }
833  }
834 
835  BeamSpot bs(pv.position(),
836  sigmaZ,
837  beamSpot.isValid() ? beamSpot->dxdz() : 0.,
838  beamSpot.isValid() ? beamSpot->dydz() : 0.,
839  beamWidth,
840  cov,
842 
843  if (useGhostTrack)
844  fittedSVs = vertexRecoGT->vertices(pv, bs, *ghostTrack);
845  else
846  fittedSVs = vertexReco->vertices(fitTracks, bs);
847  } break;
848 
849  case CONSTRAINT_PV_PRIMARIES_IN_FIT: {
850  std::vector<TransientTrack> primaries_(primaries.begin(), primaries.end());
851  if (useGhostTrack)
852  fittedSVs = vertexRecoGT->vertices(pv, *beamSpot, primaries_, *ghostTrack);
853  else
854  fittedSVs = vertexReco->vertices(primaries_, fitTracks, *beamSpot);
855  } break;
856  }
857  // build combined SV information and filter
858  SVBuilder svBuilder(pv, jetDir, withPVError, minTrackWeight);
859  std::remove_copy_if(boost::make_transform_iterator(fittedSVs.begin(), svBuilder),
860  boost::make_transform_iterator(fittedSVs.end(), svBuilder),
861  std::back_inserter(SVs),
862  SVFilter(vertexFilter, pv, jetDir));
863 
864  } else {
865  if (useSVClustering || useFatJets) {
866  size_t jetIdx = (iterJets - trackIPTagInfos->begin());
867 
868  for (size_t iExtSv = 0; iExtSv < clusteredSVs.at(jetIdx).size(); iExtSv++) {
869  const VTX &extVertex = (*extSecVertex)[clusteredSVs.at(jetIdx).at(iExtSv)];
870  if (extVertex.p4().M() < 0.3)
871  continue;
872  extAssoCollection.push_back(extVertex);
873  }
874  } else {
875  for (size_t iExtSv = 0; iExtSv < extSecVertex->size(); iExtSv++) {
876  const VTX &extVertex = (*extSecVertex)[iExtSv];
877  if (Geom::deltaR2((position(extVertex) - pv.position()), (extSVDeltaRToJet > 0) ? jetDir : -jetDir) >
879  extVertex.p4().M() < 0.3)
880  continue;
881  extAssoCollection.push_back(extVertex);
882  }
883  }
884  // build combined SV information and filter
885  SVBuilder svBuilder(pv, jetDir, withPVError, minTrackWeight);
886  std::remove_copy_if(boost::make_transform_iterator(extAssoCollection.begin(), svBuilder),
887  boost::make_transform_iterator(extAssoCollection.end(), svBuilder),
888  std::back_inserter(SVs),
889  SVFilter(vertexFilter, pv, jetDir));
890  }
891  // clean up now unneeded collections
892  gtPred.reset();
893  ghostTrack.reset();
894  gtStates.clear();
895  fitTracks.clear();
896  fittedSVs.clear();
897  extAssoCollection.clear();
898 
899  // sort SVs by importance
900 
901  std::vector<unsigned int> vtxIndices = vertexSorting(SVs);
902 
903  std::vector<typename TemplatedSecondaryVertexTagInfo<IPTI, VTX>::VertexData> svData;
904 
905  svData.resize(vtxIndices.size());
906  for (unsigned int idx = 0; idx < vtxIndices.size(); idx++) {
907  const SecondaryVertex &sv = SVs[vtxIndices[idx]];
908 
909  svData[idx].vertex = sv;
910  svData[idx].dist1d = sv.dist1d();
911  svData[idx].dist2d = sv.dist2d();
912  svData[idx].dist3d = sv.dist3d();
913  svData[idx].direction = flightDirection(pv, sv);
914  // mark tracks successfully used in vertex fit
915  markUsedTracks(trackData, trackRefs, sv, idx);
916  }
917 
918  // fill result into tag infos
919 
921  trackData,
922  svData,
923  SVs.size(),
924  edm::Ref<std::vector<IPTI> >(trackIPTagInfos, iterJets - trackIPTagInfos->begin())));
925  }
926 
927  event.put(std::move(tagInfos));
928 }
929 
930 //Need specialized template because reco::Vertex iterators are TrackBase and it is a mess to make general
931 template <>
933  const input_container &trackRefs,
934  const SecondaryVertex &sv,
935  size_t idx) {
936  for (Vertex::trackRef_iterator iter = sv.tracks_begin(); iter != sv.tracks_end(); ++iter) {
937  if (sv.trackWeight(*iter) < minTrackWeight)
938  continue;
939 
940  typename input_container::const_iterator pos =
941  std::find(trackRefs.begin(), trackRefs.end(), iter->castTo<input_item>());
942 
943  if (pos == trackRefs.end()) {
944  if (!useExternalSV)
945  throw cms::Exception("TrackNotFound") << "Could not find track from secondary "
946  "vertex in original tracks."
947  << std::endl;
948  } else {
949  unsigned int index = pos - trackRefs.begin();
950  trackData[index].second.svStatus = (btag::TrackData::trackAssociatedToVertex + idx);
951  }
952  }
953 }
954 template <>
956  TrackDataVector &trackData, const input_container &trackRefs, const SecondaryVertex &sv, size_t idx) {
957  for (typename input_container::const_iterator iter = sv.daughterPtrVector().begin();
958  iter != sv.daughterPtrVector().end();
959  ++iter) {
960  typename input_container::const_iterator pos = std::find(trackRefs.begin(), trackRefs.end(), *iter);
961 
962  if (pos != trackRefs.end()) {
963  unsigned int index = pos - trackRefs.begin();
964  trackData[index].second.svStatus = (btag::TrackData::trackAssociatedToVertex + idx);
965  }
966  }
967 }
968 
969 template <>
972  if (!sv.originalTracks().empty() && sv.originalTracks()[0].trackBaseRef().isNonnull())
973  return SecondaryVertex(pv, sv, direction, withPVError);
974  else {
975  edm::LogError("UnexpectedInputs") << "Building from Candidates, should not happen!";
976  return SecondaryVertex(pv, sv, direction, withPVError);
977  }
978 }
979 
980 template <>
983  const TransientVertex &sv) const {
984  if (!sv.originalTracks().empty() && sv.originalTracks()[0].trackBaseRef().isNonnull()) {
985  edm::LogError("UnexpectedInputs") << "Building from Tracks, should not happen!";
986  VertexCompositePtrCandidate vtxCompPtrCand;
987 
988  vtxCompPtrCand.setCovariance(sv.vertexState().error().matrix());
989  vtxCompPtrCand.setChi2AndNdof(sv.totalChiSquared(), sv.degreesOfFreedom());
990  vtxCompPtrCand.setVertex(Candidate::Point(sv.position().x(), sv.position().y(), sv.position().z()));
991 
992  return SecondaryVertex(pv, vtxCompPtrCand, direction, withPVError);
993  } else {
994  VertexCompositePtrCandidate vtxCompPtrCand;
995 
996  vtxCompPtrCand.setCovariance(sv.vertexState().error().matrix());
997  vtxCompPtrCand.setChi2AndNdof(sv.totalChiSquared(), sv.degreesOfFreedom());
998  vtxCompPtrCand.setVertex(Candidate::Point(sv.position().x(), sv.position().y(), sv.position().z()));
999 
1001  for (std::vector<reco::TransientTrack>::const_iterator tt = sv.originalTracks().begin();
1002  tt != sv.originalTracks().end();
1003  ++tt) {
1004  if (sv.trackWeight(*tt) < minTrackWeight)
1005  continue;
1006 
1007  const CandidatePtrTransientTrack *cptt =
1008  dynamic_cast<const CandidatePtrTransientTrack *>(tt->basicTransientTrack());
1009  if (cptt == nullptr)
1010  edm::LogError("DynamicCastingFailed") << "Casting of TransientTrack to CandidatePtrTransientTrack failed!";
1011  else {
1012  p4 += cptt->candidate()->p4();
1013  vtxCompPtrCand.addDaughter(cptt->candidate());
1014  }
1015  }
1016  vtxCompPtrCand.setP4(p4);
1017 
1018  return SecondaryVertex(pv, vtxCompPtrCand, direction, withPVError);
1019  }
1020 }
1021 
1022 // ------------ method that matches reclustered and original jets based on minimum dR ------------
1023 template <class IPTI, class VTX>
1024 template <class CONTAINER>
1027  const std::vector<fastjet::PseudoJet> &reclusteredJets,
1028  std::vector<int> &matchedIndices,
1029  const std::string &jetType) {
1030  std::string type = (!jetType.empty() ? jetType + " " : jetType);
1031 
1032  std::vector<bool> matchedLocks(reclusteredJets.size(), false);
1033 
1034  for (size_t j = 0; j < jets->size(); ++j) {
1035  double matchedDR2 = 1e9;
1036  int matchedIdx = -1;
1037 
1038  for (size_t rj = 0; rj < reclusteredJets.size(); ++rj) {
1039  if (matchedLocks.at(rj))
1040  continue; // skip jets that have already been matched
1041 
1042  double tempDR2 = Geom::deltaR2(toJet(jets->at(j))->rapidity(),
1043  toJet(jets->at(j))->phi(),
1044  reclusteredJets.at(rj).rapidity(),
1045  reclusteredJets.at(rj).phi_std());
1046  if (tempDR2 < matchedDR2) {
1047  matchedDR2 = tempDR2;
1048  matchedIdx = rj;
1049  }
1050  }
1051 
1052  if (matchedIdx >= 0) {
1053  if (matchedDR2 > rParam * rParam) {
1054  edm::LogError("JetMatchingFailed") << "Matched reclustered jet " << matchedIdx << " and original " << type
1055  << "jet " << j << " are separated by dR=" << sqrt(matchedDR2)
1056  << " which is greater than the jet size R=" << rParam << ".\n"
1057  << "This is not expected so please check that the jet algorithm and jet "
1058  "size match those used for the original "
1059  << type << "jet collection.";
1060  } else
1061  matchedLocks.at(matchedIdx) = true;
1062  } else
1063  edm::LogError("JetMatchingFailed")
1064  << "Matching reclustered to original " << type
1065  << "jets failed. Please check that the jet algorithm and jet size match those used for the original " << type
1066  << "jet collection.";
1067 
1068  matchedIndices.push_back(matchedIdx);
1069  }
1070 }
1071 
1072 // ------------ method that matches groomed and original jets based on minimum dR ------------
1073 template <class IPTI, class VTX>
1075  const edm::Handle<edm::View<reco::Jet> > &groomedJets,
1076  std::vector<int> &matchedIndices) {
1077  std::vector<bool> jetLocks(jets->size(), false);
1078  std::vector<int> jetIndices;
1079 
1080  for (size_t gj = 0; gj < groomedJets->size(); ++gj) {
1081  double matchedDR2 = 1e9;
1082  int matchedIdx = -1;
1083 
1084  if (groomedJets->at(gj).pt() > 0.) // skip pathological cases of groomed jets with Pt=0
1085  {
1086  for (size_t j = 0; j < jets->size(); ++j) {
1087  if (jetLocks.at(j))
1088  continue; // skip jets that have already been matched
1089 
1090  double tempDR2 = Geom::deltaR2(
1091  jets->at(j).rapidity(), jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi());
1092  if (tempDR2 < matchedDR2) {
1093  matchedDR2 = tempDR2;
1094  matchedIdx = j;
1095  }
1096  }
1097  }
1098 
1099  if (matchedIdx >= 0) {
1100  if (matchedDR2 > rParam * rParam) {
1101  edm::LogWarning("MatchedJetsFarApart")
1102  << "Matched groomed jet " << gj << " and original jet " << matchedIdx
1103  << " are separated by dR=" << sqrt(matchedDR2) << " which is greater than the jet size R=" << rParam
1104  << ".\n"
1105  << "This is not expected so the matching of these two jets has been discarded. Please check that the two "
1106  "jet collections belong to each other.";
1107  matchedIdx = -1;
1108  } else
1109  jetLocks.at(matchedIdx) = true;
1110  }
1111  jetIndices.push_back(matchedIdx);
1112  }
1113 
1114  for (size_t j = 0; j < jets->size(); ++j) {
1115  std::vector<int>::iterator matchedIndex = std::find(jetIndices.begin(), jetIndices.end(), j);
1116 
1117  matchedIndices.push_back(matchedIndex != jetIndices.end() ? std::distance(jetIndices.begin(), matchedIndex) : -1);
1118  }
1119 }
1120 
1121 // ------------ method that matches subjets and original fat jets ------------
1122 template <class IPTI, class VTX>
1123 void TemplatedSecondaryVertexProducer<IPTI, VTX>::matchSubjets(const std::vector<int> &groomedIndices,
1124  const edm::Handle<edm::View<reco::Jet> > &groomedJets,
1125  const edm::Handle<std::vector<IPTI> > &subjets,
1126  std::vector<std::vector<int> > &matchedIndices) {
1127  for (size_t g = 0; g < groomedIndices.size(); ++g) {
1128  std::vector<int> subjetIndices;
1129 
1130  if (groomedIndices.at(g) >= 0) {
1131  for (size_t s = 0; s < groomedJets->at(groomedIndices.at(g)).numberOfDaughters(); ++s) {
1132  const edm::Ptr<reco::Candidate> &subjet = groomedJets->at(groomedIndices.at(g)).daughterPtr(s);
1133 
1134  for (size_t sj = 0; sj < subjets->size(); ++sj) {
1135  const edm::RefToBase<reco::Jet> &subjetRef = subjets->at(sj).jet();
1136  if (subjet == edm::Ptr<reco::Candidate>(subjetRef.id(), subjetRef.get(), subjetRef.key())) {
1137  subjetIndices.push_back(sj);
1138  break;
1139  }
1140  }
1141  }
1142 
1143  if (subjetIndices.empty())
1144  edm::LogError("SubjetMatchingFailed") << "Matching subjets to original fat jets failed. Please check that the "
1145  "groomed fat jet and subjet collections belong to each other.";
1146 
1147  matchedIndices.push_back(subjetIndices);
1148  } else
1149  matchedIndices.push_back(subjetIndices);
1150  }
1151 }
1152 
1153 // ------------ method that matches subjets and original fat jets ------------
1154 template <class IPTI, class VTX>
1156  const edm::Handle<std::vector<IPTI> > &subjets,
1157  std::vector<std::vector<int> > &matchedIndices) {
1158  for (size_t fj = 0; fj < fatJets->size(); ++fj) {
1159  std::vector<int> subjetIndices;
1160  size_t nSubjetCollections = 0;
1161  size_t nSubjets = 0;
1162 
1163  const pat::Jet *fatJet = dynamic_cast<const pat::Jet *>(fatJets->ptrAt(fj).get());
1164 
1165  if (!fatJet) {
1166  if (fj == 0)
1167  edm::LogError("WrongJetType")
1168  << "Wrong jet type for input fat jets. Please check that the input fat jets are of the pat::Jet type.";
1169 
1170  matchedIndices.push_back(subjetIndices);
1171  continue;
1172  } else {
1173  nSubjetCollections = fatJet->subjetCollectionNames().size();
1174 
1175  if (nSubjetCollections > 0) {
1176  for (size_t coll = 0; coll < nSubjetCollections; ++coll) {
1177  const pat::JetPtrCollection &fatJetSubjets = fatJet->subjets(coll);
1178 
1179  for (size_t fjsj = 0; fjsj < fatJetSubjets.size(); ++fjsj) {
1180  ++nSubjets;
1181 
1182  for (size_t sj = 0; sj < subjets->size(); ++sj) {
1183  const pat::Jet *subJet = dynamic_cast<const pat::Jet *>(subjets->at(sj).jet().get());
1184 
1185  if (!subJet) {
1186  if (fj == 0 && coll == 0 && fjsj == 0 && sj == 0)
1187  edm::LogError("WrongJetType") << "Wrong jet type for input subjets. Please check that the input "
1188  "subjets are of the pat::Jet type.";
1189 
1190  break;
1191  } else {
1192  if (subJet->originalObjectRef() == fatJetSubjets.at(fjsj)->originalObjectRef()) {
1193  subjetIndices.push_back(sj);
1194  break;
1195  }
1196  }
1197  }
1198  }
1199  }
1200 
1201  if (subjetIndices.empty() && nSubjets > 0)
1202  edm::LogError("SubjetMatchingFailed") << "Matching subjets to fat jets failed. Please check that the fat jet "
1203  "and subjet collections belong to each other.";
1204 
1205  matchedIndices.push_back(subjetIndices);
1206  } else
1207  matchedIndices.push_back(subjetIndices);
1208  }
1209  }
1210 }
1211 
1212 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
1213 template <class IPTI, class VTX>
1216  desc.add<double>("extSVDeltaRToJet", 0.3);
1217  desc.add<edm::InputTag>("beamSpotTag", edm::InputTag("offlineBeamSpot"));
1218  {
1220  vertexReco.add<double>("primcut", 1.8);
1221  vertexReco.add<double>("seccut", 6.0);
1222  vertexReco.add<std::string>("finder", "avr");
1223  vertexReco.addOptionalNode(edm::ParameterDescription<double>("minweight", 0.5, true) and
1224  edm::ParameterDescription<double>("weightthreshold", 0.001, true) and
1225  edm::ParameterDescription<bool>("smoothing", false, true),
1226  true);
1227  vertexReco.addOptionalNode(
1228  edm::ParameterDescription<double>("maxFitChi2", 10.0, true) and
1229  edm::ParameterDescription<double>("mergeThreshold", 3.0, true) and
1230  edm::ParameterDescription<std::string>("fitType", "RefitGhostTrackWithVertices", true),
1231  true);
1232  desc.add<edm::ParameterSetDescription>("vertexReco", vertexReco);
1233  }
1234  {
1236  vertexSelection.add<std::string>("sortCriterium", "dist3dError");
1237  desc.add<edm::ParameterSetDescription>("vertexSelection", vertexSelection);
1238  }
1239  desc.add<std::string>("constraint", "BeamSpot");
1240  desc.add<edm::InputTag>("trackIPTagInfos", edm::InputTag("impactParameterTagInfos"));
1241  {
1243  vertexCuts.add<double>("distSig3dMax", 99999.9);
1244  vertexCuts.add<double>("fracPV", 0.65);
1245  vertexCuts.add<double>("distVal2dMax", 2.5);
1246  vertexCuts.add<bool>("useTrackWeights", true);
1247  vertexCuts.add<double>("maxDeltaRToJetAxis", 0.4);
1248  {
1250  v0Filter.add<double>("k0sMassWindow", 0.05);
1251  vertexCuts.add<edm::ParameterSetDescription>("v0Filter", v0Filter);
1252  }
1253  vertexCuts.add<double>("distSig2dMin", 3.0);
1254  vertexCuts.add<unsigned int>("multiplicityMin", 2);
1255  vertexCuts.add<double>("distVal2dMin", 0.01);
1256  vertexCuts.add<double>("distSig2dMax", 99999.9);
1257  vertexCuts.add<double>("distVal3dMax", 99999.9);
1258  vertexCuts.add<double>("minimumTrackWeight", 0.5);
1259  vertexCuts.add<double>("distVal3dMin", -99999.9);
1260  vertexCuts.add<double>("massMax", 6.5);
1261  vertexCuts.add<double>("distSig3dMin", -99999.9);
1262  desc.add<edm::ParameterSetDescription>("vertexCuts", vertexCuts);
1263  }
1264  desc.add<bool>("useExternalSV", false);
1265  desc.add<double>("minimumTrackWeight", 0.5);
1266  desc.add<bool>("usePVError", true);
1267  {
1269  trackSelection.add<double>("b_pT", 0.3684);
1270  trackSelection.add<double>("max_pT", 500);
1271  trackSelection.add<bool>("useVariableJTA", false);
1272  trackSelection.add<double>("maxDecayLen", 99999.9);
1273  trackSelection.add<double>("sip3dValMin", -99999.9);
1274  trackSelection.add<double>("max_pT_dRcut", 0.1);
1275  trackSelection.add<double>("a_pT", 0.005263);
1276  trackSelection.add<unsigned int>("totalHitsMin", 8);
1277  trackSelection.add<double>("jetDeltaRMax", 0.3);
1278  trackSelection.add<double>("a_dR", -0.001053);
1279  trackSelection.add<double>("maxDistToAxis", 0.2);
1280  trackSelection.add<double>("ptMin", 1.0);
1281  trackSelection.add<std::string>("qualityClass", "any");
1282  trackSelection.add<unsigned int>("pixelHitsMin", 2);
1283  trackSelection.add<double>("sip2dValMax", 99999.9);
1284  trackSelection.add<double>("max_pT_trackPTcut", 3);
1285  trackSelection.add<double>("sip2dValMin", -99999.9);
1286  trackSelection.add<double>("normChi2Max", 99999.9);
1287  trackSelection.add<double>("sip3dValMax", 99999.9);
1288  trackSelection.add<double>("sip3dSigMin", -99999.9);
1289  trackSelection.add<double>("min_pT", 120);
1290  trackSelection.add<double>("min_pT_dRcut", 0.5);
1291  trackSelection.add<double>("sip2dSigMax", 99999.9);
1292  trackSelection.add<double>("sip3dSigMax", 99999.9);
1293  trackSelection.add<double>("sip2dSigMin", -99999.9);
1294  trackSelection.add<double>("b_dR", 0.6263);
1295  desc.add<edm::ParameterSetDescription>("trackSelection", trackSelection);
1296  }
1297  desc.add<std::string>("trackSort", "sip3dSig");
1298  desc.add<edm::InputTag>("extSVCollection", edm::InputTag("secondaryVertices"));
1299  desc.addOptionalNode(edm::ParameterDescription<bool>("useSVClustering", false, true) and
1300  edm::ParameterDescription<std::string>("jetAlgorithm", true) and
1301  edm::ParameterDescription<double>("rParam", true),
1302  true);
1303  desc.addOptional<bool>("useSVMomentum", false);
1304  desc.addOptional<double>("ghostRescaling", 1e-18);
1305  desc.addOptional<double>("relPtTolerance", 1e-03);
1306  desc.addOptional<edm::InputTag>("fatJets");
1307  desc.addOptional<edm::InputTag>("groomedFatJets");
1308  desc.add<edm::InputTag>("weights", edm::InputTag(""));
1309  descriptions.addDefault(desc);
1310 }
1311 
1312 //define this as a plug-in
1315 
std::shared_ptr< fastjet::JetDefinition > JetDefPtr
math::Error< dimension >::type CovarianceMatrix
Definition: BeamSpot.h:29
reco::Vertex::Point convertPos(const GlobalPoint &p)
value_type const * get() const
Definition: RefToBase.h:209
edm::EDGetTokenT< edm::View< reco::Jet > > token_fatJets
edm::ESGetToken< TransientTrackBuilder, TransientTrackRecord > token_trackBuilder
reco::btag::SortCriteria getCriterium(const std::string &name)
Definition: TrackSorting.cc:11
TemplatedSecondaryVertex< reco::Vertex > SecondaryVertex
ParameterDescriptionBase * addOptional(U const &iLabel, T const &value)
bool existsAs(std::string const &parameterName, bool trackiness=true) const
checks if a parameter exists as a given type
Definition: ParameterSet.h:171
const double w
Definition: UKUtility.cc:23
TemplatedSecondaryVertexProducer(const edm::ParameterSet &params)
void produce(edm::Event &event, const edm::EventSetup &es) override
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
CandidatePtr candidate() const override
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
edm::EDGetTokenT< reco::BeamSpot > token_BeamSpot
const AlgebraicSymMatrix33 matrix() const
double y() const
y coordinate
Definition: Vertex.h:131
Base class for all types of Jets.
Definition: Jet.h:20
float totalChiSquared() const
reco::Vertex::Error convertError(const GlobalError &ge)
Definition: ConvertError.h:8
T y() const
Definition: PV3DBase.h:60
bool exists(std::string const &parameterName) const
checks if a parameter exists
void setWeight(double weight)
SVFilter(const VertexFilter &filter, const Vertex &pv, const GlobalVector &direction)
const Point & vertex() const override
vertex position (overwritten by PF...)
double covariance(int i, int j) const
(i, j)-th element of error matrix, i, j = 0, ... 2
Definition: Vertex.h:148
tuple vertexSelection
Log< level::Error, false > LogError
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
const reco::Track * toTrack(const reco::TrackBaseRef &t)
Definition: IPTagInfo.h:24
const Point & position() const
position
Definition: Vertex.h:127
ProductID id() const
Definition: RefToBase.h:214
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
TemplatedSecondaryVertexProducer< CandIPTagInfo, reco::VertexCompositePtrCandidate > CandSecondaryVertexProducer
void setVertex(const Point &vertex) override
set vertex
static GhostTrackVertexFinder::FitType getGhostTrackFitType(const std::string &name)
void matchReclusteredJets(const edm::Handle< CONTAINER > &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices, const std::string &jetType="")
edm::EDGetTokenT< std::vector< IPTI > > token_trackIPTagInfo
IPTI::input_container::value_type input_item
T mag() const
Definition: PV3DBase.h:64
void addDefault(ParameterSetDescription const &psetDescription)
std::vector< TemplatedSecondaryVertexTagInfo< IPTI, VTX > > Product
GlobalVector flightDirection(const reco::Vertex &pv, const reco::Vertex &sv)
std::vector< reco::TransientTrack > const & originalTracks() const
float degreesOfFreedom() const
size_t key() const
Definition: RefToBase.h:219
T sqrt(T t)
Definition: SSEVec.h:19
GlobalPoint position() const
vector< PseudoJet > jets
std::vector< edm::Ptr< pat::Jet > > JetPtrCollection
Definition: Jet.h:75
T z() const
Definition: PV3DBase.h:61
def move
Definition: eostools.py:511
edm::EDGetTokenT< edm::ValueMap< float > > token_weights
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
trackRef_iterator tracks_end() const
last iterator over tracks
Definition: Vertex.h:110
double z() const
z coordinate
Definition: Vertex.h:133
ParameterDescriptionNode * addOptionalNode(ParameterDescriptionNode const &node, bool writeToCfi)
VertexSorting< SecondaryVertex > vertexSorting
std::vector< std::string > const & subjetCollectionNames() const
Subjet collection names.
Definition: Jet.h:566
static ConstraintType getConstraintType(const std::string &name)
trackRef_iterator tracks_begin() const
first iterator over tracks
Definition: Vertex.h:108
const edm::Ptr< reco::Candidate > & originalObjectRef() const
reference to original object. Returns a null reference if not available
Definition: PATObject.h:537
ParameterDescriptionBase * add(U const &iLabel, T const &value)
bool isValid() const
Definition: HandleBase.h:70
float trackWeight(const reco::TransientTrack &track) const
void matchGroomedJets(const edm::Handle< edm::View< reco::Jet > > &jets, const edm::Handle< edm::View< reco::Jet > > &matchedJets, std::vector< int > &matchedIndices)
void matchSubjets(const std::vector< int > &groomedIndices, const edm::Handle< edm::View< reco::Jet > > &groomedJets, const edm::Handle< std::vector< IPTI > > &subjets, std::vector< std::vector< int > > &matchedIndices)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void markUsedTracks(TrackDataVector &trackData, const input_container &trackRefs, const SecondaryVertex &sv, size_t idx)
edm::EDGetTokenT< edm::View< VTX > > token_extSVCollection
Vector3DBase unit() const
Definition: Vector3DBase.h:54
SVBuilder(const reco::Vertex &pv, const GlobalVector &direction, bool withPVError, double minTrackWeight)
double x() const
x coordinate
Definition: Vertex.h:129
std::shared_ptr< fastjet::ClusterSequence > ClusterSequencePtr
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
TemplatedSecondaryVertex< VTX > SecondaryVertex
edm::EDGetTokenT< edm::View< reco::Jet > > token_groomedFatJets
bool linearize(const GhostTrackPrediction &pred, bool initial=false, double lambda=0.)
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
tuple trackIPTagInfos
tuple trackSelection
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
Analysis-level calorimeter jet class.
Definition: Jet.h:77
SecondaryVertex operator()(const TransientVertex &sv) const
Error error() const
return SMatrix
Definition: Vertex.h:163
TemplatedSecondaryVertexProducer< TrackIPTagInfo, reco::Vertex > SecondaryVertexProducer
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Candidate.h:36
std::string const & label() const
Definition: InputTag.h:36
std::vector< reco::btag::IndexedTrackData > TrackDataVector
boost::indirect_iterator< typename seq_t::const_iterator > const_iterator
Definition: View.h:86
tuple extSVDeltaRToJet
static int position[264][3]
Definition: ReadPGInfo.cc:289
void setCovariance(const CovarianceMatrix &m)
set covariance matrix
void addDaughter(const CandidatePtr &)
add a daughter via a reference
math::XYZPoint Point
point in the space
Definition: Candidate.h:40
GlobalError error() const
Definition: VertexState.h:64
void setChi2AndNdof(double chi2, double ndof)
set chi2 and ndof
ESHandle< T > getHandle(const ESGetToken< T, R > &iToken) const
Definition: EventSetup.h:157
Log< level::Warning, false > LogWarning
list indices
Definition: dqmdumpme.py:50
VertexState const & vertexState() const
T x() const
Definition: PV3DBase.h:59
pat::JetPtrCollection const & subjets(unsigned int index=0) const
Access to subjet list.
void setP4(const LorentzVector &p4) final
set 4-momentum
const reco::Jet * toJet(const reco::Jet &j)
std::vector< TrackBaseRef >::const_iterator trackRef_iterator
The iteratator for the vector&lt;TrackRef&gt;
Definition: Vertex.h:38
std::pair< unsigned int, TrackData > IndexedTrackData
Global3DVector GlobalVector
Definition: GlobalVector.h:10
tuple trackSelector
Tracks selection.
Definition: valSkim_cff.py:4