CMS 3D CMS Logo

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

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