31 #include "fastjet/Error.hh"    32 #include "fastjet/PseudoJet.hh"    33 #include "fastjet/ClusterSequence.hh"    34 #include "fastjet/ClusterSequenceStructure.hh"    35 #include "fastjet/version.hh"     36 #include "fastjet/internal/LazyTiling9Alt.hh"    37 #include "fastjet/internal/LazyTiling9.hh"    38 #include "fastjet/internal/LazyTiling25.hh"    40 #include "fastjet/internal/LazyTiling9SeparateGhosts.hh"    51 FASTJET_BEGIN_NAMESPACE      
   147 std::ostream * ClusterSequence::_fastjet_banner_ostr = &cout;
   151 ClusterSequence::~ClusterSequence () {
   154   if (_structure_shared_ptr){
   155     ClusterSequenceStructure* csi = 
dynamic_cast<ClusterSequenceStructure*
>(_structure_shared_ptr.get()); 
   161     csi->set_associated_cs(NULL);
   169     if (_deletes_self_when_unused) {
   170       _structure_shared_ptr.set_count(_structure_shared_ptr.use_count() 
   171                                         + _structure_use_count_after_construction);
   177 void ClusterSequence::signal_imminent_self_deletion()
 const {
   191   assert(_deletes_self_when_unused);
   192   _deletes_self_when_unused = 
false;
   207 void ClusterSequence::_initialise_and_run (
   209                                   const bool & writeout_combinations) {
   212   _decant_options(jet_def_in, writeout_combinations);
   215   _initialise_and_run_no_decant();
   219 void ClusterSequence::_initialise_and_run_no_decant () {
   223   _fill_initial_history();
   226   if (n_particles() == 0) 
return;
   231     _plugin_activated = 
true;
   233     _jet_def.plugin()->run_clustering( (*
this) );
   234     _plugin_activated = 
false;
   235     _update_structure_use_count();
   245       assert(_Rparam > 2.0); 
   259         _R2 = 2 * ( 3.0 + cos(_Rparam) );
   261         _R2    = 2 * ( 1.0 - cos(_Rparam) );
   265     _simple_N2_cluster_EEBriefJet();
   268     throw Error(
"A ClusterSequence cannot be created with an uninitialised JetDefinition");
   282   if (_strategy == 
Best) {
   283     _strategy = _best_strategy();
   289     int N = _jets.size();
   295     if (min(1.0,max(0.1,_Rparam)*3.3)*N <= 30) {
   300     } 
else if ((N > 16000/pow(_Rparam,1.15) && _jet_def.jet_algorithm() != 
antikt_algorithm)
   301                || N > 35000/pow(_Rparam,1.15)) {
   304     } 
else if (N <= 450) {
   315   if (_Rparam >= twopi) {
   316     if (   _strategy == 
NlnN   327     if (_jet_def.strategy() != 
Best && _strategy != _jet_def.strategy()) {
   329       oss << 
"Cluster strategy " << strategy_string(_jet_def.strategy())
   330           << 
" automatically changed to " << strategy_string()
   331           << 
" because the former is not supported for R = " << _Rparam
   333       _changed_strategy_warning.warn(oss.str());
   345     this->_simple_N2_cluster_BriefJet();
   346   } 
else if (_strategy == 
N2Tiled) {
   347     this->_faster_tiled_N2_cluster();
   349     this->_minheap_faster_tiled_N2_cluster();
   353     _plugin_activated = 
true;
   354     LazyTiling9Alt tiling(*
this);
   356     _plugin_activated = 
false;
   361     _plugin_activated = 
true;
   362     LazyTiling25 tiling(*
this);
   364     _plugin_activated = 
false;
   369     _plugin_activated = 
true;
   370     LazyTiling9 tiling(*
this);
   372     _plugin_activated = 
false;
   378     _plugin_activated = 
true;
   379     LazyTiling9SeparateGhosts tiling(*
this);
   381     _plugin_activated = 
false;
   383     throw Error(
"N2MHTLazy9AntiKtSeparateGhosts strategy not supported with FJCORE");
   386   } 
else if (_strategy == 
NlnN) {
   387     this->_delaunay_cluster();
   388   } 
else if (_strategy == 
NlnNCam) {
   389     this->_CP2DChan_cluster_2piMultD();
   391     this->_delaunay_cluster();
   392   } 
else if (_strategy ==  
N3Dumb ) {
   393     this->_really_dumb_cluster();
   395     this->_tiled_N2_cluster();
   397     this->_CP2DChan_cluster();
   399     this->_CP2DChan_cluster_2pi2R();
   402     err << 
"Unrecognised value for strategy: "<<_strategy;
   403     throw Error(err.str());
   410 bool ClusterSequence::_first_time = 
true;
   417   return "FastJet version "+string(fastjet_version);
   423 void ClusterSequence::print_banner() {
   425   if (!_first_time) {
return;}
   429   ostream * ostr = _fastjet_banner_ostr;
   432   (*ostr) << 
"#--------------------------------------------------------------------------\n";
   433   (*ostr) << 
"#                         FastJet release " << fastjet_version << endl;
   434   (*ostr) << 
"#                 M. Cacciari, G.P. Salam and G. Soyez                  \n"; 
   435   (*ostr) << 
"#     A software package for jet finding and analysis at colliders      \n";
   436   (*ostr) << 
"#                           http://fastjet.fr                           \n"; 
   438   (*ostr) << 
"# Please cite EPJC72(2012)1896 [arXiv:1111.6097] if you use this package\n";
   439   (*ostr) << 
"# for scientific work and optionally PLB641(2006)57 [hep-ph/0512210].   \n";
   441   (*ostr) << 
"# FastJet is provided without warranty under the terms of the GNU GPLv2.\n";
   442   (*ostr) << 
"# It uses T. Chan's closest pair algorithm, S. Fortune's Voronoi code";
   444   (*ostr) << 
",\n# CGAL ";
   448   (*ostr) << 
"and 3rd party plugin jet algorithms. See COPYING file for details.\n";
   449   (*ostr) << 
"#--------------------------------------------------------------------------\n";
   457                                       const bool & writeout_combinations) {
   459   _jet_def = jet_def_in;
   460   _writeout_combinations = writeout_combinations;
   464   _decant_options_partial();
   469 void ClusterSequence::_decant_options_partial() {
   473   _jet_algorithm = _jet_def.jet_algorithm();
   474   _Rparam = _jet_def.R();  _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
   475   _strategy = _jet_def.strategy();
   478   _plugin_activated = 
false;
   482   _update_structure_use_count(); 
   488 void ClusterSequence::_fill_initial_history () {
   493   _jets.reserve(_jets.size()*2);
   494   _history.reserve(_jets.size()*2);
   498   for (
int i = 0; i < static_cast<int>(_jets.size()) ; i++) {
   500     element.parent1 = InexistentParent;
   501     element.
parent2 = InexistentParent;
   502     element.
child   = Invalid;
   507     _history.push_back(element);
   510     _jet_def.recombiner()->preprocess(_jets[i]);
   513     _jets[i].set_cluster_hist_index(i);
   514     _set_structure_shared_ptr(_jets[i]);
   517     _Qtot += _jets[i].E();
   519   _initial_n = _jets.size();
   520   _deletes_self_when_unused = 
false;
   525 string ClusterSequence::strategy_string (
Strategy strategy_in)
  const {
   527   switch(strategy_in) {
   529     strategy = 
"NlnN"; 
break;
   531     strategy = 
"NlnN3pi"; 
break;
   533     strategy = 
"NlnN4pi"; 
break;
   535     strategy = 
"N2Plain"; 
break;
   537     strategy = 
"N2Tiled"; 
break;
   539     strategy = 
"N2MinHeapTiled"; 
break;
   541     strategy = 
"N2PoorTiled"; 
break;
   543     strategy = 
"N2MHTLazy9"; 
break;
   545     strategy = 
"N2MHTLazy9Alt"; 
break;
   547     strategy = 
"N2MHTLazy25"; 
break;
   549     strategy = 
"N2MHTLazy9AntiKtSeparateGhosts"; 
break;
   551     strategy = 
"N3Dumb"; 
break;
   553     strategy = 
"NlnNCam4pi"; 
break;
   555     strategy = 
"NlnNCam2pi2R"; 
break;
   557     strategy = 
"NlnNCam"; 
break; 
   559     strategy = 
"plugin strategy"; 
break;
   561     strategy = 
"Unrecognized";
   567 double ClusterSequence::jet_scale_for_algorithm(
   572     double kt2=jet.
kt2();
   573     return kt2 > 1e-300 ? 1.0/kt2 : 1e300;
   575     double kt2 = jet.
kt2();
   576     double p   = jet_def().extra_param();
   577     if (p <= 0 && kt2 < 1e-300) kt2 = 1e-300; 
   580     double kt2 = jet.
kt2();
   581     double lim = _jet_def.extra_param();
   582     if (kt2 < lim*lim && kt2 != 0.0) {
   585   } 
else {
throw Error(
"Unrecognised jet algorithm");}
   604   int N = _jets.size();
   607   double bounded_R = max(_Rparam, 0.1);
   611   if (N <= 30 || N <= 39.0/(bounded_R + 0.6)) {
   622   const static _Parabola N_Tiled_to_MHT_lowR             (-45.4947,54.3528,44.6283);
   623   const static _Parabola L_MHT_to_MHTLazy9_lowR          (0.677807,-1.05006,10.6994);
   624   const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_lowR(0.169967,-0.512589,12.1572);
   625   const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_lowR (0.16237,-0.484612,12.3373);
   626   const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_lowR = L_MHTLazy9_to_MHTLazy25_kt_lowR;
   627   const static _Parabola L_MHTLazy25_to_NlnN_akt_lowR    (0.0472051,-0.22043,15.9196);
   628   const static _Parabola L_MHTLazy25_to_NlnN_kt_lowR     (0.118609,-0.326811,14.8287);
   629   const static _Parabola L_MHTLazy25_to_NlnN_cam_lowR    (0.10119,-0.295748,14.3924);
   631   const static _Line     L_Tiled_to_MHTLazy9_medR         (-1.31304,7.29621);
   632   const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_medR = L_MHTLazy9_to_MHTLazy25_akt_lowR;
   633   const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_medR  = L_MHTLazy9_to_MHTLazy25_kt_lowR;
   634   const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_medR = L_MHTLazy9_to_MHTLazy25_cam_lowR;
   635   const static _Parabola L_MHTLazy25_to_NlnN_akt_medR     = L_MHTLazy25_to_NlnN_akt_lowR;
   636   const static _Parabola L_MHTLazy25_to_NlnN_kt_medR      = L_MHTLazy25_to_NlnN_kt_lowR;
   637   const static _Parabola L_MHTLazy25_to_NlnN_cam_medR     = L_MHTLazy25_to_NlnN_cam_lowR;
   639   const static double    N_Plain_to_MHTLazy9_largeR         = 75;
   640   const static double    N_MHTLazy9_to_MHTLazy25_akt_largeR = 700;
   641   const static double    N_MHTLazy9_to_MHTLazy25_kt_largeR  = 1000;
   642   const static double    N_MHTLazy9_to_MHTLazy25_cam_largeR = 1000;
   643   const static double    N_MHTLazy25_to_NlnN_akt_largeR     = 100000;
   644   const static double    N_MHTLazy25_to_NlnN_kt_largeR      = 40000;
   645   const static double    N_MHTLazy25_to_NlnN_cam_largeR     = 15000;
   656     double p   = jet_def().extra_param();
   664     jet_algorithm = _jet_algorithm;
   667   if (bounded_R < 0.65) {
   669     if          (N    < N_Tiled_to_MHT_lowR(bounded_R))              
return N2Tiled;
   670     double logN = log(
double(N));
   671     if          (logN < L_MHT_to_MHTLazy9_lowR(bounded_R))           
return N2MinHeapTiled;
   674         if      (logN < L_MHTLazy9_to_MHTLazy25_akt_lowR(bounded_R)) 
return N2MHTLazy9;
   675         else if (logN < L_MHTLazy25_to_NlnN_akt_lowR(bounded_R))     
return N2MHTLazy25;
   678         if      (logN < L_MHTLazy9_to_MHTLazy25_kt_lowR(bounded_R))  
return N2MHTLazy9;
   679         else if (logN < L_MHTLazy25_to_NlnN_kt_lowR(bounded_R))      
return N2MHTLazy25;
   682         if      (logN < L_MHTLazy9_to_MHTLazy25_cam_lowR(bounded_R)) 
return N2MHTLazy9;
   683         else if (logN < L_MHTLazy25_to_NlnN_cam_lowR(bounded_R))     
return N2MHTLazy25;
   687   } 
else if (bounded_R < 0.5*pi) {
   689     double logN = log(
double(N));
   690     if      (logN < L_Tiled_to_MHTLazy9_medR(bounded_R))             
return N2Tiled;
   693         if      (logN < L_MHTLazy9_to_MHTLazy25_akt_medR(bounded_R)) 
return N2MHTLazy9;
   694         else if (logN < L_MHTLazy25_to_NlnN_akt_medR(bounded_R))     
return N2MHTLazy25;
   697         if      (logN < L_MHTLazy9_to_MHTLazy25_kt_medR(bounded_R))  
return N2MHTLazy9;
   698         else if (logN < L_MHTLazy25_to_NlnN_kt_medR(bounded_R))      
return N2MHTLazy25;
   701         if      (logN < L_MHTLazy9_to_MHTLazy25_cam_medR(bounded_R)) 
return N2MHTLazy9;
   702         else if (logN < L_MHTLazy25_to_NlnN_cam_medR(bounded_R))     
return N2MHTLazy25;
   708     if      (N    < N_Plain_to_MHTLazy9_largeR)                      
return N2Plain;
   711         if      (N < N_MHTLazy9_to_MHTLazy25_akt_largeR)             
return N2MHTLazy9;
   712         else if (N < N_MHTLazy25_to_NlnN_akt_largeR)                 
return N2MHTLazy25;
   715         if      (N < N_MHTLazy9_to_MHTLazy25_kt_largeR)              
return N2MHTLazy9;
   716         else if (N < N_MHTLazy25_to_NlnN_kt_largeR)                  
return N2MHTLazy25;
   719         if      (N < N_MHTLazy9_to_MHTLazy25_cam_largeR)             
return N2MHTLazy9;
   720         else if (N < N_MHTLazy25_to_NlnN_cam_largeR)                 
return N2MHTLazy25;
   729   assert(0 && 
"Code should never reach here");
   783     _deletes_self_when_unused = 
false;
   784     transfer_from_sequence(cs);
   802   if (will_delete_self_when_unused()) 
   803     throw(
Error(
"cannot use CS::transfer_from_sequence after a call to delete_self_when_unused()"));
   806   _jet_def                 = from_seq._jet_def                ;
   807   _writeout_combinations   = from_seq._writeout_combinations  ;
   808   _initial_n               = from_seq._initial_n              ;
   809   _Rparam                  = from_seq._Rparam                 ;
   811   _invR2                   = from_seq._invR2                  ;
   812   _strategy                = from_seq._strategy               ;
   813   _jet_algorithm           = from_seq._jet_algorithm          ;
   814   _plugin_activated        = from_seq._plugin_activated       ;
   820     _jets     = (*action_on_jets)(from_seq.
_jets);
   822     _jets     = from_seq.
_jets;
   826   _extras   = from_seq._extras;
   829   if (_structure_shared_ptr) {
   833     if (_deletes_self_when_unused) 
throw Error(
"transfer_from_sequence cannot be used for a cluster sequence that deletes self when unused");
   844   _update_structure_use_count();
   846   for (
unsigned int i=0; i<_jets.size(); i++){
   849     _jets[i].set_cluster_hist_index(from_seq.
_jets[i].cluster_hist_index());
   852     _set_structure_shared_ptr(_jets[i]);
   860 void ClusterSequence::plugin_record_ij_recombination(
   861            int jet_i, 
int jet_j, 
double dij, 
   862            const PseudoJet & newjet, 
int & newjet_k) {
   864   plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
   867   int tmp_index = _jets[newjet_k].cluster_hist_index();
   868   _jets[newjet_k] = newjet;
   870   _set_structure_shared_ptr(_jets[newjet_k]);
   876 vector<PseudoJet> ClusterSequence::inclusive_jets (
const double ptmin)
 const{
   877   double dcut = ptmin*ptmin;
   878   int i = _history.size() - 1; 
   879   vector<PseudoJet> jets_local;
   885       if (_history[i].max_dij_so_far < dcut) {
break;}
   886       if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
   888         int parent1 = _history[i].parent1;
   889         jets_local.push_back(_jets[_history[parent1].jetp_index]);}
   897       if (_history[i].parent2 != BeamJet) {
break;}
   898       int parent1 = _history[i].parent1;
   899       const PseudoJet & jet = _jets[_history[parent1].jetp_index];
   900       if (jet.
perp2() >= dcut) {jets_local.push_back(jet);}
   913       if (_history[i].parent2 == BeamJet) {
   914         int parent1 = _history[i].parent1;
   915         const PseudoJet & jet = _jets[_history[parent1].jetp_index];
   916         if (jet.
perp2() >= dcut) {jets_local.push_back(jet);}
   920   } 
else {
throw Error(
"cs::inclusive_jets(...): Unrecognized jet algorithm");}
   928 int ClusterSequence::n_exclusive_jets (
const double dcut)
 const {
   932   int i = _history.size() - 1; 
   934     if (_history[i].max_dij_so_far <= dcut) {
break;}
   937   int stop_point = i + 1;
   940   int njets = 2*_initial_n - stop_point;
   947 vector<PseudoJet> ClusterSequence::exclusive_jets (
const double dcut)
 const {
   948   int njets = n_exclusive_jets(dcut);
   949   return exclusive_jets(njets);
   956 vector<PseudoJet> ClusterSequence::exclusive_jets (
const int njets)
 const {
   960   if (njets > _initial_n) {
   962     err << 
"Requested " << njets << 
" exclusive jets, but there were only "    963         << _initial_n << 
" particles in the event";
   964     throw Error(err.str());
   967   return exclusive_jets_up_to(njets);
   973 vector<PseudoJet> ClusterSequence::exclusive_jets_up_to (
const int njets)
 const {
   985        (_jet_def.extra_param() <0)) &&
   987        (!_jet_def.plugin()->exclusive_sequence_meaningful()))) {
   988     _exclusive_warnings.warn(
"dcut and exclusive jets for jet-finders other than kt, C/A or genkt with p>=0 should be interpreted with care.");
   995   int stop_point = 2*_initial_n - njets;
   997   if (stop_point < _initial_n) stop_point = _initial_n;
  1001   if (2*_initial_n != static_cast<int>(_history.size())) {
  1003     err << 
"2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
  1004     throw Error(err.str());
  1013   vector<PseudoJet> jets_local;
  1014   for (
unsigned int i = stop_point; i < _history.size(); i++) {
  1015     int parent1 = _history[i].parent1;
  1016     if (parent1 < stop_point) {
  1017       jets_local.push_back(_jets[_history[parent1].jetp_index]);
  1019     int parent2 = _history[i].parent2;
  1020     if (parent2 < stop_point && parent2 > 0) {
  1021       jets_local.push_back(_jets[_history[parent2].jetp_index]);
  1027   if (
int(jets_local.size()) != min(_initial_n, njets)) {
  1029     err << 
"ClusterSequence::exclusive_jets: size of returned vector ("  1030          <<jets_local.size()<<
") does not coincide with requested number of jets ("  1032     throw Error(err.str());
  1041 double ClusterSequence::exclusive_dmerge (
const int njets)
 const {
  1043   if (njets >= _initial_n) {
return 0.0;}
  1044   return _history[2*_initial_n-njets-1].dij;
  1053 double ClusterSequence::exclusive_dmerge_max (
const int njets)
 const {
  1055   if (njets >= _initial_n) {
return 0.0;}
  1056   return _history[2*_initial_n-njets-1].max_dij_so_far;
  1064 std::vector<PseudoJet> ClusterSequence::exclusive_subjets 
  1067   set<const history_element*> subhist;
  1071   get_subhist_set(subhist, jet, dcut, 0);
  1074   vector<PseudoJet> subjets;
  1075   subjets.reserve(subhist.size());
  1076   for (set<const history_element*>::iterator elem = subhist.begin(); 
  1077        elem != subhist.end(); elem++) {
  1078     subjets.push_back(_jets[(*elem)->jetp_index]);
  1087 int ClusterSequence::n_exclusive_subjets(
const PseudoJet & jet, 
  1088                         const double dcut)
 const {
  1089   set<const history_element*> subhist;
  1092   get_subhist_set(subhist, jet, dcut, 0);
  1093   return subhist.size();
  1100 std::vector<PseudoJet> ClusterSequence::exclusive_subjets
  1102   vector<PseudoJet> subjets = exclusive_subjets_up_to(jet, nsub);
  1103   if (
int(subjets.size()) < nsub) {
  1105     err << 
"Requested " << nsub << 
" exclusive subjets, but there were only "   1106         << subjets.size() << 
" particles in the jet";
  1107     throw Error(err.str());
  1117 std::vector<PseudoJet> ClusterSequence::exclusive_subjets_up_to
  1120   set<const history_element*> subhist;
  1123   vector<PseudoJet> subjets;
  1124   if (nsub <  0) 
throw Error(
"Requested a negative number of subjets. This is nonsensical.");
  1125   if (nsub == 0) 
return subjets;
  1129   get_subhist_set(subhist, jet, -1.0, nsub);
  1132   subjets.reserve(subhist.size());
  1133   for (set<const history_element*>::iterator elem = subhist.begin(); 
  1134        elem != subhist.end(); elem++) {
  1135     subjets.push_back(_jets[(*elem)->jetp_index]);
  1146 double ClusterSequence::exclusive_subdmerge(
const PseudoJet & jet, 
int nsub)
 const {
  1147   set<const history_element*> subhist;
  1151   get_subhist_set(subhist, jet, -1.0, nsub);
  1153   set<const history_element*>::iterator highest = subhist.end();
  1157   return (*highest)->dij;
  1167 double ClusterSequence::exclusive_subdmerge_max(
const PseudoJet & jet, 
int nsub)
 const {
  1169   set<const history_element*> subhist;
  1173   get_subhist_set(subhist, jet, -1.0, nsub);
  1175   set<const history_element*>::iterator highest = subhist.end();
  1179   return (*highest)->max_dij_so_far;
  1191 void ClusterSequence::get_subhist_set(set<const history_element*> & subhist,
  1193                                      double dcut, 
int maxjet)
 const {
  1194   assert(contains(jet));
  1204     set<const history_element*>::iterator highest = subhist.end();
  1205     assert (highest != subhist.begin()); 
  1209     if (njet == maxjet) 
break;
  1211     if (elem->parent1 < 0)            
break;
  1216     subhist.erase(highest);
  1217     subhist.insert(&(_history[elem->parent1]));
  1218     subhist.insert(&(_history[elem->
parent2]));
  1225 bool ClusterSequence::object_in_jet(
const PseudoJet & 
object, 
  1230   assert(contains(
object) && contains(jet));
  1232   const PseudoJet * this_object = &object;
  1237     } 
else if (has_child(*this_object, childp)) {
  1238       this_object = childp;
  1258   assert ((hist.parent1 >= 0 && hist.
parent2 >= 0) || 
  1259           (hist.parent1 < 0 && hist.
parent2 < 0));
  1261   if (hist.parent1 < 0) {
  1266     parent1 = _jets[_history[hist.parent1].jetp_index];
  1267     parent2 = _jets[_history[hist.
parent2].jetp_index];
  1269     if (parent1.
perp2() < parent2.
perp2()) std::swap(parent1,parent2);
  1289   bool res = has_child(jet, childp);
  1306   if (hist.
child >= 0 && _history[hist.
child].jetp_index >= 0) {
  1307     childp = &(_jets[_history[hist.
child].jetp_index]);
  1327   if (hist.
child >= 0 && _history[hist.
child].parent2 >= 0) {
  1332       partner = _jets[_history[child_hist.
parent2].jetp_index];
  1335       partner = _jets[_history[child_hist.parent1].jetp_index];
  1347 vector<PseudoJet> ClusterSequence::constituents (
const PseudoJet & jet)
 const {
  1348   vector<PseudoJet> subjets;
  1349   add_constituents(jet, subjets);
  1362 void ClusterSequence::print_jets_for_root(
const std::vector<PseudoJet> & jets_in, 
  1363                                           ostream & ostr)
 const {
  1364   for (
unsigned i = 0; i < jets_in.size(); i++) {
  1366          << jets_in[i].px() << 
" "  1367          << jets_in[i].py() << 
" "  1368          << jets_in[i].pz() << 
" "  1369          << jets_in[i].E() << endl;
  1370     vector<PseudoJet> cst = constituents(jets_in[i]);
  1371     for (
unsigned j = 0; j < cst.size() ; j++) {
  1372       ostr << 
" " << j << 
" "  1373            << cst[j].rap() << 
" "  1374            << cst[j].phi() << 
" "  1375            << cst[j].perp() << endl;
  1377     ostr << 
"#END" << endl;
  1381 void ClusterSequence::print_jets_for_root(
const std::vector<PseudoJet> & jets_in, 
  1382                                           const std::string & filename,
  1383                                           const std::string & comment )
 const {
  1384   std::ofstream ostr(filename.c_str());
  1385   if (comment != 
"") ostr << 
"# " << comment << endl;
  1386   print_jets_for_root(jets_in, ostr);
  1407 vector<int> ClusterSequence::particle_jet_indices(
  1408                         const vector<PseudoJet> & jets_in)
 const {
  1410   vector<int> indices(n_particles());
  1413   for (
unsigned ipart = 0; ipart < n_particles(); ipart++) 
  1414     indices[ipart] = -1;
  1418   for (
unsigned ijet = 0; ijet < jets_in.size(); ijet++) {
  1420     vector<PseudoJet> jet_constituents(constituents(jets_in[ijet]));
  1422     for (
unsigned ip = 0; ip < jet_constituents.size(); ip++) {
  1426       unsigned iclust = jet_constituents[ip].cluster_hist_index();
  1427       unsigned ipart = history()[iclust].jetp_index;
  1428       indices[ipart] = ijet;
  1438 void ClusterSequence::add_constituents (
  1439            const PseudoJet & jet, vector<PseudoJet> & subjet_vector)
 const {
  1442   int parent1 = _history[i].parent1;
  1443   int parent2 = _history[i].parent2;
  1445   if (parent1 == InexistentParent) {
  1451     subjet_vector.push_back(_jets[i]);
  1456   add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
  1459   if (parent2 != BeamJet) {
  1460     add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
  1468 void ClusterSequence::_add_step_to_history (
  1471                const int parent2, 
const int jetp_index,
  1475   element.parent1 = parent1;
  1478   element.
child = Invalid;
  1480   element.
max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
  1481   _history.push_back(element);
  1483   int local_step = _history.size()-1;
  1495   assert(parent1 >= 0);
  1496   if (_history[parent1].child != Invalid){
  1497     throw InternalError(
"trying to recomine an object that has previsously been recombined");
  1499   _history[parent1].child = local_step;
  1501     if (_history[parent2].child != Invalid){
  1502       throw InternalError(
"trying to recomine an object that has previsously been recombined");
  1504     _history[parent2].child = local_step;
  1508   if (jetp_index != Invalid) {
  1509     assert(jetp_index >= 0);
  1511     _jets[jetp_index].set_cluster_hist_index(local_step);
  1512     _set_structure_shared_ptr(_jets[jetp_index]);
  1515   if (_writeout_combinations) {
  1516     cout << local_step << 
": "   1517          << parent1 << 
" with " << parent2
  1518          << 
"; y = "<< dij<<endl;
  1531 vector<int> ClusterSequence::unique_history_order()
 const {
  1537   valarray<int> lowest_constituent(_history.size());
  1538   int hist_n = _history.size();
  1539   lowest_constituent = hist_n; 
  1540   for (
int i = 0; i < hist_n; i++) {
  1542     lowest_constituent[i] = min(lowest_constituent[i],i); 
  1544     if (_history[i].child > 0) lowest_constituent[_history[i].child] 
  1545       = min(lowest_constituent[_history[i].child],lowest_constituent[i]);
  1549   valarray<bool> extracted(_history.size()); extracted = 
false;
  1550   vector<int> unique_tree;
  1551   unique_tree.reserve(_history.size());
  1554   for (
unsigned i = 0; i < n_particles(); i++) {
  1555     if (!extracted[i]) {
  1556       unique_tree.push_back(i);
  1557       extracted[i] = 
true;
  1558       _extract_tree_children(i, extracted, lowest_constituent, unique_tree);
  1567 void ClusterSequence::_extract_tree_children(
  1569        valarray<bool> & extracted, 
  1570        const valarray<int> & lowest_constituent,
  1571        vector<int> & unique_tree)
 const {
  1572   if (!extracted[position]) {
  1575     _extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
  1579   int child = _history[position].child;
  1580   if (child  >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
  1586 vector<PseudoJet> ClusterSequence::unclustered_particles()
 const {
  1587   vector<PseudoJet> unclustered;
  1588   for (
unsigned i = 0; i < n_particles() ; i++) {
  1589     if (_history[i].child == Invalid) 
  1590       unclustered.push_back(_jets[_history[i].jetp_index]);
  1600 vector<PseudoJet> ClusterSequence::childless_pseudojets()
 const {
  1601   vector<PseudoJet> unclustered;
  1602   for (
unsigned i = 0; i < _history.size() ; i++) {
  1603     if ((_history[i].child == Invalid) && (_history[i].parent2 != BeamJet))
  1604       unclustered.push_back(_jets[_history[i].jetp_index]);
  1615 bool ClusterSequence::contains(
const PseudoJet & jet)
 const {
  1626 void ClusterSequence::_extract_tree_parents(
  1628        valarray<bool> & extracted, 
  1629        const valarray<int> & lowest_constituent,
  1630        vector<int> & unique_tree)
 const {
  1632   if (!extracted[position]) {
  1633     int parent1 = _history[position].parent1;
  1634     int parent2 = _history[position].parent2;
  1637     if (parent1 >= 0 && parent2 >= 0) {
  1638       if (lowest_constituent[parent1] > lowest_constituent[parent2]) 
  1639         std::swap(parent1, parent2);
  1642     if (parent1 >= 0 && !extracted[parent1]) 
  1643       _extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
  1644     if (parent2 >= 0 && !extracted[parent2]) 
  1645       _extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
  1648     unique_tree.push_back(position);
  1649     extracted[position] = 
true;
  1658 void ClusterSequence::_do_ij_recombination_step(
  1659                                const int jet_i, 
const int jet_j, 
  1669   _jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
  1670   _jets.push_back(newjet);
  1675   newjet_k = _jets.size()-1;
  1678   int newstep_k = _history.size();
  1680   _jets[newjet_k].set_cluster_hist_index(newstep_k);
  1683   int hist_i = _jets[jet_i].cluster_hist_index();
  1684   int hist_j = _jets[jet_j].cluster_hist_index();
  1686   _add_step_to_history(min(hist_i, hist_j), max(hist_i,hist_j),
  1699 void ClusterSequence::_do_iB_recombination_step(
  1700                                   const int jet_i, 
const double diB) {
  1702   _add_step_to_history(_jets[jet_i].cluster_hist_index(),BeamJet,
  1719 void ClusterSequence::_set_structure_shared_ptr(
PseudoJet & j) {
  1723   _update_structure_use_count();
  1728 void ClusterSequence::_update_structure_use_count() {
  1731   _structure_use_count_after_construction = _structure_shared_ptr.use_count();
  1738 void ClusterSequence::delete_self_when_unused() {
  1746   int new_count = _structure_shared_ptr.use_count() - _structure_use_count_after_construction;
  1747   if (new_count <= 0) {
  1748     throw Error(
"delete_self_when_unused may only be called if at least one object outside the CS (e.g. a jet) is already associated with the CS");
  1751   _structure_shared_ptr.set_count(new_count);
  1752   _deletes_self_when_unused = 
true;
  1756 FASTJET_END_NAMESPACE
 a version of cambridge with a special distance measure for particles whose pt is < extra_param(); thi...
 
like the k_t but with distance measures dij = min(kti^{2p},ktj^{2p}) Delta R_{ij}^2 / R^2 diB = 1/kti...
 
double kt2() const 
returns the squared transverse momentum 
 
Chan's closest pair method (in a variant with 4pi coverage), for use exclusively with the Cambridge a...
 
best of the NlnN variants – best overall for N>10^4. 
 
Similar to N2MHTLazy9, but uses tiles of size R/2 and a 5x5 tile grid around the particle. 
 
the value for the jet algorithm in a JetDefinition for which no algorithm has yet been defined ...
 
legacy N ln N using 4pi coverage of cylinder 
 
int cluster_hist_index() const 
return the cluster_hist_index, intended to be used by clustering routines. 
 
the e+e- genkt algorithm (R > 2 and p=1 gives ee_kt) 
 
fastest from about 50..500 
 
the longitudinally invariant kt algorithm 
 
int jetp_index
index in _history where the current jet is recombined with another jet to form its child...
 
Contains any information related to the clustering that should be directly accessible to PseudoJet...
 
std::vector< PseudoJet > _jets
This contains the physical PseudoJets; for each PseudoJet one can find the corresponding position in ...
 
Chan's closest pair method (in a variant with 2pi+minimal extra variant), for use exclusively with th...
 
std::vector< history_element > _history
this vector will contain the branching history; for each stage, _history[i].jetp_index indicates wher...
 
class to provide facilities for giving warnings up to some maximum number of times and to provide glo...
 
any plugin algorithm supplied by the user 
 
int parent2
index in _history where first parent of this jet was created (InexistentParent if this jet is an orig...
 
Like N2MHTLazy9 in a number of respects, but does not calculate ghost-ghost distances and so does not...
 
the plugin has been used... 
 
virtual void set_associated_cs(const ClusterSequence *new_cs)
set the associated csw 
 
double dij
index in the _jets vector where we will find the 
 
void set_cluster_hist_index(const int index)
set the cluster_hist_index, intended to be used by clustering routines. 
 
bool has_valid_cluster_sequence() const 
returns true if this PseudoJet has an associated and still valid(ated) ClusterSequence. 
 
worse even than the usual N^3 algorithms 
 
Like to N2MHTLazy9 but uses slightly different optimizations, e.g. 
 
base class corresponding to errors that can be thrown by FastJet 
 
string fastjet_version_string()
return a string containing information about the release 
 
the automatic strategy choice that was being made in FJ 3.0 (restricted to strategies that were prese...
 
int child
index in _history where second parent of this jet was created (InexistentParent if this jet is an ori...
 
automatic selection of the best (based on N), including the LazyTiled strategies that are new to FJ3...
 
class corresponding to critical internal errors 
 
a single element in the clustering history 
 
like the k_t but with distance measures dij = min(1/kti^2,1/ktj^2) Delta R_{ij}^2 / R^2 diB = 1/kti^2...
 
const ClusterSequence * associated_cluster_sequence() const 
get a (const) pointer to the parent ClusterSequence (NULL if inexistent) 
 
void set_structure_shared_ptr(const SharedPtr< PseudoJetStructureBase > &structure)
set the associated structure 
 
the longitudinally invariant variant of the cambridge algorithm (aka Aachen algoithm). 
 
JetAlgorithm
the various families of jet-clustering algorithm 
 
only looks into a neighbouring tile for a particle's nearest neighbour (NN) if that particle's in-til...
 
Strategy
the various options for the algorithmic strategy to adopt in clustering events with kt and cambridge ...
 
Class to contain pseudojets, including minimal information of use to jet-clustering routines...
 
double max_dij_so_far
the distance corresponding to the recombination at this stage of the clustering. 
 
legacy N ln N using 3pi coverage of cylinder. 
 
faster that N2Tiled above about 500 particles; differs from it by retainig the di(closest j) distance...
 
Chan's closest pair method (in a variant with 2pi+2R coverage), for use exclusively with the Cambridg...
 
double perp2() const 
returns the squared transverse momentum 
 
class that is intended to hold a full definition of the jet clusterer