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