fastjet 2.4.5
ClusterSequence_TiledN2.cc
Go to the documentation of this file.
00001 //STARTHEADER
00002 // $Id: ClusterSequence_TiledN2.cc 3157 2013-07-11 16:02:51Z soyez $
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) {std::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) {std::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) {std::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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines