31#include "fastjet/PseudoJet.hh"
32#include "fastjet/ClusterSequence.hh"
33#include "fastjet/ClusterSequenceActiveArea.hh"
34#include "fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
42FASTJET_BEGIN_NAMESPACE
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) {
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);
154 _average_area2 /= ghost_spec.repeat();
155 if (ghost_spec.repeat() > 1) {
158 const double tmp = ghost_spec.repeat()-1;
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];
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 ) {
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 ) {
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;
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;
473 for (
unsigned i = 0; i < _ghost_jets.size(); i++) {
474 if (selector.
pass(_ghost_jets[i])) inrange++;
476 inrange /= _ghost_spec_repeat;
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;
514 if (igs == gs_history.size())
return;
520 gs2self_hist_map[igs] = Invalid;
526 bool parent1_is_ghost = ghosted_seq.
is_pure_ghost(gs_hist_el.parent1);
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;
553 assert(gs_history[igs].parent2 == BeamJet);
555 gs2self_hist_map[igs] =
_history.size();
558 _history[gs2self_hist_map[gs_hist_el.parent1]].jetp_index,
561 }
while (++igs < gs_history.size());
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;
590 int parent1 = gs_hist.parent1;
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");
623 assert(refjet_index >= 0 && refjet_index <
int(
_jets.size()));
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)");
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++){
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...
void _postprocess_AA(const GhostedAreaSpec &ghost_spec)
run the postprocessing for the active area (and derived classes)
void _transfer_ghost_free_history(const ClusterSequenceActiveAreaExplicitGhosts &clust_seq)
transfer the history (and jet-momenta) from clust_seq to our own internal structure while removing gh...
virtual PseudoJet area_4vector(const PseudoJet &jet) const override
return a PseudoJet whose 4-vector is defined by the following integral
virtual double n_empty_jets(const Selector &selector) const override
return the true number of empty jets (replaces ClusterSequenceAreaBase::n_empty_jets(....
mean_pt_strategies
enum providing a variety of tentative strategies for estimating the background (e....
double pt_per_unit_area(mean_pt_strategies strat=median, double range=2.0) const
return the transverse momentum per unit area according to one of the above strategies; for some strat...
virtual double area(const PseudoJet &jet) const override
return the area associated with the given jet; this base class returns 0.
virtual double empty_area(const Selector &selector) const override
rewrite the empty area from the parent class, so as to use all info at our disposal return the total ...
std::valarray< double > _average_area
child classes benefit from having these at their disposal
void _initialise_and_run_AA(const JetDefinition &jet_def, const GhostedAreaSpec &ghost_spec, const bool &writeout_combinations=false)
does the initialisation and running specific to the active areas class
void _transfer_areas(const std::vector< int > &unique_hist_order, const ClusterSequenceActiveAreaExplicitGhosts &)
transfer areas from the ClusterSequenceActiveAreaExplicitGhosts object into our internal area bookkee...
void _check_selector_good_for_median(const Selector &selector) const
check the selector is suited for the computations i.e. applies jet by jet and has a finite area
std::vector< PseudoJet > unclustered_particles() const
return the set of particles that have not been clustered.
std::vector< history_element > _history
this vector will contain the branching history; for each stage, _history[i].jetp_index indicates wher...
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...
void _do_ij_recombination_step(const int jet_i, const int jet_j, const double dij, int &newjet_k)
carry out the recombination between the jets numbered jet_i and jet_j, at distance scale dij; return ...
void _do_iB_recombination_step(const int jet_i, const double diB)
carry out an recombination step in which _jets[jet_i] merges with the beam,
std::vector< PseudoJet > inclusive_jets(const double ptmin=0.0) const
return a vector of all jets (in the sense of the inclusive algorithm) with pt >= ptmin.
std::vector< PseudoJet > _jets
This contains the physical PseudoJets; for each PseudoJet one can find the corresponding position in ...
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 jetp_index
index in _history where the current jet is recombined with another jet to form its child.
int parent2
index in _history where first parent of this jet was created (InexistentParent if this jet is an orig...
double dij
index in the _jets vector where we will find the