FastJet 3.0beta1
|
00001 //STARTHEADER 00002 // $Id: ClusterSequence_TiledN2.cc 1816 2010-11-19 11:35:52Z salam $ 00003 // 00004 // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam 00005 // 00006 //---------------------------------------------------------------------- 00007 // This file is part of FastJet. 00008 // 00009 // FastJet is free software; you can redistribute it and/or modify 00010 // it under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation; either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // The algorithms that underlie FastJet have required considerable 00015 // development and are described in hep-ph/0512210. If you use 00016 // FastJet as part of work towards a scientific publication, please 00017 // include a citation to the FastJet paper. 00018 // 00019 // FastJet is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 // GNU General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with FastJet; if not, write to the Free Software 00026 // Foundation, Inc.: 00027 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00028 //---------------------------------------------------------------------- 00029 //ENDHEADER 00030 00031 00032 // The plain N^2 part of the ClusterSequence class -- separated out 00033 // from the rest of the class implementation so as to speed up 00034 // compilation of this particular part while it is under test. 00035 00036 #include<iostream> 00037 #include<vector> 00038 #include<cmath> 00039 #include<algorithm> 00040 #include "fastjet/PseudoJet.hh" 00041 #include "fastjet/ClusterSequence.hh" 00042 #include "fastjet/internal/MinHeap.hh" 00043 00044 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 00045 00046 using namespace std; 00047 00048 00049 //---------------------------------------------------------------------- 00050 void ClusterSequence::_bj_remove_from_tiles(TiledJet * const jet) { 00051 Tile * tile = & _tiles[jet->tile_index]; 00052 00053 if (jet->previous == NULL) { 00054 // we are at head of the tile, so reset it. 00055 // If this was the only jet on the tile then tile->head will now be NULL 00056 tile->head = jet->next; 00057 } else { 00058 // adjust link from previous jet in this tile 00059 jet->previous->next = jet->next; 00060 } 00061 if (jet->next != NULL) { 00062 // adjust backwards-link from next jet in this tile 00063 jet->next->previous = jet->previous; 00064 } 00065 } 00066 00067 //---------------------------------------------------------------------- 00068 /// Set up the tiles: 00069 /// - decide the range in eta 00070 /// - allocate the tiles 00071 /// - set up the cross-referencing info between tiles 00072 /// 00073 /// The neighbourhood of a tile is set up as follows 00074 /// 00075 /// LRR 00076 /// LXR 00077 /// LLR 00078 /// 00079 /// such that tiles is an array containing XLLLLRRRR with pointers 00080 /// | \ RH_tiles 00081 /// \ surrounding_tiles 00082 /// 00083 /// with appropriate precautions when close to the edge of the tiled 00084 /// region. 00085 /// 00086 void ClusterSequence::_initialise_tiles() { 00087 00088 // first decide tile sizes (with a lower bound to avoid huge memory use with 00089 // very small R) 00090 double default_size = max(0.1,_Rparam); 00091 _tile_size_eta = default_size; 00092 // it makes no sense to go below 3 tiles in phi -- 3 tiles is 00093 // sufficient to make sure all pair-wise combinations up to pi in 00094 // phi are possible 00095 _n_tiles_phi = max(3,int(floor(twopi/default_size))); 00096 _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi 00097 00098 // always include zero rapidity in the tiling region 00099 _tiles_eta_min = 0.0; 00100 _tiles_eta_max = 0.0; 00101 // but go no further than following 00102 const double maxrap = 7.0; 00103 00104 // and find out how much further one should go 00105 for(unsigned int i = 0; i < _jets.size(); i++) { 00106 double eta = _jets[i].rap(); 00107 // first check if eta is in range -- to avoid taking into account 00108 // very spurious rapidities due to particles with near-zero kt. 00109 if (abs(eta) < maxrap) { 00110 if (eta < _tiles_eta_min) {_tiles_eta_min = eta;} 00111 if (eta > _tiles_eta_max) {_tiles_eta_max = eta;} 00112 } 00113 } 00114 00115 // now adjust the values 00116 _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta)); 00117 _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta)); 00118 _tiles_eta_min = _tiles_ieta_min * _tile_size_eta; 00119 _tiles_eta_max = _tiles_ieta_max * _tile_size_eta; 00120 00121 // allocate the tiles 00122 _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi); 00123 00124 // now set up the cross-referencing between tiles 00125 for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) { 00126 for (int iphi = 0; iphi < _n_tiles_phi; iphi++) { 00127 Tile * tile = & _tiles[_tile_index(ieta,iphi)]; 00128 // no jets in this tile yet 00129 tile->head = NULL; // first element of tiles points to itself 00130 tile->begin_tiles[0] = tile; 00131 Tile ** pptile = & (tile->begin_tiles[0]); 00132 pptile++; 00133 // 00134 // set up L's in column to the left of X 00135 tile->surrounding_tiles = pptile; 00136 if (ieta > _tiles_ieta_min) { 00137 // with the itile subroutine, we can safely run tiles from 00138 // idphi=-1 to idphi=+1, because it takes care of 00139 // negative and positive boundaries 00140 for (int idphi = -1; idphi <=+1; idphi++) { 00141 *pptile = & _tiles[_tile_index(ieta-1,iphi+idphi)]; 00142 pptile++; 00143 } 00144 } 00145 // now set up last L (below X) 00146 *pptile = & _tiles[_tile_index(ieta,iphi-1)]; 00147 pptile++; 00148 // set up first R (above X) 00149 tile->RH_tiles = pptile; 00150 *pptile = & _tiles[_tile_index(ieta,iphi+1)]; 00151 pptile++; 00152 // set up remaining R's, to the right of X 00153 if (ieta < _tiles_ieta_max) { 00154 for (int idphi = -1; idphi <= +1; idphi++) { 00155 *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)]; 00156 pptile++; 00157 } 00158 } 00159 // now put semaphore for end tile 00160 tile->end_tiles = pptile; 00161 // finally make sure tiles are untagged 00162 tile->tagged = false; 00163 } 00164 } 00165 00166 } 00167 00168 00169 //---------------------------------------------------------------------- 00170 /// return the tile index corresponding to the given eta,phi point 00171 int ClusterSequence::_tile_index(const double & eta, const double & phi) const { 00172 int ieta, iphi; 00173 if (eta <= _tiles_eta_min) {ieta = 0;} 00174 else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;} 00175 else { 00176 //ieta = int(floor((eta - _tiles_eta_min) / _tile_size_eta)); 00177 ieta = int(((eta - _tiles_eta_min) / _tile_size_eta)); 00178 // following needed in case of rare but nasty rounding errors 00179 if (ieta > _tiles_ieta_max-_tiles_ieta_min) { 00180 ieta = _tiles_ieta_max-_tiles_ieta_min;} 00181 } 00182 // allow for some extent of being beyond range in calculation of phi 00183 // as well 00184 //iphi = (int(floor(phi/_tile_size_phi)) + _n_tiles_phi) % _n_tiles_phi; 00185 // with just int and no floor, things run faster but beware 00186 iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi; 00187 return (iphi + ieta * _n_tiles_phi); 00188 } 00189 00190 00191 //---------------------------------------------------------------------- 00192 // overloaded version which additionally sets up information regarding the 00193 // tiling 00194 inline void ClusterSequence::_tj_set_jetinfo( TiledJet * const jet, 00195 const int _jets_index) { 00196 // first call the generic setup 00197 _bj_set_jetinfo<>(jet, _jets_index); 00198 00199 // Then do the setup specific to the tiled case. 00200 00201 // Find out which tile it belonds to 00202 jet->tile_index = _tile_index(jet->eta, jet->phi); 00203 00204 // Insert it into the tile's linked list of jets 00205 Tile * tile = &_tiles[jet->tile_index]; 00206 jet->previous = NULL; 00207 jet->next = tile->head; 00208 if (jet->next != NULL) {jet->next->previous = jet;} 00209 tile->head = jet; 00210 } 00211 00212 00213 //---------------------------------------------------------------------- 00214 /// output the contents of the tiles 00215 void ClusterSequence::_print_tiles(TiledJet * briefjets ) const { 00216 for (vector<Tile>::const_iterator tile = _tiles.begin(); 00217 tile < _tiles.end(); tile++) { 00218 cout << "Tile " << tile - _tiles.begin()<<" = "; 00219 vector<int> list; 00220 for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) { 00221 list.push_back(jetI-briefjets); 00222 //cout <<" "<<jetI-briefjets; 00223 } 00224 sort(list.begin(),list.end()); 00225 for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];} 00226 cout <<"\n"; 00227 } 00228 } 00229 00230 00231 //---------------------------------------------------------------------- 00232 /// Add to the vector tile_union the tiles that are in the neighbourhood 00233 /// of the specified tile_index, including itself -- start adding 00234 /// from position n_near_tiles-1, and increase n_near_tiles as 00235 /// you go along (could have done it more C++ like with vector with reserved 00236 /// space, but fear is that it would have been slower, e.g. checking 00237 /// for end of vector at each stage to decide whether to resize it) 00238 void ClusterSequence::_add_neighbours_to_tile_union(const int tile_index, 00239 vector<int> & tile_union, int & n_near_tiles) const { 00240 for (Tile * const * near_tile = _tiles[tile_index].begin_tiles; 00241 near_tile != _tiles[tile_index].end_tiles; near_tile++){ 00242 // get the tile number 00243 tile_union[n_near_tiles] = *near_tile - & _tiles[0]; 00244 n_near_tiles++; 00245 } 00246 } 00247 00248 00249 //---------------------------------------------------------------------- 00250 /// Like _add_neighbours_to_tile_union, but only adds neighbours if 00251 /// their "tagged" status is false; when a neighbour is added its 00252 /// tagged status is set to true. 00253 inline void ClusterSequence::_add_untagged_neighbours_to_tile_union( 00254 const int tile_index, 00255 vector<int> & tile_union, int & n_near_tiles) { 00256 for (Tile ** near_tile = _tiles[tile_index].begin_tiles; 00257 near_tile != _tiles[tile_index].end_tiles; near_tile++){ 00258 if (! (*near_tile)->tagged) { 00259 (*near_tile)->tagged = true; 00260 // get the tile number 00261 tile_union[n_near_tiles] = *near_tile - & _tiles[0]; 00262 n_near_tiles++; 00263 } 00264 } 00265 } 00266 00267 00268 //---------------------------------------------------------------------- 00269 /// run a tiled clustering 00270 void ClusterSequence::_tiled_N2_cluster() { 00271 00272 _initialise_tiles(); 00273 00274 int n = _jets.size(); 00275 TiledJet * briefjets = new TiledJet[n]; 00276 TiledJet * jetA = briefjets, * jetB; 00277 TiledJet oldB; 00278 00279 00280 // will be used quite deep inside loops, but declare it here so that 00281 // memory (de)allocation gets done only once 00282 vector<int> tile_union(3*n_tile_neighbours); 00283 00284 // initialise the basic jet info 00285 for (int i = 0; i< n; i++) { 00286 _tj_set_jetinfo(jetA, i); 00287 //cout << i<<": "<<jetA->tile_index<<"\n"; 00288 jetA++; // move on to next entry of briefjets 00289 } 00290 TiledJet * tail = jetA; // a semaphore for the end of briefjets 00291 TiledJet * head = briefjets; // a nicer way of naming start 00292 00293 // set up the initial nearest neighbour information 00294 vector<Tile>::const_iterator tile; 00295 for (tile = _tiles.begin(); tile != _tiles.end(); tile++) { 00296 // first do it on this tile 00297 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00298 for (jetB = tile->head; jetB != jetA; jetB = jetB->next) { 00299 double dist = _bj_dist(jetA,jetB); 00300 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00301 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00302 } 00303 } 00304 // then do it for RH tiles 00305 for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) { 00306 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00307 for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) { 00308 double dist = _bj_dist(jetA,jetB); 00309 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00310 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00311 } 00312 } 00313 } 00314 } 00315 00316 // now create the diJ (where J is i's NN) table -- remember that 00317 // we differ from standard normalisation here by a factor of R2 00318 double * diJ = new double[n]; 00319 jetA = head; 00320 for (int i = 0; i < n; i++) { 00321 diJ[i] = _bj_diJ(jetA); 00322 jetA++; // have jetA follow i 00323 } 00324 00325 // now run the recombination loop 00326 int history_location = n-1; 00327 while (tail != head) { 00328 00329 // find the minimum of the diJ on this round 00330 double diJ_min = diJ[0]; 00331 int diJ_min_jet = 0; 00332 for (int i = 1; i < n; i++) { 00333 if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min = diJ[i];} 00334 } 00335 00336 // do the recombination between A and B 00337 history_location++; 00338 jetA = & briefjets[diJ_min_jet]; 00339 jetB = jetA->NN; 00340 // put the normalisation back in 00341 diJ_min *= _invR2; 00342 00343 //if (n == 19) {cout << "Hello "<<jetA-head<<" "<<jetB-head<<"\n";} 00344 00345 //cout <<" WILL RECOMBINE "<< jetA-briefjets<<" "<<jetB-briefjets<<"\n"; 00346 00347 if (jetB != NULL) { 00348 // jet-jet recombination 00349 // If necessary relabel A & B to ensure jetB < jetA, that way if 00350 // the larger of them == newtail then that ends up being jetA and 00351 // the new jet that is added as jetB is inserted in a position that 00352 // has a future! 00353 if (jetA < jetB) {std::swap(jetA,jetB);} 00354 00355 int nn; // new jet index 00356 _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn); 00357 00358 //OBS// get the two history indices 00359 //OBSint hist_a = _jets[jetA->_jets_index].cluster_hist_index(); 00360 //OBSint hist_b = _jets[jetB->_jets_index].cluster_hist_index(); 00361 //OBS// create the recombined jet 00362 //OBS_jets.push_back(_jets[jetA->_jets_index] + _jets[jetB->_jets_index]); 00363 //OBSint nn = _jets.size() - 1; 00364 //OBS_jets[nn].set_cluster_hist_index(history_location); 00365 //OBS// update history 00366 //OBS//cout <<n-1<<" "<<jetA-head<<" "<<jetB-head<<"; "; 00367 //OBS_add_step_to_history(history_location, 00368 //OBS min(hist_a,hist_b),max(hist_a,hist_b), 00369 //OBS nn, diJ_min); 00370 00371 // what was jetB will now become the new jet 00372 _bj_remove_from_tiles(jetA); 00373 oldB = * jetB; // take a copy because we will need it... 00374 _bj_remove_from_tiles(jetB); 00375 _tj_set_jetinfo(jetB, nn); // also registers the jet in the tiling 00376 } else { 00377 // jet-beam recombination 00378 _do_iB_recombination_step(jetA->_jets_index, diJ_min); 00379 00380 //OBS// get the hist_index 00381 //OBSint hist_a = _jets[jetA->_jets_index].cluster_hist_index(); 00382 //OBS//cout <<n-1<<" "<<jetA-head<<" "<<-1<<"; "; 00383 //OBS_add_step_to_history(history_location,hist_a,BeamJet,Invalid,diJ_min); 00384 _bj_remove_from_tiles(jetA); 00385 } 00386 00387 // first establish the set of tiles over which we are going to 00388 // have to run searches for updated and new nearest-neighbours 00389 int n_near_tiles = 0; 00390 _add_neighbours_to_tile_union(jetA->tile_index, tile_union, n_near_tiles); 00391 if (jetB != NULL) { 00392 bool sort_it = false; 00393 if (jetB->tile_index != jetA->tile_index) { 00394 sort_it = true; 00395 _add_neighbours_to_tile_union(jetB->tile_index,tile_union,n_near_tiles); 00396 } 00397 if (oldB.tile_index != jetA->tile_index && 00398 oldB.tile_index != jetB->tile_index) { 00399 sort_it = true; 00400 _add_neighbours_to_tile_union(oldB.tile_index,tile_union,n_near_tiles); 00401 } 00402 00403 if (sort_it) { 00404 // sort the tiles before then compressing the list 00405 sort(tile_union.begin(), tile_union.begin()+n_near_tiles); 00406 // and now condense the list 00407 int nnn = 1; 00408 for (int i = 1; i < n_near_tiles; i++) { 00409 if (tile_union[i] != tile_union[nnn-1]) { 00410 tile_union[nnn] = tile_union[i]; 00411 nnn++; 00412 } 00413 } 00414 n_near_tiles = nnn; 00415 } 00416 } 00417 00418 // now update our nearest neighbour info and diJ table 00419 // first reduce size of table 00420 tail--; n--; 00421 if (jetA == tail) { 00422 // there is nothing to be done 00423 } else { 00424 // Copy last jet contents and diJ info into position of jetA 00425 *jetA = *tail; 00426 diJ[jetA - head] = diJ[tail-head]; 00427 // IN the tiling fix pointers to tail and turn them into 00428 // pointers to jetA (from predecessors, successors and the tile 00429 // head if need be) 00430 if (jetA->previous == NULL) { 00431 _tiles[jetA->tile_index].head = jetA; 00432 } else { 00433 jetA->previous->next = jetA; 00434 } 00435 if (jetA->next != NULL) {jetA->next->previous = jetA;} 00436 } 00437 00438 // Initialise jetB's NN distance as well as updating it for 00439 // other particles. 00440 for (int itile = 0; itile < n_near_tiles; itile++) { 00441 Tile * tile = &_tiles[tile_union[itile]]; 00442 for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) { 00443 // see if jetI had jetA or jetB as a NN -- if so recalculate the NN 00444 if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) { 00445 jetI->NN_dist = _R2; 00446 jetI->NN = NULL; 00447 // now go over tiles that are neighbours of I (include own tile) 00448 for (Tile ** near_tile = tile->begin_tiles; 00449 near_tile != tile->end_tiles; near_tile++) { 00450 // and then over the contents of that tile 00451 for (TiledJet * jetJ = (*near_tile)->head; 00452 jetJ != NULL; jetJ = jetJ->next) { 00453 double dist = _bj_dist(jetI,jetJ); 00454 if (dist < jetI->NN_dist && jetJ != jetI) { 00455 jetI->NN_dist = dist; jetI->NN = jetJ; 00456 } 00457 } 00458 } 00459 diJ[jetI-head] = _bj_diJ(jetI); // update diJ 00460 } 00461 // check whether new jetB is closer than jetI's current NN and 00462 // if need to update things 00463 if (jetB != NULL) { 00464 double dist = _bj_dist(jetI,jetB); 00465 if (dist < jetI->NN_dist) { 00466 if (jetI != jetB) { 00467 jetI->NN_dist = dist; 00468 jetI->NN = jetB; 00469 diJ[jetI-head] = _bj_diJ(jetI); // update diJ... 00470 } 00471 } 00472 if (dist < jetB->NN_dist) { 00473 if (jetI != jetB) { 00474 jetB->NN_dist = dist; 00475 jetB->NN = jetI;} 00476 } 00477 } 00478 } 00479 } 00480 00481 00482 if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);} 00483 //cout << n<<" "<<briefjets[95].NN-briefjets<<" "<<briefjets[95].NN_dist <<"\n"; 00484 00485 // remember to update pointers to tail 00486 for (Tile ** near_tile = _tiles[tail->tile_index].begin_tiles; 00487 near_tile!= _tiles[tail->tile_index].end_tiles; near_tile++){ 00488 // and then the contents of that tile 00489 for (TiledJet * jetJ = (*near_tile)->head; 00490 jetJ != NULL; jetJ = jetJ->next) { 00491 if (jetJ->NN == tail) {jetJ->NN = jetA;} 00492 } 00493 } 00494 00495 //for (int i = 0; i < n; i++) { 00496 // if (briefjets[i].NN-briefjets >= n && briefjets[i].NN != NULL) {cout <<"YOU MUST BE CRAZY for n ="<<n<<", i = "<<i<<", NN = "<<briefjets[i].NN-briefjets<<"\n";} 00497 //} 00498 00499 00500 if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);} 00501 //cout << briefjets[95].NN-briefjets<<" "<<briefjets[95].NN_dist <<"\n"; 00502 00503 } 00504 00505 // final cleaning up; 00506 delete[] diJ; 00507 delete[] briefjets; 00508 } 00509 00510 00511 //---------------------------------------------------------------------- 00512 /// run a tiled clustering 00513 void ClusterSequence::_faster_tiled_N2_cluster() { 00514 00515 _initialise_tiles(); 00516 00517 int n = _jets.size(); 00518 TiledJet * briefjets = new TiledJet[n]; 00519 TiledJet * jetA = briefjets, * jetB; 00520 TiledJet oldB; 00521 00522 00523 // will be used quite deep inside loops, but declare it here so that 00524 // memory (de)allocation gets done only once 00525 vector<int> tile_union(3*n_tile_neighbours); 00526 00527 // initialise the basic jet info 00528 for (int i = 0; i< n; i++) { 00529 _tj_set_jetinfo(jetA, i); 00530 //cout << i<<": "<<jetA->tile_index<<"\n"; 00531 jetA++; // move on to next entry of briefjets 00532 } 00533 TiledJet * head = briefjets; // a nicer way of naming start 00534 00535 // set up the initial nearest neighbour information 00536 vector<Tile>::const_iterator tile; 00537 for (tile = _tiles.begin(); tile != _tiles.end(); tile++) { 00538 // first do it on this tile 00539 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00540 for (jetB = tile->head; jetB != jetA; jetB = jetB->next) { 00541 double dist = _bj_dist(jetA,jetB); 00542 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00543 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00544 } 00545 } 00546 // then do it for RH tiles 00547 for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) { 00548 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00549 for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) { 00550 double dist = _bj_dist(jetA,jetB); 00551 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00552 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00553 } 00554 } 00555 } 00556 // no need to do it for LH tiles, since they are implicitly done 00557 // when we set NN for both jetA and jetB on the RH tiles. 00558 } 00559 00560 00561 // now create the diJ (where J is i's NN) table -- remember that 00562 // we differ from standard normalisation here by a factor of R2 00563 // (corrected for at the end). 00564 struct diJ_plus_link { 00565 double diJ; // the distance 00566 TiledJet * jet; // the jet (i) for which we've found this distance 00567 // (whose NN will the J). 00568 }; 00569 diJ_plus_link * diJ = new diJ_plus_link[n]; 00570 jetA = head; 00571 for (int i = 0; i < n; i++) { 00572 diJ[i].diJ = _bj_diJ(jetA); // kt distance * R^2 00573 diJ[i].jet = jetA; // our compact diJ table will not be in 00574 jetA->diJ_posn = i; // one-to-one corresp. with non-compact jets, 00575 // so set up bi-directional correspondence here. 00576 jetA++; // have jetA follow i 00577 } 00578 00579 // now run the recombination loop 00580 int history_location = n-1; 00581 while (n > 0) { 00582 00583 // find the minimum of the diJ on this round 00584 diJ_plus_link * best, *stop; // pointers a bit faster than indices 00585 // could use best to keep track of diJ min, but it turns out to be 00586 // marginally faster to have a separate variable (avoids n 00587 // dereferences at the expense of n/2 assignments). 00588 double diJ_min = diJ[0].diJ; // initialise the best one here. 00589 best = diJ; // and here 00590 stop = diJ+n; 00591 for (diJ_plus_link * here = diJ+1; here != stop; here++) { 00592 if (here->diJ < diJ_min) {best = here; diJ_min = here->diJ;} 00593 } 00594 00595 // do the recombination between A and B 00596 history_location++; 00597 jetA = best->jet; 00598 jetB = jetA->NN; 00599 // put the normalisation back in 00600 diJ_min *= _invR2; 00601 00602 if (jetB != NULL) { 00603 // jet-jet recombination 00604 // If necessary relabel A & B to ensure jetB < jetA, that way if 00605 // the larger of them == newtail then that ends up being jetA and 00606 // the new jet that is added as jetB is inserted in a position that 00607 // has a future! 00608 if (jetA < jetB) {std::swap(jetA,jetB);} 00609 00610 int nn; // new jet index 00611 _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn); 00612 00613 //OBS// get the two history indices 00614 //OBSint ihstry_a = _jets[jetA->_jets_index].cluster_hist_index(); 00615 //OBSint ihstry_b = _jets[jetB->_jets_index].cluster_hist_index(); 00616 //OBS// create the recombined jet 00617 //OBS_jets.push_back(_jets[jetA->_jets_index] + _jets[jetB->_jets_index]); 00618 //OBSint nn = _jets.size() - 1; 00619 //OBS_jets[nn].set_cluster_hist_index(history_location); 00620 //OBS// update history 00621 //OBS//cout <<n-1<<" "<<jetA-head<<" "<<jetB-head<<"; "; 00622 //OBS_add_step_to_history(history_location, 00623 //OBS min(ihstry_a,ihstry_b),max(ihstry_a,ihstry_b), 00624 //OBS nn, diJ_min); 00625 // what was jetB will now become the new jet 00626 _bj_remove_from_tiles(jetA); 00627 oldB = * jetB; // take a copy because we will need it... 00628 _bj_remove_from_tiles(jetB); 00629 _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn] 00630 // (also registers the jet in the tiling) 00631 } else { 00632 // jet-beam recombination 00633 // get the hist_index 00634 _do_iB_recombination_step(jetA->_jets_index, diJ_min); 00635 //OBSint ihstry_a = _jets[jetA->_jets_index].cluster_hist_index(); 00636 //OBS//cout <<n-1<<" "<<jetA-head<<" "<<-1<<"; "; 00637 //OBS_add_step_to_history(history_location,ihstry_a,BeamJet,Invalid,diJ_min); 00638 _bj_remove_from_tiles(jetA); 00639 } 00640 00641 // first establish the set of tiles over which we are going to 00642 // have to run searches for updated and new nearest-neighbours -- 00643 // basically a combination of vicinity of the tiles of the two old 00644 // and one new jet. 00645 int n_near_tiles = 0; 00646 _add_untagged_neighbours_to_tile_union(jetA->tile_index, 00647 tile_union, n_near_tiles); 00648 if (jetB != NULL) { 00649 if (jetB->tile_index != jetA->tile_index) { 00650 _add_untagged_neighbours_to_tile_union(jetB->tile_index, 00651 tile_union,n_near_tiles); 00652 } 00653 if (oldB.tile_index != jetA->tile_index && 00654 oldB.tile_index != jetB->tile_index) { 00655 _add_untagged_neighbours_to_tile_union(oldB.tile_index, 00656 tile_union,n_near_tiles); 00657 } 00658 } 00659 00660 // now update our nearest neighbour info and diJ table 00661 // first reduce size of table 00662 n--; 00663 // then compactify the diJ by taking the last of the diJ and copying 00664 // it to the position occupied by the diJ for jetA 00665 diJ[n].jet->diJ_posn = jetA->diJ_posn; 00666 diJ[jetA->diJ_posn] = diJ[n]; 00667 00668 // Initialise jetB's NN distance as well as updating it for 00669 // other particles. 00670 // Run over all tiles in our union 00671 for (int itile = 0; itile < n_near_tiles; itile++) { 00672 Tile * tile = &_tiles[tile_union[itile]]; 00673 tile->tagged = false; // reset tag, since we're done with unions 00674 // run over all jets in the current tile 00675 for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) { 00676 // see if jetI had jetA or jetB as a NN -- if so recalculate the NN 00677 if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) { 00678 jetI->NN_dist = _R2; 00679 jetI->NN = NULL; 00680 // now go over tiles that are neighbours of I (include own tile) 00681 for (Tile ** near_tile = tile->begin_tiles; 00682 near_tile != tile->end_tiles; near_tile++) { 00683 // and then over the contents of that tile 00684 for (TiledJet * jetJ = (*near_tile)->head; 00685 jetJ != NULL; jetJ = jetJ->next) { 00686 double dist = _bj_dist(jetI,jetJ); 00687 if (dist < jetI->NN_dist && jetJ != jetI) { 00688 jetI->NN_dist = dist; jetI->NN = jetJ; 00689 } 00690 } 00691 } 00692 diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ kt-dist 00693 } 00694 // check whether new jetB is closer than jetI's current NN and 00695 // if jetI is closer than jetB's current (evolving) nearest 00696 // neighbour. Where relevant update things 00697 if (jetB != NULL) { 00698 double dist = _bj_dist(jetI,jetB); 00699 if (dist < jetI->NN_dist) { 00700 if (jetI != jetB) { 00701 jetI->NN_dist = dist; 00702 jetI->NN = jetB; 00703 diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ... 00704 } 00705 } 00706 if (dist < jetB->NN_dist) { 00707 if (jetI != jetB) { 00708 jetB->NN_dist = dist; 00709 jetB->NN = jetI;} 00710 } 00711 } 00712 } 00713 } 00714 00715 // finally, register the updated kt distance for B 00716 if (jetB != NULL) {diJ[jetB->diJ_posn].diJ = _bj_diJ(jetB);} 00717 00718 } 00719 00720 // final cleaning up; 00721 delete[] diJ; 00722 delete[] briefjets; 00723 } 00724 00725 00726 00727 //---------------------------------------------------------------------- 00728 /// run a tiled clustering, with our minheap for keeping track of the 00729 /// smallest dij 00730 void ClusterSequence::_minheap_faster_tiled_N2_cluster() { 00731 00732 _initialise_tiles(); 00733 00734 int n = _jets.size(); 00735 TiledJet * briefjets = new TiledJet[n]; 00736 TiledJet * jetA = briefjets, * jetB; 00737 TiledJet oldB; 00738 00739 00740 // will be used quite deep inside loops, but declare it here so that 00741 // memory (de)allocation gets done only once 00742 vector<int> tile_union(3*n_tile_neighbours); 00743 00744 // initialise the basic jet info 00745 for (int i = 0; i< n; i++) { 00746 _tj_set_jetinfo(jetA, i); 00747 //cout << i<<": "<<jetA->tile_index<<"\n"; 00748 jetA++; // move on to next entry of briefjets 00749 } 00750 TiledJet * head = briefjets; // a nicer way of naming start 00751 00752 // set up the initial nearest neighbour information 00753 vector<Tile>::const_iterator tile; 00754 for (tile = _tiles.begin(); tile != _tiles.end(); tile++) { 00755 // first do it on this tile 00756 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00757 for (jetB = tile->head; jetB != jetA; jetB = jetB->next) { 00758 double dist = _bj_dist(jetA,jetB); 00759 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00760 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00761 } 00762 } 00763 // then do it for RH tiles 00764 for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) { 00765 for (jetA = tile->head; jetA != NULL; jetA = jetA->next) { 00766 for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) { 00767 double dist = _bj_dist(jetA,jetB); 00768 if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;} 00769 if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;} 00770 } 00771 } 00772 } 00773 // no need to do it for LH tiles, since they are implicitly done 00774 // when we set NN for both jetA and jetB on the RH tiles. 00775 } 00776 00777 00778 //// now create the diJ (where J is i's NN) table -- remember that 00779 //// we differ from standard normalisation here by a factor of R2 00780 //// (corrected for at the end). 00781 //struct diJ_plus_link { 00782 // double diJ; // the distance 00783 // TiledJet * jet; // the jet (i) for which we've found this distance 00784 // // (whose NN will the J). 00785 //}; 00786 //diJ_plus_link * diJ = new diJ_plus_link[n]; 00787 //jetA = head; 00788 //for (int i = 0; i < n; i++) { 00789 // diJ[i].diJ = _bj_diJ(jetA); // kt distance * R^2 00790 // diJ[i].jet = jetA; // our compact diJ table will not be in 00791 // jetA->diJ_posn = i; // one-to-one corresp. with non-compact jets, 00792 // // so set up bi-directional correspondence here. 00793 // jetA++; // have jetA follow i 00794 //} 00795 00796 vector<double> diJs(n); 00797 for (int i = 0; i < n; i++) { 00798 diJs[i] = _bj_diJ(&briefjets[i]); 00799 briefjets[i].label_minheap_update_done(); 00800 } 00801 MinHeap minheap(diJs); 00802 // have a stack telling us which jets we'll have to update on the heap 00803 vector<TiledJet *> jets_for_minheap; 00804 jets_for_minheap.reserve(n); 00805 00806 // now run the recombination loop 00807 int history_location = n-1; 00808 while (n > 0) { 00809 00810 double diJ_min = minheap.minval() *_invR2; 00811 jetA = head + minheap.minloc(); 00812 00813 // do the recombination between A and B 00814 history_location++; 00815 jetB = jetA->NN; 00816 00817 if (jetB != NULL) { 00818 // jet-jet recombination 00819 // If necessary relabel A & B to ensure jetB < jetA, that way if 00820 // the larger of them == newtail then that ends up being jetA and 00821 // the new jet that is added as jetB is inserted in a position that 00822 // has a future! 00823 if (jetA < jetB) {std::swap(jetA,jetB);} 00824 00825 int nn; // new jet index 00826 _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn); 00827 00828 // what was jetB will now become the new jet 00829 _bj_remove_from_tiles(jetA); 00830 oldB = * jetB; // take a copy because we will need it... 00831 _bj_remove_from_tiles(jetB); 00832 _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn] 00833 // (also registers the jet in the tiling) 00834 } else { 00835 // jet-beam recombination 00836 // get the hist_index 00837 _do_iB_recombination_step(jetA->_jets_index, diJ_min); 00838 _bj_remove_from_tiles(jetA); 00839 } 00840 00841 // remove the minheap entry for jetA 00842 minheap.remove(jetA-head); 00843 00844 // first establish the set of tiles over which we are going to 00845 // have to run searches for updated and new nearest-neighbours -- 00846 // basically a combination of vicinity of the tiles of the two old 00847 // and one new jet. 00848 int n_near_tiles = 0; 00849 _add_untagged_neighbours_to_tile_union(jetA->tile_index, 00850 tile_union, n_near_tiles); 00851 if (jetB != NULL) { 00852 if (jetB->tile_index != jetA->tile_index) { 00853 _add_untagged_neighbours_to_tile_union(jetB->tile_index, 00854 tile_union,n_near_tiles); 00855 } 00856 if (oldB.tile_index != jetA->tile_index && 00857 oldB.tile_index != jetB->tile_index) { 00858 _add_untagged_neighbours_to_tile_union(oldB.tile_index, 00859 tile_union,n_near_tiles); 00860 } 00861 // indicate that we'll have to update jetB in the minheap 00862 jetB->label_minheap_update_needed(); 00863 jets_for_minheap.push_back(jetB); 00864 } 00865 00866 00867 // Initialise jetB's NN distance as well as updating it for 00868 // other particles. 00869 // Run over all tiles in our union 00870 for (int itile = 0; itile < n_near_tiles; itile++) { 00871 Tile * tile = &_tiles[tile_union[itile]]; 00872 tile->tagged = false; // reset tag, since we're done with unions 00873 // run over all jets in the current tile 00874 for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) { 00875 // see if jetI had jetA or jetB as a NN -- if so recalculate the NN 00876 if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) { 00877 jetI->NN_dist = _R2; 00878 jetI->NN = NULL; 00879 // label jetI as needing heap action... 00880 if (!jetI->minheap_update_needed()) { 00881 jetI->label_minheap_update_needed(); 00882 jets_for_minheap.push_back(jetI);} 00883 // now go over tiles that are neighbours of I (include own tile) 00884 for (Tile ** near_tile = tile->begin_tiles; 00885 near_tile != tile->end_tiles; near_tile++) { 00886 // and then over the contents of that tile 00887 for (TiledJet * jetJ = (*near_tile)->head; 00888 jetJ != NULL; jetJ = jetJ->next) { 00889 double dist = _bj_dist(jetI,jetJ); 00890 if (dist < jetI->NN_dist && jetJ != jetI) { 00891 jetI->NN_dist = dist; jetI->NN = jetJ; 00892 } 00893 } 00894 } 00895 } 00896 // check whether new jetB is closer than jetI's current NN and 00897 // if jetI is closer than jetB's current (evolving) nearest 00898 // neighbour. Where relevant update things 00899 if (jetB != NULL) { 00900 double dist = _bj_dist(jetI,jetB); 00901 if (dist < jetI->NN_dist) { 00902 if (jetI != jetB) { 00903 jetI->NN_dist = dist; 00904 jetI->NN = jetB; 00905 // label jetI as needing heap action... 00906 if (!jetI->minheap_update_needed()) { 00907 jetI->label_minheap_update_needed(); 00908 jets_for_minheap.push_back(jetI);} 00909 } 00910 } 00911 if (dist < jetB->NN_dist) { 00912 if (jetI != jetB) { 00913 jetB->NN_dist = dist; 00914 jetB->NN = jetI;} 00915 } 00916 } 00917 } 00918 } 00919 00920 // deal with jets whose minheap entry needs updating 00921 while (jets_for_minheap.size() > 0) { 00922 TiledJet * jetI = jets_for_minheap.back(); 00923 jets_for_minheap.pop_back(); 00924 minheap.update(jetI-head, _bj_diJ(jetI)); 00925 jetI->label_minheap_update_done(); 00926 } 00927 n--; 00928 } 00929 00930 // final cleaning up; 00931 delete[] briefjets; 00932 } 00933 00934 00935 FASTJET_END_NAMESPACE 00936