CMS 3D CMS Logo

PFAlgo.cc

Go to the documentation of this file.
00001 #include "RecoParticleFlow/PFAlgo/interface/PFAlgo.h"
00002 #include "RecoParticleFlow/PFAlgo/interface/PFElectronAlgo.h"  //PFElectrons
00003 #include "RecoParticleFlow/PFAlgo/interface/PFConversionAlgo.h"  // PFConversions
00004 
00005 #include "RecoParticleFlow/PFClusterTools/interface/PFEnergyCalibration.h"
00006 #include "RecoParticleFlow/PFClusterTools/interface/PFClusterCalibration.h" // Brand new cluster calibration !
00007 
00008 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h"
00009 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementTrack.h"
00010 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementCluster.h"
00011 #include "DataFormats/ParticleFlowReco/interface/PFRecTrack.h"
00012 #include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
00013 #include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
00014 
00015 #include "DataFormats/TrackReco/interface/Track.h"
00016 #include "DataFormats/MuonReco/interface/Muon.h"
00017 
00018 // #include "FWCore/Framework/interface/OrphanHandle.h"
00019 #include "DataFormats/Common/interface/OrphanHandle.h"
00020 // #include "DataFormats/Common/interface/ProductID.h"
00021 #include "DataFormats/Provenance/interface/ProductID.h"
00022 
00023 
00024 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00025 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h"
00026 
00027 #include "Math/PxPyPzM4D.h"
00028 #include "Math/LorentzVector.h"
00029 #include "Math/DisplacementVector3D.h"
00030 #include "Math/SMatrix.h"
00031 #include "TDecompChol.h"
00032 
00033 #include "boost/graph/adjacency_matrix.hpp" 
00034 #include "boost/graph/graph_utility.hpp" 
00035 
00036 using namespace std;
00037 using namespace reco;
00038 using namespace boost;
00039 
00040 float PFAlgo::maxMvaCut_ = PFCandidate::bigMva_;
00041 
00042 
00043 typedef std::list< reco::PFBlockRef >::iterator IBR;
00044 
00045 
00046 
00047 PFAlgo::PFAlgo()
00048   : pfCandidates_( new PFCandidateCollection),
00049     nSigmaECAL_(3), 
00050     nSigmaHCAL_(3),
00051     clusterRecovery_(false), 
00052     PSCut_(999.),
00053     mergedPhotonsMVA_( 0 ),
00054     mvaCut_(PFAlgo::maxMvaCut_),
00055     algo_(1),
00056     debug_(false),
00057     pfele_(0)
00058 {}
00059 
00060 PFAlgo::~PFAlgo() {
00061   if (usePFElectrons_) delete pfele_;
00062   if (usePFConversions_) delete pfConversion_;
00063 }
00064 
00065 
00066 void 
00067 PFAlgo::setParameters(double nSigmaECAL,
00068                       double nSigmaHCAL, 
00069                       const shared_ptr<PFEnergyCalibration>& calibration,
00070                       const shared_ptr<pftools::PFClusterCalibration>& clusterCalibration,
00071                       bool   newCalib,
00072                       bool   clusterRecovery,
00073                       double PSCut,
00074                       double mvaCut,
00075                       const  char* mvaWeightFile ) {
00076 
00077   nSigmaECAL_ = nSigmaECAL;
00078   nSigmaHCAL_ = nSigmaHCAL;
00079 
00080   calibration_ = calibration;
00081   clusterCalibration_ = clusterCalibration;
00082   newCalib_ = newCalib;
00083   
00084   // std::cout << "Cluster calibration parameters : " << *clusterCalibration_ << std::endl;
00085 
00086   clusterRecovery_ = clusterRecovery;
00087 
00088   PSCut_=PSCut;
00089   mvaCut_ = mvaCut;
00090   
00091   if( mergedPhotonsMVA_ ) delete mergedPhotonsMVA_;
00092   mergedPhotonsMVA_ = new TMVA::Reader();
00093   mergedPhotonsMVA_->AddVariable("eECAL/pTrack", &eECALOverpTrack_);
00094   mergedPhotonsMVA_->AddVariable("chi2ECAL", &chi2ECAL_);
00095   mergedPhotonsMVA_->AddVariable("ptTrack", &ptTrack_);
00096   
00097   if( mvaCut < PFAlgo::maxMvaCut_ ) {
00098     FILE * file = fopen(mvaWeightFile, "r");
00099     if (file) {
00100       fclose(file);
00101       // file is readable, book MVA
00102       mergedPhotonsMVA_->BookMVA( "MVA", mvaWeightFile );
00103     }
00104     else {
00105       // weight file is not readable
00106       string err = "PFAlgo: cannot open weight file '";
00107       err += mvaWeightFile;
00108       err += "'";
00109       throw invalid_argument( err );
00110     }
00111   }
00112 }
00113 
00114 //PFElectrons: a new method added to set the parameters for electron reconstruction. 
00115 void 
00116 PFAlgo::setPFEleParameters(double chi2EcalGSF,
00117                            double chi2EcalBrem,
00118                            double chi2HcalGSF,
00119                            double chi2HcalBrem,
00120                            double chi2PsGSF,
00121                            double chi2PsBrem,
00122                            double mvaEleCut,
00123                            string mvaWeightFileEleID,
00124                            bool usePFElectrons) {
00125   setchi2Values_.push_back(chi2EcalGSF);
00126   setchi2Values_.push_back(chi2EcalBrem);
00127   setchi2Values_.push_back(chi2HcalGSF);
00128   setchi2Values_.push_back(chi2HcalBrem);
00129   setchi2Values_.push_back(chi2PsGSF);
00130   setchi2Values_.push_back(chi2PsBrem);
00131 
00132   mvaEleCut_ = mvaEleCut;
00133   usePFElectrons_ = usePFElectrons;
00134   mvaWeightFileEleID_ = mvaWeightFileEleID;
00135   FILE * fileEleID = fopen(mvaWeightFileEleID_.c_str(), "r");
00136   if (fileEleID) {
00137     fclose(fileEleID);
00138   }
00139   else {
00140     string err = "PFAlgo: cannot open weight file '";
00141     err += mvaWeightFileEleID;
00142     err += "'";
00143     throw invalid_argument( err );
00144   }
00145   pfele_= new PFElectronAlgo(setchi2Values_,mvaEleCut_,mvaWeightFileEleID_);
00146 }
00147 
00148 
00149 void PFAlgo::setPFConversionParameters(bool usePFConversions ) {
00150 
00151   usePFConversions_ = usePFConversions;
00152   pfConversion_ = new PFConversionAlgo();
00153 
00154 
00155 }
00156 
00157 
00158 
00159 void PFAlgo::reconstructParticles( const reco::PFBlockHandle& blockHandle ) {
00160 
00161   blockHandle_ = blockHandle;
00162   reconstructParticles( *blockHandle_ ); 
00163 }
00164 
00165 
00166 
00167 void PFAlgo::reconstructParticles( const reco::PFBlockCollection& blocks ) {
00168 
00169   // reset output collection
00170   if(pfCandidates_.get() )
00171     pfCandidates_->clear();
00172   else 
00173     pfCandidates_.reset( new reco::PFCandidateCollection );
00174 
00175 
00176 
00177   if( debug_ ) {
00178     cout<<"*********************************************************"<<endl;
00179     cout<<"*****           Particle flow algorithm             *****"<<endl;
00180     cout<<"*********************************************************"<<endl;
00181   }
00182 
00183   // sort elements in three lists:
00184   std::list< reco::PFBlockRef > hcalBlockRefs;
00185   std::list< reco::PFBlockRef > ecalBlockRefs;
00186   std::list< reco::PFBlockRef > otherBlockRefs;
00187   
00188   for( unsigned i=0; i<blocks.size(); ++i ) {
00189     // reco::PFBlockRef blockref( blockh,i );
00190     reco::PFBlockRef blockref = createBlockRef( blocks, i);
00191     
00192     const reco::PFBlock& block = *blockref;
00193    const edm::OwnVector< reco::PFBlockElement >& 
00194       elements = block.elements();
00195         
00196     bool singleEcalOrHcal = false;
00197     if( elements.size() == 1 ){
00198       if( elements[0].type() == reco::PFBlockElement::ECAL ){
00199         ecalBlockRefs.push_back( blockref );
00200         singleEcalOrHcal = true;
00201       }
00202       if( elements[0].type() == reco::PFBlockElement::HCAL ){
00203         hcalBlockRefs.push_back( blockref );
00204         singleEcalOrHcal = true;
00205       }
00206     }      
00207     
00208     if(!singleEcalOrHcal) {
00209       otherBlockRefs.push_back( blockref );
00210     }
00211   }//loop blocks
00212   
00213   if( debug_ ){
00214     cout<<"# Ecal blocks: "<<ecalBlockRefs.size()
00215         <<", # Hcal blocks: "<<hcalBlockRefs.size()
00216         <<", # Other blocks: "<<otherBlockRefs.size()<<endl;
00217   }
00218 
00219 
00220   // loop on blocks that are not single ecal, 
00221   // and not single hcal.
00222   // single ecal and single hcal will be used in cluster recovery
00223 
00224   for( IBR io = otherBlockRefs.begin(); io!=otherBlockRefs.end(); ++io) {
00225     processBlock( *io, hcalBlockRefs, ecalBlockRefs );
00226   }
00227 
00228   // cluster recovery has been done. 
00229   // process remaining ecal and hcal clusters. 
00230   
00231   std::list< reco::PFBlockRef > empty;
00232 
00233   // process remaining single hcal blocks
00234   for( IBR ih = hcalBlockRefs.begin(); ih!=hcalBlockRefs.end(); ++ih) {
00235     processBlock( *ih, empty, empty );
00236   }
00237 
00238   // process remaining single ecal blocks
00239   for( IBR ie = ecalBlockRefs.begin(); ie!=ecalBlockRefs.end(); ++ie) {
00240     processBlock( *ie, empty, empty );
00241   }
00242 }
00243 
00244 
00245 void PFAlgo::processBlock( const reco::PFBlockRef& blockref,
00246                            std::list<reco::PFBlockRef>& hcalBlockRefs, 
00247                            std::list<reco::PFBlockRef>& ecalBlockRefs ) { 
00248   
00249   assert(!blockref.isNull() );
00250   const reco::PFBlock& block = *blockref;
00251 
00252   typedef std::multimap<double, unsigned>::iterator IE;
00253 
00254   if(debug_) {
00255     cout<<"#########################################################"<<endl;
00256     cout<<"#####           Process Block:                      #####"<<endl;
00257     cout<<"#########################################################"<<endl;
00258     cout<<block<<endl;
00259   }
00260 
00261   const edm::OwnVector< reco::PFBlockElement >& elements = block.elements();
00262 
00263   // make a copy of the link data, which will be edited.
00264   PFBlock::LinkData linkData =  block.linkData();
00265   
00266   // keep track of the elements which are still active.
00267   vector<bool>   active( elements.size(), true );
00268 
00269 
00270   // //PFElectrons:
00271   // usePFElectrons_ external configurable parameter to set the usage of pf electron
00272   if (usePFElectrons_) {
00273     if (pfele_->isElectronValidCandidate(blockref,active)){
00274       // if there is at least a valid candidate is get the vector of pfcandidates
00275       std::vector<reco::PFCandidate> PFElectCandidates_;
00276       PFElectCandidates_ = pfele_->getElectronCandidates();
00277       for ( std::vector<reco::PFCandidate>::iterator ec = PFElectCandidates_.begin();
00278             ec != PFElectCandidates_.end(); ++ec )
00279         {
00280           pfCandidates_->push_back(*ec);
00281           // the pfalgo candidates vector is filled
00282         }
00283       // The vector active is automatically changed (it is passed by ref) in PFElectronAlgo
00284       // for all the electron candidate
00285     }
00286   }
00287 
00288   
00289   // usePFConversions_ is used to switch ON/OFF the use of the PFConversionAlgo
00290   if (usePFConversions_) {
00291     if (pfConversion_->isConversionValidCandidate(blockref, active )){
00292       // if at least one conversion candidate is found ,it is fed to the final list of Pflow Candidates 
00293       std::vector<reco::PFCandidate> PFConversionCandidates = pfConversion_->conversionCandidates();
00294             
00295       for ( std::vector<reco::PFCandidate>::iterator iConv = PFConversionCandidates.begin(); 
00296             iConv != PFConversionCandidates.end(); ++iConv ) {
00297         pfCandidates_->push_back(*iConv);
00298       }
00299       for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00300         //cout << " PFAlgo::processBlock conversion element " << iEle << " active " << active[iEle] << endl;
00301       }
00302     }
00303   }
00304 
00305 
00306 
00307   if(debug_) 
00308     cout<<endl<<"--------------- loop 1 ---------------------"<<endl;
00309 
00310   // loop1: 
00311   // - sort ecal and hcal elements in separate vectors
00312   // - for tracks:
00313   //       - lock closest ecal cluster 
00314   //       - cut link to farthest hcal cluster, if more than 1.
00315 
00316   // vectors to store indices to hcal and ecal elements 
00317   vector<unsigned> hcalIs;
00318   vector<unsigned> ecalIs;
00319   vector<unsigned> trackIs;
00320 
00321 
00322   for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00323 
00324     PFBlockElement::Type type = elements[iEle].type();
00325         
00326     if(debug_ && type != PFBlockElement::BREM ) cout<<endl<<elements[iEle];   
00327 
00328     switch( type ) {
00329     case PFBlockElement::TRACK:
00330       if ( active[iEle] ) { 
00331         trackIs.push_back( iEle );
00332         if(debug_) cout<<"TRACK, stored index, continue"<<endl;
00333       }
00334       break;
00335     case PFBlockElement::ECAL: 
00336       if ( active[iEle]  ) { 
00337         ecalIs.push_back( iEle );
00338         if(debug_) cout<<"ECAL, stored index, continue"<<endl;
00339       }
00340       continue;
00341     case PFBlockElement::HCAL:
00342       if ( active[iEle] ) { 
00343         hcalIs.push_back( iEle );
00344         if(debug_) cout<<"HCAL, stored index, continue"<<endl;
00345       }
00346 
00347       continue;
00348     default:
00349       continue;
00350     }
00351 
00352     // we're now dealing with a track
00353     unsigned iTrack = iEle;
00354     if(debug_) { 
00355       cout<<"TRACK"<<endl;
00356       if ( !active[iTrack] ) cout << "Already used by electrons, muons, conversions" << endl;
00357     }
00358     
00359     // Track already used as electron, muon, conversion?
00360     // Added a check on the activated element
00361     if ( ! active[iTrack] ) continue;
00362   
00363     reco::TrackRef trackRef = elements[iTrack].trackRef();
00364     assert( !trackRef.isNull() ); 
00365                       
00366 
00367     // look for associated elements of all types
00368 
00369     std::multimap<double, unsigned> ecalElems;
00370     block.associatedElements( iTrack,  linkData,
00371                               ecalElems ,
00372                               reco::PFBlockElement::ECAL,
00373                               reco::PFBlock::LINKTEST_ALL );
00374     
00375     std::multimap<double, unsigned> hcalElems;
00376     block.associatedElements( iTrack,  linkData,
00377                               hcalElems,
00378                               reco::PFBlockElement::HCAL,
00379                               reco::PFBlock::LINKTEST_ALL ); 
00380     //MICHELE 
00381     //TEMPORARY SOLUTION FOR ELECTRON REJECTION IN PFTAU
00382     std::multimap<double,unsigned> gsfElems;
00383     if (usePFElectrons_ == false) {
00384       block.associatedElements( iTrack,  linkData,
00385                                 gsfElems ,
00386                                 reco::PFBlockElement::GSF );
00387     }
00388     //
00389 
00390     if(hcalElems.empty() && debug_) {
00391       cout<<"no hcal element connected to track "<<iTrack<<endl;
00392     }
00393 
00394     typedef std::multimap<double, unsigned>::iterator IE;
00395    
00396     // loop on associated elements
00397 
00398     bool ecalFound = false;
00399     bool hcalFound = false;
00400 
00401     if(debug_) 
00402       cout<<"now looping on elements associated to the track"<<endl;
00403           
00404     // for each element associated to track iTrack
00405 
00406     double ecalEnergy = 0;
00407 
00408     unsigned iEcal = 99999;
00409     bool     connectedToEcal = false;
00410 
00411     for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
00412       
00413       // double  dist  = ie->first;
00414       unsigned index = ie->second;
00415       
00416       PFBlockElement::Type type = elements[index].type();
00417       
00418       if(debug_) {
00419         double chi2 = block.chi2(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
00420         cout<<"\telement "<<elements[index]<<" linked with chi2 "<<chi2<<endl;
00421       }
00422 
00423       assert( type == PFBlockElement::ECAL );
00424 
00425       // PFElectrons:Added a check on the activate elements
00426       // if the ECAL cluster has already been locked break the loop?y
00427       if ( ! active[index] ) break;      
00428       
00429       reco::PFClusterRef clusterRef = elements[index].clusterRef();
00430       assert( !clusterRef.isNull() );
00431 
00432       if( !ecalFound ) { 
00433         
00434         if(debug_) 
00435           cout<<"\t\tfirst ecal element "<<endl;
00436         
00437         ecalFound = true;
00438         
00439         if( hcalElems.empty() ) { 
00440           
00441           if(debug_) {
00442             cout<<"\t\tlocking ecal cluster"<<endl;
00443           }
00444             
00445           ecalEnergy    = clusterRef->energy();
00446           iEcal = index;
00447           connectedToEcal = true;
00448 
00449           // colin  in fact the cluster should maybe not be locked,
00450           // but some of its energy could make it to the hcal 
00451           // loop
00452           // PJ Colin is right - this is dealt with a little later.
00453           // active[index] = false;
00454 
00455         } //  if( hcalElems.empty() { 
00456         else {
00457           if(debug_) 
00458             cout<<"\t\tat least one hcal element connected to the track."
00459                 <<" Sparing Ecal cluster for the hcal loop"<<endl; 
00460         }
00461       }
00462       else { // other associated ecal
00463         // this should not happen, except for very large 
00464         // chi2 max for track-ecal association
00465         // indeed, ecal clusters can't be too close
00466         // since seed look-up is done on 8 neighbours
00467         
00468         // anyway, when this happens, we cannot 
00469         // form a photon from the cluster
00470         // since this cluster might be connected to another 
00471         // track, or to an hcal cluster. 
00472         // so we do nothing.
00473         
00474         if(debug_) 
00475           cout<<"\t\tsecondary ecal element "<<endl;
00476       }
00477     
00478     }//loop ecal elements
00479 
00480     // tracks which are not linked to an HCAL 
00481     // are reconstructed now. 
00482 
00483     if( hcalElems.empty() ) {
00484 
00485       vector<unsigned> elementIndices;
00486       elementIndices.push_back(iTrack); 
00487 
00488       //  create a track candidate 
00489       
00490       active[iTrack] = false;
00491       
00492       // PJ If there is no HCAL, just remove the link by rechit with this track
00493       // Just trust the ECAL granularity
00494     
00495       
00496       unsigned tmpi = reconstructTrack( elements[iTrack] );
00497       
00498       double calibEcal = ecalEnergy;
00499       double calibHcal = 0.;
00500       double slopeEcal = 1.;
00501       if ( connectedToEcal && active[iEcal] ) {
00502         if ( newCalib_ ) { 
00503           clusterCalibration_->
00504             getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
00505                                             elements[iEcal].clusterRef()->positionREP().Eta(),
00506                                             elements[iEcal].clusterRef()->positionREP().Phi());
00507           if ( ecalEnergy > 0. ) slopeEcal = calibEcal/ecalEnergy;
00508         } else { 
00509           slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
00510           calibEcal *= slopeEcal; 
00511         }
00512       }
00513 
00514       (*pfCandidates_)[tmpi].setEcalEnergy( calibEcal );
00515       (*pfCandidates_)[tmpi].setHcalEnergy( 0 );
00516       (*pfCandidates_)[tmpi].setPs1Energy( 0 );
00517       (*pfCandidates_)[tmpi].setPs2Energy( 0 );
00518       (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack ); 
00519 
00520       // Create some photon/neutral hadron (?) if the ecal energy is too large
00521       if( connectedToEcal && active[iEcal] ) {
00522         reco::PFClusterRef pivotalRef = elements[iEcal].clusterRef();
00523         (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal ); 
00524 
00525         std::multimap<double, unsigned> sortedTracks;
00526         block.associatedElements( iEcal,  linkData,
00527                                   sortedTracks,
00528                                   reco::PFBlockElement::TRACK,
00529                                   reco::PFBlock::LINKTEST_ALL );
00530         // Check if the track closest to this ECAL is the current track
00531         // otherwise keeps this ECAL for later
00532         if ( sortedTracks.begin()->second == iTrack ) {  
00533           double neutralEnergy = calibEcal;
00534 
00535           // Check if there are other tracks linked to that ECAL
00536           for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00537             unsigned jTrack = ie->second;
00538             
00539             // Check if the ECAL closest to this track is the current ECAL
00540             // Otherwise ignore this track in the neutral energy determination
00541             std::multimap<double, unsigned> sortedECAL;
00542             block.associatedElements( jTrack,  linkData,
00543                                       sortedECAL,
00544                                       reco::PFBlockElement::ECAL,
00545                                       reco::PFBlock::LINKTEST_ALL );
00546             if ( sortedECAL.begin()->second != iEcal ) continue;
00547             
00548             // Check if this track is also linked to an HCAL 
00549             // (in which case it goes to the next loop and is ignored here)
00550             std::multimap<double, unsigned> sortedHCAL;
00551             block.associatedElements( jTrack,  linkData,
00552                                       sortedHCAL,
00553                                       reco::PFBlockElement::HCAL,
00554                                       reco::PFBlock::LINKTEST_ALL );
00555             if ( sortedHCAL.size() ) continue;
00556 
00557             // Otherwise, subtract this track momentum from the ECAL energy 
00558             reco::TrackRef trackRef = elements[jTrack].trackRef();
00559             neutralEnergy -= trackRef->p();
00560 
00561           } // End other tracks
00562           
00563           // PJ Don't forget to unfold the ECAL calibration : 01/10/08 !!!
00564           active[iEcal] = false;
00565           neutralEnergy /= slopeEcal;
00566           if ( neutralEnergy > 0. ) { 
00567             unsigned tmpj = reconstructCluster( *pivotalRef, neutralEnergy ); 
00568             (*pfCandidates_)[tmpj].setEcalEnergy( neutralEnergy );
00569             (*pfCandidates_)[tmpj].setHcalEnergy( 0. );
00570             (*pfCandidates_)[tmpj].setPs1Energy( -1 );
00571             (*pfCandidates_)[tmpj].setPs2Energy( -1 );
00572             (*pfCandidates_)[tmpj].addElementInBlock(blockref, iEcal);
00573             (*pfCandidates_)[tmpj].addElementInBlock( blockref, iTrack ); 
00574           } // End neutral energy
00575         } // End closest track
00576       } // End connected ECAL
00577       
00578       //MICHELE 
00579       //TEMPORARY SOLUTION FOR ELECTRON REJECTION IN PFTAU
00580        if (usePFElectrons_ == false) (*pfCandidates_)[tmpi].set_mva_e_pi(gsfElems.size()>0);
00581       //
00582 
00583     }
00584 
00585     for(IE ie = hcalElems.begin(); ie != hcalElems.end(); ++ie ) {
00586       
00587       // double   chi2  = ie->first;
00588       unsigned index = ie->second;
00589       
00590       PFBlockElement::Type type = elements[index].type();
00591 
00592       if(debug_) {
00593         double chi2 = block.chi2(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
00594         cout<<"\telement "<<elements[index]<<" linked with chi2 "<<chi2<<endl;
00595       }
00596 
00597       assert( type == PFBlockElement::HCAL );
00598       
00599       // all hcal clusters except the closest 
00600       // will be unlinked from the track
00601       if( !hcalFound ) { // closest hcal
00602         if(debug_) 
00603           cout<<"\t\tclosest hcal cluster, doing nothing"<<endl;
00604         
00605         hcalFound = true;
00606         
00607         // active[index] = false;
00608         // hcalUsed.push_back( index );
00609       }
00610       else { // other associated hcal
00611         // unlink from the track
00612         if(debug_) 
00613           cout<<"\t\tsecondary hcal cluster. unlinking"<<endl;
00614         //block.setLink( iTrack, index,  -1, -1, linkData );
00615         //Note ALex: a fonction should be implemented to
00616         //force link to -1 for all possible tests
00617         //For the moment (15/11/2007) only 2 possible
00618         //tests: CHI2 and RECHIT.
00619         block.setLink( iTrack, index,  -1, -1, linkData, 
00620                        PFBlock::LINKTEST_CHI2 );
00621         block.setLink( iTrack, index,  -1, -1, linkData,
00622                        PFBlock::LINKTEST_RECHIT );
00623       }
00624     } //loop hcal elements   
00625   } // end of loop 1 on elements iEle of any type
00626 
00627 
00628 
00629   if(debug_) { 
00630     cout<<endl;
00631     cout<<endl<<"--------------- loop hcal ---------------------"<<endl;
00632   }
00633   
00634   // track information:
00635   // trackRef
00636   // ecal energy
00637   // hcal energy
00638   // rescale 
00639 
00640   for(unsigned i=0; i<hcalIs.size(); i++) {
00641     
00642     unsigned iHcal= hcalIs[i];    
00643     PFBlockElement::Type type = elements[iHcal].type();
00644 
00645     assert( type == PFBlockElement::HCAL );
00646 
00647     if(debug_) cout<<endl<<elements[iHcal]<<endl;
00648 
00649     vector<unsigned> elementIndices;
00650     elementIndices.push_back(iHcal);
00651 
00652     // associated tracks
00653     std::multimap<double, unsigned> sortedTracks;
00654     block.associatedElements( iHcal,  linkData,
00655                               sortedTracks,
00656                               reco::PFBlockElement::TRACK,
00657                               reco::PFBlock::LINKTEST_ALL );
00658    
00659     std::multimap< unsigned, std::pair<double, unsigned> >
00660       associatedEcals;
00661 
00662     PFClusterRef hclusterref = elements[iHcal].clusterRef();
00663     assert(!hclusterref.isNull() );
00664 
00665 
00666     //if there is no track attached to that HCAL, then do not
00667     //reconstruct an HCAL alone, check if it can be recovered 
00668     //first
00669     
00670     // if no associated tracks, create a neutral hadron
00671     //if(sortedTracks.empty() ) {
00672 
00673     if( sortedTracks.empty() ) {
00674       if(debug_) 
00675         cout<<"\tno associated tracks, keep for later"<<endl;
00676       continue;
00677     }
00678 
00679     // Lock the HCAL cluster
00680     // This printout pops up when a cluster was recovered by a previous track
00681     // It shows that the cluster recovery must be entirely revisited, 
00682     // and should be de-activated for now.
00683     //
00684     // if ( !active[iHcal] ) std::cout << "Warning !!! HCAL locked !!!" << std::endl;
00685     active[iHcal] = false;
00686 
00687     // in the following, tracks are associated to this hcal cluster.
00688     // will look for an excess of energy in the calorimeters w/r to 
00689     // the charged energy, and turn this excess into a neutral hadron or 
00690     // a photon.
00691 
00692     if(debug_) cout<<"\t"<<sortedTracks.size()<<" associated tracks:"<<endl;
00693 
00694     double totalChargedMomentum = 0;
00695     double sumpError2 = 0.;
00696     double totalEcal = -0.0000000001; // thanks alex
00697     double totalHcal = hclusterref->energy();
00698     vector<double> hcalP;
00699     vector<double> hcalDP;
00700     vector<unsigned> tkIs;
00701     double maxDPovP = -9999.;
00702     
00703     //saving reference to associated tracks
00704     std::vector< reco::PFRecTrackRef > associatedTracks;
00705     
00706     vector< unsigned > chargedHadronsIndices;
00707     double mergedNeutralHadronEnergy = 0;
00708 
00709     for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00710       // double chi2 = ie->first;
00711 
00712 
00713       unsigned iTrack = ie->second;
00714       //       tkIs.push_back(iTrack);
00715 
00716       // Check the track has not already been used (e.g., in electrons, conversions...)
00717       if ( !active[iTrack] ) continue;
00718            
00719       PFBlockElement::Type type = elements[iTrack].type();
00720       assert( type == reco::PFBlockElement::TRACK );
00721       
00722       reco::TrackRef trackRef = elements[iTrack].trackRef();
00723       assert( !trackRef.isNull() ); 
00724       
00725       unsigned tmpi = reconstructTrack( elements[iTrack] );
00726       
00727       reco::PFCandidate& currentChargedHadron = (*pfCandidates_)[tmpi];
00728 //       currentChargedHadron.addElement(&elements[iTrack]);
00729 //       currentChargedHadron.addElement(&elements[iHcal]);
00730       currentChargedHadron.addElementInBlock( blockref, iTrack );
00731       currentChargedHadron.addElementInBlock( blockref, iHcal );
00732 
00733       chargedHadronsIndices.push_back( tmpi );
00734       //MICHELE 
00735       //TEMPORARY SOLUTION FOR ELECTRON REJECTION IN PFTAU
00736       if (usePFElectrons_ == false) {
00737         std::multimap<double,unsigned> gsfElems;
00738         block.associatedElements( iTrack,  linkData,
00739                                   gsfElems ,
00740                                   reco::PFBlockElement::GSF );
00741         currentChargedHadron.set_mva_e_pi(gsfElems.size()>0);
00742       }
00743       //
00744 
00745       //filling reference to track vector
00746       //for cluster recovery algorithm
00747       associatedTracks.push_back( elements[iTrack].trackRefPF() );
00748 
00749       if(debug_) cout<<"\t\t"<<elements[iTrack]<<endl;
00750 
00751       // introduce  tracking errors 
00752       double trackMomentum = trackRef->p();
00753       totalChargedMomentum += trackMomentum; 
00754 
00755       double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
00756       sumpError2 += Dp*Dp;
00757       hcalP.push_back(trackMomentum);
00758       hcalDP.push_back(Dp);
00759       if (Dp/trackMomentum > maxDPovP) maxDPovP = Dp/trackMomentum;
00760 
00761       // look for ecal elements associated to iTrack (associated to iHcal)
00762       // PJ Possibility of link by rechit/chi2
00763       std::multimap<double, unsigned> sortedEcals;
00764       block.associatedElements( iTrack,  linkData,
00765                                 sortedEcals,
00766                                 reco::PFBlockElement::ECAL,
00767                                 reco::PFBlock::LINKTEST_ALL );
00768     
00769       if(debug_) cout<<"\t\t\tnumber of Ecal elements linked to this track: "
00770                      <<sortedEcals.size()<<endl;
00771       
00772       if( !sortedEcals.empty() ) 
00773         { // start case: at least one ecal element associated to iTrack
00774           // double chi2Ecal = sortedEcals.begin()->first;
00775           
00776           // PJ Check if this ECAL is not closer to another track
00777           // PJ If so take the next one, etc.
00778           for ( IE iec=sortedEcals.begin(); iec!=sortedEcals.end(); ++iec ) {
00779 
00780             unsigned iEcal = iec->second;
00781             
00782             std::multimap<double, unsigned> sortedTracksEcal;
00783             block.associatedElements( iEcal,  linkData,
00784                                       sortedTracksEcal,
00785                                       reco::PFBlockElement::TRACK,
00786                                       reco::PFBlock::LINKTEST_ALL );
00787             unsigned jTrack = sortedTracksEcal.begin()->second;
00788             if ( jTrack != iTrack ) continue; 
00789 
00790             double chi2Ecal = block.chi2(jTrack,iEcal,linkData,reco::PFBlock::LINKTEST_ALL);
00791             if(debug_) cout<<"\t\t\tclosest: "
00792                            <<elements[iEcal]<<endl;
00793             
00794             if( active[iEcal] ) { // start case: iEcal is active
00795               PFBlockElement::Type type = elements[ iEcal ].type();
00796               assert( type == PFBlockElement::ECAL );
00797               PFClusterRef eclusterref = elements[iEcal].clusterRef();
00798               assert(!eclusterref.isNull() );
00799               
00800               
00801               totalEcal += eclusterref->energy();
00802               
00803               // ecal part of abc calibrated energy.
00804               // the offset is fully given to hcal energy
00805               float ecalEnergyCalibrated = eclusterref->energy();
00806               ecalEnergyCalibrated*=calibration_->paramECALplusHCAL_slopeECAL(); 
00807               
00808               currentChargedHadron.setEcalEnergy( ecalEnergyCalibrated );
00809               //             currentChargedHadron.addElement(&elements[iEcal]);
00810               currentChargedHadron.addElementInBlock( blockref, iEcal );
00811               
00812               std::pair<double, unsigned> associatedEcal 
00813                 = make_pair( chi2Ecal, iEcal );
00814               associatedEcals.insert( make_pair(iTrack, associatedEcal) );
00815               active[iEcal] = false;
00816               
00817               if(debug_) cout<<"\t\t\tactive, adding "<<eclusterref->energy()
00818                              <<" to ECAL energy, and locking"<<endl;
00819 
00820             } // end case : iEcal is active
00821             else {
00822               if(debug_) cout<<"\t\tcluster locked"<<endl;          
00823             }
00824             break;
00825           } // End loop ecal associated to iTrack
00826         } // end case: at least one ecal element associated to iTrack
00827           
00828     } // end loop on tracks associated to hcal element iHcal
00829 
00830     
00831     // test compatibility between calo and tracker. //////////////
00832 
00833     double caloEnergy = -1.;
00834     double slopeEcal = 1.0;
00835     double calibEcal = std::max(0.,totalEcal);
00836     double calibHcal = std::max(0.,totalHcal);
00837     if ( newCalib_ ) {
00838       // caloEnergy =
00839         //clusterCalibration_->
00840         //getCalibratedEnergy(totalEcal, totalHcal, 
00841         //                  hclusterref->positionREP().Eta(),
00842         //                  hclusterref->positionREP().Phi());
00843       clusterCalibration_->
00844         getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
00845                                         hclusterref->positionREP().Eta(),
00846                                         hclusterref->positionREP().Phi());
00847       caloEnergy = calibEcal+calibHcal;
00848       if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
00849     } else { 
00850       if( totalEcal>0) { 
00851         caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
00852         slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
00853         calibEcal = totalEcal * slopeEcal;
00854       } else { 
00855         caloEnergy = calibration_->energyHad( totalHcal );
00856         calibEcal = totalEcal;
00857       }
00858     }
00859 
00860     assert(caloEnergy>=0);
00861 
00862     //colin: resolution should be measured on the ecal+hcal case. 
00863     // however, the result will be close. 
00864     // double Caloresolution = neutralHadronEnergyResolution( caloEnergy );
00865     // Caloresolution *= caloEnergy;
00866     // PJ The resolution is on the expected charged calo energy !
00867     double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum );
00868     Caloresolution *= totalChargedMomentum;
00869     // that of the charged particles linked to the cluster!
00870     double TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
00871 
00872     if(debug_) {
00873           
00874       cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
00875       cout<<"\t\tsum p    = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
00876       cout<<"\t\tsum ecal = "<<totalEcal<<endl;
00877       cout<<"\t\tsum hcal = "<<totalHcal<<endl;
00878       cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
00879       cout<<"\t\t => Calo Energy- total charged momentum = "
00880           <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
00881       cout<<endl;
00882     }
00883     
00884     double nsigma = nSigmaHCAL_;
00885 
00886 
00888 
00889     if( abs(totalChargedMomentum-caloEnergy)<nsigma*TotalError ) {
00890 
00891       // deposited caloEnergy compatible with total charged momentum
00892       // if tracking errors are large take weighted average
00893       
00894       if(debug_) {
00895         cout<<"\t\tcase 1: COMPATIBLE "
00896             <<"|Calo Energy- total charged momentum| = "
00897             <<abs(caloEnergy-totalChargedMomentum)
00898             <<" < "<<nsigma<<" x "<<TotalError<<endl;
00899         if (maxDPovP < 0.1 )
00900           cout<<"\t\t\tmax DP/P = "<< maxDPovP 
00901               <<" less than 0.1: do nothing "<<endl;
00902         else 
00903           cout<<"\t\t\tmax DP/P = "<< maxDPovP 
00904               <<" >  0.1: take weighted averages "<<endl;
00905       }
00906       
00907       // if max DP/P < 10%  do nothing
00908       if (maxDPovP > 0.1) {
00909       
00910         // for each track associated to hcal
00911         //      int nrows = tkIs.size();
00912         int nrows = chargedHadronsIndices.size();
00913         TMatrixTSym<double> a (nrows);
00914         TVectorD b (nrows);
00915         TVectorD check(nrows);
00916         double sigma2E = Caloresolution*Caloresolution;
00917         for(int i=0; i<nrows; i++) {
00918           double sigma2i = hcalDP[i]*hcalDP[i];
00919           if (debug_){
00920             cout<<"\t\t\ttrack associated to hcal "<<i 
00921                 <<" P = "<<hcalP[i]<<" +- "
00922                 <<hcalDP[i]<<endl;
00923           }
00924           a(i,i) = 1./sigma2i + 1./sigma2E;
00925           b(i) = hcalP[i]/sigma2i + caloEnergy/sigma2E;
00926           for(int j=0; j<nrows; j++) {
00927             if (i==j) continue;
00928             a(i,j) = 1./sigma2E;
00929           } // end loop on j
00930         } // end loop on i
00931         
00932         // solve ax = b
00933         //if (debug_){// debug1
00934         //cout<<" matrix a(i,j) "<<endl;
00935         //a.Print();
00936         //cout<<" vector b(i) "<<endl;
00937         //b.Print();
00938         //} // debug1
00939         TDecompChol decomp(a);
00940         bool ok = false;
00941         TVectorD x = decomp.Solve(b, ok);
00942         // for each track create a PFCandidate track
00943         // with a momentum rescaled to weighted average
00944         if (ok) {
00945           for (int i=0; i<nrows; i++){
00946             //      unsigned iTrack = trackInfos[i].index;
00947             unsigned ich = chargedHadronsIndices[i];
00948             double rescaleFactor =  x(i)/hcalP[i];
00949             (*pfCandidates_)[ich].rescaleMomentum( rescaleFactor );
00950 
00951             if(debug_){
00952               cout<<"\t\t\told p "<<hcalP[i]
00953                   <<" new p "<<x(i) 
00954                   <<" rescale "<<rescaleFactor<<endl;
00955             }
00956           }
00957         }
00958         else {
00959           cerr<<"not ok!"<<endl;
00960           assert(0);
00961         }
00962       }
00963     }
00964 
00966     else if( caloEnergy > totalChargedMomentum ) {
00967       
00968       //case 2: caloEnergy > totalChargedMomentum + nsigma*TotalError
00969       //there is an excess of energy in the calos
00970       //create a neutral hadron or a photon
00971         
00972       double eNeutralHadron = caloEnergy - totalChargedMomentum;
00973       double ePhoton = (caloEnergy - totalChargedMomentum) / slopeEcal;
00974         
00975       if(debug_) {
00976         if(!sortedTracks.empty() ){
00977           cout<<"\t\tcase 2: NEUTRAL DETECTION "
00978               <<caloEnergy<<" > "<<nsigma<<"x"<<TotalError
00979               <<" + "<<totalChargedMomentum<<endl;
00980           cout<<"\t\tneutral activity detected: "<<endl
00981               <<"\t\t\t           photon = "<<ePhoton<<endl
00982               <<"\t\t\tor neutral hadron = "<<eNeutralHadron<<endl;
00983             
00984           cout<<"\t\tphoton or hadron ?"<<endl;}
00985           
00986         if(sortedTracks.empty() )
00987           cout<<"\t\tno track -> hadron "<<endl;
00988         else 
00989           cout<<"\t\t"<<sortedTracks.size()
00990               <<"tracks -> loop and compute mva"<<endl;
00991       }
00992         
00993       // IE maxMvaIe = sortedTracks.end(); 
00994       reco::PFClusterRef maxMvaEcalRef;
00995       reco::PFClusterRef maxPSClusterRef;
00996       double maxMva = -PFCandidate::bigMva_;
00997       bool PSsignature = false;
00998       unsigned maxMvaiEcal= 9999;       
00999       unsigned maxPSiEcal= 9999;  
01000       // for each track associated to hcal: iterator IE ie :
01001         
01002       for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
01003           
01004         unsigned iTrack = ie->second;
01005           
01006         PFBlockElement::Type type = elements[iTrack].type();
01007         assert( type == reco::PFBlockElement::TRACK );
01008           
01009         reco::TrackRef trackRef = elements[iTrack].trackRef();
01010         assert( !trackRef.isNull() ); 
01011           
01012         std::multimap< unsigned, std::pair<double, unsigned> >::iterator 
01013           iae = associatedEcals.find(iTrack);
01014           
01015         if( iae == associatedEcals.end() ) continue;
01016           
01017         double chi2ECAL = iae->second.first;
01018         unsigned iEcal = iae->second.second;
01019           
01020         PFBlockElement::Type typeEcal = elements[iEcal].type();
01021         assert(typeEcal == reco::PFBlockElement::ECAL);
01022           
01023         reco::PFClusterRef clusterRef = elements[iEcal].clusterRef();
01024         assert( !clusterRef.isNull() );
01025           
01026         chi2ECAL_ = static_cast<float>( chi2ECAL );
01027         ptTrack_ = static_cast<float>( trackRef->pt() );
01028           
01029         float pTrack = static_cast<float>( trackRef->p() );
01030         float eECAL = static_cast<float>( clusterRef->energy() );
01031         eECALOverpTrack_ = eECAL / pTrack;
01032           
01033         double value = -PFAlgo::maxMvaCut_;
01034         if(mvaCut_ < PFAlgo::maxMvaCut_ ) {
01035           value = mergedPhotonsMVA_->EvaluateMVA( "MVA" );
01036           if( value>maxMva ) {
01037             maxMva = value;
01038             maxMvaEcalRef = clusterRef;
01039             maxMvaiEcal = iEcal;
01040           }
01041         }         
01042           
01043         if(debug_) {
01044           cout<<"\t\t"<<elements[iTrack]<<endl;
01045           cout<<"\t\t\tassociated ECAL "<<elements[iEcal]<<endl;
01046           cout<<"\t\t\tmva evaluation : "<<endl;
01047           cout<<"\t\t\t\teECALOverpTrack = "<<eECALOverpTrack_<<endl;
01048           cout<<"\t\t\t\tptTrack         = "<<ptTrack_<<endl;
01049           cout<<"\t\t\t\tchi2ECAL        = "<<chi2ECAL_<<endl;
01050           cout<<"\t\t\t ==>        mva = "<<value<<endl;
01051             
01052         }
01053         // look for PS1 elements associated to iEcal
01054         bool PS1found = false;
01055         double PS1energy = -1.;
01056         std::multimap<double, unsigned> sortedPS1;
01057         block.associatedElements( iEcal,  linkData,
01058                                   sortedPS1,
01059                                   reco::PFBlockElement::PS1 );
01060           
01061         if(debug_) cout<<"\t\t\tnumber of PS1 elements linked to this ecal: "
01062                        <<sortedPS1.size()<<endl;
01063           
01064         if( !sortedPS1.empty() ) 
01065           { // start case: at least one PS1 element associated to iEcal
01066             //double chi2PS1 = sortedPS1.begin()->first; //Alex//not used
01067             unsigned iPS1  = sortedPS1.begin()->second;
01068             if(debug_) cout<<"\t\t\tclosest: "
01069                            <<elements[iPS1]<<endl;
01070               
01071             PFBlockElement::Type type = elements[ iPS1 ].type();
01072             assert( type == PFBlockElement::PS1 );
01073             PFClusterRef PSclusterref = elements[iPS1].clusterRef();
01074             assert(!PSclusterref.isNull() );
01075               
01076             PS1energy = PSclusterref->energy();
01077             if (PS1energy > PSCut_) PS1found = true;
01078           } // end case: at least one PS1 element associated to iEcal
01079           
01080         // look for PS2 elements associated to iEcal
01081         bool PS2found = false;
01082         double PS2energy = -1.;
01083         std::multimap<double, unsigned> sortedPS2;
01084         block.associatedElements( iEcal,  linkData,
01085                                   sortedPS2,
01086                                   reco::PFBlockElement::PS2 );
01087           
01088         if(debug_) cout<<"\t\t\tnumber of PS2 elements linked to this ecal: "
01089                        <<sortedPS2.size()<<endl;
01090           
01091         if( !sortedPS2.empty() ) 
01092           { // start case: at least one PS2 element associated to iEcal
01093             //double chi2PS2 = sortedPS2.begin()->first; //Alex//noused
01094             unsigned iPS2  = sortedPS2.begin()->second;
01095             if(debug_) cout<<"\t\t\tclosest: "
01096                            <<elements[iPS2]<<endl;
01097               
01098             PFBlockElement::Type type = elements[ iPS2 ].type();
01099             assert( type == PFBlockElement::PS2 );
01100             PFClusterRef PSclusterref = elements[iPS2].clusterRef();
01101             assert(!PSclusterref.isNull() );
01102               
01103             PS2energy = PSclusterref->energy();
01104             if (PS2energy > PSCut_) PS2found = true;
01105               
01106           } // end case: at least one PS2 element associated to iEcal
01107           
01108           
01109         // evaluate PS signature
01110         if (PSsignature) continue;
01111         //PSsignature = PS1found&&PS2found;
01112         PSsignature = PS1found||PS2found;
01113         maxPSClusterRef = clusterRef;
01114         maxPSiEcal = iEcal;
01115         if (debug_) {
01116           cout<<" PS signature "<<PSsignature 
01117               <<" PS1 energy "<<PS1energy
01118               <<" PS2 energy "<<PS2energy<<endl;
01119         }
01120           
01121       }  // end loop on tracks associated to hcal: iterator IE ie
01122 
01123       std::vector<reco::PFClusterRef> pivotalClusterRef;
01124       std::vector<unsigned> iPivotal;
01125       std::vector<double> particleEnergy, ecalEnergy, hcalEnergy;
01126       vector<unsigned> elementIndices;
01127 
01128       // double particleEnergy = -1;
01129       // float  ecalEnergy = 0;
01130       // float  hcalEnergy = 0;
01131       
01132       if( !maxPSClusterRef.isNull() && 
01133           // PJ This is probably a bug too.
01134           // We need to save a neutral hadron if 
01135           // ePhoton is larger than EEcal!
01136           PSsignature) { //  overwrites MVA decision
01137         if(debug_) {
01138           cout<<" PS signature is true"
01139               <<", reconstruct a photon"<<endl;
01140         }
01141         particleEnergy.push_back(ePhoton);
01142         ecalEnergy.push_back(ePhoton);
01143         hcalEnergy.push_back(0.);
01144         pivotalClusterRef.push_back(maxPSClusterRef);
01145         iPivotal.push_back(maxPSiEcal);
01146       } // end case: PS signature is true
01147       else { // start case PS signature is false
01148         if( !maxMvaEcalRef.isNull() && 
01149             maxMva > mvaCut_) { //  start case: maxMva > mvaCut_
01150 
01151           if ( ePhoton < totalEcal || eNeutralHadron-calibEcal < 1E-10 ) { // PJ !!! waiting for a better MVA ;-)
01152             if(debug_) {
01153               cout<<"\t\tmaxMva = "<<maxMva<<">"<< mvaCut_
01154                   <<", reconstruct a photon"<<endl;
01155               
01156             }
01157             
01158             // PJ BUG !
01159             //if( ePhoton>totalEcal ) 
01160             //  ePhoton = totalEcal;
01161             
01162             pivotalClusterRef.push_back(maxMvaEcalRef);
01163             particleEnergy.push_back(ePhoton);
01164             ecalEnergy.push_back(ePhoton);
01165             hcalEnergy.push_back(0.);
01166             iPivotal.push_back(maxMvaiEcal);
01167             
01168           } else { 
01169             
01170             // Assign the ECAL energy to the photon
01171             pivotalClusterRef.push_back(maxMvaEcalRef);
01172             particleEnergy.push_back(totalEcal);
01173             ecalEnergy.push_back(totalEcal);
01174             hcalEnergy.push_back(0.);
01175             iPivotal.push_back(maxMvaiEcal);
01176 
01177             // Assign the remaining excess to a neutral hadron
01178             pivotalClusterRef.push_back(hclusterref);
01179             particleEnergy.push_back(eNeutralHadron-calibEcal);
01180             ecalEnergy.push_back(0.);
01181             hcalEnergy.push_back(eNeutralHadron-calibEcal);
01182             iPivotal.push_back(iHcal);
01183 
01184             mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
01185 
01186           }
01187 
01188         }   // end case: maxMva > mvaCut_
01189         else {   //  start case : maxMva < mvaCut_
01190           if(debug_) {
01191             cout<<"\t\treconstruct a hadron"<<endl;
01192           }
01193           
01194           // if ( totalEcal > 0. ) { 
01195           if ( ePhoton < totalEcal || eNeutralHadron-calibEcal <= 1E-10 ) { // PJ !!! waiting for a better MVA ;-)
01196             // Assign the ECAL energy to the photon
01197             pivotalClusterRef.push_back(maxMvaEcalRef);
01198             particleEnergy.push_back(ePhoton);
01199             ecalEnergy.push_back(ePhoton);
01200             hcalEnergy.push_back(0.);
01201             iPivotal.push_back(maxMvaiEcal);
01202             
01203           } else { 
01204             
01205             // Assign the ECAL energy to the photon
01206             if ( totalEcal > 0. ) { 
01207               pivotalClusterRef.push_back(maxMvaEcalRef);
01208               particleEnergy.push_back(totalEcal);
01209               ecalEnergy.push_back(totalEcal);
01210               hcalEnergy.push_back(0.);
01211               iPivotal.push_back(maxMvaiEcal);
01212             }
01213 
01214             // Assign the remaining excess to a neutral hadron
01215             pivotalClusterRef.push_back(hclusterref);
01216             particleEnergy.push_back(eNeutralHadron-calibEcal);
01217             ecalEnergy.push_back(0.);
01218             hcalEnergy.push_back(eNeutralHadron-calibEcal);
01219             iPivotal.push_back(iHcal);
01220 
01221             /*
01222               pivotalClusterRef.push_back(hclusterref);
01223               particleEnergy.push_back(eNeutralHadron);
01224               ecalEnergy.push_back(0.);
01225               hcalEnergy.push_back(eNeutralHadron);
01226               iPivotal.push_back(iHcal);
01227             */
01228             
01229             // keep track globally of the merged neutral hadron
01230             mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
01231           } 
01232         }   // end case : maxMva < mvaCut_
01233       }   // end case PS signature is false 
01234 
01235 
01236       // reconstructing a merged neutral
01237       // the type of PFCandidate is known from the 
01238       // reference to the pivotal cluster. 
01239 
01240       for ( unsigned iPivot=0; iPivot<iPivotal.size(); ++iPivot ) { 
01241 
01242         if ( particleEnergy[iPivot] < 0. ) 
01243           std::cout << "ALARM = Negative energy ! " 
01244                     << particleEnergy[iPivot] << std::endl;
01245 
01246         unsigned tmpi = reconstructCluster( *pivotalClusterRef[iPivot], 
01247                                             particleEnergy[iPivot] ); 
01248       
01249         (*pfCandidates_)[tmpi].setEcalEnergy( ecalEnergy[iPivot] );
01250         (*pfCandidates_)[tmpi].setHcalEnergy( hcalEnergy[iPivot] );
01251         (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01252         (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01253         (*pfCandidates_)[tmpi].set_mva_nothing_gamma( maxMva );
01254         //       (*pfCandidates_)[tmpi].addElement(&elements[iPivotal]);
01255         (*pfCandidates_)[tmpi].addElementInBlock(blockref, iPivotal[iPivot]);
01256         // add PS elements to be done
01257 
01258       }
01259 
01260     } // excess of energy
01261 
01263     //COLIN will modify PFCandidate hcal (and ecal) energy
01264     else if(clusterRecovery_) { //  caloEnergy < totalChargedMomentum 
01265       // case 3: caloEnergy < totalChargedMomentum - nsigma*TotalError
01266       // energy is missing : look for additional hcal clusters?
01267       if(debug_) {
01268         cout<<"\t\tcase 3: CLUSTER RECOVERY "
01269             <<caloEnergy<<" < "
01270             <<totalChargedMomentum<<" - "<<nsigma
01271             <<" x "<<TotalError<<endl;
01272       }
01273                   
01274       bool investigateOtherBlocks = false;
01275           
01276       //More energy needed, looking for hcal clusters in the vicinity
01277       //of the tracks extrapolated to hcal in the present block
01278           
01279       if( recoveringClusters( totalChargedMomentum, 
01280                               totalEcal,
01281                               totalHcal, 
01282                               associatedTracks,
01283                               blockref,
01284                               active ) == KEEP_SEARCHING ){
01285             
01286         if( debug_ ){
01287           cout<<"\t\t\tNo satellite cluster found in current block."<<endl;
01288         }
01289         investigateOtherBlocks = true;
01290       }
01291           
01292       //More energy needed, looking for hcal clusters in the vicinity
01293       //of the tracks extrapolated to hcal in other blocks
01294       if( investigateOtherBlocks ){
01295             
01296         if( debug_ )
01297           cout<<"\t\t\tInvestigating other blocks now "<<endl;
01298             
01299         //loop on blocks
01300         for( IBR ih = hcalBlockRefs.begin(); 
01301              ih!=hcalBlockRefs.end();) {
01302                       
01303           vector<bool> active;
01304           active.push_back(true);
01305           RecoveryStatus recovery =
01306             recoveringClusters( totalChargedMomentum, 
01307                                 totalEcal,
01308                                 totalHcal, 
01309                                 associatedTracks,
01310                                 *ih,
01311                                 active );
01312               
01313           if( recovery == DONE ){
01314             if( debug_ )
01315               cout<<"Cluster Recovery is done, stop here"<<endl;
01316             break;
01317           }
01318               
01319           if( !active[0] ) {
01320             // cluster has been used and locked in the cluster recovery
01321             // removing the corresponding sincle cluster block 
01322             // from the list of block refs to be used 
01323             // in cluster recovery
01324             // erase automatically increments the iterator
01325             ih = hcalBlockRefs.erase( ih );
01326           }
01327           else ++ih; // incrementing manually to continue the loop
01328               
01329 
01330         } //loop on blocks   
01331       } //investigating blocks
01332       
01333       // recompute calo energy after cluster recovery
01334 
01335       double slopeEcal = 1.0;
01336       double calibEcal = std::max(0.,totalEcal);
01337       double calibHcal = std::max(0.,totalHcal);
01338       if ( newCalib_ ) {
01339         clusterCalibration_->
01340           getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
01341                                           hclusterref->positionREP().Eta(),
01342                                           hclusterref->positionREP().Phi());
01343         caloEnergy = calibEcal+calibHcal;
01344         if ( totalEcal > 0. ) slopeEcal = calibEcal/totalEcal;
01345       } else { 
01346         if( totalEcal>0) { 
01347           caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
01348           slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01349           calibEcal = totalEcal * slopeEcal;
01350           calibHcal = caloEnergy - calibEcal;
01351         } else { 
01352           caloEnergy = calibration_->energyHad( totalHcal );
01353           calibEcal = totalEcal;
01354           calibHcal = caloEnergy - calibEcal;
01355         }
01356       }
01357 
01358     } // end if cluster recovery
01359 
01360     // will now share the hcal energy between the various charged hadron 
01361     // candidates, taking into account the potential neutral hadrons
01362     
01363     double totalHcalEnergyCalibrated = calibHcal;
01364     /*
01365     if(totalEcal>0) {
01366       // removing ecal energy from abc calibration
01367       totalHcalEnergyCalibrated  -= calibEcal;
01368       // totalHcalEnergyCalibrated -= calibration_->paramECALplusHCAL_slopeECAL() * totalEcal;
01369     }
01370     */
01371     // else caloEnergy = hcal only calibrated energy -> ok.
01372 
01373     // remove the energy of the potential neutral hadron
01374     totalHcalEnergyCalibrated -= mergedNeutralHadronEnergy;
01375 
01376     // share between the charged hadrons
01377 
01378     //COLIN can compute this before
01379     // not exactly equal to sum p, this is sum E
01380     double chargedHadronsTotalEnergy = 0;
01381     for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
01382       unsigned index = chargedHadronsIndices[ich];
01383       reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
01384       chargedHadronsTotalEnergy += chargedHadron.energy();
01385     }
01386 
01387     for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
01388       unsigned index = chargedHadronsIndices[ich];
01389       reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
01390       float fraction = chargedHadron.energy()/chargedHadronsTotalEnergy;
01391       chargedHadron.setHcalEnergy( fraction * totalHcalEnergyCalibrated );
01392       // Alex: add recovered Hcal and Ecal elements?
01393       // create a vector <unsigned> hcalrecov
01394       // create a vector <unsigned> ecalrecov
01395       //for (unsigned i; i<hcalrecov.size(); i++){
01396       //unsigned iHcal = hcalrecov{i];
01397       //chargedHadron.addElement(&elements[iHcal]);
01398       //}
01399       //for (unsigned i; i<ecalrecov.size(); i++){
01400       //unsigned iEcal = ecalrecov{i];
01401       //chargedHadron.addElement(&elements[iEcal]);
01402       //}
01403 
01404           
01405     }
01406 
01407   } // end loop on hcal element iHcal= hcalIs[i] 
01408 
01409 
01410   // Processing the remaining HCAL clusters
01411   if(debug_) { 
01412     cout<<endl;
01413     if(debug_) 
01414       cout<<endl
01415           <<"---- loop remaining hcal ------- "<<endl;
01416   }
01417   
01418 
01419   for(unsigned ihcluster=0; ihcluster<hcalIs.size(); ihcluster++) {
01420     unsigned iHcal = hcalIs[ihcluster];
01421     
01422     if(debug_)
01423       cout<<endl<<elements[iHcal]<<" ";
01424     
01425     
01426     if( !active[iHcal] ) {
01427       if(debug_) 
01428         cout<<"not active"<<endl;         
01429       continue;
01430     }
01431     
01432     // Find the ECAL elements linked to it
01433     std::multimap<double, unsigned> ecalElems;
01434     block.associatedElements( iHcal,  linkData,
01435                               ecalElems ,
01436                               reco::PFBlockElement::ECAL,
01437                               reco::PFBlock::LINKTEST_ALL );
01438 
01439     // Loop on these ECAL elements
01440     float totalEcal = 0.;
01441     for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
01442       
01443       unsigned iEcal = ie->second;
01444       double dist = ie->first;
01445       double chi2 = block.chi2(iHcal,iEcal,linkData,reco::PFBlock::LINKTEST_ALL);
01446       PFBlockElement::Type type = elements[iEcal].type();
01447       assert( type == PFBlockElement::ECAL );
01448       
01449       // Check if already used
01450       if( !active[iEcal] ) continue;
01451 
01452       // Check the chi2
01453       if ( chi2 > 10. ) continue;
01454 
01455       // Check the distance (one HCALPlusECAL tower, roughly)
01456       if ( dist > 0.06 ) continue;
01457 
01458       if(debug_) {
01459         cout<<"\telement "<<elements[iEcal]<<" linked with chi2/dist "<<chi2<<" / " << dist<<endl;
01460         cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
01461       }
01462       
01463       reco::PFClusterRef eclusterRef = elements[iEcal].clusterRef();
01464       assert( !eclusterRef.isNull() );
01465 
01466       totalEcal += eclusterRef->energy();
01467 
01468       active[iEcal] = false;
01469 
01470     }// End loop ECAL
01471 
01472     
01473     PFClusterRef hclusterRef 
01474       = elements[iHcal].clusterRef();
01475     assert( !hclusterRef.isNull() );
01476     
01477     // HCAL energy
01478     double totalHcal =  hclusterRef->energy();
01479     // Calibration
01480     double caloEnergy = totalHcal;
01481     double slopeEcal = 1.0;
01482     double calibEcal = totalEcal > 0. ? totalEcal : 0.;
01483     double calibHcal = std::max(0.,totalHcal);
01484     if ( newCalib_ ) {
01485       clusterCalibration_->
01486         getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
01487                                         hclusterRef->positionREP().Eta(),
01488                                         hclusterRef->positionREP().Phi());
01489       if ( calibEcal == 0. ) calibEcal = totalEcal;
01490       if ( calibHcal == 0. ) calibHcal = totalHcal;
01491       caloEnergy = calibEcal+calibHcal;
01492       if ( totalEcal > 0. ) slopeEcal = calibEcal/totalEcal;
01493     } else { 
01494       if( totalEcal>0) { 
01495         caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
01496         slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01497         calibEcal = totalEcal * slopeEcal;
01498         calibHcal = caloEnergy - calibEcal;
01499       } else if  (  hclusterRef->layer() != PFLayer::HCAL_HF ) { 
01500         caloEnergy = calibration_->energyHad( totalHcal );
01501         calibEcal = totalEcal;
01502         calibHcal = caloEnergy;
01503       }
01504     }
01505 
01506    // ECAL energy : calibration
01507 
01508     // double particleEnergy = caloEnergy;
01509     double particleEnergy = totalEcal + calibHcal;
01510     // particleEnergy /= (1.-0.724/sqrt(particleEnergy)-0.0226/particleEnergy);
01511 
01512     unsigned tmpi = reconstructCluster( *hclusterRef, 
01513                                         particleEnergy ); 
01514 
01515     
01516     (*pfCandidates_)[tmpi].setEcalEnergy( totalEcal );
01517     (*pfCandidates_)[tmpi].setHcalEnergy( calibHcal );
01518     (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01519     (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01520     (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
01521       
01522   }//loop hcal elements
01523 
01524 
01525 
01526 
01527   if(debug_) { 
01528     cout<<endl;
01529     if(debug_) cout<<endl<<"---- loop ecal------- "<<endl;
01530   }
01531   
01532   // for each ecal element iEcal = ecalIs[i] in turn:
01533 
01534   for(unsigned i=0; i<ecalIs.size(); i++) {
01535     unsigned iEcal = ecalIs[i];
01536     
01537     if(debug_) 
01538       cout<<endl<<elements[iEcal]<<" ";
01539     
01540     if( ! active[iEcal] ) {
01541       if(debug_) 
01542         cout<<"not active"<<endl;         
01543       continue;
01544     }
01545     
01546     PFBlockElement::Type type = elements[ iEcal ].type();
01547     assert( type == PFBlockElement::ECAL );
01548 
01549     PFClusterRef clusterref = elements[iEcal].clusterRef();
01550     assert(!clusterref.isNull() );
01551 
01552     active[iEcal] = false;
01553 
01554     float ecalEnergy = calibration_->energyEm( clusterref->energy() );
01555     double particleEnergy = ecalEnergy;
01556     
01557     unsigned tmpi = reconstructCluster( *clusterref, 
01558                                         particleEnergy );
01559  
01560     (*pfCandidates_)[tmpi].setEcalEnergy( ecalEnergy );
01561     (*pfCandidates_)[tmpi].setHcalEnergy( 0 );
01562     (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01563     (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01564     (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
01565     
01566 
01567   }  // end loop on ecal elements iEcal = ecalIs[i]
01568  
01569 
01570 }  // end processBlock
01571 
01572 
01573 
01574 
01575 
01576 
01577 
01578 unsigned PFAlgo::reconstructTrack( const reco::PFBlockElement& elt ) {
01579 
01580   const reco::PFBlockElementTrack* eltTrack 
01581     = dynamic_cast<const reco::PFBlockElementTrack*>(&elt);
01582 
01583   reco::TrackRef trackRef = eltTrack->trackRef();
01584   const reco::Track& track = *trackRef;
01585 
01586   reco::MuonRef muonRef = eltTrack->muonRef();
01587 
01588   int charge = track.charge()>0 ? 1 : -1;
01589 
01590   double px = track.px();
01591   double py = track.py();
01592   double pz = track.pz();
01593   double energy = track.p();
01594 
01595   if( muonRef.isNonnull() ) {
01596     
01597     px = muonRef->px();
01598     py = muonRef->py();
01599     pz = muonRef->pz();
01600     energy = muonRef->energy();  
01601 
01602   }
01603 
01604   math::XYZTLorentzVector momentum(px,py,pz,energy);
01605 
01606   reco::PFCandidate::ParticleType particleType 
01607     = reco::PFCandidate::h;
01608 
01609   pfCandidates_->push_back( PFCandidate( charge, 
01610                                          momentum,
01611                                          particleType ) );
01612   
01613   pfCandidates_->back().setVertex( track.vertex() );
01614   pfCandidates_->back().setTrackRef( trackRef );
01615   pfCandidates_->back().setPositionAtECALEntrance( eltTrack->positionAtECALEntrance());
01616 
01617 
01618   // setting the muon ref if there is
01619   if (muonRef.isNonnull()) {
01620     pfCandidates_->back().setMuonRef( muonRef );
01621 
01622     // setting the muon particle type if it is a global muon
01623     if (muonRef->isGlobalMuon() ) {
01624       particleType = reco::PFCandidate::mu;
01625       pfCandidates_->back().setParticleType( particleType );
01626       if (debug_) cout << "PFAlgo: particle type set to muon" << endl; 
01627     }
01628   }
01629 
01630   // nuclear
01631   if( particleType != reco::PFCandidate::mu )
01632     if( eltTrack->trackType(reco::PFBlockElement::T_FROM_NUCL)) {
01633       pfCandidates_->back().setFlag( reco::PFCandidate::T_FROM_NUCLINT, true);
01634       pfCandidates_->back().setNuclearRef( eltTrack->nuclearRef() );
01635     }
01636     else if( eltTrack->trackType(reco::PFBlockElement::T_TO_NUCL)) {
01637       pfCandidates_->back().setFlag( reco::PFCandidate::T_TO_NUCLINT, true);
01638       pfCandidates_->back().setNuclearRef( eltTrack->nuclearRef() );
01639     }
01640 
01641   // conversion...
01642   
01643   if(debug_) 
01644     cout<<"** candidate: "<<pfCandidates_->back()<<endl; 
01645   
01646   // returns index to the newly created PFCandidate
01647   return pfCandidates_->size()-1;
01648 }
01649 
01650 
01651 
01652 
01653 
01654 unsigned PFAlgo::reconstructCluster(const reco::PFCluster& cluster,
01655                                     double particleEnergy) {
01656   
01657   reco::PFCandidate::ParticleType particleType = reco::PFCandidate::X;
01658 
01659   // need to convert the math::XYZPoint data member of the PFCluster class=
01660   // to a displacement vector: 
01661   ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D<double> , ROOT::Math::DefaultCoordinateSystemTag > clusterPos( cluster.position().X(), cluster.position().Y(),cluster.position().Z() );
01662   
01663 
01664   clusterPos = clusterPos.Unit();
01665   clusterPos *= particleEnergy;
01666 
01667   // clusterPos is now a vector along the cluster direction, 
01668   // with a magnitude equal to the cluster energy.
01669   
01670   double mass = 0;
01671   switch( cluster.layer() ) {
01672   case PFLayer::ECAL_BARREL:
01673   case PFLayer::ECAL_ENDCAP:
01674     particleType = PFCandidate::gamma;
01675     break;
01676   case PFLayer::HCAL_BARREL1:
01677   case PFLayer::HCAL_ENDCAP:
01678     particleType = PFCandidate::h0;
01679     break;
01680   case PFLayer::HCAL_HF:
01681     particleType = PFCandidate::h_HF;
01682     break;
01683   default:
01684     assert(0);
01685   }
01686 
01687 
01688   ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> > 
01689     momentum( clusterPos.X(), clusterPos.Y(), clusterPos.Z(), mass); 
01690 
01691   int charge = 0;
01692 
01693   // mathcore is a piece of #$%
01694   math::XYZTLorentzVector  tmp;
01695 
01696   // implicit constructor not allowed
01697   tmp = momentum;
01698 
01699   pfCandidates_->push_back( PFCandidate( charge, 
01700                                          tmp, 
01701                                          particleType ) );
01702 
01703   if(debug_) 
01704     cout<<"** candidate: "<<pfCandidates_->back()<<endl; 
01705 
01706   // returns index to the newly created PFCandidate
01707   return pfCandidates_->size()-1;
01708 
01709 }
01710 
01711 
01712 
01713 
01714 double PFAlgo::neutralHadronEnergyResolution( double clusterEnergyHCAL ) 
01715   const {
01716 
01717 
01718   return  newCalib_ ? 
01719     1.40/sqrt(clusterEnergyHCAL) +5.00/clusterEnergyHCAL:
01720     1.50/sqrt(clusterEnergyHCAL) +3.00/clusterEnergyHCAL;
01721   // 1.50/sqrt(clusterEnergyHCAL) +0.00/clusterEnergyHCAL;
01722     // 5 GeV
01723     // + 2.34/clusterEnergyHCAL;
01724     // 9 GeV
01725     //+ 3.15/clusterEnergyHCAL;
01726     // 16 GeV
01727     // + 4.20/clusterEnergyHCAL;
01728   // PJ Portnainwak!
01729   //  + 6.62527e-03*sqrt(clusterEnergyHCAL) -6.33966e-02; 
01730   // return  1.2/sqrt(clusterEnergyHCAL) + 0.05;
01731 }
01732 
01733 
01734 
01735 
01736 ostream& operator<<(ostream& out, const PFAlgo& algo) {
01737   if(!out ) return out;
01738 
01739   out<<"====== Particle Flow Algorithm ======= ";
01740   out<<endl;
01741   out<<"nSigmaECAL_     "<<algo.nSigmaECAL_<<endl;
01742   out<<"nSigmaHCAL_     "<<algo.nSigmaHCAL_<<endl;
01743   out<<"mvaCut_         "<<algo.mvaCut_<<endl;
01744   out<<"PSCut_          "<<algo.PSCut_<<endl;
01745   out<<endl;
01746   out<<(*(algo.calibration_))<<endl;
01747   out<<endl;
01748   out<<"reconstructed particles: "<<endl;
01749    
01750   const std::auto_ptr< reco::PFCandidateCollection >& 
01751     candidates = algo.pfCandidates(); 
01752 
01753   if(!candidates.get() ) {
01754     out<<"candidates already transfered"<<endl;
01755     return out;
01756   }
01757   for(PFCandidateConstIterator ic=algo.pfCandidates_->begin(); 
01758       ic != algo.pfCandidates_->end(); ic++) {
01759     out<<(*ic)<<endl;
01760   }
01761 
01762   return out;
01763 }
01764 
01765 PFAlgo::EnergyTest 
01766 PFAlgo::energyTest( double energyTrk, 
01767                     double energyHcal, 
01768                     double energyEcal,
01769                     double eta, 
01770                     double phi,
01771                     double& neutralHadron ) {
01772   
01773   //This function can be used to Test whether the calorimetric
01774   //energy deposition (after calibration) is compatible with 
01775   //the track(s) momemtum. 
01776   //Compatibility is defined as having the calorimetric energy
01777   //within +/- 3*sigma(HCAL) around the track momentum 
01778 
01779   double slopeEcal = 1.0;
01780   double calibEcal = std::max(0.,energyEcal);
01781   double calibHcal = std::max(0.,energyHcal);
01782   double eCalib = -1;
01783   if ( newCalib_ ) {
01784     clusterCalibration_->
01785       getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal, eta, phi);
01786     eCalib = calibEcal+calibHcal;
01787     if ( energyEcal > 0. ) slopeEcal = calibEcal/energyEcal;
01788   } else { 
01789     if( energyEcal>0) { 
01790       eCalib = calibration_->energyEmHad( energyEcal, energyHcal );
01791       slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01792       calibEcal = energyEcal * slopeEcal;
01793       calibHcal = eCalib - calibEcal;
01794     } else { 
01795       eCalib = calibration_->energyHad( energyHcal );
01796       calibEcal = energyEcal;
01797       calibHcal = eCalib - calibEcal;
01798     }
01799   }
01800 
01801   /*
01802   double eCalib = -1;
01803   if( energyEcal>0)
01804     eCalib = calibration_->energyEmHad( energyEcal, energyHcal );
01805   else 
01806     eCalib = calibration_->energyHad( energyHcal );
01807   */
01808   
01809   assert(eCalib>=0);
01810 
01811   // PJ The resolution is on the expected charged energy
01812   // double reso   = neutralHadronEnergyResolution( eCalib );
01813   // reso *= eCalib;
01814   double reso   = neutralHadronEnergyResolution( energyTrk );
01815   reso *= energyTrk;
01816   
01817   // Alex: one should add TK errors as in main PFAlgo
01818   // double TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
01822   //PFAlgo::recoveringClusters( double  totalChargedMomentum, double sumpError2,
01823   //PFAlgo::energyTest( double energyTrk, double sumpError2,  
01824 
01825   
01826   double lowerlimit = energyTrk  - nSigmaHCAL_*reso;
01827   double upperlimit = energyTrk  + nSigmaHCAL_*reso;
01828 
01829   if( debug_ ) {
01830     cout<<"\t\t\tEnergy test: " 
01831         <<"Ecal ="<<energyEcal<<" Hcal="<<energyHcal
01832         <<" ChargedEnergy= "<<energyTrk 
01833         <<" Ecalib="<<eCalib 
01834         <<" Resolution="<<reso 
01835         <<" Interval=" 
01836         <<lowerlimit<<" " 
01837         <<upperlimit<<endl;
01838   }
01839 
01840   if( (eCalib >= lowerlimit) && 
01841       (eCalib <= upperlimit) )
01842     return COMPATIBLE; //compatible
01843   
01844   if( eCalib < lowerlimit )
01845     return NOT_ENOUGH_ENERGY; //more energy needed
01846 
01847   if( eCalib > upperlimit ) {
01848     neutralHadron = eCalib - energyTrk - calibEcal + energyEcal;
01849     return TOO_MUCH_ENERGY; // too much calo energy already!
01850   }
01851 
01852   return COMPATIBLE;
01853 }// energy Test
01854 
01855 
01856 bool PFAlgo::isSatelliteCluster( const reco::PFRecTrack& track, 
01857                                  const PFCluster& cluster ){
01858   //This is to check whether a HCAL cluster could be 
01859   //a satellite cluster of a given track (charged hadron)
01860   //Definitions:
01861   //Track-Hcal: An Hcal cluster can be associated to a 
01862   //            track if it is found in a region around (dr<0.17 ~ 3x3 matrix)
01863   //            the position of the track extrapolated to the Hcal.
01864 
01865   bool link = false;
01866 
01867   if( cluster.layer() == PFLayer::HCAL_BARREL1 ||
01868       cluster.layer() == PFLayer::HCAL_ENDCAP ) { //Hcal case
01869     
01870     const reco::PFTrajectoryPoint& atHCAL 
01871       = track.extrapolatedPoint( reco::PFTrajectoryPoint::HCALEntrance );
01872               
01873     if( atHCAL.isValid() ){ //valid extrapolation?
01874       double tracketa = atHCAL.position().Eta();
01875       double trackphi = atHCAL.position().Phi();
01876       double hcaleta  = cluster.positionREP().Eta();
01877       double hcalphi  = cluster.positionREP().Phi();
01878                   
01879       //distance track-cluster
01880       double deta = hcaleta - tracketa;
01881       double dphi = acos(cos(hcalphi - trackphi));
01882       double dr   = sqrt(deta*deta + dphi*dphi);
01883 
01884       if( debug_ ){
01885         cout<<"\t\t\tSatellite Test " 
01886             <<tracketa<<" "<<trackphi<<" "
01887             <<hcaleta<<" "<<hcalphi<<" dr="<<dr 
01888             <<endl;
01889       }
01890       
01891       //looking if cluster is in the  
01892       //region around the track. 
01893       //Alex: Will have to adjust this cut?
01894       if( dr < 0.17 ) link = true;
01895     }//extrapolation
01896     
01897   }//HCAL
01898   
01899   return link; 
01900 }
01901 
01902 PFAlgo::RecoveryStatus 
01903 PFAlgo::recoveringClusters( double  totalChargedMomentum, 
01904                             double  totalEcal,
01905                             double& totalHcal, 
01906                             const std::vector< reco::PFRecTrackRef >& associatedTracks,
01907                             const reco::PFBlockRef& blockref,
01908                             vector<bool>& active ) {
01909   
01910 
01911   //This fonction should be used to retrieve the satellite 
01912   //HCAL clusters created from interaction(s) of a charged
01913   //particle into the ECAL.
01914   
01915   //Note: Alex 19/11/07: Should also recover missing energy
01916   //in ECAL => to be implemented!
01917 
01918   if(debug_) 
01919     cout<<"\t\t\trecovering clusters"<<endl;
01920 
01921   //Retrieving elements of the block
01922   const reco::PFBlock& block
01923     = *blockref;
01924   const edm::OwnVector< reco::PFBlockElement >& 
01925     elements_h = block.elements();
01926 
01927 
01928   assert( active.size() ==  elements_h.size() );
01929 
01930   RecoveryStatus status = KEEP_SEARCHING;
01931 
01932   for(unsigned iEle=0; iEle<elements_h.size(); iEle++) {
01933 
01934     PFBlockElement::Type type = elements_h[iEle].type();      
01935     if( type != PFBlockElement::HCAL ) continue;
01936     
01937     if(debug_)
01938       cout<<"\t\t\thcal "<<iEle<<" ";
01939 
01940     //is this cluster active ?    
01941 
01942     if( !active[iEle] ) {
01943       if( debug_ ) {
01944         cout<<" not active. skip"<<endl;
01945       }
01946       continue;
01947     }    
01948     
01949     if( debug_ ) {
01950       cout<<" active. Is it a satellite? "<<endl;
01951     }
01952 
01953     //retrieving hcal cluster 
01954     const reco::PFClusterRef hclusterref 
01955       = elements_h[ iEle ].clusterRef();
01956     assert( !hclusterref.isNull() );
01957     
01958     const reco::PFCluster&  hcal = *hclusterref; 
01959 
01960     // if cluster active, 
01961     // test if it is a satellite cluster
01962     bool tobeadded = false;    
01963     for(unsigned iT=0; iT < associatedTracks.size(); ++iT) {
01964 
01965       assert( !associatedTracks[iT].isNull() );
01966 
01967       const reco::PFRecTrack& track_h 
01968         = *associatedTracks[iT];     
01969 
01970       if( isSatelliteCluster( track_h,
01971                               *hclusterref ) ) {
01972         if( debug_ ) {
01973           cout<<"\t\t\tsatellite of track : "<<iT<<endl;
01974         }
01975         tobeadded = true;
01976         break;
01977       }
01978     }//loop tracks
01979 
01980     //not satellite cluster?
01981     if( !tobeadded ) continue;
01982     
01983     totalHcal += hcal.energy();
01984     double neutralHadron = 0.;
01985     double etaH = hclusterref->positionREP().Eta();
01986     double phiH = hclusterref->positionREP().Phi();
01987     EnergyTest entest = energyTest( totalChargedMomentum,
01988                                     totalHcal, totalEcal,
01989                                     etaH, phiH,
01990                                     neutralHadron);
01991     
01992     if( debug_ ){
01993       cout<<"\t\t\tyes, adding hcal energy (" 
01994           <<hcal.energy()<<") to totHcal= "
01995           <<totalHcal 
01996           <<" test="<<entest<<endl;
01997     }
01998 
01999     switch( entest ) {
02000     case COMPATIBLE:
02001       //if entest ==0 then there is enough energy stop here
02002       if( debug_ ) cout<<"\t\t\tRecoveryStop"<<endl; 
02003       active[iEle]=false; 
02004       status = DONE;
02005       break;
02006     case NOT_ENOUGH_ENERGY:
02007       //if entest ==1 not enough energy continue.
02008       if(debug_) cout<<"\t\t\tRecoveryContinue"<<endl;
02009       active[iEle]=false; 
02010       status = KEEP_SEARCHING;   
02011       continue;
02012     case TOO_MUCH_ENERGY:
02013       //if entest ==2 too much energy has been added, 
02014       //create a neutral hadron
02015       unsigned tmpi = reconstructCluster( *hclusterref, 
02016                                           neutralHadron ); 
02017 
02018       // std::cout << "A cluster recovered here " << neutralHadron << std::endl;
02019       
02020       (*pfCandidates_)[tmpi].setEcalEnergy( 0. );
02021       (*pfCandidates_)[tmpi].setHcalEnergy( neutralHadron );
02022       (*pfCandidates_)[tmpi].setPs1Energy( -1 );
02023       (*pfCandidates_)[tmpi].setPs2Energy( -1 );
02024       (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEle );
02025        
02026       active[iEle]=false; 
02027       status = DONE;
02028       break;
02029     default:
02030       assert(0);
02031       //      continue;
02032     }
02033 
02034   }//loop elements
02035 
02036   return status;
02037 } 
02038 
02039 reco::PFBlockRef 
02040 PFAlgo::createBlockRef( const reco::PFBlockCollection& blocks, 
02041                         unsigned bi ) {
02042 
02043   if( blockHandle_.isValid() ) {
02044     return reco::PFBlockRef(  blockHandle_, bi );
02045   } 
02046   else {
02047     return reco::PFBlockRef(  &blocks, bi );
02048   }
02049 }

Generated on Tue Jun 9 17:44:38 2009 for CMSSW by  doxygen 1.5.4