ClusterSequence.cc

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