CMS 3D CMS Logo

PFRecoTauChargedHadronFromGenericTrackPlugin.cc
Go to the documentation of this file.
1 /*
2  * PFRecoTauChargedHadronFromGenericTrackPlugin
3  *
4  * Build PFRecoTauChargedHadron objects
5  * using tracks as input, from either collection of RECO/AOD reco::Tracks
6  * (PFRecoTauChargedHadronFromTrackPlugin) or from a collection of MINIAOD
7  * pat::PackedCandidates (PFRecoTauChargedHadronFromLostTrackPlugin), typically
8  * using the 'lostTracks' collection
9  *
10  * Author: Christian Veelken, LLR
11  *
12  * inclusion of lost tracks based on original implementation
13  * by Michal Bluj, NCBJ, Poland
14  */
15 
17 
19 
22 
35 
38 
43 
44 #include <TMath.h>
45 
46 #include <memory>
47 #include <cmath>
48 #include <algorithm>
49 #include <atomic>
50 
51 namespace reco {
52  namespace tau {
53 
54  template <class TrackClass>
55  class PFRecoTauChargedHadronFromGenericTrackPlugin : public PFRecoTauChargedHadronBuilderPlugin {
56  public:
59  // Return type is unique_ptr<ChargedHadronVector>
60  return_type operator()(const reco::Jet&) const override;
61  // Hook to update PV information
62  void beginEvent() override;
63 
64  private:
65  bool filterTrack(const edm::Handle<std::vector<TrackClass> >&, size_t iTrack) const;
66  void setChargedHadronTrack(PFRecoTauChargedHadron& chargedHadron, const edm::Ptr<TrackClass>& track) const;
67  double getTrackPtError(const TrackClass& track) const;
69 
71 
73 
77  double dRcone_;
79 
82 
84 
85  static std::atomic<unsigned int> numWarnings_;
86  static constexpr unsigned int maxWarnings_ = 3;
87 
89  };
90 
91  template <class TrackClass>
93 
94  template <class TrackClass>
98  vertexAssociator_(pset.getParameter<edm::ParameterSet>("qualityCuts"), std::move(iC)),
99  qcuts_(nullptr),
100  magneticFieldToken_(iC.esConsumes()) {
101  edm::ParameterSet qcuts_pset = pset.getParameterSet("qualityCuts").getParameterSet("signalQualityCuts");
102  qcuts_ = new RecoTauQualityCuts(qcuts_pset);
103 
104  srcTracks_ = pset.getParameter<edm::InputTag>("srcTracks");
105  Tracks_token = iC.consumes<std::vector<TrackClass> >(srcTracks_);
106  dRcone_ = pset.getParameter<double>("dRcone");
107  dRconeLimitedToJetArea_ = pset.getParameter<bool>("dRconeLimitedToJetArea");
108 
109  dRmergeNeutralHadron_ = pset.getParameter<double>("dRmergeNeutralHadron");
110  dRmergePhoton_ = pset.getParameter<double>("dRmergePhoton");
111 
112  verbosity_ = pset.getParameter<int>("verbosity");
113  }
114 
115  template <class TrackClass>
117  delete qcuts_;
118  }
119 
120  // Update the primary vertex
121  template <class TrackClass>
123  vertexAssociator_.setEvent(*this->evt());
124 
125  magneticFieldStrength_ = evtSetup()->getData(magneticFieldToken_).inTesla(GlobalPoint(0., 0., 0.));
126  }
127 
128  template <>
130  const edm::Handle<std::vector<reco::Track> >& tracks, size_t iTrack) const {
131  // ignore tracks which fail quality cuts
132  reco::TrackRef trackRef(tracks, iTrack);
133  return qcuts_->filterTrack(trackRef);
134  }
135 
136  template <>
138  const edm::Handle<std::vector<pat::PackedCandidate> >& tracks, size_t iTrack) const {
139  // ignore tracks which fail quality cuts
140  const pat::PackedCandidate& cand = (*tracks)[iTrack];
141  if (cand.charge() == 0)
142  return false;
143 
144  return qcuts_->filterChargedCand(cand);
145  }
146 
147  template <>
150  chargedHadron.track_ = track;
151  }
152 
153  template <>
156  chargedHadron.lostTrackCandidate_ = track;
157  }
158 
159  template <>
161  return track.ptError();
162  }
163 
164  template <>
166  const pat::PackedCandidate& cand) const {
167  double trackPtError =
168  0.06; // MB: Approximate avarage track PtError by 2.5% (barrel), 4% (transition), 6% (endcaps) lostTracks w/o detailed track information available (after TRK-11-001)
169  const reco::Track* track(cand.bestTrack());
170  if (track != nullptr) {
171  trackPtError = track->ptError();
172  } else {
173  if (std::abs(cand.eta()) < 0.9)
174  trackPtError = 0.025;
175  else if (std::abs(cand.eta()) < 1.4)
176  trackPtError = 0.04;
177  }
178  return trackPtError;
179  }
180 
181  template <>
183  const reco::Track& track) const {
184  return XYZTLorentzVector(track.referencePoint().x(), track.referencePoint().y(), track.referencePoint().z(), 0.);
185  }
186 
187  template <>
189  const pat::PackedCandidate& track) const {
190  return XYZTLorentzVector(track.vertex().x(), track.vertex().y(), track.vertex().z(), 0.);
191  }
192 
193  namespace {
194  struct Candidate_withDistance {
196  double distance_;
197  };
198 
199  bool isSmallerDistance(const Candidate_withDistance& cand1, const Candidate_withDistance& cand2) {
200  return (cand1.distance_ < cand2.distance_);
201  }
202  } // namespace
203 
204  template <class TrackClass>
207  if (verbosity_) {
208  edm::LogPrint("TauChHFromTrack") << "<PFRecoTauChargedHadronFromGenericTrackPlugin::operator()>:";
209  edm::LogPrint("TauChHFromTrack") << " pluginName = " << name();
210  }
211 
213 
214  const edm::Event& evt = (*this->evt());
215 
217  evt.getByToken(Tracks_token, tracks);
218 
219  qcuts_->setPV(vertexAssociator_.associatedVertex(jet));
220  float jEta = jet.eta();
221  float jPhi = jet.phi();
222  size_t numTracks = tracks->size();
223  for (size_t iTrack = 0; iTrack < numTracks; ++iTrack) {
224  const TrackClass& track = (*tracks)[iTrack];
225 
226  // consider tracks in vicinity of tau-jet candidate only
227  double dR = deltaR(track.eta(), track.phi(), jEta, jPhi);
228  double dRmatch = dRcone_;
229  if (dRconeLimitedToJetArea_) {
230  double jetArea = jet.jetArea();
231  if (jetArea > 0.) {
232  dRmatch = std::min(dRmatch, sqrt(jetArea / M_PI));
233  } else {
234  if (numWarnings_ < maxWarnings_) {
235  edm::LogInfo("PFRecoTauChargedHadronFromGenericTrackPlugin::operator()")
236  << "Jet: Pt = " << jet.pt() << ", eta = " << jet.eta() << ", phi = " << jet.phi()
237  << " has area = " << jetArea << " !!" << std::endl;
238  ++numWarnings_;
239  }
240  dRmatch = 0.1;
241  }
242  }
243  if (dR > dRmatch)
244  continue;
245 
246  if (!this->filterTrack(tracks, iTrack))
247  continue;
248 
249  reco::Candidate::Charge trackCharge_int = 0;
250  if (track.charge() > 0.)
251  trackCharge_int = +1;
252  else if (track.charge() < 0.)
253  trackCharge_int = -1;
254 
255  const double chargedPionMass = 0.13957; // GeV
256  double chargedPionP = track.p();
257  double chargedPionEn = TMath::Sqrt(chargedPionP * chargedPionP + chargedPionMass * chargedPionMass);
258  reco::Candidate::LorentzVector chargedPionP4(track.px(), track.py(), track.pz(), chargedPionEn);
259 
260  reco::Vertex::Point vtx(0., 0., 0.);
261  if (vertexAssociator_.associatedVertex(jet).isNonnull())
262  vtx = vertexAssociator_.associatedVertex(jet)->position();
263 
264  std::unique_ptr<PFRecoTauChargedHadron> chargedHadron(
265  new PFRecoTauChargedHadron(trackCharge_int, chargedPionP4, vtx, 0, true, PFRecoTauChargedHadron::kTrack));
266 
267  setChargedHadronTrack(*chargedHadron, edm::Ptr<TrackClass>(tracks, iTrack));
268 
269  // CV: Take code for propagating track to ECAL entrance
270  // from RecoParticleFlow/PFTracking/src/PFTrackTransformer.cc
271  // to make sure propagation is done in the same way as for charged PFCandidates.
272  //
273  // The following replacements need to be made
274  // outerMomentum -> momentum
275  // outerPosition -> referencePoint
276  // in order to run on AOD input
277  // (outerMomentum and outerPosition require access to reco::TrackExtra objects, which are available in RECO only)
278  //
279  XYZTLorentzVector chargedPionPos(getTrackPos(track));
280  RawParticle p(chargedPionP4, chargedPionPos);
281  p.setCharge(track.charge());
282  BaseParticlePropagator trackPropagator(p, 0., 0., magneticFieldStrength_.z());
283  trackPropagator.propagateToEcalEntrance(false);
284  if (trackPropagator.getSuccess() != 0) {
285  chargedHadron->positionAtECALEntrance_ = trackPropagator.particle().vertex();
286  } else {
287  if (chargedPionP4.pt() > 2. and std::abs(chargedPionP4.eta()) < 3.) {
288  edm::LogWarning("PFRecoTauChargedHadronFromGenericTrackPlugin::operator()")
289  << "Failed to propagate track: Pt = " << track.pt() << ", eta = " << track.eta()
290  << ", phi = " << track.phi() << " to ECAL entrance !!" << std::endl;
291  }
292  chargedHadron->positionAtECALEntrance_ = math::XYZPointF(0., 0., 0.);
293  }
294 
295  std::vector<Candidate_withDistance> neutralJetConstituents_withDistance;
296  for (const auto& jetConstituent : jet.daughterPtrVector()) {
297  int pdgId = jetConstituent->pdgId();
298  if (!(pdgId == 130 || pdgId == 22))
299  continue;
300  double dR = deltaR(atECALEntrance(&*jetConstituent, magneticFieldStrength_.z()),
301  chargedHadron->positionAtECALEntrance_);
302  double dRmerge = -1.;
303  if (pdgId == 130)
304  dRmerge = dRmergeNeutralHadron_;
305  else if (pdgId == 22)
306  dRmerge = dRmergePhoton_;
307  if (dR < dRmerge) {
308  Candidate_withDistance jetConstituent_withDistance;
309  jetConstituent_withDistance.pfCandidate_ = jetConstituent;
310  jetConstituent_withDistance.distance_ = dR;
311  neutralJetConstituents_withDistance.push_back(jetConstituent_withDistance);
312  chargedHadron->addDaughter(jetConstituent);
313  }
314  }
315  std::sort(
316  neutralJetConstituents_withDistance.begin(), neutralJetConstituents_withDistance.end(), isSmallerDistance);
317 
318  const double caloResolutionCoeff =
319  1.0; // CV: approximate ECAL + HCAL calorimeter resolution for hadrons by 100%*sqrt(E)
320  double resolutionTrackP = track.p() * (getTrackPtError(track) / track.pt());
321  double neutralEnSum = 0.;
322  for (std::vector<Candidate_withDistance>::const_iterator nextNeutral =
323  neutralJetConstituents_withDistance.begin();
324  nextNeutral != neutralJetConstituents_withDistance.end();
325  ++nextNeutral) {
326  double nextNeutralEn = nextNeutral->pfCandidate_->energy();
327  double resolutionCaloEn = caloResolutionCoeff * sqrt(neutralEnSum + nextNeutralEn);
328  double resolution = sqrt(resolutionTrackP * resolutionTrackP + resolutionCaloEn * resolutionCaloEn);
329  if ((neutralEnSum + nextNeutralEn) < (track.p() + 2. * resolution)) {
330  chargedHadron->neutralPFCandidates_.push_back(nextNeutral->pfCandidate_);
331  neutralEnSum += nextNeutralEn;
332  } else {
333  break;
334  }
335  }
336 
338 
339  if (verbosity_) {
340  edm::LogPrint("TauChHFromTrack") << *chargedHadron;
341  }
342 
343  output.push_back(std::move(chargedHadron));
344  }
345 
346  return output;
347  }
348 
351 
352  } // namespace tau
353 } // namespace reco
354 
356 
359  "PFRecoTauChargedHadronFromTrackPlugin");
362  "PFRecoTauChargedHadronFromLostTrackPlugin");
int Charge
electric charge type
Definition: Candidate.h:34
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
std::vector< std::unique_ptr< PFRecoTauChargedHadron > > ChargedHadronVector
math::XYZPointF atECALEntrance(const reco::Candidate *part, double bField)
reco::CandidatePtr pfCandidate_
bool filterTrack(const edm::Handle< std::vector< TrackClass > > &, size_t iTrack) const
Base class for all types of Jets.
Definition: Jet.h:20
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
PFRecoTauChargedHadronFromGenericTrackPlugin(const edm::ParameterSet &, edm::ConsumesCollector &&iC)
XYZTLorentzVector getTrackPos(const TrackClass &track) const
void setChargedHadronTrack(PFRecoTauChargedHadron &chargedHadron, const edm::Ptr< TrackClass > &track) const
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< float > > XYZPointF
point in space with cartesian internal representation
Definition: Point3D.h:10
void beginEvent() override
Hook called at the beginning of the event.
double getTrackPtError(const TrackClass &track) const
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
T sqrt(T t)
Definition: SSEVec.h:19
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
return_type operator()(const reco::Jet &) const override
Build a collection of chargedHadrons from objects in the input jet.
math::XYZPoint Point
point in the space
Definition: Vertex.h:40
Log< level::Warning, true > LogPrint
bool propagateToEcalEntrance(bool first=true)
#define M_PI
constexpr auto deltaR(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:30
Log< level::Info, false > LogInfo
auto const & tracks
cannot be loose
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:31
PFRecoTauChargedHadronFromGenericTrackPlugin< reco::Track > PFRecoTauChargedHadronFromTrackPlugin
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Candidate.h:36
fixed size matrix
HLT enums.
#define DEFINE_EDM_PLUGIN(factory, type, name)
PFRecoTauChargedHadronFromGenericTrackPlugin< pat::PackedCandidate > PFRecoTauChargedHadronFromLostTrackPlugin
Log< level::Warning, false > LogWarning
void setChargedHadronP4(reco::PFRecoTauChargedHadron &chargedHadron, double scaleFactor_neutralPFCands=1.0)
const edm::ESGetToken< MagneticField, IdealMagneticFieldRecord > magneticFieldToken_
def move(src, dest)
Definition: eostools.py:511
math::XYZTLorentzVector XYZTLorentzVector
Definition: RawParticle.h:25