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...
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
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.
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
double kt2() const
returns the squared transverse momentum
int cluster_hist_index() const
return the cluster_hist_index, intended to be used by clustering routines.
string fastjet_version_string()
return a string containing information about the release
double perp2() const
returns the squared transverse momentum
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
const ClusterSequence * associated_cluster_sequence() const
get a (const) pointer to the parent ClusterSequence (NULL if inexistent)
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...
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...
bool has_valid_cluster_sequence() const
returns true if this PseudoJet has an associated and still valid(ated) ClusterSequence.
class that is intended to hold a full definition of the jet clusterer