Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

ClusterSequence.cc

Go to the documentation of this file.
00001 //STARTHEADER
00002 // $Id: ClusterSequence.cc 458 2007-02-14 21:38:23Z 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 #include "fastjet/Error.hh"
00032 #include "fastjet/PseudoJet.hh"
00033 #include "fastjet/ClusterSequence.hh"
00034 #include "fastjet/version.hh" // stores the current version number
00035 #include<iostream>
00036 #include<sstream>
00037 #include<cmath>
00038 #include<cstdlib>
00039 #include<cassert>
00040 #include<string>
00041 
00042 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00043 
00044 using namespace std;
00045 
00047 JetFinder ClusterSequence::_default_jet_finder = kt_algorithm;
00048 //
00049 
00050 
00051 //----------------------------------------------------------------------
00052 void ClusterSequence::_initialise_and_run (
00053                                   const double & R,
00054                                   const Strategy & strategy,
00055                                   const bool & writeout_combinations) {
00056 
00057   JetDefinition jet_def(_default_jet_finder, R, strategy);
00058   _initialise_and_run(jet_def, writeout_combinations);
00059 }
00060 
00061 
00062 //----------------------------------------------------------------------
00063 void ClusterSequence::_initialise_and_run (
00064                                   const JetDefinition & jet_def,
00065                                   const bool & writeout_combinations) {
00066 
00067   // transfer all relevant info into internal variables
00068   _decant_options(jet_def, writeout_combinations);
00069 
00070   // set up the history entries for the initial particles (those
00071   // currently in _jets)
00072   _fill_initial_history();
00073 
00074   // run the plugin if that's what's decreed
00075   if (_jet_finder == plugin_algorithm) {
00076     _plugin_activated = true;
00077     _jet_def.plugin()->run_clustering( (*this) );
00078     _plugin_activated = false;
00079     return;
00080   }
00081 
00082 
00083   // automatically redefine the strategy according to N if that is
00084   // what the user requested -- transition points (and especially
00085   // their R-dependence) are based on empirical observations for a
00086   // R=0.4, 0.7 and 1.0, running on toth (3.4GHz, Pentium IV D [dual
00087   // core] with 2MB of cache).
00088   if (_strategy == Best) {
00089     int N = _jets.size();
00090     if (N > 6200/pow(_Rparam,2.0) 
00091         && jet_def.jet_finder() == cambridge_algorithm) {
00092       _strategy = NlnNCam;}
00093     else
00094 #ifndef DROP_CGAL
00095     if (N > 16000/pow(_Rparam,1.15)) {
00096       _strategy = NlnN; }   
00097     else                    
00098 #endif  // DROP_CGAL
00099       if (N > 450) {
00100       _strategy = N2MinHeapTiled;
00101     }
00102     else if (N > 55*max(0.5,min(1.0,_Rparam))) {// empirical scaling with R
00103       _strategy = N2Tiled;
00104     } else {
00105       _strategy = N2Plain;
00106     }
00107   }
00108 
00109 
00110   // run the code containing the selected strategy
00111   if (_strategy == NlnN || _strategy == NlnN3pi 
00112       || _strategy == NlnN4pi ) {
00113     this->_delaunay_cluster();
00114   } else if (_strategy ==  N3Dumb ) {
00115     this->_really_dumb_cluster();
00116   } else if (_strategy == N2Tiled) {
00117     this->_faster_tiled_N2_cluster();
00118   } else if (_strategy == N2PoorTiled) {
00119     this->_tiled_N2_cluster();
00120   } else if (_strategy == N2Plain) {
00121     this->_simple_N2_cluster();
00122   } else if (_strategy == N2MinHeapTiled) {
00123     this->_minheap_faster_tiled_N2_cluster();
00124   } else if (_strategy == NlnNCam4pi) {
00125     this->_CP2DChan_cluster();
00126   } else if (_strategy == NlnNCam2pi2R) {
00127     this->_CP2DChan_cluster_2pi2R();
00128   } else if (_strategy == NlnNCam) {
00129     this->_CP2DChan_cluster_2piMultD();
00130   } else {
00131     ostringstream err;
00132     err << "Unrecognised value for strategy: "<<_strategy;
00133     throw Error(err.str());
00134     //assert(false);
00135   }
00136 }
00137 
00138 
00139 // these needs to be defined outside the class definition.
00140 bool ClusterSequence::_first_time = true;
00141 int ClusterSequence::_n_exclusive_warnings = 0;
00142 
00143 //----------------------------------------------------------------------
00144 // prints a banner on the first call
00145 void ClusterSequence::_print_banner() {
00146 
00147   if (!_first_time) {return;}
00148   _first_time = false;
00149   
00150   
00151   //Symp. Discr. Alg, p.472 (2002) and  CGAL (http://www.cgal.org);
00152 
00153   cout << "#------------------------------------------------------------------------\n";
00154   cout << "#                      FastJet release " << fastjet_version << endl;
00155   cout << "#              Written by Matteo Cacciari and Gavin Salam               \n"; 
00156   cout << "#              http://www.lpthe.jussieu.fr/~salam/fastjet               \n"; 
00157   cout << "#                                                                       \n";
00158   cout << "# Longitudinally invariant Kt, and inclusive Cambridge/Aachen clustering\n";
00159   cout << "# using fast geometric algorithms, with optional external jet-finder    \n";
00160   cout << "# plugins. Please cite hep-ph/0512210 if you use this code.             \n";
00161   cout << "#                                                                       \n";
00162   cout << "# This package uses T.Chan's closest pair algorithm, Proc.13th ACM-SIAM \n";
00163   cout << "# Symp. Discr. Alg, p.472 (2002)";
00164 #ifndef DROP_CGAL
00165   cout << " as well as CGAL: http://www.cgal.org/";
00166 #endif  // DROP_CGAL
00167   cout << ".\n";
00168   cout << "#-----------------------------------------------------------------------\n";
00169 }
00170 
00171 //----------------------------------------------------------------------
00172 // transfer all relevant info into internal variables
00173 void ClusterSequence::_decant_options(const JetDefinition & jet_def,
00174                                       const bool & writeout_combinations) {
00175 
00176   // let the user know what's going on
00177   _print_banner();
00178 
00179   // make a local copy of the jet definition (for future use?)
00180   _jet_def = jet_def;
00181   
00182   _writeout_combinations = writeout_combinations;
00183   _jet_finder = jet_def.jet_finder();
00184   _Rparam = jet_def.R();  _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
00185   _strategy = jet_def.strategy();
00186 
00187   // disallow interference from the plugin
00188   _plugin_activated = false;
00189   
00190 }
00191 
00192 
00193 //----------------------------------------------------------------------
00194 // initialise the history in a standard way
00195 void ClusterSequence::_fill_initial_history () {
00196 
00197   if (_jets.size() == 0) {throw Error("Cannot run jet-finder on empty event");}
00198 
00199   // reserve sufficient space for everything
00200   _jets.reserve(_jets.size()*2);
00201   _history.reserve(_jets.size()*2);
00202 
00203   for (int i = 0; i < static_cast<int>(_jets.size()) ; i++) {
00204     history_element element;
00205     element.parent1 = InexistentParent;
00206     element.parent2 = InexistentParent;
00207     element.child   = Invalid;
00208     element.jetp_index = i;
00209     element.dij     = 0.0;
00210     element.max_dij_so_far = 0.0;
00211 
00212     _history.push_back(element);
00213     
00214     // do any momentum preprocessing needed by the recombination scheme
00215     _jet_def.recombiner()->preprocess(_jets[i]);
00216 
00217     // get cross-referencing right from PseudoJets
00218     _jets[i].set_cluster_hist_index(i);
00219   }
00220   _initial_n = _jets.size();
00221 }
00222 
00223 
00224 //----------------------------------------------------------------------
00225 // Return the component corresponding to the specified index.
00226 // taken from CLHEP
00227 string ClusterSequence::strategy_string ()  const {
00228   string strategy;
00229   switch(_strategy) {
00230   case NlnN:
00231     strategy = "NlnN"; break;
00232   case NlnN3pi:
00233     strategy = "NlnN3pi"; break;
00234   case NlnN4pi:
00235     strategy = "NlnN4pi"; break;
00236   case N2Plain:
00237     strategy = "N2Plain"; break;
00238   case N2Tiled:
00239     strategy = "N2Tiled"; break;
00240   case N2MinHeapTiled:
00241     strategy = "N2MinHeapTiled"; break;
00242   case N2PoorTiled:
00243     strategy = "N2PoorTiled"; break;
00244   case N3Dumb:
00245     strategy = "N3Dumb"; break;
00246   case NlnNCam4pi:
00247     strategy = "NlnNCam4pi"; break;
00248   case NlnNCam2pi2R:
00249     strategy = "NlnNCam2pi2R"; break;
00250   case NlnNCam:
00251     strategy = "NlnNCam"; break; // 2piMultD
00252   case plugin_strategy:
00253     strategy = "plugin strategy"; break;
00254   default:
00255     strategy = "Unrecognized";
00256   }
00257   return strategy;
00258 }  
00259 
00260 
00261 //----------------------------------------------------------------------
00262 // record an ij recombination and reset the _jets[newjet_k] momentum and
00263 // user index to be those of newjet
00264 void ClusterSequence::plugin_record_ij_recombination(
00265            int jet_i, int jet_j, double dij, 
00266            const PseudoJet & newjet, int & newjet_k) {
00267 
00268   plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
00269 
00270   // now transfer newjet into place
00271   int tmp_index = _jets[newjet_k].cluster_hist_index();
00272   _jets[newjet_k] = newjet;
00273   _jets[newjet_k].set_cluster_hist_index(tmp_index);
00274 }
00275 
00276 
00277 //----------------------------------------------------------------------
00278 // return all inclusive jets with pt > ptmin
00279 vector<PseudoJet> ClusterSequence::inclusive_jets (const double & ptmin) const{
00280   double dcut = ptmin*ptmin;
00281   int i = _history.size() - 1; // last jet
00282   vector<PseudoJet> jets;
00283   if (_jet_finder == kt_algorithm) {
00284     while (i >= 0) {
00285       // with our specific definition of dij and diB (i.e. R appears only in 
00286       // dij), then dij==diB is the same as the jet.perp2() and we can exploit
00287       // this in selecting the jets...
00288       if (_history[i].max_dij_so_far < dcut) {break;}
00289       if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
00290         // for beam jets
00291         int parent1 = _history[i].parent1;
00292         jets.push_back(_jets[_history[parent1].jetp_index]);}
00293       i--;
00294     }
00295   } else if (_jet_finder == cambridge_algorithm) {
00296     while (i >= 0) {
00297       // inclusive jets are all at end of clustering sequence in the
00298       // Cambridge algorithm -- so if we find a non-exclusive jet, then
00299       // we can exit
00300       if (_history[i].parent2 != BeamJet) {break;}
00301       int parent1 = _history[i].parent1;
00302       const PseudoJet & jet = _jets[_history[parent1].jetp_index];
00303       if (jet.perp2() >= dcut) {jets.push_back(jet);}
00304       i--;
00305     }
00306   } else if (_jet_finder == plugin_algorithm) {
00307     // for inclusive jets with a plugin algorith, we make no
00308     // assumptions about anything (relation of dij to momenta,
00309     // ordering of the dij, etc.)
00310     while (i >= 0) {
00311       if (_history[i].parent2 == BeamJet) {
00312         int parent1 = _history[i].parent1;
00313         const PseudoJet & jet = _jets[_history[parent1].jetp_index];
00314         if (jet.perp2() >= dcut) {jets.push_back(jet);}
00315       }
00316       i--;
00317     }
00318   } else {throw Error("Unrecognized jet algorithm");}
00319   return jets;
00320 }
00321 
00322 
00323 //----------------------------------------------------------------------
00324 // return the number of exclusive jets that would have been obtained
00325 // running the algorithm in exclusive mode with the given dcut
00326 int ClusterSequence::n_exclusive_jets (const double & dcut) const {
00327 
00328   // first locate the point where clustering would have stopped (i.e. the
00329   // first time max_dij_so_far > dcut)
00330   int i = _history.size() - 1; // last jet
00331   while (i >= 0) {
00332     if (_history[i].max_dij_so_far <= dcut) {break;}
00333     i--;
00334   }
00335   int stop_point = i + 1;
00336   // relation between stop_point, njets assumes one extra jet disappears
00337   // at each clustering.
00338   int njets = 2*_initial_n - stop_point;
00339   return njets;
00340 }
00341 
00342 //----------------------------------------------------------------------
00343 // return all exclusive jets that would have been obtained running
00344 // the algorithm in exclusive mode with the given dcut
00345 vector<PseudoJet> ClusterSequence::exclusive_jets (const double & dcut) const {
00346   int njets = n_exclusive_jets(dcut);
00347   return exclusive_jets(njets);
00348 }
00349 
00350 
00351 //----------------------------------------------------------------------
00352 // return the jets obtained by clustering the event to n jets.
00353 vector<PseudoJet> ClusterSequence::exclusive_jets (const int & njets) const {
00354 
00355   // make sure the user does not ask for more than jets than there
00356   // were particles in the first place.
00357   assert (njets <= _initial_n);
00358 
00359   // provide a warning when extracting exclusive jets 
00360   if (_jet_def.jet_finder() != kt_algorithm && _n_exclusive_warnings < 5) {
00361     _n_exclusive_warnings++;
00362     cerr << "FastJet WARNING: dcut and exclusive jets for jet-finders other than kt should be interpreted with care." << endl;
00363   }
00364 
00365 
00366   // calculate the point where we have to stop the clustering.
00367   // relation between stop_point, njets assumes one extra jet disappears
00368   // at each clustering.
00369   int stop_point = 2*_initial_n - njets;
00370 
00371   // some sanity checking to make sure that e+e- does not give us
00372   // surprises (should we ever implement e+e-)...
00373   if (2*_initial_n != static_cast<int>(_history.size())) {
00374     ostringstream err;
00375     err << "2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
00376     throw Error(err.str());
00377     //assert(false);
00378   }
00379 
00380   // now go forwards and reconstitute the jets that we have --
00381   // basically for any history element, see if the parent jets to
00382   // which it refers were created before the stopping point -- if they
00383   // were then add them to the list, otherwise they are subsequent
00384   // recombinations of the jets that we are looking for.
00385   vector<PseudoJet> jets;
00386   for (unsigned int i = stop_point; i < _history.size(); i++) {
00387     int parent1 = _history[i].parent1;
00388     if (parent1 < stop_point) {
00389       jets.push_back(_jets[_history[parent1].jetp_index]);
00390     }
00391     int parent2 = _history[i].parent2;
00392     if (parent2 < stop_point && parent2 > 0) {
00393       jets.push_back(_jets[_history[parent2].jetp_index]);
00394     }
00395     
00396   }
00397 
00398   // sanity check...
00399   if (static_cast<int>(jets.size()) != njets) {
00400     ostringstream err;
00401     err << "ClusterSequence::exclusive_jets: size of returned vector ("
00402          <<jets.size()<<") does not coincide with requested number of jets ("
00403          <<njets<<")";
00404     throw Error(err.str());
00405   }
00406 
00407   return jets;
00408 }
00409 
00410 //----------------------------------------------------------------------
00413 double ClusterSequence::exclusive_dmerge (const int & njets) const {
00414   assert(njets > 0);
00415   if (njets >= _initial_n) {return 0.0;}
00416   return _history[2*_initial_n-njets-1].dij;
00417 }
00418 
00419 
00420 //----------------------------------------------------------------------
00425 double ClusterSequence::exclusive_dmerge_max (const int & njets) const {
00426   assert(njets > 0);
00427   if (njets >= _initial_n) {return 0.0;}
00428   return _history[2*_initial_n-njets-1].max_dij_so_far;
00429 }
00430 
00431 
00432 //----------------------------------------------------------------------
00433 // return a vector of the particles that make up a jet
00434 vector<PseudoJet> ClusterSequence::constituents (const PseudoJet & jet) const {
00435   vector<PseudoJet> subjets;
00436   add_constituents(jet, subjets);
00437   return subjets;
00438 }
00439 
00440 
00441 //----------------------------------------------------------------------
00446 vector<int> ClusterSequence::particle_jet_indices(
00447                         const vector<PseudoJet> & jets) const {
00448 
00449   vector<int> indices(n_particles());
00450 
00451   // first label all particles as not belonging to any jets
00452   for (unsigned ipart = 0; ipart < n_particles(); ipart++) 
00453     indices[ipart] = -1;
00454 
00455   // then for each of the jets relabel its consituents as belonging to
00456   // that jet
00457   for (unsigned ijet = 0; ijet < jets.size(); ijet++) {
00458 
00459     vector<PseudoJet> jet_constituents(constituents(jets[ijet]));
00460 
00461     for (unsigned ip = 0; ip < jet_constituents.size(); ip++) {
00462       // a safe (if slightly redundant) way of getting the particle
00463       // index (for initial particles it is actually safe to assume
00464       // ipart=iclust).
00465       unsigned iclust = jet_constituents[ip].cluster_hist_index();
00466       unsigned ipart = history()[iclust].jetp_index;
00467       indices[ipart] = ijet;
00468     }
00469   }
00470 
00471   return indices;
00472 }
00473 
00474 
00475 //----------------------------------------------------------------------
00476 // recursive routine that adds on constituents of jet to the subjet_vector
00477 void ClusterSequence::add_constituents (
00478            const PseudoJet & jet, vector<PseudoJet> & subjet_vector) const {
00479   // find out position in cluster history
00480   int i = jet.cluster_hist_index();
00481   int parent1 = _history[i].parent1;
00482   int parent2 = _history[i].parent2;
00483 
00484   if (parent1 == InexistentParent) {
00485     // It is an original particle (labelled by its parent having value
00486     // InexistentParent), therefore add it on to the subjet vector
00487     subjet_vector.push_back(jet);
00488     return;
00489   } 
00490 
00491   // add parent 1
00492   add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
00493 
00494   // see if parent2 is a real jet; if it is then add its constituents
00495   if (parent2 != BeamJet) {
00496     add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
00497   }
00498 }
00499 
00500 
00501 
00502 //----------------------------------------------------------------------
00503 // initialise the history in a standard way
00504 void ClusterSequence::_add_step_to_history (
00505                const int & step_number, const int & parent1, 
00506                const int & parent2, const int & jetp_index,
00507                const double & dij) {
00508 
00509   history_element element;
00510   element.parent1 = parent1;
00511   element.parent2 = parent2;
00512   element.jetp_index = jetp_index;
00513   element.child = Invalid;
00514   element.dij   = dij;
00515   element.max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
00516   _history.push_back(element);
00517 
00518   int local_step = _history.size()-1;
00519   assert(local_step == step_number);
00520 
00521   assert(parent1 >= 0);
00522   _history[parent1].child = local_step;
00523   if (parent2 >= 0) {_history[parent2].child = local_step;}
00524 
00525   // get cross-referencing right from PseudoJets
00526   if (jetp_index != Invalid) {
00527     assert(jetp_index >= 0);
00528     //cout << _jets.size() <<" "<<jetp_index<<"\n";
00529     _jets[jetp_index].set_cluster_hist_index(local_step);
00530   }
00531 
00532   if (_writeout_combinations) {
00533     cout << local_step << ": " 
00534          << parent1 << " with " << parent2
00535          << "; y = "<< dij<<endl;
00536   }
00537 
00538 }
00539 
00540 
00541 
00542 
00543 //======================================================================
00544 // Return an order in which to read the history such that _history[order[i]] 
00545 // will always correspond to the same set of consituent particles if 
00546 // two branching histories are equivalent in terms of the particles
00547 // contained in any given pseudojet.
00548 vector<int> ClusterSequence::unique_history_order() const {
00549 
00550   // first construct an array that will tell us the lowest constituent
00551   // of a given jet -- this will always be one of the original
00552   // particles, whose order is well defined and so will help us to
00553   // follow the tree in a unique manner.
00554   valarray<int> lowest_constituent(_history.size());
00555   int hist_n = _history.size();
00556   lowest_constituent = hist_n; // give it a large number
00557   for (int i = 0; i < hist_n; i++) {
00558     // sets things up for the initial partons
00559     lowest_constituent[i] = min(lowest_constituent[i],i); 
00560     // propagates them through to the children of this parton
00561     if (_history[i].child > 0) lowest_constituent[_history[i].child] 
00562       = min(lowest_constituent[_history[i].child],lowest_constituent[i]);
00563   }
00564 
00565   // establish an array for what we have and have not extracted so far
00566   valarray<bool> extracted(_history.size()); extracted = false;
00567   vector<int> unique_tree;
00568   unique_tree.reserve(_history.size());
00569 
00570   // now work our way through the tree
00571   for (unsigned i = 0; i < n_particles(); i++) {
00572     if (!extracted[i]) {
00573       unique_tree.push_back(i);
00574       extracted[i] = true;
00575       _extract_tree_children(i, extracted, lowest_constituent, unique_tree);
00576     }
00577   }
00578 
00579   return unique_tree;
00580 }
00581 
00582 //======================================================================
00583 // helper for unique_history_order
00584 void ClusterSequence::_extract_tree_children(
00585        int position, 
00586        valarray<bool> & extracted, 
00587        const valarray<int> & lowest_constituent,
00588        vector<int> & unique_tree) const {
00589   if (!extracted[position]) {
00590     // that means we may have unidentified parents around, so go and
00591     // collect them (extracted[position]) will then be made true)
00592     _extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
00593   } 
00594   
00595   // now look after the children...
00596   int child = _history[position].child;
00597   if (child  >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
00598 }
00599 
00600 
00601 //======================================================================
00602 // return the list of unclustered particles
00603 vector<PseudoJet> ClusterSequence::unclustered_particles() const {
00604   vector<PseudoJet> unclustered;
00605   for (unsigned i = 0; i < n_particles() ; i++) {
00606     if (_history[i].child == Invalid) 
00607       unclustered.push_back(_jets[_history[i].jetp_index]);
00608   }
00609   return unclustered;
00610 }
00611 
00612 
00613 
00614 //======================================================================
00615 // helper for unique_history_order
00616 void ClusterSequence::_extract_tree_parents(
00617        int position, 
00618        valarray<bool> & extracted, 
00619        const valarray<int> & lowest_constituent,
00620        vector<int> & unique_tree) const {
00621 
00622   if (!extracted[position]) {
00623     int parent1 = _history[position].parent1;
00624     int parent2 = _history[position].parent2;
00625     // where relevant order parents so that we will first treat the
00626     // one containing the smaller "lowest_constituent"
00627     if (parent1 >= 0 && parent2 >= 0) {
00628       if (lowest_constituent[parent1] > lowest_constituent[parent2]) 
00629         swap(parent1, parent2);
00630     }
00631     // then actually run through the parents to extract the constituents...
00632     if (parent1 >= 0 && !extracted[parent1]) 
00633       _extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
00634     if (parent2 >= 0 && !extracted[parent2]) 
00635       _extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
00636     // finally declare this position to be accounted for and push it
00637     // onto our list.
00638     unique_tree.push_back(position);
00639     extracted[position] = true;
00640   }
00641 }
00642 
00643 
00644 //======================================================================
00648 void ClusterSequence::_do_ij_recombination_step(
00649                                const int & jet_i, const int & jet_j, 
00650                                const double & dij, 
00651                                int & newjet_k) {
00652 
00653   // create the new jet by recombining the first two
00654   PseudoJet newjet;
00655   _jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
00656   _jets.push_back(newjet);
00657   // original version...
00658   //_jets.push_back(_jets[jet_i] + _jets[jet_j]);
00659 
00660   // get its index
00661   newjet_k = _jets.size()-1;
00662 
00663   // get history index
00664   int newstep_k = _history.size();
00665   // and provide jet with the info
00666   _jets[newjet_k].set_cluster_hist_index(newstep_k);
00667 
00668   // finally sort out the history 
00669   int hist_i = _jets[jet_i].cluster_hist_index();
00670   int hist_j = _jets[jet_j].cluster_hist_index();
00671 
00672   _add_step_to_history(newstep_k, min(hist_i, hist_j), max(hist_i,hist_j),
00673                        newjet_k, dij);
00674 
00675 }
00676 
00677 
00678 //======================================================================
00681 void ClusterSequence::_do_iB_recombination_step(
00682                                   const int & jet_i, const double & diB) {
00683   // get history index
00684   int newstep_k = _history.size();
00685 
00686   // recombine the jet with the beam
00687   _add_step_to_history(newstep_k,_jets[jet_i].cluster_hist_index(),BeamJet,
00688                        Invalid, diB);
00689 
00690 }
00691 
00692 FASTJET_END_NAMESPACE
00693 

Generated on Mon Apr 2 20:57:48 2007 for fastjet by  doxygen 1.4.2