31#include "fastjet/PseudoJet.hh"
32#include "fastjet/ClusterSequence.hh"
33#include "fastjet/ClusterSequenceActiveArea.hh"
34#include "fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
42FASTJET_BEGIN_NAMESPACE
53void ClusterSequenceActiveArea::_initialise_and_run_AA (
56 const bool & writeout_combinations) {
58 bool continue_running;
59 _initialise_AA(jet_def_in, ghost_spec, writeout_combinations, continue_running);
60 if (continue_running) {
62 _postprocess_AA(ghost_spec);
67void ClusterSequenceActiveArea::_resize_and_zero_AA () {
69 _average_area.resize(2*_jets.size()); _average_area = 0.0;
70 _average_area2.resize(2*_jets.size()); _average_area2 = 0.0;
71 _average_area_4vector.resize(2*_jets.size());
72 _average_area_4vector =
PseudoJet(0.0,0.0,0.0,0.0);
73 _non_jet_area = 0.0; _non_jet_area2 = 0.0; _non_jet_number=0.0;
77void ClusterSequenceActiveArea::_initialise_AA (
78 const JetDefinition & jet_def_in,
79 const GhostedAreaSpec & ghost_spec,
80 const bool & writeout_combinations,
81 bool & continue_running)
85 _ghost_spec_repeat = ghost_spec.repeat();
88 _resize_and_zero_AA();
91 _maxrap_for_area = ghost_spec.ghost_maxrap();
92 _safe_rap_for_area = _maxrap_for_area - jet_def_in.R();
101 if (ghost_spec.repeat() <= 0) {
102 _initialise_and_run(jet_def_in, writeout_combinations);
103 continue_running =
false;
108 _decant_options(jet_def_in, writeout_combinations);
112 _fill_initial_history();
115 _has_dangerous_particles =
false;
117 continue_running =
true;
122void ClusterSequenceActiveArea::_run_AA (
const GhostedAreaSpec & ghost_spec) {
124 vector<PseudoJet> input_jets(_jets);
127 vector<int> unique_tree;
130 for (
int irepeat = 0; irepeat < ghost_spec.repeat(); irepeat++) {
132 ClusterSequenceActiveAreaExplicitGhosts clust_seq(input_jets,
133 jet_def(), ghost_spec);
135 _has_dangerous_particles |= clust_seq.has_dangerous_particles();
139 _transfer_ghost_free_history(clust_seq);
141 unique_tree = unique_history_order();
145 _transfer_areas(unique_tree, clust_seq);
153 _average_area /= ghost_spec.repeat();
154 _average_area2 /= ghost_spec.repeat();
155 if (ghost_spec.repeat() > 1) {
158 const double tmp = ghost_spec.repeat()-1;
159 _average_area2 = sqrt(abs(_average_area2 - _average_area*_average_area)/tmp);
161 _average_area2 = 0.0;
164 _non_jet_area /= ghost_spec.repeat();
165 _non_jet_area2 /= ghost_spec.repeat();
166 _non_jet_area2 = sqrt(abs(_non_jet_area2 - _non_jet_area*_non_jet_area)/
167 ghost_spec.repeat());
168 _non_jet_number /= ghost_spec.repeat();
173 for (
unsigned i = 0; i < _average_area_4vector.size(); i++) {
174 _average_area_4vector[i] = (1.0/ghost_spec.repeat()) * _average_area_4vector[i];
276double ClusterSequenceActiveArea::pt_per_unit_area(
279 vector<PseudoJet> incl_jets = inclusive_jets();
280 vector<double> pt_over_areas;
282 for (
unsigned i = 0; i < incl_jets.size(); i++) {
283 if (abs(incl_jets[i].rap()) < _safe_rap_for_area) {
285 if ( strat == median_4vector ) {
286 this_area = area_4vector(incl_jets[i]).perp();
288 this_area = area(incl_jets[i]);
290 pt_over_areas.push_back(incl_jets[i].perp()/this_area);
295 if (pt_over_areas.size() == 0) {
return 0.0;}
300 sort(pt_over_areas.begin(), pt_over_areas.end());
301 double non_ghost_median_ratio = pt_over_areas[pt_over_areas.size()/2];
306 double nj_median_pos = (pt_over_areas.size()-1 - _non_jet_number)/2.0;
307 double nj_median_ratio;
308 if (nj_median_pos >= 0 && pt_over_areas.size() > 1) {
309 int int_nj_median = int(nj_median_pos);
311 pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos)
312 + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median);
314 nj_median_ratio = 0.0;
319 double pt_sum = 0.0, pt_sum_with_cut = 0.0;
320 double area_sum = _non_jet_area, area_sum_with_cut = _non_jet_area;
321 double ratio_sum = 0.0;
322 double ratio_n = _non_jet_number;
323 for (
unsigned i = 0; i < incl_jets.size(); i++) {
324 if (abs(incl_jets[i].rap()) < _safe_rap_for_area) {
326 if ( strat == median_4vector ) {
327 this_area = area_4vector(incl_jets[i]).perp();
329 this_area = area(incl_jets[i]);
331 pt_sum += incl_jets[i].perp();
332 area_sum += this_area;
333 double ratio = incl_jets[i].perp()/this_area;
334 if (ratio < range*nj_median_ratio) {
335 pt_sum_with_cut += incl_jets[i].perp();
336 area_sum_with_cut += this_area;
337 ratio_sum += ratio; ratio_n++;
343 double trunc_sum = 0, trunc_sumsqr = 0;
344 vector<double> means(pt_over_areas.size()), sd(pt_over_areas.size());
345 for (
unsigned i = 0; i < pt_over_areas.size() ; i++ ) {
346 double ratio = pt_over_areas[i];
348 trunc_sumsqr += ratio*ratio;
349 means[i] = trunc_sum / (i+1);
350 sd[i] = sqrt(abs(means[i]*means[i] - trunc_sumsqr/(i+1)));
351 cerr <<
"i, means, sd: " <<i<<
", "<< means[i] <<
", "<<sd[i]<<
", "<<
352 sd[i]/sqrt(i+1.0)<<endl;
354 cout <<
"-----------------------------------"<<endl;
355 for (
unsigned i = 0; i <= pt_over_areas.size()/2 ; i++ ) {
356 cout <<
"Median "<< i <<
" = " << pt_over_areas[i]<<endl;
358 cout <<
"Number of non-jets: "<<_non_jet_number<<endl;
359 cout <<
"Area of non-jets: "<<_non_jet_area<<endl;
360 cout <<
"Default median position: " << (pt_over_areas.size()-1)/2.0<<endl;
361 cout <<
"NJ median position: " << nj_median_pos <<endl;
362 cout <<
"NJ median value: " << nj_median_ratio <<endl;
369 return nj_median_ratio;
370 case non_ghost_median:
371 return non_ghost_median_ratio;
372 case pttot_over_areatot:
373 return pt_sum / area_sum;
374 case pttot_over_areatot_cut:
375 return pt_sum_with_cut / area_sum_with_cut;
377 return ratio_sum/ratio_n;
379 return nj_median_ratio;
445double ClusterSequenceActiveArea::empty_area(
const Selector & selector)
const {
448 throw Error(
"ClusterSequenceActiveArea: empty area can only be computed from selectors applying jet by jet");
453 for (
unsigned i = 0; i < _ghost_jets.size(); i++) {
454 if (selector.
pass(_ghost_jets[i])) {
455 empty += _ghost_jets[i].area;
459 for (
unsigned i = 0; i < _unclustered_ghosts.size(); i++) {
460 if (selector.
pass(_unclustered_ghosts[i])) {
461 empty += _unclustered_ghosts[i].area;
464 empty /= _ghost_spec_repeat;
469double ClusterSequenceActiveArea::n_empty_jets(
const Selector & selector)
const {
470 _check_selector_good_for_median(selector);
473 for (
unsigned i = 0; i < _ghost_jets.size(); i++) {
474 if (selector.
pass(_ghost_jets[i])) inrange++;
476 inrange /= _ghost_spec_repeat;
483void ClusterSequenceActiveArea::_transfer_ghost_free_history(
486 const vector<history_element> & gs_history = ghosted_seq.
history();
487 vector<int> gs2self_hist_map(gs_history.size());
496 while (igs < gs_history.size() && gs_history[igs].parent1 == InexistentParent) {
499 gs2self_hist_map[igs] = iself++;
501 gs2self_hist_map[igs] = Invalid;
508 assert(iself == _history.size());
514 if (igs == gs_history.size())
return;
520 gs2self_hist_map[igs] = Invalid;
532 if (parent1_is_ghost && !parent2_is_ghost && gs_hist_el.
parent2 >= 0) {
533 gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.
parent2];
536 if (!parent1_is_ghost && parent2_is_ghost) {
537 gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.
parent1];
544 gs2self_hist_map[igs] = _history.size();
547 int jet_i = _history[gs2self_hist_map[gs_hist_el.
parent1]].jetp_index;
548 int jet_j = _history[gs2self_hist_map[gs_hist_el.
parent2]].jetp_index;
550 _do_ij_recombination_step(jet_i, jet_j, gs_hist_el.
dij, newjet_k);
553 assert(gs_history[igs].parent2 == BeamJet);
555 gs2self_hist_map[igs] = _history.size();
557 _do_iB_recombination_step(
558 _history[gs2self_hist_map[gs_hist_el.
parent1]].jetp_index,
561 }
while (++igs < gs_history.size());
566void ClusterSequenceActiveArea::_transfer_areas(
567 const vector<int> & unique_hist_order,
570 const vector<history_element> & gs_history = ghosted_seq.
history();
571 const vector<PseudoJet> & gs_jets = ghosted_seq.
jets();
574 const double tolerance = 1e-11;
579 valarray<double> our_areas(_history.size());
582 valarray<PseudoJet> our_area_4vectors(_history.size());
583 our_area_4vectors =
PseudoJet(0.0,0.0,0.0,0.0);
585 for (
unsigned i = 0; i < gs_history.size(); i++) {
587 unsigned gs_hist_index = gs_unique_hist_order[i];
588 if (gs_hist_index < ghosted_seq.
n_particles())
continue;
593 if (parent2 == BeamJet) {
596 gs_jets[gs_history[parent1].jetp_index];
597 double area_local = ghosted_seq.
area(jet);
602 _ghost_jets.push_back(GhostJet(jet,area_local));
603 if (abs(jet.
rap()) < _safe_rap_for_area) {
604 _non_jet_area += area_local;
605 _non_jet_area2 += area_local*area_local;
606 _non_jet_number += 1;
613 while (++j <
int(_history.size())) {
614 hist_index = unique_hist_order[j];
615 if (hist_index >= _initial_n)
break;}
618 if (j >=
int(_history.size()))
throw Error(
"ClusterSequenceActiveArea: overran reference array in diB matching");
622 int refjet_index = _history[_history[hist_index].parent1].jetp_index;
623 assert(refjet_index >= 0 && refjet_index <
int(_jets.size()));
624 const PseudoJet & refjet = _jets[refjet_index];
634 _throw_unless_jets_have_same_perp_or_E(jet, refjet, tolerance,
638 our_areas[hist_index] = area_local;
639 our_area_4vectors[hist_index] = ext_area;
645 our_areas[_history[hist_index].parent1] = area_local;
646 our_area_4vectors[_history[hist_index].parent1] = ext_area;
654 while (++j <
int(_history.size())) {
655 hist_index = unique_hist_order[j];
656 if (hist_index >= _initial_n)
break;}
659 if (j >=
int(_history.size()))
throw Error(
"ClusterSequenceActiveArea: overran reference array in dij matching");
664 if (_history[hist_index].parent2 == BeamJet)
throw Error(
"ClusterSequenceActiveArea: could not match clustering sequences (encountered dij matched with diB)");
671 const PseudoJet & refjet = _jets[_history[hist_index].jetp_index];
674 _throw_unless_jets_have_same_perp_or_E(jet, refjet, tolerance,
679 double area_local = ghosted_seq.
area(jet);
680 our_areas[hist_index] += area_local;
699 _jet_def.recombiner()->plus_equal(our_area_4vectors[hist_index], ext_area);
707 const PseudoJet & jet1 = gs_jets[gs_history[parent1].jetp_index];
708 int our_parent1 = _history[hist_index].parent1;
709 our_areas[our_parent1] = ghosted_seq.
area(jet1);
710 our_area_4vectors[our_parent1] = ghosted_seq.
area_4vector(jet1);
712 const PseudoJet & jet2 = gs_jets[gs_history[parent2].jetp_index];
713 int our_parent2 = _history[hist_index].parent2;
714 our_areas[our_parent2] = ghosted_seq.
area(jet2);
715 our_area_4vectors[our_parent2] = ghosted_seq.
area_4vector(jet2);
723 for (
unsigned iu = 0; iu < unclust.size(); iu++) {
725 double area_local = ghosted_seq.
area(unclust[iu]);
726 _unclustered_ghosts.push_back(GhostJet(unclust[iu],area_local));
738 for (
unsigned int area_index = 0; area_index<our_areas.size(); area_index++){
739 _average_area[area_index] += our_areas[area_index];
740 _average_area2[area_index] += our_areas[area_index]*our_areas[area_index];
746 for (
unsigned i = 0; i < our_area_4vectors.size(); i++) {
747 _jet_def.recombiner()->plus_equal(_average_area_4vector[i],
748 our_area_4vectors[i]);
756void ClusterSequenceActiveArea::_throw_unless_jets_have_same_perp_or_E(
765 && abs(jet.E()-refjet.E()) > tolerance*max(jet.E(),refjet.E())) {
767 ostr <<
"Could not match clustering sequence for an inclusive/exclusive jet when reconstructing areas. See FAQ for possible explanations." << endl;
769 << refjet.px() <<
" "
770 << refjet.py() <<
" "
771 << refjet.pz() <<
" "
772 << refjet.E() << endl;
779 ostr <<
" NB: some particles have pt too low wrt ghosts -- this may be the cause" << endl;}
782 throw Error(ostr.str());
Like ClusterSequence with computation of the active jet area with the addition of explicit ghosts.
virtual PseudoJet area_4vector(const PseudoJet &jet) const override
returns a four vector corresponding to the sum (E-scheme) of the ghost four-vectors composing the jet...
virtual double area(const PseudoJet &jet) const override
returns the area of a jet
virtual bool is_pure_ghost(const PseudoJet &jet) const override
true if a jet is made exclusively of ghosts
bool has_dangerous_particles() const
returns true if there are any particles whose transverse momentum if so low that there's a risk of th...
mean_pt_strategies
enum providing a variety of tentative strategies for estimating the background (e....
std::vector< PseudoJet > unclustered_particles() const
return the set of particles that have not been clustered.
std::vector< int > unique_history_order() const
routine that returns an order in which to read the history such that clusterings that lead to identic...
const std::vector< history_element > & history() const
allow the user to access the raw internal history.
unsigned int n_particles() const
returns the number of particles that were provided to the clustering algorithm (helps the user find t...
const std::vector< PseudoJet > & jets() const
allow the user to access the internally stored _jets() array, which contains both the initial particl...
Strategy strategy_used() const
return the enum value of the strategy used to cluster the event
base class corresponding to errors that can be thrown by FastJet
Parameters to configure the computation of jet areas using ghosts.
class that is intended to hold a full definition of the jet clusterer
Class to contain pseudojets, including minimal information of use to jet-clustering routines.
double rap() const
returns the rapidity or some large value when the rapidity is infinite
double perp2() const
returns the squared transverse momentum
Class that encodes information about cuts and other selection criteria that can be applied to PseudoJ...
bool pass(const PseudoJet &jet) const
return true if the jet passes the selection
bool applies_jet_by_jet() const
returns true if this can be applied jet by jet
a single element in the clustering history
int parent1
index in _history where first parent of this jet was created (InexistentParent if this jet is an orig...
int jetp_index
index in the _jets vector where we will find the PseudoJet object corresponding to this jet (i....
int parent2
index in _history where second parent of this jet was created (InexistentParent if this jet is an ori...
double dij
the distance corresponding to the recombination at this stage of the clustering.