FastJet 3.0alpha3
BackgroundEstimator.cc
00001 //STARTHEADER
00002 // $Id: BackgroundEstimator.cc 2188 2011-05-31 15:44:46Z soyez $
00003 //
00004 // Copyright (c) 2005-2011, Matteo Cacciari, Gavin Salam and Gregory Soyez
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 // design questions?
00032 //
00033 //  - keep the option to define things with just a Selector and a list of particles
00034 //    HOWTO:
00035 //     . ClusterSequenceArea:
00036 //        o impose an area for the Selector
00037 //        o if not relocatable, take ghosts maxrap from there
00038 //          otherwise, get it from the maxrap of the particles
00039 //          warn in the doc that one should set a decent maxrap
00040 //        o use kt, R=0.6
00041 //        o active_area_explicit_ghosts
00042 //        o have functions that allow to control the maxrap, the ghost area, the alg, R
00043 //
00044 //     . have a SharedPtr<ClusterSequenceArea> initialised only in that case
00045 //       remove the const CSA & _csa;
00046 //     . access the cs using 
00047 //         dynamic_cast<ClusterSequenceArea*>(_csw()->cs());
00048 //       
00049 //
00050 //  - use a default Selector: SelectorStrip(2.0) * !SelectorNHardest(2)
00051 
00052 #include "fastjet/tools/BackgroundEstimator.hh"
00053 #include <fastjet/ClusterSequenceAreaBase.hh>
00054 #include <fastjet/ClusterSequenceStructure.hh>
00055 #include <iostream>
00056 
00057 FASTJET_BEGIN_NAMESPACE     // defined in fastjet/internal/base.hh
00058 
00059 using namespace std;
00060 
00061 double BackgroundJetScalarPtDensity::result(const PseudoJet & jet) const {
00062   std::vector<PseudoJet> constituents = jet.constituents();
00063   double scalar_pt = 0;
00064   for (unsigned i = 0; i < constituents.size(); i++) {
00065     scalar_pt += pow(constituents[i].perp(), _pt_power);
00066   }
00067   return scalar_pt / jet.area();
00068 }
00069 
00070 
00071 //----------------------------------------------------------------------
00072 double BackgroundRescalingYPolynomial::result(const PseudoJet & jet) const {
00073   double y = jet.rap();
00074   double y2 = y*y;
00075   double rescaling = _a0 + _a1*y + _a2*y2 + _a3*y2*y + _a4*y2*y2;
00076   return rescaling;
00077 }
00078 
00079 /// allow for warnings
00080 LimitedWarning BackgroundEstimator::_warnings;
00081 LimitedWarning BackgroundEstimator::_warnings_zero_area;
00082 
00083 
00084 //---------------------------------------------------------------------
00085 // class BackgroundEstimator
00086 // Class to estimate the density of the background per unit area
00087 //---------------------------------------------------------------------
00088 
00089 // default ctor
00090 //  - csa        the ClusterSequenceArea to use
00091 //  - rho_range  the range over which jets will be considered
00092 BackgroundEstimator::BackgroundEstimator(const ClusterSequenceAreaBase &csa, const Selector &rho_range)
00093   : _rho_range(rho_range){
00094 
00095   // initialise things properly
00096   reset();
00097 
00098   // tell the BGE about the cluster sequence
00099   set_cluster_sequence(csa);
00100 }
00101 
00102 
00103 
00104 //----------------------------------------------------------------------
00105 // ctor from a list of jets
00106 //  - jets        the set of jets to use for the computation
00107 //  - rho_range   the range over which jets will be considered
00108 BackgroundEstimator::BackgroundEstimator(const vector<PseudoJet> &jets, const Selector &rho_range)
00109   : _rho_range(rho_range){
00110 
00111   // initialise things properly
00112   reset();
00113 }
00114 
00115 
00116 // default dtor
00117 BackgroundEstimator::~BackgroundEstimator(){
00118 
00119 }
00120 
00121 
00122 //----------------------------------------------------------------------
00123 void BackgroundEstimator::set_cluster_sequence(const ClusterSequenceAreaBase & csa) {
00124   _csi = csa.structure_shared_ptr();
00125 
00126   // sanity checks
00127   //---------------
00128   //  (i) check the alg is appropriate
00129   _check_jet_alg_good_for_median();
00130 
00131   //  (ii) check that, if there are no explicit ghosts, the selector has a finite area
00132   if ((!csa.has_explicit_ghosts()) && (!_rho_range.has_finite_area())){
00133     throw Error("BackgroundEstimator: either an area with explicit ghosts (recommended) or a Selector with finite area is needed (to allow for the computation of the empty area)");
00134   }
00135 
00136   // get the initial list of jets
00137   _included_jets = csa.inclusive_jets();
00138 
00139   _uptodate = false;
00140 }
00141 
00142 
00143 //----------------------------------------------------------------------
00144 void BackgroundEstimator::set_jets(const vector<PseudoJet> &jets) {
00145   
00146   if (! jets.size())
00147     throw Error("BackgroundEstimator::BackgroundEstimator: At least one jet is needed to compute the background properties");
00148 
00149   // sanity checks
00150   //---------------
00151   //  (o) check that there is an underlying CS shared by all the jets
00152   if (! (jets[0].has_associated_cluster_sequence()) && (jets[0].has_area()))
00153     throw Error("BackgroundEstimator::BackgroundEstimator: the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00154 
00155   _csi = jets[0].structure_shared_ptr();
00156   ClusterSequenceStructure * csi = dynamic_cast<ClusterSequenceStructure*>(_csi());
00157   const ClusterSequenceAreaBase * csab = csi->validated_csab();
00158 
00159   for (unsigned int i=1;i<jets.size(); i++){
00160     if (! jets[i].has_associated_cluster_sequence()) // area automatic if the next test succeeds
00161       throw Error("BackgroundEstimator::set_jets(...): the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00162 
00163     if (jets[i].structure_shared_ptr().get() != _csi.get())
00164       throw Error("BackgroundEstimator::set_jets(...): all the jets used to estimate the background properties must share the same ClusterSequence");
00165   }
00166 
00167   //  (i) check the alg is appropriate
00168   _check_jet_alg_good_for_median();
00169 
00170   //  (ii) check that, if there are no explicit ghosts, the selector has a finite area
00171   if ((!csab->has_explicit_ghosts()) && (!_rho_range.has_finite_area())){
00172     throw Error("BackgroundEstimator: either an area with explicit ghosts (recommended) or a Selector with finite area is needed (to allow for the computation of the empty area)");
00173   }
00174 
00175 
00176   // get the initial list of jets
00177   _included_jets = jets;
00178 
00179   // ensure recalculation of quantities that need it
00180   _uptodate = false;
00181 }
00182 
00183 
00184 //----------------------------------------------------------------------
00185 // for estimation using a relocatable selector (i.e. local range)
00186 // this allows to set its position. Note that this HAS to be called
00187 // before any attempt to compute the background properties
00188 void BackgroundEstimator::_recompute_if_needed(const PseudoJet &jet){
00189   // if the range is relocatable, handles its relocation
00190   if (_rho_range.takes_reference()){
00191     // check that the reference is not the same as the previous one
00192     // (would avoid an unnecessary recomputation)
00193     if (jet == _current_reference) return;
00194 
00195     // relocate the range and make sure things get recomputed the next
00196     // time one tries to get some information
00197     _rho_range.set_reference(jet);
00198     _uptodate=false;
00199   }
00200 
00201   _recompute_if_needed();
00202 }
00203 
00204 // reset to default values
00205 // 
00206 // set the variou options to their default values
00207 void BackgroundEstimator::reset(){
00208   // set the remaining default parameters
00209   set_use_area_4vector();  // true by default
00210   set_provide_fj2_sigma(false);
00211 
00212   // reset the computed values
00213   _rho = _sigma = 0.0;
00214   _n_jets_used = _n_empty_jets = 0;
00215   _empty_area = _mean_area = 0.0;
00216 
00217   _jet_density_class = 0; // null pointer
00218   _rescaling_class = 0;   // null pointer
00219 
00220   _uptodate = false;
00221 }
00222 
00223 
00224 // do the actual job
00225 void BackgroundEstimator::_compute() const {
00226   // check if the clustersequence is still valid
00227   _check_csa_alive();
00228 
00229   // fill the vector of pt/area (or the quantity from the jet density class) 
00230   //  - in the range
00231   vector<double> vector_for_median;
00232   double total_area  = 0.0;
00233   _n_jets_used = 0;
00234 
00235   // apply the selector to the included jets
00236   vector<PseudoJet> selected_jets = _rho_range(_included_jets);
00237 
00238   // compute the pt/area for the selected jets
00239   for (unsigned i = 0; i < selected_jets.size(); i++) {
00240     const PseudoJet & current_jet = selected_jets[i];
00241 
00242     double this_area = (_use_area_4vector) ? current_jet.area_4vector().perp() : current_jet.area(); 
00243 
00244     if (this_area>0){
00245       double median_input;
00246       if (_jet_density_class == 0) {
00247         median_input = current_jet.perp()/this_area;
00248       } else {
00249         median_input = (*_jet_density_class)(current_jet);
00250       }
00251       if (_rescaling_class != 0) {
00252         median_input /= (*_rescaling_class)(current_jet);
00253       }
00254       vector_for_median.push_back(median_input);
00255       total_area  += this_area;
00256       _n_jets_used++;
00257     } else {
00258       _warnings_zero_area.warn("BackgroundEstimator::_compute(...): discarded jet with zero area. Zero-area jets may be due to (i) too large a ghost area (ii) a jet being outside the ghost range (iii) the computation not being done using an appropriate algorithm (kt;C/A).");
00259     }
00260       
00261   }
00262   
00263   // there is nothing inside our region, so answer will always be zero
00264   if (vector_for_median.size() == 0) {
00265     _rho        = 0.0;
00266     _sigma      = 0.0;
00267     _mean_area  = 0.0;
00268     return;
00269   }
00270 
00271   // determine the number of empty jets
00272   const ClusterSequenceAreaBase * csab = (dynamic_cast<ClusterSequenceStructure*>(_csi()))->validated_csab();
00273   if (csab->has_explicit_ghosts()) {
00274     _empty_area = 0.0;
00275     _n_empty_jets = 0;
00276   } else {
00277     _empty_area = csab->empty_area(_rho_range);
00278     _n_empty_jets = csab->n_empty_jets(_rho_range);
00279   }
00280 
00281   double total_njets = _n_jets_used + _n_empty_jets;
00282   total_area  += _empty_area;
00283 
00284   double stand_dev;
00285   _median_and_stddev(vector_for_median, _n_empty_jets, _rho, stand_dev, 
00286                      _provide_fj2_sigma);
00287 
00288   // process and store the results (_rho was already stored above)
00289   _mean_area  = total_area / total_njets;
00290   _sigma      = stand_dev * sqrt(_mean_area);
00291 
00292   // record that the computation has been performed  
00293   _uptodate = true;
00294 }
00295 
00296 //----------------------------------------------------------------------
00297 void BackgroundEstimator::_median_and_stddev(const vector<double> & quantity_vector, 
00298                                              double n_empty_jets, 
00299                                              double & median, 
00300                                              double & stand_dev_if_gaussian,
00301                                              bool do_fj2_calculation) const {
00302 
00303   // this check is redundant (the code below behaves sensibly even
00304   // with a zero size), but serves as a reminder of what happens if
00305   // the quantity vector is zero-sized
00306   if (quantity_vector.size() == 0) {
00307     median = 0;
00308     stand_dev_if_gaussian = 0;
00309     return;
00310   }
00311 
00312   vector<double> sorted_quantity_vector = quantity_vector;
00313   sort(sorted_quantity_vector.begin(), sorted_quantity_vector.end());
00314 
00315   // now get the median & error, accounting for empty jets
00316   // define the fractions of distribution at median, median-1sigma
00317   double posn[2] = {0.5, (1.0-0.6827)/2.0};
00318   double res[2];
00319 
00320   int n_jets_used = sorted_quantity_vector.size();
00321   double total_njets = n_jets_used + _n_empty_jets;
00322 
00323   for (int i = 0; i < 2; i++) {
00324     double nj_median_pos;
00325     if (do_fj2_calculation) {
00326       nj_median_pos = (total_njets-1)*posn[i] - n_empty_jets;
00327     } else {
00328       nj_median_pos = (total_njets)*posn[i] - n_empty_jets - 0.5;
00329     }
00330 
00331     double nj_median_ratio;
00332     if (nj_median_pos >= 0 && sorted_quantity_vector.size() > 1) {
00333       int int_nj_median = int(nj_median_pos);
00334       nj_median_ratio =
00335         sorted_quantity_vector[int_nj_median] * (int_nj_median+1-nj_median_pos)
00336         + sorted_quantity_vector[int_nj_median+1] * (nj_median_pos - int_nj_median);
00337     } else if (nj_median_pos > -0.5 && sorted_quantity_vector.size() >= 1 && !do_fj2_calculation) {
00338       // in the LHS of this "bin", just keep a constant value (we could have
00339       // interpolated to zero, but this might misbehave in cases where all jets
00340       // are active, because it would go to zero too fast)
00341       nj_median_ratio = sorted_quantity_vector[0];
00342     } else {
00343       nj_median_ratio = 0.0;
00344     }
00345     res[i] = nj_median_ratio;
00346   }
00347   
00348   median = res[0];
00349   stand_dev_if_gaussian = res[0] - res[1];
00350 }
00351 
00352 
00353 // check that the underlying structure is still alive;
00354 // throw an error otherwise
00355 void BackgroundEstimator::_check_csa_alive() const{
00356   ClusterSequenceStructure* csa = dynamic_cast<ClusterSequenceStructure*>(_csi());
00357   if (csa == 0) {
00358     throw Error("BackgroundEstimator: there is no cluster sequence associated with the BackgroundEstimator");
00359   }
00360   if (! dynamic_cast<ClusterSequenceStructure*>(_csi())->has_associated_cluster_sequence())
00361     throw Error("BackgroundEstimator: modifications are no longer possible as the underlying ClusterSequence has gone out of scope");
00362 }
00363 
00364 
00365 // check that the algorithm used for the clustering is suitable for
00366 // background estimation (i.e. either kt or C/A).
00367 // Issue a warning otherwise
00368 void BackgroundEstimator::_check_jet_alg_good_for_median() const{
00369   const ClusterSequence * cs = dynamic_cast<ClusterSequenceStructure*>(_csi())->validated_cs();
00370 
00371   if (cs->jet_def().jet_algorithm() != kt_algorithm
00372       && cs->jet_def().jet_algorithm() != cambridge_algorithm
00373       && cs->jet_def().jet_algorithm() != cambridge_for_passive_algorithm) {
00374     _warnings.warn("BackgroundEstimator: jet_def being used may not be suitable for estimating diffuse backgrounds (good alternatives are kt, cam)");
00375   }
00376 }
00377 
00378 
00379 
00380 
00381 FASTJET_END_NAMESPACE
00382 
00383 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends