CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/RecoParticleFlow/PFClusterProducer/src/PFClusterAlgo.cc

Go to the documentation of this file.
00001 #include "RecoParticleFlow/PFClusterProducer/interface/PFClusterAlgo.h"
00002 #include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
00003 #include "DataFormats/HcalDetId/interface/HcalDetId.h"
00004 #include "Math/GenVector/VectorUtil.h"
00005 #include "TFile.h"
00006 #include "TH2F.h"
00007 #include "TROOT.h"
00008 
00009 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00010 
00011 #include <stdexcept>
00012 #include <string>
00013 #include <sstream>
00014 
00015 using namespace std;
00016 
00017 unsigned PFClusterAlgo::prodNum_ = 1;
00018 
00019 //for debug only 
00020 //#define PFLOW_DEBUG
00021 
00022 PFClusterAlgo::PFClusterAlgo() :
00023   pfClusters_( new vector<reco::PFCluster> ),
00024   pfRecHitsCleaned_( new vector<reco::PFRecHit> ),
00025   threshBarrel_(0.),
00026   threshPtBarrel_(0.),
00027   threshSeedBarrel_(0.2),
00028   threshPtSeedBarrel_(0.),
00029   threshEndcap_(0.),
00030   threshPtEndcap_(0.),
00031   threshSeedEndcap_(0.6),
00032   threshPtSeedEndcap_(0.),
00033   threshCleanBarrel_(1E5),
00034   minS4S1Barrel_(0.),
00035   threshDoubleSpikeBarrel_(1E9),
00036   minS6S2DoubleSpikeBarrel_(-1.),
00037   threshCleanEndcap_(1E5),
00038   minS4S1Endcap_(0.),
00039   threshDoubleSpikeEndcap_(1E9),
00040   minS6S2DoubleSpikeEndcap_(-1.),
00041   nNeighbours_(4),
00042   posCalcNCrystal_(-1),
00043   posCalcP1_(-1),
00044   showerSigma_(5),
00045   useCornerCells_(false),
00046   cleanRBXandHPDs_(false),
00047   debug_(false) 
00048 {
00049   file_ = 0;
00050   hBNeighbour = 0;
00051   hENeighbour = 0;
00052 }
00053 
00054 void
00055 PFClusterAlgo::write() { 
00056 
00057   if ( file_ ) { 
00058     file_->Write();
00059     cout << "Benchmark output written to file " << file_->GetName() << endl;
00060     file_->Close();
00061   }
00062 
00063 }
00064 
00065 
00066 void PFClusterAlgo::doClustering( const PFRecHitHandle& rechitsHandle ) {
00067   const reco::PFRecHitCollection& rechits = * rechitsHandle;
00068 
00069   // cache the Handle to the rechits
00070   rechitsHandle_ = rechitsHandle;
00071 
00072   // clear rechits mask
00073   mask_.clear();
00074   mask_.resize( rechits.size(), true );
00075 
00076   // perform clustering
00077   doClusteringWorker( rechits );
00078 }
00079 
00080 void PFClusterAlgo::doClustering( const PFRecHitHandle& rechitsHandle, const std::vector<bool> & mask ) {
00081 
00082   const reco::PFRecHitCollection& rechits = * rechitsHandle;
00083 
00084   // cache the Handle to the rechits
00085   rechitsHandle_ = rechitsHandle;
00086 
00087   // use the specified mask, unless it doesn't match with the rechits
00088   mask_.clear();
00089   if (mask.size() == rechits.size()) {
00090       mask_.insert( mask_.end(), mask.begin(), mask.end() );
00091   } else {
00092       edm::LogError("PClusterAlgo::doClustering") << "map size should be " << rechits.size() << ". Will be reinitialized.";
00093       mask_.resize( rechits.size(), true );
00094   }
00095 
00096   // perform clustering
00097 
00098   doClusteringWorker( rechits );
00099 
00100 }
00101 
00102 void PFClusterAlgo::doClustering( const reco::PFRecHitCollection& rechits ) {
00103 
00104   // using rechits without a Handle, clear to avoid a stale member
00105   rechitsHandle_.clear();
00106 
00107   // clear rechits mask
00108   mask_.clear();
00109   mask_.resize( rechits.size(), true );
00110 
00111   // perform clustering
00112   doClusteringWorker( rechits );
00113 
00114 }
00115 
00116 void PFClusterAlgo::doClustering( const reco::PFRecHitCollection& rechits, const std::vector<bool> & mask ) {
00117   // using rechits without a Handle, clear to avoid a stale member
00118 
00119   rechitsHandle_.clear();
00120 
00121   // use the specified mask, unless it doesn't match with the rechits
00122   mask_.clear();
00123 
00124   if (mask.size() == rechits.size()) {
00125       mask_.insert( mask_.end(), mask.begin(), mask.end() );
00126   } else {
00127       edm::LogError("PClusterAlgo::doClustering") << "map size should be " << rechits.size() << ". Will be reinitialized.";
00128       mask_.resize( rechits.size(), true );
00129   }
00130 
00131   // perform clustering
00132   doClusteringWorker( rechits );
00133 
00134 }
00135 
00136 
00137 void PFClusterAlgo::doClusteringWorker( const reco::PFRecHitCollection& rechits ) {
00138 
00139 
00140   if ( pfClusters_.get() )
00141     pfClusters_->clear();
00142   else 
00143     pfClusters_.reset( new std::vector<reco::PFCluster> );
00144 
00145 
00146   if ( pfRecHitsCleaned_.get() )
00147     pfRecHitsCleaned_->clear();
00148   else 
00149     pfRecHitsCleaned_.reset( new std::vector<reco::PFRecHit> );
00150 
00151 
00152   eRecHits_.clear();
00153 
00154   for ( unsigned i = 0; i < rechits.size(); i++ ){
00155 
00156     eRecHits_.insert( make_pair( rechit(i, rechits).energy(), i) );
00157   }
00158 
00159   color_.clear(); 
00160   color_.resize( rechits.size(), 0 );
00161 
00162   seedStates_.clear();
00163   seedStates_.resize( rechits.size(), UNKNOWN );
00164 
00165   usedInTopo_.clear();
00166   usedInTopo_.resize( rechits.size(), false );
00167 
00168   if ( cleanRBXandHPDs_ ) cleanRBXAndHPD( rechits);
00169 
00170   // look for seeds.
00171 
00172   findSeeds( rechits );
00173 
00174   // build topological clusters around seeds
00175   buildTopoClusters( rechits );
00176 
00177   // look for PFClusters inside each topological cluster (one per seed)
00178   
00179   
00180   //  int ix=0;
00181   //  for (reco::PFRecHitCollection::const_iterator cand =rechits.begin(); cand<rechits.end(); cand++){
00182   //    cout <<ix++<<" "<< cand->layer()<<endl;
00183   //  }
00184 
00185 
00186   for(unsigned i=0; i<topoClusters_.size(); i++) {
00187 
00188     const std::vector< unsigned >& topocluster = topoClusters_[i];
00189 
00190     buildPFClusters( topocluster, rechits ); 
00191 
00192   }
00193 
00194 }
00195 
00196 
00197 double PFClusterAlgo::parameter( Parameter paramtype, 
00198                                  PFLayer::Layer layer,
00199                                  unsigned iCoeff, int iring )  const {
00200   
00201 
00202   double value = 0;
00203 
00204   switch( layer ) {
00205 
00206   case PFLayer::ECAL_BARREL:
00207   case PFLayer::HCAL_BARREL1:
00208   case PFLayer::HCAL_BARREL2: //  HO. 
00209                                  
00210     switch(paramtype) {
00211     case THRESH:
00212       value = (iring==0) ? threshBarrel_ : threshEndcap_; //For HO Ring0 and others
00213       break;
00214     case SEED_THRESH:
00215       value = (iring==0) ? threshSeedBarrel_ : threshSeedEndcap_;
00216       break;
00217     case PT_THRESH:
00218       value = (iring==0) ? threshPtBarrel_ : threshPtEndcap_;
00219       break;
00220     case SEED_PT_THRESH:
00221       value = (iring==0) ? threshPtSeedBarrel_ : threshPtSeedEndcap_;
00222       break;
00223     case CLEAN_THRESH:
00224       value = threshCleanBarrel_;
00225       break;
00226     case CLEAN_S4S1:
00227       value = minS4S1Barrel_[iCoeff];
00228       break;
00229     case DOUBLESPIKE_THRESH:
00230       value = threshDoubleSpikeBarrel_;
00231       break;
00232     case DOUBLESPIKE_S6S2:
00233       value = minS6S2DoubleSpikeBarrel_;
00234       break;
00235     default:
00236       cerr<<"PFClusterAlgo::parameter : unknown parameter type "
00237           <<paramtype<<endl;
00238       assert(0);
00239     }
00240     break;
00241   case PFLayer::ECAL_ENDCAP:
00242   case PFLayer::HCAL_ENDCAP:
00243   case PFLayer::PS1:
00244   case PFLayer::PS2:
00245   case PFLayer::HF_EM:
00246   case PFLayer::HF_HAD:
00247     // and no particle flow in VFCAL
00248     switch(paramtype) {
00249     case THRESH:
00250       value = threshEndcap_;
00251       break;
00252     case SEED_THRESH:
00253       value = threshSeedEndcap_;
00254       break;
00255     case PT_THRESH:
00256       value = threshPtEndcap_;
00257       break;
00258     case SEED_PT_THRESH:
00259       value = threshPtSeedEndcap_;
00260       break;
00261     case CLEAN_THRESH:
00262       value = threshCleanEndcap_;
00263       break;
00264     case CLEAN_S4S1:
00265       value = minS4S1Endcap_[iCoeff];
00266       break;
00267     case DOUBLESPIKE_THRESH:
00268       value = threshDoubleSpikeEndcap_;
00269       break;
00270     case DOUBLESPIKE_S6S2:
00271       value = minS6S2DoubleSpikeEndcap_;
00272       break;
00273     default:
00274       cerr<<"PFClusterAlgo::parameter : unknown parameter type "
00275           <<paramtype<<endl;
00276       assert(0);
00277     }
00278     break;
00279   default:
00280     cerr<<"PFClusterAlgo::parameter : unknown layer "<<layer<<endl;
00281     assert(0);
00282     break;
00283   }
00284 
00285   return value;
00286 }
00287 
00288 
00289 void 
00290 PFClusterAlgo::cleanRBXAndHPD(  const reco::PFRecHitCollection& rechits ) {
00291 
00292   std::map< int, std::vector<unsigned> > hpds;
00293   std::map< int, std::vector<unsigned> > rbxs;
00294 
00295   for(EH ih = eRecHits_.begin(); ih != eRecHits_.end(); ih++ ) {
00296 
00297     unsigned  rhi      = ih->second; 
00298 
00299     if(! masked(rhi) ) continue;
00300     // rechit was asked to be processed
00301     const reco::PFRecHit& rhit = rechit( rhi, rechits);
00302     //double energy = rhit.energy();
00303     int layer = rhit.layer();
00304     if ( layer != PFLayer::HCAL_BARREL1 &&
00305          layer != PFLayer::HCAL_ENDCAP ) break; 
00306       // layer != PFLayer::HCAL_BARREL2) break; //BARREL2 for HO : need specific cleaning
00307     HcalDetId theHcalDetId = HcalDetId(rhit.detId());
00308     int ieta = theHcalDetId.ieta();
00309     int iphi = theHcalDetId.iphi();
00310     int ihpd = ieta < 0 ?  
00311       ( layer == PFLayer::HCAL_ENDCAP ?  -(iphi+1)/2-100 : -iphi ) : 
00312       ( layer == PFLayer::HCAL_ENDCAP ?   (iphi+1)/2+100 :  iphi ) ;      
00313     hpds[ihpd].push_back(rhi);
00314     int irbx = ieta < 0 ? 
00315       ( layer == PFLayer::HCAL_ENDCAP ?  -(iphi+5)/4 - 20 : -(iphi+5)/4 ) : 
00316       ( layer == PFLayer::HCAL_ENDCAP ?   (iphi+5)/4 + 20 :  (iphi+5)/4 ) ;      
00317     if ( irbx == 19 ) irbx = 1;
00318     else if ( irbx == -19 ) irbx = -1;
00319     else if ( irbx == 39 ) irbx = 21;
00320     else if ( irbx == -39 ) irbx = -21;
00321     rbxs[irbx].push_back(rhi);
00322   }
00323 
00324   // Loop on readout boxes
00325   for ( std::map<int, std::vector<unsigned> >::iterator itrbx = rbxs.begin();
00326         itrbx != rbxs.end(); ++itrbx ) { 
00327     if ( ( abs(itrbx->first)<20 && itrbx->second.size() > 30 ) || 
00328          ( abs(itrbx->first)>20 && itrbx->second.size() > 30 ) ) { 
00329       const std::vector<unsigned>& rhits = itrbx->second;
00330       double totalEta = 0.;
00331       double totalEtaW = 0.;
00332       double totalPhi = 0.;
00333       double totalPhiW = 0.;
00334       double totalEta2 = 1E-9;
00335       double totalEta2W = 1E-9;
00336       double totalPhi2 = 1E-9;
00337       double totalPhi2W = 1E-9;
00338       double totalEnergy = 0.;
00339       double totalEnergy2 = 1E-9;
00340       unsigned nSeeds = rhits.size();
00341       unsigned nSeeds0 = rhits.size();
00342       std::map< int,std::vector<unsigned> > theHPDs;
00343       std::multimap< double,unsigned > theEnergies;
00344       for ( unsigned jh=0; jh < rhits.size(); ++jh ) {
00345         const reco::PFRecHit& hit = rechit(rhits[jh], rechits);
00346         // Check if the hit is a seed
00347         unsigned nN = 0;
00348         bool isASeed = true;
00349         const vector<unsigned>& neighbours4 = *(& hit.neighbours4());
00350         for(unsigned in=0; in<neighbours4.size(); in++) {
00351           const reco::PFRecHit& neighbour = rechit( neighbours4[in], rechits ); 
00352           // one neighbour has a higher energy -> the tested rechit is not a seed
00353           if( neighbour.energy() > hit.energy() ) {
00354             --nSeeds;
00355             --nSeeds0;
00356             isASeed = false;
00357             break;
00358           } else {
00359             if ( neighbour.energy() > 0.4 ) ++nN;
00360           }
00361         }
00362         if ( isASeed && !nN ) --nSeeds0;
00363 
00364         HcalDetId theHcalDetId = HcalDetId(hit.detId());
00365         // int ieta = theHcalDetId.ieta();
00366         int iphi = theHcalDetId.iphi();
00367         // std::cout << "Hit : " << hit.energy() << " " << ieta << " " << iphi << std::endl;
00368         if ( hit.layer() == PFLayer::HCAL_BARREL1 )
00369           theHPDs[iphi].push_back(rhits[jh]);
00370         else
00371           theHPDs[(iphi-1)/2].push_back(rhits[jh]);
00372         theEnergies.insert(std::pair<double,unsigned>(hit.energy(),rhits[jh]));
00373         totalEnergy += hit.energy();
00374         totalPhi += fabs(hit.position().phi());
00375         totalPhiW += hit.energy()*fabs(hit.position().phi());
00376         totalEta += hit.position().eta();
00377         totalEtaW += hit.energy()*hit.position().eta();
00378         totalEnergy2 += hit.energy()*hit.energy();
00379         totalPhi2 += hit.position().phi()*hit.position().phi();
00380         totalPhi2W += hit.energy()*hit.position().phi()*hit.position().phi();
00381         totalEta2 += hit.position().eta()*hit.position().eta();
00382         totalEta2W += hit.energy()*hit.position().eta()*hit.position().eta();
00383       }
00384       // totalPhi /= totalEnergy;
00385       totalPhi /= rhits.size();
00386       totalEta /= rhits.size();
00387       totalPhiW /= totalEnergy;
00388       totalEtaW /= totalEnergy;
00389       totalPhi2 /= rhits.size();
00390       totalEta2 /= rhits.size();
00391       totalPhi2W /= totalEnergy;
00392       totalEta2W /= totalEnergy;
00393       totalPhi2 = std::sqrt(totalPhi2 - totalPhi*totalPhi);
00394       totalEta2 = std::sqrt(totalEta2 - totalEta*totalEta);
00395       totalPhi2W = std::sqrt(totalPhi2W - totalPhiW*totalPhiW);
00396       totalEta2W = std::sqrt(totalEta2W - totalEtaW*totalEtaW);
00397       totalEnergy /= rhits.size();
00398       totalEnergy2 /= rhits.size();
00399       totalEnergy2 = std::sqrt(totalEnergy2 - totalEnergy*totalEnergy);
00400       //if ( totalPhi2W/totalEta2W < 0.18 ) { 
00401       if ( nSeeds0 > 6 ) {
00402         unsigned nHPD15 = 0;
00403         for ( std::map<int, std::vector<unsigned> >::iterator itHPD = theHPDs.begin();
00404               itHPD != theHPDs.end(); ++itHPD ) { 
00405           int hpdN = itHPD->first;
00406           const std::vector<unsigned>& hpdHits = itHPD->second;
00407           if ( ( abs(hpdN) < 100 && hpdHits.size() > 14 ) || 
00408                ( abs(hpdN) > 100 && hpdHits.size() > 14 ) ) ++nHPD15;
00409         }
00410         if ( nHPD15 > 1 ) {
00411           /*
00412           std::cout << "Read out box numero " << itrbx->first 
00413                     << " has " << itrbx->second.size() << " hits in it !"
00414                     << std::endl << "sigma Eta/Phi = " << totalEta2 << " " << totalPhi2 << " " << totalPhi2/totalEta2
00415                     << std::endl << "sigma EtaW/PhiW = " << totalEta2W << " " << totalPhi2W << " " << totalPhi2W/totalEta2W
00416                     << std::endl << "E = " << totalEnergy << " +/- " << totalEnergy2
00417                     << std::endl << "nSeeds = " << nSeeds << " " << nSeeds0
00418                     << std::endl;
00419           for ( std::map<int, std::vector<unsigned> >::iterator itHPD = theHPDs.begin();
00420                 itHPD != theHPDs.end(); ++itHPD ) { 
00421             unsigned hpdN = itHPD->first;
00422             const std::vector<unsigned>& hpdHits = itHPD->second;
00423             std::cout << "HPD number " << hpdN << " contains " << hpdHits.size() << " hits" << std::endl;
00424           }
00425           */
00426           std::multimap<double, unsigned >::iterator ntEn = theEnergies.end();
00427           --ntEn;
00428           unsigned nn = 0;
00429           double threshold = 1.;
00430           for ( std::multimap<double, unsigned >::iterator itEn = theEnergies.begin();
00431                 itEn != theEnergies.end(); ++itEn ) {
00432             ++nn;
00433             if ( nn < 5 ) { 
00434               mask_[itEn->second] = false;
00435             } else if ( nn == 5 ) { 
00436               threshold = itEn->first * 5.;
00437               mask_[itEn->second] = false;
00438             } else { 
00439               if ( itEn->first < threshold ) mask_[itEn->second] = false;
00440             }
00441             if ( !masked(itEn->second) ) { 
00442               reco::PFRecHit theCleanedHit(rechit(itEn->second, rechits));
00443               //theCleanedHit.setRescale(0.);
00444               pfRecHitsCleaned_->push_back(theCleanedHit);
00445             }
00446             /*
00447             if ( !masked(itEn->second) ) 
00448               std::cout << "Hit Energies = " << itEn->first 
00449                         << " " << ntEn->first/itEn->first << " masked " << std::endl;
00450             else 
00451               std::cout << "Hit Energies = " << itEn->first 
00452                         << " " << ntEn->first/itEn->first << " kept for clustering " << std::endl;
00453             */
00454           }
00455         }
00456       }
00457     }
00458   }
00459 
00460   // Loop on hpd's
00461   std::map<int, std::vector<unsigned> >::iterator neighbour1;
00462   std::map<int, std::vector<unsigned> >::iterator neighbour2;
00463   std::map<int, std::vector<unsigned> >::iterator neighbour0;
00464   std::map<int, std::vector<unsigned> >::iterator neighbour3;
00465   unsigned size1 = 0;
00466   unsigned size2 = 0;
00467   for ( std::map<int, std::vector<unsigned> >::iterator ithpd = hpds.begin();
00468         ithpd != hpds.end(); ++ithpd ) { 
00469 
00470     const std::vector<unsigned>& rhits = ithpd->second;
00471     std::multimap< double,unsigned > theEnergies;
00472     double totalEnergy = 0.;
00473     double totalEnergy2 = 1E-9;
00474     for ( unsigned jh=0; jh < rhits.size(); ++jh ) {
00475       const reco::PFRecHit& hit = rechit(rhits[jh], rechits);
00476       totalEnergy += hit.energy();
00477       totalEnergy2 += hit.energy()*hit.energy();
00478       theEnergies.insert(std::pair<double,unsigned>(hit.energy(),rhits[jh]));
00479     }
00480     totalEnergy /= rhits.size();
00481     totalEnergy2 /= rhits.size();
00482     totalEnergy2 = std::sqrt(totalEnergy2 - totalEnergy*totalEnergy);
00483 
00484     if ( ithpd->first == 1 ) neighbour1 = hpds.find(72);
00485     else if ( ithpd->first == -1 ) neighbour1 = hpds.find(-72);
00486     else if ( ithpd->first == 101 ) neighbour1 = hpds.find(136);
00487     else if ( ithpd->first == -101 ) neighbour1 = hpds.find(-136);
00488     else neighbour1 = ithpd->first > 0 ? hpds.find(ithpd->first-1) : hpds.find(ithpd->first+1) ;
00489 
00490     if ( ithpd->first == 72 ) neighbour2 = hpds.find(1);
00491     else if ( ithpd->first == -72 ) neighbour2 = hpds.find(-1);
00492     else if ( ithpd->first == 136 ) neighbour2 = hpds.find(101);
00493     else if ( ithpd->first == -136 ) neighbour2 = hpds.find(-101);
00494     else neighbour2 = ithpd->first > 0 ? hpds.find(ithpd->first+1) : hpds.find(ithpd->first-1) ;
00495 
00496     if ( neighbour1 != hpds.end() ) { 
00497       if ( neighbour1->first == 1 ) neighbour0 = hpds.find(72);
00498       else if ( neighbour1->first == -1 ) neighbour0 = hpds.find(-72);
00499       else if ( neighbour1->first == 101 ) neighbour0 = hpds.find(136);
00500       else if ( neighbour1->first == -101 ) neighbour0 = hpds.find(-136);
00501       else neighbour0 = neighbour1->first > 0 ? hpds.find(neighbour1->first-1) : hpds.find(neighbour1->first+1) ;
00502     } 
00503 
00504     if ( neighbour2 != hpds.end() ) { 
00505       if ( neighbour2->first == 72 ) neighbour3 = hpds.find(1);
00506       else if ( neighbour2->first == -72 ) neighbour3 = hpds.find(-1);
00507       else if ( neighbour2->first == 136 ) neighbour3 = hpds.find(101);
00508       else if ( neighbour2->first == -136 ) neighbour3 = hpds.find(-101);
00509       else neighbour3 = neighbour2->first > 0 ? hpds.find(neighbour2->first+1) : hpds.find(neighbour2->first-1) ;
00510     }
00511 
00512     size1 = neighbour1 != hpds.end() ? neighbour1->second.size() : 0;
00513     size2 = neighbour2 != hpds.end() ? neighbour2->second.size() : 0;
00514 
00515     // Also treat the case of two neighbouring HPD's not in the same RBX
00516     if ( size1 > 10 ) { 
00517       if ( ( abs(neighbour1->first) > 100 && neighbour1->second.size() > 15 ) || 
00518            ( abs(neighbour1->first) < 100 && neighbour1->second.size() > 12 ) ) 
00519         size1 = neighbour0 != hpds.end() ? neighbour0->second.size() : 0;
00520     }
00521     if ( size2 > 10 ) { 
00522       if ( ( abs(neighbour2->first) > 100 && neighbour2->second.size() > 15 ) || 
00523            ( abs(neighbour2->first) < 100 && neighbour2->second.size() > 12 ) ) 
00524         size2 = neighbour3 != hpds.end() ? neighbour3->second.size() : 0;
00525     }
00526     
00527     if ( ( abs(ithpd->first) > 100 && ithpd->second.size() > 15 ) || 
00528          ( abs(ithpd->first) < 100 && ithpd->second.size() > 12 ) )
00529       if ( (float)(size1 + size2)/(float)ithpd->second.size() < 1.0 ) {
00530         /* 
00531         std::cout << "HPD numero " << ithpd->first 
00532                   << " has " << ithpd->second.size() << " hits in it !" << std::endl
00533                   << "Neighbours : " << size1 << " " << size2
00534                   << std::endl;
00535         */
00536         std::multimap<double, unsigned >::iterator ntEn = theEnergies.end();
00537         --ntEn;
00538         unsigned nn = 0;
00539         double threshold = 1.;
00540         for ( std::multimap<double, unsigned >::iterator itEn = theEnergies.begin();
00541               itEn != theEnergies.end(); ++itEn ) {
00542           ++nn;
00543           if ( nn < 5 ) { 
00544             mask_[itEn->second] = false;
00545           } else if ( nn == 5 ) { 
00546             threshold = itEn->first * 2.5;
00547             mask_[itEn->second] = false;
00548           } else { 
00549             if ( itEn->first < threshold ) mask_[itEn->second] = false;
00550           }
00551           if ( !masked(itEn->second) ) { 
00552             reco::PFRecHit theCleanedHit(rechit(itEn->second, rechits));
00553             //theCleanedHit.setRescale(0.);
00554             pfRecHitsCleaned_->push_back(theCleanedHit);
00555           }
00556           /*
00557           if ( !masked(itEn->second) ) 
00558             std::cout << "Hit Energies = " << itEn->first 
00559                       << " " << ntEn->first/itEn->first << " masked " << std::endl;
00560           else 
00561             std::cout << "Hit Energies = " << itEn->first 
00562             << " " << ntEn->first/itEn->first << " kept for clustering " << std::endl;
00563           */
00564         }
00565       }
00566   }
00567 
00568 }
00569 
00570 
00571 void PFClusterAlgo::findSeeds( const reco::PFRecHitCollection& rechits ) {
00572 
00573   seeds_.clear();
00574 
00575   // should replace this by the message logger.
00576 #ifdef PFLOW_DEBUG
00577   if(debug_) 
00578     cout<<"PFClusterAlgo::findSeeds : start"<<endl;
00579 #endif
00580 
00581 
00582   // An empty list of neighbours
00583   const vector<unsigned> noNeighbours(0, static_cast<unsigned>(0));
00584 
00585   // loop on rechits (sorted by decreasing energy - not E_T)
00586 
00587   for(EH ih = eRecHits_.begin(); ih != eRecHits_.end(); ih++ ) {
00588 
00589     unsigned  rhi      = ih->second; 
00590 
00591     if(! masked(rhi) ) continue;
00592     // rechit was asked to be processed
00593 
00594     double    rhenergy = ih->first;   
00595     const reco::PFRecHit& wannaBeSeed = rechit(rhi, rechits);
00596      
00597     if( seedStates_[rhi] == NO ) continue;
00598     // this hit was already tested, and is not a seed
00599  
00600     // determine seed energy threshold depending on the detector
00601     int layer = wannaBeSeed.layer();
00602     //for HO Ring0 and 1/2 boundary
00603     
00604     int iring = 0;
00605     if (layer==PFLayer::HCAL_BARREL2 && abs(wannaBeSeed.positionREP().Eta())>0.34) iring= 1;
00606 
00607     double seedThresh = parameter( SEED_THRESH, 
00608                                    static_cast<PFLayer::Layer>(layer), 0, iring );
00609 
00610     double seedPtThresh = parameter( SEED_PT_THRESH, 
00611                                      static_cast<PFLayer::Layer>(layer), 0., iring );
00612 
00613     double cleanThresh = parameter( CLEAN_THRESH, 
00614                                     static_cast<PFLayer::Layer>(layer), 0, iring );
00615 
00616     double minS4S1_a = parameter( CLEAN_S4S1, 
00617                                   static_cast<PFLayer::Layer>(layer), 0, iring );
00618 
00619     double minS4S1_b = parameter( CLEAN_S4S1, 
00620                                   static_cast<PFLayer::Layer>(layer), 1, iring );
00621 
00622     double doubleSpikeThresh = parameter( DOUBLESPIKE_THRESH, 
00623                                           static_cast<PFLayer::Layer>(layer), 0, iring );
00624 
00625     double doubleSpikeS6S2 = parameter( DOUBLESPIKE_S6S2, 
00626                                         static_cast<PFLayer::Layer>(layer), 0, iring );
00627 
00628 #ifdef PFLOW_DEBUG
00629     if(debug_) 
00630       cout<<"layer:"<<layer<<" seedThresh:"<<seedThresh<<endl;
00631 #endif
00632 
00633 
00634     if( rhenergy < seedThresh || (seedPtThresh>0. && wannaBeSeed.pt2() < seedPtThresh*seedPtThresh )) {
00635       seedStates_[rhi] = NO; 
00636       continue;
00637     } 
00638 
00639     // Find the cell unused neighbours
00640     const vector<unsigned>* nbp;
00641     double tighterE = 1.0;
00642     double tighterF = 1.0;
00643 
00644     switch ( layer ) { 
00645     case PFLayer::ECAL_BARREL:         
00646     case PFLayer::ECAL_ENDCAP:       
00647     case PFLayer::HCAL_BARREL1:
00648     case PFLayer::HCAL_BARREL2:
00649     case PFLayer::HCAL_ENDCAP:
00650       tighterE = 2.0;
00651       tighterF = 3.0;
00652     case PFLayer::HF_EM:
00653     case PFLayer::HF_HAD:
00654       if( nNeighbours_ == 4 ) {
00655         nbp = & wannaBeSeed.neighbours4();
00656       }
00657       else if( nNeighbours_ == 8 ) {
00658         nbp = & wannaBeSeed.neighbours8();
00659       }
00660       else if( nNeighbours_ == 0 ) {
00661         nbp = & noNeighbours;
00662         // Allows for no clustering at all: all rechits are clusters.
00663         // Useful for HF
00664       }
00665       else {
00666         cerr<<"you're not allowed to set n neighbours to "
00667             <<nNeighbours_<<endl;
00668         assert(0);
00669       }
00670       break;
00671     case PFLayer::PS1:       
00672     case PFLayer::PS2:     
00673       nbp = & wannaBeSeed.neighbours4();
00674       break;
00675 
00676     default:
00677       cerr<<"CellsEF::PhotonSeeds : unknown layer "<<layer<<endl;
00678       assert(0);
00679     }
00680 
00681     const vector<unsigned>& neighbours = *nbp;
00682 
00683       
00684     // Select as a seed if all neighbours have a smaller energy
00685 
00686     seedStates_[rhi] = YES;
00687     for(unsigned in=0; in<neighbours.size(); in++) {
00688         
00689       unsigned rhj =  neighbours[in];
00690       // Ignore neighbours already masked
00691       if ( !masked(rhj) ) continue;
00692       const reco::PFRecHit& neighbour = rechit( rhj, rechits ); 
00693         
00694       // one neighbour has a higher energy -> the tested rechit is not a seed
00695       if( neighbour.energy() > wannaBeSeed.energy() ) {
00696         seedStates_[rhi] = NO;
00697         break;
00698       }
00699     }
00700     
00701     // Cleaning : check energetic, isolated seeds, likely to come from erratic noise.
00702     if ( file_ || wannaBeSeed.energy() > cleanThresh ) { 
00703       
00704       const vector<unsigned>& neighbours4 = *(& wannaBeSeed.neighbours4());
00705       // Determine the fraction of surrounding energy
00706       double surroundingEnergy = wannaBeSeed.energyUp();
00707       double neighbourEnergy = 0.;
00708       double layerEnergy = 0.;
00709       for(unsigned in4=0; in4<neighbours4.size(); in4++) {
00710         unsigned rhj =  neighbours4[in4];
00711         // Ignore neighbours already masked
00712         if ( !masked(rhj) ) continue;
00713         const reco::PFRecHit& neighbour = rechit( rhj, rechits ); 
00714         surroundingEnergy += neighbour.energy() + neighbour.energyUp();
00715         neighbourEnergy += neighbour.energy() + neighbour.energyUp();
00716         layerEnergy += neighbour.energy();
00717       }
00718       // Fraction 0 is the balance between EM and HAD layer for this tower
00719       // double fraction0 = layer == PFLayer::HF_EM || layer == PFLayer::HF_HAD ? 
00720       //   wannaBeSeed.energyUp()/wannaBeSeed.energy() : 1.;
00721       // Fraction 1 is the balance between the hit and its neighbours from both layers
00722       double fraction1 = surroundingEnergy/wannaBeSeed.energy();
00723       // Fraction 2 is the balance between the tower and the tower neighbours
00724       // double fraction2 = neighbourEnergy/(wannaBeSeed.energy()+wannaBeSeed.energyUp());
00725       // Fraction 3 is the balance between the hits and the hits neighbours in the same layer.
00726       // double fraction3 = layerEnergy/(wannaBeSeed.energy());
00727       // Mask the seed and the hit if energetic/isolated rechit
00728       // if ( fraction0 < minS4S1 || fraction1 < minS4S1 || fraction2 < minS4S1 || fraction3 < minS4S1 ) {
00729       // if ( fraction1 < minS4S1 || ( wannaBeSeed.energy() > 1.5*cleanThresh && fraction0 + fraction3 < minS4S1 ) ) {
00730       
00731       if ( file_ ) { 
00732         if ( layer == PFLayer::ECAL_BARREL || layer == PFLayer::HCAL_BARREL1 || layer == PFLayer::HCAL_BARREL2) { //BARREL2 for HO 
00733           /*
00734           double eta = wannaBeSeed.position().eta();
00735           double phi = wannaBeSeed.position().phi();
00736           std::pair<double,double> dcr = dCrack(phi,eta);
00737           double dcrmin = std::min(dcr.first, dcr.second);
00738           if ( dcrmin > 1. ) 
00739           */
00740           hBNeighbour->Fill(1./wannaBeSeed.energy(), fraction1);
00741         } else if ( fabs(wannaBeSeed.position().eta()) < 5.0  ) {
00742           if ( layer == PFLayer::ECAL_ENDCAP || layer == PFLayer::HCAL_ENDCAP ) { 
00743             if ( wannaBeSeed.energy() > 1000 ) { 
00744               if ( fabs(wannaBeSeed.position().eta()) < 2.8  ) 
00745                 hENeighbour->Fill(1./wannaBeSeed.energy(), fraction1);
00746             }
00747           } else { 
00748             hENeighbour->Fill(1./wannaBeSeed.energy(), fraction1);
00749           }
00750         }
00751       }
00752       
00753       if ( wannaBeSeed.energy() > cleanThresh ) { 
00754         double f1Cut = minS4S1_a * log10(wannaBeSeed.energy()) + minS4S1_b;
00755         if ( fraction1 < f1Cut ) {
00756           // Double the energy cleaning threshold when close to the ECAL/HCAL - HF transition
00757           double eta = wannaBeSeed.position().eta();
00758           double phi = wannaBeSeed.position().phi();
00759           std::pair<double,double> dcr = dCrack(phi,eta);
00760           double dcrmin = layer == PFLayer::ECAL_BARREL ? std::min(dcr.first, dcr.second) : dcr.second;
00761           eta = fabs(eta);
00762           if (   eta < 5.0 &&                         // No cleaning for the HF border 
00763                  ( ( eta < 2.85 && dcrmin > 1. ) || 
00764                    ( rhenergy > tighterE*cleanThresh && 
00765                      fraction1 < f1Cut/tighterF ) )  // Tighter cleaning for various cracks 
00766               ) { 
00767             seedStates_[rhi] = CLEAN;
00768             mask_[rhi] = false;
00769             reco::PFRecHit theCleanedHit(wannaBeSeed);
00770             //theCleanedHit.setRescale(0.);
00771             pfRecHitsCleaned_->push_back(theCleanedHit);
00772             /*
00773             std::cout << "A seed with E/pT/eta/phi = " << wannaBeSeed.energy() << " " << wannaBeSeed.energyUp() 
00774                       << " " << sqrt(wannaBeSeed.pt2()) << " " << wannaBeSeed.position().eta() << " " << phi 
00775                       << " and with surrounding fractions = " << fraction0 << " " << fraction1 
00776                       << " " << fraction2 << " " << fraction3
00777                       << " in layer " << layer 
00778                       << " had been cleaned " << std::endl
00779                       << " Distances to cracks : " << dcr.first << " " << dcr.second << std::endl
00780                       << "(Cuts were : " << cleanThresh << " and " << f1Cut << ")" << std::endl; 
00781             */
00782           }
00783         }
00784       }
00785     }
00786 
00787     // Clean double spikes
00788     if ( mask_[rhi] && wannaBeSeed.energy() > doubleSpikeThresh ) {
00789       // Determine energy surrounding the seed and the most energetic neighbour
00790       double surroundingEnergyi = 0.;
00791       double enmax = -999.;
00792       unsigned mostEnergeticNeighbour = 0;
00793       const vector<unsigned>& neighbours4i = *(& wannaBeSeed.neighbours4());
00794       for(unsigned in4=0; in4<neighbours4i.size(); in4++) {
00795         unsigned rhj =  neighbours4i[in4];
00796         if ( !masked(rhj) ) continue;
00797         const reco::PFRecHit& neighbouri = rechit( rhj, rechits );
00798         surroundingEnergyi += neighbouri.energy();
00799         if ( neighbouri.energy() > enmax ) { 
00800           enmax = neighbouri.energy();
00801           mostEnergeticNeighbour = rhj;
00802         }
00803       }
00804       // Is there an energetic neighbour ?
00805       if ( enmax > 0. ) { 
00806         unsigned rhj = mostEnergeticNeighbour;
00807         const reco::PFRecHit& neighbouri = rechit( rhj, rechits );
00808         double surroundingEnergyj = 0.;
00809         //if ( mask_[rhj] && neighbouri.energy() > doubleSpikeThresh ) {
00810         // Determine energy surrounding the energetic neighbour
00811         const vector<unsigned>& neighbours4j = *(& neighbouri.neighbours4());
00812         for(unsigned jn4=0; jn4<neighbours4j.size(); jn4++) {
00813           unsigned rhk =  neighbours4j[jn4];
00814           const reco::PFRecHit& neighbourj = rechit( rhk, rechits ); 
00815           surroundingEnergyj += neighbourj.energy();
00816         }
00817         // The energy surrounding the double spike candidate 
00818         double surroundingEnergyFraction = 
00819           (surroundingEnergyi+surroundingEnergyj) / (wannaBeSeed.energy()+neighbouri.energy()) - 1.;
00820         if ( surroundingEnergyFraction < doubleSpikeS6S2 ) { 
00821           double eta = wannaBeSeed.position().eta();
00822           double phi = wannaBeSeed.position().phi();
00823           std::pair<double,double> dcr = dCrack(phi,eta);
00824           double dcrmin = layer == PFLayer::ECAL_BARREL ? std::min(dcr.first, dcr.second) : dcr.second;
00825           eta = fabs(eta);
00826           if (  ( eta < 5.0 && dcrmin > 1. ) ||
00827                 ( wannaBeSeed.energy() > tighterE*doubleSpikeThresh &&
00828                   surroundingEnergyFraction < doubleSpikeS6S2/tighterF ) ) {
00829             /*
00830             std::cout << "Double spike cleaned : Energies = " << wannaBeSeed.energy()
00831                       << " " << neighbouri.energy() 
00832                       << " surrounded by only " << surroundingEnergyFraction*100.
00833                       << "% of the two spike energies at eta/phi/distance to closest crack = "  
00834                       <<        eta << " " << phi << " " << dcrmin
00835                       << std::endl;
00836             */
00837             // mask the seed
00838             seedStates_[rhi] = CLEAN;
00839             mask_[rhi] = false;
00840             reco::PFRecHit theCleanedSeed(wannaBeSeed);
00841             pfRecHitsCleaned_->push_back(theCleanedSeed);
00842             // mask the neighbour
00843             seedStates_[rhj] = CLEAN;
00844             mask_[rhj] = false;
00845             reco::PFRecHit theCleanedNeighbour(wannaBeSeed);
00846             pfRecHitsCleaned_->push_back(neighbouri);
00847           }
00848         }
00849       } else { 
00850         /*
00851         std::cout << "PFClusterAlgo : Double spike search : An isolated cell should have been killed " << std::endl 
00852                   << "but is going through the double spike search!" << std::endl;
00853         */
00854       }
00855     }
00856 
00857     if ( seedStates_[rhi] == YES ) {
00858 
00859       // seeds_ contains the indices of all seeds. 
00860       seeds_.push_back( rhi );
00861       
00862       // marking the rechit
00863       paint(rhi, SEED);
00864         
00865       // then all neighbours cannot be seeds and are flagged as such
00866       for(unsigned in=0; in<neighbours.size(); in++) {
00867         seedStates_[ neighbours[in] ] = NO;
00868       }
00869     }
00870 
00871   }  
00872 
00873 #ifdef PFLOW_DEBUG
00874   if(debug_) 
00875     cout<<"PFClusterAlgo::findSeeds : done"<<endl;
00876 #endif
00877 }
00878 
00879 
00880 
00881   
00882 void PFClusterAlgo::buildTopoClusters( const reco::PFRecHitCollection& rechits ){
00883 
00884   topoClusters_.clear(); 
00885   
00886 #ifdef PFLOW_DEBUG
00887   if(debug_) 
00888     cout<<"PFClusterAlgo::buildTopoClusters start"<<endl;
00889 #endif
00890   
00891   for(unsigned is = 0; is<seeds_.size(); is++) {
00892     
00893     unsigned rhi = seeds_[is];
00894 
00895     if( !masked(rhi) ) continue;
00896     // rechit was masked to be processed
00897 
00898     // already used in a topological cluster
00899     if( usedInTopo_[rhi] ) {
00900 #ifdef PFLOW_DEBUG
00901       if(debug_) 
00902         cout<<rhi<<" used"<<endl; 
00903 #endif
00904       continue;
00905     }
00906     
00907     vector< unsigned > topocluster;
00908     buildTopoCluster( topocluster, rhi, rechits );
00909    
00910     if(topocluster.empty() ) continue;
00911     
00912     topoClusters_.push_back( topocluster );
00913 
00914   }
00915 
00916 #ifdef PFLOW_DEBUG
00917   if(debug_) 
00918     cout<<"PFClusterAlgo::buildTopoClusters done"<<endl;
00919 #endif
00920   
00921   return;
00922 }
00923 
00924 
00925 void 
00926 PFClusterAlgo::buildTopoCluster( vector< unsigned >& cluster,
00927                                  unsigned rhi, 
00928                                  const reco::PFRecHitCollection& rechits ){
00929 
00930 
00931 #ifdef PFLOW_DEBUG
00932   if(debug_)
00933     cout<<"PFClusterAlgo::buildTopoCluster in"<<endl;
00934 #endif
00935 
00936   const reco::PFRecHit& rh = rechit( rhi, rechits); 
00937 
00938   double e = rh.energy();
00939   int layer = rh.layer();
00940   
00941 
00942   int iring = 0;
00943   if (layer==PFLayer::HCAL_BARREL2 && abs(rh.positionREP().Eta())>0.34) iring= 1;
00944 
00945   double thresh = parameter( THRESH, 
00946                              static_cast<PFLayer::Layer>(layer), 0, iring );
00947   double ptThresh = parameter( PT_THRESH, 
00948                                static_cast<PFLayer::Layer>(layer), 0, iring );
00949 
00950 
00951   if( e < thresh ||  (ptThresh > 0. && rh.pt2() < ptThresh*ptThresh) ) {
00952 #ifdef PFLOW_DEBUG
00953     if(debug_)
00954       cout<<"return : "<<e<<"<"<<thresh<<endl; 
00955 #endif
00956     return;
00957   }
00958 
00959   // add hit to cluster
00960 
00961   cluster.push_back( rhi );
00962   // idUsedRecHits_.insert( rh.detId() );
00963 
00964   usedInTopo_[ rhi ] = true;
00965 
00966   //   cout<<" hit ptr "<<hit<<endl;
00967 
00968   // get neighbours, either with one side in common, 
00969   // or with one corner in common (if useCornerCells_)
00970   const std::vector< unsigned >& nbs 
00971     = useCornerCells_ ? rh.neighbours8() : rh.neighbours4();
00972   
00973   for(unsigned i=0; i<nbs.size(); i++) {
00974 
00975 //     const reco::PFRecHit& neighbour = rechit( nbs[i], rechits );
00976 
00977 //     set<unsigned>::iterator used 
00978 //       = idUsedRecHits_.find( neighbour.detId() );
00979 //     if(used != idUsedRecHits_.end() ) continue;
00980     
00981     // already used
00982     if( usedInTopo_[ nbs[i] ] ) {
00983 #ifdef PFLOW_DEBUG
00984       if(debug_) 
00985         cout<<rhi<<" used"<<endl; 
00986 #endif
00987       continue;
00988     }
00989                              
00990     if( !masked(nbs[i]) ) continue;
00991     buildTopoCluster( cluster, nbs[i], rechits );
00992   }
00993 #ifdef PFLOW_DEBUG
00994   if(debug_)
00995     cout<<"PFClusterAlgo::buildTopoCluster out"<<endl;
00996 #endif
00997 
00998 }
00999 
01000 
01001 void 
01002 PFClusterAlgo::buildPFClusters( const std::vector< unsigned >& topocluster,
01003                                 const reco::PFRecHitCollection& rechits ) 
01004 {
01005 
01006 
01007   //  bool debug = false;
01008 
01009 
01010   // several rechits may be seeds. initialize PFClusters on these seeds. 
01011   
01012   vector<reco::PFCluster> curpfclusters;
01013   vector<reco::PFCluster> curpfclusterswodepthcor;
01014   vector< unsigned > seedsintopocluster;
01015 
01016 
01017   for(unsigned i=0; i<topocluster.size(); i++ ) {
01018 
01019     unsigned rhi = topocluster[i];
01020 
01021     if( seedStates_[rhi] == YES ) {
01022 
01023       reco::PFCluster cluster;
01024       reco::PFCluster clusterwodepthcor;
01025 
01026       double fraction = 1.0; 
01027       
01028       reco::PFRecHitRef  recHitRef = createRecHitRef( rechits, rhi ); 
01029 
01030       cluster.addRecHitFraction( reco::PFRecHitFraction( recHitRef, 
01031                                                          fraction ) );
01032 
01033     // cluster.addRecHit( rhi, fraction );
01034 
01035       calculateClusterPosition( cluster,
01036                                 clusterwodepthcor, 
01037                                 true );    
01038 
01039 
01040 //       cout<<"PFClusterAlgo: 2"<<endl;
01041       curpfclusters.push_back( cluster );
01042       curpfclusterswodepthcor.push_back( clusterwodepthcor );
01043 #ifdef PFLOW_DEBUG
01044       if(debug_) {
01045         cout << "PFClusterAlgo::buildPFClusters: seed "
01046              << rechit( rhi, rechits) <<endl;
01047         cout << "PFClusterAlgo::buildPFClusters: pfcluster initialized : "
01048              << cluster <<endl;
01049       }
01050 #endif
01051 
01052       // keep track of the seed of each topocluster
01053       seedsintopocluster.push_back( rhi );
01054     }
01055   }
01056 
01057   // if only one seed in the topocluster, use all crystals
01058   // in the position calculation (posCalcNCrystal = -1)
01059   // otherwise, use the user specified value
01060   int posCalcNCrystal = seedsintopocluster.size()>1 ? posCalcNCrystal_:-1;
01061   double ns2 = std::max(1.,(double)(seedsintopocluster.size())-1.);
01062   ns2 *= ns2;
01063     
01064   // Find iteratively the energy and position
01065   // of each pfcluster in the topological cluster
01066   unsigned iter = 0;
01067   unsigned niter = 50;
01068   double diff = ns2;
01069 
01070   // if(debug_) niter=2;
01071   vector<double> ener;
01072   vector<double> dist;
01073   vector<double> frac;
01074   vector<math::XYZVector> tmp;
01075 
01076   while ( iter++ < niter && diff > 1E-8*ns2 ) {
01077 
01078     // Store previous iteration's result and reset pfclusters     
01079     ener.clear();
01080     tmp.clear();
01081 
01082     for ( unsigned ic=0; ic<curpfclusters.size(); ic++ ) {
01083       ener.push_back( curpfclusters[ic].energy() );
01084       
01085       math::XYZVector v;
01086       v = curpfclusters[ic].position();
01087 
01088       tmp.push_back( v );
01089 
01090 #ifdef PFLOW_DEBUG
01091       if(debug_)  {
01092         cout<<"saving photon pos "<<ic<<" "<<curpfclusters[ic]<<endl;
01093         cout<<tmp[ic].X()<<" "<<tmp[ic].Y()<<" "<<tmp[ic].Z()<<endl;
01094       }
01095 #endif
01096 
01097       curpfclusters[ic].reset();
01098     }
01099 
01100     // Loop over topocluster cells
01101     for( unsigned irh=0; irh<topocluster.size(); irh++ ) {
01102       unsigned rhindex = topocluster[irh];
01103       
01104       const reco::PFRecHit& rh = rechit( rhindex, rechits);
01105       
01106       // int layer = rh.layer();
01107              
01108       dist.clear();
01109       frac.clear();
01110       double fractot = 0.;
01111 
01112       bool isaseed = isSeed(rhindex);
01113 
01114       math::XYZVector cposxyzcell;
01115       cposxyzcell = rh.position();
01116 
01117 #ifdef PFLOW_DEBUG
01118       if(debug_) { 
01119         cout<<rh<<endl;
01120         cout<<"start loop on curpfclusters"<<endl;
01121       }
01122 #endif
01123 
01124       // Loop over pfclusters
01125       for ( unsigned ic=0; ic<tmp.size(); ic++) {
01126         
01127 #ifdef PFLOW_DEBUG
01128         if(debug_) cout<<"pfcluster "<<ic<<endl;
01129 #endif
01130         
01131         double frc=0.;
01132         bool seedexclusion=true;
01133 
01134         // convert cluster coordinates to xyz
01135         //math::XYZVector cposxyzclust( tmp[ic].X(), tmp[ic].Y(), tmp[ic].Z() );
01136         // cluster position used to compute distance with cell
01137         math::XYZVector cposxyzclust;
01138         cposxyzclust = curpfclusterswodepthcor[ic].position();
01139 
01140 #ifdef PFLOW_DEBUG
01141         if(debug_) {
01142           
01143           cout<<"CLUSTER "<<cposxyzclust.X()<<","
01144               <<cposxyzclust.Y()<<","
01145               <<cposxyzclust.Z()<<"\t\t"
01146               <<"CELL "<<cposxyzcell.X()<<","
01147               <<cposxyzcell.Y()<<","
01148               <<cposxyzcell.Z()<<endl;
01149         }  
01150 #endif
01151         
01152         // Compute the distance between the current cell 
01153         // and the current PF cluster, normalized to a 
01154         // number of "sigma"
01155         math::XYZVector deltav = cposxyzclust;
01156         deltav -= cposxyzcell;
01157         double d = deltav.R() / showerSigma_;
01158         
01159         // if distance cell-cluster is too large, it means that 
01160         // we're right on the junction between 2 subdetectors (HCAL/VFCAL...)
01161         // in this case, distance is calculated in the xy plane
01162         // could also be a large supercluster... 
01163 #ifdef PFLOW_DEBUG
01164         if( d > 10. && debug_ ) { 
01165           paint(rhindex, SPECIAL);
01166           cout<<"PFClusterAlgo Warning: distance too large"<<d<<endl;
01167         }
01168 #endif
01169         dist.push_back( d );
01170 
01171         // the current cell is the seed from the current photon.
01172         if( rhindex == seedsintopocluster[ic] && seedexclusion ) {
01173           frc = 1.;
01174 #ifdef PFLOW_DEBUG
01175           if(debug_) cout<<"this cell is a seed for the current photon"<<endl;
01176 #endif
01177         }
01178         else if( isaseed && seedexclusion ) {
01179           frc = 0.;
01180 #ifdef PFLOW_DEBUG
01181           if(debug_) cout<<"this cell is a seed for another photon"<<endl;
01182 #endif
01183         }
01184         else {
01185           // Compute the fractions of the cell energy to be assigned to 
01186           // each curpfclusters in the cluster.
01187           frc = ener[ic] * exp ( - dist[ic]*dist[ic] / 2. );
01188 
01189 #ifdef PFLOW_DEBUG
01190           if(debug_) {
01191             cout<<"dist["<<ic<<"] "<<dist[ic]
01192               //                <<", sigma="<<sigma
01193                 <<", frc="<<frc<<endl;
01194           }  
01195 #endif
01196         
01197         }
01198         fractot += frc;
01199         frac.push_back(frc);
01200       }      
01201 
01202       // Add the relevant fraction of the cell to the curpfclusters
01203 #ifdef PFLOW_DEBUG
01204       if(debug_) cout<<"start add cell"<<endl;
01205 #endif
01206       for ( unsigned ic=0; ic<tmp.size(); ++ic ) {
01207 #ifdef PFLOW_DEBUG
01208         if(debug_) 
01209           cout<<" frac["<<ic<<"] "<<frac[ic]<<" "<<fractot<<" "<<rh<<endl;
01210 #endif
01211 
01212         if( fractot ) 
01213           frac[ic] /= fractot;
01214         else { 
01215 #ifdef PFLOW_DEBUG
01216           if( debug_ ) {
01217             int layer = rh.layer();
01218             cerr<<"fractot = 0 ! "<<layer<<endl;
01219             
01220             for( unsigned trh=0; trh<topocluster.size(); trh++ ) {
01221               unsigned tindex = topocluster[trh];
01222               const reco::PFRecHit& rh = rechit( tindex, rechits);
01223               cout<<rh<<endl;
01224             }
01225 
01226             // assert(0)
01227           }
01228 #endif
01229 
01230           continue;
01231         }
01232 
01233         // if the fraction has been set to 0, the cell 
01234         // is now added to the cluster - careful ! (PJ, 19/07/08)
01235         // BUT KEEP ONLY CLOSE CELLS OTHERWISE MEMORY JUST EXPLOSES
01236         // (PJ, 15/09/08 <- similar to what existed before the 
01237         // previous bug fix, but keeps the close seeds inside, 
01238         // even if their fraction was set to zero.)
01239         // Also add a protection to keep the seed in the cluster 
01240         // when the latter gets far from the former. These cases
01241         // (about 1% of the clusters) need to be studied, as 
01242         // they create fake photons, in general.
01243         // (PJ, 16/09/08) 
01244         if ( dist[ic] < 10. || frac[ic] > 0.99999 ) { 
01245           // if ( dist[ic] > 6. ) cout << "Warning : PCluster is getting very far from its seeding cell" << endl;
01246           reco::PFRecHitRef  recHitRef = createRecHitRef( rechits, rhindex ); 
01247           reco::PFRecHitFraction rhf( recHitRef,frac[ic] );
01248           curpfclusters[ic].addRecHitFraction( rhf );
01249         }
01250       }
01251       // if(debug_) cout<<" end add cell"<<endl;
01252     }
01253 
01254     // Determine the new cluster position and check 
01255     // the distance with the previous iteration
01256     diff = 0.;
01257     for (  unsigned ic=0; ic<tmp.size(); ++ic ) {
01258 
01259       calculateClusterPosition( curpfclusters[ic], curpfclusterswodepthcor[ic], 
01260                                 true, posCalcNCrystal );
01261 #ifdef PFLOW_DEBUG
01262       if(debug_) cout<<"new iter "<<ic<<endl;
01263       if(debug_) cout<<curpfclusters[ic]<<endl;
01264 #endif
01265 
01266       double delta = ROOT::Math::VectorUtil::DeltaR(curpfclusters[ic].position(),tmp[ic]);
01267       if ( delta > diff ) diff = delta;
01268     }
01269   }
01270   
01271   // Issue a warning message if the number of iterations 
01272   // exceeds 50
01273 #ifdef PFLOW_DEBUG
01274   if ( iter >= 50 && debug_ ) 
01275     cout << "PFClusterAlgo Warning: "
01276          << "more than "<<niter<<" iterations in pfcluster finding: " 
01277          <<  setprecision(10) << diff << endl;
01278 #endif
01279   
01280   // There we go
01281   // add all clusters to the list of pfClusters.
01282   for(unsigned ic=0; ic<curpfclusters.size(); ic++) {
01283 
01284     calculateClusterPosition(curpfclusters[ic], curpfclusterswodepthcor[ic], 
01285                              true, posCalcNCrystal);
01286 
01287     pfClusters_->push_back(curpfclusters[ic]); 
01288   }
01289 }
01290 
01291 
01292 
01293 void 
01294 PFClusterAlgo::calculateClusterPosition(reco::PFCluster& cluster,
01295                                         reco::PFCluster& clusterwodepthcor,
01296                                         bool depcor, 
01297                                         int posCalcNCrystal) {
01298 
01299   if( posCalcNCrystal_ != -1 && 
01300       posCalcNCrystal_ != 5 && 
01301       posCalcNCrystal_ != 9 ) {
01302     throw "PFCluster::calculatePosition : posCalcNCrystal_ must be -1, 5, or 9.";
01303   }  
01304 
01305 
01306   if(!posCalcNCrystal) posCalcNCrystal = posCalcNCrystal_; 
01307 
01308   cluster.position_.SetXYZ(0,0,0);
01309 
01310   cluster.energy_ = 0;
01311   
01312   double normalize = 0;
01313 
01314   // calculate total energy, average layer, and look for seed  ---------- //
01315 
01316 
01317   // double layer = 0;
01318   map <PFLayer::Layer, double> layers; 
01319 
01320   unsigned seedIndex = 0;
01321   bool     seedIndexFound = false;
01322 
01323   //Colin: the following can be simplified!
01324 
01325   // loop on rechit fractions
01326   for (unsigned ic=0; ic<cluster.rechits_.size(); ic++ ) {
01327 
01328     unsigned rhi = cluster.rechits_[ic].recHitRef().index();
01329     // const reco::PFRecHit& rh = rechit( rhi, rechits );
01330 
01331     const reco::PFRecHit& rh = *(cluster.rechits_[ic].recHitRef());
01332     double fraction =  cluster.rechits_[ic].fraction();
01333 
01334     // Find the seed of this sub-cluster (excluding other seeds found in the topological
01335     // cluster, the energy fraction of which were set to 0 fpr the position determination.
01336     if( isSeed(rhi) && fraction > 1e-9 ) {
01337       seedIndex = rhi;
01338       seedIndexFound = true;
01339     }
01340 
01341     double recHitEnergy = rh.energy() * fraction;
01342 
01343     // is nan ? 
01344     if( recHitEnergy!=recHitEnergy ) {
01345       ostringstream ostr;
01346       edm::LogError("PFClusterAlgo")<<"rechit "<<rh.detId()<<" has a NaN energy... The input of the particle flow clustering seems to be corrupted.";
01347     }
01348 
01349     cluster.energy_ += recHitEnergy;
01350 
01351     // sum energy in each layer
01352     PFLayer::Layer layer = rh.layer();  
01353 
01354     map <PFLayer::Layer, double>:: iterator it = layers.find(layer);
01355 
01356     if (it != layers.end()) {
01357       it->second += recHitEnergy;
01358     } else {
01359 
01360       layers.insert(make_pair(layer, recHitEnergy));
01361 
01362     }
01363 
01364   }  
01365 
01366   assert(seedIndexFound);
01367 
01368   // loop over pairs to find layer with max energy          
01369   double Emax = 0.;
01370   PFLayer::Layer layer = PFLayer::NONE;
01371   for (map<PFLayer::Layer, double>::iterator it = layers.begin();
01372        it != layers.end(); ++it) {
01373     double e = it->second;
01374     if(e > Emax){ 
01375       Emax = e; 
01376       layer = it->first;
01377     }
01378   }
01379   
01380 
01381   //setlayer here
01382   cluster.setLayer( layer ); // take layer with max energy
01383 
01384   // layer /= cluster.energy_;
01385   // cluster.layer_ = lrintf(layer); // nearest integer
01386 
01387 
01388 
01389   double p1 =  posCalcP1_;
01390   if( p1 < 0 ) { 
01391     // automatic (and hopefully best !) determination of the parameter
01392     // for position determination.
01393     
01394     // Remove the ad-hoc determination of p1, and set it to the 
01395     // seed threshold.
01396     switch(cluster.layer() ) {
01397     case PFLayer::ECAL_BARREL:
01398     case PFLayer::HCAL_BARREL1:
01399     case PFLayer::HCAL_BARREL2:
01400       //    case PFLayer::HCAL_HO:
01401       p1 = threshBarrel_;
01402       break;
01403     case PFLayer::ECAL_ENDCAP:
01404     case PFLayer::HCAL_ENDCAP:
01405     case PFLayer::HF_EM:
01406     case PFLayer::HF_HAD:
01407     case PFLayer::PS1:
01408     case PFLayer::PS2:
01409       p1 = threshEndcap_;
01410       break;
01411 
01412     /*
01413     switch(cluster.layer() ) {
01414     case PFLayer::ECAL_BARREL:
01415       p1 = 0.004 + 0.022*cluster.energy_; // 27 feb 2006 
01416       break;
01417     case PFLayer::ECAL_ENDCAP:
01418       p1 = 0.014 + 0.009*cluster.energy_; // 27 feb 2006 
01419       break;
01420     case PFLayer::HCAL_BARREL1:
01421     case PFLayer::HCAL_BARREL2:
01422     case PFLayer::HCAL_ENDCAP:
01423     case PFLayer::HCAL_HF:
01424       p1 = 5.41215e-01 * log( cluster.energy_ / 1.29803e+01 );
01425       if(p1<0.01) p1 = 0.01;
01426       break;
01427     */
01428 
01429     default:
01430       cerr<<"Clusters weight_p1 -1 not yet allowed for layer "<<layer
01431           <<". Chose a better value in the opt file"<<endl;
01432       assert(0);
01433       break;
01434     }
01435   } 
01436   else if( p1< 1e-9 ) { // will divide by p1 later on
01437     p1 = 1e-9;
01438   }
01439   // calculate uncorrected cluster position --------------------------------
01440 
01441   reco::PFCluster::REPPoint clusterpos;   // uncorrected cluster pos 
01442   math::XYZPoint clusterposxyz;           // idem, xyz coord 
01443   math::XYZPoint firstrechitposxyz;       // pos of the rechit with highest E
01444 
01445   double maxe = -9999;
01446   double x = 0;
01447   double y = 0;
01448   double z = 0;
01449   
01450   for (unsigned ic=0; ic<cluster.rechits_.size(); ic++ ) {
01451     
01452     unsigned rhi = cluster.rechits_[ic].recHitRef().index();
01453 //     const reco::PFRecHit& rh = rechit( rhi, rechits );
01454 
01455     const reco::PFRecHit& rh = *(cluster.rechits_[ic].recHitRef());
01456 
01457     if(rhi != seedIndex) { // not the seed
01458       if( posCalcNCrystal == 5 ) { // pos calculated from the 5 neighbours only
01459         if(!rh.isNeighbour4(seedIndex) ) {
01460           continue;
01461         }
01462       }
01463       if( posCalcNCrystal == 9 ) { // pos calculated from the 9 neighbours only
01464         if(!rh.isNeighbour8(seedIndex) ) {
01465           continue;
01466         }
01467       }
01468     }
01469     double fraction =  cluster.rechits_[ic].fraction();
01470     double recHitEnergy = rh.energy() * fraction;
01471 
01472     double norm = fraction < 1E-9 ? 0. : max(0., log(recHitEnergy/p1 ));
01473     
01474     const math::XYZPoint& rechitposxyz = rh.position();
01475     
01476     if( recHitEnergy > maxe ) {
01477       firstrechitposxyz = rechitposxyz;
01478       maxe = recHitEnergy;
01479     }
01480 
01481     x += rechitposxyz.X() * norm;
01482     y += rechitposxyz.Y() * norm;
01483     z += rechitposxyz.Z() * norm;
01484     
01485     // clusterposxyz += rechitposxyz * norm;
01486     normalize += norm;
01487   }
01488 
01489   // normalize uncorrected position
01490   // assert(normalize);
01491   if( normalize < 1e-9 ) {
01492     //    cerr<<"--------------------"<<endl;
01493     //    cerr<<(*this)<<endl;
01494     cout << "Watch out : cluster too far from its seeding cell, set to 0,0,0" << endl;
01495     clusterposxyz.SetXYZ(0,0,0);
01496     clusterpos.SetCoordinates(0,0,0);
01497     return;
01498   }
01499   else {
01500     x /= normalize;
01501     y /= normalize; 
01502     z /= normalize; 
01503 
01504     clusterposxyz.SetCoordinates( x, y, z);
01505 
01506     clusterpos.SetCoordinates( clusterposxyz.Rho(), clusterposxyz.Eta(), clusterposxyz.Phi() );
01507 
01508   }  
01509 
01510   cluster.posrep_ = clusterpos;
01511 
01512   cluster.position_ = clusterposxyz;
01513 
01514   clusterwodepthcor = cluster;
01515 
01516 
01517   // correctio of the rechit position, 
01518   // according to the depth, only for ECAL 
01519 
01520 
01521   if( depcor &&   // correction requested and ECAL
01522       ( cluster.layer() == PFLayer::ECAL_BARREL ||       
01523         cluster.layer() == PFLayer::ECAL_ENDCAP ) ) {
01524 
01525 
01526     double corra = reco::PFCluster::depthCorA_;
01527     double corrb = reco::PFCluster::depthCorB_;
01528     if( abs(clusterpos.Eta() ) < 2.6 && 
01529         abs(clusterpos.Eta() ) > 1.65   ) { 
01530       // if crystals under preshower, correction is not the same  
01531       // (shower depth smaller)
01532       corra = reco::PFCluster::depthCorAp_;
01533       corrb = reco::PFCluster::depthCorBp_;
01534     }
01535 
01536     double depth = 0;
01537 
01538     switch( reco::PFCluster::depthCorMode_ ) {
01539     case 1: // for e/gamma 
01540       depth = corra * ( corrb + log(cluster.energy_) ); 
01541       break;
01542     case 2: // for hadrons
01543       depth = corra;
01544       break;
01545     default:
01546       cerr<<"PFClusterAlgo::calculateClusterPosition : unknown function for depth correction! "<<endl;
01547       assert(0);
01548     }
01549 
01550 
01551     // calculate depth vector:
01552     // its mag is depth
01553     // its direction is the cluster direction (uncorrected)
01554 
01555 //     double xdepthv = clusterposxyz.X();
01556 //     double ydepthv = clusterposxyz.Y();
01557 //     double zdepthv = clusterposxyz.Z();
01558 //     double mag = sqrt( xdepthv*xdepthv + 
01559 //                     ydepthv*ydepthv + 
01560 //                     zdepthv*zdepthv );
01561     
01562 
01563 //     math::XYZPoint depthv(clusterposxyz); 
01564 //     depthv.SetMag(depth);
01565     
01566     
01567     math::XYZVector depthv( clusterposxyz.X(), 
01568                             clusterposxyz.Y(),
01569                             clusterposxyz.Z() );
01570     depthv /= sqrt(depthv.Mag2() );
01571     depthv *= depth;
01572 
01573 
01574     // now calculate corrected cluster position:    
01575     math::XYZPoint clusterposxyzcor;
01576 
01577     maxe = -9999;
01578     x = 0;
01579     y = 0;
01580     z = 0;
01581     cluster.posrep_.SetXYZ(0,0,0);
01582     normalize = 0;
01583     for (unsigned ic=0; ic<cluster.rechits_.size(); ic++ ) {
01584 
01585       unsigned rhi = cluster.rechits_[ic].recHitRef().index();
01586 //       const reco::PFRecHit& rh = rechit( rhi, rechits );
01587       
01588       const reco::PFRecHit& rh = *(cluster.rechits_[ic].recHitRef());
01589 
01590       if(rhi != seedIndex) {
01591         if( posCalcNCrystal == 5 ) {
01592           if(!rh.isNeighbour4(seedIndex) ) {
01593             continue;
01594           }
01595         }
01596         if( posCalcNCrystal == 9 ) {
01597           if(!rh.isNeighbour8(seedIndex) ) {
01598             continue;
01599           }
01600         }
01601       }
01602 
01603       double fraction =  cluster.rechits_[ic].fraction();
01604       double recHitEnergy = rh.energy() * fraction;
01605       
01606       const math::XYZPoint&  rechitposxyz = rh.position();
01607 
01608       // rechit axis not correct ! 
01609       math::XYZVector rechitaxis = rh.getAxisXYZ();
01610       // rechitaxis -= math::XYZVector( rechitposxyz.X(), rechitposxyz.Y(), rechitposxyz.Z() );
01611       
01612       math::XYZVector rechitaxisu( rechitaxis );
01613       rechitaxisu /= sqrt( rechitaxis.Mag2() );
01614 
01615       math::XYZVector displacement( rechitaxisu );
01616       // displacement /= sqrt( displacement.Mag2() );    
01617       displacement *= rechitaxisu.Dot( depthv );
01618       
01619       math::XYZPoint rechitposxyzcor( rechitposxyz );
01620       rechitposxyzcor += displacement;
01621 
01622       if( recHitEnergy > maxe ) {
01623         firstrechitposxyz = rechitposxyzcor;
01624         maxe = recHitEnergy;
01625       }
01626 
01627       double norm = fraction < 1E-9 ? 0. : max(0., log(recHitEnergy/p1 ));
01628       
01629       x += rechitposxyzcor.X() * norm;
01630       y += rechitposxyzcor.Y() * norm;
01631       z += rechitposxyzcor.Z() * norm;
01632       
01633       // clusterposxyzcor += rechitposxyzcor * norm;
01634       normalize += norm;
01635     }
01636 
01637     // normalize
01638     if(normalize < 1e-9) {
01639       cerr<<"--------------------"<<endl;
01640       cerr<< cluster <<endl;
01641       assert(0);
01642     }
01643     else {
01644       x /= normalize;
01645       y /= normalize;
01646       z /= normalize;
01647       
01648 
01649       clusterposxyzcor.SetCoordinates(x,y,z);
01650       cluster.posrep_.SetCoordinates( clusterposxyzcor.Rho(), 
01651                                       clusterposxyzcor.Eta(), 
01652                                       clusterposxyzcor.Phi() );
01653       cluster.position_  = clusterposxyzcor;
01654       clusterposxyz = clusterposxyzcor;
01655     }
01656 
01657   }
01658 }
01659 
01660 
01661 
01662 const reco::PFRecHit& 
01663 PFClusterAlgo::rechit(unsigned i, 
01664                       const reco::PFRecHitCollection& rechits ) {
01665 
01666   if(i >= rechits.size() ) { // i >= 0, since i is unsigned
01667     string err = "PFClusterAlgo::rechit : out of range";
01668     throw std::out_of_range(err);
01669   }
01670   
01671   return rechits[i];
01672 }
01673 
01674 
01675 
01676 bool PFClusterAlgo::masked(unsigned rhi) const {
01677 
01678   if(rhi>=mask_.size() ) { // rhi >= 0, since rhi is unsigned
01679     string err = "PFClusterAlgo::masked : out of range";
01680     throw std::out_of_range(err);
01681   }
01682   
01683   return mask_[rhi];
01684 }
01685 
01686 
01687 unsigned PFClusterAlgo::color(unsigned rhi) const {
01688 
01689   if(rhi>=color_.size() ) { // rhi >= 0, since rhi is unsigned
01690     string err = "PFClusterAlgo::color : out of range";
01691     throw std::out_of_range(err);
01692   }
01693   
01694   return color_[rhi];
01695 }
01696 
01697 
01698 
01699 bool PFClusterAlgo::isSeed(unsigned rhi) const {
01700 
01701   if(rhi>=seedStates_.size() ) { // rhi >= 0, since rhi is unsigned
01702     string err = "PFClusterAlgo::isSeed : out of range";
01703     throw std::out_of_range(err);
01704   }
01705   
01706   return seedStates_[rhi]>0 ? true : false;
01707 }
01708 
01709 
01710 void PFClusterAlgo::paint(unsigned rhi, unsigned color ) {
01711 
01712   if(rhi>=color_.size() ) { // rhi >= 0, since rhi is unsigned
01713     string err = "PFClusterAlgo::color : out of range";
01714     throw std::out_of_range(err);
01715   }
01716   
01717   color_[rhi] = color;
01718 }
01719 
01720 
01721 reco::PFRecHitRef 
01722 PFClusterAlgo::createRecHitRef( const reco::PFRecHitCollection& rechits, 
01723                                 unsigned rhi ) {
01724 
01725   if( rechitsHandle_.isValid() ) {
01726     return reco::PFRecHitRef(  rechitsHandle_, rhi );
01727   } 
01728   else {
01729     return reco::PFRecHitRef(  &rechits, rhi );
01730   }
01731 }
01732 
01733 
01734 ostream& operator<<(ostream& out,const PFClusterAlgo& algo) {
01735   if(!out) return out;
01736   out<<"PFClusterAlgo parameters : "<<endl;
01737   out<<"-----------------------------------------------------"<<endl;
01738   out<<"threshBarrel       : "<<algo.threshBarrel_       <<endl;
01739   out<<"threshSeedBarrel   : "<<algo.threshSeedBarrel_   <<endl;
01740   out<<"threshPtBarrel     : "<<algo.threshPtBarrel_     <<endl;
01741   out<<"threshPtSeedBarrel : "<<algo.threshPtSeedBarrel_ <<endl;
01742   out<<"threshCleanBarrel  : "<<algo.threshCleanBarrel_  <<endl;
01743   out<<"minS4S1Barrel      : "<<algo.minS4S1Barrel_[0]<<" x log10(E) + "<<algo.minS4S1Barrel_[1]<<endl;
01744   out<<"threshEndcap       : "<<algo.threshEndcap_       <<endl;
01745   out<<"threshSeedEndcap   : "<<algo.threshSeedEndcap_   <<endl;
01746   out<<"threshPtEndcap     : "<<algo.threshPtEndcap_     <<endl;
01747   out<<"threshPtSeedEndcap : "<<algo.threshPtSeedEndcap_ <<endl;
01748   out<<"threshEndcap       : "<<algo.threshEndcap_       <<endl;
01749   out<<"threshCleanEndcap  : "<<algo.threshCleanEndcap_  <<endl;
01750   out<<"minS4S1Endcap      : "<<algo.minS4S1Endcap_[0]<<" x log10(E) + "<<algo.minS4S1Endcap_[1]<<endl;
01751   out<<"nNeighbours        : "<<algo.nNeighbours_        <<endl;
01752   out<<"posCalcNCrystal    : "<<algo.posCalcNCrystal_    <<endl;
01753   out<<"posCalcP1          : "<<algo.posCalcP1_          <<endl;
01754   out<<"showerSigma        : "<<algo.showerSigma_        <<endl;
01755   out<<"useCornerCells     : "<<algo.useCornerCells_     <<endl;
01756 
01757   out<<endl;
01758   out<<algo.pfClusters_->size()<<" clusters:"<<endl;
01759 
01760   for(unsigned i=0; i<algo.pfClusters_->size(); i++) {
01761     out<<(*algo.pfClusters_)[i]<<endl;
01762     
01763     if(!out) return out;
01764   }
01765   
01766   return out;
01767 }
01768 
01769 
01770 //compute the unsigned distance to the closest phi-crack in the barrel
01771 std::pair<double,double>
01772 PFClusterAlgo::dCrack(double phi, double eta){
01773 
01774   static double pi= M_PI;// 3.14159265358979323846;
01775   
01776   //Location of the 18 phi-cracks
01777   static std::vector<double> cPhi;
01778   if(cPhi.size()==0)
01779     {
01780       cPhi.resize(18,0);
01781       cPhi[0]=2.97025;
01782       for(unsigned i=1;i<=17;++i) cPhi[i]=cPhi[0]-2*i*pi/18;
01783     }
01784 
01785   //Shift of this location if eta<0
01786   static double delta_cPhi=0.00638;
01787 
01788   double defi; //the result
01789 
01790   //the location is shifted
01791   if(eta<0) phi +=delta_cPhi;
01792 
01793   if (phi>=-pi && phi<=pi){
01794 
01795     //the problem of the extrema
01796     if (phi<cPhi[17] || phi>=cPhi[0]){
01797       if (phi<0) phi+= 2*pi;
01798       defi = std::min(fabs(phi -cPhi[0]),fabs(phi-cPhi[17]-2*pi));              
01799     }
01800 
01801     //between these extrema...
01802     else{
01803       bool OK = false;
01804       unsigned i=16;
01805       while(!OK){
01806         if (phi<cPhi[i]){
01807           defi=std::min(fabs(phi-cPhi[i+1]),fabs(phi-cPhi[i]));
01808           OK=true;
01809         }
01810         else i-=1;
01811       }
01812     }
01813   }
01814   else{
01815     defi=0.;        //if there is a problem, we assum that we are in a crack
01816     std::cout<<"Problem in dminphi"<<std::endl;
01817   }
01818   //if(eta<0) defi=-defi;   //because of the disymetry
01819 
01820   static std::vector<double> cEta;
01821   if ( cEta.size() == 0 ) { 
01822     cEta.push_back(0.0);
01823     cEta.push_back(4.44747e-01)  ;   cEta.push_back(-4.44747e-01)  ;
01824     cEta.push_back(7.92824e-01)  ;   cEta.push_back(-7.92824e-01) ;
01825     cEta.push_back(1.14090e+00)  ;   cEta.push_back(-1.14090e+00)  ;
01826     cEta.push_back(1.47464e+00)  ;   cEta.push_back(-1.47464e+00)  ;
01827   }
01828   double deta = 999.; // the other result
01829 
01830   for ( unsigned ieta=0; ieta<cEta.size(); ++ieta ) { 
01831     deta = std::min(deta,fabs(eta-cEta[ieta]));
01832   }
01833   
01834   defi /= 0.0175;
01835   deta /= 0.0175;
01836   return std::pair<double,double>(defi,deta);
01837 
01838 }