16 void PFCandConnector::setParameters(
bool bCorrect,
bool bCalibPrimary,
double dptRel_PrimaryTrack,
double dptRel_MergedTrack,
double ptErrorSecondary,
const std::vector<double>& nuclCalibFactors){
19 bCalibPrimary_ = bCalibPrimary;
20 dptRel_PrimaryTrack_ = dptRel_PrimaryTrack;
21 dptRel_MergedTrack_ = dptRel_MergedTrack;
22 ptErrorSecondary_ = ptErrorSecondary;
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;
53 std::unique_ptr<reco::PFCandidateCollection>
56 if(pfC_.get() ) pfC_->clear();
61 bMask_.resize(pfCand->size(),
false);
69 cout <<
"==================== ------------------------------ ===============" << endl;
70 cout <<
"==================== Cand Connector ===============" << endl;
71 cout <<
"==================== ------------------------------ ===============" << endl;
72 cout <<
"==================== \tfor " << pfCand->size() <<
" Candidates\t =============" << endl;
73 cout <<
"==================== primary calibrated " << bCalibPrimary_ <<
" =============" << endl;
76 for(
unsigned int ce1=0; ce1 < pfCand->size(); ++ce1){
77 if ( isPrimaryNucl(pfCand->at(ce1)) ){
80 cout <<
"" << endl <<
"Nuclear Interaction w Primary Candidate " << ce1
81 <<
" " << pfCand->at(ce1) << endl
82 <<
" based on the Track " << pfCand->at(ce1).trackRef().key()
83 <<
" w pT = " << pfCand->at(ce1).trackRef()->pt()
84 <<
" #pm " << pfCand->at(ce1).trackRef()->ptError()/pfCand->at(ce1).trackRef()->pt()*100 <<
" %"
85 <<
" ECAL = " << pfCand->at(ce1).ecalEnergy()
86 <<
" HCAL = " << pfCand->at(ce1).hcalEnergy() << endl;
88 if (debug_) (pfCand->at(ce1)).displacedVertexRef(fT_TO_DISP_)->Dump();
90 analyseNuclearWPrim(pfCand, ce1);
93 cout <<
"After Connection the candidate " << ce1
94 <<
" is " << pfCand->at(ce1) << endl << endl;
97 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
98 if (blockElem == 0)
cout << *(elementsInBlocks[blockElem].first) << endl;
99 cout <<
" position " << elementsInBlocks[blockElem].second;
107 for(
unsigned int ce1=0; ce1 < pfCand->size(); ++ce1){
108 if ( !bMask_[ce1] && isSecondaryNucl(pfCand->at(ce1)) ){
110 cout <<
"" << endl <<
"Nuclear Interaction w no Primary Candidate " << ce1
111 <<
" " << pfCand->at(ce1) << endl
112 <<
" based on the Track " << pfCand->at(ce1).trackRef().key()
113 <<
" w pT = " << pfCand->at(ce1).trackRef()->pt()
114 <<
" #pm " << pfCand->at(ce1).trackRef()->ptError() <<
" %"
115 <<
" ECAL = " << pfCand->at(ce1).ecalEnergy()
116 <<
" HCAL = " << pfCand->at(ce1).hcalEnergy()
117 <<
" dE(Trk-CALO) = " << pfCand->at(ce1).trackRef()->p()-pfCand->at(ce1).ecalEnergy()-pfCand->at(ce1).hcalEnergy()
120 if (debug_) (pfCand->at(ce1)).displacedVertexRef(fT_FROM_DISP_)->Dump();
122 analyseNuclearWSec(pfCand, ce1);
125 cout <<
"After Connection the candidate " << ce1
126 <<
" is " << pfCand->at(ce1)
127 <<
" and elements connected to it are: " << endl;
130 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
131 if (blockElem == 0)
cout << *(elementsInBlocks[blockElem].first) << endl;
132 cout <<
" position " << elementsInBlocks[blockElem].second;
145 for(
unsigned int ce1=0; ce1 < pfCand->size(); ++ce1)
146 if (!bMask_[ce1]) pfC_->push_back(pfCand->at(ce1));
149 if(debug_ && bCorrect_)
cout <<
"==================== ------------------------------ ===============" << endl<< endl << endl;
170 momentumSec = momentumPrim/momentumPrim.E()*(primaryCand.
ecalEnergy() + primaryCand.
hcalEnergy());
172 map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
173 map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
178 for(
unsigned int ce2=0; ce2 < pfCand->size(); ++ce2) {
179 if (ce2 != ce1 && isSecondaryNucl(pfCand->at(ce2))){
181 ref2 = (pfCand->at(ce2)).displacedVertexRef(fT_FROM_DISP_);
185 if (debug_)
cout <<
"\t here is a Secondary Candidate " << ce2
186 <<
" " << pfCand->at(ce2) << endl
187 <<
"\t based on the Track " << pfCand->at(ce2).trackRef().key()
188 <<
" w p = " << pfCand->at(ce2).trackRef()->p()
189 <<
" w pT = " << pfCand->at(ce2).trackRef()->pt()
190 <<
" #pm " << pfCand->at(ce2).trackRef()->ptError() <<
" %"
191 <<
" ECAL = " << pfCand->at(ce2).ecalEnergy()
192 <<
" HCAL = " << pfCand->at(ce2).hcalEnergy()
193 <<
" dE(Trk-CALO) = " << pfCand->at(ce2).trackRef()->p()-pfCand->at(ce2).ecalEnergy()-pfCand->at(ce2).hcalEnergy()
196 if(isPrimaryNucl(pfCand->at(ce2))){
197 if (debug_)
cout <<
"\t\t but it is also a Primary Candidate " << ce2 << endl;
199 ref1_bis = (pfCand->at(ce2)).displacedVertexRef(fT_TO_DISP_);
200 if(ref1_bis.
isNonnull()) analyseNuclearWPrim(pfCand, ce2);
207 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
208 bool isAlreadyHere =
false;
209 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
210 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second) isAlreadyHere =
true;
212 if (!isAlreadyHere) pfCand->at(ce1).addElementInBlock( elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
215 double caloEn = pfCand->at(ce2).ecalEnergy() + pfCand->at(ce2).hcalEnergy();
216 double deltaEn = pfCand->at(ce2).p4().E() - caloEn;
221 if (deltaEn > 1 && nMissOuterHits > 1) {
223 momentumSec += momentumToAdd;
224 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;
228 if (caloEn > 0.01 && deltaEn > 1 && nMissOuterHits > 0) {
230 candidatesWithTrackExcess[pfCand->at(ce2).trackRef()->pt()/pfCand->at(ce2).trackRef()->ptError()] = momentumExcess;
232 else if(caloEn < 0.01) candidatesWithoutCalo[pfCand->at(ce2).trackRef()->pt()/pfCand->at(ce2).trackRef()->ptError()] = pfCand->at(ce2).p4();
233 momentumSec += (pfCand->at(ce2)).
p4();
248 if (momentumPrim.E() < momentumSec.E()){
250 if(debug_)
cout <<
"Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
251 for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin(); iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E(); iter++)
252 if (momentumSec.E() > iter->second.E()+0.1) {
253 momentumSec -= iter->second;
255 if(debug_)
cout <<
"\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
257 if(debug_)
cout <<
"momentumPrim.E() = " << momentumPrim.E() <<
" and momentumSec.E() = " << momentumSec.E() << endl;
264 if (momentumPrim.E() < momentumSec.E()){
265 if(debug_)
cout <<
"0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates" << candidatesWithTrackExcess.size() << endl;
266 for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin(); iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E(); iter++)
267 if (momentumSec.E() > iter->second.E()+0.1) momentumSec -= iter->second;
274 double dpt = pfCand->at(ce1).trackRef()->ptError()/pfCand->at(ce1).trackRef()->pt()*100;
276 if (momentumSec.E() < 0.1) {
284 if( ( (ref1->isTherePrimaryTracks() && dpt<dptRel_PrimaryTrack_) || (ref1->isThereMergedTracks() && dpt<dptRel_MergedTrack_) ) && momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
287 double factor = rescaleFactor( momentumPrim.Pt(), momentumSec.E()/momentumPrim.E());
288 if (debug_)
cout <<
"factor = " << factor << endl;
289 if (factor*momentumPrim.Pt() < momentumSec.Pt()) momentumSec = momentumPrim;
290 else momentumSec += (1-
factor)*momentumPrim;
293 double px = momentumPrim.Px()*momentumSec.P()/momentumPrim.P();
294 double py = momentumPrim.Py()*momentumSec.P()/momentumPrim.P();
295 double pz = momentumPrim.Pz()*momentumSec.P()/momentumPrim.P();
296 double E =
sqrt(px*px + py*py + pz*pz + pion_mass2);
298 pfCand->at(ce1).setP4(momentum);
307 if (primDir.Mag2() < 0.1){
309 edm::LogWarning(
"PFCandConnector") <<
"A Nuclear Interaction do not have primary direction" << std::endl;
310 pfCand->at(ce1).setP4(momentumSec);
314 double momentumS = momentumSec.P();
315 if (momentumS < 1
e-4) 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);
342 double caloEn = pfCand->at(ce1).ecalEnergy() + pfCand->at(ce1).hcalEnergy();
343 double deltaEn = pfCand->at(ce1).p4().E() - caloEn;
347 ref1 = pfCand->at(ce1).displacedVertexRef(fT_FROM_DISP_);
352 if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()){
355 for(
unsigned it = 0; it < refittedTracks.size(); it++){
357 if (ref1->isIncomingTrack(primaryBaseRef))
358 if (debug_)
cout <<
"There is a Primary track ref with pt = " << primaryBaseRef->
pt()<< endl;
360 for(
unsigned int ce=0; ce < pfCand->size(); ++ce){
364 if (debug_)
cout <<
" It is an electron and it has a ref to a track " << (pfCand->at(ce)).trackRef().isNonnull() << endl;
367 if ( (pfCand->at(ce)).trackRef().isNonnull() ){
370 if (debug_)
cout <<
"With Track Ref pt = " << (pfCand->at(ce)).trackRef()->pt() << endl;
372 if (bRef == primaryBaseRef) {
373 if (debug_ && (pfCand->at(ce)).particleId() ==
reco::PFCandidate::e)
cout <<
"It is a NI from electron. NI Discarded. Just release the candidate." << endl;
374 if (debug_ && (pfCand->at(ce)).particleId() ==
reco::PFCandidate::mu)
cout <<
"It is a NI from muon. NI Discarded. Just release the candidate" << endl;
379 if (caloEn < 0.1 && pfCand->at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
380 cout <<
"discarded track since no calo energy and ill measured" << endl;
383 if (caloEn > 0.1 && deltaEn >ptErrorSecondary_ && pfCand->at(ce1).trackRef()->ptError() > ptErrorSecondary_) {
384 cout <<
"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);
403 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
405 momentumSec = momentumToAdd;
406 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;
411 for(
unsigned int ce2=ce1+1; ce2 < pfCand->size(); ++ce2) {
412 if (isSecondaryNucl(pfCand->at(ce2))){
413 ref2 = (pfCand->at(ce2)).displacedVertexRef(fT_FROM_DISP_);
417 if (debug_)
cout <<
"\t here is a Secondary Candidate " << ce2
418 <<
" " << pfCand->at(ce2) << endl
419 <<
"\t based on the Track " << pfCand->at(ce2).trackRef().key()
420 <<
" w pT = " << pfCand->at(ce2).trackRef()->pt()
421 <<
" #pm " << pfCand->at(ce2).trackRef()->ptError() <<
" %"
422 <<
" ECAL = " << pfCand->at(ce2).ecalEnergy()
423 <<
" HCAL = " << pfCand->at(ce2).hcalEnergy()
424 <<
" dE(Trk-CALO) = " << pfCand->at(ce2).trackRef()->p()-pfCand->at(ce2).ecalEnergy()-pfCand->at(ce2).hcalEnergy()
430 for (
unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
431 bool isAlreadyHere =
false;
432 for (
unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
433 if (elementsAlreadyInBlocks[alreadyBlock].
second == elementsInBlocks[blockElem].
second) isAlreadyHere =
true;
435 if (!isAlreadyHere) pfCand->at(ce1).addElementInBlock( elementsInBlocks[blockElem].
first, elementsInBlocks[blockElem].
second);
438 double caloEn = pfCand->at(ce2).ecalEnergy() + pfCand->at(ce2).hcalEnergy();
439 double deltaEn = pfCand->at(ce2).p4().E() - caloEn;
441 if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
443 momentumSec += momentumToAdd;
444 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;
446 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) momentumS = 1
e-4;
468 double px = momentumS*primDir.x();
469 double py = momentumS*primDir.y();
470 double pz = momentumS*primDir.z();
471 double E =
sqrt(px*px + py*py + pz*pz + pion_mass2);
475 pfCand->at(ce1).setP4(momentum);
486 if( pf.
flag( fT_FROM_DISP_ ) ) {
490 else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
503 if( pf.
flag( fT_TO_DISP_ ) ) {
508 else if (ref1->isNucl()|| ref1->isNucl_Loose() || ref1->isNucl_Kink())
550 double fConst, fNorm, fExp;
552 fConst = fConst_[0] + fConst_[1]*cFrac;
553 fNorm = fNorm_[0] - fNorm_[1]*cFrac;
556 double factor = fConst - fNorm*
exp( -fExp*pt );
double ecalEnergy() const
return corrected Ecal energy
bool isNonnull() const
Checks for non-null.
void analyseNuclearWSec(std::unique_ptr< reco::PFCandidateCollection > &, unsigned int)
Analyse nuclear interactions where a secondary track is present.
bool isPrimaryNucl(const reco::PFCandidate &pf) const
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzE4D< double > > XYZTLorentzVectorD
Lorentz vector with cylindrical internal representation using pseudorapidity.
std::unique_ptr< reco::PFCandidateCollection > connect(std::unique_ptr< reco::PFCandidateCollection > &pfCand)
bool isSecondaryNucl(const reco::PFCandidate &pf) const
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
void analyseNuclearWPrim(std::unique_ptr< reco::PFCandidateCollection > &, unsigned int)
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)
virtual const LorentzVector & p4() const final
four-momentum Lorentz vector