CMS 3D CMS Logo

PFCandConnector.cc
Go to the documentation of this file.
7 
8 using namespace reco;
9 using namespace std;
10 
11 const double PFCandConnector::pion_mass2 = 0.0194;
12 
15 
17  bool bCalibPrimary,
18  double dptRel_PrimaryTrack,
19  double dptRel_MergedTrack,
20  double ptErrorSecondary,
21  const std::vector<double>& nuclCalibFactors) {
22  bCorrect_ = bCorrect;
23  bCalibPrimary_ = bCalibPrimary;
24  dptRel_PrimaryTrack_ = dptRel_PrimaryTrack;
25  dptRel_MergedTrack_ = dptRel_MergedTrack;
26  ptErrorSecondary_ = ptErrorSecondary;
27 
28  if (nuclCalibFactors.size() == 5) {
29  fConst_[0] = nuclCalibFactors[0];
30  fConst_[1] = nuclCalibFactors[1];
31 
32  fNorm_[0] = nuclCalibFactors[2];
33  fNorm_[1] = nuclCalibFactors[3];
34 
35  fExp_[0] = nuclCalibFactors[4];
36  } else {
37  edm::LogWarning("PFCandConnector")
38  << "Wrong calibration factors for nuclear interactions. The calibration procedure would not be applyed."
39  << std::endl;
40  bCalibPrimary_ = false;
41  }
42 
43  std::string sCorrect = bCorrect_ ? "On" : "Off";
44  edm::LogInfo("PFCandConnector") << " ====================== The PFCandConnector is switched " << sCorrect.c_str()
45  << " ==================== " << std::endl;
46  std::string sCalibPrimary = bCalibPrimary_ ? "used for calibration" : "not used for calibration";
47  if (bCorrect_)
48  edm::LogInfo("PFCandConnector") << "Primary Tracks are " << sCalibPrimary.c_str() << std::endl;
49  if (bCorrect_ && bCalibPrimary_)
50  edm::LogInfo("PFCandConnector") << "Under the condition that the precision on the Primary track is better than "
51  << dptRel_PrimaryTrack_ << " % " << std::endl;
52  if (bCorrect_ && bCalibPrimary_)
53  edm::LogInfo("PFCandConnector") << " and on merged tracks better than " << dptRel_MergedTrack_ << " % "
54  << std::endl;
55  if (bCorrect_ && bCalibPrimary_)
56  edm::LogInfo("PFCandConnector") << " and secondary tracks in some cases more precise than "
57  << ptErrorSecondary_ << " GeV" << std::endl;
58  if (bCorrect_ && bCalibPrimary_)
59  edm::LogInfo("PFCandConnector") << "factor = (" << fConst_[0] << " + " << fConst_[1] << "*cFrac) - (" << fNorm_[0]
60  << " - " << fNorm_[1] << "cFrac)*exp( " << -1 * fExp_[0] << "*pT )" << std::endl;
61  edm::LogInfo("PFCandConnector") << " =========================================================== " << std::endl;
62 }
63 
68  std::vector<bool> bMask;
69  bMask.resize(pfCand.size(), false);
70 
71  // loop on primary
72  if (bCorrect_) {
73  LogTrace("PFCandConnector|connect") << "pfCand.size()=" << pfCand.size() << "bCalibPrimary_=" << bCalibPrimary_;
74 
75  for (unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1) {
76  if (isPrimaryNucl(pfCand.at(ce1))) {
77  LogTrace("PFCandConnector|connect")
78  << "" << endl
79  << "Nuclear Interaction w Primary Candidate " << ce1 << " " << pfCand.at(ce1) << endl
80  << " based on the Track " << pfCand.at(ce1).trackRef().key()
81  << " w pT = " << pfCand.at(ce1).trackRef()->pt() << " #pm "
82  << pfCand.at(ce1).trackRef()->ptError() / pfCand.at(ce1).trackRef()->pt() * 100 << " %"
83  << " ECAL = " << pfCand.at(ce1).ecalEnergy() << " HCAL = " << pfCand.at(ce1).hcalEnergy() << endl;
84 
85 #ifdef EDM_ML_DEBUG
86  (pfCand.at(ce1)).displacedVertexRef(fT_TO_DISP_)->Dump();
87 #endif
88 
89  analyseNuclearWPrim(pfCand, bMask, ce1);
90 
91 #ifdef EDM_ML_DEBUG
92  LogTrace("PFCandConnector|connect")
93  << "After Connection the candidate " << ce1 << " is " << pfCand.at(ce1) << endl
94  << endl;
95 
96  PFCandidate::ElementsInBlocks elementsInBlocks = pfCand.at(ce1).elementsInBlocks();
97  for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
98  if (blockElem == 0)
99  LogTrace("PFCandConnector|connect") << *(elementsInBlocks[blockElem].first) << endl;
100  LogTrace("PFCandConnector|connect") << " position " << elementsInBlocks[blockElem].second;
101  }
102 #endif
103  }
104  }
105 
106  for (unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1) {
107  if (!bMask[ce1] && isSecondaryNucl(pfCand.at(ce1))) {
108  LogTrace("PFCandConnector|connect")
109  << "" << endl
110  << "Nuclear Interaction w no Primary Candidate " << ce1 << " " << pfCand.at(ce1) << endl
111  << " based on the Track " << pfCand.at(ce1).trackRef().key()
112  << " w pT = " << pfCand.at(ce1).trackRef()->pt() << " #pm " << pfCand.at(ce1).trackRef()->ptError() << " %"
113  << " ECAL = " << pfCand.at(ce1).ecalEnergy() << " HCAL = " << pfCand.at(ce1).hcalEnergy()
114  << " dE(Trk-CALO) = "
115  << pfCand.at(ce1).trackRef()->p() - pfCand.at(ce1).ecalEnergy() - pfCand.at(ce1).hcalEnergy()
116  << " Nmissing hits = "
117  << pfCand.at(ce1).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS) << endl;
118 
119 #ifdef EDM_ML_DEBUG
120  (pfCand.at(ce1)).displacedVertexRef(fT_FROM_DISP_)->Dump();
121 #endif
122 
123  analyseNuclearWSec(pfCand, bMask, ce1);
124 
125 #ifdef EDM_ML_DEBUG
126  LogTrace("PFCandConnector|connect") << "After Connection the candidate " << ce1 << " is " << pfCand.at(ce1)
127  << " and elements connected to it are: " << endl;
128 
129  PFCandidate::ElementsInBlocks elementsInBlocks = pfCand.at(ce1).elementsInBlocks();
130  for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
131  if (blockElem == 0)
132  LogTrace("PFCandConnector|connect") << *(elementsInBlocks[blockElem].first) << endl;
133  LogTrace("PFCandConnector|connect") << " position " << elementsInBlocks[blockElem].second;
134  }
135 #endif
136  }
137  }
138  }
139 
140  for (unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1)
141  if (!bMask[ce1])
142  pfC.push_back(pfCand.at(ce1));
143 
144  LogTrace("PFCandConnector|connect") << "end of function";
145 
146  return pfC;
147 }
148 
150  std::vector<bool>& bMask,
151  unsigned int ce1) const {
152  PFDisplacedVertexRef ref1, ref2, ref1_bis;
153 
154  PFCandidate primaryCand = pfCand.at(ce1);
155 
156  // ------- look for the little friends -------- //
157 
158  const math::XYZTLorentzVectorD& momentumPrim = primaryCand.p4();
159 
160  math::XYZTLorentzVectorD momentumSec;
161 
162  momentumSec = momentumPrim / momentumPrim.E() * (primaryCand.ecalEnergy() + primaryCand.hcalEnergy());
163 
164  map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
165  map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
166 
167  ref1 = primaryCand.displacedVertexRef(fT_TO_DISP_);
168 
169  for (unsigned int ce2 = 0; ce2 < pfCand.size(); ++ce2) {
170  if (ce2 != ce1 && isSecondaryNucl(pfCand.at(ce2))) {
171  ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
172 
173  if (ref1 == ref2) {
174  LogTrace("PFCandConnector|analyseNuclearWPrim")
175  << "\t here is a Secondary Candidate " << ce2 << " " << pfCand.at(ce2) << endl
176  << "\t based on the Track " << pfCand.at(ce2).trackRef().key()
177  << " w p = " << pfCand.at(ce2).trackRef()->p() << " w pT = " << pfCand.at(ce2).trackRef()->pt() << " #pm "
178  << pfCand.at(ce2).trackRef()->ptError() << " %"
179  << " ECAL = " << pfCand.at(ce2).ecalEnergy() << " HCAL = " << pfCand.at(ce2).hcalEnergy()
180  << " dE(Trk-CALO) = "
181  << pfCand.at(ce2).trackRef()->p() - pfCand.at(ce2).ecalEnergy() - pfCand.at(ce2).hcalEnergy()
182  << " Nmissing hits = "
183  << pfCand.at(ce2).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS) << endl;
184 
185  if (isPrimaryNucl(pfCand.at(ce2))) {
186  LogTrace("PFCandConnector|analyseNuclearWPrim") << "\t\t but it is also a Primary Candidate " << ce2 << endl;
187 
188  ref1_bis = (pfCand.at(ce2)).displacedVertexRef(fT_TO_DISP_);
189  if (ref1_bis.isNonnull())
190  analyseNuclearWPrim(pfCand, bMask, ce2);
191  }
192 
193  // Take now the parameters of the secondary track that are relevant and use them to construct the NI candidate
194 
195  PFCandidate::ElementsInBlocks elementsInBlocks = pfCand.at(ce2).elementsInBlocks();
196  PFCandidate::ElementsInBlocks elementsAlreadyInBlocks = pfCand.at(ce1).elementsInBlocks();
197  for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
198  bool isAlreadyHere = false;
199  for (unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++) {
200  if (elementsAlreadyInBlocks[alreadyBlock].second == elementsInBlocks[blockElem].second)
201  isAlreadyHere = true;
202  }
203  if (!isAlreadyHere)
204  pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].first, elementsInBlocks[blockElem].second);
205  }
206 
207  double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
208  double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
209  int nMissOuterHits =
210  pfCand.at(ce2).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS);
211 
212  // Check if the difference Track Calo is not too large and if we can trust the track, ie it doesn't miss too much hits.
213  if (deltaEn > 1 && nMissOuterHits > 1) {
214  math::XYZTLorentzVectorD momentumToAdd = pfCand.at(ce2).p4() * caloEn / pfCand.at(ce2).p4().E();
215  momentumSec += momentumToAdd;
216  LogTrace("PFCandConnector|analyseNuclearWPrim")
217  << "The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may "
218  "have happened. Let's trust the calo energy"
219  << endl
220  << "add " << momentumToAdd << endl;
221 
222  } else {
223  // Check if the difference Track Calo is not too large and if we can trust the track, ie it doesn't miss too much hits.
224  if (caloEn > 0.01 && deltaEn > 1 && nMissOuterHits > 0) {
225  math::XYZTLorentzVectorD momentumExcess = pfCand.at(ce2).p4() * deltaEn / pfCand.at(ce2).p4().E();
226  candidatesWithTrackExcess[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
227  momentumExcess;
228  } else if (caloEn < 0.01)
229  candidatesWithoutCalo[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
230  pfCand.at(ce2).p4();
231  momentumSec += (pfCand.at(ce2)).p4();
232  }
233 
234  bMask[ce2] = true;
235  }
236  }
237  }
238 
239  // We have more primary energy than secondary: reject all secondary tracks which have no calo energy attached.
240 
241  if (momentumPrim.E() < momentumSec.E()) {
242  LogTrace("PFCandConnector|analyseNuclearWPrim")
243  << "Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
244  for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin();
245  iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E();
246  iter++)
247  if (momentumSec.E() > iter->second.E() + 0.1) {
248  momentumSec -= iter->second;
249 
250  LogTrace("PFCandConnector|analyseNuclearWPrim")
251  << "\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
252  LogTrace("PFCandConnector|analyseNuclearWPrim")
253  << "momentumPrim.E() = " << momentumPrim.E() << " and momentumSec.E() = " << momentumSec.E() << endl;
254  }
255  }
256 
257  if (momentumPrim.E() < momentumSec.E()) {
258  LogTrace("PFCandConnector|analyseNuclearWPrim")
259  << "0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates"
260  << candidatesWithTrackExcess.size() << endl;
261  for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin();
262  iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E();
263  iter++)
264  if (momentumSec.E() > iter->second.E() + 0.1)
265  momentumSec -= iter->second;
266  }
267 
268  double dpt = pfCand.at(ce1).trackRef()->ptError() / pfCand.at(ce1).trackRef()->pt() * 100;
269 
270  if (momentumSec.E() < 0.1) {
271  bMask[ce1] = true;
272  return;
273  }
274 
275  // Rescale the secondary candidates to account for the loss of energy, but only if we can trust the primary track:
276  // if it has more energy than secondaries and is precise enough and secondary exist and was not eaten or rejected during the PFAlgo step.
277 
278  if (((ref1->isTherePrimaryTracks() && dpt < dptRel_PrimaryTrack_) ||
279  (ref1->isThereMergedTracks() && dpt < dptRel_MergedTrack_)) &&
280  momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
281  if (bCalibPrimary_) {
282  double factor = rescaleFactor(momentumPrim.Pt(), momentumSec.E() / momentumPrim.E());
283  LogTrace("PFCandConnector|analyseNuclearWPrim") << "factor = " << factor << endl;
284  if (factor * momentumPrim.Pt() < momentumSec.Pt())
285  momentumSec = momentumPrim;
286  else
287  momentumSec += (1 - factor) * momentumPrim;
288  }
289 
290  double px = momentumPrim.Px() * momentumSec.P() / momentumPrim.P();
291  double py = momentumPrim.Py() * momentumSec.P() / momentumPrim.P();
292  double pz = momentumPrim.Pz() * momentumSec.P() / momentumPrim.P();
293  double E = sqrt(px * px + py * py + pz * pz + pion_mass2);
294  math::XYZTLorentzVectorD momentum(px, py, pz, E);
295  pfCand.at(ce1).setP4(momentum);
296 
297  return;
298 
299  } else {
300  math::XYZVector primDir = ref1->primaryDirection();
301 
302  if (primDir.Mag2() < 0.1) {
303  // It might be 0 but this situation should never happend. Throw a warning if it happens.
304  edm::LogWarning("PFCandConnector") << "A Nuclear Interaction do not have primary direction" << std::endl;
305  pfCand.at(ce1).setP4(momentumSec);
306  return;
307  } else {
308  // rescale the primary direction to the optimal momentum. But take care of the factthat it shall not be completly 0 to avoid a warning if Jet Area.
309  double momentumS = momentumSec.P();
310  if (momentumS < 1e-4)
311  momentumS = 1e-4;
312  double px = momentumS * primDir.x();
313  double py = momentumS * primDir.y();
314  double pz = momentumS * primDir.z();
315  double E = sqrt(px * px + py * py + pz * pz + pion_mass2);
316 
317  math::XYZTLorentzVectorD momentum(px, py, pz, E);
318  pfCand.at(ce1).setP4(momentum);
319  return;
320  }
321  }
322 }
323 
325  std::vector<bool>& bMask,
326  unsigned int ce1) const {
327  PFDisplacedVertexRef ref1, ref2;
328 
329  // Check if the track excess was not too large and track may miss some outer hits. This may point to a secondary NI.
330 
331  double caloEn = pfCand.at(ce1).ecalEnergy() + pfCand.at(ce1).hcalEnergy();
332  double deltaEn = pfCand.at(ce1).p4().E() - caloEn;
333  int nMissOuterHits = pfCand.at(ce1).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS);
334 
335  ref1 = pfCand.at(ce1).displacedVertexRef(fT_FROM_DISP_);
336 
337  // ------- check if an electron or a muon vas spotted as incoming track -------- //
338  // ------- this mean probably that the NI was fake thus we do not correct it -------- /
339 
340  if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()) {
341  std::vector<reco::Track> refittedTracks = ref1->refittedTracks();
342  for (unsigned it = 0; it < refittedTracks.size(); it++) {
343  reco::TrackBaseRef primaryBaseRef = ref1->originalTrack(refittedTracks[it]);
344  if (ref1->isIncomingTrack(primaryBaseRef))
345  LogTrace("PFCandConnector|analyseNuclearWSec")
346  << "There is a Primary track ref with pt = " << primaryBaseRef->pt() << endl;
347 
348  for (unsigned int ce = 0; ce < pfCand.size(); ++ce) {
349  // cout << "PFCand Id = " << (pfCand.at(ce)).particleId() << endl;
350  if ((pfCand.at(ce)).particleId() == reco::PFCandidate::e ||
351  (pfCand.at(ce)).particleId() == reco::PFCandidate::mu) {
352  LogTrace("PFCandConnector|analyseNuclearWSec")
353  << " It is an electron and it has a ref to a track " << (pfCand.at(ce)).trackRef().isNonnull() << endl;
354 
355  if ((pfCand.at(ce)).trackRef().isNonnull()) {
356  reco::TrackRef tRef = (pfCand.at(ce)).trackRef();
357  reco::TrackBaseRef bRef(tRef);
358  LogTrace("PFCandConnector|analyseNuclearWSec")
359  << "With Track Ref pt = " << (pfCand.at(ce)).trackRef()->pt() << endl;
360 
361  if (bRef == primaryBaseRef) {
362  if ((pfCand.at(ce)).particleId() == reco::PFCandidate::e)
363  LogTrace("PFCandConnector|analyseNuclearWSec")
364  << "It is a NI from electron. NI Discarded. Just release the candidate." << endl;
365  if ((pfCand.at(ce)).particleId() == reco::PFCandidate::mu)
366  LogTrace("PFCandConnector|analyseNuclearWSec")
367  << "It is a NI from muon. NI Discarded. Just release the candidate" << endl;
368 
369  // release the track but take care of not overcounting bad tracks. In fact those tracks was protected against destruction in
370  // PFAlgo. Now we treat them as if they was treated in PFAlgo
371 
372  if (caloEn < 0.1 && pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
373  edm::LogInfo("PFCandConnector|analyseNuclearWSec")
374  << "discarded track since no calo energy and ill measured" << endl;
375  bMask[ce1] = true;
376  }
377  if (caloEn > 0.1 && deltaEn > ptErrorSecondary_ &&
378  pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
379  edm::LogInfo("PFCandConnector|analyseNuclearWSec")
380  << "rescaled momentum of the track since no calo energy and ill measured" << endl;
381 
382  double factor = caloEn / pfCand.at(ce1).p4().E();
383  pfCand.at(ce1).rescaleMomentum(factor);
384  }
385 
386  return;
387  }
388  }
389  }
390  }
391  }
392  }
393 
394  PFCandidate secondaryCand = pfCand.at(ce1);
395 
396  math::XYZTLorentzVectorD momentumSec = secondaryCand.p4();
397 
398  if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
399  math::XYZTLorentzVectorD momentumToAdd = pfCand.at(ce1).p4() * caloEn / pfCand.at(ce1).p4().E();
400  momentumSec = momentumToAdd;
401  LogTrace("PFCandConnector|analyseNuclearWSec")
402  << "The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have "
403  "happened. Let's trust the calo energy"
404  << endl
405  << "add " << momentumToAdd << endl;
406  }
407 
408  // ------- look for the little friends -------- //
409  for (unsigned int ce2 = ce1 + 1; ce2 < pfCand.size(); ++ce2) {
410  if (isSecondaryNucl(pfCand.at(ce2))) {
411  ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
412 
413  if (ref1 == ref2) {
414  LogTrace("PFCandConnector|analyseNuclearWSec")
415  << "\t here is a Secondary Candidate " << ce2 << " " << pfCand.at(ce2) << endl
416  << "\t based on the Track " << pfCand.at(ce2).trackRef().key()
417  << " w pT = " << pfCand.at(ce2).trackRef()->pt() << " #pm " << pfCand.at(ce2).trackRef()->ptError() << " %"
418  << " ECAL = " << pfCand.at(ce2).ecalEnergy() << " HCAL = " << pfCand.at(ce2).hcalEnergy()
419  << " dE(Trk-CALO) = "
420  << pfCand.at(ce2).trackRef()->p() - pfCand.at(ce2).ecalEnergy() - pfCand.at(ce2).hcalEnergy()
421  << " Nmissing hits = "
422  << pfCand.at(ce2).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS) << endl;
423 
424  // Take now the parameters of the secondary track that are relevant and use them to construct the NI candidate
425  PFCandidate::ElementsInBlocks elementsInBlocks = pfCand.at(ce2).elementsInBlocks();
426  PFCandidate::ElementsInBlocks elementsAlreadyInBlocks = pfCand.at(ce1).elementsInBlocks();
427  for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
428  bool isAlreadyHere = false;
429  for (unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++) {
430  if (elementsAlreadyInBlocks[alreadyBlock].second == elementsInBlocks[blockElem].second)
431  isAlreadyHere = true;
432  }
433  if (!isAlreadyHere)
434  pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].first, elementsInBlocks[blockElem].second);
435  }
436 
437  double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
438  double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
439  int nMissOuterHits =
440  pfCand.at(ce2).trackRef()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS);
441  if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
442  math::XYZTLorentzVectorD momentumToAdd = pfCand.at(ce2).p4() * caloEn / pfCand.at(ce2).p4().E();
443  momentumSec += momentumToAdd;
444  LogTrace("PFCandConnector|analyseNuclearWSec")
445  << "The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may "
446  "have happened. Let's trust the calo energy"
447  << endl
448  << "add " << momentumToAdd << endl;
449  } else {
450  momentumSec += (pfCand.at(ce2)).p4();
451  }
452 
453  bMask[ce2] = true;
454  }
455  }
456  }
457 
458  math::XYZVector primDir = ref1->primaryDirection();
459 
460  if (primDir.Mag2() < 0.1) {
461  // It might be 0 but this situation should never happend. Throw a warning if it happens.
462  pfCand.at(ce1).setP4(momentumSec);
463  edm::LogWarning("PFCandConnector") << "A Nuclear Interaction do not have primary direction" << std::endl;
464  return;
465  } else {
466  // rescale the primary direction to the optimal momentum. But take care of the factthat it shall not be completly 0 to avoid a warning if Jet Area.
467  double momentumS = momentumSec.P();
468  if (momentumS < 1e-4)
469  momentumS = 1e-4;
470  double px = momentumS * primDir.x();
471  double py = momentumS * primDir.y();
472  double pz = momentumS * primDir.z();
473  double E = sqrt(px * px + py * py + pz * pz + pion_mass2);
474 
475  math::XYZTLorentzVectorD momentum(px, py, pz, E);
476 
477  pfCand.at(ce1).setP4(momentum);
478  return;
479  }
480 }
481 
484  // nuclear
485  if (pf.flag(fT_FROM_DISP_)) {
486  ref1 = pf.displacedVertexRef(fT_FROM_DISP_);
487  // ref1->Dump();
488  if (!ref1.isNonnull())
489  return false;
490  else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
491  return true;
492  }
493 
494  return false;
495 }
496 
499 
500  // nuclear
501  if (pf.flag(fT_TO_DISP_)) {
502  ref1 = pf.displacedVertexRef(fT_TO_DISP_);
503  //ref1->Dump();
504 
505  if (!ref1.isNonnull())
506  return false;
507  else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
508  return true;
509  }
510 
511  return false;
512 }
513 
514 double PFCandConnector::rescaleFactor(const double pt, const double cFrac) const {
515  /*
516  LOG NORMAL FIT
517  FCN=35.8181 FROM MIGRAD STATUS=CONVERGED 257 CALLS 258 TOTAL
518  EDM=8.85763e-09 STRATEGY= 1 ERROR MATRIX ACCURATE
519  EXT PARAMETER STEP FIRST
520  NO. NAME VALUE ERROR SIZE DERIVATIVE
521  1 p0 7.99434e-01 2.77264e-02 6.59108e-06 9.80247e-03
522  2 p1 1.51303e-01 2.89981e-02 1.16775e-05 6.99035e-03
523  3 p2 -5.03829e-01 2.87929e-02 1.90070e-05 1.37015e-03
524  4 p3 4.54043e-01 5.00908e-02 3.17625e-05 3.86622e-03
525  5 p4 -4.61736e-02 8.07940e-03 3.25775e-06 -1.37247e-02
526  */
527 
528  /*
529  FCN=34.4051 FROM MIGRAD STATUS=CONVERGED 221 CALLS 222 TOTAL
530  EDM=1.02201e-09 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 2.3 per cent
531 
532  fConst
533  1 p0 7.99518e-01 2.23519e-02 1.41523e-06 4.05975e-04
534  2 p1 1.44619e-01 2.39398e-02 -7.68117e-07 -2.55775e-03
535 
536  fNorm
537  3 p2 -5.16571e-01 3.12362e-02 5.74932e-07 3.42292e-03
538  4 p3 4.69055e-01 5.09665e-02 1.94353e-07 1.69031e-03
539 
540  fExp
541  5 p4 -5.18044e-02 8.13458e-03 4.29815e-07 -1.07624e-02
542  */
543 
544  double fConst, fNorm, fExp;
545 
546  fConst = fConst_[0] + fConst_[1] * cFrac;
547  fNorm = fNorm_[0] - fNorm_[1] * cFrac;
548  fExp = fExp_[0];
549 
550  double factor = fConst - fNorm * exp(-fExp * pt);
551 
552  return factor;
553 }
554 
556  iDesc.add<bool>("bCorrect", true);
557  iDesc.add<bool>("bCalibPrimary", true);
558  iDesc.add<double>("dptRel_PrimaryTrack", 10.0);
559  iDesc.add<double>("dptRel_MergedTrack", 5.0);
560  iDesc.add<double>("ptErrorSecondary", 1.0);
561  iDesc.add<std::vector<double>>("nuclCalibFactors", {0.8, 0.15, 0.5, 0.5, 0.05});
562 }
double ecalEnergy() const
return corrected Ecal energy
Definition: PFCandidate.h:220
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
bool isPrimaryNucl(const reco::PFCandidate &pf) const
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzE4D< double > > XYZTLorentzVectorD
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:14
bool isSecondaryNucl(const reco::PFCandidate &pf) const
void analyseNuclearWSec(reco::PFCandidateCollection &, std::vector< bool > &, unsigned int) const
Analyse nuclear interactions where a secondary track is present.
double rescaleFactor(const double pt, const double cFrac) const
Return a calibration factor for a reconstructed nuclear interaction.
static const reco::PFCandidate::Flags fT_FROM_DISP_
static const reco::PFCandidate::Flags fT_TO_DISP_
std::vector< ElementInBlock > ElementsInBlocks
Definition: PFCandidate.h:378
reco::PFDisplacedVertexRef displacedVertexRef(Flags type) const
Definition: PFCandidate.cc:481
U second(std::pair< T, U > const &p)
T sqrt(T t)
Definition: SSEVec.h:19
double p4[4]
Definition: TauolaWrapper.h:92
double pt() const
track transverse momentum
Definition: TrackBase.h:602
bool flag(Flags theFlag) const
return a given flag
Definition: PFCandidate.cc:284
const LorentzVector & p4() const final
four-momentum Lorentz vector
reco::PFCandidateCollection connect(reco::PFCandidateCollection &pfCand) const
void analyseNuclearWPrim(reco::PFCandidateCollection &, std::vector< bool > &, unsigned int) const
Analyse nuclear interactions where a primary or merged track is present.
static const double pion_mass2
Useful constants.
ParameterDescriptionBase * add(U const &iLabel, T const &value)
#define LogTrace(id)
static void fillPSetDescription(edm::ParameterSetDescription &iDesc)
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:31
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:40
fixed size matrix
double hcalEnergy() const
return corrected Hcal energy
Definition: PFCandidate.h:232
void setParameters(const edm::ParameterSet &iCfgCandConnector)