fastjet 2.4.5
ClusterSequence.cc
Go to the documentation of this file.
00001 //STARTHEADER
00002 // $Id: ClusterSequence.cc 3162 2013-07-17 14:40:02Z salam $
00003 //
00004 // Copyright (c) 2005-2009, Matteo Cacciari, Gavin Salam and Gregory Soyez
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<fstream>
00038 #include<cmath>
00039 #include<cstdlib>
00040 #include<cassert>
00041 #include<string>
00042 #include<set>
00043 
00044 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00045 
00046 using namespace std;
00047 
00049 JetAlgorithm ClusterSequence::_default_jet_algorithm = kt_algorithm;
00050 //
00051 
00052 
00053 // destructor that does nothing
00054 ClusterSequence::~ClusterSequence () {}
00055 
00056 //----------------------------------------------------------------------
00057 void ClusterSequence::_initialise_and_run (
00058                                   const double & R,
00059                                   const Strategy & strategy,
00060                                   const bool & writeout_combinations) {
00061 
00062   JetDefinition jet_def(_default_jet_algorithm, R, strategy);
00063   _initialise_and_run(jet_def, writeout_combinations);
00064 }
00065 
00066 
00067 //----------------------------------------------------------------------
00068 void ClusterSequence::_initialise_and_run (
00069                                   const JetDefinition & jet_def,
00070                                   const bool & writeout_combinations) {
00071 
00072   // transfer all relevant info into internal variables
00073   _decant_options(jet_def, writeout_combinations);
00074 
00075   // set up the history entries for the initial particles (those
00076   // currently in _jets)
00077   _fill_initial_history();
00078 
00079   // don't run anything if the event is empty
00080   if (n_particles() == 0) return;
00081 
00082   // ----- deal with special cases: plugins & e+e- ------
00083   if (_jet_algorithm == plugin_algorithm) {
00084     // allows plugin_xyz() functions to modify cluster sequence
00085     _plugin_activated = true;
00086     // let the plugin do its work here
00087     _jet_def.plugin()->run_clustering( (*this) );
00088     _plugin_activated = false;
00089     return;
00090   } else if (_jet_algorithm == ee_kt_algorithm ||
00091              _jet_algorithm == ee_genkt_algorithm) {
00092     // ignore requested strategy
00093     _strategy = N2Plain;
00094     if (_jet_algorithm == ee_kt_algorithm) {
00095       // make sure that R is large enough so that "beam" recomb only
00096       // occurs when a single particle is left
00097       // Normally, this should be automatically set to 4 from JetDefinition
00098       assert(_Rparam > 2.0); 
00099       // this is used to renormalise the dij to get a "standard" form
00100       // and our convention in e+e- will be different from that
00101       // in long.inv case; NB: _invR2 name should be changed -> _renorm_dij?
00102       _invR2 = 1.0;
00103     } else {
00104       // as of 2009-01-09, choose R to be an angular distance, in
00105       // radians.  Since the algorithm uses 2(1-cos(theta)) as its
00106       // squared angular measure, make sure that the _R2 is defined
00107       // in a similar way.
00108       if (_Rparam > pi) {
00109         // choose a value that ensures that back-to-back particles will
00110         // always recombine 
00111         //_R2 = 4.0000000000001;
00112         _R2 = 2 * ( 3.0 + cos(_Rparam) );
00113       } else {
00114         _R2    = 2 * ( 1.0 - cos(_Rparam) );
00115       }
00116       _invR2 = 1.0/_R2;
00117     }
00118     //_simple_N2_cluster<EEBriefJet>();
00119     _simple_N2_cluster_EEBriefJet();
00120     return;
00121   }
00122 
00123 
00124   // automatically redefine the strategy according to N if that is
00125   // what the user requested -- transition points (and especially
00126   // their R-dependence) are based on empirical observations for a
00127   // R=0.4, 0.7 and 1.0, running on toth (3.4GHz, Pentium IV D [dual
00128   // core] with 2MB of cache).
00129   if (_strategy == Best) {
00130     int N = _jets.size();
00131     if (N > 6200/pow(_Rparam,2.0) 
00132         && jet_def.jet_algorithm() == cambridge_algorithm) {
00133       _strategy = NlnNCam;}
00134     else
00135 #ifndef DROP_CGAL
00136       if ((N > 16000/pow(_Rparam,1.15) && jet_def.jet_algorithm() != antikt_algorithm)
00137         || N > 35000/pow(_Rparam,1.15)) {
00138       _strategy = NlnN; }   
00139     else                    
00140 #endif  // DROP_CGAL
00141       if (N > 450) {
00142       _strategy = N2MinHeapTiled;
00143     }
00144     else if (N > 55*max(0.5,min(1.0,_Rparam))) {// empirical scaling with R
00145       _strategy = N2Tiled;
00146     } else {
00147       _strategy = N2Plain;
00148     }
00149   }
00150 
00151 
00152   // run the code containing the selected strategy
00153   if (_strategy == NlnN || _strategy == NlnN3pi 
00154       || _strategy == NlnN4pi ) {
00155     this->_delaunay_cluster();
00156   } else if (_strategy ==  N3Dumb ) {
00157     this->_really_dumb_cluster();
00158   } else if (_strategy == N2Tiled) {
00159     this->_faster_tiled_N2_cluster();
00160   } else if (_strategy == N2PoorTiled) {
00161     this->_tiled_N2_cluster();
00162   } else if (_strategy == N2Plain) {
00163     // BriefJet provides standard long.invariant kt alg.
00164     //this->_simple_N2_cluster<BriefJet>();
00165     this->_simple_N2_cluster_BriefJet();
00166   } else if (_strategy == N2MinHeapTiled) {
00167     this->_minheap_faster_tiled_N2_cluster();
00168   } else if (_strategy == NlnNCam4pi) {
00169     this->_CP2DChan_cluster();
00170   } else if (_strategy == NlnNCam2pi2R) {
00171     this->_CP2DChan_cluster_2pi2R();
00172   } else if (_strategy == NlnNCam) {
00173     this->_CP2DChan_cluster_2piMultD();
00174   } else {
00175     ostringstream err;
00176     err << "Unrecognised value for strategy: "<<_strategy;
00177     throw Error(err.str());
00178     //assert(false);
00179   }
00180 }
00181 
00182 
00183 // these needs to be defined outside the class definition.
00184 bool ClusterSequence::_first_time = true;
00185 int ClusterSequence::_n_exclusive_warnings = 0;
00186 
00187 
00188 //----------------------------------------------------------------------
00189 // the version string
00190 string fastjet_version_string() {
00191   return "FastJet version "+string(fastjet_version);
00192 }
00193 
00194 
00195 //----------------------------------------------------------------------
00196 // prints a banner on the first call
00197 void ClusterSequence::_print_banner() {
00198 
00199   if (!_first_time) {return;}
00200   _first_time = false;
00201   
00202   
00203   //Symp. Discr. Alg, p.472 (2002) and  CGAL (http://www.cgal.org);
00204 
00205   cout << "#--------------------------------------------------------------------------\n";
00206   cout << "#                         FastJet release " << fastjet_version << endl;
00207   cout << "#            Written by M. Cacciari, G.P. Salam and G. Soyez            \n"; 
00208   cout << "#                         http://www.fastjet.fr                         \n"; 
00209   cout << "#                                                                       \n";
00210   cout << "# Longitudinally invariant Kt, anti-Kt, and inclusive Cambridge/Aachen  \n";
00211   cout << "# clustering using fast geometric algorithms, with jet areas and optional\n";
00212   cout << "# external jet-finder plugins. If you use this code towards a scientific \n";
00213   cout << "# publication please cite EPJC72(2012)1896 [arXiv:1111.6097] and        \n";
00214   cout << "# optionally PLB641(2006)57 [hep-ph/0512210].                           \n";
00215   cout << "#                                                                       \n";
00216   cout << "# This package uses T.Chan's closest pair algorithm, Proc.13th ACM-SIAM \n";
00217   cout << "# Symp. Discr. Alg, p.472 (2002), S.Fortune's Voronoi algorithm and code" ;
00218 #ifndef DROP_CGAL
00219   cout << endl << "# and CGAL: http://www.cgal.org/";
00220 #endif  // DROP_CGAL
00221   cout << ".\n";
00222   cout << "#-------------------------------------------------------------------------\n";
00223   // make sure we really have the output done.
00224   cout.flush();
00225 }
00226 
00227 //----------------------------------------------------------------------
00228 // transfer all relevant info into internal variables
00229 void ClusterSequence::_decant_options(const JetDefinition & jet_def,
00230                                       const bool & writeout_combinations) {
00231 
00232   // let the user know what's going on
00233   _print_banner();
00234 
00235   // make a local copy of the jet definition (for future use?)
00236   _jet_def = jet_def;
00237   
00238   _writeout_combinations = writeout_combinations;
00239   _jet_algorithm = jet_def.jet_algorithm();
00240   _Rparam = jet_def.R();  _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
00241   _strategy = jet_def.strategy();
00242 
00243   // disallow interference from the plugin
00244   _plugin_activated = false;
00245   
00246 }
00247 
00248 
00249 //----------------------------------------------------------------------
00250 // initialise the history in a standard way
00251 void ClusterSequence::_fill_initial_history () {
00252 
00253   //if (_jets.size() == 0) {throw Error("Cannot run jet-finder on empty event");}
00254 
00255   // reserve sufficient space for everything
00256   _jets.reserve(_jets.size()*2);
00257   _history.reserve(_jets.size()*2);
00258 
00259   _Qtot = 0;
00260 
00261   for (int i = 0; i < static_cast<int>(_jets.size()) ; i++) {
00262     history_element element;
00263     element.parent1 = InexistentParent;
00264     element.parent2 = InexistentParent;
00265     element.child   = Invalid;
00266     element.jetp_index = i;
00267     element.dij     = 0.0;
00268     element.max_dij_so_far = 0.0;
00269 
00270     _history.push_back(element);
00271     
00272     // do any momentum preprocessing needed by the recombination scheme
00273     _jet_def.recombiner()->preprocess(_jets[i]);
00274 
00275     // get cross-referencing right from PseudoJets
00276     _jets[i].set_cluster_hist_index(i);
00277 
00278     // determine the total energy in the event
00279     _Qtot += _jets[i].E();
00280   }
00281   _initial_n = _jets.size();
00282 }
00283 
00284 
00285 //----------------------------------------------------------------------
00286 // Return the component corresponding to the specified index.
00287 // taken from CLHEP
00288 string ClusterSequence::strategy_string ()  const {
00289   string strategy;
00290   switch(_strategy) {
00291   case NlnN:
00292     strategy = "NlnN"; break;
00293   case NlnN3pi:
00294     strategy = "NlnN3pi"; break;
00295   case NlnN4pi:
00296     strategy = "NlnN4pi"; break;
00297   case N2Plain:
00298     strategy = "N2Plain"; break;
00299   case N2Tiled:
00300     strategy = "N2Tiled"; break;
00301   case N2MinHeapTiled:
00302     strategy = "N2MinHeapTiled"; break;
00303   case N2PoorTiled:
00304     strategy = "N2PoorTiled"; break;
00305   case N3Dumb:
00306     strategy = "N3Dumb"; break;
00307   case NlnNCam4pi:
00308     strategy = "NlnNCam4pi"; break;
00309   case NlnNCam2pi2R:
00310     strategy = "NlnNCam2pi2R"; break;
00311   case NlnNCam:
00312     strategy = "NlnNCam"; break; // 2piMultD
00313   case plugin_strategy:
00314     strategy = "plugin strategy"; break;
00315   default:
00316     strategy = "Unrecognized";
00317   }
00318   return strategy;
00319 }  
00320 
00321 
00322 double ClusterSequence::jet_scale_for_algorithm(
00323                                   const PseudoJet & jet) const {
00324   if (_jet_algorithm == kt_algorithm)             {return jet.kt2();}
00325   else if (_jet_algorithm == cambridge_algorithm) {return 1.0;}
00326   else if (_jet_algorithm == antikt_algorithm) {
00327     double kt2=jet.kt2();
00328     return kt2 > 1e-300 ? 1.0/kt2 : 1e300;
00329   } else if (_jet_algorithm == genkt_algorithm) {
00330     double kt2 = jet.kt2();
00331     double p   = jet_def().extra_param();
00332     if (p <= 0 && kt2 < 1e-300) kt2 = 1e-300; // dodgy safety check
00333     return pow(kt2, p);
00334   } else if (_jet_algorithm == cambridge_for_passive_algorithm) {
00335     double kt2 = jet.kt2();
00336     double lim = _jet_def.extra_param();
00337     if (kt2 < lim*lim && kt2 != 0.0) {
00338       return 1.0/kt2;
00339     } else {return 1.0;}
00340   } else {throw Error("Unrecognised jet algorithm");}
00341 }
00342 
00343 
00344 //----------------------------------------------------------------------
00348 void ClusterSequence::transfer_from_sequence(ClusterSequence & from_seq) {
00349 
00350   // the metadata
00351   _jet_def                 = from_seq._jet_def                ;
00352   _writeout_combinations   = from_seq._writeout_combinations  ;
00353   _initial_n               = from_seq._initial_n              ;
00354   _Rparam                  = from_seq._Rparam                 ;
00355   _R2                      = from_seq._R2                     ;
00356   _invR2                   = from_seq._invR2                  ;
00357   _strategy                = from_seq._strategy               ;
00358   _jet_algorithm           = from_seq._jet_algorithm          ;
00359   _plugin_activated        = from_seq._plugin_activated       ;
00360 
00361   // the data
00362   _jets     = from_seq._jets;
00363   _history  = from_seq._history;
00364   // the following transferse ownership of the extras from the from_seq
00365   _extras   = from_seq._extras;
00366 
00367 }
00368 
00369 //----------------------------------------------------------------------
00370 // record an ij recombination and reset the _jets[newjet_k] momentum and
00371 // user index to be those of newjet
00372 void ClusterSequence::plugin_record_ij_recombination(
00373            int jet_i, int jet_j, double dij, 
00374            const PseudoJet & newjet, int & newjet_k) {
00375 
00376   plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
00377 
00378   // now transfer newjet into place
00379   int tmp_index = _jets[newjet_k].cluster_hist_index();
00380   _jets[newjet_k] = newjet;
00381   _jets[newjet_k].set_cluster_hist_index(tmp_index);
00382 }
00383 
00384 
00385 //----------------------------------------------------------------------
00386 // return all inclusive jets with pt > ptmin
00387 vector<PseudoJet> ClusterSequence::inclusive_jets (const double & ptmin) const{
00388   double dcut = ptmin*ptmin;
00389   int i = _history.size() - 1; // last jet
00390   vector<PseudoJet> jets;
00391   if (_jet_algorithm == kt_algorithm) {
00392     while (i >= 0) {
00393       // with our specific definition of dij and diB (i.e. R appears only in 
00394       // dij), then dij==diB is the same as the jet.perp2() and we can exploit
00395       // this in selecting the jets...
00396       if (_history[i].max_dij_so_far < dcut) {break;}
00397       if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
00398         // for beam jets
00399         int parent1 = _history[i].parent1;
00400         jets.push_back(_jets[_history[parent1].jetp_index]);}
00401       i--;
00402     }
00403   } else if (_jet_algorithm == cambridge_algorithm) {
00404     while (i >= 0) {
00405       // inclusive jets are all at end of clustering sequence in the
00406       // Cambridge algorithm -- so if we find a non-exclusive jet, then
00407       // we can exit
00408       if (_history[i].parent2 != BeamJet) {break;}
00409       int parent1 = _history[i].parent1;
00410       const PseudoJet & jet = _jets[_history[parent1].jetp_index];
00411       if (jet.perp2() >= dcut) {jets.push_back(jet);}
00412       i--;
00413     }
00414   } else if (_jet_algorithm == plugin_algorithm 
00415              || _jet_algorithm == ee_kt_algorithm
00416              || _jet_algorithm == antikt_algorithm
00417              || _jet_algorithm == genkt_algorithm
00418              || _jet_algorithm == ee_genkt_algorithm
00419              || _jet_algorithm == cambridge_for_passive_algorithm) {
00420     // for inclusive jets with a plugin algorithm, we make no
00421     // assumptions about anything (relation of dij to momenta,
00422     // ordering of the dij, etc.)
00423     while (i >= 0) {
00424       if (_history[i].parent2 == BeamJet) {
00425         int parent1 = _history[i].parent1;
00426         const PseudoJet & jet = _jets[_history[parent1].jetp_index];
00427         if (jet.perp2() >= dcut) {jets.push_back(jet);}
00428       }
00429       i--;
00430     }
00431   } else {throw Error("cs::inclusive_jets(...): Unrecognized jet algorithm");}
00432   return jets;
00433 }
00434 
00435 
00436 //----------------------------------------------------------------------
00437 // return the number of exclusive jets that would have been obtained
00438 // running the algorithm in exclusive mode with the given dcut
00439 int ClusterSequence::n_exclusive_jets (const double & dcut) const {
00440 
00441   // first locate the point where clustering would have stopped (i.e. the
00442   // first time max_dij_so_far > dcut)
00443   int i = _history.size() - 1; // last jet
00444   while (i >= 0) {
00445     if (_history[i].max_dij_so_far <= dcut) {break;}
00446     i--;
00447   }
00448   int stop_point = i + 1;
00449   // relation between stop_point, njets assumes one extra jet disappears
00450   // at each clustering.
00451   int njets = 2*_initial_n - stop_point;
00452   return njets;
00453 }
00454 
00455 //----------------------------------------------------------------------
00456 // return all exclusive jets that would have been obtained running
00457 // the algorithm in exclusive mode with the given dcut
00458 vector<PseudoJet> ClusterSequence::exclusive_jets (const double & dcut) const {
00459   int njets = n_exclusive_jets(dcut);
00460   return exclusive_jets(njets);
00461 }
00462 
00463 
00464 //----------------------------------------------------------------------
00465 // return the jets obtained by clustering the event to n jets.
00466 vector<PseudoJet> ClusterSequence::exclusive_jets (const int & njets) const {
00467 
00468   // make sure the user does not ask for more than jets than there
00469   // were particles in the first place.
00470   assert (njets <= _initial_n);
00471 
00472   // provide a warning when extracting exclusive jets for algorithms 
00473   // that does not support it explicitly.
00474   // Native algorithm that support it are: kt, ee_kt, cambridge, 
00475   //   genkt and ee_genkt (both with p>=0)
00476   // For plugins, we check Plugin::exclusive_sequence_meaningful()
00477   if (( _jet_def.jet_algorithm() != kt_algorithm) &&
00478       ( _jet_def.jet_algorithm() != cambridge_algorithm) &&
00479       ( _jet_def.jet_algorithm() != ee_kt_algorithm) &&
00480       (((_jet_def.jet_algorithm() != genkt_algorithm) && 
00481         (_jet_def.jet_algorithm() != ee_genkt_algorithm)) || 
00482        (_jet_def.extra_param() <0)) &&
00483       ((_jet_def.jet_algorithm() != plugin_algorithm) ||
00484        (!_jet_def.plugin()->exclusive_sequence_meaningful())) &&
00485       (_n_exclusive_warnings < 5)) {
00486     _n_exclusive_warnings++;
00487     cerr << "FastJet WARNING: dcut and exclusive jets for jet-finders other than kt should be interpreted with care." << endl;
00488   }
00489 
00490 
00491   // calculate the point where we have to stop the clustering.
00492   // relation between stop_point, njets assumes one extra jet disappears
00493   // at each clustering.
00494   int stop_point = 2*_initial_n - njets;
00495 
00496   // some sanity checking to make sure that e+e- does not give us
00497   // surprises (should we ever implement e+e-)...
00498   if (2*_initial_n != static_cast<int>(_history.size())) {
00499     ostringstream err;
00500     err << "2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
00501     throw Error(err.str());
00502     //assert(false);
00503   }
00504 
00505   // now go forwards and reconstitute the jets that we have --
00506   // basically for any history element, see if the parent jets to
00507   // which it refers were created before the stopping point -- if they
00508   // were then add them to the list, otherwise they are subsequent
00509   // recombinations of the jets that we are looking for.
00510   vector<PseudoJet> jets;
00511   for (unsigned int i = stop_point; i < _history.size(); i++) {
00512     int parent1 = _history[i].parent1;
00513     if (parent1 < stop_point) {
00514       jets.push_back(_jets[_history[parent1].jetp_index]);
00515     }
00516     int parent2 = _history[i].parent2;
00517     if (parent2 < stop_point && parent2 > 0) {
00518       jets.push_back(_jets[_history[parent2].jetp_index]);
00519     }
00520     
00521   }
00522 
00523   // sanity check...
00524   if (static_cast<int>(jets.size()) != njets) {
00525     ostringstream err;
00526     err << "ClusterSequence::exclusive_jets: size of returned vector ("
00527          <<jets.size()<<") does not coincide with requested number of jets ("
00528          <<njets<<")";
00529     throw Error(err.str());
00530   }
00531 
00532   return jets;
00533 }
00534 
00535 //----------------------------------------------------------------------
00538 double ClusterSequence::exclusive_dmerge (const int & njets) const {
00539   assert(njets >= 0);
00540   if (njets >= _initial_n) {return 0.0;}
00541   return _history[2*_initial_n-njets-1].dij;
00542 }
00543 
00544 
00545 //----------------------------------------------------------------------
00550 double ClusterSequence::exclusive_dmerge_max (const int & njets) const {
00551   assert(njets >= 0);
00552   if (njets >= _initial_n) {return 0.0;}
00553   return _history[2*_initial_n-njets-1].max_dij_so_far;
00554 }
00555 
00556 
00557 //----------------------------------------------------------------------
00561 std::vector<PseudoJet> ClusterSequence::exclusive_subjets 
00562    (const PseudoJet & jet, const double & dcut) const {
00563 
00564   set<const history_element*> subhist;
00565 
00566   // get the set of history elements that correspond to subjets at
00567   // scale dcut
00568   get_subhist_set(subhist, jet, dcut, 0);
00569 
00570   // now transfer this into a sequence of jets
00571   vector<PseudoJet> subjets;
00572   subjets.reserve(subhist.size());
00573   for (set<const history_element*>::iterator elem = subhist.begin(); 
00574        elem != subhist.end(); elem++) {
00575     subjets.push_back(_jets[(*elem)->jetp_index]);
00576   }
00577   return subjets;
00578 }
00579 
00580 //----------------------------------------------------------------------
00584 int ClusterSequence::n_exclusive_subjets(const PseudoJet & jet, 
00585                         const double & dcut) const {
00586   set<const history_element*> subhist;
00587   // get the set of history elements that correspond to subjets at
00588   // scale dcut
00589   get_subhist_set(subhist, jet, dcut, 0);
00590   return subhist.size();
00591 }
00592 
00593 //----------------------------------------------------------------------
00597 std::vector<PseudoJet> ClusterSequence::exclusive_subjets 
00598    (const PseudoJet & jet, int n) const {
00599 
00600   set<const history_element*> subhist;
00601 
00602   // get the set of history elements that correspond to subjets at
00603   // scale dcut
00604   get_subhist_set(subhist, jet, -1.0, n);
00605 
00606   // now transfer this into a sequence of jets
00607   vector<PseudoJet> subjets;
00608   subjets.reserve(subhist.size());
00609   for (set<const history_element*>::iterator elem = subhist.begin(); 
00610        elem != subhist.end(); elem++) {
00611     subjets.push_back(_jets[(*elem)->jetp_index]);
00612   }
00613   return subjets;
00614 }
00615 
00616 
00617 //----------------------------------------------------------------------
00622 double ClusterSequence::exclusive_subdmerge(const PseudoJet & jet, int nsub) const {
00623   set<const history_element*> subhist;
00624 
00625   // get the set of history elements that correspond to subjets at
00626   // scale dcut
00627   get_subhist_set(subhist, jet, -1.0, nsub);
00628   
00629   set<const history_element*>::iterator highest = subhist.end();
00630   highest--;
00633   return (*highest)->dij;
00634 }
00635 
00636 
00637 //----------------------------------------------------------------------
00643 double ClusterSequence::exclusive_subdmerge_max(const PseudoJet & jet, int nsub) const {
00644 
00645   set<const history_element*> subhist;
00646 
00647   // get the set of history elements that correspond to subjets at
00648   // scale dcut
00649   get_subhist_set(subhist, jet, -1.0, nsub);
00650   
00651   set<const history_element*>::iterator highest = subhist.end();
00652   highest--;
00655   return (*highest)->max_dij_so_far;
00656 }
00657 
00658 
00659 
00660 //----------------------------------------------------------------------
00667 void ClusterSequence::get_subhist_set(set<const history_element*> & subhist,
00668                                      const  PseudoJet & jet, 
00669                                      double dcut, int maxjet) const {
00670   subhist.clear();
00671   subhist.insert(&(_history[jet.cluster_hist_index()]));
00672 
00673   // establish the set of jets that are relevant
00674   int njet = 1;
00675   while (true) {
00676     // first find out if we need to probe deeper into jet.
00677     // Get history element closest to end of sequence
00678     set<const history_element*>::iterator highest = subhist.end();
00679     assert (highest != subhist.begin()); 
00680     highest--;
00681     const history_element* elem = *highest;
00682     // make sure we haven't got too many jets
00683     if (njet == maxjet) break;
00684     // make sure it has parents
00685     if (elem->parent1 < 0)            break;
00686     // make sure that we still resolve it at scale dcut
00687     if (elem->max_dij_so_far <= dcut) break;
00688 
00689     // then do so: replace "highest" with its two parents
00690     subhist.erase(highest);
00691     subhist.insert(&(_history[elem->parent1]));
00692     subhist.insert(&(_history[elem->parent2]));
00693     njet++;
00694   }
00695 }
00696 
00697 //----------------------------------------------------------------------
00698 // work through the object's history until
00699 bool ClusterSequence::object_in_jet(const PseudoJet & object, 
00700                                     const PseudoJet & jet) const {
00701 
00702   // make sure the object conceivably belongs to this clustering
00703   // sequence
00704   assert(_potentially_valid(object) && _potentially_valid(jet));
00705 
00706   const PseudoJet * this_object = &object;
00707   const PseudoJet * childp;
00708   while(true) {
00709     if (this_object->cluster_hist_index() == jet.cluster_hist_index()) {
00710       return true;
00711     } else if (has_child(*this_object, childp)) {this_object = childp;}
00712     else {return false;}
00713   }
00714 }
00715 
00716 //----------------------------------------------------------------------
00722 bool ClusterSequence::has_parents(const PseudoJet & jet, PseudoJet & parent1, 
00723                               PseudoJet & parent2) const {
00724 
00725   const history_element & hist = _history[jet.cluster_hist_index()];
00726 
00727   // make sure we do not run into any unexpected situations --
00728   // i.e. both parents valid, or neither
00729   assert ((hist.parent1 >= 0 && hist.parent2 >= 0) || 
00730           (hist.parent1 < 0 && hist.parent2 < 0));
00731 
00732   if (hist.parent1 < 0) {
00733     parent1 = PseudoJet(0.0,0.0,0.0,0.0);
00734     parent2 = parent1;
00735     return false;
00736   } else {
00737     parent1 = _jets[_history[hist.parent1].jetp_index];
00738     parent2 = _jets[_history[hist.parent2].jetp_index];
00739     // order the parents in decreasing pt
00740     if (parent1.perp2() < parent2.perp2()) std::swap(parent1,parent2);
00741     return true;
00742   }
00743 }
00744 
00745 //----------------------------------------------------------------------
00748 bool ClusterSequence::has_child(const PseudoJet & jet, PseudoJet & child) const {
00749 
00750   //const history_element & hist = _history[jet.cluster_hist_index()];
00751   //
00752   //if (hist.child >= 0) {
00753   //  child = _jets[_history[hist.child].jetp_index];
00754   //  return true;
00755   //} else {
00756   //  child = PseudoJet(0.0,0.0,0.0,0.0);
00757   //  return false;
00758   //}
00759   const PseudoJet * childp;
00760   bool res = has_child(jet, childp);
00761   if (res) {
00762     child = *childp;
00763     return true;
00764   } else {
00765     child = PseudoJet(0.0,0.0,0.0,0.0);
00766     return false;
00767   }
00768 }
00769 
00770 bool ClusterSequence::has_child(const PseudoJet & jet, const PseudoJet * & childp) const {
00771 
00772   const history_element & hist = _history[jet.cluster_hist_index()];
00773 
00774   // check that this jet has a child and that the child corresponds to
00775   // a true jet [RETHINK-IF-CHANGE-NUMBERING: what is the right
00776   // behaviour if the child is the same jet but made inclusive...?]
00777   if (hist.child >= 0 && _history[hist.child].jetp_index >= 0) {
00778     childp = &(_jets[_history[hist.child].jetp_index]);
00779     return true;
00780   } else {
00781     childp = NULL;
00782     return false;
00783   }
00784 }
00785 
00786 
00787 //----------------------------------------------------------------------
00791 bool ClusterSequence::has_partner(const PseudoJet & jet, 
00792                               PseudoJet & partner) const {
00793 
00794   const history_element & hist = _history[jet.cluster_hist_index()];
00795 
00796   // make sure we have a child and that the child does not correspond
00797   // to a clustering with the beam (or some other invalid quantity)
00798   if (hist.child >= 0 && _history[hist.child].parent2 >= 0) {
00799     const history_element & child_hist = _history[hist.child];
00800     if (child_hist.parent1 == jet.cluster_hist_index()) {
00801       // partner will be child's parent2 -- for iB clustering
00802       // parent2 will not be valid
00803       partner = _jets[_history[child_hist.parent2].jetp_index];
00804     } else {
00805       // partner will be child's parent1
00806       partner = _jets[_history[child_hist.parent1].jetp_index];
00807     }
00808     return true;
00809   } else {
00810     partner = PseudoJet(0.0,0.0,0.0,0.0);
00811     return false;
00812   }
00813 }
00814 
00815 
00816 //----------------------------------------------------------------------
00817 // return a vector of the particles that make up a jet
00818 vector<PseudoJet> ClusterSequence::constituents (const PseudoJet & jet) const {
00819   vector<PseudoJet> subjets;
00820   add_constituents(jet, subjets);
00821   return subjets;
00822 }
00823 
00824 //----------------------------------------------------------------------
00833 void ClusterSequence::print_jets_for_root(const std::vector<PseudoJet> & jets, 
00834                                           ostream & ostr) const {
00835   for (unsigned i = 0; i < jets.size(); i++) {
00836     ostr << i  << " "
00837          << jets[i].px() << " "
00838          << jets[i].py() << " "
00839          << jets[i].pz() << " "
00840          << jets[i].E() << endl;
00841     vector<PseudoJet> cst = constituents(jets[i]);
00842     for (unsigned j = 0; j < cst.size() ; j++) {
00843       ostr << " " << j << " "
00844            << cst[j].rap() << " "
00845            << cst[j].phi() << " "
00846            << cst[j].perp() << endl;
00847     }
00848     ostr << "#END" << endl;
00849   }
00850 }
00851 
00852 void ClusterSequence::print_jets_for_root(const std::vector<PseudoJet> & jets, 
00853                                           const std::string & filename,
00854                                           const std::string & comment ) const {
00855   std::ofstream ostr(filename.c_str());
00856   if (comment != "") ostr << "# " << comment << endl;
00857   print_jets_for_root(jets, ostr);
00858 }
00859 
00860 
00861 // Not yet. Perhaps in a future release
00862 // //----------------------------------------------------------------------
00863 // // print out all inclusive jets with pt > ptmin
00864 // void ClusterSequence::print_jets (const double & ptmin) const{
00865 //     vector<PseudoJet> jets = sorted_by_pt(inclusive_jets(ptmin));
00866 // 
00867 //     for (size_t j = 0; j < jets.size(); j++) {
00868 //        printf("%5u %7.3f %7.3f %9.3f\n",
00869 //        j,jets[j].rap(),jets[j].phi(),jets[j].perp());
00870 //     }
00871 // }
00872 
00873 //----------------------------------------------------------------------
00878 vector<int> ClusterSequence::particle_jet_indices(
00879                         const vector<PseudoJet> & jets) const {
00880 
00881   vector<int> indices(n_particles());
00882 
00883   // first label all particles as not belonging to any jets
00884   for (unsigned ipart = 0; ipart < n_particles(); ipart++) 
00885     indices[ipart] = -1;
00886 
00887   // then for each of the jets relabel its consituents as belonging to
00888   // that jet
00889   for (unsigned ijet = 0; ijet < jets.size(); ijet++) {
00890 
00891     vector<PseudoJet> jet_constituents(constituents(jets[ijet]));
00892 
00893     for (unsigned ip = 0; ip < jet_constituents.size(); ip++) {
00894       // a safe (if slightly redundant) way of getting the particle
00895       // index (for initial particles it is actually safe to assume
00896       // ipart=iclust).
00897       unsigned iclust = jet_constituents[ip].cluster_hist_index();
00898       unsigned ipart = history()[iclust].jetp_index;
00899       indices[ipart] = ijet;
00900     }
00901   }
00902 
00903   return indices;
00904 }
00905 
00906 
00907 //----------------------------------------------------------------------
00908 // recursive routine that adds on constituents of jet to the subjet_vector
00909 void ClusterSequence::add_constituents (
00910            const PseudoJet & jet, vector<PseudoJet> & subjet_vector) const {
00911   // find out position in cluster history
00912   int i = jet.cluster_hist_index();
00913   int parent1 = _history[i].parent1;
00914   int parent2 = _history[i].parent2;
00915 
00916   if (parent1 == InexistentParent) {
00917     // It is an original particle (labelled by its parent having value
00918     // InexistentParent), therefore add it on to the subjet vector
00919     // Note: we add the initial particle and not simply 'jet' so that
00920     //       calling add_constituents with a subtracted jet containing
00921     //       only one particle will work.
00922     subjet_vector.push_back(_jets[i]);
00923     return;
00924   } 
00925 
00926   // add parent 1
00927   add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
00928 
00929   // see if parent2 is a real jet; if it is then add its constituents
00930   if (parent2 != BeamJet) {
00931     add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
00932   }
00933 }
00934 
00935 
00936 
00937 //----------------------------------------------------------------------
00938 // initialise the history in a standard way
00939 void ClusterSequence::_add_step_to_history (
00940                const int & step_number, const int & parent1, 
00941                const int & parent2, const int & jetp_index,
00942                const double & dij) {
00943 
00944   history_element element;
00945   element.parent1 = parent1;
00946   element.parent2 = parent2;
00947   element.jetp_index = jetp_index;
00948   element.child = Invalid;
00949   element.dij   = dij;
00950   element.max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
00951   _history.push_back(element);
00952 
00953   int local_step = _history.size()-1;
00954   assert(local_step == step_number);
00955 
00956   assert(parent1 >= 0);
00957   _history[parent1].child = local_step;
00958   if (parent2 >= 0) {_history[parent2].child = local_step;}
00959 
00960   // get cross-referencing right from PseudoJets
00961   if (jetp_index != Invalid) {
00962     assert(jetp_index >= 0);
00963     //cout << _jets.size() <<" "<<jetp_index<<"\n";
00964     _jets[jetp_index].set_cluster_hist_index(local_step);
00965   }
00966 
00967   if (_writeout_combinations) {
00968     cout << local_step << ": " 
00969          << parent1 << " with " << parent2
00970          << "; y = "<< dij<<endl;
00971   }
00972 
00973 }
00974 
00975 
00976 
00977 
00978 //======================================================================
00979 // Return an order in which to read the history such that _history[order[i]] 
00980 // will always correspond to the same set of consituent particles if 
00981 // two branching histories are equivalent in terms of the particles
00982 // contained in any given pseudojet.
00983 vector<int> ClusterSequence::unique_history_order() const {
00984 
00985   // first construct an array that will tell us the lowest constituent
00986   // of a given jet -- this will always be one of the original
00987   // particles, whose order is well defined and so will help us to
00988   // follow the tree in a unique manner.
00989   valarray<int> lowest_constituent(_history.size());
00990   int hist_n = _history.size();
00991   lowest_constituent = hist_n; // give it a large number
00992   for (int i = 0; i < hist_n; i++) {
00993     // sets things up for the initial partons
00994     lowest_constituent[i] = min(lowest_constituent[i],i); 
00995     // propagates them through to the children of this parton
00996     if (_history[i].child > 0) lowest_constituent[_history[i].child] 
00997       = min(lowest_constituent[_history[i].child],lowest_constituent[i]);
00998   }
00999 
01000   // establish an array for what we have and have not extracted so far
01001   valarray<bool> extracted(_history.size()); extracted = false;
01002   vector<int> unique_tree;
01003   unique_tree.reserve(_history.size());
01004 
01005   // now work our way through the tree
01006   for (unsigned i = 0; i < n_particles(); i++) {
01007     if (!extracted[i]) {
01008       unique_tree.push_back(i);
01009       extracted[i] = true;
01010       _extract_tree_children(i, extracted, lowest_constituent, unique_tree);
01011     }
01012   }
01013 
01014   return unique_tree;
01015 }
01016 
01017 //======================================================================
01018 // helper for unique_history_order
01019 void ClusterSequence::_extract_tree_children(
01020        int position, 
01021        valarray<bool> & extracted, 
01022        const valarray<int> & lowest_constituent,
01023        vector<int> & unique_tree) const {
01024   if (!extracted[position]) {
01025     // that means we may have unidentified parents around, so go and
01026     // collect them (extracted[position]) will then be made true)
01027     _extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
01028   } 
01029   
01030   // now look after the children...
01031   int child = _history[position].child;
01032   if (child  >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
01033 }
01034 
01035 
01036 //======================================================================
01037 // return the list of unclustered particles
01038 vector<PseudoJet> ClusterSequence::unclustered_particles() const {
01039   vector<PseudoJet> unclustered;
01040   for (unsigned i = 0; i < n_particles() ; i++) {
01041     if (_history[i].child == Invalid) 
01042       unclustered.push_back(_jets[_history[i].jetp_index]);
01043   }
01044   return unclustered;
01045 }
01046 
01047 
01048 
01049 //======================================================================
01050 // helper for unique_history_order
01051 void ClusterSequence::_extract_tree_parents(
01052        int position, 
01053        valarray<bool> & extracted, 
01054        const valarray<int> & lowest_constituent,
01055        vector<int> & unique_tree) const {
01056 
01057   if (!extracted[position]) {
01058     int parent1 = _history[position].parent1;
01059     int parent2 = _history[position].parent2;
01060     // where relevant order parents so that we will first treat the
01061     // one containing the smaller "lowest_constituent"
01062     if (parent1 >= 0 && parent2 >= 0) {
01063       if (lowest_constituent[parent1] > lowest_constituent[parent2]) 
01064         std::swap(parent1, parent2);
01065     }
01066     // then actually run through the parents to extract the constituents...
01067     if (parent1 >= 0 && !extracted[parent1]) 
01068       _extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
01069     if (parent2 >= 0 && !extracted[parent2]) 
01070       _extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
01071     // finally declare this position to be accounted for and push it
01072     // onto our list.
01073     unique_tree.push_back(position);
01074     extracted[position] = true;
01075   }
01076 }
01077 
01078 
01079 //======================================================================
01083 void ClusterSequence::_do_ij_recombination_step(
01084                                const int & jet_i, const int & jet_j, 
01085                                const double & dij, 
01086                                int & newjet_k) {
01087 
01088   // create the new jet by recombining the first two
01089   PseudoJet newjet;
01090   _jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
01091   _jets.push_back(newjet);
01092   // original version...
01093   //_jets.push_back(_jets[jet_i] + _jets[jet_j]);
01094 
01095   // get its index
01096   newjet_k = _jets.size()-1;
01097 
01098   // get history index
01099   int newstep_k = _history.size();
01100   // and provide jet with the info
01101   _jets[newjet_k].set_cluster_hist_index(newstep_k);
01102 
01103   // finally sort out the history 
01104   int hist_i = _jets[jet_i].cluster_hist_index();
01105   int hist_j = _jets[jet_j].cluster_hist_index();
01106 
01107   _add_step_to_history(newstep_k, min(hist_i, hist_j), max(hist_i,hist_j),
01108                        newjet_k, dij);
01109 
01110 }
01111 
01112 
01113 //======================================================================
01116 void ClusterSequence::_do_iB_recombination_step(
01117                                   const int & jet_i, const double & diB) {
01118   // get history index
01119   int newstep_k = _history.size();
01120 
01121   // recombine the jet with the beam
01122   _add_step_to_history(newstep_k,_jets[jet_i].cluster_hist_index(),BeamJet,
01123                        Invalid, diB);
01124 
01125 }
01126 
01127 FASTJET_END_NAMESPACE
01128 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines