24 if (nuclCalibFactors.size() == 5) {
25 fConst_[0] = nuclCalibFactors[0];
26 fConst_[1] = nuclCalibFactors[1];
28 fNorm_[0] = nuclCalibFactors[2];
29 fNorm_[1] = nuclCalibFactors[3];
31 fExp_[0] = nuclCalibFactors[4];
33 edm::LogWarning(
"PFCandConnector") <<
"Wrong calibration factors for nuclear interactions. The calibration procedure would not be applyed." << std::endl;
34 bCalibPrimary_ =
false;
38 edm::LogInfo(
"PFCandConnector") <<
" ====================== The PFCandConnector is switched " << sCorrect.c_str() <<
" ==================== " << std::endl;
39 std::string sCalibPrimary = bCalibPrimary_ ?
"used for calibration" :
"not used for calibration";
40 if (bCorrect_)
edm::LogInfo(
"PFCandConnector") <<
"Primary Tracks are " << sCalibPrimary.c_str() << std::endl;
41 if (bCorrect_ && bCalibPrimary_)
edm::LogInfo(
"PFCandConnector") <<
"Under the condition that the precision on the Primary track is better than " << dptRel_PrimaryTrack_ <<
" % "<< std::endl;
42 if (bCorrect_ && bCalibPrimary_)
edm::LogInfo(
"PFCandConnector") <<
" and on merged tracks better than " << dptRel_MergedTrack_ <<
" % "<< std::endl;
43 if (bCorrect_ && bCalibPrimary_)
edm::LogInfo(
"PFCandConnector") <<
" and secondary tracks in some cases more precise than " << ptErrorSecondary_ <<
" GeV"<< std::endl;
44 if (bCorrect_ && bCalibPrimary_)
edm::LogInfo(
"PFCandConnector") <<
"factor = (" << fConst_[0] <<
" + " << fConst_[1] <<
"*cFrac) - (" 45 << fNorm_[0] <<
" - " << fNorm_[1] <<
"cFrac)*exp( " 46 << -1*fExp_[0] <<
"*pT )"<< std::endl;
47 edm::LogInfo(
"PFCandConnector") <<
" =========================================================== " << std::endl;
59 std::vector<bool> bMask;
60 bMask.resize(pfCand.size(),
false);
68 cout <<
"==================== ------------------------------ ===============" << endl;
69 cout <<
"==================== Cand Connector ===============" << endl;
70 cout <<
"==================== ------------------------------ ===============" << endl;
71 cout <<
"==================== \tfor " << pfCand.size() <<
" Candidates\t =============" << endl;
72 cout <<
"==================== primary calibrated " << bCalibPrimary_ <<
" =============" << endl;
75 for(
unsigned int ce1=0; ce1 < pfCand.size(); ++ce1){
76 if ( isPrimaryNucl(pfCand.at(ce1)) ){
79 cout <<
"" << endl <<
"Nuclear Interaction w Primary Candidate " << ce1
80 <<
" " << pfCand.at(ce1) << endl
81 <<
" based on the Track " << pfCand.at(ce1).trackRef().key()
82 <<
" w pT = " << pfCand.at(ce1).trackRef()->pt()
83 <<
" #pm " << pfCand.at(ce1).trackRef()->ptError()/pfCand.at(ce1).trackRef()->pt()*100 <<
" %" 84 <<
" ECAL = " << pfCand.at(ce1).ecalEnergy()
85 <<
" HCAL = " << pfCand.at(ce1).hcalEnergy() << endl;
87 if (debug_) (pfCand.at(ce1)).displacedVertexRef(fT_TO_DISP_)->Dump();
89 analyseNuclearWPrim(pfCand, bMask, ce1);
92 cout <<
"After Connection the candidate " << ce1
93 <<
" is " << pfCand.at(ce1) << endl << endl;
96 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
97 if (blockElem == 0)
cout << *(elementsInBlocks[blockElem].first) << endl;
98 cout <<
" position " << elementsInBlocks[blockElem].second;
106 for(
unsigned int ce1=0; ce1 < pfCand.size(); ++ce1){
107 if ( !bMask[ce1] && isSecondaryNucl(pfCand.at(ce1)) ){
109 cout <<
"" << endl <<
"Nuclear Interaction w no Primary Candidate " << ce1
110 <<
" " << pfCand.at(ce1) << endl
111 <<
" based on the Track " << pfCand.at(ce1).trackRef().key()
112 <<
" w pT = " << pfCand.at(ce1).trackRef()->pt()
113 <<
" #pm " << pfCand.at(ce1).trackRef()->ptError() <<
" %" 114 <<
" ECAL = " << pfCand.at(ce1).ecalEnergy()
115 <<
" HCAL = " << pfCand.at(ce1).hcalEnergy()
116 <<
" dE(Trk-CALO) = " << pfCand.at(ce1).trackRef()->p()-pfCand.at(ce1).ecalEnergy()-pfCand.at(ce1).hcalEnergy()
119 if (debug_) (pfCand.at(ce1)).displacedVertexRef(fT_FROM_DISP_)->Dump();
121 analyseNuclearWSec(pfCand, bMask, ce1);
124 cout <<
"After Connection the candidate " << ce1
125 <<
" is " << pfCand.at(ce1)
126 <<
" and elements connected to it are: " << endl;
129 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
130 if (blockElem == 0)
cout << *(elementsInBlocks[blockElem].first) << endl;
131 cout <<
" position " << elementsInBlocks[blockElem].second;
144 for(
unsigned int ce1=0; ce1 < pfCand.size(); ++ce1)
145 if (!bMask[ce1]) pfC.push_back(pfCand.at(ce1));
148 if(debug_ && bCorrect_)
cout <<
"==================== ------------------------------ ===============" << endl<< endl << endl;
169 momentumSec = momentumPrim/momentumPrim.E()*(primaryCand.
ecalEnergy() + primaryCand.
hcalEnergy());
171 map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
172 map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
177 for(
unsigned int ce2=0; ce2 < pfCand.size(); ++ce2) {
178 if (ce2 != ce1 && isSecondaryNucl(pfCand.at(ce2))){
180 ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
184 if (debug_)
cout <<
"\t here is a Secondary Candidate " << ce2
185 <<
" " << pfCand.at(ce2) << endl
186 <<
"\t based on the Track " << pfCand.at(ce2).trackRef().key()
187 <<
" w p = " << pfCand.at(ce2).trackRef()->p()
188 <<
" w pT = " << pfCand.at(ce2).trackRef()->pt()
189 <<
" #pm " << pfCand.at(ce2).trackRef()->ptError() <<
" %" 190 <<
" ECAL = " << pfCand.at(ce2).ecalEnergy()
191 <<
" HCAL = " << pfCand.at(ce2).hcalEnergy()
192 <<
" dE(Trk-CALO) = " << pfCand.at(ce2).trackRef()->p()-pfCand.at(ce2).ecalEnergy()-pfCand.at(ce2).hcalEnergy()
195 if(isPrimaryNucl(pfCand.at(ce2))){
196 if (debug_)
cout <<
"\t\t but it is also a Primary Candidate " << ce2 << endl;
198 ref1_bis = (pfCand.at(ce2)).displacedVertexRef(fT_TO_DISP_);
199 if(ref1_bis.
isNonnull()) analyseNuclearWPrim(pfCand, bMask, ce2);
206 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
207 bool isAlreadyHere =
false;
208 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
209 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second) isAlreadyHere =
true;
211 if (!isAlreadyHere) pfCand.at(ce1).addElementInBlock( elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
214 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
215 double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
220 if (deltaEn > 1 && nMissOuterHits > 1) {
222 momentumSec += momentumToAdd;
223 if (debug_)
cout <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have happened. Let's trust the calo energy" << endl <<
"add " << momentumToAdd << endl;
227 if (caloEn > 0.01 && deltaEn > 1 && nMissOuterHits > 0) {
229 candidatesWithTrackExcess[pfCand.at(ce2).trackRef()->pt()/pfCand.at(ce2).trackRef()->ptError()] = momentumExcess;
231 else if(caloEn < 0.01) candidatesWithoutCalo[pfCand.at(ce2).trackRef()->pt()/pfCand.at(ce2).trackRef()->ptError()] = pfCand.at(ce2).p4();
232 momentumSec += (pfCand.at(ce2)).
p4();
247 if (momentumPrim.E() < momentumSec.E()){
249 if(debug_)
cout <<
"Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
250 for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin(); iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E(); iter++)
251 if (momentumSec.E() > iter->second.E()+0.1) {
252 momentumSec -= iter->second;
254 if(debug_)
cout <<
"\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
256 if(debug_)
cout <<
"momentumPrim.E() = " << momentumPrim.E() <<
" and momentumSec.E() = " << momentumSec.E() << endl;
263 if (momentumPrim.E() < momentumSec.E()){
264 if(debug_)
cout <<
"0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates" << candidatesWithTrackExcess.size() << endl;
265 for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin(); iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E(); iter++)
266 if (momentumSec.E() > iter->second.E()+0.1) momentumSec -= iter->second;
273 double dpt = pfCand.at(ce1).trackRef()->ptError()/pfCand.at(ce1).trackRef()->pt()*100;
275 if (momentumSec.E() < 0.1) {
283 if( ( (ref1->isTherePrimaryTracks() && dpt<dptRel_PrimaryTrack_) || (ref1->isThereMergedTracks() && dpt<dptRel_MergedTrack_) ) && momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
286 double factor = rescaleFactor( momentumPrim.Pt(), momentumSec.E()/momentumPrim.E());
287 if (debug_)
cout <<
"factor = " << factor << endl;
288 if (factor*momentumPrim.Pt() < momentumSec.Pt()) momentumSec = momentumPrim;
289 else momentumSec += (1-factor)*momentumPrim;
292 double px = momentumPrim.Px()*momentumSec.P()/momentumPrim.P();
293 double py = momentumPrim.Py()*momentumSec.P()/momentumPrim.P();
294 double pz = momentumPrim.Pz()*momentumSec.P()/momentumPrim.P();
295 double E =
sqrt(px*px + py*py + pz*pz + pion_mass2);
297 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) momentumS = 1
e-4;
315 double px = momentumS*primDir.x();
316 double py = momentumS*primDir.y();
317 double pz = momentumS*primDir.z();
318 double E =
sqrt(px*px + py*py + pz*pz + pion_mass2);
321 pfCand.at(ce1).setP4(momentum);
341 double caloEn = pfCand.at(ce1).ecalEnergy() + pfCand.at(ce1).hcalEnergy();
342 double deltaEn = pfCand.at(ce1).p4().E() - caloEn;
346 ref1 = pfCand.at(ce1).displacedVertexRef(fT_FROM_DISP_);
351 if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()){
353 std::vector<reco::Track> refittedTracks = ref1->refittedTracks();
354 for(
unsigned it = 0; it < refittedTracks.size(); it++){
356 if (ref1->isIncomingTrack(primaryBaseRef))
357 if (debug_)
cout <<
"There is a Primary track ref with pt = " << primaryBaseRef->
pt()<< endl;
359 for(
unsigned int ce=0; ce < pfCand.size(); ++ce){
363 if (debug_)
cout <<
" It is an electron and it has a ref to a track " << (pfCand.at(ce)).trackRef().isNonnull() << endl;
366 if ( (pfCand.at(ce)).trackRef().isNonnull() ){
369 if (debug_)
cout <<
"With Track Ref pt = " << (pfCand.at(ce)).trackRef()->pt() << endl;
371 if (bRef == primaryBaseRef) {
372 if (debug_ && (pfCand.at(ce)).particleId() ==
reco::PFCandidate::e)
cout <<
"It is a NI from electron. NI Discarded. Just release the candidate." << endl;
373 if (debug_ && (pfCand.at(ce)).particleId() ==
reco::PFCandidate::mu)
cout <<
"It is a NI from muon. NI Discarded. Just release the candidate" << endl;
378 if (caloEn < 0.1 && pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
379 cout <<
"discarded track since no calo energy and ill measured" << endl;
382 if (caloEn > 0.1 && deltaEn >ptErrorSecondary_ && pfCand.at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
383 cout <<
"rescaled momentum of the track since no calo energy and ill measured" << endl;
385 double factor = caloEn/pfCand.at(ce1).p4().E();
386 pfCand.at(ce1).rescaleMomentum(factor);
402 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
404 momentumSec = momentumToAdd;
405 if (debug_)
cout <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have happened. Let's trust the calo energy" << endl <<
"add " << momentumToAdd << endl;
410 for(
unsigned int ce2=ce1+1; ce2 < pfCand.size(); ++ce2) {
411 if (isSecondaryNucl(pfCand.at(ce2))){
412 ref2 = (pfCand.at(ce2)).displacedVertexRef(fT_FROM_DISP_);
416 if (debug_)
cout <<
"\t here is a Secondary Candidate " << ce2
417 <<
" " << pfCand.at(ce2) << endl
418 <<
"\t based on the Track " << pfCand.at(ce2).trackRef().key()
419 <<
" w pT = " << pfCand.at(ce2).trackRef()->pt()
420 <<
" #pm " << pfCand.at(ce2).trackRef()->ptError() <<
" %" 421 <<
" ECAL = " << pfCand.at(ce2).ecalEnergy()
422 <<
" HCAL = " << pfCand.at(ce2).hcalEnergy()
423 <<
" dE(Trk-CALO) = " << pfCand.at(ce2).trackRef()->p()-pfCand.at(ce2).ecalEnergy()-pfCand.at(ce2).hcalEnergy()
429 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
430 bool isAlreadyHere =
false;
431 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
432 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second) isAlreadyHere =
true;
434 if (!isAlreadyHere) pfCand.at(ce1).addElementInBlock( elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
437 double caloEn = pfCand.at(ce2).ecalEnergy() + pfCand.at(ce2).hcalEnergy();
438 double deltaEn = pfCand.at(ce2).p4().E() - caloEn;
440 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
442 momentumSec += momentumToAdd;
443 if (debug_)
cout <<
"The difference track-calo s really large and the track miss at least 2 hits. A secondary NI may have happened. Let's trust the calo energy" << endl <<
"add " << momentumToAdd << endl;
445 momentumSec += (pfCand.at(ce2)).
p4();
458 if (primDir.Mag2() < 0.1){
460 pfCand.at(ce1).setP4(momentumSec);
461 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
465 double momentumS = momentumSec.P();
466 if (momentumS < 1
e-4) momentumS = 1
e-4;
467 double px = momentumS*primDir.x();
468 double py = momentumS*primDir.y();
469 double pz = momentumS*primDir.z();
470 double E =
sqrt(px*px + py*py + pz*pz + pion_mass2);
474 pfCand.at(ce1).setP4(momentum);
485 if( pf.
flag( fT_FROM_DISP_ ) ) {
489 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
502 if( pf.
flag( fT_TO_DISP_ ) ) {
507 else if (ref1->isNucl()|| ref1->isNucl_Loose() || ref1->isNucl_Kink())
549 double fConst, fNorm, fExp;
551 fConst = fConst_[0] + fConst_[1]*cFrac;
552 fNorm = fNorm_[0] - fNorm_[1]*cFrac;
555 double factor = fConst - fNorm*
exp( -fExp*pt );
double ecalEnergy() const
return corrected Ecal energy
bool isNonnull() const
Checks for non-null.
bool isPrimaryNucl(const reco::PFCandidate &pf) const
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzE4D< double > > XYZTLorentzVectorD
Lorentz vector with cylindrical internal representation using pseudorapidity.
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
reco::PFDisplacedVertexRef displacedVertexRef(Flags type) const
U second(std::pair< T, U > const &p)
double pt() const
track transverse momentum
bool flag(Flags theFlag) const
return a given flag
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.
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Particle reconstructed by the particle flow algorithm.
double hcalEnergy() const
return corrected Hcal energy
void setParameters(const edm::ParameterSet &iCfgCandConnector)