37 <<
"Wrong calibration factors for nuclear interactions. The calibration procedure would not be applyed." 39 bCalibPrimary_ =
false;
43 edm::LogInfo(
"PFCandConnector") <<
" ====================== The PFCandConnector is switched " << sCorrect.c_str()
44 <<
" ==================== " << std::endl;
45 std::string sCalibPrimary = bCalibPrimary_ ?
"used for calibration" :
"not used for calibration";
47 edm::LogInfo(
"PFCandConnector") <<
"Primary Tracks are " << sCalibPrimary.c_str() << std::endl;
48 if (bCorrect_ && bCalibPrimary_)
49 edm::LogInfo(
"PFCandConnector") <<
"Under the condition that the precision on the Primary track is better than " 50 << dptRel_PrimaryTrack_ <<
" % " << std::endl;
51 if (bCorrect_ && bCalibPrimary_)
52 edm::LogInfo(
"PFCandConnector") <<
" and on merged tracks better than " << dptRel_MergedTrack_ <<
" % " 54 if (bCorrect_ && bCalibPrimary_)
55 edm::LogInfo(
"PFCandConnector") <<
" and secondary tracks in some cases more precise than " 56 << ptErrorSecondary_ <<
" GeV" << std::endl;
57 if (bCorrect_ && bCalibPrimary_)
58 edm::LogInfo(
"PFCandConnector") <<
"factor = (" << fConst_[0] <<
" + " << fConst_[1] <<
"*cFrac) - (" << fNorm_[0]
59 <<
" - " << fNorm_[1] <<
"cFrac)*exp( " << -1 * fExp_[0] <<
"*pT )" << std::endl;
60 edm::LogInfo(
"PFCandConnector") <<
" =========================================================== " << std::endl;
67 std::vector<bool> bMask;
68 bMask.resize(pfCand.size(),
false);
72 LogTrace(
"PFCandConnector|connect") <<
"pfCand.size()=" << pfCand.size() <<
"bCalibPrimary_=" << bCalibPrimary_;
74 for (
unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1) {
75 if (isPrimaryNucl(pfCand.at(ce1))) {
78 <<
"Nuclear Interaction w Primary Candidate " << ce1 <<
" " << pfCand.at(ce1) << endl
79 <<
" based on the Track " << pfCand.at(ce1).trackRef().key()
80 <<
" w pT = " << pfCand.at(ce1).trackRef()->pt() <<
" #pm " 81 << pfCand.at(ce1).trackRef()->ptError() / pfCand.at(ce1).trackRef()->pt() * 100 <<
" %" 82 <<
" ECAL = " << pfCand.at(ce1).ecalEnergy() <<
" HCAL = " << pfCand.at(ce1).hcalEnergy() << endl;
85 (pfCand.at(ce1)).displacedVertexRef(fT_TO_DISP_)->Dump();
88 analyseNuclearWPrim(pfCand, bMask, ce1);
92 <<
"After Connection the candidate " << ce1 <<
" is " << pfCand.at(ce1) << endl
96 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
98 LogTrace(
"PFCandConnector|connect") << *(elementsInBlocks[blockElem].first) << endl;
99 LogTrace(
"PFCandConnector|connect") <<
" position " << elementsInBlocks[blockElem].second;
105 for (
unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1) {
106 if (!bMask[ce1] && isSecondaryNucl(pfCand.at(ce1))) {
109 <<
"Nuclear Interaction w no Primary Candidate " << ce1 <<
" " << pfCand.at(ce1) << endl
110 <<
" based on the Track " << pfCand.at(ce1).trackRef().key()
111 <<
" w pT = " << pfCand.at(ce1).trackRef()->pt() <<
" #pm " << pfCand.at(ce1).trackRef()->ptError() <<
" %" 112 <<
" ECAL = " << pfCand.at(ce1).ecalEnergy() <<
" HCAL = " << pfCand.at(ce1).hcalEnergy()
113 <<
" dE(Trk-CALO) = " 114 << pfCand.at(ce1).trackRef()->p() - pfCand.at(ce1).ecalEnergy() - pfCand.at(ce1).hcalEnergy()
115 <<
" Nmissing hits = " 119 (pfCand.at(ce1)).displacedVertexRef(fT_FROM_DISP_)->Dump();
122 analyseNuclearWSec(pfCand, bMask, ce1);
125 LogTrace(
"PFCandConnector|connect") <<
"After Connection the candidate " << ce1 <<
" is " << pfCand.at(ce1)
126 <<
" and elements connected to it are: " << endl;
129 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
131 LogTrace(
"PFCandConnector|connect") << *(elementsInBlocks[blockElem].first) << endl;
132 LogTrace(
"PFCandConnector|connect") <<
" position " << elementsInBlocks[blockElem].second;
139 for (
unsigned int ce1 = 0; ce1 < pfCand.size(); ++ce1)
141 pfC.push_back(pfCand.at(ce1));
143 LogTrace(
"PFCandConnector|connect") <<
"end of function";
149 std::vector<bool>& bMask,
150 unsigned int ce1)
const {
161 if (momentumPrim.E() > 0)
162 momentumSec = momentumPrim / momentumPrim.E() * (primaryCand.
ecalEnergy() + primaryCand.
hcalEnergy());
164 map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
165 map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
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_);
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 = " 185 if (isPrimaryNucl(pfCand.at(ce2))) {
186 LogTrace(
"PFCandConnector|analyseNuclearWPrim") <<
"\t\t but it is also a Primary Candidate " << ce2 << endl;
188 ref1_bis = (pfCand.at(ce2)).displacedVertexRef(fT_TO_DISP_);
190 analyseNuclearWPrim(pfCand, bMask, ce2);
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;
204 pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
207 double candE = pfCand.at(ce2).p4().E();
208 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
209 double deltaEn = candE - caloEn;
214 if (deltaEn > 1 && nMissOuterHits > 1 && candE > 0) {
216 momentumSec += momentumToAdd;
217 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
218 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may " 219 "have happened. Let's trust the calo energy" 221 <<
"add " << momentumToAdd << endl;
225 if (caloEn > 0.01 && deltaEn > 1 && nMissOuterHits > 0 && candE > 0) {
227 candidatesWithTrackExcess[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
229 }
else if (caloEn < 0.01)
230 candidatesWithoutCalo[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
232 momentumSec += (pfCand.at(ce2)).p4();
242 if (momentumPrim.E() < momentumSec.E()) {
243 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
244 <<
"Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
245 for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin();
246 iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E();
248 if (momentumSec.E() > iter->second.E() + 0.1) {
249 momentumSec -= iter->second;
251 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
252 <<
"\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
253 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
254 <<
"momentumPrim.E() = " << momentumPrim.E() <<
" and momentumSec.E() = " << momentumSec.E() << endl;
258 if (momentumPrim.E() < momentumSec.E()) {
259 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
260 <<
"0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates" 261 << candidatesWithTrackExcess.size() << endl;
262 for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin();
263 iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E();
265 if (momentumSec.E() > iter->second.E() + 0.1)
266 momentumSec -= iter->second;
269 double dpt = pfCand.at(ce1).trackRef()->ptError() / pfCand.at(ce1).trackRef()->pt() * 100;
271 if (momentumSec.E() < 0.1) {
279 if (((ref1->isTherePrimaryTracks() && dpt < dptRel_PrimaryTrack_) ||
280 (ref1->isThereMergedTracks() && dpt < dptRel_MergedTrack_)) &&
281 momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
282 if (bCalibPrimary_) {
283 double factor = momentumPrim.E() > 0 ? rescaleFactor(momentumPrim.Pt(), momentumSec.E() / momentumPrim.E()) : 1.;
284 LogTrace(
"PFCandConnector|analyseNuclearWPrim") <<
"factor = " <<
factor << endl;
285 if (
factor * momentumPrim.Pt() < momentumSec.Pt())
286 momentumSec = momentumPrim;
288 momentumSec += (1 -
factor) * momentumPrim;
291 double px = 0,
py = 0, pz = 0.;
292 if (momentumPrim.P() > 0) {
293 px = momentumPrim.Px() * momentumSec.P() / momentumPrim.P();
294 py = momentumPrim.Py() * momentumSec.P() / momentumPrim.P();
295 pz = momentumPrim.Pz() * momentumSec.P() / momentumPrim.P();
297 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
299 pfCand.at(ce1).setP4(momentum);
306 if (primDir.Mag2() < 0.1) {
308 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
309 pfCand.at(ce1).setP4(momentumSec);
313 double momentumS = momentumSec.P();
314 if (momentumS < 1
e-4)
316 double px = momentumS * primDir.x();
317 double py = momentumS * primDir.y();
318 double pz = momentumS * primDir.z();
319 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
322 pfCand.at(ce1).setP4(momentum);
329 std::vector<bool>& bMask,
330 unsigned int ce1)
const {
335 double caloEn = pfCand.at(ce1).ecalEnergy() + pfCand.at(ce1).hcalEnergy();
336 double deltaEn = pfCand.at(ce1).p4().E() - caloEn;
339 ref1 = pfCand.at(ce1).displacedVertexRef(fT_FROM_DISP_);
344 if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()) {
348 if (ref1->isIncomingTrack(primaryBaseRef))
349 LogTrace(
"PFCandConnector|analyseNuclearWSec")
350 <<
"There is a Primary track ref with pt = " << primaryBaseRef->
pt() << endl;
352 for (
unsigned int ce = 0; ce < pfCand.size(); ++ce) {
356 LogTrace(
"PFCandConnector|analyseNuclearWSec")
357 <<
" It is an electron and it has a ref to a track " << (pfCand.at(ce)).trackRef().isNonnull() << endl;
359 if ((pfCand.at(ce)).trackRef().isNonnull()) {
362 LogTrace(
"PFCandConnector|analyseNuclearWSec")
363 <<
"With Track Ref pt = " << (pfCand.at(ce)).trackRef()->pt() << endl;
365 if (bRef == primaryBaseRef) {
367 LogTrace(
"PFCandConnector|analyseNuclearWSec")
368 <<
"It is a NI from electron. NI Discarded. Just release the candidate." << endl;
370 LogTrace(
"PFCandConnector|analyseNuclearWSec")
371 <<
"It is a NI from muon. NI Discarded. Just release the candidate" << endl;
376 if (caloEn < 0.1 && pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
378 <<
"discarded track since no calo energy and ill measured" << endl;
381 if (caloEn > 0.1 && deltaEn > ptErrorSecondary_ &&
382 pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
384 <<
"rescaled momentum of the track since no calo energy and ill measured" << endl;
386 double factor = caloEn / pfCand.at(ce1).p4().E();
387 pfCand.at(ce1).rescaleMomentum(
factor);
402 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
404 float candE = pfCand.at(ce1).p4().E();
406 momentumToAdd = pfCand.at(ce1).p4() * caloEn / candE;
407 momentumSec = momentumToAdd;
408 LogTrace(
"PFCandConnector|analyseNuclearWSec")
409 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have " 410 "happened. Let's trust the calo energy" 412 <<
"add " << momentumToAdd << endl;
416 for (
unsigned int ce2 = ce1 + 1; ce2 < pfCand.size(); ++ce2) {
417 if (isSecondaryNucl(pfCand.at(ce2))) {
418 ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
421 LogTrace(
"PFCandConnector|analyseNuclearWSec")
422 <<
"\t here is a Secondary Candidate " << ce2 <<
" " << pfCand.at(ce2) << endl
423 <<
"\t based on the Track " << pfCand.at(ce2).trackRef().key()
424 <<
" w pT = " << pfCand.at(ce2).trackRef()->pt() <<
" #pm " << pfCand.at(ce2).trackRef()->ptError() <<
" %" 425 <<
" ECAL = " << pfCand.at(ce2).ecalEnergy() <<
" HCAL = " << pfCand.at(ce2).hcalEnergy()
426 <<
" dE(Trk-CALO) = " 427 << pfCand.at(ce2).trackRef()->p() - pfCand.at(ce2).ecalEnergy() - pfCand.at(ce2).hcalEnergy()
428 <<
" Nmissing hits = " 434 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
435 bool isAlreadyHere =
false;
436 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++) {
437 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second)
438 isAlreadyHere =
true;
441 pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
444 double candE = pfCand.at(ce2).p4().E();
445 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
446 double deltaEn = candE - caloEn;
449 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
451 momentumSec += momentumToAdd;
452 LogTrace(
"PFCandConnector|analyseNuclearWSec")
453 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may " 454 "have happened. Let's trust the calo energy" 456 <<
"add " << momentumToAdd << endl;
458 momentumSec += (pfCand.at(ce2)).p4();
468 if (primDir.Mag2() < 0.1) {
470 pfCand.at(ce1).setP4(momentumSec);
471 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
475 double momentumS = momentumSec.P();
476 if (momentumS < 1
e-4)
478 double px = momentumS * primDir.x();
479 double py = momentumS * primDir.y();
480 double pz = momentumS * primDir.z();
481 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
485 pfCand.at(ce1).setP4(momentum);
493 if (
pf.flag(fT_FROM_DISP_)) {
494 ref1 =
pf.displacedVertexRef(fT_FROM_DISP_);
498 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
509 if (
pf.flag(fT_TO_DISP_)) {
510 ref1 =
pf.displacedVertexRef(fT_TO_DISP_);
515 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
552 double fConst, fNorm, fExp;
554 fConst = fConst_[0] + fConst_[1] * cFrac;
555 fNorm = fNorm_[0] - fNorm_[1] * cFrac;
564 iDesc.
add<
bool>(
"bCorrect",
true);
565 iDesc.
add<
bool>(
"bCalibPrimary",
true);
566 iDesc.
add<
double>(
"dptRel_PrimaryTrack", 10.0);
567 iDesc.
add<
double>(
"dptRel_MergedTrack", 5.0);
568 iDesc.
add<
double>(
"ptErrorSecondary", 1.0);
569 iDesc.
add<std::vector<double>>(
"nuclCalibFactors", {0.8, 0.15, 0.5, 0.5, 0.05});
reco::PFDisplacedVertexRef displacedVertexRef(Flags type) const
bool isPrimaryNucl(const reco::PFCandidate &pf) const
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzE4D< double > > XYZTLorentzVectorD
Lorentz vector with cylindrical internal representation using pseudorapidity.
static const reco::PFCandidate::Flags fT_FROM_DISP_
bool isNonnull() const
Checks for non-null.
static const reco::PFCandidate::Flags fT_TO_DISP_
const LorentzVector & p4() const final
four-momentum Lorentz vector
std::vector< ElementInBlock > ElementsInBlocks
U second(std::pair< T, U > const &p)
void analyseNuclearWPrim(reco::PFCandidateCollection &, std::vector< bool > &, unsigned int) const
Analyse nuclear interactions where a primary or merged track is present.
void analyseNuclearWSec(reco::PFCandidateCollection &, std::vector< bool > &, unsigned int) const
Analyse nuclear interactions where a secondary track is present.
double pt() const
track transverse momentum
double hcalEnergy() const
return corrected Hcal energy
static const double pion_mass2
Useful constants.
ParameterDescriptionBase * add(U const &iLabel, T const &value)
double ecalEnergy() const
return corrected Ecal energy
static void fillPSetDescription(edm::ParameterSetDescription &iDesc)
Log< level::Info, false > LogInfo
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
XYZVectorD XYZVector
spatial vector with cartesian internal representation
reco::PFCandidateCollection connect(reco::PFCandidateCollection &pfCand) const
Particle reconstructed by the particle flow algorithm.
void setParameters(const edm::ParameterSet &iCfgCandConnector)
bool isSecondaryNucl(const reco::PFCandidate &pf) const
Log< level::Warning, false > LogWarning
double rescaleFactor(const double pt, const double cFrac) const
Return a calibration factor for a reconstructed nuclear interaction.