fastjet 2.4.5
ILConeAlgorithm.hpp
Go to the documentation of this file.
00001 #ifndef  D0RunIIconeJets_ILCONEALGORITHM
00002 #define  D0RunIIconeJets_ILCONEALGORITHM
00003 // ---------------------------------------------------------------------------
00004 // ILConeAlgorithm.hpp
00005 //
00006 // Created: 28-JUL-2000 Francois Touze (+ Laurent Duflot)
00007 //
00008 // Purpose: Implements the Improved Legacy Cone Algorithm
00009 //
00010 // Modified:
00011 //   31-JUL-2000  Laurent Duflot
00012 //     + introduce support for additional informations (ConeJetInfo)
00013 //    1-AUG-2000  Laurent Duflot
00014 //     + seedET for midpoint jet is -999999., consistent with seedET ordering
00015 //       in ConeSplitMerge: final jets with seedET=-999999. will be midpoint 
00016 //       jets which were actually different from stable cones.
00017 //    4-Aug-2000  Laurent Duflot
00018 //     + remove unecessary copy in TemporaryJet::is_stable()
00019 //   11-Aug-2000  Laurent Duflot
00020 //     + remove using namespace std
00021 //     + add threshold on item. The input list to makeClusters() IS modified
00022 //   20-June-2002 John Krane
00023 //     + remove bug in midpoint calculation based on pT weight
00024 //     + started to add new midpoint calculation based on 4-vectors,
00025 //       but not enough info held by this class
00026 //   24-June-2002 John Krane
00027 //     + modify is_stable() to not iterate if desired 
00028 //       (to expand search cone w/out moving it)
00029 //     + added search cone logic for initial jets but not midpoint jets as per
00030 //       agreement with CDF
00031 //   19-July-2002 John Krane
00032 //     + _SEARCH_CONE size factor now provided by calreco/CalClusterReco.cpp 
00033 //     + (default = 1.0 = like original ILCone behavior)
00034 //   10-Oct-2002 John Krane
00035 //     + Check min Pt of cone with full size first, then iterate with search cone
00036 //   07-Dec-2002 John Krane
00037 //     + speed up the midpoint phi-wrap solution
00038 //   01-May-2007 Lars Sonnenschein
00039 //   extracted from D0 software framework and modified to remove subsequent dependencies
00040 //
00041 // ---------------------------------------------------------------------------
00042 
00044 #include <vector>
00045 #include <list>
00046 #include <utility>  // defines pair<,>
00047 #include <map>
00048 #include <algorithm>
00049 #include <iostream>
00050 
00051 
00052 //#include "energycluster/EnergyClusterReco.hpp"
00053 //#include "energycluster/ProtoJet.hpp"
00054 #include "ProtoJet.hpp"
00055 //#include "energycluster/ConeSplitMerge.hpp"
00056 #include "ConeSplitMerge.hpp"
00057 //#include "energycluster/ConeJetInfoChunk.hpp"
00058 
00059 #include "inline_maths.h"
00060 
00062 #include <fastjet/internal/base.hh>
00063 
00064 FASTJET_BEGIN_NAMESPACE
00065 
00066 namespace d0{
00067 
00068 using namespace inline_maths;
00069 
00070 /*
00071  NB: Some attempt at optimizing the code has been made by ordering the object
00072      along rapidity but this did not improve the speed. There are traces of 
00073      these atemps in the code, that will be cleaned up in the future.
00074  */
00075 
00076 // at most one of those !
00077 // order the input list and use lower_bound() and upper_bound() to restrict the
00078 // on item to those that could possibly be in the cone.
00079 //#define ILCA_USE_ORDERED_LIST
00080 
00081 // idem but use an intermediate multimap in hope that lower_bound() and 
00082 // upper_bound() are faster in this case.
00083 //#define ILCA_USE_MMAP
00084 
00085 
00086 #ifdef ILCA_USE_ORDERED_LIST
00087 // this class is used to order the item list along rapidity
00088 template <class Item>
00089 class rapidity_order
00090 {
00091 public:
00092   bool operator()(const Item* first, const Item* second)
00093   {
00094     return (first->y() < second->y());
00095   }
00096   bool operator()(float const & first, const Item* second)
00097   {
00098     return (first  < second->y());
00099   }
00100   bool operator()(const Item* first, float const& second)
00101   {
00102     return (first->y() < second);
00103   }
00104 };
00105 #endif
00106 
00107 
00108 //template <class Item,class ItemAddress,class IChunk>
00109 template <class Item>
00110 class ILConeAlgorithm 
00111 {
00112 
00113 public:
00114 
00115   // default constructor (default parameters are crazy: you should not use that
00116   // constructor !)
00117   ILConeAlgorithm():
00118     _CONE_RADIUS(0.),
00119     _MIN_JET_ET(99999.),
00120     _ET_MIN_RATIO(0.5),
00121     _FAR_RATIO(0.5),
00122     _SPLIT_RATIO(0.5),
00123     _DUPLICATE_DR(0.005),
00124     _DUPLICATE_DPT(0.01),
00125     _SEARCH_CONE(0.5),
00126     _PT_MIN_LEADING_PROTOJET(0), 
00127     _PT_MIN_SECOND_PROTOJET(0), 
00128     _MERGE_MAX(10000), 
00129     _PT_MIN_noMERGE_MAX(0)
00130   {;}
00131 
00132   // full constructor
00133   ILConeAlgorithm(float cone_radius, float min_jet_Et, float split_ratio,
00134                   float far_ratio=0.5, float Et_min_ratio=0.5,
00135                   bool kill_duplicate=true, float duplicate_dR=0.005, 
00136                   float duplicate_dPT=0.01, float search_factor=1.0, 
00137                   float pT_min_leading_protojet=0., float pT_min_second_protojet=0.,
00138                   int merge_max=10000, float pT_min_nomerge=0.) :
00139     // cone radius
00140     _CONE_RADIUS(cone_radius), 
00141     // minimum jet ET
00142     _MIN_JET_ET(min_jet_Et), 
00143     // stable cones must have ET > _ET_MIN_RATIO*_MIN_JET_ET at any iteration
00144     _ET_MIN_RATIO(Et_min_ratio),
00145     // precluster at least _FAR_RATIO*_CONE_RADIUS away from stable cones
00146     _FAR_RATIO(far_ratio), 
00147     // split or merge criterium           
00148     _SPLIT_RATIO(split_ratio),
00149     _DUPLICATE_DR(duplicate_dR),
00150     _DUPLICATE_DPT(duplicate_dPT),
00151     _SEARCH_CONE(cone_radius/search_factor),
00152     // kill stable cone if within _DUPLICATE_DR and delta(pT)<_DUPLICATE_DPT
00153     // of another stable cone.
00154     _KILL_DUPLICATE(kill_duplicate),
00155     _PT_MIN_LEADING_PROTOJET(pT_min_leading_protojet),
00156     _PT_MIN_SECOND_PROTOJET(pT_min_second_protojet),
00157     _MERGE_MAX(merge_max),
00158     _PT_MIN_noMERGE_MAX(pT_min_nomerge)
00159     {;}
00160 
00161   //destructor
00162   ~ILConeAlgorithm() {;}
00163 
00164   // make jet clusters using improved legacy cone algorithm
00165   //void makeClusters(const EnergyClusterReco* r,
00166   void makeClusters(
00167                     // the input list modified (ordered)
00168                     std::list<Item> &jets,
00169                     std::list<const Item*>& itemlist, 
00170                     //float zvertex,   
00172                     //const EnergyClusterCollection<ItemAddress>& preclu,
00173                     //IChunk* chunkptr, ConeJetInfoChunk* infochunkptr,
00174                     const float Item_ET_Threshold);
00175 
00176   // this will hold the final jets + contents
00177   std::vector<ProtoJet<Item> > ilcv;
00178 
00179 private:
00180 
00181   float _CONE_RADIUS;
00182   float _MIN_JET_ET;
00183   float _ET_MIN_RATIO;
00184   float _FAR_RATIO;
00185   float _SPLIT_RATIO;
00186   float _DUPLICATE_DR;
00187   float _DUPLICATE_DPT;
00188   float _SEARCH_CONE;
00189 
00190   bool _KILL_DUPLICATE;
00191 
00192   float _PT_MIN_LEADING_PROTOJET;
00193   float _PT_MIN_SECOND_PROTOJET;
00194   int  _MERGE_MAX; 
00195   float _PT_MIN_noMERGE_MAX;
00196 
00197   // private class 
00198   // This is a ProtoJet with additional methods dist(), midpoint() and 
00199   // is_stable()
00200   class TemporaryJet : public ProtoJet<Item> 
00201   {
00202     
00203   public :
00204     
00205     TemporaryJet(float seedET) : ProtoJet<Item>(seedET) {;}
00206 
00207     TemporaryJet(float seedET,float y,float phi) : 
00208       ProtoJet<Item>(seedET,y,phi) {;}
00209     
00210     ~TemporaryJet() {;}
00211     
00212     float dist(TemporaryJet& jet) const 
00213     {
00214       return RDelta(this->_y,this->_phi,jet.y(),jet.phi()); 
00215     }
00216     
00217     void midpoint(const TemporaryJet& jet,float & y, float & phi) const 
00218     {
00219       // Midpoint should probably be computed w/4-vectors but don't 
00220       // have that info.  Preserving Pt-weighted calculation - JPK
00221       float pTsum = this->_pT + jet.pT();
00222       y = (this->_y*this->_pT + jet.y()*jet.pT())/pTsum;
00223 
00224       phi = (this->_phi*this->_pT + jet.phi()*jet.pT())/pTsum;
00225       // careful with phi-wrap area: convert from [0,2pi] to [-pi,pi]
00226       //ls: original D0 code, as of 23/Mar/2007
00227       //if ( abs(phi-this->_phi)>2.0 ) { // assumes cones R=1.14 or smaller, merge within 2R only  
00228       //ls: abs bug fixed 26/Mar/2007 
00229       if ( fabs(phi-this->_phi)>2.0 ) { // assumes cones R=1.14 or smaller, merge within 2R only  
00230         phi = fmod( this->_phi+PI, TWOPI);
00231         if (phi < 0.0) phi += TWOPI;
00232         phi -= PI;
00233 
00234         float temp=fmod( jet.phi()+PI, TWOPI);
00235         if (temp < 0.0) temp += TWOPI;
00236         temp -= PI;
00237 
00238         phi = (phi*this->_pT + temp*jet.pT()) /pTsum;
00239       }
00240 
00241       if ( phi < 0. ) phi += TWOPI;
00242     }
00243     
00244 
00246 #ifdef ILCA_USE_MMAP
00247     bool is_stable(const std::multimap<float,const Item*>& items, 
00248                    float radius, float min_ET, int max_iterations=50) 
00249 #else
00250     bool is_stable(const std::list<const Item*>& itemlist, float radius, 
00251                  float min_ET, int max_iterations=50) 
00252 #endif
00253     // Note: max_iterations = 0 will just recompute the jet using the specified cone
00254     {
00255       float radius2 = radius*radius;
00256       float Rcut= 1.E-06;
00257       
00258       
00259       // ?? if(_Increase_Delta_R) Rcut= 1.E-04;
00260       bool stable= true;
00261       int trial= 0;
00262       float Yst;
00263       float PHIst;
00264       do {  
00265         trial++;
00266         //std::cout << "   trial " << trial << " " << _y << " " << _phi << std::endl; 
00267         Yst  = this->_y;
00268         PHIst= this->_phi;    
00269         //cout << "is_stable beginning do loop: this->_pT=" << this->_pT << " this->_y=" << this->_y << " this->_phi=" << this->_phi << endl;
00270         this->erase();
00271         
00272         this->setJet(Yst,PHIst,0.0);
00273         
00274         
00275 #ifdef ILCA_USE_ORDERED_LIST      
00276         std::list<const Item*>::const_iterator lower = 
00277           lower_bound(itemlist.begin(),itemlist.end(),Yst-radius,
00278                       rapidity_order<Item>());
00279         std::list<const Item*>::const_iterator upper = 
00280           upper_bound(itemlist.begin(),itemlist.end(),Yst+radius,
00281                       rapidity_order<Item>());
00282         for(std::list<const Item*>::const_iterator tk = lower; tk != upper; ++tk)      {
00283           //std::cout << " is_stable: item y=" << (*tk)->y() << " phi=" << (*tk)->phi() << " RD2=" << RD2((*tk)->y(),(*tk)->phi(),Yst,PHIst) << " " << Yst-radius << " " << Yst+radius << endl;
00284           if(RD2((*tk)->y(),(*tk)->phi(),Yst,PHIst) <= radius2) 
00285             {
00286               addItem(*tk);
00287             }
00288         }       
00289 #else
00290 #ifdef ILCA_USE_MMAP      
00291         // need to loop only on the subset with   Yst-R < y < Yst+R
00292         for ( std::multimap<float,const Item*>::const_iterator 
00293                 tk = items.lower_bound(Yst-radius);
00294               tk != items.upper_bound(Yst+radius); ++tk )
00295           {
00296             //std::cout << "     item " << (*tk)->y() << " " << (*tk)->phi() << " " << RD2((*tk)->y(),(*tk)->phi(),Yst,PHIst) << " " << Yst-radius << " " << Yst+radius << endl;
00297             if(RD2(((*tk).second)->y(),((*tk).second)->phi(),Yst,PHIst) <= radius2) 
00298               {
00299                 addItem((*tk).second);
00300               }
00301           }
00302         
00303 #else   
00304 
00305         //cout << " is_stable: itemlist.size()=" << itemlist.size() << endl;
00306         for(typename std::list<const Item*>::const_iterator tk = itemlist.begin(); tk != itemlist.end(); ++tk) 
00307           {
00308             //std::cout << "    is_stable: item (*tk)->y()=" << (*tk)->y() << " (*tk)->phi=" << (*tk)->phi() << " RD2=" << RD2((*tk)->y(),(*tk)->phi(),Yst,PHIst) << " Yst-rad=" << Yst-radius << " Yst+rad=" << Yst+radius << endl;
00309             if(RD2((*tk)->y(),(*tk)->phi(),Yst,PHIst) <= radius2) 
00310                {
00311                  //cout << "add item to *tk" << endl;
00312                 this->addItem(*tk);
00313               }
00314           }
00315 #endif
00316 #endif      
00317       
00318         //std::cout << "is_stable, before update: jet this->_y=" << this->_y << " _phi=" << this->_phi << " _pT=" << this->_pT << " min_ET=" << min_ET << std::endl; 
00319         this->updateJet();
00320         //std::cout << "is_stable, after update: jet this->_y=" << this->_y << " _phi=" << this->_phi << " _pT=" << this->_pT << " min_ET=" << min_ET << std::endl; 
00321         
00322         if(this->_pT < min_ET ) 
00323           {
00324             stable= false;
00325             break;
00326           } 
00327         //cout << "is_stable end while loop: this->_pT=" << this->_pT << " this->_y=" << this->_y << " this->_phi=" << this->_phi << endl;
00328       } while(RD2(this->_y,this->_phi,Yst,PHIst) >= Rcut && trial <= max_iterations);
00329       //std::cout << "   trial stable " << trial << " " << stable << std::endl; 
00330       return stable;
00331     }
00332     
00333   private :
00334     
00335   };
00336 };
00338 //template <class Item,class ItemAddress,class IChunk>
00339 //void ILConeAlgorithm <Item,ItemAddress,IChunk>::
00340 template <class Item>
00341 void ILConeAlgorithm <Item>::
00342 //makeClusters(const EnergyClusterReco* r,
00343 makeClusters(
00344              std::list<Item> &jets,
00345              std::list<const Item*>& ilist, 
00346              //float Zvertex, 
00348              //const EnergyClusterCollection<ItemAddress>& preclu,
00349              //IChunk* chunkptr, ConeJetInfoChunk* infochunkptr,
00350              const float Item_ET_Threshold) 
00351 {
00352   // remove items below threshold
00353   for ( typename std::list<const Item*>::iterator it = ilist.begin(); 
00354 
00355         it != ilist.end(); )
00356   {
00357     if ( (*it)->pT() < Item_ET_Threshold ) 
00358     {
00359       it = ilist.erase(it);
00360     }
00361       else ++it;
00362   }
00363 
00364   // create an energy cluster collection for jets 
00365   //EnergyClusterCollection<ItemAddress>* ptrcol;
00366   //Item* ptrcol;
00367   //r->createClusterCollection(chunkptr,ptrcol);
00369   std::vector<const Item*> ecv;
00370   for ( typename std::list<const Item*>::iterator it = ilist.begin(); 
00371         it != ilist.end(); it++) {
00372     ecv.push_back(*it);
00373   }
00374 
00375 
00376   //preclu.getClusters(ecv);
00377   //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% need to fill here vector ecv
00378 
00379   //std::cout << " number of seed clusters: " << ecv.size() << std::endl;
00380 
00381   // skip precluster close to jets
00382   float far_def = _FAR_RATIO*_CONE_RADIUS * _FAR_RATIO*_CONE_RADIUS;
00383 
00384   // skip if jet Et is below some value
00385   float ratio= _MIN_JET_ET*_ET_MIN_RATIO;
00386 
00387 
00388 #ifdef ILCA_USE_ORDERED_LIST
00389   // sort the list in rapidity order
00390   ilist.sort(rapidity_order<Item>());
00391 #else
00392 #ifdef ILCA_USE_MMAP  
00393   // create a y ordered list of items 
00394   std::multimap<float,const Item*> items;
00395   std::list<const Item*>::const_iterator it;
00396   for(it = ilist.begin(); it != ilist.end(); ++it) 
00397   {
00398     pair<float,const Item*> p((*it)->y(),*it);
00399     items.insert(p);
00400   }
00401 #endif
00402 #endif
00403 
00404   std::vector<ProtoJet<Item> > mcoll;
00405   std::vector<TemporaryJet> scoll; 
00406 
00407 
00408   // find stable jets around seeds 
00409   //typename std::vector<const EnergyCluster<ItemAddress>* >::iterator jclu;
00410   typename std::vector<const Item*>::iterator jclu;
00411   for(jclu = ecv.begin(); jclu != ecv.end(); ++jclu) 
00412   {
00413     //const EnergyCluster<ItemAddress>* ptr= *jclu;
00414     const Item* ptr= *jclu;
00415     float p[4];
00416     ptr->p4vec(p);
00417     float Yst  = P2y(p);
00418     float PHIst= P2phi(p);
00419 
00420     // don't keep preclusters close to jet
00421     bool is_far= true;
00422     // ?? if(_Kill_Far_Clusters) {
00423     for(unsigned int i = 0; i < scoll.size(); ++i) 
00424     {
00425       float y  = scoll[i].y();
00426       float phi= scoll[i].phi();
00427       if(RD2(Yst,PHIst,y,phi) < far_def) 
00428       {
00429         is_far= false;
00430         break;
00431       }
00432     }
00433     // ?? }
00434 
00435     if(is_far) 
00436     {
00437       TemporaryJet jet(ptr->pT(),Yst,PHIst);
00438       //cout << "temporary jet: pt=" << ptr->pT() << " y=" << Yst << " phi=" << PHIst << endl;
00439 
00440       // Search cones are smaller, so contain less jet Et 
00441       // Don't throw out too many little jets during search phase!
00442       // Strategy: check Et first with full cone, then search with low-GeV min_et thresh
00443 #ifdef ILCA_USE_MMAP
00444       if(jet.is_stable(items,_CONE_RADIUS,ratio,0) && jet.is_stable(items,_SEARCH_CONE,3.0)) 
00445 #else
00446       if(jet.is_stable(ilist,_CONE_RADIUS,ratio,0) && jet.is_stable(ilist,_SEARCH_CONE,3.0)) 
00447 #endif
00448       {
00449 
00450         //cout << "temporary jet is stable" << endl;
00451 
00452 // jpk  Resize the found jets 
00453 #ifdef ILCA_USE_MMAP
00454         jet.is_stable(items,_CONE_RADIUS,ratio,0) ;
00455 #else
00456         jet.is_stable(ilist,_CONE_RADIUS,ratio,0) ;
00457 #endif
00458         //cout << "found jet has been resized if any" << endl;
00459 
00460         if ( _KILL_DUPLICATE ) 
00461         {
00462           // check if we are not finding the same jet again
00463           float distmax = 999.; int imax = -1;
00464           for(unsigned int i = 0; i < scoll.size(); ++i) 
00465           {
00466             float dist = jet.dist(scoll[i]);
00467             if ( dist < distmax )
00468             {
00469               distmax = dist;
00470               imax = i;
00471             }
00472           }
00473           if ( distmax > _DUPLICATE_DR ||
00474                fabs((jet.pT()-scoll[imax].pT())/scoll[imax].pT())>_DUPLICATE_DPT )
00475           {
00476             scoll.push_back(jet);
00477             mcoll.push_back(jet);
00478             //std::cout << " stable cone " << jet.y() << " " << jet.phi() << " " << jet.pT() << std::endl;
00479           }
00480           /*
00481             else
00482             {
00483             std::cout << " jet too close to a found jet " << distmax << " " << 
00484             fabs((jet.pT()-scoll[imax].pT())/scoll[imax].pT()) << std::endl;
00485             }
00486           */
00487         }
00488         else
00489         {
00490           scoll.push_back(jet);
00491           mcoll.push_back(jet);
00492           //std::cout << " stable cone " << jet.y() << " " << jet.phi() << " " << jet.pT() << std::endl;
00493         }
00494 
00495       }
00496     }
00497   }
00498 
00499   // find stable jets around midpoints
00500   for(unsigned int i = 0; i < scoll.size(); ++i) 
00501   {
00502     for(unsigned int k = i+1; k < scoll.size(); ++k) 
00503     {
00504       float djet= scoll[i].dist(scoll[k]);
00505       if(djet > _CONE_RADIUS && djet < 2.*_CONE_RADIUS) 
00506       {
00507         float y_mid,phi_mid;
00508         scoll[i].midpoint(scoll[k],y_mid,phi_mid);
00509         TemporaryJet jet(-999999.,y_mid,phi_mid);
00510         //std::cout << " midpoint: " << scoll[i].pT() << " " << scoll[i].info().seedET() << " " << scoll[k].pT() << " " << scoll[k].info().seedET() << " " << y_mid << " " << phi_mid << std::endl; 
00511 
00512 // midpoint jets are full size
00513 #ifdef ILCA_USE_MMAP
00514       if(jet.is_stable(items,_CONE_RADIUS,ratio)) 
00515 #else
00516       if(jet.is_stable(ilist,_CONE_RADIUS,ratio)) 
00517 #endif
00518         {
00519           mcoll.push_back(jet);
00520           //std::cout << " stable midpoint cone " << jet.y() << " " << jet.phi() << " " << jet.pT() << std::endl;
00521         }
00522       }
00523     }
00524   }
00525 
00526 
00527   // do a pT ordered splitting/merging
00528   ConeSplitMerge<Item> pjets(mcoll);
00529   ilcv.clear();
00530   pjets.split_merge(ilcv,_SPLIT_RATIO, _PT_MIN_LEADING_PROTOJET, _PT_MIN_SECOND_PROTOJET, _MERGE_MAX, _PT_MIN_noMERGE_MAX);
00531 
00532 
00533   for(unsigned int i = 0; i < ilcv.size(); ++i) 
00534   {
00535     if ( ilcv[i].pT() > _MIN_JET_ET )
00536     {
00537       //EnergyCluster<ItemAddress>* ptrclu;
00538       Item ptrclu;
00539       //r->createCluster(ptrcol,ptrclu);
00540       
00541       std::list<const Item*> tlist=ilcv[i].LItems();
00542       typename std::list<const Item*>::iterator tk;
00543       for(tk = tlist.begin(); tk != tlist.end(); ++tk) 
00544       {
00545         //ItemAddress addr= (*tk)->address();
00546         float pk[4];
00547         (*tk)->p4vec(pk);
00548         //std::cout << (*tk)->index <<" " <<  (*tk) << std::endl;
00549         //float emE= (*tk)->emE();
00550         //r->addClusterItem(ptrclu,addr,pk,emE);
00551         //ptrclu->Add(*tk);
00552         ptrclu.Add(**tk);
00553       }
00554       // print out
00555       //ptrclu->print(cout);
00556       
00557       //infochunkptr->addInfo(ilcv[i].info());
00558       jets.push_back(ptrclu);
00559     }
00560   }
00561 }
00562 
00563 }  // namespace d0
00564 
00565 FASTJET_END_NAMESPACE
00566 
00567 #endif
00568 
00569 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines