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 momentumSec = momentumPrim / momentumPrim.E() * (primaryCand.
ecalEnergy() + primaryCand.
hcalEnergy());
163 map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
164 map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
168 for (
unsigned int ce2 = 0; ce2 < pfCand.size(); ++ce2) {
169 if (ce2 != ce1 && isSecondaryNucl(pfCand.at(ce2))) {
170 ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
173 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
174 <<
"\t here is a Secondary Candidate " << ce2 <<
" " << pfCand.at(ce2) << endl
175 <<
"\t based on the Track " << pfCand.at(ce2).trackRef().key()
176 <<
" w p = " << pfCand.at(ce2).trackRef()->p() <<
" w pT = " << pfCand.at(ce2).trackRef()->pt() <<
" #pm " 177 << pfCand.at(ce2).trackRef()->ptError() <<
" %" 178 <<
" ECAL = " << pfCand.at(ce2).ecalEnergy() <<
" HCAL = " << pfCand.at(ce2).hcalEnergy()
179 <<
" dE(Trk-CALO) = " 180 << pfCand.at(ce2).trackRef()->p() - pfCand.at(ce2).ecalEnergy() - pfCand.at(ce2).hcalEnergy()
181 <<
" Nmissing hits = " 184 if (isPrimaryNucl(pfCand.at(ce2))) {
185 LogTrace(
"PFCandConnector|analyseNuclearWPrim") <<
"\t\t but it is also a Primary Candidate " << ce2 << endl;
187 ref1_bis = (pfCand.at(ce2)).displacedVertexRef(fT_TO_DISP_);
189 analyseNuclearWPrim(pfCand, bMask, ce2);
196 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
197 bool isAlreadyHere =
false;
198 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++) {
199 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second)
200 isAlreadyHere =
true;
203 pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
206 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
207 double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
212 if (deltaEn > 1 && nMissOuterHits > 1) {
214 momentumSec += momentumToAdd;
215 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
216 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may " 217 "have happened. Let's trust the calo energy" 219 <<
"add " << momentumToAdd << endl;
223 if (caloEn > 0.01 && deltaEn > 1 && nMissOuterHits > 0) {
225 candidatesWithTrackExcess[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
227 }
else if (caloEn < 0.01)
228 candidatesWithoutCalo[pfCand.at(ce2).trackRef()->pt() / pfCand.at(ce2).trackRef()->ptError()] =
230 momentumSec += (pfCand.at(ce2)).p4();
240 if (momentumPrim.E() < momentumSec.E()) {
241 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
242 <<
"Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
243 for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin();
244 iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E();
246 if (momentumSec.E() > iter->second.E() + 0.1) {
247 momentumSec -= iter->second;
249 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
250 <<
"\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
251 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
252 <<
"momentumPrim.E() = " << momentumPrim.E() <<
" and momentumSec.E() = " << momentumSec.E() << endl;
256 if (momentumPrim.E() < momentumSec.E()) {
257 LogTrace(
"PFCandConnector|analyseNuclearWPrim")
258 <<
"0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates" 259 << candidatesWithTrackExcess.size() << endl;
260 for (map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin();
261 iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E();
263 if (momentumSec.E() > iter->second.E() + 0.1)
264 momentumSec -= iter->second;
267 double dpt = pfCand.at(ce1).trackRef()->ptError() / pfCand.at(ce1).trackRef()->pt() * 100;
269 if (momentumSec.E() < 0.1) {
277 if (((ref1->isTherePrimaryTracks() && dpt < dptRel_PrimaryTrack_) ||
278 (ref1->isThereMergedTracks() && dpt < dptRel_MergedTrack_)) &&
279 momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
280 if (bCalibPrimary_) {
281 double factor = rescaleFactor(momentumPrim.Pt(), momentumSec.E() / momentumPrim.E());
282 LogTrace(
"PFCandConnector|analyseNuclearWPrim") <<
"factor = " <<
factor << endl;
283 if (
factor * momentumPrim.Pt() < momentumSec.Pt())
284 momentumSec = momentumPrim;
286 momentumSec += (1 -
factor) * momentumPrim;
289 double px = momentumPrim.Px() * momentumSec.P() / momentumPrim.P();
290 double py = momentumPrim.Py() * momentumSec.P() / momentumPrim.P();
291 double pz = momentumPrim.Pz() * momentumSec.P() / momentumPrim.P();
292 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
294 pfCand.at(ce1).setP4(momentum);
301 if (primDir.Mag2() < 0.1) {
303 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
304 pfCand.at(ce1).setP4(momentumSec);
308 double momentumS = momentumSec.P();
309 if (momentumS < 1
e-4)
311 double px = momentumS * primDir.x();
312 double py = momentumS * primDir.y();
313 double pz = momentumS * primDir.z();
314 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
317 pfCand.at(ce1).setP4(momentum);
324 std::vector<bool>& bMask,
325 unsigned int ce1)
const {
330 double caloEn = pfCand.at(ce1).ecalEnergy() + pfCand.at(ce1).hcalEnergy();
331 double deltaEn = pfCand.at(ce1).p4().E() - caloEn;
334 ref1 = pfCand.at(ce1).displacedVertexRef(fT_FROM_DISP_);
339 if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()) {
343 if (ref1->isIncomingTrack(primaryBaseRef))
344 LogTrace(
"PFCandConnector|analyseNuclearWSec")
345 <<
"There is a Primary track ref with pt = " << primaryBaseRef->
pt() << endl;
347 for (
unsigned int ce = 0; ce < pfCand.size(); ++ce) {
351 LogTrace(
"PFCandConnector|analyseNuclearWSec")
352 <<
" It is an electron and it has a ref to a track " << (pfCand.at(ce)).trackRef().isNonnull() << endl;
354 if ((pfCand.at(ce)).trackRef().isNonnull()) {
357 LogTrace(
"PFCandConnector|analyseNuclearWSec")
358 <<
"With Track Ref pt = " << (pfCand.at(ce)).trackRef()->pt() << endl;
360 if (bRef == primaryBaseRef) {
362 LogTrace(
"PFCandConnector|analyseNuclearWSec")
363 <<
"It is a NI from electron. NI Discarded. Just release the candidate." << endl;
365 LogTrace(
"PFCandConnector|analyseNuclearWSec")
366 <<
"It is a NI from muon. NI Discarded. Just release the candidate" << endl;
371 if (caloEn < 0.1 && pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
373 <<
"discarded track since no calo energy and ill measured" << endl;
376 if (caloEn > 0.1 && deltaEn > ptErrorSecondary_ &&
377 pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
379 <<
"rescaled momentum of the track since no calo energy and ill measured" << endl;
381 double factor = caloEn / pfCand.at(ce1).p4().E();
382 pfCand.at(ce1).rescaleMomentum(
factor);
397 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
399 momentumSec = momentumToAdd;
400 LogTrace(
"PFCandConnector|analyseNuclearWSec")
401 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have " 402 "happened. Let's trust the calo energy" 404 <<
"add " << momentumToAdd << endl;
408 for (
unsigned int ce2 = ce1 + 1; ce2 < pfCand.size(); ++ce2) {
409 if (isSecondaryNucl(pfCand.at(ce2))) {
410 ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
413 LogTrace(
"PFCandConnector|analyseNuclearWSec")
414 <<
"\t here is a Secondary Candidate " << ce2 <<
" " << pfCand.at(ce2) << endl
415 <<
"\t based on the Track " << pfCand.at(ce2).trackRef().key()
416 <<
" w pT = " << pfCand.at(ce2).trackRef()->pt() <<
" #pm " << pfCand.at(ce2).trackRef()->ptError() <<
" %" 417 <<
" ECAL = " << pfCand.at(ce2).ecalEnergy() <<
" HCAL = " << pfCand.at(ce2).hcalEnergy()
418 <<
" dE(Trk-CALO) = " 419 << pfCand.at(ce2).trackRef()->p() - pfCand.at(ce2).ecalEnergy() - pfCand.at(ce2).hcalEnergy()
420 <<
" Nmissing hits = " 426 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++) {
427 bool isAlreadyHere =
false;
428 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++) {
429 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second)
430 isAlreadyHere =
true;
433 pfCand.at(ce1).addElementInBlock(elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
436 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
437 double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
440 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
442 momentumSec += momentumToAdd;
443 LogTrace(
"PFCandConnector|analyseNuclearWSec")
444 <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may " 445 "have happened. Let's trust the calo energy" 447 <<
"add " << momentumToAdd << endl;
449 momentumSec += (pfCand.at(ce2)).p4();
459 if (primDir.Mag2() < 0.1) {
461 pfCand.at(ce1).setP4(momentumSec);
462 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
466 double momentumS = momentumSec.P();
467 if (momentumS < 1
e-4)
469 double px = momentumS * primDir.x();
470 double py = momentumS * primDir.y();
471 double pz = momentumS * primDir.z();
472 double E =
sqrt(
px *
px +
py *
py + pz * pz + pion_mass2);
476 pfCand.at(ce1).setP4(momentum);
484 if (
pf.flag(fT_FROM_DISP_)) {
485 ref1 =
pf.displacedVertexRef(fT_FROM_DISP_);
489 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
500 if (
pf.flag(fT_TO_DISP_)) {
501 ref1 =
pf.displacedVertexRef(fT_TO_DISP_);
506 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
543 double fConst, fNorm, fExp;
545 fConst = fConst_[0] + fConst_[1] * cFrac;
546 fNorm = fNorm_[0] - fNorm_[1] * cFrac;
555 iDesc.
add<
bool>(
"bCorrect",
true);
556 iDesc.
add<
bool>(
"bCalibPrimary",
true);
557 iDesc.
add<
double>(
"dptRel_PrimaryTrack", 10.0);
558 iDesc.
add<
double>(
"dptRel_MergedTrack", 5.0);
559 iDesc.
add<
double>(
"ptErrorSecondary", 1.0);
560 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.