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 
72  std::unique_ptr<RecoTauQualityCuts> qcuts_;
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_ = std::make_unique<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 
118  // Update the primary vertex
119  template <class TrackClass>
121  vertexAssociator_.setEvent(*this->evt());
122 
123  magneticFieldStrength_ = evtSetup()->getData(magneticFieldToken_).inTesla(GlobalPoint(0., 0., 0.));
124  }
125 
126  template <>
128  const edm::Handle<std::vector<reco::Track> >& tracks, size_t iTrack) const {
129  // ignore tracks which fail quality cuts
130  reco::TrackRef trackRef(tracks, iTrack);
131  return qcuts_->filterTrack(trackRef);
132  }
133 
134  template <>
136  const edm::Handle<std::vector<pat::PackedCandidate> >& tracks, size_t iTrack) const {
137  // ignore tracks which fail quality cuts
138  const pat::PackedCandidate& cand = (*tracks)[iTrack];
139  if (cand.charge() == 0)
140  return false;
141 
142  return qcuts_->filterChargedCand(cand);
143  }
144 
145  template <>
148  chargedHadron.track_ = track;
149  }
150 
151  template <>
154  chargedHadron.lostTrackCandidate_ = track;
155  }
156 
157  template <>
159  return track.ptError();
160  }
161 
162  template <>
164  const pat::PackedCandidate& cand) const {
165  double trackPtError =
166  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)
167  const reco::Track* track(cand.bestTrack());
168  if (track != nullptr) {
169  trackPtError = track->ptError();
170  } else {
171  if (std::abs(cand.eta()) < 0.9)
172  trackPtError = 0.025;
173  else if (std::abs(cand.eta()) < 1.4)
174  trackPtError = 0.04;
175  }
176  return trackPtError;
177  }
178 
179  template <>
181  const reco::Track& track) const {
182  return XYZTLorentzVector(track.referencePoint().x(), track.referencePoint().y(), track.referencePoint().z(), 0.);
183  }
184 
185  template <>
187  const pat::PackedCandidate& track) const {
188  return XYZTLorentzVector(track.vertex().x(), track.vertex().y(), track.vertex().z(), 0.);
189  }
190 
191  namespace {
192  struct Candidate_withDistance {
194  double distance_;
195  };
196 
197  bool isSmallerDistance(const Candidate_withDistance& cand1, const Candidate_withDistance& cand2) {
198  return (cand1.distance_ < cand2.distance_);
199  }
200  } // namespace
201 
202  template <class TrackClass>
205  if (verbosity_) {
206  edm::LogPrint("TauChHFromTrack") << "<PFRecoTauChargedHadronFromGenericTrackPlugin::operator()>:";
207  edm::LogPrint("TauChHFromTrack") << " pluginName = " << name();
208  }
209 
211 
212  const edm::Event& evt = (*this->evt());
213 
215  evt.getByToken(Tracks_token, tracks);
216 
217  qcuts_->setPV(vertexAssociator_.associatedVertex(jet));
218  float jEta = jet.eta();
219  float jPhi = jet.phi();
220  size_t numTracks = tracks->size();
221  for (size_t iTrack = 0; iTrack < numTracks; ++iTrack) {
222  const TrackClass& track = (*tracks)[iTrack];
223 
224  // consider tracks in vicinity of tau-jet candidate only
225  double dR = deltaR(track.eta(), track.phi(), jEta, jPhi);
226  double dRmatch = dRcone_;
227  if (dRconeLimitedToJetArea_) {
228  double jetArea = jet.jetArea();
229  if (jetArea > 0.) {
230  dRmatch = std::min(dRmatch, sqrt(jetArea / M_PI));
231  } else {
232  if (numWarnings_ < maxWarnings_) {
233  edm::LogInfo("PFRecoTauChargedHadronFromGenericTrackPlugin::operator()")
234  << "Jet: Pt = " << jet.pt() << ", eta = " << jet.eta() << ", phi = " << jet.phi()
235  << " has area = " << jetArea << " !!" << std::endl;
236  ++numWarnings_;
237  }
238  dRmatch = 0.1;
239  }
240  }
241  if (dR > dRmatch)
242  continue;
243 
244  if (!this->filterTrack(tracks, iTrack))
245  continue;
246 
247  reco::Candidate::Charge trackCharge_int = 0;
248  if (track.charge() > 0.)
249  trackCharge_int = +1;
250  else if (track.charge() < 0.)
251  trackCharge_int = -1;
252 
253  const double chargedPionMass = 0.13957; // GeV
254  double chargedPionP = track.p();
255  double chargedPionEn = TMath::Sqrt(chargedPionP * chargedPionP + chargedPionMass * chargedPionMass);
256  reco::Candidate::LorentzVector chargedPionP4(track.px(), track.py(), track.pz(), chargedPionEn);
257 
258  reco::Vertex::Point vtx(0., 0., 0.);
259  if (vertexAssociator_.associatedVertex(jet).isNonnull())
260  vtx = vertexAssociator_.associatedVertex(jet)->position();
261 
262  auto chargedHadron = std::make_unique<PFRecoTauChargedHadron>(
263  trackCharge_int, chargedPionP4, vtx, 0, true, PFRecoTauChargedHadron::kTrack);
264 
265  setChargedHadronTrack(*chargedHadron, edm::Ptr<TrackClass>(tracks, iTrack));
266 
267  // CV: Take code for propagating track to ECAL entrance
268  // from RecoParticleFlow/PFTracking/src/PFTrackTransformer.cc
269  // to make sure propagation is done in the same way as for charged PFCandidates.
270  //
271  // The following replacements need to be made
272  // outerMomentum -> momentum
273  // outerPosition -> referencePoint
274  // in order to run on AOD input
275  // (outerMomentum and outerPosition require access to reco::TrackExtra objects, which are available in RECO only)
276  //
277  XYZTLorentzVector chargedPionPos(getTrackPos(track));
278  RawParticle p(chargedPionP4, chargedPionPos);
279  p.setCharge(track.charge());
280  BaseParticlePropagator trackPropagator(p, 0., 0., magneticFieldStrength_.z());
281  trackPropagator.propagateToEcalEntrance(false);
282  if (trackPropagator.getSuccess() != 0) {
283  chargedHadron->positionAtECALEntrance_ = trackPropagator.particle().vertex();
284  } else {
285  if (chargedPionP4.pt() > 2. and std::abs(chargedPionP4.eta()) < 3.) {
286  edm::LogWarning("PFRecoTauChargedHadronFromGenericTrackPlugin::operator()")
287  << "Failed to propagate track: Pt = " << track.pt() << ", eta = " << track.eta()
288  << ", phi = " << track.phi() << " to ECAL entrance !!" << std::endl;
289  }
290  chargedHadron->positionAtECALEntrance_ = math::XYZPointF(0., 0., 0.);
291  }
292 
293  std::vector<Candidate_withDistance> neutralJetConstituents_withDistance;
294  for (const auto& jetConstituent : jet.daughterPtrVector()) {
295  int pdgId = jetConstituent->pdgId();
296  if (!(pdgId == 130 || pdgId == 22))
297  continue;
298  double dR = deltaR(atECALEntrance(&*jetConstituent, magneticFieldStrength_.z()),
299  chargedHadron->positionAtECALEntrance_);
300  double dRmerge = -1.;
301  if (pdgId == 130)
302  dRmerge = dRmergeNeutralHadron_;
303  else if (pdgId == 22)
304  dRmerge = dRmergePhoton_;
305  if (dR < dRmerge) {
306  Candidate_withDistance jetConstituent_withDistance;
307  jetConstituent_withDistance.pfCandidate_ = jetConstituent;
308  jetConstituent_withDistance.distance_ = dR;
309  neutralJetConstituents_withDistance.push_back(jetConstituent_withDistance);
310  chargedHadron->addDaughter(jetConstituent);
311  }
312  }
313  std::sort(
314  neutralJetConstituents_withDistance.begin(), neutralJetConstituents_withDistance.end(), isSmallerDistance);
315 
316  const double caloResolutionCoeff =
317  1.0; // CV: approximate ECAL + HCAL calorimeter resolution for hadrons by 100%*sqrt(E)
318  double resolutionTrackP = track.p() * (getTrackPtError(track) / track.pt());
319  double neutralEnSum = 0.;
320  for (std::vector<Candidate_withDistance>::const_iterator nextNeutral =
321  neutralJetConstituents_withDistance.begin();
322  nextNeutral != neutralJetConstituents_withDistance.end();
323  ++nextNeutral) {
324  double nextNeutralEn = nextNeutral->pfCandidate_->energy();
325  double resolutionCaloEn = caloResolutionCoeff * sqrt(neutralEnSum + nextNeutralEn);
326  double resolution = sqrt(resolutionTrackP * resolutionTrackP + resolutionCaloEn * resolutionCaloEn);
327  if ((neutralEnSum + nextNeutralEn) < (track.p() + 2. * resolution)) {
328  chargedHadron->neutralPFCandidates_.push_back(nextNeutral->pfCandidate_);
329  neutralEnSum += nextNeutralEn;
330  } else {
331  break;
332  }
333  }
334 
336 
337  if (verbosity_) {
338  edm::LogPrint("TauChHFromTrack") << *chargedHadron;
339  }
340 
341  output.push_back(std::move(chargedHadron));
342  }
343 
344  return output;
345  }
346 
349 
350  } // namespace tau
351 } // namespace reco
352 
354 
357  "PFRecoTauChargedHadronFromTrackPlugin");
360  "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:526
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:23
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
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)
Definition: output.py:1
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