CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_2_9/src/RecoParticleFlow/PFProducer/src/PFAlgo.cc

Go to the documentation of this file.
00001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00002 
00003 #include "RecoParticleFlow/PFProducer/interface/PFAlgo.h"
00004 #include "RecoParticleFlow/PFProducer/interface/PFMuonAlgo.h"  //PFMuons
00005 #include "RecoParticleFlow/PFProducer/interface/PFElectronAlgo.h"  
00006 #include "RecoParticleFlow/PFProducer/interface/PFPhotonAlgo.h"    
00007 #include "RecoParticleFlow/PFProducer/interface/PFElectronExtraEqual.h"
00008 
00009 #include "RecoParticleFlow/PFClusterTools/interface/PFEnergyCalibration.h"
00010 #include "RecoParticleFlow/PFClusterTools/interface/PFEnergyCalibrationHF.h"
00011 #include "RecoParticleFlow/PFClusterTools/interface/PFSCEnergyCalibration.h"
00012 
00013 #include "DataFormats/ParticleFlowReco/interface/PFRecHit.h"
00014 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h"
00015 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementTrack.h"
00016 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementCluster.h"
00017 #include "DataFormats/ParticleFlowReco/interface/PFRecTrack.h"
00018 #include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
00019 #include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
00020 
00021 #include "DataFormats/VertexReco/interface/Vertex.h"
00022 #include "DataFormats/TrackReco/interface/Track.h"
00023 #include "DataFormats/MuonReco/interface/Muon.h"
00024 
00025 // #include "FWCore/Framework/interface/OrphanHandle.h"
00026 #include "DataFormats/Common/interface/OrphanHandle.h"
00027 // #include "DataFormats/Common/interface/ProductID.h"
00028 #include "DataFormats/Provenance/interface/ProductID.h"
00029 #include "DataFormats/Math/interface/LorentzVector.h"
00030 
00031 
00032 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00033 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h"
00034 
00035 #include "DataFormats/ParticleFlowReco/interface/PFDisplacedVertex.h"
00036 #include "DataFormats/ParticleFlowReco/interface/PFDisplacedVertexFwd.h"
00037 
00038 
00039 #include "Math/PxPyPzM4D.h"
00040 #include "Math/LorentzVector.h"
00041 #include "Math/DisplacementVector3D.h"
00042 #include "Math/SMatrix.h"
00043 #include "TDecompChol.h"
00044 
00045 #include "boost/graph/adjacency_matrix.hpp" 
00046 #include "boost/graph/graph_utility.hpp" 
00047 
00048 
00049 using namespace std;
00050 using namespace reco;
00051 using namespace boost;
00052 
00053 typedef std::list< reco::PFBlockRef >::iterator IBR;
00054 
00055 
00056 
00057 PFAlgo::PFAlgo()
00058   : pfCandidates_( new PFCandidateCollection),
00059     nSigmaECAL_(0), 
00060     nSigmaHCAL_(1),
00061     algo_(1),
00062     debug_(false),
00063     pfele_(0),
00064     pfpho_(0),
00065     useVertices_(false)
00066 {}
00067 
00068 PFAlgo::~PFAlgo() {
00069   if (usePFElectrons_) delete pfele_;
00070   if (usePFPhotons_)     delete pfpho_;
00071 }
00072 
00073 
00074 void 
00075 PFAlgo::setParameters(double nSigmaECAL,
00076                       double nSigmaHCAL, 
00077                       const boost::shared_ptr<PFEnergyCalibration>& calibration,
00078                       const boost::shared_ptr<PFEnergyCalibrationHF>&  thepfEnergyCalibrationHF) {
00079 
00080   nSigmaECAL_ = nSigmaECAL;
00081   nSigmaHCAL_ = nSigmaHCAL;
00082 
00083   calibration_ = calibration;
00084   thepfEnergyCalibrationHF_ = thepfEnergyCalibrationHF;
00085 
00086 }
00087 
00088 //PFElectrons: a new method added to set the parameters for electron reconstruction. 
00089 void 
00090 PFAlgo::setPFEleParameters(double mvaEleCut,
00091                            string mvaWeightFileEleID,
00092                            bool usePFElectrons,
00093                            const boost::shared_ptr<PFSCEnergyCalibration>& thePFSCEnergyCalibration,
00094                            const boost::shared_ptr<PFEnergyCalibration>& thePFEnergyCalibration,
00095                            double sumEtEcalIsoForEgammaSC_barrel,
00096                            double sumEtEcalIsoForEgammaSC_endcap,
00097                            double coneEcalIsoForEgammaSC,
00098                            double sumPtTrackIsoForEgammaSC_barrel,
00099                            double sumPtTrackIsoForEgammaSC_endcap,
00100                            unsigned int nTrackIsoForEgammaSC,
00101                            double coneTrackIsoForEgammaSC,
00102                            bool applyCrackCorrections,
00103                            bool usePFSCEleCalib,
00104                            bool useEGElectrons,
00105                            bool useEGammaSupercluster) {
00106   
00107   mvaEleCut_ = mvaEleCut;
00108   usePFElectrons_ = usePFElectrons;
00109   applyCrackCorrectionsElectrons_ = applyCrackCorrections;  
00110   usePFSCEleCalib_ = usePFSCEleCalib;
00111   thePFSCEnergyCalibration_ = thePFSCEnergyCalibration;
00112   useEGElectrons_ = useEGElectrons;
00113   useEGammaSupercluster_ = useEGammaSupercluster;
00114   sumEtEcalIsoForEgammaSC_barrel_ = sumEtEcalIsoForEgammaSC_barrel;
00115   sumEtEcalIsoForEgammaSC_endcap_ = sumEtEcalIsoForEgammaSC_endcap;
00116   coneEcalIsoForEgammaSC_ = coneEcalIsoForEgammaSC;
00117   sumPtTrackIsoForEgammaSC_barrel_ = sumPtTrackIsoForEgammaSC_barrel;
00118   sumPtTrackIsoForEgammaSC_endcap_ = sumPtTrackIsoForEgammaSC_endcap;
00119   coneTrackIsoForEgammaSC_ = coneTrackIsoForEgammaSC;
00120   nTrackIsoForEgammaSC_ = nTrackIsoForEgammaSC;
00121 
00122 
00123   if(!usePFElectrons_) return;
00124   mvaWeightFileEleID_ = mvaWeightFileEleID;
00125   FILE * fileEleID = fopen(mvaWeightFileEleID_.c_str(), "r");
00126   if (fileEleID) {
00127     fclose(fileEleID);
00128   }
00129   else {
00130     string err = "PFAlgo: cannot open weight file '";
00131     err += mvaWeightFileEleID;
00132     err += "'";
00133     throw invalid_argument( err );
00134   }
00135   pfele_= new PFElectronAlgo(mvaEleCut_,mvaWeightFileEleID_,
00136                              thePFSCEnergyCalibration_,
00137                              thePFEnergyCalibration,
00138                              applyCrackCorrectionsElectrons_,
00139                              usePFSCEleCalib_,
00140                              useEGElectrons_,
00141                              useEGammaSupercluster_,
00142                              sumEtEcalIsoForEgammaSC_barrel_,
00143                              sumEtEcalIsoForEgammaSC_endcap_,
00144                              coneEcalIsoForEgammaSC_,
00145                              sumPtTrackIsoForEgammaSC_barrel_,
00146                              sumPtTrackIsoForEgammaSC_endcap_,
00147                              nTrackIsoForEgammaSC_,
00148                              coneTrackIsoForEgammaSC_);
00149 }
00150 
00151 void 
00152 PFAlgo::setPFPhotonParameters(bool usePFPhotons,  
00153                               std::string mvaWeightFileConvID, 
00154                               double mvaConvCut,
00155                               bool useReg,
00156                               std::string X0_Map,
00157                               const boost::shared_ptr<PFEnergyCalibration>& thePFEnergyCalibration,
00158                               double sumPtTrackIsoForPhoton,
00159                               double sumPtTrackIsoSlopeForPhoton)
00160  {
00161 
00162   usePFPhotons_ = usePFPhotons;
00163 
00164   //for MVA pass PV if there is one in the collection otherwise pass a dummy    
00165   reco::Vertex dummy;  
00166   const reco::Vertex* pv=&dummy;  
00167   if(useVertices_)  
00168     {  
00169       dummy = primaryVertex_;  
00170     }  
00171   else { // create a dummy PV  
00172     reco::Vertex::Error e;  
00173     e(0, 0) = 0.0015 * 0.0015;  
00174     e(1, 1) = 0.0015 * 0.0015;  
00175     e(2, 2) = 15. * 15.;  
00176     reco::Vertex::Point p(0, 0, 0);  
00177     dummy = reco::Vertex(p, e, 0, 0, 0);  
00178   }  
00179    
00180   if(! usePFPhotons_) return;  
00181   FILE * filePhotonConvID = fopen(mvaWeightFileConvID.c_str(), "r");  
00182   if (filePhotonConvID) {  
00183     fclose(filePhotonConvID);  
00184   }  
00185   else {  
00186     string err = "PFAlgo: cannot open weight file '";  
00187     err += mvaWeightFileConvID;  
00188     err += "'";  
00189     throw invalid_argument( err );  
00190   }  
00191    
00192   
00193   pfpho_ = new PFPhotonAlgo(mvaWeightFileConvID, 
00194                             mvaConvCut, 
00195                             useReg,
00196                             X0_Map,  
00197                             *pv,
00198                             thePFEnergyCalibration,
00199                             sumPtTrackIsoForPhoton,
00200                             sumPtTrackIsoSlopeForPhoton
00201                             );
00202   return;
00203 }
00204 
00205 void PFAlgo::setPFPhotonRegWeights(
00206                   const GBRForest *LCorrForest,
00207                   const GBRForest *GCorrForest,
00208                   const GBRForest *ResForest
00209                   ) {                                                           
00210   if(usePFPhotons_) 
00211     pfpho_->setGBRForest(LCorrForest, GCorrForest, ResForest);
00212 } 
00213 
00214 void 
00215 PFAlgo::setPFMuonAndFakeParameters(std::vector<double> muonHCAL,
00216                                    std::vector<double> muonECAL,
00217                                    std::vector<double> muonHO,
00218                                    double nSigmaTRACK,
00219                                    double ptError,
00220                                    std::vector<double> factors45,
00221                                    bool usePFMuonMomAssign,
00222                                    bool useBestMuonTrack) 
00223 {
00224   muonHCAL_ = muonHCAL;
00225   muonECAL_ = muonECAL;
00226   muonHO_ = muonHO;
00227   nSigmaTRACK_ = nSigmaTRACK;
00228   ptError_ = ptError;
00229   factors45_ = factors45;
00230   usePFMuonMomAssign_ = usePFMuonMomAssign;
00231   useBestMuonTrack_ = useBestMuonTrack;
00232 }
00233   
00234 void 
00235 PFAlgo::setPostHFCleaningParameters(bool postHFCleaning,
00236                                     double minHFCleaningPt,
00237                                     double minSignificance,
00238                                     double maxSignificance,
00239                                     double minSignificanceReduction,
00240                                     double maxDeltaPhiPt,
00241                                     double minDeltaMet) { 
00242   postHFCleaning_ = postHFCleaning;
00243   minHFCleaningPt_ = minHFCleaningPt;
00244   minSignificance_ = minSignificance;
00245   maxSignificance_ = maxSignificance;
00246   minSignificanceReduction_= minSignificanceReduction;
00247   maxDeltaPhiPt_ = maxDeltaPhiPt;
00248   minDeltaMet_ = minDeltaMet;
00249 }
00250 
00251 void 
00252 PFAlgo::setDisplacedVerticesParameters(bool rejectTracks_Bad,
00253                                        bool rejectTracks_Step45,
00254                                        bool usePFNuclearInteractions,
00255                                        bool usePFConversions,
00256                                        bool usePFDecays, 
00257                                        double dptRel_DispVtx){
00258 
00259   rejectTracks_Bad_ = rejectTracks_Bad;
00260   rejectTracks_Step45_ = rejectTracks_Step45;
00261   usePFNuclearInteractions_ = usePFNuclearInteractions;
00262   usePFConversions_ = usePFConversions;
00263   usePFDecays_ = usePFDecays;
00264   dptRel_DispVtx_ = dptRel_DispVtx;
00265 
00266 }
00267 
00268 
00269 void
00270 PFAlgo::setPFVertexParameters(bool useVertex,
00271                               const reco::VertexCollection& primaryVertices) {
00272   useVertices_ = useVertex;
00273   //Now find the primary vertex!
00274   bool primaryVertexFound = false;
00275   for (unsigned short i=0 ;i<primaryVertices.size();++i)
00276     {
00277       if(primaryVertices[i].isValid()&&(!primaryVertices[i].isFake()))
00278         {
00279           primaryVertex_ = primaryVertices[i];
00280           primaryVertexFound = true;
00281           break;
00282         }
00283     }
00284   //Use vertices if the user wants to but only if it exists a good vertex 
00285   useVertices_ = useVertex && primaryVertexFound; 
00286 
00287 }
00288 
00289 
00290 void PFAlgo::reconstructParticles( const reco::PFBlockHandle& blockHandle ) {
00291 
00292   blockHandle_ = blockHandle;
00293   reconstructParticles( *blockHandle_ ); 
00294 }
00295 
00296 
00297 
00298 void PFAlgo::reconstructParticles( const reco::PFBlockCollection& blocks ) {
00299 
00300   // reset output collection
00301   if(pfCandidates_.get() )
00302     pfCandidates_->clear();
00303   else 
00304     pfCandidates_.reset( new reco::PFCandidateCollection );
00305 
00306   if(pfElectronCandidates_.get() )
00307     pfElectronCandidates_->clear();
00308   else
00309     pfElectronCandidates_.reset( new reco::PFCandidateCollection);
00310 
00311   // Clearing pfPhotonCandidates
00312   if( pfPhotonCandidates_.get() )
00313     pfPhotonCandidates_->clear();
00314   else
00315     pfPhotonCandidates_.reset( new reco::PFCandidateCollection);
00316 
00317   if(pfCleanedCandidates_.get() ) 
00318     pfCleanedCandidates_->clear();
00319   else
00320     pfCleanedCandidates_.reset( new reco::PFCandidateCollection );
00321   
00322   if(pfCosmicsMuonCleanedCandidates_.get() )
00323     pfCosmicsMuonCleanedCandidates_->clear();
00324   else 
00325     pfCosmicsMuonCleanedCandidates_.reset( new reco::PFCandidateCollection );
00326 
00327   if(pfCleanedTrackerAndGlobalMuonCandidates_.get() )
00328     pfCleanedTrackerAndGlobalMuonCandidates_->clear();
00329   else 
00330     pfCleanedTrackerAndGlobalMuonCandidates_.reset( new reco::PFCandidateCollection );
00331 
00332   if(pfFakeMuonCleanedCandidates_.get() )
00333     pfFakeMuonCleanedCandidates_->clear();
00334   else 
00335     pfFakeMuonCleanedCandidates_.reset( new reco::PFCandidateCollection );
00336 
00337   if(pfPunchThroughMuonCleanedCandidates_.get() )
00338     pfPunchThroughMuonCleanedCandidates_->clear();
00339   else 
00340     pfPunchThroughMuonCleanedCandidates_.reset( new reco::PFCandidateCollection );
00341 
00342   if(pfPunchThroughHadronCleanedCandidates_.get() )
00343     pfPunchThroughHadronCleanedCandidates_->clear();
00344   else 
00345     pfPunchThroughHadronCleanedCandidates_.reset( new reco::PFCandidateCollection );
00346 
00347   if(pfAddedMuonCandidates_.get() )
00348     pfAddedMuonCandidates_->clear();
00349   else 
00350     pfAddedMuonCandidates_.reset( new reco::PFCandidateCollection );
00351 
00352   // not a auto_ptr; shout not be deleted after transfer
00353   pfElectronExtra_.clear();
00354   pfPhotonExtra_.clear();
00355   
00356   if( debug_ ) {
00357     cout<<"*********************************************************"<<endl;
00358     cout<<"*****           Particle flow algorithm             *****"<<endl;
00359     cout<<"*********************************************************"<<endl;
00360   }
00361 
00362   // sort elements in three lists:
00363   std::list< reco::PFBlockRef > hcalBlockRefs;
00364   std::list< reco::PFBlockRef > ecalBlockRefs;
00365   std::list< reco::PFBlockRef > hoBlockRefs;
00366   std::list< reco::PFBlockRef > otherBlockRefs;
00367   
00368   for( unsigned i=0; i<blocks.size(); ++i ) {
00369     // reco::PFBlockRef blockref( blockh,i );
00370     reco::PFBlockRef blockref = createBlockRef( blocks, i);
00371     
00372     const reco::PFBlock& block = *blockref;
00373     const edm::OwnVector< reco::PFBlockElement >& 
00374       elements = block.elements();
00375    
00376     bool singleEcalOrHcal = false;
00377     if( elements.size() == 1 ){
00378       if( elements[0].type() == reco::PFBlockElement::ECAL ){
00379         ecalBlockRefs.push_back( blockref );
00380         singleEcalOrHcal = true;
00381       }
00382       if( elements[0].type() == reco::PFBlockElement::HCAL ){
00383         hcalBlockRefs.push_back( blockref );
00384         singleEcalOrHcal = true;
00385       }
00386       if( elements[0].type() == reco::PFBlockElement::HO ){
00387         // Single HO elements are likely to be noise. Not considered for now.
00388         hoBlockRefs.push_back( blockref );
00389         singleEcalOrHcal = true;
00390       }
00391     }
00392     
00393     if(!singleEcalOrHcal) {
00394       otherBlockRefs.push_back( blockref );
00395     }
00396   }//loop blocks
00397   
00398   if( debug_ ){
00399     cout<<"# Ecal blocks: "<<ecalBlockRefs.size()
00400         <<", # Hcal blocks: "<<hcalBlockRefs.size()
00401         <<", # HO blocks: "<<hoBlockRefs.size()
00402         <<", # Other blocks: "<<otherBlockRefs.size()<<endl;
00403   }
00404 
00405 
00406   // loop on blocks that are not single ecal, 
00407   // and not single hcal.
00408 
00409   unsigned nblcks = 0;
00410   for( IBR io = otherBlockRefs.begin(); io!=otherBlockRefs.end(); ++io) {
00411     if ( debug_ ) std::cout << "Block number " << nblcks++ << std::endl; 
00412     processBlock( *io, hcalBlockRefs, ecalBlockRefs );
00413   }
00414 
00415   std::list< reco::PFBlockRef > empty;
00416 
00417   unsigned hblcks = 0;
00418   // process remaining single hcal blocks
00419   for( IBR ih = hcalBlockRefs.begin(); ih!=hcalBlockRefs.end(); ++ih) {
00420     if ( debug_ ) std::cout << "HCAL block number " << hblcks++ << std::endl;
00421     processBlock( *ih, empty, empty );
00422   }
00423 
00424   unsigned eblcks = 0;
00425   // process remaining single ecal blocks
00426   for( IBR ie = ecalBlockRefs.begin(); ie!=ecalBlockRefs.end(); ++ie) {
00427     if ( debug_ ) std::cout << "ECAL block number " << eblcks++ << std::endl;
00428     processBlock( *ie, empty, empty );
00429   }
00430 
00431   // Post HF Cleaning
00432   postCleaning();
00433 }
00434 
00435 
00436 void PFAlgo::processBlock( const reco::PFBlockRef& blockref,
00437                            std::list<reco::PFBlockRef>& hcalBlockRefs, 
00438                            std::list<reco::PFBlockRef>& ecalBlockRefs ) { 
00439   
00440   // debug_ = false;
00441   assert(!blockref.isNull() );
00442   const reco::PFBlock& block = *blockref;
00443 
00444   typedef std::multimap<double, unsigned>::iterator IE;
00445   typedef std::multimap<double, std::pair<unsigned,math::XYZVector> >::iterator IS;
00446   typedef std::multimap<double, std::pair<unsigned,bool> >::iterator IT;
00447   typedef std::multimap< unsigned, std::pair<double, unsigned> >::iterator II;
00448 
00449   if(debug_) {
00450     cout<<"#########################################################"<<endl;
00451     cout<<"#####           Process Block:                      #####"<<endl;
00452     cout<<"#########################################################"<<endl;
00453     cout<<block<<endl;
00454   }
00455 
00456 
00457   const edm::OwnVector< reco::PFBlockElement >& elements = block.elements();
00458   // make a copy of the link data, which will be edited.
00459   PFBlock::LinkData linkData =  block.linkData();
00460   
00461   // keep track of the elements which are still active.
00462   vector<bool>   active( elements.size(), true );
00463 
00464 
00465   // //PFElectrons:
00466   // usePFElectrons_ external configurable parameter to set the usage of pf electron
00467   std::vector<reco::PFCandidate> tempElectronCandidates;
00468   tempElectronCandidates.clear();
00469   if (usePFElectrons_) {
00470     if (pfele_->isElectronValidCandidate(blockref,active)){
00471       // if there is at least a valid candidate is get the vector of pfcandidates
00472       const std::vector<reco::PFCandidate> PFElectCandidates_(pfele_->getElectronCandidates());
00473       for ( std::vector<reco::PFCandidate>::const_iterator ec=PFElectCandidates_.begin();   ec != PFElectCandidates_.end(); ++ec )tempElectronCandidates.push_back(*ec);
00474       
00475       // (***) We're filling the ElectronCandidates into the PFCandiate collection
00476       // ..... Once we let PFPhotonAlgo over-write electron-decision, we need to move this to
00477       // ..... after the PhotonAlgo has run (Fabian)
00478     }    
00479     // The vector active is automatically changed (it is passed by ref) in PFElectronAlgo
00480     // for all the electron candidate      
00481     pfElectronCandidates_->insert(pfElectronCandidates_->end(), 
00482                                   pfele_->getAllElectronCandidates().begin(), 
00483                                   pfele_->getAllElectronCandidates().end()); 
00484 
00485     pfElectronExtra_.insert(pfElectronExtra_.end(), 
00486                             pfele_->getElectronExtra().begin(),
00487                             pfele_->getElectronExtra().end());
00488     
00489   }
00490   if( /* --- */ usePFPhotons_ /* --- */ ) {    
00491     
00492     if(debug_)
00493       cout<<endl<<"--------------- entering PFPhotonAlgo ----------------"<<endl;
00494     vector<PFCandidatePhotonExtra> pfPhotonExtraCand;
00495     if ( pfpho_->isPhotonValidCandidate(blockref,               // passing the reference to the PFBlock
00496                                         active,                 // std::vector<bool> containing information about acitivity
00497                                         pfPhotonCandidates_,    // pointer to candidate vector, to be filled by the routine
00498                                         pfPhotonExtraCand,      // candidate extra vector, to be filled by the routine   
00499                                         tempElectronCandidates
00500                                         //pfElectronCandidates_   // pointer to some auziliary UNTOUCHED FOR NOW
00501                                         ) ) {
00502       if(debug_)
00503         std::cout<< " In this PFBlock we found "<<pfPhotonCandidates_->size()<<" Photon Candidates."<<std::endl;
00504       
00505       // CAUTION: In case we want to allow the PhotonAlgo to 'over-write' what the ElectronAlgo did above
00506       // ........ we should NOT fill the PFCandidate-vector with the electrons above (***)
00507       
00508       // Here we need to add all the photon cands to the pfCandidate list
00509       unsigned int extracand =0;
00510       PFCandidateCollection::const_iterator cand = pfPhotonCandidates_->begin();      
00511       for( ; cand != pfPhotonCandidates_->end(); ++cand, ++extracand) {
00512         pfCandidates_->push_back(*cand);
00513         pfPhotonExtra_.push_back(pfPhotonExtraCand[extracand]);
00514       }
00515       
00516     } // end of 'if' in case photons are found    
00517     pfPhotonExtraCand.clear();
00518     pfPhotonCandidates_->clear();
00519   } // end of Photon algo
00520   
00521   //Lock extra conversion tracks not used by Photon Algo
00522   if (usePFConversions_  )
00523     {
00524       for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00525         PFBlockElement::Type type = elements[iEle].type();
00526         if(type==PFBlockElement::TRACK)
00527           {
00528             if(elements[iEle].trackRef()->algo() == 12)
00529               active[iEle]=false;       
00530             if(elements[iEle].trackRef()->quality(reco::TrackBase::highPurity))continue;
00531             const reco::PFBlockElementTrack * trackRef = dynamic_cast<const reco::PFBlockElementTrack*>((&elements[iEle]));
00532             if(!(trackRef->trackType(reco::PFBlockElement::T_FROM_GAMMACONV)))continue;
00533             if(elements[iEle].convRef().isNonnull())active[iEle]=false;
00534           }
00535       }
00536     }
00537   for ( std::vector<reco::PFCandidate>::const_iterator ec=tempElectronCandidates.begin();   ec != tempElectronCandidates.end(); ++ec ){
00538     pfCandidates_->push_back(*ec);  
00539   } 
00540   tempElectronCandidates.clear();
00541   
00542   
00543   if(debug_) 
00544     cout<<endl<<"--------------- loop 1 ------------------"<<endl;
00545 
00546   //COLINFEB16
00547   // In loop 1, we loop on all elements. 
00548 
00549   // The primary goal is to deal with tracks that are:
00550   // - not associated to an HCAL cluster
00551   // - not identified as an electron. 
00552   // Those tracks should be predominantly relatively low energy charged 
00553   // hadrons which are not detected in the ECAL. 
00554 
00555   // The secondary goal is to prepare for the next loops
00556   // - The ecal and hcal elements are sorted in separate vectors
00557   // which will be used as a base for the corresponding loops.
00558   // - For tracks which are connected to more than one HCAL cluster, 
00559   // the links between the track and the cluster are cut for all clusters 
00560   // but the closest one. 
00561   // - HF only blocks ( HFEM, HFHAD, HFEM+HFAD) are identified 
00562 
00563   // obsolete comments? 
00564   // loop1: 
00565   // - sort ecal and hcal elements in separate vectors
00566   // - for tracks:
00567   //       - lock closest ecal cluster 
00568   //       - cut link to farthest hcal cluster, if more than 1.
00569 
00570   // vectors to store indices to ho, hcal and ecal elements 
00571   vector<unsigned> hcalIs;
00572   vector<unsigned> hoIs;
00573   vector<unsigned> ecalIs;
00574   vector<unsigned> trackIs;
00575   vector<unsigned> ps1Is;
00576   vector<unsigned> ps2Is;
00577 
00578   vector<unsigned> hfEmIs;
00579   vector<unsigned> hfHadIs;
00580   
00581 
00582   for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00583     PFBlockElement::Type type = elements[iEle].type();
00584 
00585     if(debug_ && type != PFBlockElement::BREM ) cout<<endl<<elements[iEle];   
00586 
00587     switch( type ) {
00588     case PFBlockElement::TRACK:
00589       if ( active[iEle] ) { 
00590         trackIs.push_back( iEle );
00591         if(debug_) cout<<"TRACK, stored index, continue"<<endl;
00592       }
00593       break;
00594     case PFBlockElement::ECAL: 
00595       if ( active[iEle]  ) { 
00596         ecalIs.push_back( iEle );
00597         if(debug_) cout<<"ECAL, stored index, continue"<<endl;
00598       }
00599       continue;
00600     case PFBlockElement::HCAL:
00601       if ( active[iEle] ) { 
00602         hcalIs.push_back( iEle );
00603         if(debug_) cout<<"HCAL, stored index, continue"<<endl;
00604       }
00605       continue;
00606     case PFBlockElement::HO:
00607       if (useHO_) {
00608         if ( active[iEle] ) { 
00609           hoIs.push_back( iEle );
00610           if(debug_) cout<<"HO, stored index, continue"<<endl;
00611         }
00612       }
00613       continue;
00614     case PFBlockElement::HFEM:
00615       if ( active[iEle] ) { 
00616         hfEmIs.push_back( iEle );
00617         if(debug_) cout<<"HFEM, stored index, continue"<<endl;
00618       }
00619       continue;
00620     case PFBlockElement::HFHAD:
00621       if ( active[iEle] ) { 
00622         hfHadIs.push_back( iEle );
00623         if(debug_) cout<<"HFHAD, stored index, continue"<<endl;
00624       }
00625       continue;
00626 
00627       //COLINFEB16 the following is not used... removing
00628       
00629       //     case PFBlockElement::PS1:
00630       //        if ( active[iEle] ) { 
00631       //         ps1Is.push_back( iEle );
00632       //         if(debug_) cout<<"PS1, stored index, continue"<<endl;
00633       //        }
00634       //        continue;
00635       //     case PFBlockElement::PS2:
00636       //       if ( active[iEle] ) { 
00637       //        ps2Is.push_back( iEle );
00638       //        if(debug_) cout<<"PS2, stored index, continue"<<endl;
00639       //       }
00640       //       continue;
00641     default:
00642       continue;
00643     }
00644 
00645     // we're now dealing with a track
00646     unsigned iTrack = iEle;
00647     reco::MuonRef muonRef = elements[iTrack].muonRef();    
00648 
00649 
00650     if (active[iTrack] && isFromSecInt(elements[iEle], "primary")){
00651       bool isPrimaryTrack = elements[iEle].displacedVertexRef(PFBlockElement::T_TO_DISP)->displacedVertexRef()->isTherePrimaryTracks();
00652       if (isPrimaryTrack) {
00653         if (debug_) cout << "Primary Track reconstructed alone" << endl;
00654         unsigned tmpi = reconstructTrack(elements[iEle]);
00655         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEle );
00656         active[iTrack] = false;
00657       }
00658     }
00659 
00660 
00661     if(debug_) { 
00662       if ( !active[iTrack] ) 
00663         cout << "Already used by electrons, muons, conversions" << endl;
00664     }
00665     
00666     // Track already used as electron, muon, conversion?
00667     // Added a check on the activated element
00668     if ( ! active[iTrack] ) continue;
00669   
00670     reco::TrackRef trackRef = elements[iTrack].trackRef();
00671     assert( !trackRef.isNull() ); 
00672 
00673     if (debug_ ) {
00674       cout <<"PFAlgo:processBlock "<<" "<<trackIs.size()<<" "<<ecalIs.size()<<" "<<hcalIs.size()<<" "<<hoIs.size()<<endl;
00675     }
00676 
00677     // look for associated elements of all types
00678     //COLINFEB16 
00679     // all types of links are considered. 
00680     // the elements are sorted by increasing distance
00681     std::multimap<double, unsigned> ecalElems;
00682     block.associatedElements( iTrack,  linkData,
00683                               ecalElems ,
00684                               reco::PFBlockElement::ECAL,
00685                               reco::PFBlock::LINKTEST_ALL );
00686     
00687     std::multimap<double, unsigned> hcalElems;
00688     block.associatedElements( iTrack,  linkData,
00689                               hcalElems,
00690                               reco::PFBlockElement::HCAL,
00691                               reco::PFBlock::LINKTEST_ALL );
00692 
00693     // When a track has no HCAL cluster linked, but another track is linked to the same
00694     // ECAL cluster and an HCAL cluster, link the track to the HCAL cluster for 
00695     // later analysis
00696     if ( hcalElems.empty() && !ecalElems.empty() ) {
00697       // debug_ = true;
00698       unsigned ntt = 1;
00699       unsigned index = ecalElems.begin()->second;
00700       std::multimap<double, unsigned> sortedTracks;
00701       block.associatedElements( index,  linkData,
00702                                 sortedTracks,
00703                                 reco::PFBlockElement::TRACK,
00704                                 reco::PFBlock::LINKTEST_ALL );
00705       // std::cout << "The ECAL is linked to " << sortedTracks.size() << std::endl;
00706 
00707       // Loop over all tracks
00708       for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00709         unsigned jTrack = ie->second;
00710         // std::cout << "Track " << jTrack << std::endl;
00711         // Track must be active
00712         if ( !active[jTrack] ) continue;
00713         //std::cout << "Active " << std::endl;
00714         
00715         // The loop is on the other tracks !
00716         if ( jTrack == iTrack ) continue;
00717         //std::cout << "A different track ! " << std::endl;
00718         
00719         // Check if the ECAL closest to this track is the current ECAL
00720         // Otherwise ignore this track in the neutral energy determination
00721         std::multimap<double, unsigned> sortedECAL;
00722         block.associatedElements( jTrack,  linkData,
00723                                   sortedECAL,
00724                                   reco::PFBlockElement::ECAL,
00725                                   reco::PFBlock::LINKTEST_ALL );
00726         if ( sortedECAL.begin()->second != index ) continue;
00727         //std::cout << "With closest ECAL identical " << std::endl;
00728 
00729         
00730         // Check if this track is also linked to an HCAL 
00731         std::multimap<double, unsigned> sortedHCAL;
00732         block.associatedElements( jTrack,  linkData,
00733                                   sortedHCAL,
00734                                   reco::PFBlockElement::HCAL,
00735                                   reco::PFBlock::LINKTEST_ALL );
00736         if ( !sortedHCAL.size() ) continue;
00737         //std::cout << "With an HCAL cluster " << sortedHCAL.begin()->first << std::endl;
00738         ntt++;
00739         
00740         // In that case establish a link with the first track 
00741         block.setLink( iTrack, 
00742                        sortedHCAL.begin()->second, 
00743                        sortedECAL.begin()->first, 
00744                        linkData,
00745                        PFBlock::LINKTEST_RECHIT );
00746         
00747       } // End other tracks
00748       
00749       // Redefine HCAL elements 
00750       block.associatedElements( iTrack,  linkData,
00751                                 hcalElems,
00752                                 reco::PFBlockElement::HCAL,
00753                                 reco::PFBlock::LINKTEST_ALL );
00754 
00755       if ( debug_ && hcalElems.size() ) 
00756         std::cout << "Track linked back to HCAL due to ECAL sharing with other tracks" << std::endl;
00757     }
00758     
00759     //MICHELE 
00760     //TEMPORARY SOLUTION FOR ELECTRON REJECTION IN PFTAU
00761     //COLINFEB16 
00762     // in case particle flow electrons are not reconstructed, 
00763     // the mva_e_pi of the charged hadron will be set to 1 
00764     // if a GSF element is associated to the current TRACK element
00765     // This information will be used in the electron rejection for tau ID.
00766     std::multimap<double,unsigned> gsfElems;
00767     if (usePFElectrons_ == false) {
00768       block.associatedElements( iTrack,  linkData,
00769                                 gsfElems ,
00770                                 reco::PFBlockElement::GSF );
00771     }
00772     //
00773 
00774     if(hcalElems.empty() && debug_) {
00775       cout<<"no hcal element connected to track "<<iTrack<<endl;
00776     }
00777 
00778     // will now loop on associated elements ... 
00779     // typedef std::multimap<double, unsigned>::iterator IE;
00780    
00781     bool hcalFound = false;
00782 
00783     if(debug_) 
00784       cout<<"now looping on elements associated to the track"<<endl;
00785     
00786     // ... first on associated ECAL elements
00787     // Check if there is still a free ECAL for this track
00788     for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
00789       
00790       unsigned index = ie->second;
00791       // Sanity checks and optional printout
00792       PFBlockElement::Type type = elements[index].type();
00793       if(debug_) {
00794         double  dist  = ie->first;
00795         cout<<"\telement "<<elements[index]<<" linked with distance = "<< dist <<endl;
00796         if ( ! active[index] ) cout << "This ECAL is already used - skip it" << endl;      
00797       }
00798       assert( type == PFBlockElement::ECAL );
00799 
00800       // This ECAL is not free (taken by an electron?) - just skip it
00801       if ( ! active[index] ) continue;      
00802 
00803       // Flag ECAL clusters for which the corresponding track is not linked to an HCAL cluster
00804 
00805       //reco::PFClusterRef clusterRef = elements[index].clusterRef();
00806       //assert( !clusterRef.isNull() );
00807       if( !hcalElems.empty() && debug_)
00808         cout<<"\t\tat least one hcal element connected to the track."
00809             <<" Sparing Ecal cluster for the hcal loop"<<endl; 
00810 
00811     } //loop print ecal elements
00812 
00813   
00814     // tracks which are not linked to an HCAL 
00815     // are reconstructed now. 
00816 
00817     if( hcalElems.empty() ) {
00818       
00819       if ( debug_ ) 
00820         std::cout << "Now deals with tracks linked to no HCAL clusters" << std::endl; 
00821       // vector<unsigned> elementIndices;
00822       // elementIndices.push_back(iTrack); 
00823 
00824       // The track momentum
00825       double trackMomentum = elements[iTrack].trackRef()->p();      
00826       if ( debug_ ) 
00827         std::cout << elements[iTrack] << std::endl; 
00828       
00829       // Is it a "tight" muon ?
00830       bool thisIsAMuon = PFMuonAlgo::isMuon(elements[iTrack]);
00831       if ( thisIsAMuon ) trackMomentum = 0.;
00832 
00833       // Is it a fake track ?
00834       bool rejectFake = false;
00835       if ( !thisIsAMuon  && elements[iTrack].trackRef()->ptError() > ptError_ ) { 
00836 
00837         double deficit = trackMomentum; 
00838         double resol = neutralHadronEnergyResolution(trackMomentum,
00839                                                      elements[iTrack].trackRef()->eta());
00840         resol *= trackMomentum;
00841 
00842         if ( !ecalElems.empty() ) { 
00843           unsigned thisEcal = ecalElems.begin()->second;
00844           reco::PFClusterRef clusterRef = elements[thisEcal].clusterRef();
00845           deficit -= clusterRef->energy();
00846           resol = neutralHadronEnergyResolution(trackMomentum,
00847                                                 clusterRef->positionREP().Eta());
00848           resol *= trackMomentum;
00849         }
00850 
00851         bool isPrimary = isFromSecInt(elements[iTrack], "primary");
00852 
00853         if ( deficit > nSigmaTRACK_*resol && !isPrimary) { 
00854           rejectFake = true;
00855           active[iTrack] = false;
00856           if ( debug_ )  
00857             std::cout << elements[iTrack] << std::endl
00858                       << "is probably a fake (1) --> lock the track" 
00859                       << std::endl;
00860         }
00861       }
00862 
00863       if ( rejectFake ) continue;
00864 
00865       // Create a track candidate       
00866       // unsigned tmpi = reconstructTrack( elements[iTrack] );
00867       //active[iTrack] = false;
00868       std::vector<unsigned> tmpi;
00869       std::vector<unsigned> kTrack;
00870       
00871       // Some cleaning : secondary tracks without calo's and large momentum must be fake
00872       double Dpt = trackRef->ptError();
00873 
00874       if ( rejectTracks_Step45_ && ecalElems.empty() && 
00875            trackMomentum > 30. && Dpt > 0.5 && 
00876            ( trackRef->algo() == TrackBase::iter4 || 
00877              trackRef->algo() == TrackBase::iter5 || 
00878              trackRef->algo() == TrackBase::iter6 ) ) {
00879 
00880         //
00881         double dptRel = Dpt/trackRef->pt()*100;
00882         bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
00883 
00884         if ( isPrimaryOrSecondary && dptRel < dptRel_DispVtx_) continue;
00885         unsigned nHits =  elements[iTrack].trackRef()->hitPattern().trackerLayersWithMeasurement();
00886         unsigned int NLostHit = trackRef->hitPattern().trackerLayersWithoutMeasurement();
00887 
00888         if ( debug_ ) 
00889           std::cout << "A track (algo = " << trackRef->algo() << ") with momentum " << trackMomentum 
00890                     << " / " << elements[iTrack].trackRef()->pt() << " +/- " << Dpt 
00891                     << " / " << elements[iTrack].trackRef()->eta() 
00892                     << " without any link to ECAL/HCAL and with " << nHits << " (" << NLostHit 
00893                     << ") hits (lost hits) has been cleaned" << std::endl;
00894         active[iTrack] = false;
00895         continue;
00896       }
00897 
00898 
00899       tmpi.push_back(reconstructTrack( elements[iTrack]));
00900       kTrack.push_back(iTrack);
00901       active[iTrack] = false;
00902 
00903       // No ECAL cluster either ... continue...
00904       if ( ecalElems.empty() ) { 
00905         (*pfCandidates_)[tmpi[0]].setEcalEnergy( 0., 0. );
00906         (*pfCandidates_)[tmpi[0]].setHcalEnergy( 0., 0. );
00907         (*pfCandidates_)[tmpi[0]].setHoEnergy( 0., 0. );
00908         (*pfCandidates_)[tmpi[0]].setPs1Energy( 0 );
00909         (*pfCandidates_)[tmpi[0]].setPs2Energy( 0 );
00910         (*pfCandidates_)[tmpi[0]].addElementInBlock( blockref, kTrack[0] );
00911         continue;
00912       }
00913           
00914       // Look for closest ECAL cluster
00915       unsigned thisEcal = ecalElems.begin()->second;
00916       reco::PFClusterRef clusterRef = elements[thisEcal].clusterRef();
00917       if ( debug_ ) std::cout << " is associated to " << elements[thisEcal] << std::endl;
00918 
00919       // Set ECAL energy for muons
00920       if ( thisIsAMuon ) { 
00921         (*pfCandidates_)[tmpi[0]].setEcalEnergy( clusterRef->energy(),
00922                                                  std::min(clusterRef->energy(), muonECAL_[0]) );
00923         (*pfCandidates_)[tmpi[0]].setHcalEnergy( 0., 0. );
00924         (*pfCandidates_)[tmpi[0]].setHoEnergy( 0., 0. );
00925         (*pfCandidates_)[tmpi[0]].setPs1Energy( 0 );
00926         (*pfCandidates_)[tmpi[0]].setPs2Energy( 0 );
00927         (*pfCandidates_)[tmpi[0]].addElementInBlock( blockref, kTrack[0] );
00928       }
00929       
00930       double slopeEcal = 1.;
00931       bool connectedToEcal = false;
00932       unsigned iEcal = 99999;
00933       double calibEcal = 0.;
00934       double calibHcal = 0.;
00935       double totalEcal = thisIsAMuon ? -muonECAL_[0] : 0.;
00936 
00937       // Consider charged particles closest to the same ECAL cluster
00938       std::multimap<double, unsigned> sortedTracks;
00939       block.associatedElements( thisEcal,  linkData,
00940                                 sortedTracks,
00941                                 reco::PFBlockElement::TRACK,
00942                                 reco::PFBlock::LINKTEST_ALL );
00943     
00944       for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00945         unsigned jTrack = ie->second;
00946 
00947         // Don't consider already used tracks
00948         if ( !active[jTrack] ) continue;
00949 
00950         // The loop is on the other tracks !
00951         if ( jTrack == iTrack ) continue;
00952         
00953         // Check if the ECAL cluster closest to this track is 
00954         // indeed the current ECAL cluster. Only tracks not 
00955         // linked to an HCAL cluster are considered here
00956         std::multimap<double, unsigned> sortedECAL;
00957         block.associatedElements( jTrack,  linkData,
00958                                   sortedECAL,
00959                                   reco::PFBlockElement::ECAL,
00960                                   reco::PFBlock::LINKTEST_ALL );
00961         if ( sortedECAL.begin()->second != thisEcal ) continue;
00962 
00963         // Check if this track is a muon
00964         bool thatIsAMuon = PFMuonAlgo::isMuon(elements[jTrack]);
00965 
00966         // Check if this track is not a fake
00967         bool rejectFake = false;
00968         reco::TrackRef trackRef = elements[jTrack].trackRef();
00969         if ( !thatIsAMuon && trackRef->ptError() > ptError_) { 
00970           double deficit = trackMomentum + trackRef->p() - clusterRef->energy();
00971           double resol = nSigmaTRACK_*neutralHadronEnergyResolution(trackMomentum+trackRef->p(),
00972                                                                     clusterRef->positionREP().Eta());
00973           resol *= (trackMomentum+trackRef->p());
00974           if ( deficit > nSigmaTRACK_*resol ) { 
00975             rejectFake = true;
00976             kTrack.push_back(jTrack);
00977             active[jTrack] = false;
00978             if ( debug_ )  
00979               std::cout << elements[jTrack] << std::endl
00980                         << "is probably a fake (2) --> lock the track" 
00981                         << std::endl; 
00982           }
00983         }
00984         if ( rejectFake ) continue;
00985         
00986         
00987         // Otherwise, add this track momentum to the total track momentum
00988         /* */
00989         // reco::TrackRef trackRef = elements[jTrack].trackRef();
00990         if ( !thatIsAMuon ) {   
00991           if ( debug_ ) 
00992             std::cout << "Track momentum increased from " << trackMomentum << " GeV "; 
00993           trackMomentum += trackRef->p();
00994           if ( debug_ ) {
00995             std::cout << "to " << trackMomentum << " GeV." << std::endl; 
00996             std::cout << "with " << elements[jTrack] << std::endl;
00997           }
00998         } else { 
00999           totalEcal -= muonECAL_[0];
01000           totalEcal = std::max(totalEcal, 0.);
01001         }
01002 
01003         // And create a charged particle candidate !
01004         tmpi.push_back(reconstructTrack( elements[jTrack] ));
01005         kTrack.push_back(jTrack);
01006         active[jTrack] = false;
01007 
01008         if ( thatIsAMuon ) { 
01009           (*pfCandidates_)[tmpi.back()].setEcalEnergy(clusterRef->energy(),
01010                                                       std::min(clusterRef->energy(),muonECAL_[0]));
01011           (*pfCandidates_)[tmpi.back()].setHcalEnergy( 0., 0. );
01012           (*pfCandidates_)[tmpi.back()].setHoEnergy( 0., 0. );
01013           (*pfCandidates_)[tmpi.back()].setPs1Energy( 0 );
01014           (*pfCandidates_)[tmpi.back()].setPs2Energy( 0 );
01015           (*pfCandidates_)[tmpi.back()].addElementInBlock( blockref, kTrack.back() );
01016         }
01017       }
01018 
01019 
01020       if ( debug_ ) std::cout << "Loop over all associated ECAL clusters" << std::endl; 
01021       // Loop over all ECAL linked clusters ordered by increasing distance.
01022       for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
01023         
01024         unsigned index = ie->second;
01025         PFBlockElement::Type type = elements[index].type();
01026         assert( type == PFBlockElement::ECAL );
01027         if ( debug_ ) std::cout << elements[index] << std::endl;
01028         
01029         // Just skip clusters already taken
01030         if ( debug_ && ! active[index] ) std::cout << "is not active  - ignore " << std::endl;
01031         if ( ! active[index] ) continue;
01032 
01033         // Just skip this cluster if it's closer to another track
01034         /* */
01035         block.associatedElements( index,  linkData,
01036                                   sortedTracks,
01037                                   reco::PFBlockElement::TRACK,
01038                                   reco::PFBlock::LINKTEST_ALL );
01039         bool skip = true;
01040         for (unsigned ic=0; ic<kTrack.size();++ic) {
01041           if ( sortedTracks.begin()->second == kTrack[ic] ) { 
01042             skip = false;
01043             break;
01044           }
01045         }
01046         if ( debug_ && skip ) std::cout << "is closer to another track - ignore " << std::endl;
01047         if ( skip ) continue;
01048         /* */
01049                 
01050         // The corresponding PFCluster and energy
01051         reco::PFClusterRef clusterRef = elements[index].clusterRef();
01052         assert( !clusterRef.isNull() );
01053 
01054         if ( debug_ ) {
01055           double dist = ie->first;
01056           std::cout <<"Ecal cluster with raw energy = " << clusterRef->energy() 
01057                     <<" linked with distance = " << dist << std::endl;
01058         }
01059         /*
01060         double dist = ie->first;
01061         if ( !connectedToEcal && dist > 0.1 ) {
01062           std::cout << "Warning - first ECAL cluster at a distance of " << dist << "from the closest track!" << std::endl;
01063           cout<<"\telement "<<elements[index]<<" linked with distance = "<< dist <<endl;
01064           cout<<"\telement "<<elements[iTrack]<<" linked with distance = "<< dist <<endl;
01065         }
01066         */ 
01067 
01068         // Check the presence of preshower clusters in the vicinity
01069         // Preshower cluster closer to another ECAL cluster are ignored.
01070         vector<double> ps1Ene(1,static_cast<double>(0.));
01071         associatePSClusters(index, reco::PFBlockElement::PS1, block, elements, linkData, active, ps1Ene);
01072         vector<double> ps2Ene(1,static_cast<double>(0.));
01073         associatePSClusters(index, reco::PFBlockElement::PS2, block, elements, linkData, active, ps2Ene);
01074         
01075         // Get the energy calibrated (for photons)
01076         bool crackCorrection = false;
01077         double ecalEnergy = calibration_->energyEm(*clusterRef,ps1Ene,ps2Ene,crackCorrection);
01078         if ( debug_ )
01079           std::cout << "Corrected ECAL(+PS) energy = " << ecalEnergy << std::endl;
01080 
01081         // Since the electrons were found beforehand, this track must be a hadron. Calibrate 
01082         // the energy under the hadron hypothesis.
01083         totalEcal += ecalEnergy;
01084         double previousCalibEcal = calibEcal;
01085         double previousSlopeEcal = slopeEcal;
01086         calibEcal = std::max(totalEcal,0.);
01087         calibHcal = 0.;
01088         calibration_->energyEmHad(trackMomentum,calibEcal,calibHcal,
01089                                   clusterRef->positionREP().Eta(),
01090                                   clusterRef->positionREP().Phi());
01091         if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
01092 
01093         if ( debug_ )
01094           std::cout << "The total calibrated energy so far amounts to = " << calibEcal << std::endl;
01095         
01096 
01097         // Stop the loop when adding more ECAL clusters ruins the compatibility
01098         if ( connectedToEcal && calibEcal - trackMomentum >= 0. ) {
01099         // if ( connectedToEcal && calibEcal - trackMomentum >=
01100         //     nSigmaECAL_*neutralHadronEnergyResolution(trackMomentum,clusterRef->positionREP().Eta())  ) { 
01101           calibEcal = previousCalibEcal;
01102           slopeEcal = previousSlopeEcal;
01103           totalEcal = calibEcal/slopeEcal;
01104 
01105           // Turn this last cluster in a photon 
01106           // (The PS clusters are already locked in "associatePSClusters")
01107           active[index] = false;
01108 
01109           // Find the associated tracks
01110           std::multimap<double, unsigned> assTracks;
01111           block.associatedElements( index,  linkData,
01112                                     assTracks,
01113                                     reco::PFBlockElement::TRACK,
01114                                     reco::PFBlock::LINKTEST_ALL );
01115 
01116 
01117           unsigned tmpe = reconstructCluster( *clusterRef, ecalEnergy ); 
01118           (*pfCandidates_)[tmpe].setEcalEnergy( clusterRef->energy(), ecalEnergy );
01119           (*pfCandidates_)[tmpe].setHcalEnergy( 0., 0. );
01120           (*pfCandidates_)[tmpe].setHoEnergy( 0., 0. );
01121           (*pfCandidates_)[tmpe].setPs1Energy( ps1Ene[0] );
01122           (*pfCandidates_)[tmpe].setPs2Energy( ps2Ene[0] );
01123           (*pfCandidates_)[tmpe].addElementInBlock( blockref, index );
01124           // Check that there is at least one track
01125           if(assTracks.size()) {
01126             (*pfCandidates_)[tmpe].addElementInBlock( blockref, assTracks.begin()->second );
01127             
01128             // Assign the position of the track at the ECAL entrance
01129             const math::XYZPointF& chargedPosition = 
01130               dynamic_cast<const reco::PFBlockElementTrack*>(&elements[assTracks.begin()->second])->positionAtECALEntrance();
01131             (*pfCandidates_)[tmpe].setPositionAtECALEntrance(chargedPosition);
01132           }
01133           break;
01134         }
01135 
01136         // Lock used clusters.
01137         connectedToEcal = true;
01138         iEcal = index;
01139         active[index] = false;
01140         for (unsigned ic=0; ic<tmpi.size();++ic)  
01141           (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, iEcal ); 
01142 
01143 
01144       } // Loop ecal elements
01145     
01146       bool bNeutralProduced = false;
01147   
01148       // Create a photon if the ecal energy is too large
01149       if( connectedToEcal ) {
01150         reco::PFClusterRef pivotalRef = elements[iEcal].clusterRef();
01151 
01152         double neutralEnergy = calibEcal - trackMomentum;
01153 
01154         /*
01155         // Check if there are other tracks linked to that ECAL
01156         for(IE ie = sortedTracks.begin(); ie != sortedTracks.end() && neutralEnergy > 0; ++ie ) {
01157           unsigned jTrack = ie->second;
01158           
01159           // The loop is on the other tracks !
01160           if ( jTrack == iTrack ) continue;
01161 
01162           // Check if the ECAL closest to this track is the current ECAL
01163           // Otherwise ignore this track in the neutral energy determination
01164           std::multimap<double, unsigned> sortedECAL;
01165           block.associatedElements( jTrack,  linkData,
01166                                     sortedECAL,
01167                                     reco::PFBlockElement::ECAL,
01168                                     reco::PFBlock::LINKTEST_ALL );
01169           if ( sortedECAL.begin()->second != iEcal ) continue;
01170           
01171           // Check if this track is also linked to an HCAL 
01172           // (in which case it goes to the next loop and is ignored here)
01173           std::multimap<double, unsigned> sortedHCAL;
01174           block.associatedElements( jTrack,  linkData,
01175                                     sortedHCAL,
01176                                     reco::PFBlockElement::HCAL,
01177                                     reco::PFBlock::LINKTEST_ALL );
01178           if ( sortedHCAL.size() ) continue;
01179           
01180           // Otherwise, subtract this track momentum from the ECAL energy 
01181           reco::TrackRef trackRef = elements[jTrack].trackRef();
01182           neutralEnergy -= trackRef->p();
01183 
01184         } // End other tracks
01185         */
01186         
01187         // Add a photon is the energy excess is large enough
01188         double resol = neutralHadronEnergyResolution(trackMomentum,pivotalRef->positionREP().Eta());
01189         resol *= trackMomentum;
01190         if ( neutralEnergy > std::max(0.5,nSigmaECAL_*resol) ) {
01191           neutralEnergy /= slopeEcal;
01192           unsigned tmpj = reconstructCluster( *pivotalRef, neutralEnergy ); 
01193           (*pfCandidates_)[tmpj].setEcalEnergy( pivotalRef->energy(), neutralEnergy );
01194           (*pfCandidates_)[tmpj].setHcalEnergy( 0., 0. );
01195           (*pfCandidates_)[tmpj].setHoEnergy( 0., 0. );
01196           (*pfCandidates_)[tmpj].setPs1Energy( 0. );
01197           (*pfCandidates_)[tmpj].setPs2Energy( 0. );
01198           (*pfCandidates_)[tmpj].addElementInBlock(blockref, iEcal);
01199           bNeutralProduced = true;
01200           for (unsigned ic=0; ic<kTrack.size();++ic) 
01201             (*pfCandidates_)[tmpj].addElementInBlock( blockref, kTrack[ic] ); 
01202         } // End neutral energy
01203 
01204         // Set elements in blocks and ECAL energies to all tracks
01205         for (unsigned ic=0; ic<tmpi.size();++ic) { 
01206           
01207           // Skip muons
01208           if ( (*pfCandidates_)[tmpi[ic]].particleId() == reco::PFCandidate::mu ) continue; 
01209 
01210           double fraction = (*pfCandidates_)[tmpi[ic]].trackRef()->p()/trackMomentum;
01211           double ecalCal = bNeutralProduced ? 
01212             (calibEcal-neutralEnergy*slopeEcal)*fraction : calibEcal*fraction;
01213           double ecalRaw = totalEcal*fraction;
01214 
01215           if (debug_) cout << "The fraction after photon supression is " << fraction << " calibrated ecal = " << ecalCal << endl;
01216 
01217           (*pfCandidates_)[tmpi[ic]].setEcalEnergy( ecalRaw, ecalCal );
01218           (*pfCandidates_)[tmpi[ic]].setHcalEnergy( 0., 0. );
01219           (*pfCandidates_)[tmpi[ic]].setHoEnergy( 0., 0. );
01220           (*pfCandidates_)[tmpi[ic]].setPs1Energy( 0 );
01221           (*pfCandidates_)[tmpi[ic]].setPs2Energy( 0 );
01222           (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, kTrack[ic] );
01223         }
01224 
01225       } // End connected ECAL
01226 
01227       // Fill the element_in_block for tracks that are eventually linked to no ECAL clusters at all.
01228       for (unsigned ic=0; ic<tmpi.size();++ic) { 
01229         const PFCandidate& pfc = (*pfCandidates_)[tmpi[ic]];
01230         const PFCandidate::ElementsInBlocks& eleInBlocks = pfc.elementsInBlocks();
01231         if ( eleInBlocks.size() == 0 ) { 
01232           if ( debug_ )std::cout << "Single track / Fill element in block! " << std::endl;
01233           (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, kTrack[ic] );
01234         }
01235       }
01236 
01237     }
01238 
01239 
01240     // In case several HCAL elements are linked to this track, 
01241     // unlinking all of them except the closest. 
01242     for(IE ie = hcalElems.begin(); ie != hcalElems.end(); ++ie ) {
01243       
01244       unsigned index = ie->second;
01245       
01246       PFBlockElement::Type type = elements[index].type();
01247 
01248       if(debug_) {
01249         double dist = block.dist(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
01250         cout<<"\telement "<<elements[index]<<" linked with distance "<< dist <<endl;
01251       }
01252 
01253       assert( type == PFBlockElement::HCAL );
01254       
01255       // all hcal clusters except the closest 
01256       // will be unlinked from the track
01257       if( !hcalFound ) { // closest hcal
01258         if(debug_) 
01259           cout<<"\t\tclosest hcal cluster, doing nothing"<<endl;
01260         
01261         hcalFound = true;
01262         
01263         // active[index] = false;
01264         // hcalUsed.push_back( index );
01265       }
01266       else { // other associated hcal
01267         // unlink from the track
01268         if(debug_) 
01269           cout<<"\t\tsecondary hcal cluster. unlinking"<<endl;
01270         block.setLink( iTrack, index, -1., linkData,
01271                        PFBlock::LINKTEST_RECHIT );
01272       }
01273     } //loop hcal elements   
01274   } // end of loop 1 on elements iEle of any type
01275 
01276 
01277 
01278   // deal with HF. 
01279   if( !(hfEmIs.empty() &&  hfHadIs.empty() ) ) {
01280     // there is at least one HF element in this block. 
01281     // so all elements must be HF.
01282     assert( hfEmIs.size() + hfHadIs.size() == elements.size() );
01283 
01284     if( elements.size() == 1 ) {
01285       //Auguste: HAD-only calibration here
01286       reco::PFClusterRef clusterRef = elements[0].clusterRef();
01287       double energyHF = 0.;
01288       double uncalibratedenergyHF = 0.;
01289       unsigned tmpi = 0;
01290       switch( clusterRef->layer() ) {
01291       case PFLayer::HF_EM:
01292         // do EM-only calibration here
01293         energyHF = clusterRef->energy();
01294         uncalibratedenergyHF = energyHF;
01295         if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
01296           energyHF = thepfEnergyCalibrationHF_->energyEm(uncalibratedenergyHF,
01297                                                          clusterRef->positionREP().Eta(),
01298                                                          clusterRef->positionREP().Phi()); 
01299         }
01300         tmpi = reconstructCluster( *clusterRef, energyHF );     
01301         (*pfCandidates_)[tmpi].setEcalEnergy( uncalibratedenergyHF, energyHF );
01302         (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0.);
01303         (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
01304         (*pfCandidates_)[tmpi].setPs1Energy( 0. );
01305         (*pfCandidates_)[tmpi].setPs2Energy( 0. );
01306         (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfEmIs[0] );
01307         //std::cout << "HF EM alone ! " << energyHF << std::endl;
01308         break;
01309       case PFLayer::HF_HAD:
01310         // do HAD-only calibration here
01311         energyHF = clusterRef->energy();
01312         uncalibratedenergyHF = energyHF;
01313         if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
01314           energyHF = thepfEnergyCalibrationHF_->energyHad(uncalibratedenergyHF,
01315                                                          clusterRef->positionREP().Eta(),
01316                                                          clusterRef->positionREP().Phi()); 
01317         }
01318         tmpi = reconstructCluster( *clusterRef, energyHF );     
01319         (*pfCandidates_)[tmpi].setHcalEnergy( uncalibratedenergyHF, energyHF );
01320         (*pfCandidates_)[tmpi].setEcalEnergy( 0., 0.);
01321         (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
01322         (*pfCandidates_)[tmpi].setPs1Energy( 0. );
01323         (*pfCandidates_)[tmpi].setPs2Energy( 0. );
01324         (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfHadIs[0] );
01325         //std::cout << "HF Had alone ! " << energyHF << std::endl;
01326         break;
01327       default:
01328         assert(0);
01329       }
01330     }
01331     else if(  elements.size() == 2 ) {
01332       //Auguste: EM + HAD calibration here
01333       reco::PFClusterRef c0 = elements[0].clusterRef();
01334       reco::PFClusterRef c1 = elements[1].clusterRef();
01335       // 2 HF elements. Must be in each layer.
01336       reco::PFClusterRef cem = c1;
01337       reco::PFClusterRef chad = c0;
01338       
01339       if( c0->layer()== PFLayer::HF_EM ) {
01340         if ( c1->layer()== PFLayer::HF_HAD ) {
01341           cem = c0; chad = c1;
01342         } else { 
01343           assert(0);
01344         }
01345         // do EM+HAD calibration here
01346         double energyHfEm = cem->energy();
01347         double energyHfHad = chad->energy();
01348         double uncalibratedenergyHFEm = energyHfEm;
01349         double uncalibratedenergyHFHad = energyHfHad;
01350         if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
01351 
01352           energyHfEm = thepfEnergyCalibrationHF_->energyEmHad(uncalibratedenergyHFEm,
01353                                                              0.0,
01354                                                              c0->positionREP().Eta(),
01355                                                              c0->positionREP().Phi()); 
01356           energyHfHad = thepfEnergyCalibrationHF_->energyEmHad(0.0,
01357                                                               uncalibratedenergyHFHad,
01358                                                               c1->positionREP().Eta(),
01359                                                               c1->positionREP().Phi()); 
01360         }
01361         unsigned tmpi = reconstructCluster( *chad, energyHfEm+energyHfHad );     
01362         (*pfCandidates_)[tmpi].setEcalEnergy( uncalibratedenergyHFEm, energyHfEm );
01363         (*pfCandidates_)[tmpi].setHcalEnergy( uncalibratedenergyHFHad, energyHfHad);
01364         (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
01365         (*pfCandidates_)[tmpi].setPs1Energy( 0. );
01366         (*pfCandidates_)[tmpi].setPs2Energy( 0. );
01367         (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfEmIs[0] );
01368         (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfHadIs[0] );
01369         //std::cout << "HF EM+HAD found ! " << energyHfEm << " " << energyHfHad << std::endl;
01370 
01371       }
01372       else {
01373         cerr<<"Warning: 2 elements, but not 1 HFEM and 1 HFHAD"<<endl;
01374         cerr<<block<<endl;
01375 //      assert( c1->layer()== PFLayer::HF_EM &&
01376 //              c0->layer()== PFLayer::HF_HAD );
01377       }      
01378     }
01379     else {
01380       // 1 HF element in the block, 
01381       // but number of elements not equal to 1 or 2 
01382       cerr<<"Warning: HF, but n elem different from 1 or 2"<<endl;
01383       cerr<<block<<endl;
01384 //       assert(0);
01385 //       cerr<<"not ready for navigation in the HF!"<<endl;
01386     }
01387   }
01388 
01389 
01390 
01391   if(debug_) { 
01392     cout<<endl;
01393     cout<<endl<<"--------------- loop hcal ---------------------"<<endl;
01394   }
01395   
01396   // track information:
01397   // trackRef
01398   // ecal energy
01399   // hcal energy
01400   // rescale 
01401 
01402   for(unsigned i=0; i<hcalIs.size(); i++) {
01403     
01404     unsigned iHcal= hcalIs[i];    
01405     PFBlockElement::Type type = elements[iHcal].type();
01406 
01407     assert( type == PFBlockElement::HCAL );
01408 
01409     if(debug_) cout<<endl<<elements[iHcal]<<endl;
01410 
01411     // vector<unsigned> elementIndices;
01412     // elementIndices.push_back(iHcal);
01413 
01414     // associated tracks
01415     std::multimap<double, unsigned> sortedTracks;
01416     block.associatedElements( iHcal,  linkData,
01417                               sortedTracks,
01418                               reco::PFBlockElement::TRACK,
01419                               reco::PFBlock::LINKTEST_ALL );
01420 
01421     std::multimap< unsigned, std::pair<double, unsigned> > associatedEcals;
01422 
01423     std::map< unsigned, std::pair<double, double> > associatedPSs;
01424  
01425     std::multimap<double, std::pair<unsigned,bool> > associatedTracks;
01426     
01427     // A temporary maps for ECAL satellite clusters
01428     std::multimap<double,std::pair<unsigned,math::XYZVector> > ecalSatellites;
01429     std::pair<unsigned,math::XYZVector> fakeSatellite = make_pair(iHcal,math::XYZVector(0.,0.,0.));
01430     ecalSatellites.insert( make_pair(-1., fakeSatellite) );
01431 
01432     std::multimap< unsigned, std::pair<double, unsigned> > associatedHOs;
01433     
01434     PFClusterRef hclusterref = elements[iHcal].clusterRef();
01435     assert(!hclusterref.isNull() );
01436 
01437 
01438     //if there is no track attached to that HCAL, then do not
01439     //reconstruct an HCAL alone, check if it can be recovered 
01440     //first
01441     
01442     // if no associated tracks, create a neutral hadron
01443     //if(sortedTracks.empty() ) {
01444 
01445     if( sortedTracks.empty() ) {
01446       if(debug_) 
01447         cout<<"\tno associated tracks, keep for later"<<endl;
01448       continue;
01449     }
01450 
01451     // Lock the HCAL cluster
01452     active[iHcal] = false;
01453 
01454 
01455     // in the following, tracks are associated to this hcal cluster.
01456     // will look for an excess of energy in the calorimeters w/r to 
01457     // the charged energy, and turn this excess into a neutral hadron or 
01458     // a photon.
01459 
01460     if(debug_) cout<<"\t"<<sortedTracks.size()<<" associated tracks:"<<endl;
01461 
01462     double totalChargedMomentum = 0;
01463     double sumpError2 = 0.;
01464     double totalHO = 0.;
01465     double totalEcal = 0.;
01466     double totalHcal = hclusterref->energy();
01467     vector<double> hcalP;
01468     vector<double> hcalDP;
01469     vector<unsigned> tkIs;
01470     double maxDPovP = -9999.;
01471     
01472     //Keep track of how much energy is assigned to calorimeter-vs-track energy/momentum excess
01473     vector< unsigned > chargedHadronsIndices;
01474     vector< unsigned > chargedHadronsInBlock;
01475     double mergedNeutralHadronEnergy = 0;
01476     double mergedPhotonEnergy = 0;
01477     double muonHCALEnergy = 0.;
01478     double muonECALEnergy = 0.;
01479     double muonHCALError = 0.;
01480     double muonECALError = 0.;
01481     unsigned nMuons = 0; 
01482 
01483 
01484     math::XYZVector photonAtECAL(0.,0.,0.);
01485     math::XYZVector hadronDirection(hclusterref->position().X(),
01486                                     hclusterref->position().Y(),
01487                                     hclusterref->position().Z());
01488     hadronDirection = hadronDirection.Unit();
01489     math::XYZVector hadronAtECAL = totalHcal * hadronDirection;
01490 
01491     // Loop over all tracks associated to this HCAL cluster
01492     for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
01493 
01494       unsigned iTrack = ie->second;
01495 
01496       // Check the track has not already been used (e.g., in electrons, conversions...)
01497       if ( !active[iTrack] ) continue;
01498       // Sanity check 1
01499       PFBlockElement::Type type = elements[iTrack].type();
01500       assert( type == reco::PFBlockElement::TRACK );
01501       // Sanity check 2
01502       reco::TrackRef trackRef = elements[iTrack].trackRef();
01503       assert( !trackRef.isNull() ); 
01504 
01505       // The direction at ECAL entrance
01506       const math::XYZPointF& chargedPosition = 
01507         dynamic_cast<const reco::PFBlockElementTrack*>(&elements[iTrack])->positionAtECALEntrance();
01508       math::XYZVector chargedDirection(chargedPosition.X(),chargedPosition.Y(),chargedPosition.Z());
01509       chargedDirection = chargedDirection.Unit();
01510 
01511       // look for ECAL elements associated to iTrack (associated to iHcal)
01512       std::multimap<double, unsigned> sortedEcals;
01513       block.associatedElements( iTrack,  linkData,
01514                                 sortedEcals,
01515                                 reco::PFBlockElement::ECAL,
01516                                 reco::PFBlock::LINKTEST_ALL );
01517 
01518       if(debug_) cout<<"\t\t\tnumber of Ecal elements linked to this track: "
01519                      <<sortedEcals.size()<<endl;     
01520 
01521       // look for HO elements associated to iTrack (associated to iHcal)
01522       std::multimap<double, unsigned> sortedHOs;
01523       if (useHO_) {
01524         block.associatedElements( iTrack,  linkData,
01525                                   sortedHOs,
01526                                   reco::PFBlockElement::HO,
01527                                   reco::PFBlock::LINKTEST_ALL );
01528 
01529       }
01530       if(debug_) 
01531         cout<<"PFAlgo : number of HO elements linked to this track: "
01532             <<sortedHOs.size()<<endl;
01533       
01534       // Create a PF Candidate right away if the track is a tight muon
01535       reco::MuonRef muonRef = elements[iTrack].muonRef();
01536       bool thisIsAMuon = PFMuonAlgo::isMuon(elements[iTrack]);
01537       bool thisIsAnIsolatedMuon = PFMuonAlgo::isIsolatedMuon(elements[iTrack]);
01538       bool thisIsALooseMuon = false;
01539 
01540       if(!thisIsAMuon ) {
01541         thisIsALooseMuon = PFMuonAlgo::isLooseMuon(elements[iTrack]);
01542       }
01543       if ( thisIsAMuon ) {
01544         if ( debug_ ) { 
01545           std::cout << "\t\tThis track is identified as a muon - remove it from the stack" << std::endl;
01546           std::cout << "\t\t" << elements[iTrack] << std::endl;
01547         }
01548 
01549         // Create a muon.
01550         unsigned tmpi = reconstructTrack( elements[iTrack] );
01551         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
01552         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
01553         double muonHcal = std::min(muonHCAL_[0]+muonHCAL_[1],totalHcal);
01554 
01555         // if muon is isolated and muon momentum exceeds the calo energy, absorb the calo energy        
01556         // rationale : there has been a EM showering by the muon in the calorimeter - or the coil -
01557         // and we don't want to double count the energy 
01558         bool letMuonEatCaloEnergy = false;
01559 
01560         if(thisIsAnIsolatedMuon){
01561           // The factor 1.3 is the e/pi factor in HCAL...
01562           double totalCaloEnergy = totalHcal / 1.30;
01563           unsigned iEcal = 0;
01564           if( !sortedEcals.empty() ) { 
01565             iEcal = sortedEcals.begin()->second; 
01566             PFClusterRef eclusterref = elements[iEcal].clusterRef();
01567             totalCaloEnergy += eclusterref->energy();
01568           }
01569 
01570           if (useHO_) {
01571             // The factor 1.3 is assumed to be the e/pi factor in HO, too.
01572             unsigned iHO = 0;
01573             if( !sortedHOs.empty() ) { 
01574               iHO = sortedHOs.begin()->second; 
01575               PFClusterRef eclusterref = elements[iHO].clusterRef();
01576               totalCaloEnergy += eclusterref->energy() / 1.30;
01577             }
01578           }
01579 
01580           // std::cout << "muon p / total calo = " << muonRef->p() << " "  << (pfCandidates_->back()).p() << " " << totalCaloEnergy << std::endl;
01581           //if(muonRef->p() > totalCaloEnergy ) letMuonEatCaloEnergy = true;
01582           if( (pfCandidates_->back()).p() > totalCaloEnergy ) letMuonEatCaloEnergy = true;
01583         }
01584 
01585         if(letMuonEatCaloEnergy) muonHcal = totalHcal;
01586         double muonEcal =0.;
01587         unsigned iEcal = 0;
01588         if( !sortedEcals.empty() ) { 
01589           iEcal = sortedEcals.begin()->second; 
01590           PFClusterRef eclusterref = elements[iEcal].clusterRef();
01591           (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal);
01592           muonEcal = std::min(muonECAL_[0]+muonECAL_[1],eclusterref->energy());
01593           if(letMuonEatCaloEnergy) muonEcal = eclusterref->energy();
01594           // If the muon expected energy accounts for the whole ecal cluster energy, lock the ecal cluster
01595           if ( eclusterref->energy() - muonEcal  < 0.2 ) active[iEcal] = false;
01596           (*pfCandidates_)[tmpi].setEcalEnergy(eclusterref->energy(), muonEcal);
01597         }
01598         unsigned iHO = 0;
01599         double muonHO =0.;
01600         if (useHO_) {
01601           if( !sortedHOs.empty() ) { 
01602             iHO = sortedHOs.begin()->second; 
01603             PFClusterRef hoclusterref = elements[iHO].clusterRef();
01604             (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO);
01605             muonHO = std::min(muonHO_[0]+muonHO_[1],hoclusterref->energy());
01606             if(letMuonEatCaloEnergy) muonHO = hoclusterref->energy();
01607             // If the muon expected energy accounts for the whole HO cluster energy, lock the HO cluster
01608             if ( hoclusterref->energy() - muonHO  < 0.2 ) active[iHO] = false;      
01609             (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal, muonHcal);
01610             (*pfCandidates_)[tmpi].setHoEnergy(hoclusterref->energy(), muonHO);
01611           }
01612         } else {
01613           (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal, muonHcal);
01614         }
01615 
01616         if(letMuonEatCaloEnergy){
01617           muonHCALEnergy += totalHcal;
01618           if (useHO_) muonHCALEnergy +=muonHO;
01619           muonHCALError += 0.;
01620           muonECALEnergy += muonEcal;
01621           muonECALError += 0.;
01622           photonAtECAL -= muonEcal*chargedDirection;
01623           hadronAtECAL -= totalHcal*chargedDirection;
01624           if ( !sortedEcals.empty() ) active[iEcal] = false;
01625           active[iHcal] = false;
01626           if (useHO_ && !sortedHOs.empty() ) active[iHO] = false;
01627         }
01628         else{
01629         // Estimate of the energy deposit & resolution in the calorimeters
01630           muonHCALEnergy += muonHCAL_[0];
01631           muonHCALError += muonHCAL_[1]*muonHCAL_[1];
01632           if ( muonHO > 0. ) { 
01633             muonHCALEnergy += muonHO_[0];
01634             muonHCALError += muonHO_[1]*muonHO_[1];
01635           }
01636           muonECALEnergy += muonECAL_[0];
01637           muonECALError += muonECAL_[1]*muonECAL_[1];
01638           // ... as well as the equivalent "momentum" at ECAL entrance
01639           photonAtECAL -= muonECAL_[0]*chargedDirection;
01640           hadronAtECAL -= muonHCAL_[0]*chargedDirection;
01641         }
01642 
01643         // Remove it from the stack
01644         active[iTrack] = false;
01645         // Go to next track
01646         continue;
01647       }
01648  
01649       //
01650 
01651       if(debug_) cout<<"\t\t"<<elements[iTrack]<<endl;
01652 
01653       // introduce  tracking errors 
01654       double trackMomentum = trackRef->p();
01655       totalChargedMomentum += trackMomentum; 
01656 
01657       // If the track is not a tight muon, but still resembles a muon
01658       // keep it for later for blocks with too large a charged energy
01659       if ( thisIsALooseMuon && !thisIsAMuon ) nMuons += 1;      
01660 
01661       // ... and keep anyway the pt error for possible fake rejection
01662       // ... blow up errors of 5th anf 4th iteration, to reject those
01663       // ... tracks first (in case it's needed)
01664       double Dpt = trackRef->ptError();
01665       double blowError = 1.;
01666       switch (trackRef->algo()) {
01667       case TrackBase::ctf:
01668       case TrackBase::iter0:
01669       case TrackBase::iter1:
01670       case TrackBase::iter2:
01671       case TrackBase::iter3:
01672       case TrackBase::iter4:
01673         blowError = 1.;
01674         break;
01675       case TrackBase::iter5:
01676         blowError = factors45_[0];
01677         break;
01678       case TrackBase::iter6:
01679         blowError = factors45_[1];
01680         break;
01681       default:
01682         blowError = 1E9;
01683         break;
01684       }
01685       // except if it is from an interaction
01686       bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
01687 
01688       if ( isPrimaryOrSecondary ) blowError = 1.;
01689 
01690       std::pair<unsigned,bool> tkmuon = make_pair(iTrack,thisIsALooseMuon);
01691       associatedTracks.insert( make_pair(-Dpt*blowError, tkmuon) );     
01692  
01693       // Also keep the total track momentum error for comparison with the calo energy
01694       double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
01695       sumpError2 += Dp*Dp;
01696 
01697       bool connectedToEcal = false; // Will become true if there is at least one ECAL cluster connected
01698       if( !sortedEcals.empty() ) 
01699         { // start case: at least one ecal element associated to iTrack
01700           
01701           // Loop over all connected ECAL clusters
01702           for ( IE iec=sortedEcals.begin(); 
01703                 iec!=sortedEcals.end(); ++iec ) {
01704 
01705             unsigned iEcal = iec->second;
01706             double dist = iec->first;
01707             
01708             // Ignore ECAL cluters already used
01709             if( !active[iEcal] ) { 
01710               if(debug_) cout<<"\t\tcluster locked"<<endl;          
01711               continue;
01712             }
01713 
01714             // Sanity checks
01715             PFBlockElement::Type type = elements[ iEcal ].type();
01716             assert( type == PFBlockElement::ECAL );
01717             PFClusterRef eclusterref = elements[iEcal].clusterRef();
01718             assert(!eclusterref.isNull() );
01719               
01720             // Check if this ECAL is not closer to another track - ignore it in that case
01721             std::multimap<double, unsigned> sortedTracksEcal;
01722             block.associatedElements( iEcal,  linkData,
01723                                       sortedTracksEcal,
01724                                       reco::PFBlockElement::TRACK,
01725                                       reco::PFBlock::LINKTEST_ALL );
01726             unsigned jTrack = sortedTracksEcal.begin()->second;
01727             if ( jTrack != iTrack ) continue; 
01728 
01729             // double chi2Ecal = block.chi2(jTrack,iEcal,linkData,
01730             //                              reco::PFBlock::LINKTEST_ALL);
01731             double distEcal = block.dist(jTrack,iEcal,linkData,
01732                                          reco::PFBlock::LINKTEST_ALL);
01733                                          
01734             // totalEcal += eclusterref->energy();
01735             // float ecalEnergyUnCalibrated = eclusterref->energy();
01736             //std::cout << "Ecal Uncalibrated " << ecalEnergyUnCalibrated << std::endl;
01737             
01738             // check the presence of preshower clusters in the vicinity
01739             vector<double> ps1Ene(1,static_cast<double>(0.));
01740             associatePSClusters(iEcal, reco::PFBlockElement::PS1, 
01741                                 block, elements, linkData, active, 
01742                                 ps1Ene);
01743             vector<double> ps2Ene(1,static_cast<double>(0.));
01744             associatePSClusters(iEcal, reco::PFBlockElement::PS2, 
01745                                 block, elements, linkData, active, 
01746                                 ps2Ene); 
01747             std::pair<double,double> psEnes = make_pair(ps1Ene[0],
01748                                                         ps2Ene[0]);
01749             associatedPSs.insert(make_pair(iEcal,psEnes));
01750               
01751             // Calibrate the ECAL energy for photons
01752             bool crackCorrection = false;
01753             float ecalEnergyCalibrated = calibration_->energyEm(*eclusterref,ps1Ene,ps2Ene,crackCorrection);
01754             math::XYZVector photonDirection(eclusterref->position().X(),
01755                                             eclusterref->position().Y(),
01756                                             eclusterref->position().Z());
01757             photonDirection = photonDirection.Unit();
01758 
01759             if ( !connectedToEcal ) { // This is the closest ECAL cluster - will add its energy later
01760               
01761               if(debug_) cout<<"\t\t\tclosest: "
01762                              <<elements[iEcal]<<endl;
01763               
01764               connectedToEcal = true;
01765               // PJ 1st-April-09 : To be done somewhere !!! (Had to comment it, but it is needed)
01766               // currentChargedHadron.addElementInBlock( blockref, iEcal );
01767        
01768               std::pair<unsigned,math::XYZVector> satellite = 
01769                 make_pair(iEcal,ecalEnergyCalibrated*photonDirection);
01770               ecalSatellites.insert( make_pair(-1., satellite) );
01771 
01772             } else { // Keep satellite clusters for later
01773               
01774               std::pair<unsigned,math::XYZVector> satellite = 
01775                 make_pair(iEcal,ecalEnergyCalibrated*photonDirection);
01776               ecalSatellites.insert( make_pair(dist, satellite) );
01777               
01778             }
01779             
01780             std::pair<double, unsigned> associatedEcal 
01781               = make_pair( distEcal, iEcal );
01782             associatedEcals.insert( make_pair(iTrack, associatedEcal) );
01783 
01784           } // End loop ecal associated to iTrack
01785         } // end case: at least one ecal element associated to iTrack
01786 
01787       if( useHO_ && !sortedHOs.empty() ) 
01788         { // start case: at least one ho element associated to iTrack
01789           
01790           // Loop over all connected HO clusters
01791           for ( IE ieho=sortedHOs.begin(); ieho!=sortedHOs.end(); ++ieho ) {
01792 
01793             unsigned iHO = ieho->second;
01794             double distHO = ieho->first;
01795             
01796             // Ignore HO cluters already used
01797             if( !active[iHO] ) { 
01798               if(debug_) cout<<"\t\tcluster locked"<<endl;          
01799               continue;
01800             }
01801             
01802             // Sanity checks
01803             PFBlockElement::Type type = elements[ iHO ].type();
01804             assert( type == PFBlockElement::HO );
01805             PFClusterRef hoclusterref = elements[iHO].clusterRef();
01806             assert(!hoclusterref.isNull() );
01807             
01808             // Check if this HO is not closer to another track - ignore it in that case
01809             std::multimap<double, unsigned> sortedTracksHO;
01810             block.associatedElements( iHO,  linkData,
01811                                       sortedTracksHO,
01812                                       reco::PFBlockElement::TRACK,
01813                                       reco::PFBlock::LINKTEST_ALL );
01814             unsigned jTrack = sortedTracksHO.begin()->second;
01815             if ( jTrack != iTrack ) continue; 
01816 
01817             // double chi2HO = block.chi2(jTrack,iHO,linkData,
01818             //                              reco::PFBlock::LINKTEST_ALL);
01819             //double distHO = block.dist(jTrack,iHO,linkData,
01820             //                 reco::PFBlock::LINKTEST_ALL);
01821             
01822             // Increment the total energy by the energy of this HO cluster
01823             totalHO += hoclusterref->energy();
01824             active[iHO] = false;
01825             // Keep track for later reference in the PFCandidate.
01826             std::pair<double, unsigned> associatedHO
01827               = make_pair( distHO, iHO );
01828             associatedHOs.insert( make_pair(iTrack, associatedHO) );
01829             
01830           } // End loop ho associated to iTrack
01831         } // end case: at least one ho element associated to iTrack
01832       
01833       
01834     } // end loop on tracks associated to hcal element iHcal
01835 
01836     // Include totalHO in totalHCAL for the time being (it will be calibrated as HCAL energy)
01837     totalHcal += totalHO;
01838     
01839     // test compatibility between calo and tracker. //////////////
01840 
01841     double caloEnergy = 0.;
01842     double slopeEcal = 1.0;
01843     double calibEcal = 0.;
01844     double calibHcal = 0.;
01845     hadronDirection = hadronAtECAL.Unit();
01846 
01847     // Determine the expected calo resolution from the total charged momentum
01848     double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());    
01849     Caloresolution *= totalChargedMomentum;
01850     // Account for muons
01851     Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
01852     totalEcal -= std::min(totalEcal,muonECALEnergy);
01853     totalHcal -= std::min(totalHcal,muonHCALEnergy);
01854     if ( totalEcal < 1E-9 ) photonAtECAL = math::XYZVector(0.,0.,0.);
01855     if ( totalHcal < 1E-9 ) hadronAtECAL = math::XYZVector(0.,0.,0.);
01856 
01857     // Loop over all ECAL satellites, starting for the closest to the various tracks
01858     // and adding other satellites until saturation of the total track momentum
01859     // Note : for code simplicity, the first element of the loop is the HCAL cluster
01860     // with 0 energy in the ECAL
01861     for ( IS is = ecalSatellites.begin(); is != ecalSatellites.end(); ++is ) { 
01862 
01863       // Add the energy of this ECAL cluster
01864       double previousCalibEcal = calibEcal;
01865       double previousCalibHcal = calibHcal;
01866       double previousCaloEnergy = caloEnergy;
01867       double previousSlopeEcal = slopeEcal;
01868       math::XYZVector previousHadronAtECAL = hadronAtECAL;
01869       //
01870       totalEcal += sqrt(is->second.second.Mag2());
01871       photonAtECAL += is->second.second;
01872       calibEcal = std::max(0.,totalEcal);
01873       calibHcal = std::max(0.,totalHcal);
01874       hadronAtECAL = calibHcal * hadronDirection;
01875       // Calibrate ECAL and HCAL energy under the hadron hypothesis.
01876       calibration_->energyEmHad(totalChargedMomentum,calibEcal,calibHcal,
01877                                 hclusterref->positionREP().Eta(),
01878                                 hclusterref->positionREP().Phi());
01879       caloEnergy = calibEcal+calibHcal;
01880       if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
01881 
01882       hadronAtECAL = calibHcal * hadronDirection; 
01883       
01884       // Continue looping until all closest clusters are exhausted and as long as
01885       // the calorimetric energy does not saturate the total momentum.
01886       if ( is->first < 0. || caloEnergy - totalChargedMomentum <= 0. ) { 
01887         if(debug_) cout<<"\t\t\tactive, adding "<<is->second.second
01888                        <<" to ECAL energy, and locking"<<endl;
01889         active[is->second.first] = false;
01890         continue;
01891       }
01892 
01893       // Otherwise, do not consider the last cluster examined and exit.
01894       // active[is->second.first] = true;
01895       totalEcal -= sqrt(is->second.second.Mag2());
01896       photonAtECAL -= is->second.second;
01897       calibEcal = previousCalibEcal;
01898       calibHcal = previousCalibHcal;
01899       hadronAtECAL = previousHadronAtECAL;
01900       slopeEcal = previousSlopeEcal;
01901       caloEnergy = previousCaloEnergy;
01902 
01903       break;
01904 
01905     }
01906 
01907     // Sanity check !
01908     assert(caloEnergy>=0);
01909 
01910 
01911     // And now check for hadronic energy excess...
01912 
01913     //colin: resolution should be measured on the ecal+hcal case. 
01914     // however, the result will be close. 
01915     // double Caloresolution = neutralHadronEnergyResolution( caloEnergy );
01916     // Caloresolution *= caloEnergy;
01917     // PJ The resolution is on the expected charged calo energy !
01918     //double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
01919     //Caloresolution *= totalChargedMomentum;
01920     // that of the charged particles linked to the cluster!
01921     double TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
01922 
01923     /* */
01925     if ( totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution ) {    
01926 
01927       /* 
01928       cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
01929       cout<<"\t\tsum p    = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
01930       cout<<"\t\tsum ecal = "<<totalEcal<<endl;
01931       cout<<"\t\tsum hcal = "<<totalHcal<<endl;
01932       cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
01933       cout<<"\t\t => Calo Energy- total charged momentum = "
01934          <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
01935       cout<<endl;
01936       cout << "\t\tNumber/momentum of muons found in the block : " << nMuons << std::endl;
01937       */
01938       // First consider loose muons
01939       if ( nMuons > 0 ) { 
01940         for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) { 
01941           unsigned iTrack = it->second.first;
01942           // Only active tracks
01943           if ( !active[iTrack] ) continue;
01944           // Only muons
01945           if ( !it->second.second ) continue;
01946 
01947           bool isTrack = elements[it->second.first].muonRef()->isTrackerMuon();
01948           double trackMomentum = elements[it->second.first].trackRef()->p();
01949 
01950           // look for ECAL elements associated to iTrack (associated to iHcal)
01951           std::multimap<double, unsigned> sortedEcals;
01952           block.associatedElements( iTrack,  linkData,
01953                                     sortedEcals,
01954                                     reco::PFBlockElement::ECAL,
01955                                     reco::PFBlock::LINKTEST_ALL );
01956           std::multimap<double, unsigned> sortedHOs;
01957           block.associatedElements( iTrack,  linkData,
01958                                     sortedHOs,
01959                                     reco::PFBlockElement::HO,
01960                                     reco::PFBlock::LINKTEST_ALL );
01961           // Add the muon to the PF candidate list
01962           unsigned tmpi = reconstructTrack( elements[iTrack] );
01963           (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
01964           (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
01965           double muonHcal = std::min(muonHCAL_[0]+muonHCAL_[1],totalHcal-totalHO);
01966           double muonHO = 0.;
01967           (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal,muonHcal);
01968           if( !sortedEcals.empty() ) { 
01969             unsigned iEcal = sortedEcals.begin()->second; 
01970             PFClusterRef eclusterref = elements[iEcal].clusterRef();
01971             (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal);
01972             double muonEcal = std::min(muonECAL_[0]+muonECAL_[1],eclusterref->energy());
01973             (*pfCandidates_)[tmpi].setEcalEnergy(eclusterref->energy(),muonEcal);
01974           }
01975           if( useHO_ && !sortedHOs.empty() ) { 
01976             unsigned iHO = sortedHOs.begin()->second; 
01977             PFClusterRef hoclusterref = elements[iHO].clusterRef();
01978             (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO);
01979             muonHO = std::min(muonHO_[0]+muonHO_[1],hoclusterref->energy());
01980             (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal-totalHO,muonHcal);
01981             (*pfCandidates_)[tmpi].setHoEnergy(hoclusterref->energy(),muonHO);
01982           }
01983           reco::PFCandidate::ParticleType particleType = reco::PFCandidate::mu;
01984           (*pfCandidates_)[tmpi].setParticleType(particleType);
01985 
01986           if(PFMuonAlgo::isGlobalLooseMuon(elements[it->second.first].muonRef())){
01987             // Take the best pt measurement
01988             reco::TrackRef bestMuTrack =  elements[it->second.first].muonRef()->muonBestTrack();
01989             if(!useBestMuonTrack_)
01990               bestMuTrack = elements[it->second.first].muonRef()->combinedMuon();
01991 
01992             double muonMomentum = bestMuTrack->p();
01993             double muonPtError  = bestMuTrack->ptError();
01994 
01995             double staMomentum = elements[it->second.first].muonRef()->standAloneMuon()->p();
01996             double staPtError = elements[it->second.first].muonRef()->standAloneMuon()->ptError();
01997             double trackPtError = elements[it->second.first].trackRef()->ptError();
01998 
01999 
02000             double globalCorr = 1;
02001 
02002             // for loose muons we choose whichever fit has the best error, since the track is often mis-recontructed or there are problems with arbitration
02003             if(!isTrack || muonPtError < trackPtError || staPtError < trackPtError){          
02004               if(muonPtError < staPtError) globalCorr = muonMomentum/trackMomentum;
02005               else globalCorr = staMomentum/trackMomentum;
02006             }
02007             (*pfCandidates_)[tmpi].rescaleMomentum(globalCorr);
02008             
02009             if (debug_){
02010               std::cout << "\tElement  " << elements[iTrack] << std::endl 
02011                         << "PFAlgo: particle type set to muon (global, loose), pT = "<<elements[it->second.first].muonRef()->pt()<<std::endl; 
02012               PFMuonAlgo::printMuonProperties(elements[it->second.first].muonRef());
02013             }
02014           }
02015           else{
02016             if (debug_){
02017               std::cout << "\tElement  " << elements[iTrack] << std::endl 
02018                         << "PFAlgo: particle type set to muon (tracker, loose), pT = "<<elements[it->second.first].muonRef()->pt()<<std::endl;
02019               PFMuonAlgo::printMuonProperties(elements[it->second.first].muonRef()); 
02020             }
02021           }
02022           
02023           // Remove it from the block
02024           const math::XYZPointF& chargedPosition = 
02025             dynamic_cast<const reco::PFBlockElementTrack*>(&elements[it->second.first])->positionAtECALEntrance();        
02026           math::XYZVector chargedDirection(chargedPosition.X(), chargedPosition.Y(), chargedPosition.Z());
02027           chargedDirection = chargedDirection.Unit();
02028           totalChargedMomentum -= trackMomentum;
02029           // Update the calo energies
02030           if ( totalEcal > 0. ) 
02031             calibEcal -= std::min(calibEcal,muonECAL_[0]*calibEcal/totalEcal);
02032           if ( totalHcal > 0. ) 
02033             calibHcal -= std::min(calibHcal,muonHCAL_[0]*calibHcal/totalHcal);
02034           totalEcal -= std::min(totalEcal,muonECAL_[0]);
02035           totalHcal -= std::min(totalHcal,muonHCAL_[0]);
02036           if ( totalEcal > muonECAL_[0] ) photonAtECAL -= muonECAL_[0] * chargedDirection;
02037           if ( totalHcal > muonHCAL_[0] ) hadronAtECAL -= muonHCAL_[0]*calibHcal/totalHcal * chargedDirection;
02038           caloEnergy = calibEcal+calibHcal;
02039           muonHCALEnergy += muonHCAL_[0];
02040           muonHCALError += muonHCAL_[1]*muonHCAL_[1];
02041           if ( muonHO > 0. ) { 
02042             muonHCALEnergy += muonHO_[0];
02043             muonHCALError += muonHO_[1]*muonHO_[1];
02044             if ( totalHcal > 0. ) { 
02045               calibHcal -= std::min(calibHcal,muonHO_[0]*calibHcal/totalHcal);
02046               totalHcal -= std::min(totalHcal,muonHO_[0]);
02047             }
02048           }
02049           muonECALEnergy += muonECAL_[0];
02050           muonECALError += muonECAL_[1]*muonECAL_[1];
02051           active[iTrack] = false;
02052           // Stop the loop whenever enough muons are removed
02053           //Commented out: Keep looking for muons since they often come in pairs -Matt
02054           //if ( totalChargedMomentum < caloEnergy ) break;     
02055         }
02056         // New calo resolution.
02057         Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());    
02058         Caloresolution *= totalChargedMomentum;
02059         Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
02060       }
02061     }
02062     /*    
02063     if(debug_){
02064       cout<<"\tBefore Cleaning "<<endl;
02065       cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
02066       cout<<"\t\tsum p    = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
02067       cout<<"\t\tsum ecal = "<<totalEcal<<endl;
02068       cout<<"\t\tsum hcal = "<<totalHcal<<endl;
02069       cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
02070       cout<<"\t\t => Calo Energy- total charged momentum = "
02071           <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
02072       cout<<endl;
02073     }
02074     */
02075 
02076     // Second consider bad tracks (if still needed after muon removal)
02077     unsigned corrTrack = 10000000;
02078     double corrFact = 1.;
02079 
02080     if (rejectTracks_Bad_ && 
02081         totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution) { 
02082       
02083       for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) { 
02084         unsigned iTrack = it->second.first;
02085         // Only active tracks
02086         if ( !active[iTrack] ) continue;
02087         const reco::TrackRef& trackref = elements[it->second.first].trackRef();
02088 
02089         double dptRel = fabs(it->first)/trackref->pt()*100;
02090         bool isSecondary = isFromSecInt(elements[iTrack], "secondary");
02091         bool isPrimary = isFromSecInt(elements[iTrack], "primary");
02092 
02093         if ( isSecondary && dptRel < dptRel_DispVtx_ ) continue;
02094         // Consider only bad tracks
02095         if ( fabs(it->first) < ptError_ ) break;
02096         // What would become the block charged momentum if this track were removed
02097         double wouldBeTotalChargedMomentum = 
02098           totalChargedMomentum - trackref->p();
02099         // Reject worst tracks, as long as the total charged momentum 
02100         // is larger than the calo energy
02101 
02102         if ( wouldBeTotalChargedMomentum > caloEnergy ) { 
02103 
02104           if (debug_ && isSecondary) {
02105             cout << "In bad track rejection step dptRel = " << dptRel << " dptRel_DispVtx_ = " << dptRel_DispVtx_ << endl;
02106             cout << "The calo energy would be still smaller even without this track but it is attached to a NI"<< endl;
02107           }
02108 
02109 
02110           if(isPrimary || (isSecondary && dptRel < dptRel_DispVtx_)) continue;
02111           active[iTrack] = false;
02112           totalChargedMomentum = wouldBeTotalChargedMomentum;
02113           if ( debug_ )
02114             std::cout << "\tElement  " << elements[iTrack] 
02115                       << " rejected (Dpt = " << -it->first 
02116                       << " GeV/c, algo = " << trackref->algo() << ")" << std::endl;
02117         // Just rescale the nth worst track momentum to equalize the calo energy
02118         } else {        
02119           if(isPrimary) break;
02120           corrTrack = iTrack;
02121           corrFact = (caloEnergy - wouldBeTotalChargedMomentum)/elements[it->second.first].trackRef()->p();
02122           if ( trackref->p()*corrFact < 0.05 ) { 
02123             corrFact = 0.;
02124             active[iTrack] = false;
02125           }
02126           totalChargedMomentum -= trackref->p()*(1.-corrFact);
02127           if ( debug_ ) 
02128             std::cout << "\tElement  " << elements[iTrack] 
02129                       << " (Dpt = " << -it->first 
02130                       << " GeV/c, algo = " << trackref->algo() 
02131                       << ") rescaled by " << corrFact 
02132                       << " Now the total charged momentum is " << totalChargedMomentum  << endl;
02133           break;
02134         }
02135       }
02136     }
02137 
02138     // New determination of the calo and track resolution avec track deletion/rescaling.
02139     Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());    
02140     Caloresolution *= totalChargedMomentum;
02141     Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
02142 
02143     // Check if the charged momentum is still very inconsistent with the calo measurement.
02144     // In this case, just drop all tracks from 4th and 5th iteration linked to this block
02145     
02146     if ( rejectTracks_Step45_ &&
02147          sortedTracks.size() > 1 && 
02148          totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution ) { 
02149       for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) { 
02150         unsigned iTrack = it->second.first;
02151         reco::TrackRef trackref = elements[iTrack].trackRef();
02152         if ( !active[iTrack] ) continue;
02153 
02154         double dptRel = fabs(it->first)/trackref->pt()*100;
02155         bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
02156 
02157 
02158 
02159 
02160         if (isPrimaryOrSecondary && dptRel < dptRel_DispVtx_) continue;
02161         //
02162         switch (trackref->algo()) {
02163         case TrackBase::ctf:
02164         case TrackBase::iter0:
02165         case TrackBase::iter1:
02166         case TrackBase::iter2:
02167         case TrackBase::iter3:
02168         case TrackBase::iter4:
02169           break;
02170         case TrackBase::iter5:
02171         case TrackBase::iter6:
02172           active[iTrack] = false;       
02173           totalChargedMomentum -= trackref->p();
02174           
02175           if ( debug_ ) 
02176             std::cout << "\tElement  " << elements[iTrack] 
02177                       << " rejected (Dpt = " << -it->first 
02178                       << " GeV/c, algo = " << trackref->algo() << ")" << std::endl;
02179           break;
02180         default:
02181           break;
02182         }
02183       }
02184     }
02185 
02186     // New determination of the calo and track resolution avec track deletion/rescaling.
02187     Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());    
02188     Caloresolution *= totalChargedMomentum;
02189     Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
02190 
02191     // Make PF candidates with the remaining tracks in the block
02192     sumpError2 = 0.;
02193     for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) { 
02194       unsigned iTrack = it->second.first;
02195       if ( !active[iTrack] ) continue;
02196       reco::TrackRef trackRef = elements[iTrack].trackRef();
02197       double trackMomentum = trackRef->p();
02198       double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
02199       unsigned tmpi = reconstructTrack( elements[iTrack] );
02200       (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
02201       (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
02202       std::pair<II,II> myEcals = associatedEcals.equal_range(iTrack);
02203       for (II ii=myEcals.first; ii!=myEcals.second; ++ii ) { 
02204         unsigned iEcal = ii->second.second;
02205         if ( active[iEcal] ) continue;
02206         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
02207       }
02208       
02209       if (useHO_) {
02210         std::pair<II,II> myHOs = associatedHOs.equal_range(iTrack);
02211         for (II ii=myHOs.first; ii!=myHOs.second; ++ii ) { 
02212           unsigned iHO = ii->second.second;
02213           if ( active[iHO] ) continue;
02214           (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO );
02215         }
02216       }
02217 
02218       if ( iTrack == corrTrack ) { 
02219         (*pfCandidates_)[tmpi].rescaleMomentum(corrFact);
02220         trackMomentum *= corrFact;
02221       }
02222       chargedHadronsIndices.push_back( tmpi );
02223       chargedHadronsInBlock.push_back( iTrack );
02224       active[iTrack] = false;
02225       hcalP.push_back(trackMomentum);
02226       hcalDP.push_back(Dp);
02227       if (Dp/trackMomentum > maxDPovP) maxDPovP = Dp/trackMomentum;
02228       sumpError2 += Dp*Dp;
02229     }
02230 
02231     // The total uncertainty of the difference Calo-Track
02232     TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
02233 
02234     if ( debug_ ) {
02235       cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
02236       cout<<"\t\tsum p    = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
02237       cout<<"\t\tsum ecal = "<<totalEcal<<endl;
02238       cout<<"\t\tsum hcal = "<<totalHcal<<endl;
02239       cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
02240       cout<<"\t\t => Calo Energy- total charged momentum = "
02241           <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
02242       cout<<endl;
02243     }
02244 
02245     /* */
02246 
02248     double nsigma = nSigmaHCAL(totalChargedMomentum,hclusterref->positionREP().Eta());
02249     //double nsigma = nSigmaHCAL(caloEnergy,hclusterref->positionREP().Eta());
02250     if ( abs(totalChargedMomentum-caloEnergy)<nsigma*TotalError ) {
02251 
02252       // deposited caloEnergy compatible with total charged momentum
02253       // if tracking errors are large take weighted average
02254       
02255       if(debug_) {
02256         cout<<"\t\tcase 1: COMPATIBLE "
02257             <<"|Calo Energy- total charged momentum| = "
02258             <<abs(caloEnergy-totalChargedMomentum)
02259             <<" < "<<nsigma<<" x "<<TotalError<<endl;
02260         if (maxDPovP < 0.1 )
02261           cout<<"\t\t\tmax DP/P = "<< maxDPovP 
02262               <<" less than 0.1: do nothing "<<endl;
02263         else 
02264           cout<<"\t\t\tmax DP/P = "<< maxDPovP 
02265               <<" >  0.1: take weighted averages "<<endl;
02266       }
02267       
02268       // if max DP/P < 10%  do nothing
02269       if (maxDPovP > 0.1) {
02270       
02271         // for each track associated to hcal
02272         //      int nrows = tkIs.size();
02273         int nrows = chargedHadronsIndices.size();
02274         TMatrixTSym<double> a (nrows);
02275         TVectorD b (nrows);
02276         TVectorD check(nrows);
02277         double sigma2E = Caloresolution*Caloresolution;
02278         for(int i=0; i<nrows; i++) {
02279           double sigma2i = hcalDP[i]*hcalDP[i];
02280           if (debug_){
02281             cout<<"\t\t\ttrack associated to hcal "<<i 
02282                 <<" P = "<<hcalP[i]<<" +- "
02283                 <<hcalDP[i]<<endl;
02284           }
02285           a(i,i) = 1./sigma2i + 1./sigma2E;
02286           b(i) = hcalP[i]/sigma2i + caloEnergy/sigma2E;
02287           for(int j=0; j<nrows; j++) {
02288             if (i==j) continue;
02289             a(i,j) = 1./sigma2E;
02290           } // end loop on j
02291         } // end loop on i
02292         
02293         // solve ax = b
02294         //if (debug_){// debug1
02295         //cout<<" matrix a(i,j) "<<endl;
02296         //a.Print();
02297         //cout<<" vector b(i) "<<endl;
02298         //b.Print();
02299         //} // debug1
02300         TDecompChol decomp(a);
02301         bool ok = false;
02302         TVectorD x = decomp.Solve(b, ok);
02303         // for each track create a PFCandidate track
02304         // with a momentum rescaled to weighted average
02305         if (ok) {
02306           for (int i=0; i<nrows; i++){
02307             //      unsigned iTrack = trackInfos[i].index;
02308             unsigned ich = chargedHadronsIndices[i];
02309             double rescaleFactor =  x(i)/hcalP[i];
02310             (*pfCandidates_)[ich].rescaleMomentum( rescaleFactor );
02311 
02312             if(debug_){
02313               cout<<"\t\t\told p "<<hcalP[i]
02314                   <<" new p "<<x(i) 
02315                   <<" rescale "<<rescaleFactor<<endl;
02316             }
02317           }
02318         }
02319         else {
02320           cerr<<"not ok!"<<endl;
02321           assert(0);
02322         }
02323       }
02324     }
02325 
02327     else if( caloEnergy > totalChargedMomentum ) {
02328       
02329       //case 2: caloEnergy > totalChargedMomentum + nsigma*TotalError
02330       //there is an excess of energy in the calos
02331       //create a neutral hadron or a photon
02332 
02333       /*        
02334       //If it's isolated don't create neutrals since the energy deposit is always coming from a showering muon
02335       bool thisIsAnIsolatedMuon = false;
02336       for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
02337         unsigned iTrack = ie->second;
02338         if(PFMuonAlgo::isIsolatedMuon(elements[iTrack].muonRef())) thisIsAnIsolatedMuon = true; 
02339       }
02340       
02341       if(thisIsAnIsolatedMuon){
02342         if(debug_)cout<<" Not looking for neutral b/c this is an isolated muon "<<endl;
02343         break;
02344       }
02345       */
02346       double eNeutralHadron = caloEnergy - totalChargedMomentum;
02347       double ePhoton = (caloEnergy - totalChargedMomentum) / slopeEcal;
02348 
02349       if(debug_) {
02350         if(!sortedTracks.empty() ){
02351           cout<<"\t\tcase 2: NEUTRAL DETECTION "
02352               <<caloEnergy<<" > "<<nsigma<<"x"<<TotalError
02353               <<" + "<<totalChargedMomentum<<endl;
02354           cout<<"\t\tneutral activity detected: "<<endl
02355               <<"\t\t\t           photon = "<<ePhoton<<endl
02356               <<"\t\t\tor neutral hadron = "<<eNeutralHadron<<endl;
02357             
02358           cout<<"\t\tphoton or hadron ?"<<endl;}
02359           
02360         if(sortedTracks.empty() )
02361           cout<<"\t\tno track -> hadron "<<endl;
02362         else 
02363           cout<<"\t\t"<<sortedTracks.size()
02364               <<"tracks -> check if the excess is photonic or hadronic"<<endl;
02365       }
02366         
02367 
02368       double ratioMax = 0.;
02369       reco::PFClusterRef maxEcalRef;
02370       unsigned maxiEcal= 9999;       
02371 
02372       // for each track associated to hcal: iterator IE ie :
02373         
02374       for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
02375           
02376         unsigned iTrack = ie->second;
02377           
02378         PFBlockElement::Type type = elements[iTrack].type();
02379         assert( type == reco::PFBlockElement::TRACK );
02380           
02381         reco::TrackRef trackRef = elements[iTrack].trackRef();
02382         assert( !trackRef.isNull() ); 
02383           
02384         II iae = associatedEcals.find(iTrack);
02385           
02386         if( iae == associatedEcals.end() ) continue;
02387           
02388         // double distECAL = iae->second.first;
02389         unsigned iEcal = iae->second.second;
02390           
02391         PFBlockElement::Type typeEcal = elements[iEcal].type();
02392         assert(typeEcal == reco::PFBlockElement::ECAL);
02393           
02394         reco::PFClusterRef clusterRef = elements[iEcal].clusterRef();
02395         assert( !clusterRef.isNull() );
02396           
02397         double pTrack = trackRef->p();
02398         double eECAL = clusterRef->energy();
02399         double eECALOverpTrack = eECAL / pTrack;
02400 
02401         if ( eECALOverpTrack > ratioMax ) { 
02402           ratioMax = eECALOverpTrack;
02403           maxEcalRef = clusterRef;
02404           maxiEcal = iEcal;
02405         }          
02406         
02407       }  // end loop on tracks associated to hcal: iterator IE ie
02408     
02409       std::vector<reco::PFClusterRef> pivotalClusterRef;
02410       std::vector<unsigned> iPivotal;
02411       std::vector<double> particleEnergy, ecalEnergy, hcalEnergy, rawecalEnergy, rawhcalEnergy;
02412       std::vector<math::XYZVector> particleDirection;
02413 
02414       // If the excess is smaller than the ecal energy, assign the whole 
02415       // excess to a photon
02416       if ( ePhoton < totalEcal || eNeutralHadron-calibEcal < 1E-10 ) { 
02417         
02418         if ( !maxEcalRef.isNull() ) { 
02419           particleEnergy.push_back(ePhoton);
02420           particleDirection.push_back(photonAtECAL);
02421           ecalEnergy.push_back(ePhoton);
02422           hcalEnergy.push_back(0.);
02423           rawecalEnergy.push_back(totalEcal);
02424           rawhcalEnergy.push_back(totalHcal);
02425           pivotalClusterRef.push_back(maxEcalRef);
02426           iPivotal.push_back(maxiEcal);
02427           // So the merged photon energy is,
02428           mergedPhotonEnergy  = ePhoton;
02429         }
02430         
02431       } else { 
02432         
02433         // Otherwise assign the whole ECAL energy to the photon
02434         if ( !maxEcalRef.isNull() ) { 
02435           pivotalClusterRef.push_back(maxEcalRef);
02436           particleEnergy.push_back(totalEcal);
02437           particleDirection.push_back(photonAtECAL);
02438           ecalEnergy.push_back(totalEcal);
02439           hcalEnergy.push_back(0.);
02440           rawecalEnergy.push_back(totalEcal);
02441           rawhcalEnergy.push_back(totalHcal);
02442           iPivotal.push_back(maxiEcal);
02443           // So the merged photon energy is,
02444           mergedPhotonEnergy  = totalEcal;
02445         }
02446         
02447         // ... and assign the remaining excess to a neutral hadron
02448         mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
02449         if ( mergedNeutralHadronEnergy > 1.0 ) { 
02450           pivotalClusterRef.push_back(hclusterref);
02451           particleEnergy.push_back(mergedNeutralHadronEnergy);
02452           particleDirection.push_back(hadronAtECAL);
02453           ecalEnergy.push_back(0.);
02454           hcalEnergy.push_back(mergedNeutralHadronEnergy);
02455           rawecalEnergy.push_back(totalEcal);
02456           rawhcalEnergy.push_back(totalHcal);
02457           iPivotal.push_back(iHcal);    
02458         }
02459         
02460       }
02461         
02462 
02463       // reconstructing a merged neutral
02464       // the type of PFCandidate is known from the 
02465       // reference to the pivotal cluster. 
02466       
02467       for ( unsigned iPivot=0; iPivot<iPivotal.size(); ++iPivot ) { 
02468         
02469         if ( particleEnergy[iPivot] < 0. ) 
02470           std::cout << "ALARM = Negative energy ! " 
02471                     << particleEnergy[iPivot] << std::endl;
02472         
02473         bool useDirection = true;
02474         unsigned tmpi = reconstructCluster( *pivotalClusterRef[iPivot], 
02475                                             particleEnergy[iPivot], 
02476                                             useDirection,
02477                                             particleDirection[iPivot].X(),
02478                                             particleDirection[iPivot].Y(),
02479                                             particleDirection[iPivot].Z()); 
02480 
02481       
02482         (*pfCandidates_)[tmpi].setEcalEnergy( rawecalEnergy[iPivot],ecalEnergy[iPivot] );
02483         if ( !useHO_ ) { 
02484           (*pfCandidates_)[tmpi].setHcalEnergy( rawhcalEnergy[iPivot],hcalEnergy[iPivot] );
02485           (*pfCandidates_)[tmpi].setHoEnergy(0., 0.);
02486         } else { 
02487           (*pfCandidates_)[tmpi].setHcalEnergy( rawhcalEnergy[iPivot]-totalHO,hcalEnergy[iPivot]*(1.-totalHO/rawhcalEnergy[iPivot]));
02488           (*pfCandidates_)[tmpi].setHoEnergy(totalHO, totalHO * hcalEnergy[iPivot]/rawhcalEnergy[iPivot]);
02489         } 
02490         (*pfCandidates_)[tmpi].setPs1Energy( 0. );
02491         (*pfCandidates_)[tmpi].setPs2Energy( 0. );
02492         (*pfCandidates_)[tmpi].set_mva_nothing_gamma( -1. );
02493         //       (*pfCandidates_)[tmpi].addElement(&elements[iPivotal]);
02494         // (*pfCandidates_)[tmpi].addElementInBlock(blockref, iPivotal[iPivot]);
02495         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
02496         for ( unsigned ich=0; ich<chargedHadronsInBlock.size(); ++ich) { 
02497           unsigned iTrack = chargedHadronsInBlock[ich];
02498           (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
02499           // Assign the position of the track at the ECAL entrance
02500           const math::XYZPointF& chargedPosition = 
02501             dynamic_cast<const reco::PFBlockElementTrack*>(&elements[iTrack])->positionAtECALEntrance();
02502           (*pfCandidates_)[tmpi].setPositionAtECALEntrance(chargedPosition);
02503 
02504           std::pair<II,II> myEcals = associatedEcals.equal_range(iTrack);
02505           for (II ii=myEcals.first; ii!=myEcals.second; ++ii ) { 
02506             unsigned iEcal = ii->second.second;
02507             if ( active[iEcal] ) continue;
02508             (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
02509           }
02510         }
02511 
02512       }
02513 
02514     } // excess of energy
02515   
02516   
02517     // will now share the hcal energy between the various charged hadron 
02518     // candidates, taking into account the potential neutral hadrons
02519     
02520     double totalHcalEnergyCalibrated = calibHcal;
02521     double totalEcalEnergyCalibrated = calibEcal;
02522     //JB: The question is: we've resolved the merged photons cleanly, but how should
02523     //the remaining hadrons be assigned the remaining ecal energy?
02524     //*Temporary solution*: follow HCAL example with fractions...    
02525  
02526    /*
02527     if(totalEcal>0) {
02528       // removing ecal energy from abc calibration
02529       totalHcalEnergyCalibrated  -= calibEcal;
02530       // totalHcalEnergyCalibrated -= calibration_->paramECALplusHCAL_slopeECAL() * totalEcal;
02531     }
02532     */
02533     // else caloEnergy = hcal only calibrated energy -> ok.
02534 
02535     // remove the energy of the potential neutral hadron
02536     totalHcalEnergyCalibrated -= mergedNeutralHadronEnergy;
02537     // similarly for the merged photons
02538     totalEcalEnergyCalibrated -= mergedPhotonEnergy;
02539     // share between the charged hadrons
02540 
02541     //COLIN can compute this before
02542     // not exactly equal to sum p, this is sum E
02543     double chargedHadronsTotalEnergy = 0;
02544     for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
02545       unsigned index = chargedHadronsIndices[ich];
02546       reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
02547       chargedHadronsTotalEnergy += chargedHadron.energy();
02548     }
02549 
02550     for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
02551       unsigned index = chargedHadronsIndices[ich];
02552       reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
02553       float fraction = chargedHadron.energy()/chargedHadronsTotalEnergy;
02554 
02555       if ( !useHO_ ) { 
02556         chargedHadron.setHcalEnergy(  fraction * totalHcal, fraction * totalHcalEnergyCalibrated );          
02557         chargedHadron.setHoEnergy(  0., 0. ); 
02558       } else { 
02559         chargedHadron.setHcalEnergy(  fraction * (totalHcal-totalHO), fraction * totalHcalEnergyCalibrated * (1.-totalHO/totalHcal) );          
02560         chargedHadron.setHoEnergy( fraction * totalHO, fraction * totalHO * totalHcalEnergyCalibrated / totalHcal ); 
02561       }
02562       //JB: fixing up (previously omitted) setting of ECAL energy gouzevit
02563       chargedHadron.setEcalEnergy( fraction * totalEcal, fraction * totalEcalEnergyCalibrated );
02564     }
02565 
02566     // Finally treat unused ecal satellites as photons.
02567     for ( IS is = ecalSatellites.begin(); is != ecalSatellites.end(); ++is ) { 
02568       
02569       // Ignore satellites already taken
02570       unsigned iEcal = is->second.first;
02571       if ( !active[iEcal] ) continue;
02572 
02573       // Sanity checks again (well not useful, this time!)
02574       PFBlockElement::Type type = elements[ iEcal ].type();
02575       assert( type == PFBlockElement::ECAL );
02576       PFClusterRef eclusterref = elements[iEcal].clusterRef();
02577       assert(!eclusterref.isNull() );
02578 
02579       // Lock the cluster
02580       active[iEcal] = false;
02581       
02582       // Find the associated tracks
02583       std::multimap<double, unsigned> assTracks;
02584       block.associatedElements( iEcal,  linkData,
02585                                 assTracks,
02586                                 reco::PFBlockElement::TRACK,
02587                                 reco::PFBlock::LINKTEST_ALL );
02588 
02589       // Create a photon
02590       unsigned tmpi = reconstructCluster( *eclusterref, sqrt(is->second.second.Mag2()) ); 
02591       (*pfCandidates_)[tmpi].setEcalEnergy( eclusterref->energy(),sqrt(is->second.second.Mag2()) );
02592       (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0. );
02593       (*pfCandidates_)[tmpi].setHoEnergy( 0., 0. );
02594       (*pfCandidates_)[tmpi].setPs1Energy( associatedPSs[iEcal].first );
02595       (*pfCandidates_)[tmpi].setPs2Energy( associatedPSs[iEcal].second );
02596       (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
02597       (*pfCandidates_)[tmpi].addElementInBlock( blockref, sortedTracks.begin()->second) ;
02598     }
02599 
02600 
02601   }
02602 
02603    // end loop on hcal element iHcal= hcalIs[i] 
02604 
02605 
02606   // Processing the remaining HCAL clusters
02607   if(debug_) { 
02608     cout<<endl;
02609     if(debug_) 
02610       cout<<endl
02611           <<"---- loop remaining hcal ------- "<<endl;
02612   }
02613   
02614 
02615   //COLINFEB16 
02616   // now dealing with the HCAL elements that are not linked to any track 
02617   for(unsigned ihcluster=0; ihcluster<hcalIs.size(); ihcluster++) {
02618     unsigned iHcal = hcalIs[ihcluster];
02619 
02620     // Keep ECAL and HO elements for reference in the PFCandidate
02621     std::vector<unsigned> ecalRefs;
02622     std::vector<unsigned> hoRefs;
02623     
02624     if(debug_)
02625       cout<<endl<<elements[iHcal]<<" ";
02626     
02627     
02628     if( !active[iHcal] ) {
02629       if(debug_) 
02630         cout<<"not active"<<endl;         
02631       continue;
02632     }
02633     
02634     // Find the ECAL elements linked to it
02635     std::multimap<double, unsigned> ecalElems;
02636     block.associatedElements( iHcal,  linkData,
02637                               ecalElems ,
02638                               reco::PFBlockElement::ECAL,
02639                               reco::PFBlock::LINKTEST_ALL );
02640 
02641     // Loop on these ECAL elements
02642     float totalEcal = 0.;
02643     float ecalMax = 0.;
02644     reco::PFClusterRef eClusterRef;
02645     for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
02646       
02647       unsigned iEcal = ie->second;
02648       double dist = ie->first;
02649       PFBlockElement::Type type = elements[iEcal].type();
02650       assert( type == PFBlockElement::ECAL );
02651       
02652       // Check if already used
02653       if( !active[iEcal] ) continue;
02654 
02655       // Check the distance (one HCALPlusECAL tower, roughly)
02656       // if ( dist > 0.15 ) continue;
02657 
02658       //COLINFEB16 
02659       // what could be done is to
02660       // - link by rechit.
02661       // - take in the neutral hadron all the ECAL clusters 
02662       // which are within the same CaloTower, according to the distance, 
02663       // except the ones which are closer to another HCAL cluster.
02664       // - all the other ECAL linked to this HCAL are photons. 
02665       // 
02666       // about the closest HCAL cluster. 
02667       // it could maybe be easier to loop on the ECAL clusters first
02668       // to cut the links to all HCAL clusters except the closest, as is 
02669       // done in the first track loop. But maybe not!
02670       // or add an helper function to the PFAlgo class to ask 
02671       // if a given element is the closest of a given type to another one?
02672     
02673       // Check if not closer from another free HCAL 
02674       std::multimap<double, unsigned> hcalElems;
02675       block.associatedElements( iEcal,  linkData,
02676                                 hcalElems ,
02677                                 reco::PFBlockElement::HCAL,
02678                                 reco::PFBlock::LINKTEST_ALL );
02679 
02680       bool isClosest = true;
02681       for(IE ih = hcalElems.begin(); ih != hcalElems.end(); ++ih ) {
02682 
02683         unsigned jHcal = ih->second;
02684         double distH = ih->first;
02685         
02686         if ( !active[jHcal] ) continue;
02687 
02688         if ( distH < dist ) { 
02689           isClosest = false;
02690           break;
02691         }
02692 
02693       }
02694 
02695       if (!isClosest) continue;
02696 
02697 
02698       if(debug_) {
02699         cout<<"\telement "<<elements[iEcal]<<" linked with dist "<< dist<<endl;
02700         cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
02701       }
02702       
02703       reco::PFClusterRef eclusterRef = elements[iEcal].clusterRef();
02704       assert( !eclusterRef.isNull() );
02705 
02706       // Check the presence of ps clusters in the vicinity
02707       vector<double> ps1Ene(1,static_cast<double>(0.));
02708       associatePSClusters(iEcal, reco::PFBlockElement::PS1, block, elements, linkData, active, ps1Ene);
02709       vector<double> ps2Ene(1,static_cast<double>(0.));
02710       associatePSClusters(iEcal, reco::PFBlockElement::PS2, block, elements, linkData, active, ps2Ene);
02711       bool crackCorrection = false;
02712       double ecalEnergy = calibration_->energyEm(*eclusterRef,ps1Ene,ps2Ene,crackCorrection);
02713       
02714       //std::cout << "EcalEnergy, ps1, ps2 = " << ecalEnergy 
02715       //          << ", " << ps1Ene[0] << ", " << ps2Ene[0] << std::endl;
02716       totalEcal += ecalEnergy;
02717       if ( ecalEnergy > ecalMax ) { 
02718         ecalMax = ecalEnergy;
02719         eClusterRef = eclusterRef;
02720       }
02721       
02722       ecalRefs.push_back(iEcal);
02723       active[iEcal] = false;
02724 
02725 
02726     }// End loop ECAL
02727     
02728     // Now find the HO clusters linked to the HCAL cluster
02729     double totalHO = 0.;
02730     double hoMax = 0.;
02731     //unsigned jHO = 0;
02732     if (useHO_) {
02733       std::multimap<double, unsigned> hoElems;
02734       block.associatedElements( iHcal,  linkData,
02735                                 hoElems ,
02736                                 reco::PFBlockElement::HO,
02737                                 reco::PFBlock::LINKTEST_ALL );
02738       
02739       // Loop on these HO elements
02740       //      double totalHO = 0.;
02741       //      double hoMax = 0.;
02742       //      unsigned jHO = 0;
02743       reco::PFClusterRef hoClusterRef;
02744       for(IE ie = hoElems.begin(); ie != hoElems.end(); ++ie ) {
02745         
02746         unsigned iHO = ie->second;
02747         double dist = ie->first;
02748         PFBlockElement::Type type = elements[iHO].type();
02749         assert( type == PFBlockElement::HO );
02750         
02751         // Check if already used
02752         if( !active[iHO] ) continue;
02753         
02754         // Check the distance (one HCALPlusHO tower, roughly)
02755         // if ( dist > 0.15 ) continue;
02756         
02757         // Check if not closer from another free HCAL 
02758         std::multimap<double, unsigned> hcalElems;
02759         block.associatedElements( iHO,  linkData,
02760                                   hcalElems ,
02761                                   reco::PFBlockElement::HCAL,
02762                                   reco::PFBlock::LINKTEST_ALL );
02763         
02764         bool isClosest = true;
02765         for(IE ih = hcalElems.begin(); ih != hcalElems.end(); ++ih ) {
02766           
02767           unsigned jHcal = ih->second;
02768           double distH = ih->first;
02769           
02770           if ( !active[jHcal] ) continue;
02771           
02772           if ( distH < dist ) { 
02773             isClosest = false;
02774             break;
02775           }
02776           
02777         }
02778         
02779         if (!isClosest) continue;
02780         
02781         if(debug_ && useHO_) {
02782           cout<<"\telement "<<elements[iHO]<<" linked with dist "<< dist<<endl;
02783           cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
02784         }
02785         
02786         reco::PFClusterRef hoclusterRef = elements[iHO].clusterRef();
02787         assert( !hoclusterRef.isNull() );
02788         
02789         double hoEnergy = hoclusterRef->energy(); // calibration_->energyEm(*hoclusterRef,ps1Ene,ps2Ene,crackCorrection);
02790         
02791         totalHO += hoEnergy;
02792         if ( hoEnergy > hoMax ) { 
02793           hoMax = hoEnergy;
02794           hoClusterRef = hoclusterRef;
02795           //jHO = iHO;
02796         }
02797         
02798         hoRefs.push_back(iHO);
02799         active[iHO] = false;
02800         
02801       }// End loop HO
02802     }
02803 
02804     PFClusterRef hclusterRef 
02805       = elements[iHcal].clusterRef();
02806     assert( !hclusterRef.isNull() );
02807     
02808     // HCAL energy
02809     double totalHcal =  hclusterRef->energy();
02810     // Include the HO energy 
02811     if ( useHO_ ) totalHcal += totalHO;
02812 
02813     // std::cout << "Hcal Energy,eta : " << totalHcal 
02814     //          << ", " << hclusterRef->positionREP().Eta()
02815     //          << std::endl;
02816     // Calibration
02817     //double caloEnergy = totalHcal;
02818     // double slopeEcal = 1.0;
02819     double calibEcal = totalEcal > 0. ? totalEcal : 0.;
02820     double calibHcal = std::max(0.,totalHcal);
02821     if  (  hclusterRef->layer() == PFLayer::HF_HAD  ||
02822            hclusterRef->layer() == PFLayer::HF_EM ) { 
02823       //caloEnergy = totalHcal/0.7;
02824       calibEcal = totalEcal;
02825     } else { 
02826       calibration_->energyEmHad(-1.,calibEcal,calibHcal,
02827                                 hclusterRef->positionREP().Eta(),
02828                                 hclusterRef->positionREP().Phi());      
02829       //caloEnergy = calibEcal+calibHcal;
02830     }
02831 
02832     // std::cout << "CalibEcal,HCal = " << calibEcal << ", " << calibHcal << std::endl;
02833     // std::cout << "-------------------------------------------------------------------" << std::endl;
02834     // ECAL energy : calibration
02835 
02836     // double particleEnergy = caloEnergy;
02837     // double particleEnergy = totalEcal + calibHcal;
02838     // particleEnergy /= (1.-0.724/sqrt(particleEnergy)-0.0226/particleEnergy);
02839 
02840     unsigned tmpi = reconstructCluster( *hclusterRef, 
02841                                         calibEcal+calibHcal ); 
02842 
02843     
02844     (*pfCandidates_)[tmpi].setEcalEnergy( totalEcal, calibEcal );
02845     if ( !useHO_ ) { 
02846       (*pfCandidates_)[tmpi].setHcalEnergy( totalHcal, calibHcal );
02847       (*pfCandidates_)[tmpi].setHoEnergy(0.,0.);
02848     } else { 
02849       (*pfCandidates_)[tmpi].setHcalEnergy( totalHcal-totalHO, calibHcal*(1.-totalHO/totalHcal));
02850       (*pfCandidates_)[tmpi].setHoEnergy(totalHO,totalHO*calibHcal/totalHcal);
02851     }
02852     (*pfCandidates_)[tmpi].setPs1Energy( 0. );
02853     (*pfCandidates_)[tmpi].setPs2Energy( 0. );
02854     (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
02855     for (unsigned iec=0; iec<ecalRefs.size(); ++iec) 
02856       (*pfCandidates_)[tmpi].addElementInBlock( blockref, ecalRefs[iec] );
02857     for (unsigned iho=0; iho<hoRefs.size(); ++iho) 
02858       (*pfCandidates_)[tmpi].addElementInBlock( blockref, hoRefs[iho] );
02859       
02860   }//loop hcal elements
02861 
02862 
02863 
02864 
02865   if(debug_) { 
02866     cout<<endl;
02867     if(debug_) cout<<endl<<"---- loop ecal------- "<<endl;
02868   }
02869   
02870   // for each ecal element iEcal = ecalIs[i] in turn:
02871 
02872   for(unsigned i=0; i<ecalIs.size(); i++) {
02873     unsigned iEcal = ecalIs[i];
02874     
02875     if(debug_) 
02876       cout<<endl<<elements[iEcal]<<" ";
02877     
02878     if( ! active[iEcal] ) {
02879       if(debug_) 
02880         cout<<"not active"<<endl;         
02881       continue;
02882     }
02883     
02884     PFBlockElement::Type type = elements[ iEcal ].type();
02885     assert( type == PFBlockElement::ECAL );
02886 
02887     PFClusterRef clusterref = elements[iEcal].clusterRef();
02888     assert(!clusterref.isNull() );
02889 
02890     active[iEcal] = false;
02891 
02892     // Check the presence of ps clusters in the vicinity
02893     vector<double> ps1Ene(1,static_cast<double>(0.));
02894     associatePSClusters(iEcal, reco::PFBlockElement::PS1, block, elements, linkData, active, ps1Ene);
02895     vector<double> ps2Ene(1,static_cast<double>(0.));
02896     associatePSClusters(iEcal, reco::PFBlockElement::PS2, block, elements, linkData, active, ps2Ene);
02897     bool crackCorrection = false;
02898     float ecalEnergy = calibration_->energyEm(*clusterref,ps1Ene,ps2Ene,crackCorrection);
02899     // float ecalEnergy = calibration_->energyEm( clusterref->energy() );
02900     double particleEnergy = ecalEnergy;
02901     
02902     unsigned tmpi = reconstructCluster( *clusterref, 
02903                                         particleEnergy );
02904  
02905     (*pfCandidates_)[tmpi].setEcalEnergy( clusterref->energy(),ecalEnergy );
02906     (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0. );
02907     (*pfCandidates_)[tmpi].setHoEnergy( 0., 0. );
02908     (*pfCandidates_)[tmpi].setPs1Energy( 0. );
02909     (*pfCandidates_)[tmpi].setPs2Energy( 0. );
02910     (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
02911     
02912 
02913   }  // end loop on ecal elements iEcal = ecalIs[i]
02914 
02915 }  // end processBlock
02916 
02917 
02918 
02919 unsigned PFAlgo::reconstructTrack( const reco::PFBlockElement& elt ) {
02920 
02921   const reco::PFBlockElementTrack* eltTrack 
02922     = dynamic_cast<const reco::PFBlockElementTrack*>(&elt);
02923 
02924   reco::TrackRef trackRef = eltTrack->trackRef();
02925   const reco::Track& track = *trackRef;
02926 
02927   reco::MuonRef muonRef = eltTrack->muonRef();
02928 
02929   int charge = track.charge()>0 ? 1 : -1;
02930 
02931   // Assign the pion mass to all charged particles
02932   double px = track.px();
02933   double py = track.py();
02934   double pz = track.pz();
02935   double energy = sqrt(track.p()*track.p() + 0.13957*0.13957);
02936 
02937 
02938   // Except if it is a muon, of course ! 
02939   bool thisIsAMuon = PFMuonAlgo::isMuon(elt);
02940   bool thisIsAnIsolatedMuon = PFMuonAlgo::isIsolatedMuon(elt);
02941   bool thisIsAGlobalTightMuon = PFMuonAlgo::isGlobalTightMuon(elt);
02942   bool thisIsATrackerTightMuon = PFMuonAlgo::isTrackerTightMuon(elt);
02943 
02944   // Or from nuclear inetraction then use the refitted momentum
02945   bool isFromDisp = isFromSecInt(elt, "secondary");
02946   bool isToDisp  = isFromSecInt(elt, "primary");
02947   //isFromNucl = false;
02948   bool globalFitUsed = false;
02949 
02950   if ( thisIsAMuon ) { 
02951     
02952     //By default take muon kinematics directly from the muon object (usually determined by the track) 
02953     px = muonRef->px();
02954     py = muonRef->py();
02955     pz = muonRef->pz();
02956     energy = sqrt(muonRef->p()*muonRef->p() + 0.1057*0.1057);
02957 
02958     reco::TrackBase::TrackQuality trackQualityHighPurity = TrackBase::qualityByName("highPurity");
02959     if(debug_)if(!trackRef->quality(trackQualityHighPurity))cout<<" Low Purity Track "<<endl;
02960 
02961     if(muonRef->isGlobalMuon() && !usePFMuonMomAssign_){
02962       
02963       reco::TrackRef bestMuTrack =  muonRef->muonBestTrack();
02964       if(!useBestMuonTrack_)
02965         bestMuTrack = muonRef->combinedMuon(); 
02966 
02967       // take the global fit instead under special circumstances
02968       bool useGlobalFit = false;
02969       
02970       if(thisIsAnIsolatedMuon && (!muonRef->isTrackerMuon() || (muonRef->pt() > bestMuTrack->pt() && track.ptError() > 5.0*bestMuTrack->ptError()))) useGlobalFit = true;
02971       else if(!trackRef->quality(trackQualityHighPurity)) useGlobalFit = true;
02972       else if(muonRef->pt() > bestMuTrack->pt() &&
02973               (track.hitPattern().numberOfValidTrackerHits() < 8 || track.hitPattern().numberOfValidPixelHits() == 0 ) &&
02974               track.ptError() > 5.0*bestMuTrack->ptError()) useGlobalFit = true;
02975 
02976       if(useGlobalFit){
02977         px = bestMuTrack->px();
02978         py = bestMuTrack->py();
02979         pz = bestMuTrack->pz();
02980         energy = sqrt(bestMuTrack->p()*bestMuTrack->p() + 0.1057*0.1057);   
02981         globalFitUsed = true;
02982       }
02983     }      
02984     else if(usePFMuonMomAssign_){
02985       // If this option is set we take more liberties choosing the muon kinematics (not advised by the muon POG)
02986       if(thisIsAGlobalTightMuon)
02987         {
02988           // If the global muon above 10 GeV and is a tracker muon take the global pT     
02989           if(muonRef->isTrackerMuon()){
02990             if(sqrt(px*px+py*py) > 10){
02991 
02992               reco::TrackRef bestMuTrack =  muonRef->muonBestTrack();
02993               if(!useBestMuonTrack_)
02994                 bestMuTrack = muonRef->combinedMuon(); 
02995               
02996               px = bestMuTrack->px();
02997               py = bestMuTrack->py();
02998               pz = bestMuTrack->pz();
02999               energy = sqrt(bestMuTrack->p()*bestMuTrack->p() + 0.1057*0.1057);   
03000               globalFitUsed = true;
03001             }
03002           }   // If it's not a tracker muon, choose between the global pT and the STA pT
03003           else{ 
03004             
03005             reco::TrackRef bestMuTrack = muonRef->combinedMuon()->normalizedChi2() < muonRef->standAloneMuon()->normalizedChi2() ?
03006               muonRef->muonBestTrack() : 
03007               muonRef->standAloneMuon() ;
03008             
03009             if(!useBestMuonTrack_)
03010               bestMuTrack =
03011                 muonRef->combinedMuon()->normalizedChi2() < muonRef->standAloneMuon()->normalizedChi2() ?
03012                 muonRef->combinedMuon() : 
03013                 muonRef->standAloneMuon() ;
03014 
03015             px = bestMuTrack->px();
03016             py = bestMuTrack->py();
03017             pz = bestMuTrack->pz();
03018             energy = sqrt(bestMuTrack->p()*bestMuTrack->p() + 0.1057*0.1057);   
03019             globalFitUsed = true;
03020           }
03021         } // close else if(thisIsAGlobalTightMuon)
03022     } // close (usePFPFMuonMomAssign_)      
03023   }// close if(thisIsAMuon)
03024   else if (isFromDisp) {
03025     double Dpt = trackRef->ptError();
03026     double dptRel = Dpt/trackRef->pt()*100;
03027     //If the track is ill measured it is better to not refit it, since the track information probably would not be used.
03028     //In the PFAlgo we use the trackref information. If the track error is too big the refitted information might be very different
03029     // from the not refitted one.
03030     if (dptRel < dptRel_DispVtx_){
03031 
03032       if (debug_) 
03033         cout << "Not refitted px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl; 
03034       //reco::TrackRef trackRef = eltTrack->trackRef();
03035       reco::PFDisplacedVertexRef vRef = eltTrack->displacedVertexRef(reco::PFBlockElement::T_FROM_DISP)->displacedVertexRef();
03036       reco::Track trackRefit = vRef->refittedTrack(trackRef);
03037       px = trackRefit.px();
03038       py = trackRefit.py();
03039       pz = trackRefit.pz();
03040       energy = sqrt(trackRefit.p()*trackRefit.p() + 0.13957*0.13957);
03041       if (debug_) 
03042         cout << "Refitted px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl; 
03043     
03044     }
03045   }
03046   
03047   if ((isFromDisp || isToDisp) && debug_) cout << "Final px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl; 
03048 
03049   // Create a PF Candidate
03050   math::XYZTLorentzVector momentum(px,py,pz,energy);
03051   reco::PFCandidate::ParticleType particleType 
03052     = reco::PFCandidate::h;
03053 
03054   // Add it to the stack
03055   pfCandidates_->push_back( PFCandidate( charge, 
03056                                          momentum,
03057                                          particleType ) );
03058 
03059   // displaced vertices 
03060   if( isFromDisp ) {
03061     pfCandidates_->back().setFlag( reco::PFCandidate::T_FROM_DISP, true);
03062     pfCandidates_->back().setDisplacedVertexRef( eltTrack->displacedVertexRef(reco::PFBlockElement::T_FROM_DISP)->displacedVertexRef(), reco::PFCandidate::T_FROM_DISP);
03063   }
03064   
03065   // do not label as primary a track which would be recognised as a muon. A muon cannot produce NI. It is with high probability a fake
03066   if( isToDisp && !thisIsAMuon ) {
03067     pfCandidates_->back().setFlag( reco::PFCandidate::T_TO_DISP, true);
03068     pfCandidates_->back().setDisplacedVertexRef( eltTrack->displacedVertexRef(reco::PFBlockElement::T_TO_DISP)->displacedVertexRef(), reco::PFCandidate::T_TO_DISP);
03069   }
03070 
03071 
03072 
03073   if ( thisIsAMuon && globalFitUsed ) 
03074     pfCandidates_->back().setVertexSource(  PFCandidate::kComMuonVertex );
03075   else
03076     pfCandidates_->back().setVertexSource( PFCandidate::kTrkVertex );
03077 
03078   pfCandidates_->back().setTrackRef( trackRef );
03079   pfCandidates_->back().setPositionAtECALEntrance( eltTrack->positionAtECALEntrance());
03080 
03081 
03082 
03083   // setting the muon ref if there is
03084   if (muonRef.isNonnull()) {
03085     pfCandidates_->back().setMuonRef( muonRef );
03086     // setting the muon particle type if it is a global muon
03087     if ( thisIsAMuon) {
03088       particleType = reco::PFCandidate::mu;
03089       pfCandidates_->back().setParticleType( particleType );
03090       if (debug_) {
03091         if(thisIsAGlobalTightMuon) cout << "PFAlgo: particle type set to muon (global, tight), pT = " <<muonRef->pt()<< endl; 
03092         else if(thisIsATrackerTightMuon) cout << "PFAlgo: particle type set to muon (tracker, tight), pT = " <<muonRef->pt()<< endl;
03093         else if(thisIsAnIsolatedMuon) cout << "PFAlgo: particle type set to muon (isolated), pT = " <<muonRef->pt()<< endl; 
03094         else cout<<" problem with muon assignment "<<endl;
03095         PFMuonAlgo::printMuonProperties( muonRef );
03096       }
03097     }
03098   }  
03099 
03100   // conversion...
03101 
03102   if(debug_) 
03103     cout<<"** candidate: "<<pfCandidates_->back()<<endl; 
03104   
03105   // returns index to the newly created PFCandidate
03106   return pfCandidates_->size()-1;
03107 }
03108 
03109 
03110 
03111 
03112 
03113 unsigned 
03114 PFAlgo::reconstructCluster(const reco::PFCluster& cluster,
03115                            double particleEnergy, 
03116                            bool useDirection, 
03117                            double particleX,
03118                            double particleY, 
03119                            double particleZ) {
03120   
03121   reco::PFCandidate::ParticleType particleType = reco::PFCandidate::X;
03122 
03123   // need to convert the math::XYZPoint data member of the PFCluster class=
03124   // to a displacement vector: 
03125 
03126   // Transform particleX,Y,Z to a position at ECAL/HCAL entrance
03127   double factor = 1.;
03128   if ( useDirection ) { 
03129     switch( cluster.layer() ) {
03130     case PFLayer::ECAL_BARREL:
03131     case PFLayer::HCAL_BARREL1:
03132       factor = std::sqrt(cluster.position().Perp2()/(particleX*particleX+particleY*particleY));
03133       break;
03134     case PFLayer::ECAL_ENDCAP:
03135     case PFLayer::HCAL_ENDCAP:
03136     case PFLayer::HF_HAD:
03137     case PFLayer::HF_EM:
03138       factor = cluster.position().Z()/particleZ;
03139       break;
03140     default:
03141       assert(0);
03142     }
03143   }
03144   //MIKE First of all let's check if we have vertex.
03145   math::XYZPoint vertexPos; 
03146   if(useVertices_)
03147     vertexPos = math::XYZPoint(primaryVertex_.x(),primaryVertex_.y(),primaryVertex_.z());
03148   else
03149     vertexPos = math::XYZPoint(0.0,0.0,0.0);
03150 
03151 
03152   math::XYZVector clusterPos( cluster.position().X()-vertexPos.X(), 
03153                               cluster.position().Y()-vertexPos.Y(),
03154                               cluster.position().Z()-vertexPos.Z());
03155   math::XYZVector particleDirection ( particleX*factor-vertexPos.X(), 
03156                                       particleY*factor-vertexPos.Y(), 
03157                                       particleZ*factor-vertexPos.Z() );
03158 
03159   //math::XYZVector clusterPos( cluster.position().X(), cluster.position().Y(),cluster.position().Z() );
03160   //math::XYZVector particleDirection ( particleX, particleY, particleZ );
03161 
03162   clusterPos = useDirection ? particleDirection.Unit() : clusterPos.Unit();
03163   clusterPos *= particleEnergy;
03164 
03165   // clusterPos is now a vector along the cluster direction, 
03166   // with a magnitude equal to the cluster energy.
03167   
03168   double mass = 0;
03169   ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> > 
03170     momentum( clusterPos.X(), clusterPos.Y(), clusterPos.Z(), mass); 
03171   // mathcore is a piece of #$%
03172   math::XYZTLorentzVector  tmp;
03173   // implicit constructor not allowed
03174   tmp = momentum;
03175 
03176   // Charge
03177   int charge = 0;
03178 
03179   // Type
03180   switch( cluster.layer() ) {
03181   case PFLayer::ECAL_BARREL:
03182   case PFLayer::ECAL_ENDCAP:
03183     particleType = PFCandidate::gamma;
03184     break;
03185   case PFLayer::HCAL_BARREL1:
03186   case PFLayer::HCAL_ENDCAP:    
03187     particleType = PFCandidate::h0;
03188     break;
03189   case PFLayer::HF_HAD:
03190     particleType = PFCandidate::h_HF;
03191     break;
03192   case PFLayer::HF_EM:
03193     particleType = PFCandidate::egamma_HF;
03194     break;
03195   default:
03196     assert(0);
03197   }
03198 
03199   // The pf candidate
03200   pfCandidates_->push_back( PFCandidate( charge, 
03201                                          tmp, 
03202                                          particleType ) );
03203 
03204   // The position at ECAL entrance (well: watch out, it is not true
03205   // for HCAL clusters... to be fixed)
03206   pfCandidates_->back().
03207     setPositionAtECALEntrance(math::XYZPointF(cluster.position().X(),
03208                                               cluster.position().Y(),
03209                                               cluster.position().Z()));
03210 
03211   //Set the cnadidate Vertex
03212   pfCandidates_->back().setVertex(vertexPos);  
03213 
03214   if(debug_) 
03215     cout<<"** candidate: "<<pfCandidates_->back()<<endl; 
03216 
03217   // returns index to the newly created PFCandidate
03218   return pfCandidates_->size()-1;
03219 
03220 }
03221 
03222 
03223 //GMA need the followign two for HO also
03224 
03225 double 
03226 PFAlgo::neutralHadronEnergyResolution(double clusterEnergyHCAL, double eta) const {
03227 
03228   // Add a protection
03229   if ( clusterEnergyHCAL < 1. ) clusterEnergyHCAL = 1.;
03230 
03231   double resol =  fabs(eta) < 1.48 ? 
03232     sqrt (1.02*1.02/clusterEnergyHCAL + 0.065*0.065)
03233     :
03234     sqrt (1.20*1.20/clusterEnergyHCAL + 0.028*0.028);
03235 
03236   return resol;
03237 
03238 }
03239 
03240 double
03241 PFAlgo::nSigmaHCAL(double clusterEnergyHCAL, double eta) const {
03242   double nS = fabs(eta) < 1.48 ? 
03243     nSigmaHCAL_ * (1. + exp(-clusterEnergyHCAL/100.))     
03244     :
03245     nSigmaHCAL_ * (1. + exp(-clusterEnergyHCAL/100.));     
03246   
03247   return nS;
03248 }
03249 
03250 
03251 ostream& operator<<(ostream& out, const PFAlgo& algo) {
03252   if(!out ) return out;
03253 
03254   out<<"====== Particle Flow Algorithm ======= ";
03255   out<<endl;
03256   out<<"nSigmaECAL_     "<<algo.nSigmaECAL_<<endl;
03257   out<<"nSigmaHCAL_     "<<algo.nSigmaHCAL_<<endl;
03258   out<<endl;
03259   out<<(*(algo.calibration_))<<endl;
03260   out<<endl;
03261   out<<"reconstructed particles: "<<endl;
03262    
03263   const std::auto_ptr< reco::PFCandidateCollection >& 
03264     candidates = algo.pfCandidates(); 
03265 
03266   if(!candidates.get() ) {
03267     out<<"candidates already transfered"<<endl;
03268     return out;
03269   }
03270   for(PFCandidateConstIterator ic=algo.pfCandidates_->begin(); 
03271       ic != algo.pfCandidates_->end(); ic++) {
03272     out<<(*ic)<<endl;
03273   }
03274 
03275   return out;
03276 }
03277 
03278 reco::PFBlockRef 
03279 PFAlgo::createBlockRef( const reco::PFBlockCollection& blocks, 
03280                         unsigned bi ) {
03281 
03282   if( blockHandle_.isValid() ) {
03283     return reco::PFBlockRef(  blockHandle_, bi );
03284   } 
03285   else {
03286     return reco::PFBlockRef(  &blocks, bi );
03287   }
03288 }
03289 
03290 void 
03291 PFAlgo::associatePSClusters(unsigned iEcal,
03292                             reco::PFBlockElement::Type psElementType,
03293                             const reco::PFBlock& block,
03294                             const edm::OwnVector< reco::PFBlockElement >& elements, 
03295                             const reco::PFBlock::LinkData& linkData,
03296                             std::vector<bool>& active, 
03297                             std::vector<double>& psEne) {
03298 
03299   // Find all PS clusters with type psElement associated to ECAL cluster iEcal, 
03300   // within all PFBlockElement "elements" of a given PFBlock "block"
03301   // psElement can be reco::PFBlockElement::PS1 or reco::PFBlockElement::PS2
03302   // Returns a vector of PS cluster energies, and updates the "active" vector.
03303 
03304   // Find all PS clusters linked to the iEcal cluster
03305   std::multimap<double, unsigned> sortedPS;
03306   typedef std::multimap<double, unsigned>::iterator IE;
03307   block.associatedElements( iEcal,  linkData,
03308                             sortedPS, psElementType,
03309                             reco::PFBlock::LINKTEST_ALL );
03310 
03311   // Loop over these PS clusters
03312   double totalPS = 0.;
03313   for ( IE ips=sortedPS.begin(); ips!=sortedPS.end(); ++ips ) {
03314 
03315     // CLuster index and distance to iEcal
03316     unsigned iPS = ips->second;
03317     // double distPS = ips->first;
03318 
03319     // Ignore clusters already in use
03320     if (!active[iPS]) continue;
03321 
03322     // Check that this cluster is not closer to another ECAL cluster
03323     std::multimap<double, unsigned> sortedECAL;
03324     block.associatedElements( iPS,  linkData,
03325                               sortedECAL,
03326                               reco::PFBlockElement::ECAL,
03327                               reco::PFBlock::LINKTEST_ALL );
03328     unsigned jEcal = sortedECAL.begin()->second;
03329     if ( jEcal != iEcal ) continue; 
03330     
03331     // Update PS energy
03332     PFBlockElement::Type pstype = elements[ iPS ].type();
03333     assert( pstype == psElementType );
03334     PFClusterRef psclusterref = elements[iPS].clusterRef();
03335     assert(!psclusterref.isNull() );
03336     totalPS += psclusterref->energy(); 
03337     psEne[0] += psclusterref->energy();
03338     active[iPS] = false;
03339   }
03340             
03341 
03342 }
03343 
03344 
03345 bool
03346 PFAlgo::isFromSecInt(const reco::PFBlockElement& eTrack, string order) const {
03347 
03348   reco::PFBlockElement::TrackType T_TO_DISP = reco::PFBlockElement::T_TO_DISP;
03349   reco::PFBlockElement::TrackType T_FROM_DISP = reco::PFBlockElement::T_FROM_DISP;
03350   //  reco::PFBlockElement::TrackType T_FROM_GAMMACONV = reco::PFBlockElement::T_FROM_GAMMACONV;
03351   reco::PFBlockElement::TrackType T_FROM_V0 = reco::PFBlockElement::T_FROM_V0;
03352 
03353   bool bPrimary = (order.find("primary") != string::npos);
03354   bool bSecondary = (order.find("secondary") != string::npos);
03355   bool bAll = (order.find("all") != string::npos);
03356 
03357   bool isToDisp = usePFNuclearInteractions_ && eTrack.trackType(T_TO_DISP);
03358   bool isFromDisp = usePFNuclearInteractions_ && eTrack.trackType(T_FROM_DISP);
03359 
03360   if (bPrimary && isToDisp) return true;
03361   if (bSecondary && isFromDisp ) return true;
03362   if (bAll && ( isToDisp || isFromDisp ) ) return true;
03363 
03364 //   bool isFromConv = usePFConversions_ && eTrack.trackType(T_FROM_GAMMACONV);
03365 
03366 //   if ((bAll || bSecondary)&& isFromConv) return true;
03367 
03368   bool isFromDecay = (bAll || bSecondary) && usePFDecays_ && eTrack.trackType(T_FROM_V0);
03369 
03370   return isFromDecay;
03371 
03372 
03373 }
03374 
03375 
03376 void  
03377 PFAlgo::setEGElectronCollection(const reco::GsfElectronCollection & egelectrons) {
03378   if(useEGElectrons_ && pfele_) pfele_->setEGElectronCollection(egelectrons);
03379 }
03380 
03381 void 
03382 PFAlgo::postCleaning() { 
03383   
03384   // Check if the post HF Cleaning was requested - if not, do nothing
03385   if ( !postHFCleaning_ ) return;
03386 
03387   //Compute met and met significance (met/sqrt(SumEt))
03388   double metX = 0.;
03389   double metY = 0.;
03390   double sumet = 0;
03391   std::vector<unsigned int> pfCandidatesToBeRemoved;
03392   for(unsigned i=0; i<pfCandidates_->size(); i++) {
03393     const PFCandidate& pfc = (*pfCandidates_)[i];
03394     metX += pfc.px();
03395     metY += pfc.py();
03396     sumet += pfc.pt();
03397   }    
03398   double met2 = metX*metX+metY*metY;
03399   // Select events with large MET significance.
03400   double significance = std::sqrt(met2/sumet);
03401   double significanceCor = significance;
03402   if ( significance > minSignificance_ ) { 
03403     
03404     double metXCor = metX;
03405     double metYCor = metY;
03406     double sumetCor = sumet;
03407     double met2Cor = met2;
03408     double deltaPhi = 3.14159;
03409     double deltaPhiPt = 100.;
03410     bool next = true;
03411     unsigned iCor = 1E9;
03412 
03413     // Find the HF candidate with the largest effect on the MET
03414     while ( next ) { 
03415 
03416       double metReduc = -1.;
03417       // Loop on the candidates
03418       for(unsigned i=0; i<pfCandidates_->size(); ++i) {
03419         const PFCandidate& pfc = (*pfCandidates_)[i];
03420 
03421         // Check that the pfCandidate is in the HF
03422         if ( pfc.particleId() != reco::PFCandidate::h_HF && 
03423              pfc.particleId() != reco::PFCandidate::egamma_HF ) continue;
03424 
03425         // Check if has meaningful pt
03426         if ( pfc.pt() < minHFCleaningPt_ ) continue;
03427         
03428         // Check that it is  not already scheculed to be cleaned
03429         bool skip = false;
03430         for(unsigned j=0; j<pfCandidatesToBeRemoved.size(); ++j) {
03431           if ( i == pfCandidatesToBeRemoved[j] ) skip = true;
03432           if ( skip ) break;
03433         }
03434         if ( skip ) continue;
03435         
03436         // Check that the pt and the MET are aligned
03437         deltaPhi = std::acos((metX*pfc.px()+metY*pfc.py())/(pfc.pt()*std::sqrt(met2)));
03438         deltaPhiPt = deltaPhi*pfc.pt();
03439         if ( deltaPhiPt > maxDeltaPhiPt_ ) continue;
03440 
03441         // Now remove the candidate from the MET
03442         double metXInt = metX - pfc.px();
03443         double metYInt = metY - pfc.py();
03444         double sumetInt = sumet - pfc.pt();
03445         double met2Int = metXInt*metXInt+metYInt*metYInt;
03446         if ( met2Int < met2Cor ) {
03447           metXCor = metXInt;
03448           metYCor = metYInt;
03449           metReduc = (met2-met2Int)/met2Int; 
03450           met2Cor = met2Int;
03451           sumetCor = sumetInt;
03452           significanceCor = std::sqrt(met2Cor/sumetCor);
03453           iCor = i;
03454         }
03455       }
03456       //
03457       // If the MET must be significanly reduced, schedule the candidate to be cleaned
03458       if ( metReduc > minDeltaMet_ ) { 
03459         pfCandidatesToBeRemoved.push_back(iCor);
03460         metX = metXCor;
03461         metY = metYCor;
03462         sumet = sumetCor;
03463         met2 = met2Cor;
03464       } else { 
03465       // Otherwise just stop the loop
03466         next = false;
03467       }
03468     }
03469     //
03470     // The significance must be significantly reduced to indeed clean the candidates
03471     if ( significance - significanceCor > minSignificanceReduction_ && 
03472          significanceCor < maxSignificance_ ) {
03473       std::cout << "Significance reduction = " << significance << " -> " 
03474                 << significanceCor << " = " << significanceCor - significance 
03475                 << std::endl;
03476       for(unsigned j=0; j<pfCandidatesToBeRemoved.size(); ++j) {
03477         std::cout << "Removed : " << (*pfCandidates_)[pfCandidatesToBeRemoved[j]] << std::endl;
03478         pfCleanedCandidates_->push_back( (*pfCandidates_)[ pfCandidatesToBeRemoved[j] ] );
03479         (*pfCandidates_)[pfCandidatesToBeRemoved[j]].rescaleMomentum(1E-6);
03480         //reco::PFCandidate::ParticleType unknown = reco::PFCandidate::X;
03481         //(*pfCandidates_)[pfCandidatesToBeRemoved[j]].setParticleType(unknown);
03482       }
03483     }
03484   }
03485 
03486 }
03487 
03488 void 
03489 PFAlgo::checkCleaning( const reco::PFRecHitCollection& cleanedHits ) { 
03490   
03491 
03492   // No hits to recover, leave.
03493   if ( !cleanedHits.size() ) return;
03494 
03495   //Compute met and met significance (met/sqrt(SumEt))
03496   double metX = 0.;
03497   double metY = 0.;
03498   double sumet = 0;
03499   std::vector<unsigned int> hitsToBeAdded;
03500   for(unsigned i=0; i<pfCandidates_->size(); i++) {
03501     const PFCandidate& pfc = (*pfCandidates_)[i];
03502     metX += pfc.px();
03503     metY += pfc.py();
03504     sumet += pfc.pt();
03505   }
03506   double met2 = metX*metX+metY*metY;
03507   double met2_Original = met2;
03508   // Select events with large MET significance.
03509   // double significance = std::sqrt(met2/sumet);
03510   // double significanceCor = significance;
03511   double metXCor = metX;
03512   double metYCor = metY;
03513   double sumetCor = sumet;
03514   double met2Cor = met2;
03515   bool next = true;
03516   unsigned iCor = 1E9;
03517   
03518   // Find the cleaned hit with the largest effect on the MET
03519   while ( next ) { 
03520     
03521     double metReduc = -1.;
03522     // Loop on the candidates
03523     for(unsigned i=0; i<cleanedHits.size(); ++i) {
03524       const PFRecHit& hit = cleanedHits[i];
03525       double length = std::sqrt(hit.position().Mag2()); 
03526       double px = hit.energy() * hit.position().x()/length;
03527       double py = hit.energy() * hit.position().y()/length;
03528       double pt = std::sqrt(px*px + py*py);
03529       
03530       // Check that it is  not already scheculed to be cleaned
03531       bool skip = false;
03532       for(unsigned j=0; j<hitsToBeAdded.size(); ++j) {
03533         if ( i == hitsToBeAdded[j] ) skip = true;
03534         if ( skip ) break;
03535       }
03536       if ( skip ) continue;
03537       
03538       // Now add the candidate to the MET
03539       double metXInt = metX + px;
03540       double metYInt = metY + py;
03541       double sumetInt = sumet + pt;
03542       double met2Int = metXInt*metXInt+metYInt*metYInt;
03543 
03544       // And check if it could contribute to a MET reduction
03545       if ( met2Int < met2Cor ) {
03546         metXCor = metXInt;
03547         metYCor = metYInt;
03548         metReduc = (met2-met2Int)/met2Int; 
03549         met2Cor = met2Int;
03550         sumetCor = sumetInt;
03551         // significanceCor = std::sqrt(met2Cor/sumetCor);
03552         iCor = i;
03553       }
03554     }
03555     //
03556     // If the MET must be significanly reduced, schedule the candidate to be added
03557     //
03558     if ( metReduc > minDeltaMet_ ) { 
03559       hitsToBeAdded.push_back(iCor);
03560       metX = metXCor;
03561       metY = metYCor;
03562       sumet = sumetCor;
03563       met2 = met2Cor;
03564     } else { 
03565       // Otherwise just stop the loop
03566       next = false;
03567     }
03568   }
03569   //
03570   // At least 10 GeV MET reduction
03571   if ( std::sqrt(met2_Original) - std::sqrt(met2) > 5. ) { 
03572     if ( debug_ ) { 
03573       std::cout << hitsToBeAdded.size() << " hits were re-added " << std::endl;
03574       std::cout << "MET reduction = " << std::sqrt(met2_Original) << " -> " 
03575                 << std::sqrt(met2Cor) << " = " <<  std::sqrt(met2Cor) - std::sqrt(met2_Original)  
03576                 << std::endl;
03577       std::cout << "Added after cleaning check : " << std::endl; 
03578     }
03579     for(unsigned j=0; j<hitsToBeAdded.size(); ++j) {
03580       const PFRecHit& hit = cleanedHits[hitsToBeAdded[j]];
03581       PFCluster cluster(hit.layer(), hit.energy(),
03582                         hit.position().x(), hit.position().y(), hit.position().z() );
03583       reconstructCluster(cluster,hit.energy());
03584       if ( debug_ ) { 
03585         std::cout << pfCandidates_->back() << ". time = " << hit.time() << std::endl;
03586       }
03587     }
03588   }
03589 
03590 }
03591 
03592 
03593 void 
03594 PFAlgo::postMuonCleaning( const edm::Handle<reco::MuonCollection>& muonh,
03595                           const reco::VertexCollection& primaryVertices) {
03596   
03597 
03598   bool printout = false;
03599   // Check if the post muon Cleaning was requested - if not, do nothing
03600   //if ( !postMuonCleaning_ ) return;
03601 
03602   // Estimate SumEt from pile-up
03603   double sumetPU = 0.;
03604   for (unsigned short i=1 ;i<primaryVertices.size();++i ) {
03605     if ( !primaryVertices[i].isValid() || primaryVertices[i].isFake() ) continue; 
03606     primaryVertices[i];
03607     for ( reco::Vertex::trackRef_iterator itr = primaryVertices[i].tracks_begin();
03608           itr <  primaryVertices[i].tracks_end(); ++itr ) { 
03609       sumetPU += (*itr)->pt();
03610     }
03611   }
03612   sumetPU /= 0.65; // To estimate the neutral contribution from PU
03613   // std::cout << "Evaluation of sumetPU from " << primaryVertices.size() << " vertices : " << sumetPU << std::endl;
03614 
03615   //Compute met and met significance (met/sqrt(SumEt))
03616   double metX = 0.;
03617   double metY = 0.;
03618   double sumet = 0;
03619   double metXCosmics = 0.;
03620   double metYCosmics = 0.;
03621   double sumetCosmics = 0.;
03622 
03623   std::map<double,unsigned int> pfMuons;
03624   std::map<double,unsigned int> pfCosmics;
03625   typedef std::multimap<double, unsigned int>::iterator IE;
03626 
03627   for(unsigned i=0; i<pfCandidates_->size(); i++) {
03628     const PFCandidate& pfc = (*pfCandidates_)[i];
03629     double origin = 
03630       (pfc.vx()-primaryVertex_.x())*(pfc.vx()-primaryVertex_.x()) + 
03631       (pfc.vy()-primaryVertex_.y())*(pfc.vy()-primaryVertex_.y());
03632 
03633     // Compute MET
03634     metX += pfc.px();
03635     metY += pfc.py();
03636     sumet += pfc.pt();
03637 
03638     // Remember the muons and order them by decreasing energy
03639     // Remember the cosmic muons too 
03640     if ( pfc.particleId() == reco::PFCandidate::mu ) { 
03641       pfMuons.insert(std::pair<double,unsigned int>(-pfc.pt(),i));
03642       if ( origin > 1.0 ) { 
03643         pfCosmics.insert(std::pair<double,unsigned int>(-pfc.pt(),i));
03644         metXCosmics += pfc.px();
03645         metYCosmics += pfc.py();
03646         sumetCosmics += pfc.pt();
03647       }
03648     }
03649       
03650   }
03651 
03652   double met2 = metX*metX+metY*metY;
03653   double met2Cosmics = (metX-metXCosmics)*(metX-metXCosmics)+(metY-metYCosmics)*(metY-metYCosmics);
03654 
03655   // Clean cosmic muons
03656   if ( sumetCosmics > (sumet-sumetPU)/10. && met2Cosmics < met2 ) { 
03657     if ( printout ) 
03658       std::cout << "MEX,MEY,MET Before (Cosmics)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03659     for ( IE imu = pfCosmics.begin(); imu != pfCosmics.end(); ++imu ) { 
03660       const PFCandidate& pfc = (*pfCandidates_)[imu->second];
03661       //const PFCandidate pfcopy = pfc;
03662       pfCosmicsMuonCleanedCandidates_->push_back(pfc);
03663       if ( printout ) 
03664         std::cout << "Muon cleaned (cosmic). pt/d0 = " << pfc.pt() << " " 
03665                   << std::sqrt(pfc.vx()*pfc.vx() + pfc.vy()*pfc.vy()) << std::endl; 
03666       metX -= pfc.px();
03667       metY -= pfc.py();
03668       sumet -= pfc.pt();
03669       (*pfCandidates_)[imu->second].rescaleMomentum(1E-6);
03670     }
03671     met2 = metX*metX+metY*metY;
03672     if ( printout ) 
03673       std::cout << "MEX,MEY,MET After  (Cosmics)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03674   }
03675 
03676   // The remaining met
03677   // double metInitial = std::sqrt(met2);
03678   
03679   // Clean mismeasured muons
03680   for ( IE imu = pfMuons.begin(); imu != pfMuons.end(); ++imu ) { 
03681     const PFCandidate& pfc = (*pfCandidates_)[imu->second];
03682 
03683     // Don't care about low momentum muons
03684     if ( pfc.pt() < 20. ) continue;
03685 
03686     double metXNO = metX - pfc.px();
03687     double metYNO = metY - pfc.py();
03688     double met2NO = metXNO*metXNO + metYNO*metYNO; 
03689     double sumetNO = sumet - pfc.pt();
03690     double factor = std::max(2.,2000./sumetNO);
03691 
03692     reco::MuonRef muonRef = pfc.muonRef();
03693     reco::TrackRef bestMuTrack =  muonRef->muonBestTrack();
03694     if(!useBestMuonTrack_)
03695       bestMuTrack = muonRef->combinedMuon(); 
03696     reco::TrackRef trackerMu = muonRef->track();
03697     reco::TrackRef standAloneMu = muonRef->standAloneMuon();
03698 
03699     if ( !bestMuTrack || !trackerMu ) { 
03700       if ( sumetNO-sumetPU > 500. && met2NO < met2/4.) { 
03701         pfFakeMuonCleanedCandidates_->push_back(pfc);
03702         if ( printout ) {
03703           std::cout << "Muon cleaned (NO-bad) " << sumetNO << std::endl;
03704           std::cout << "sumet NO " << sumetNO << std::endl;
03705         }
03706         (*pfCandidates_)[imu->second].rescaleMomentum(1E-6);
03707         if ( printout ) 
03708           std::cout << "MEX,MEY,MET            " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03709         metX = metXNO;
03710         metY = metYNO;
03711         met2 = met2NO;
03712         sumet = sumetNO;
03713         if ( printout ) {
03714           std::cout << "Muon cleaned (NO/TK) ! " << std::endl;
03715           std::cout << "MEX,MEY,MET Now (NO/TK)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03716         }
03717       }
03718     } else { 
03719       /*
03720       std::cout << "PF Muon vx,vy " << pfc.vx() << " " << pfc.vy() << std::endl;
03721       std::cout << "PF Muon px,py,pt: " << pfc.px() << " " << pfc.py() << " " << pfc.pt() << std::endl;
03722       std::cout << "TK Muon px,py,pt: " << trackerMu->px() << " " << trackerMu->py() << " " << trackerMu->pt() << " " << std::endl;
03723       std::cout << "GL Muon px,py,pt: " << bestMuTrack->px() << " " << bestMuTrack->py() << " " << bestMuTrack->pt() << " " << std::endl; 
03724       std::cout << "ST Muon px,py,pt: " << standAloneMu->px() << " " << standAloneMu->py() << " " << standAloneMu->pt() << " " << std::endl;
03725       std::cout << "isolated ? " << PFMuonAlgo::isIsolatedMuon(muonRef) << std::endl; 
03726       */
03727       double metXTK = metXNO + trackerMu->px(); 
03728       double metYTK = metYNO + trackerMu->py();
03729       double met2TK = metXTK*metXTK + metYTK*metYTK;
03730  
03731       double metXGL = metXNO + bestMuTrack->px();
03732       double metYGL = metYNO + bestMuTrack->py();
03733       double met2GL = metXGL*metXGL + metYGL*metYGL; 
03734 
03735       /*
03736       double metXST = metXNO + standAloneMu->px();
03737       double metYST = metYNO + standAloneMu->py();
03738       double met2ST = metXST*metXST + metYST*metYST; 
03739       */
03740 
03741       /*
03742       std::cout << "sumet NO " << sumetNO << std::endl;
03743       std::cout << "MEX,MEY,MET NO" << metXNO << " " << metYNO << " " << std::sqrt(met2NO) << std::endl;
03744       std::cout << "MEX,MEY,MET TK" << metXTK << " " << metYTK << " " << std::sqrt(met2TK) << std::endl;
03745       std::cout << "MEX,MEY,MET GL" << metXGL << " " << metYGL << " " << std::sqrt(met2GL) << std::endl;
03746       std::cout << "MEX,MEY,MET ST" << metXST << " " << metYST << " " << std::sqrt(met2ST) << std::endl;
03747       */
03748 
03749       //bool fixed = false;
03750       if ( ( sumetNO-sumetPU > 250. && met2TK < met2/4. && met2TK < met2GL ) || 
03751            ( met2TK < met2/2. && trackerMu->pt() < bestMuTrack->pt()/4. && met2TK < met2GL ) )  { 
03752         pfCleanedTrackerAndGlobalMuonCandidates_->push_back(pfc);
03753         math::XYZTLorentzVectorD p4(trackerMu->px(),trackerMu->py(),trackerMu->pz(),
03754                                     std::sqrt(trackerMu->p()*trackerMu->p()+0.1057*0.1057));
03755         if ( printout ) 
03756           std::cout << "Muon cleaned (TK) ! " << met2TK/met2 << " " << trackerMu->pt() / bestMuTrack->pt() << std::endl;
03757         (*pfCandidates_)[imu->second].setP4(p4);
03758         if ( printout ) 
03759           std::cout << "MEX,MEY,MET Before (TK)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03760         metX = metXTK;
03761         metY = metYTK;
03762         met2 = met2TK;
03763         //fixed = true;
03764         if ( printout ) 
03765           std::cout << "MEX,MEY,MET Now    (TK)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03766       } 
03767       
03768       else if ( ( sumetNO-sumetPU > 250. && met2GL < met2/4. && met2GL < met2TK ) ||  
03769                 ( met2GL < met2/2. && bestMuTrack->pt() < trackerMu->pt()/4.&& met2GL < met2TK ) )  { 
03770         pfCleanedTrackerAndGlobalMuonCandidates_->push_back(pfc);
03771         math::XYZTLorentzVectorD p4(bestMuTrack->px(),bestMuTrack->py(),bestMuTrack->pz(),
03772                                     std::sqrt(bestMuTrack->p()*bestMuTrack->p()+0.1057*0.1057));
03773         if ( printout ) 
03774           std::cout << "Muon cleaned (GL) ! " << met2GL/met2 << " " << bestMuTrack->pt()/trackerMu->pt() <<  std::endl;
03775         (*pfCandidates_)[imu->second].setP4(p4);
03776         if ( printout ) 
03777           std::cout << "MEX,MEY,MET before (GL)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03778         metX = metXGL;
03779         metY = metYGL;
03780         met2 = met2GL;
03781         //fixed = true;
03782         if ( printout ) 
03783           std::cout << "MEX,MEY,MET Now    (GL)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03784       }
03785 
03786       // Fake muons at large pseudo-rapidity
03787       bool fake = 
03788         fabs ( pfc.eta() ) > 2.15 && 
03789         met2NO < met2/25. && 
03790         (met2GL < met2TK/2. || met2TK < met2GL/2.) &&
03791         standAloneMu->pt() < bestMuTrack->pt()/10. &&
03792         standAloneMu->pt() < trackerMu->pt()/10.; 
03793 
03794       // Fake and/or punch-through candidates
03795       bool punchthrough1 =  
03796         ( sumetNO-sumetPU > 250. && met2NO < met2/4. && (met2GL < met2TK/factor || met2TK < met2GL/factor) );
03797 
03798       // Now look for punch through candidates (i.e., muon with large neutral hadron behind)
03799       bool punchthrough2 =  
03800         pfc.p() > 100. &&  pfc.rawHcalEnergy() > 100. && 
03801         pfc.rawEcalEnergy()+pfc.rawHcalEnergy() > pfc.p()/3. &&
03802         !PFMuonAlgo::isIsolatedMuon(muonRef) && met2NO < met2/4.;
03803 
03804       if ( punchthrough1 ||  punchthrough2 || fake ) { 
03805         
03806         // Find the block of the muon
03807         const PFCandidate::ElementsInBlocks& eleInBlocks = pfc.elementsInBlocks();
03808         if ( !eleInBlocks.size() ) { 
03809           ostringstream err;
03810           err<<"A muon has no associated elements in block. Cannot proceed with postMuonCleaning()";
03811           edm::LogError("PFAlgo")<<err.str()<<endl;
03812         } else { 
03813           PFBlockRef blockRefMuon = eleInBlocks[0].first;
03814           unsigned indexMuon = eleInBlocks[0].second;
03815           for ( unsigned iele = 1; iele < eleInBlocks.size(); ++iele ) { 
03816             indexMuon = eleInBlocks[iele].second;
03817             break;
03818           }
03819           
03820           // Check if the muon gave rise to a neutral hadron
03821           double iHad = 1E9;
03822           bool hadron = false;
03823           for ( unsigned i = imu->second+1; i < pfCandidates_->size(); ++i ) { 
03824             const PFCandidate& pfcn = (*pfCandidates_)[i];
03825             const PFCandidate::ElementsInBlocks& ele = pfcn.elementsInBlocks();
03826             if ( !ele.size() ) { 
03827               ostringstream err2;
03828               err2<<"A pfCandidate has no associated elements in block. Cannot proceed with postMuonCleaning()";
03829               edm::LogError("PFAlgo")<<err2.str()<<endl;
03830               continue;
03831             }
03832             PFBlockRef blockRefHadron = ele[0].first;
03833             unsigned indexHadron = ele[0].second;
03834             // We are out of the block -> exit the loop
03835             if ( blockRefHadron.key() != blockRefMuon.key() ) break;
03836             // Check that this particle is a neutral hadron
03837             if ( indexHadron == indexMuon && 
03838                  pfcn.particleId() == reco::PFCandidate::h0 ) {
03839               iHad = i;
03840               hadron = true;
03841             }
03842             if ( hadron ) break;
03843           }
03844           
03845           if ( hadron ) { 
03846             const PFCandidate& pfch = (*pfCandidates_)[iHad];
03847             pfPunchThroughMuonCleanedCandidates_->push_back(pfc);
03848             pfPunchThroughHadronCleanedCandidates_->push_back(pfch);
03849             if ( printout ) {
03850               std::cout << pfc << std::endl;
03851               std::cout << "Raw ecal/hcal : " << pfc.rawEcalEnergy() << " " << pfc.rawHcalEnergy() << std::endl;
03852               std::cout << "Hadron: " << (*pfCandidates_)[iHad] << std::endl;
03853             }
03854             double rescaleFactor = (*pfCandidates_)[iHad].p()/(*pfCandidates_)[imu->second].p();
03855             metX -=  (*pfCandidates_)[imu->second].px() + (*pfCandidates_)[iHad].px();
03856             metY -=  (*pfCandidates_)[imu->second].py() + (*pfCandidates_)[iHad].py();
03857             (*pfCandidates_)[imu->second].rescaleMomentum(rescaleFactor);
03858             (*pfCandidates_)[iHad].rescaleMomentum(1E-6);
03859             (*pfCandidates_)[imu->second].setParticleType(reco::PFCandidate::h);
03860             if ( printout ) 
03861               std::cout << "MEX,MEY,MET Before " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03862             metX +=  (*pfCandidates_)[imu->second].px();
03863             metY +=  (*pfCandidates_)[imu->second].py();          
03864             met2 = metX*metX + metY*metY;
03865             if ( printout ) {
03866               std::cout << "Muon changed to charged hadron" << std::endl;
03867               std::cout << "MEX,MEY,MET Now (NO)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03868             }
03869           } else if ( punchthrough1 || fake ) {
03870             const PFCandidate& pfc = (*pfCandidates_)[imu->second];
03871             pfFakeMuonCleanedCandidates_->push_back(pfc);
03872             if ( printout ) 
03873               std::cout << "MEX,MEY,MET Before " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03874             metX -=  (*pfCandidates_)[imu->second].px();
03875             metY -=  (*pfCandidates_)[imu->second].py();          
03876             met2 = metX*metX + metY*metY;
03877             (*pfCandidates_)[imu->second].rescaleMomentum(1E-6);
03878             if ( printout ) {
03879               std::cout << "Muon cleaned (NO)" << std::endl;
03880               std::cout << "MEX,MEY,MET Now (NO)" << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03881             }
03882           }
03883         }
03884       }
03885       /*
03886       if ( !fixed ) { 
03887         std::cout << "TK Muon px,py,pt: " << trackerMu->px() << " " << trackerMu->py() << " " << trackerMu->pt() << " " << std::endl;
03888         std::cout << "GL Muon px,py,pt: " << bestMuTrack->px() << " " << bestMuTrack->py() << " " << bestMuTrack->pt() << " " << std::endl;
03889         std::cout << "MEX,MEY,MET PF " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
03890         std::cout << "MEX,MEY,MET NO " << metXNO << " " << metYNO << " " << std::sqrt(met2NO) << std::endl;
03891         std::cout << "MEX,MEY,MET TK " << metXTK << " " << metYTK << " " << std::sqrt(met2TK) << std::endl;
03892         std::cout << "MEX,MEY,MET GL " << metXGL << " " << metYGL << " " << std::sqrt(met2GL) << std::endl;
03893       }
03894       */
03895     }
03896 
03897   }
03898 
03899   // And now, add muons which did not make it for various reasons
03900   for ( unsigned imu = 0; imu < muonh->size(); ++imu ) {
03901     reco::MuonRef muonRef( muonh, imu );
03902     // If not used, check its effect on met
03903     reco::TrackRef bestMuTrack =  muonRef->muonBestTrack();
03904     if(!useBestMuonTrack_)
03905       bestMuTrack = muonRef->combinedMuon(); 
03906     reco::TrackRef trackerMu = muonRef->track();
03907     reco::TrackRef standAloneMu = muonRef->standAloneMuon();
03908 
03909     // check if the muons has already been taken
03910     bool used = false;
03911     bool hadron = false;
03912     for(unsigned i=0; i<pfCandidates_->size(); i++) {
03913       const PFCandidate& pfc = (*pfCandidates_)[i];
03914       if ( !pfc.trackRef().isNonnull() ) continue;
03915 
03916       if ( pfc.trackRef().isNonnull() && pfc.trackRef() == trackerMu ) { 
03917         hadron = true;
03918       }
03919 
03920       // The pf candidate is not associated to a muon
03921       // if ( !pfc.muonRef().isNonnull() || pfc.muonRef() != muonRef ) continue; ! This test is buggy !     
03922       if ( !pfc.muonRef().isNonnull() ) continue;
03923       
03924       // Check if the muon is used... 
03925       if ( pfc.muonRef()->track() == trackerMu || pfc.muonRef()->combinedMuon() == bestMuTrack ) {
03926         if ( printout ) { 
03927           std::cout << "This muon is already used ..." << std::endl;
03928           std::cout << pfc << std::endl;
03929           std::cout << muonRef->p() << " " << muonRef->pt() << " " << muonRef->eta() << " " << muonRef->phi() << std::endl;
03930         }
03931         used = true;
03932       } 
03933       else {
03934         // Check if the stand-alone muon is not a spurious copy of an existing muon 
03935         // (Protection needed for HLT)
03936         if ( pfc.muonRef()->isStandAloneMuon() && muonRef->isStandAloneMuon() ) { 
03937           double dEta = pfc.muonRef()->standAloneMuon()->eta() - standAloneMu->eta();
03938           double dPhi = pfc.muonRef()->standAloneMuon()->phi() - standAloneMu->phi();
03939           double dR = sqrt(dEta*dEta + dPhi*dPhi);
03940           if ( printout ) { 
03941             std::cout << "StandAlone to be added ? " << std::endl;
03942             std::cout << " eta = " << pfc.muonRef()->standAloneMuon()->eta() << " " << standAloneMu->eta() << std::endl;
03943             std::cout << " phi = " << pfc.muonRef()->standAloneMuon()->phi() << " " << standAloneMu->phi() << std::endl;
03944             std::cout << " pt = " << pfc.muonRef()->standAloneMuon()->pt() << " " << standAloneMu->pt() << std::endl;
03945             std::cout << " Delta R = " << dR << std::endl;
03946           }
03947           if ( dR < 0.005 ) { 
03948             used = true;
03949             if ( printout ) std::cout << "Not removed !" << std::endl;
03950           }
03951         }
03952       } 
03953       if ( used ) break; 
03954 
03955     }
03956 
03957     if ( used ) continue;
03958 
03959     double ptGL = muonRef->isGlobalMuon() ? bestMuTrack->pt() : 0.;
03960     double pxGL = muonRef->isGlobalMuon() ? bestMuTrack->px() : 0.;
03961     double pyGL = muonRef->isGlobalMuon() ? bestMuTrack->py() : 0.;
03962     double pzGL = muonRef->isGlobalMuon() ? bestMuTrack->pz() : 0.;
03963 
03964     double ptTK = muonRef->isTrackerMuon() ? trackerMu->pt() : 0.;
03965     double pxTK = muonRef->isTrackerMuon() ? trackerMu->px() : 0.;
03966     double pyTK = muonRef->isTrackerMuon() ? trackerMu->py() : 0.;
03967     double pzTK = muonRef->isTrackerMuon() ? trackerMu->pz() : 0.;
03968 
03969     double ptST = muonRef->isStandAloneMuon() ? standAloneMu->pt() : 0.;
03970     double pxST = muonRef->isStandAloneMuon() ? standAloneMu->px() : 0.;
03971     double pyST = muonRef->isStandAloneMuon() ? standAloneMu->py() : 0.;
03972     double pzST = muonRef->isStandAloneMuon() ? standAloneMu->pz() : 0.;
03973 
03974     //std::cout << "pT TK/GL/ST : " << ptTK << " " << ptGL << " " << ptST << std::endl;
03975 
03976     double metXTK = metX + pxTK; 
03977     double metYTK = metY + pyTK;
03978     double met2TK = metXTK*metXTK + metYTK*metYTK;
03979     
03980     double metXGL = metX + pxGL;
03981     double metYGL = metY + pyGL;
03982     double met2GL = metXGL*metXGL + metYGL*metYGL; 
03983 
03984     double metXST = metX + pxST; 
03985     double metYST = metY + pyST;
03986     double met2ST = metXST*metXST + metYST*metYST;
03987 
03988     //std::cout << "met TK/GL/ST : " << sqrt(met2) << " " << sqrt(met2TK) << " " << sqrt(met2GL) << " " << sqrt(met2ST) << std::endl;
03989 
03990 
03991     if ( ptTK > 20. && met2TK < met2/4. && met2TK < met2GL && met2TK < met2ST ) { 
03992       double energy = std::sqrt(pxTK*pxTK+pyTK*pyTK+pzTK*pzTK+0.1057*0.1057);
03993       int charge = trackerMu->charge()>0 ? 1 : -1;
03994       math::XYZTLorentzVector momentum(pxTK,pyTK,pzTK,energy);
03995       reco::PFCandidate::ParticleType particleType = 
03996          ptGL > 20. ? reco::PFCandidate::mu : reco::PFCandidate::h;
03997       double radius = std::sqrt(
03998          (trackerMu->vertex().x()-primaryVertex_.x())*(trackerMu->vertex().x()-primaryVertex_.x())+
03999          (trackerMu->vertex().y()-primaryVertex_.y())*(trackerMu->vertex().y()-primaryVertex_.y()));
04000       
04001       // Add it to the stack ( if not already in the list ) 
04002       if ( !hadron && radius < 1.0 ) { 
04003         pfCandidates_->push_back( PFCandidate( charge, 
04004                                                momentum,
04005                                                particleType ) );
04006         
04007         pfCandidates_->back().setVertexSource( PFCandidate::kTrkMuonVertex );
04008         pfCandidates_->back().setTrackRef( trackerMu );
04009         pfCandidates_->back().setMuonRef( muonRef );
04010         
04011         if ( printout ) {
04012           std::cout << "MEX,MEY,MET before " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
04013           std::cout << "Muon TK added " << std::endl;
04014           std::cout << "pT TK/GL/ST : " << ptTK << " " << ptGL << " " << ptST << std::endl;
04015         }
04016         metX +=  pfCandidates_->back().px();
04017         metY +=  pfCandidates_->back().py();      
04018         met2 = metX*metX + metY*metY;
04019         if ( printout ) {
04020           std::cout <<  pfCandidates_->back() << std::endl;
04021           std::cout << "MEX,MEY,MET   now " << metX << " " << metY << " " << std::sqrt(met2) << std::endl; 
04022         }
04023 
04024         const PFCandidate& pfc = pfCandidates_->back();
04025         pfAddedMuonCandidates_->push_back(pfc);
04026 
04027       }
04028 
04029     } else  if (  ptGL > 20. && met2GL < met2/4. && met2GL < met2TK && met2GL < met2ST ) { 
04030 
04031       double energy = std::sqrt(pxGL*pxGL+pyGL*pyGL+pzGL*pzGL+0.1057*0.1057);
04032       int charge = bestMuTrack->charge()>0 ? 1 : -1;
04033       math::XYZTLorentzVector momentum(pxGL,pyGL,pzGL,energy);
04034       reco::PFCandidate::ParticleType particleType = reco::PFCandidate::mu;
04035       double radius = std::sqrt(
04036         (bestMuTrack->vertex().x()-primaryVertex_.x())*(bestMuTrack->vertex().x()-primaryVertex_.x())+
04037         (bestMuTrack->vertex().y()-primaryVertex_.y())*(bestMuTrack->vertex().y()-primaryVertex_.y()));
04038       
04039       // Add it to the stack
04040       if ( radius < 1.0 ) { 
04041         pfCandidates_->push_back( PFCandidate( charge, 
04042                                                momentum,
04043                                                particleType ) );
04044         
04045         pfCandidates_->back().setVertexSource( PFCandidate::kComMuonVertex );
04046         //if ( ptTK > 0. ) 
04047         if (trackerMu.isNonnull() ) pfCandidates_->back().setTrackRef( trackerMu );
04048         pfCandidates_->back().setMuonRef( muonRef );
04049         
04050         if ( printout ) {
04051           std::cout << "MEX,MEY,MET before " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
04052           std::cout << "Muon GL added " << std::endl;
04053           std::cout << "pT TK/GL/ST : " << ptTK << " " << ptGL << " " << ptST << std::endl;
04054         }
04055         
04056         metX +=  pfCandidates_->back().px();
04057         metY +=  pfCandidates_->back().py();      
04058         met2 = metX*metX + metY*metY;
04059         
04060         if ( printout ) {
04061           std::cout <<  pfCandidates_->back() << std::endl;
04062           std::cout << "MEX,MEY,MET   now " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
04063         }
04064 
04065         const PFCandidate& pfc = pfCandidates_->back();
04066         pfAddedMuonCandidates_->push_back(pfc);
04067 
04068       }
04069         
04070     } else  if ( ptST > 20. &&  met2ST < met2/4. && met2ST < met2TK && met2ST < met2GL ) { 
04071 
04072       double energy = std::sqrt(pxST*pxST+pyST*pyST+pzST*pzST+0.1057*0.1057);
04073       int charge = standAloneMu->charge()>0 ? 1 : -1;
04074       math::XYZTLorentzVector momentum(pxST,pyST,pzST,energy);
04075       reco::PFCandidate::ParticleType particleType = reco::PFCandidate::mu;
04076       double radius = std::sqrt(
04077         (standAloneMu->vertex().x()-primaryVertex_.x())*(standAloneMu->vertex().x()-primaryVertex_.x())+
04078         (standAloneMu->vertex().y()-primaryVertex_.y())*(standAloneMu->vertex().y()-primaryVertex_.y()));
04079       
04080       // Add it to the stack
04081       if ( radius < 1.0 ) { 
04082         pfCandidates_->push_back( PFCandidate( charge, 
04083                                                momentum,
04084                                                particleType ) );
04085         
04086         pfCandidates_->back().setVertexSource( PFCandidate::kSAMuonVertex);
04087         if (trackerMu.isNonnull() ) pfCandidates_->back().setTrackRef( trackerMu );
04088         pfCandidates_->back().setMuonRef( muonRef );
04089         
04090         if ( printout ) {
04091           std::cout << "MEX,MEY,MET before " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
04092           std::cout << "Muon ST added " << std::endl;
04093           std::cout << "pT TK/GL/ST : " << ptTK << " " << ptGL << " " << ptST << std::endl;
04094         }
04095 
04096         metX +=  pfCandidates_->back().px();
04097         metY +=  pfCandidates_->back().py();      
04098         met2 = metX*metX + metY*metY;
04099         
04100         if ( printout ) {
04101           std::cout <<  pfCandidates_->back() << std::endl;
04102           std::cout << "MEX,MEY,MET   now " << metX << " " << metY << " " << std::sqrt(met2) << std::endl;
04103         }
04104 
04105         const PFCandidate& pfc = pfCandidates_->back();
04106         pfAddedMuonCandidates_->push_back(pfc);
04107 
04108       }
04109     }
04110 
04111   }
04112 
04113   /*
04114   if ( std::sqrt(met2) > 500. ) { 
04115     std::cout << "MET initial : " << metInitial << std::endl;
04116     std::cout << "MET final : " << std::sqrt(met2) << std::endl;
04117   }
04118   */
04119 
04120 }
04121 
04122 void PFAlgo::setElectronExtraRef(const edm::OrphanHandle<reco::PFCandidateElectronExtraCollection >& extrah) {
04123   if(!usePFElectrons_) return;
04124   //  std::cout << " setElectronExtraRef " << std::endl;
04125   unsigned size=pfCandidates_->size();
04126 
04127   for(unsigned ic=0;ic<size;++ic) {
04128     // select the electrons and add the extra
04129     if((*pfCandidates_)[ic].particleId()==PFCandidate::e) {
04130       
04131       PFElectronExtraEqual myExtraEqual((*pfCandidates_)[ic].gsfTrackRef());
04132       std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
04133       if(it!=pfElectronExtra_.end()) {
04134         //      std::cout << " Index " << it-pfElectronExtra_.begin() << std::endl;
04135         reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
04136         (*pfCandidates_)[ic].setPFElectronExtraRef(theRef);
04137       }
04138       else {
04139         (*pfCandidates_)[ic].setPFElectronExtraRef(PFCandidateElectronExtraRef());
04140       }
04141     }
04142     else  // else save the mva and the extra as well ! 
04143       {
04144         if((*pfCandidates_)[ic].trackRef().isNonnull()) {
04145           PFElectronExtraKfEqual myExtraEqual((*pfCandidates_)[ic].trackRef());
04146           std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
04147           if(it!=pfElectronExtra_.end()) {
04148             (*pfCandidates_)[ic].set_mva_e_pi(it->mvaVariable(PFCandidateElectronExtra::MVA_MVA));
04149             reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
04150             (*pfCandidates_)[ic].setPFElectronExtraRef(theRef);
04151             (*pfCandidates_)[ic].setGsfTrackRef(it->gsfTrackRef());
04152           }     
04153         }
04154       }
04155 
04156   }
04157 
04158   size=pfElectronCandidates_->size();
04159   for(unsigned ic=0;ic<size;++ic) {
04160     // select the electrons - this test is actually not needed for this collection
04161     if((*pfElectronCandidates_)[ic].particleId()==PFCandidate::e) {
04162       // find the corresponding extra
04163       PFElectronExtraEqual myExtraEqual((*pfElectronCandidates_)[ic].gsfTrackRef());
04164       std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
04165       if(it!=pfElectronExtra_.end()) {
04166         reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
04167         (*pfElectronCandidates_)[ic].setPFElectronExtraRef(theRef);
04168 
04169       }
04170     }
04171   }
04172 
04173 }
04174 void PFAlgo::setPhotonExtraRef(const edm::OrphanHandle<reco::PFCandidatePhotonExtraCollection >& ph_extrah) {
04175   if(!usePFPhotons_) return;  
04176   unsigned int size=pfCandidates_->size();
04177   unsigned int sizePhExtra = pfPhotonExtra_.size();
04178   for(unsigned ic=0;ic<size;++ic) {
04179     // select the electrons and add the extra
04180     if((*pfCandidates_)[ic].particleId()==PFCandidate::gamma && (*pfCandidates_)[ic].mva_nothing_gamma() > 0.99) {
04181       if((*pfCandidates_)[ic].superClusterRef().isNonnull()) {
04182         bool found = false;
04183         for(unsigned pcextra=0;pcextra<sizePhExtra;++pcextra) {
04184           if((*pfCandidates_)[ic].superClusterRef() == pfPhotonExtra_[pcextra].superClusterRef()) {
04185             reco::PFCandidatePhotonExtraRef theRef(ph_extrah,pcextra);
04186             (*pfCandidates_)[ic].setPFPhotonExtraRef(theRef);
04187             found = true;
04188             break;
04189           }
04190         }
04191         if(!found) 
04192           (*pfCandidates_)[ic].setPFPhotonExtraRef((PFCandidatePhotonExtraRef())); // null ref
04193       }
04194       else {
04195         (*pfCandidates_)[ic].setPFPhotonExtraRef((PFCandidatePhotonExtraRef())); // null ref
04196       }
04197     }
04198   }      
04199 }