FastJet 3.0beta1
ClusterSequence_TiledN2.cc
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends