fastjet 2.4.3
|
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 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