Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

ClusterSequenceActiveArea.cc

Go to the documentation of this file.
00001 //STARTHEADER
00002 // $Id: ClusterSequenceActiveArea.cc 308 2006-08-24 09:41:01Z cacciari $
00003 //
00004 // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
00005 //
00006 //----------------------------------------------------------------------
00007 // This file is part of FastJet.
00008 //
00009 //  FastJet is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU General Public License as published by
00011 //  the Free Software Foundation; either version 2 of the License, or
00012 //  (at your option) any later version.
00013 //
00014 //  The algorithms that underlie FastJet have required considerable
00015 //  development and are described in hep-ph/0512210. If you use
00016 //  FastJet as part of work towards a scientific publication, please
00017 //  include a citation to the FastJet paper.
00018 //
00019 //  FastJet is distributed in the hope that it will be useful,
00020 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 //  GNU General Public License for more details.
00023 //
00024 //  You should have received a copy of the GNU General Public License
00025 //  along with FastJet; if not, write to the Free Software
00026 //  Foundation, Inc.:
00027 //      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028 //----------------------------------------------------------------------
00029 //ENDHEADER
00030 
00031 #include "fastjet/PseudoJet.hh"
00032 #include "fastjet/ClusterSequence.hh"
00033 #include "fastjet/ClusterSequenceActiveArea.hh"
00034 #include "fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
00035 #include<iostream>
00036 #include<vector>
00037 
00038 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00039 
00040 
00041 using namespace std;
00042 
00043 
00044 //int ClusterSequenceActiveArea::_n_seed_warnings = 0;
00045 //const int _max_seed_warnings = 10;
00046 
00047 void ClusterSequenceActiveArea::_initialise_and_run_AA (
00048                 const JetDefinition & jet_def,
00049                 const ActiveAreaSpec & area_spec,
00050                 const bool & writeout_combinations) 
00051 {
00052 
00053   // initialize our local area information
00054   _average_area.resize(2*_jets.size());  _average_area  = 0.0;
00055   _average_area2.resize(2*_jets.size()); _average_area2 = 0.0;
00056   _average_area_4vector.resize(2*_jets.size()); 
00057   _average_area_4vector = PseudoJet(0.0,0.0,0.0,0.0);
00058   _non_jet_area = 0.0; _non_jet_area2 = 0.0; _non_jet_number=0.0;
00059      
00060   // for future reference...
00061   _etamax_for_area = area_spec.ghost_etamax();
00062   _etalim_for_area = _etamax_for_area - jet_def.R();
00063 
00064   // Make sure we'll have at least one repetition -- then we can
00065   // deduce the unghosted clustering sequence from one of the ghosted
00066   // sequences. If we do not have any repetitions, then get the
00067   // unghosted sequence from the plain unghosted clustering.
00068   //
00069   // NB: all decanting and filling of initial history will then
00070   // be carried out by base-class routine
00071   if (area_spec.repeat() <= 0) {
00072     _initialise_and_run(jet_def, writeout_combinations);
00073     return;
00074   }
00075 
00076   // transfer all relevant info into internal variables
00077   _decant_options(jet_def, writeout_combinations);
00078 
00079   // set up the history entries for the initial particles (those
00080   // currently in _jets)
00081   _fill_initial_history();
00082 
00083   // record the input jets as they are currently
00084   vector<PseudoJet> input_jets(_jets);
00085 
00086   // code for testing the unique tree
00087   vector<int> unique_tree;
00088 
00089   
00090   
00091 
00092   // run the clustering multiple times so as to get areas of all the jets
00093   for (int irepeat = 0; irepeat < area_spec.repeat(); irepeat++) {
00094 
00095     ClusterSequenceActiveAreaExplicitGhosts clust_seq(input_jets, 
00096                                                       jet_def, area_spec);
00097 
00098     if (irepeat == 0) {
00099       // take the non-ghost part of the history and put into our own
00100       // history.
00101       _transfer_ghost_free_history(clust_seq);
00102       // get the "unique" order that will be used for transferring all areas. 
00103       unique_tree = unique_history_order();
00104     }
00105 
00106     // transfer areas from clust_seq into our object
00107     _transfer_areas(unique_tree, clust_seq);
00108   }
00109   
00110   _average_area  /= area_spec.repeat();
00111   _average_area2 /= area_spec.repeat();
00112   if (area_spec.repeat() > 1) {
00113     _average_area2 = sqrt(abs(_average_area2 - _average_area*_average_area)/
00114                           (area_spec.repeat()-1));
00115   } else {
00116     _average_area2 = 0.0;
00117   }
00118 
00119   _non_jet_area  /= area_spec.repeat();
00120   _non_jet_area2 /= area_spec.repeat();
00121   _non_jet_area2  = sqrt(abs(_non_jet_area2 - _non_jet_area*_non_jet_area)/
00122                          area_spec.repeat());
00123   _non_jet_number /= area_spec.repeat();
00124 
00125   // following bizarre way of writing things is related to 
00126   // poverty of operations on PseudoJet objects (as well as some confusion
00127   // in one or two places)
00128   for (unsigned i = 0; i < _average_area_4vector.size(); i++) {
00129     _average_area_4vector[i] = (1.0/area_spec.repeat()) * _average_area_4vector[i];
00130   }
00131   //cerr << "Non-jet area = " << _non_jet_area << " +- " << _non_jet_area2<<endl;
00132 
00133   
00134 }
00135 
00136 
00137 //----------------------------------------------------------------------
00138 double ClusterSequenceActiveArea::pt_per_unit_area(
00139                        mean_pt_strategies strat, double range) const {
00140   
00141   vector<PseudoJet> incl_jets = inclusive_jets();
00142   vector<double> pt_over_areas;
00143 
00144   for (unsigned i = 0; i < incl_jets.size(); i++) {
00145     if (abs(incl_jets[i].rap()) < _etalim_for_area) {
00146       double this_area = area(incl_jets[i]);
00147       pt_over_areas.push_back(incl_jets[i].perp()/this_area);
00148     }
00149   }
00150   
00151   // there is nothing inside our region, so answer will always be zero
00152   if (pt_over_areas.size() == 0) {return 0.0;}
00153   
00154   // get median (pt/area) [this is the "old" median definition. It considers
00155   // only the "real" jets in calculating the median, i.e. excluding the
00156   // only-ghost ones]
00157   sort(pt_over_areas.begin(), pt_over_areas.end());
00158   double non_ghost_median_ratio = pt_over_areas[pt_over_areas.size()/2];
00159 
00160   // new median definition that takes into account non-jet area (i.e.
00161   // jets composed only of ghosts), and for fractional median position 
00162   // interpolates between the corresponding entries in the pt_over_areas array
00163   double nj_median_pos = (pt_over_areas.size()-1 - _non_jet_number)/2.0;
00164   double nj_median_ratio;
00165   if (nj_median_pos >= 0 && pt_over_areas.size() > 1) {
00166     int int_nj_median = int(nj_median_pos);
00167     nj_median_ratio = 
00168       pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos)
00169       + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median);
00170   } else {
00171     nj_median_ratio = 0.0;
00172   }
00173 
00174 
00175   // get various forms of mean (pt/area)
00176   double pt_sum = 0.0, pt_sum_with_cut = 0.0;
00177   double area_sum = _non_jet_area, area_sum_with_cut = _non_jet_area;
00178   double ratio_sum = 0.0; 
00179   double ratio_n = _non_jet_number;
00180   for (unsigned i = 0; i < incl_jets.size(); i++) {
00181     if (abs(incl_jets[i].rap()) < _etalim_for_area) {
00182       double this_area = area(incl_jets[i]);
00183       pt_sum   += incl_jets[i].perp();
00184       area_sum += this_area;
00185       double ratio = incl_jets[i].perp()/this_area;
00186       if (ratio < range*nj_median_ratio) {
00187         pt_sum_with_cut   += incl_jets[i].perp();
00188         area_sum_with_cut += this_area;
00189         ratio_sum += ratio; ratio_n++;
00190       }
00191     }
00192   }
00193   
00194   if (strat == play) {
00195     double trunc_sum = 0, trunc_sumsqr = 0;
00196     vector<double> means(pt_over_areas.size()), sd(pt_over_areas.size());
00197     for (unsigned i = 0; i < pt_over_areas.size() ; i++ ) {
00198       double ratio = pt_over_areas[i];
00199       trunc_sum += ratio;
00200       trunc_sumsqr += ratio*ratio;
00201       means[i] = trunc_sum / (i+1);
00202       sd[i]    = sqrt(abs(means[i]*means[i]  - trunc_sumsqr/(i+1)));
00203       cerr << "i, means, sd: " <<i<<", "<< means[i] <<", "<<sd[i]<<", "<<
00204         sd[i]/sqrt(i+1.0)<<endl;
00205     }
00206     cout << "-----------------------------------"<<endl;
00207     for (unsigned i = 0; i <= pt_over_areas.size()/2 ; i++ ) {
00208       cout << "Median "<< i <<" = " << pt_over_areas[i]<<endl;
00209     }
00210     cout << "Number of non-jets: "<<_non_jet_number<<endl;
00211     cout << "Area of non-jets: "<<_non_jet_area<<endl;
00212     cout << "Default median position: " << (pt_over_areas.size()-1)/2.0<<endl;
00213     cout << "NJ median position: " << nj_median_pos <<endl;
00214     cout << "NJ median value: " << nj_median_ratio <<endl;
00215     return 0.0;
00216   }
00217 
00218   switch(strat) {
00219   case median:
00220     return nj_median_ratio;
00221   case non_ghost_median:
00222     return non_ghost_median_ratio; 
00223   case pttot_over_areatot:
00224     return pt_sum / area_sum;
00225   case pttot_over_areatot_cut:
00226     return pt_sum_with_cut / area_sum_with_cut;
00227   case mean_ratio_cut:
00228     return ratio_sum/ratio_n;
00229   default:
00230     return nj_median_ratio;
00231   }
00232 
00233 }
00234 
00235 
00236 //----------------------------------------------------------------------
00237 // fit a parabola to pt/area as a function of rapidity, using the
00238 // formulae of CCN28-36 (which actually fits f = a+b*x^2)
00239 void ClusterSequenceActiveArea::parabolic_pt_per_unit_area(
00240        double & a, double & b, double raprange, double exclude_above) const {
00241   
00242   double this_raprange;
00243   if (raprange <= 0) {this_raprange = _etalim_for_area;}
00244   else {this_raprange = raprange;}
00245 
00246   int n=0;
00247   int n_excluded = 0;
00248   double mean_f=0, mean_x2=0, mean_x4=0, mean_fx2=0; 
00249 
00250   vector<PseudoJet> incl_jets = inclusive_jets();
00251 
00252   for (unsigned i = 0; i < incl_jets.size(); i++) {
00253     if (abs(incl_jets[i].rap()) < this_raprange) {
00254       double this_area = area(incl_jets[i]);
00255       double f = incl_jets[i].perp()/this_area;
00256       if (exclude_above <= 0.0 || f < exclude_above) {
00257         double x = incl_jets[i].rap(); double x2 = x*x;
00258         mean_f   += f;
00259         mean_x2  += x2;
00260         mean_x4  += x2*x2;
00261         mean_fx2 += f*x2;
00262         n++;
00263       } else {
00264         n_excluded++;
00265       }
00266     }
00267   }
00268 
00269   if (n <= 1) {
00270     // meaningful results require at least two jets inside the
00271     // area -- mind you if there are empty jets we should be in 
00272     // any case doing something special...
00273     a = 0.0;
00274     b = 0.0;
00275   } else {
00276     mean_f   /= n;
00277     mean_x2  /= n;
00278     mean_x4  /= n;
00279     mean_fx2 /= n;
00280     
00281     b = (mean_f*mean_x2 - mean_fx2)/(mean_x2*mean_x2 - mean_x4);
00282     a = mean_f - b*mean_x2;
00283   }
00284   //cerr << "n_excluded = "<< n_excluded << endl;
00285 }
00286 
00287 
00288 //----------------------------------------------------------------------
00291 void ClusterSequenceActiveArea::_transfer_ghost_free_history(
00292              const ClusterSequenceActiveAreaExplicitGhosts & ghosted_seq) {
00293   
00294   const vector<history_element> & gs_history  = ghosted_seq.history();
00295   vector<int> gs2self_hist_map(gs_history.size());
00296 
00297   // work our way through to first non-trivial combination
00298   unsigned igs = 0;
00299   unsigned iself = 0;
00300   while (gs_history[igs].parent1 == InexistentParent) {
00301     // record correspondence 
00302     if (!ghosted_seq.is_pure_ghost(igs)) {
00303       gs2self_hist_map[igs] = iself++; 
00304     } else {
00305       gs2self_hist_map[igs] = Invalid; 
00306     }
00307     igs++;
00308   };
00309 
00310   // make sure the count of non-ghost initial jets is equal to
00311   // what we already have in terms of initial jets
00312   assert(iself == _history.size());
00313 
00314   // now actually transfer things
00315   do  {
00316     // if we are a pure ghost, then go on to next round
00317     if (ghosted_seq.is_pure_ghost(igs)) {
00318       gs2self_hist_map[igs] = Invalid;
00319       continue;
00320     }
00321 
00322     const history_element & gs_hist_el = gs_history[igs];
00323 
00324     bool parent1_is_ghost = ghosted_seq.is_pure_ghost(gs_hist_el.parent1);
00325     bool parent2_is_ghost = ghosted_seq.is_pure_ghost(gs_hist_el.parent2);
00326 
00327     // if exactly one parent is a ghost then maintain info about the
00328     // non-ghost correspondence for this jet, and then go on to next
00329     // recombination in the ghosted sequence
00330     if (parent1_is_ghost && !parent2_is_ghost && gs_hist_el.parent2 >= 0) {
00331       gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.parent2];
00332       continue;
00333     }
00334     if (!parent1_is_ghost && parent2_is_ghost) {
00335       gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.parent1];
00336       continue;
00337     }
00338 
00339     // no parents are ghosts...
00340     if (gs_hist_el.parent2 >= 0) {
00341       // recombination of two non-ghosts
00342       gs2self_hist_map[igs] = _history.size();
00343       // record the recombination in our own sequence
00344       int newjet_k; // dummy var -- not used
00345       //cerr << igs << " " << gs_hist_el.parent1 << " " << gs_hist_el.parent2 << endl;
00346       //cerr << gs2self_hist_map[gs_hist_el.parent1] << " " << gs2self_hist_map[gs_hist_el.parent2] << endl;
00347       int jet_i = _history[gs2self_hist_map[gs_hist_el.parent1]].jetp_index;
00348       int jet_j = _history[gs2self_hist_map[gs_hist_el.parent2]].jetp_index;
00349       //cerr << "recombining "<< jet_i << " and "<< jet_j << endl;
00350       _do_ij_recombination_step(jet_i, jet_j, gs_hist_el.dij, newjet_k);
00351     } else {
00352       // we have a non-ghost that has become a beam-jet
00353       assert(gs_history[igs].parent2 == BeamJet);
00354       // record position
00355       gs2self_hist_map[igs] = _history.size();
00356       // record the recombination in our own sequence
00357       _do_iB_recombination_step(
00358              _history[gs2self_hist_map[gs_hist_el.parent1]].jetp_index,
00359              gs_hist_el.dij);
00360     }
00361   } while (++igs < gs_history.size());
00362 
00363   // finally transfer info about strategy used (which isn't necessarily
00364   // always the one that got asked for...)
00365   _strategy = ghosted_seq.strategy_used();
00366 }
00367 
00368 //----------------------------------------------------------------------
00369 void ClusterSequenceActiveArea::_transfer_areas(
00370             const vector<int> & unique_hist_order,
00371             const ClusterSequenceActiveAreaExplicitGhosts & ghosted_seq  ) {
00372 
00373   const vector<history_element> & gs_history  = ghosted_seq.history();
00374   const vector<PseudoJet>       & gs_jets     = ghosted_seq.jets();
00375   vector<int>    gs_unique_hist_order = ghosted_seq.unique_history_order();
00376 
00377   const double tolerance = 1e-13; // to decide when two jets are the same
00378 
00379   int j = -1;
00380   int hist_index = -1;
00381   
00382   valarray<double> our_areas(_history.size());
00383   our_areas = 0.0;
00384 
00385   valarray<PseudoJet> our_area_4vectors(_history.size());
00386   our_area_4vectors = PseudoJet(0.0,0.0,0.0,0.0);
00387 
00388   for (unsigned i = 0; i < gs_history.size(); i++) {
00389     // only consider composite particles
00390     unsigned gs_hist_index = gs_unique_hist_order[i];
00391     if (gs_hist_index < ghosted_seq.n_particles()) continue;
00392     const history_element & gs_hist = gs_history[gs_unique_hist_order[i]];
00393     int parent1 = gs_hist.parent1;
00394     int parent2 = gs_hist.parent2;
00395 
00396     if (parent2 == BeamJet) {
00397       // need to look at parent to get the actual jet
00398       const PseudoJet & jet = 
00399           gs_jets[gs_history[parent1].jetp_index];
00400       double area = ghosted_seq.area(jet);
00401       PseudoJet ext_area = ghosted_seq.area_4vector(jet);
00402 
00403       if (ghosted_seq.is_pure_ghost(parent1)) {
00404         if (abs(jet.rap()) < _etalim_for_area) {
00405           _non_jet_area  += area;
00406           _non_jet_area2 += area*area;
00407           _non_jet_number += 1;
00408         }
00409       } else {
00410 
00411         // get next "combined-particle" index in our own history
00412         // making sure we don't go beyond it's bounds (if we do
00413         // then we're in big trouble anyway...)
00414         while (++j < static_cast<int>(_history.size())) {
00415           hist_index = unique_hist_order[j];
00416           if (hist_index >= _initial_n) break;}
00417 
00418         // sanity check 
00419         const PseudoJet & refjet = 
00420           _jets[_history[_history[hist_index].parent1].jetp_index];
00421         //if (jet.perp2() != refjet.perp2()) {
00422         if (abs(jet.perp2()-refjet.perp2()) > 
00423                     tolerance*max(jet.perp2(),refjet.perp2())) {
00424           cerr << jet.perp() << " " << refjet.perp() << " "<< jet.perp() - refjet.perp() << endl;
00425           throw Error("Could not match clustering sequence for an inclusive jet when reconstructing areas"); }
00426 
00427         // set the area at this clustering stage
00428         our_areas[hist_index]  = area; 
00429         our_area_4vectors[hist_index]  = ext_area; 
00430 
00431         // update the parent as well -- that way its area is the area
00432         // immediately before clustering (i.e. resolve an ambiguity in
00433         // the Cambridge case and ensure in the kt case that the original
00434         // particles get a correct area)
00435         our_areas[_history[hist_index].parent1] = area;
00436         our_area_4vectors[_history[hist_index].parent1] = ext_area;
00437         
00438       }
00439     }
00440     else if (!ghosted_seq.is_pure_ghost(parent1) && 
00441              !ghosted_seq.is_pure_ghost(parent2)) {
00442 
00443       // get next "combined-particle" index in our own history
00444       while (++j < static_cast<int>(_history.size())) {
00445         hist_index = unique_hist_order[j];
00446         if (hist_index >= _initial_n) break;}
00447       
00448       const PseudoJet & jet = gs_jets[gs_hist.jetp_index];
00449       const PseudoJet & refjet = _jets[_history[hist_index].jetp_index];
00450 
00451       // run sanity check 
00452       if (abs(jet.perp2()-refjet.perp2()) > 
00453           tolerance*max(jet.perp2(),refjet.perp2())) {
00454           cerr << jet.perp() << " " << refjet.perp() << " "<< jet.perp() - refjet.perp() << endl;
00455           throw Error("Could not match clustering sequence for an exclusive jet when reconstructing areas"); }
00456 
00457       // update area and our local index (maybe redundant since later
00458       // the descendants will reupdate it?)
00459       double area  = ghosted_seq.area(jet);
00460       our_areas[hist_index]  += area; 
00461 
00462       PseudoJet ext_area = ghosted_seq.area_4vector(jet);
00463       our_area_4vectors[hist_index] = our_area_4vectors[hist_index] + ext_area; 
00464 
00465       // now update areas of parents (so that they becomes areas
00466       // immediately before clustering occurred). This is of use
00467       // because it allows us to set the areas of the original hard
00468       // particles in the kt algorithm; for the Cambridge case it
00469       // means a jet's area will be the area just before it clusters
00470       // with another hard jet.
00471       const PseudoJet & jet1 = gs_jets[gs_history[parent1].jetp_index];
00472       int our_parent1 = _history[hist_index].parent1;
00473       our_areas[our_parent1] = ghosted_seq.area(jet1);
00474       our_area_4vectors[our_parent1] = ghosted_seq.area_4vector(jet1);
00475 
00476       const PseudoJet & jet2 = gs_jets[gs_history[parent2].jetp_index];
00477       int our_parent2 = _history[hist_index].parent2;
00478       our_areas[our_parent2] = ghosted_seq.area(jet2);
00479       our_area_4vectors[our_parent2] = ghosted_seq.area_4vector(jet2);
00480     }
00481 
00482   }
00483 
00484   _average_area  += our_areas; 
00485   _average_area2 += our_areas*our_areas; 
00486 
00487   // poverty of operators forces us to write things this way...
00488   //_average_area_4vector = _average_area_4vector + our_area_4vectors;
00489   _average_area_4vector += our_area_4vectors;
00490   
00491 }
00492 
00493 
00494 
00495 FASTJET_END_NAMESPACE
00496 

Generated on Thu Oct 12 17:36:34 2006 for fastjet by  doxygen 1.4.2