CMS 3D CMS Logo

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