CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_10_patch2/src/RecoParticleFlow/PFProducer/src/PFCandConnector.cc

Go to the documentation of this file.
00001 #include "RecoParticleFlow/PFProducer/interface/PFCandConnector.h"
00002 #include "DataFormats/ParticleFlowReco/interface/PFDisplacedVertexFwd.h" 
00003 #include "DataFormats/ParticleFlowReco/interface/PFDisplacedVertex.h" 
00004 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h" 
00005 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h" 
00006 #include "FWCore/MessageLogger/interface/MessageLogger.h" 
00007 
00008 using namespace reco;
00009 using namespace std;
00010 
00011 const double PFCandConnector::pion_mass2 = 0.0194;
00012 
00013 const reco::PFCandidate::Flags PFCandConnector::fT_TO_DISP_ = PFCandidate::T_TO_DISP;
00014 const reco::PFCandidate::Flags PFCandConnector::fT_FROM_DISP_ = PFCandidate::T_FROM_DISP;
00015 
00016 void PFCandConnector::setParameters(bool bCorrect, bool bCalibPrimary, double dptRel_PrimaryTrack, double dptRel_MergedTrack, double ptErrorSecondary, std::vector<double> nuclCalibFactors){
00017 
00018          bCorrect_ = bCorrect;
00019          bCalibPrimary_ =  bCalibPrimary;
00020          dptRel_PrimaryTrack_ = dptRel_PrimaryTrack;
00021          dptRel_MergedTrack_ =  dptRel_MergedTrack;
00022          ptErrorSecondary_ = ptErrorSecondary;
00023 
00024          if (nuclCalibFactors.size() == 5) {
00025            fConst_[0] =  nuclCalibFactors[0]; 
00026            fConst_[1] =  nuclCalibFactors[1]; 
00027            
00028            fNorm_[0] = nuclCalibFactors[2]; 
00029            fNorm_[1] = nuclCalibFactors[3]; 
00030            
00031            fExp_[0] = nuclCalibFactors[4];
00032          } else {
00033            edm::LogWarning("PFCandConnector") << "Wrong calibration factors for nuclear interactions. The calibration procedure would not be applyed." << std::endl;
00034            bCalibPrimary_ =  false;
00035          }
00036 
00037          std::string sCorrect = bCorrect_ ? "On" : "Off";
00038          edm::LogInfo("PFCandConnector")  << " ====================== The PFCandConnector is switched " << sCorrect.c_str() << " ==================== " << std::endl;
00039          std::string sCalibPrimary = bCalibPrimary_ ? "used for calibration" : "not used for calibration";
00040          if (bCorrect_) edm::LogInfo("PFCandConnector")  << "Primary Tracks are " << sCalibPrimary.c_str() << std::endl;
00041          if (bCorrect_ && bCalibPrimary_) edm::LogInfo("PFCandConnector") << "Under the condition that the precision on the Primary track is better than " << dptRel_PrimaryTrack_ << " % "<< std::endl;
00042          if (bCorrect_ && bCalibPrimary_) edm::LogInfo("PFCandConnector") << "      and on merged tracks better than " <<  dptRel_MergedTrack_ << " % "<< std::endl;
00043          if (bCorrect_ && bCalibPrimary_) edm::LogInfo("PFCandConnector") << "      and secondary tracks in some cases more precise than " << ptErrorSecondary_ << " GeV"<< std::endl;
00044          if (bCorrect_ && bCalibPrimary_) edm::LogInfo("PFCandConnector") << "factor = (" << fConst_[0] << " + " << fConst_[1] << "*cFrac) - (" 
00045                                        << fNorm_[0] << " - " << fNorm_[1] << "cFrac)*exp( "
00046                                        << -1*fExp_[0] << "*pT )"<< std::endl;
00047          edm::LogInfo("PFCandConnector") << " =========================================================== " << std::endl;        
00048 
00049        }
00050 
00051 
00052 
00053 std::auto_ptr<reco::PFCandidateCollection>
00054 PFCandConnector::connect(std::auto_ptr<PFCandidateCollection>& pfCand) {
00055    
00056   if(pfC_.get() ) pfC_->clear();
00057   else 
00058     pfC_.reset( new PFCandidateCollection );
00059 
00060   bMask_.clear();
00061   bMask_.resize(pfCand->size(), false);
00062 
00063   // debug_ = true;
00064 
00065   // loop on primary
00066   if (bCorrect_){
00067     if(debug_){
00068       cout << "" << endl;
00069       cout << "==================== ------------------------------ ===============" << endl;
00070       cout << "====================         Cand Connector         ===============" << endl;
00071       cout << "==================== ------------------------------ ===============" << endl;
00072       cout << "====================   \tfor " <<  pfCand->size() << " Candidates\t  =============" << endl; 
00073       cout << "==================== primary calibrated " << bCalibPrimary_ << "     =============" << endl;
00074     }
00075 
00076     for( unsigned int ce1=0; ce1 < pfCand->size(); ++ce1){
00077       if ( isPrimaryNucl(pfCand->at(ce1)) ){
00078 
00079         if (debug_) 
00080           cout << "" << endl << "Nuclear Interaction w Primary Candidate " << ce1 
00081                << " " << pfCand->at(ce1) << endl
00082                << " based on the Track " << pfCand->at(ce1).trackRef().key()
00083                << " w pT = " << pfCand->at(ce1).trackRef()->pt()
00084                << " #pm " << pfCand->at(ce1).trackRef()->ptError()/pfCand->at(ce1).trackRef()->pt()*100 << " %" 
00085                << " ECAL = " << pfCand->at(ce1).ecalEnergy() 
00086                << " HCAL = " << pfCand->at(ce1).hcalEnergy() << endl;
00087 
00088         if (debug_) (pfCand->at(ce1)).displacedVertexRef(fT_TO_DISP_)->Dump();
00089 
00090         analyseNuclearWPrim(pfCand, ce1);
00091             
00092         if (debug_){
00093           cout << "After Connection the candidate " << ce1 
00094                << " is " << pfCand->at(ce1) << endl << endl;
00095           
00096           PFCandidate::ElementsInBlocks elementsInBlocks = pfCand->at(ce1).elementsInBlocks();
00097           for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
00098             if (blockElem == 0) cout << *(elementsInBlocks[blockElem].first) << endl;  
00099             cout << " position " << elementsInBlocks[blockElem].second;
00100           }         
00101         }
00102 
00103       }
00104 
00105     }
00106 
00107     for( unsigned int ce1=0; ce1 < pfCand->size(); ++ce1){
00108       if ( !bMask_[ce1] && isSecondaryNucl(pfCand->at(ce1)) ){
00109         if (debug_) 
00110           cout << "" << endl << "Nuclear Interaction w no Primary Candidate " << ce1 
00111                << " " << pfCand->at(ce1) << endl
00112                << " based on the Track " << pfCand->at(ce1).trackRef().key()
00113                << " w pT = " << pfCand->at(ce1).trackRef()->pt()
00114                << " #pm " << pfCand->at(ce1).trackRef()->ptError() << " %" 
00115                << " ECAL = " << pfCand->at(ce1).ecalEnergy() 
00116                << " HCAL = " << pfCand->at(ce1).hcalEnergy() 
00117                << " dE(Trk-CALO) = " << pfCand->at(ce1).trackRef()->p()-pfCand->at(ce1).ecalEnergy()-pfCand->at(ce1).hcalEnergy() 
00118                << " Nmissing hits = " << pfCand->at(ce1).trackRef()->trackerExpectedHitsOuter().numberOfHits() << endl;
00119 
00120         if (debug_) (pfCand->at(ce1)).displacedVertexRef(fT_FROM_DISP_)->Dump();
00121                 
00122         analyseNuclearWSec(pfCand, ce1);
00123         
00124         if (debug_) {
00125           cout << "After Connection the candidate " << ce1 
00126                << " is " << pfCand->at(ce1)
00127                << " and elements connected to it are: " << endl;
00128           
00129           PFCandidate::ElementsInBlocks elementsInBlocks = pfCand->at(ce1).elementsInBlocks();
00130           for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
00131             if (blockElem == 0) cout << *(elementsInBlocks[blockElem].first) << endl;  
00132             cout << " position " << elementsInBlocks[blockElem].second;
00133           }         
00134         }
00135 
00136       }
00137 
00138 
00139     }
00140   }   
00141   
00142 
00143     
00144 
00145   for( unsigned int ce1=0; ce1 < pfCand->size(); ++ce1)
00146     if (!bMask_[ce1]) pfC_->push_back(pfCand->at(ce1));
00147 
00148 
00149   if(debug_ && bCorrect_) cout << "==================== ------------------------------ ===============" << endl<< endl << endl;
00150    
00151   return pfC_;
00152 
00153 
00154 }
00155 
00156 void 
00157 PFCandConnector::analyseNuclearWPrim(std::auto_ptr<PFCandidateCollection>& pfCand, unsigned int ce1) {
00158 
00159 
00160   PFDisplacedVertexRef ref1, ref2, ref1_bis;  
00161 
00162   PFCandidate primaryCand = pfCand->at(ce1);
00163 
00164   // ------- look for the little friends -------- //
00165 
00166   math::XYZTLorentzVectorD momentumPrim = primaryCand.p4();
00167 
00168   math::XYZTLorentzVectorD momentumSec;
00169 
00170   momentumSec = momentumPrim/momentumPrim.E()*(primaryCand.ecalEnergy() + primaryCand.hcalEnergy());
00171 
00172   map<double, math::XYZTLorentzVectorD> candidatesWithTrackExcess;
00173   map<double, math::XYZTLorentzVectorD> candidatesWithoutCalo;
00174   
00175     
00176   ref1 = primaryCand.displacedVertexRef(fT_TO_DISP_);
00177   
00178   for( unsigned int ce2=0; ce2 < pfCand->size(); ++ce2) {
00179     if (ce2 != ce1 && isSecondaryNucl(pfCand->at(ce2))){
00180       
00181       ref2 = (pfCand->at(ce2)).displacedVertexRef(fT_FROM_DISP_);
00182       
00183       if (ref1 == ref2) {
00184         
00185         if (debug_) cout << "\t here is a Secondary Candidate " << ce2  
00186                          << " " << pfCand->at(ce2) << endl
00187                          << "\t based on the Track " << pfCand->at(ce2).trackRef().key()
00188                          << " w p = " << pfCand->at(ce2).trackRef()->p()
00189                          << " w pT = " << pfCand->at(ce2).trackRef()->pt()
00190                          << " #pm " << pfCand->at(ce2).trackRef()->ptError() << " %"
00191                          << " ECAL = " << pfCand->at(ce2).ecalEnergy() 
00192                          << " HCAL = " << pfCand->at(ce2).hcalEnergy() 
00193                          << " dE(Trk-CALO) = " << pfCand->at(ce2).trackRef()->p()-pfCand->at(ce2).ecalEnergy()-pfCand->at(ce2).hcalEnergy() 
00194                          << " Nmissing hits = " << pfCand->at(ce2).trackRef()->trackerExpectedHitsOuter().numberOfHits() << endl;
00195 
00196         if(isPrimaryNucl(pfCand->at(ce2))){
00197           if (debug_) cout << "\t\t but it is also a Primary Candidate " << ce2 << endl;
00198           
00199           ref1_bis = (pfCand->at(ce2)).displacedVertexRef(fT_TO_DISP_);
00200           if(ref1_bis.isNonnull()) analyseNuclearWPrim(pfCand, ce2);  
00201         }
00202 
00203         // Take now the parameters of the secondary track that are relevant and use them to construct the NI candidate
00204 
00205         PFCandidate::ElementsInBlocks elementsInBlocks = pfCand->at(ce2).elementsInBlocks();
00206         PFCandidate::ElementsInBlocks elementsAlreadyInBlocks = pfCand->at(ce1).elementsInBlocks();
00207         for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
00208           bool isAlreadyHere = false;
00209           for (unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
00210             if (elementsAlreadyInBlocks[alreadyBlock].second == elementsInBlocks[blockElem].second) isAlreadyHere = true;
00211           }
00212           if (!isAlreadyHere) pfCand->at(ce1).addElementInBlock( elementsInBlocks[blockElem].first,  elementsInBlocks[blockElem].second);
00213         }
00214 
00215         double caloEn = pfCand->at(ce2).ecalEnergy() + pfCand->at(ce2).hcalEnergy();
00216         double deltaEn =  pfCand->at(ce2).p4().E() - caloEn;
00217         int nMissOuterHits = pfCand->at(ce2).trackRef()->trackerExpectedHitsOuter().numberOfHits();
00218         
00219 
00220         // 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.
00221         if (deltaEn > 1  && nMissOuterHits > 1) {
00222           math::XYZTLorentzVectorD momentumToAdd = pfCand->at(ce2).p4()*caloEn/pfCand->at(ce2).p4().E();
00223           momentumSec += momentumToAdd;
00224           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;
00225           
00226         } else {
00227           // 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.
00228           if (caloEn > 0.01 && deltaEn > 1  && nMissOuterHits > 0) {
00229             math::XYZTLorentzVectorD momentumExcess = pfCand->at(ce2).p4()*deltaEn/pfCand->at(ce2).p4().E();
00230             candidatesWithTrackExcess[pfCand->at(ce2).trackRef()->pt()/pfCand->at(ce2).trackRef()->ptError()] =  momentumExcess;
00231           }
00232           else if(caloEn < 0.01) candidatesWithoutCalo[pfCand->at(ce2).trackRef()->pt()/pfCand->at(ce2).trackRef()->ptError()] = pfCand->at(ce2).p4();
00233           momentumSec += (pfCand->at(ce2)).p4();
00234         }
00235 
00236         bMask_[ce2] = true;
00237 
00238 
00239         
00240       }
00241     }
00242   }
00243   
00244   
00245   // We have more primary energy than secondary: reject all secondary tracks which have no calo energy attached.
00246   
00247   
00248   if (momentumPrim.E() < momentumSec.E()){
00249     
00250     if(debug_) cout << "Size of 0 calo Energy secondary candidates" << candidatesWithoutCalo.size() << endl;
00251     for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithoutCalo.begin(); iter != candidatesWithoutCalo.end() && momentumPrim.E() < momentumSec.E(); iter++)
00252       if (momentumSec.E() > iter->second.E()+0.1) {
00253         momentumSec -= iter->second;   
00254     
00255         if(debug_) cout << "\t Remove a SecondaryCandidate with 0 calo energy " << iter->second << endl;
00256         
00257         if(debug_) cout << "momentumPrim.E() = " << momentumPrim.E() << " and momentumSec.E() = " <<  momentumSec.E() << endl; 
00258             
00259       }
00260 
00261   }
00262 
00263       
00264   if (momentumPrim.E() < momentumSec.E()){
00265     if(debug_) cout << "0 Calo Energy rejected but still not sufficient. Size of not enough calo Energy secondary candidates" << candidatesWithTrackExcess.size() << endl;
00266      for( map<double, math::XYZTLorentzVectorD>::iterator iter = candidatesWithTrackExcess.begin(); iter != candidatesWithTrackExcess.end() && momentumPrim.E() < momentumSec.E(); iter++)
00267       if (momentumSec.E() > iter->second.E()+0.1) momentumSec -= iter->second;   
00268      
00269   }
00270 
00271 
00272     
00273 
00274   double dpt = pfCand->at(ce1).trackRef()->ptError()/pfCand->at(ce1).trackRef()->pt()*100; 
00275 
00276   if (momentumSec.E() < 0.1) {
00277     bMask_[ce1] = true;
00278     return;
00279   }
00280   
00281   // Rescale the secondary candidates to account for the loss of energy, but only if we can trust the primary track:
00282   // if it has more energy than secondaries and is precise enough and secondary exist and was not eaten or rejected during the PFAlgo step.
00283   
00284   if( ( (ref1->isTherePrimaryTracks() && dpt<dptRel_PrimaryTrack_)  || (ref1->isThereMergedTracks() && dpt<dptRel_MergedTrack_) ) && momentumPrim.E() > momentumSec.E() && momentumSec.E() > 0.1) {
00285       
00286     if (bCalibPrimary_){
00287       double factor = rescaleFactor( momentumPrim.Pt(), momentumSec.E()/momentumPrim.E()); 
00288       if (debug_) cout << "factor = " << factor << endl;
00289       if (factor*momentumPrim.Pt() < momentumSec.Pt()) momentumSec = momentumPrim;
00290       else momentumSec += (1-factor)*momentumPrim;
00291     }
00292     
00293     double px = momentumPrim.Px()*momentumSec.P()/momentumPrim.P();
00294     double py = momentumPrim.Py()*momentumSec.P()/momentumPrim.P();
00295     double pz = momentumPrim.Pz()*momentumSec.P()/momentumPrim.P();
00296     double E  = sqrt(px*px + py*py + pz*pz + pion_mass2);
00297     math::XYZTLorentzVectorD momentum(px, py, pz, E);
00298     pfCand->at(ce1).setP4(momentum);
00299     
00300     return;
00301     
00302   } else {
00303 
00304     math::XYZVector primDir =  ref1->primaryDirection();
00305 
00306     
00307     if (primDir.Mag2() < 0.1){
00308       // It might be 0 but this situation should never happend. Throw a warning if it happens.
00309       edm::LogWarning("PFCandConnector") << "A Nuclear Interaction do not have primary direction" << std::endl;
00310       pfCand->at(ce1).setP4(momentumSec);
00311       return;
00312     } else {
00313       // 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. 
00314       double momentumS = momentumSec.P();
00315       if (momentumS < 1e-4) momentumS = 1e-4;
00316       double px = momentumS*primDir.x();
00317       double py = momentumS*primDir.y();
00318       double pz = momentumS*primDir.z();
00319       double E  = sqrt(px*px + py*py + pz*pz + pion_mass2);
00320       
00321       math::XYZTLorentzVectorD momentum(px, py, pz, E);
00322       pfCand->at(ce1).setP4(momentum);
00323       return;
00324     }
00325   }
00326   
00327   
00328 
00329 }
00330 
00331 
00332 
00333 
00334 void 
00335 PFCandConnector::analyseNuclearWSec(std::auto_ptr<PFCandidateCollection>& pfCand, unsigned int ce1){
00336 
00337   PFDisplacedVertexRef ref1, ref2;  
00338 
00339 
00340   // Check if the track excess was not too large and track may miss some outer hits. This may point to a secondary NI.
00341 
00342   double caloEn = pfCand->at(ce1).ecalEnergy() + pfCand->at(ce1).hcalEnergy();
00343   double deltaEn =  pfCand->at(ce1).p4().E() - caloEn;
00344   int nMissOuterHits = pfCand->at(ce1).trackRef()->trackerExpectedHitsOuter().numberOfHits();  
00345 
00346 
00347   ref1 = pfCand->at(ce1).displacedVertexRef(fT_FROM_DISP_);
00348 
00349   // ------- check if an electron or a muon vas spotted as incoming track -------- //
00350   // ------- this mean probably that the NI was fake thus we do not correct it -------- /
00351 
00352   if (ref1->isTherePrimaryTracks() || ref1->isThereMergedTracks()){
00353     
00354     std::vector<reco::Track> refittedTracks = ref1->refittedTracks();
00355     for(unsigned it = 0; it < refittedTracks.size(); it++){
00356       reco::TrackBaseRef primaryBaseRef = ref1->originalTrack(refittedTracks[it]);  
00357       if (ref1->isIncomingTrack(primaryBaseRef))
00358         if (debug_) cout << "There is a Primary track ref with pt = " << primaryBaseRef->pt()<< endl;
00359 
00360       for( unsigned int ce=0; ce < pfCand->size(); ++ce){
00361         //        cout << "PFCand Id = " << (pfCand->at(ce)).particleId() << endl;
00362         if ((pfCand->at(ce)).particleId() == reco::PFCandidate::e || (pfCand->at(ce)).particleId() == reco::PFCandidate::mu) {
00363 
00364           if (debug_) cout << " It is an electron and it has a ref to a track " << (pfCand->at(ce)).trackRef().isNonnull() << endl;
00365           
00366 
00367           if ( (pfCand->at(ce)).trackRef().isNonnull() ){
00368             reco::TrackRef tRef = (pfCand->at(ce)).trackRef();
00369             reco::TrackBaseRef bRef(tRef);
00370             if (debug_) cout << "With Track Ref pt = " << (pfCand->at(ce)).trackRef()->pt() << endl;
00371 
00372             if (bRef == primaryBaseRef) {
00373               if (debug_ && (pfCand->at(ce)).particleId() == reco::PFCandidate::e) cout << "It is a NI from electron. NI Discarded. Just release the candidate." << endl; 
00374               if (debug_ && (pfCand->at(ce)).particleId() == reco::PFCandidate::mu) cout << "It is a NI from muon. NI Discarded. Just release the candidate" << endl; 
00375         
00376               // release the track but take care of not overcounting bad tracks. In fact those tracks was protected against destruction in 
00377               // PFAlgo. Now we treat them as if they was treated in PFAlgo
00378 
00379               if (caloEn < 0.1 && pfCand->at(ce1).trackRef()->ptError() > ptErrorSecondary_) { 
00380                 cout << "discarded track since no calo energy and ill measured" << endl; 
00381                 bMask_[ce1] = true;
00382               }
00383               if (caloEn > 0.1 && deltaEn >ptErrorSecondary_  && pfCand->at(ce1).trackRef()->ptError() > ptErrorSecondary_) { 
00384                 cout << "rescaled momentum of the track since no calo energy and ill measured" << endl;
00385                 
00386                 double factor = caloEn/pfCand->at(ce1).p4().E();
00387                 pfCand->at(ce1).rescaleMomentum(factor);
00388               }
00389 
00390               return;
00391             }
00392           }
00393         }
00394       }
00395     }
00396   }
00397 
00398 
00399   PFCandidate secondaryCand = pfCand->at(ce1);
00400 
00401   math::XYZTLorentzVectorD momentumSec = secondaryCand.p4();
00402 
00403   if (deltaEn > ptErrorSecondary_  && nMissOuterHits > 1) {
00404     math::XYZTLorentzVectorD momentumToAdd = pfCand->at(ce1).p4()*caloEn/pfCand->at(ce1).p4().E();
00405     momentumSec = momentumToAdd;
00406     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;  
00407   }
00408 
00409 
00410   // ------- look for the little friends -------- //
00411   for( unsigned int ce2=ce1+1; ce2 < pfCand->size(); ++ce2) {
00412     if (isSecondaryNucl(pfCand->at(ce2))){
00413       ref2 = (pfCand->at(ce2)).displacedVertexRef(fT_FROM_DISP_);
00414 
00415       if (ref1 == ref2) {
00416          
00417         if (debug_) cout << "\t here is a Secondary Candidate " << ce2  
00418                          << " " << pfCand->at(ce2) << endl
00419                          << "\t based on the Track " << pfCand->at(ce2).trackRef().key()
00420                          << " w pT = " << pfCand->at(ce2).trackRef()->pt()
00421                          << " #pm " << pfCand->at(ce2).trackRef()->ptError() << " %" 
00422                          << " ECAL = " << pfCand->at(ce2).ecalEnergy() 
00423                          << " HCAL = " << pfCand->at(ce2).hcalEnergy() 
00424                          << " dE(Trk-CALO) = " << pfCand->at(ce2).trackRef()->p()-pfCand->at(ce2).ecalEnergy()-pfCand->at(ce2).hcalEnergy() 
00425                          << " Nmissing hits = " << pfCand->at(ce2).trackRef()->trackerExpectedHitsOuter().numberOfHits() << endl;
00426 
00427         // Take now the parameters of the secondary track that are relevant and use them to construct the NI candidate
00428         PFCandidate::ElementsInBlocks elementsInBlocks = pfCand->at(ce2).elementsInBlocks();
00429         PFCandidate::ElementsInBlocks elementsAlreadyInBlocks = pfCand->at(ce1).elementsInBlocks();
00430         for (unsigned blockElem = 0; blockElem < elementsInBlocks.size(); blockElem++){
00431           bool isAlreadyHere = false;
00432           for (unsigned alreadyBlock = 0; alreadyBlock < elementsAlreadyInBlocks.size(); alreadyBlock++){
00433             if (elementsAlreadyInBlocks[alreadyBlock].second == elementsInBlocks[blockElem].second) isAlreadyHere = true;
00434           }
00435           if (!isAlreadyHere) pfCand->at(ce1).addElementInBlock( elementsInBlocks[blockElem].first,  elementsInBlocks[blockElem].second);
00436         }
00437 
00438         double caloEn = pfCand->at(ce2).ecalEnergy() + pfCand->at(ce2).hcalEnergy();
00439         double deltaEn =  pfCand->at(ce2).p4().E() - caloEn;
00440         int nMissOuterHits = pfCand->at(ce2).trackRef()->trackerExpectedHitsOuter().numberOfHits();  
00441         if (deltaEn > ptErrorSecondary_ && nMissOuterHits > 1) {
00442           math::XYZTLorentzVectorD momentumToAdd = pfCand->at(ce2).p4()*caloEn/pfCand->at(ce2).p4().E();
00443           momentumSec += momentumToAdd;
00444           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;  
00445         } else {
00446           momentumSec += (pfCand->at(ce2)).p4();        
00447         }
00448 
00449         bMask_[ce2] = true;
00450       }
00451     }
00452   }
00453   
00454   
00455 
00456 
00457   math::XYZVector primDir =  ref1->primaryDirection();
00458 
00459   if (primDir.Mag2() < 0.1){
00460     // It might be 0 but this situation should never happend. Throw a warning if it happens.
00461     pfCand->at(ce1).setP4(momentumSec);
00462     edm::LogWarning("PFCandConnector") << "A Nuclear Interaction do not have primary direction" << std::endl;
00463     return;
00464   } else {
00465     // 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.
00466     double momentumS = momentumSec.P();
00467     if (momentumS < 1e-4) momentumS = 1e-4;
00468     double px = momentumS*primDir.x();
00469     double py = momentumS*primDir.y();
00470     double pz = momentumS*primDir.z();
00471     double E  = sqrt(px*px + py*py + pz*pz + pion_mass2);
00472      
00473     math::XYZTLorentzVectorD momentum(px, py, pz, E);
00474      
00475     pfCand->at(ce1).setP4(momentum);
00476     return;
00477   }
00478 
00479 }
00480 
00481 bool 
00482 PFCandConnector::isSecondaryNucl( const PFCandidate& pf ) const {
00483   
00484   PFDisplacedVertexRef ref1;
00485   // nuclear
00486   if( pf.flag( fT_FROM_DISP_ ) ) {
00487     ref1 = pf.displacedVertexRef(fT_FROM_DISP_);
00488     //    ref1->Dump();
00489     if (!ref1.isNonnull()) return false;
00490     else if (ref1->isNucl() || ref1->isNucl_Loose() || ref1->isNucl_Kink())
00491     return true;
00492   }
00493   
00494   return false;
00495 }
00496 
00497 bool 
00498 PFCandConnector::isPrimaryNucl( const PFCandidate& pf ) const {
00499 
00500   PFDisplacedVertexRef ref1;
00501   
00502   // nuclear
00503   if( pf.flag( fT_TO_DISP_ ) ) {
00504     ref1 = pf.displacedVertexRef(fT_TO_DISP_);
00505     //ref1->Dump();
00506 
00507     if (!ref1.isNonnull()) return false;
00508     else if (ref1->isNucl()|| ref1->isNucl_Loose() || ref1->isNucl_Kink())
00509     return true;
00510   }
00511   
00512   return false;
00513 }
00514 
00515 
00516 double
00517 PFCandConnector::rescaleFactor( const double pt, const double cFrac ) const {
00518 
00519 
00520   /*
00521     LOG NORMAL FIT
00522  FCN=35.8181 FROM MIGRAD    STATUS=CONVERGED     257 CALLS         258 TOTAL
00523  EDM=8.85763e-09    STRATEGY= 1      ERROR MATRIX ACCURATE
00524   EXT PARAMETER                                   STEP         FIRST
00525   NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE
00526    1  p0           7.99434e-01   2.77264e-02   6.59108e-06   9.80247e-03
00527    2  p1           1.51303e-01   2.89981e-02   1.16775e-05   6.99035e-03
00528    3  p2          -5.03829e-01   2.87929e-02   1.90070e-05   1.37015e-03
00529    4  p3           4.54043e-01   5.00908e-02   3.17625e-05   3.86622e-03
00530    5  p4          -4.61736e-02   8.07940e-03   3.25775e-06  -1.37247e-02
00531   */
00532 
00533 
00534   /*
00535     FCN=34.4051 FROM MIGRAD    STATUS=CONVERGED     221 CALLS         222 TOTAL
00536     EDM=1.02201e-09    STRATEGY= 1  ERROR MATRIX UNCERTAINTY   2.3 per cent
00537 
00538    fConst
00539    1  p0           7.99518e-01   2.23519e-02   1.41523e-06   4.05975e-04
00540    2  p1           1.44619e-01   2.39398e-02  -7.68117e-07  -2.55775e-03
00541 
00542    fNorm
00543    3  p2          -5.16571e-01   3.12362e-02   5.74932e-07   3.42292e-03
00544    4  p3           4.69055e-01   5.09665e-02   1.94353e-07   1.69031e-03
00545 
00546    fExp
00547    5  p4          -5.18044e-02   8.13458e-03   4.29815e-07  -1.07624e-02
00548   */
00549 
00550   double fConst, fNorm, fExp;
00551 
00552   fConst = fConst_[0] + fConst_[1]*cFrac;
00553   fNorm = fNorm_[0] - fNorm_[1]*cFrac;
00554   fExp = fExp_[0];  
00555 
00556   double factor = fConst - fNorm*exp( -fExp*pt );
00557 
00558   return factor;
00559 
00560 }