FastJet 3.0beta1
JetMedianBackgroundEstimator.cc
00001 //STARTHEADER
00002 // $Id: JetMedianBackgroundEstimator.cc 2472 2011-07-26 11:25:42Z cacciari $
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 #include "fastjet/tools/JetMedianBackgroundEstimator.hh"
00032 #include <fastjet/ClusterSequenceArea.hh>
00033 #include <fastjet/ClusterSequenceStructure.hh>
00034 #include <iostream>
00035 
00036 FASTJET_BEGIN_NAMESPACE     // defined in fastjet/internal/base.hh
00037 
00038 using namespace std;
00039 
00040 double BackgroundJetScalarPtDensity::result(const PseudoJet & jet) const {
00041   std::vector<PseudoJet> constituents = jet.constituents();
00042   double scalar_pt = 0;
00043   for (unsigned i = 0; i < constituents.size(); i++) {
00044     scalar_pt += pow(constituents[i].perp(), _pt_power);
00045   }
00046   return scalar_pt / jet.area();
00047 }
00048 
00049 
00050 //----------------------------------------------------------------------
00051 double BackgroundRescalingYPolynomial::result(const PseudoJet & jet) const {
00052   double y = jet.rap();
00053   double y2 = y*y;
00054   double rescaling = _a0 + _a1*y + _a2*y2 + _a3*y2*y + _a4*y2*y2;
00055   return rescaling;
00056 }
00057 
00058 /// allow for warnings
00059 LimitedWarning JetMedianBackgroundEstimator::_warnings;
00060 LimitedWarning JetMedianBackgroundEstimator::_warnings_zero_area;
00061 LimitedWarning JetMedianBackgroundEstimator::_warnings_preliminary;
00062 
00063 
00064 //---------------------------------------------------------------------
00065 // class JetMedianBackgroundEstimator
00066 // Class to estimate the density of the background per unit area
00067 //---------------------------------------------------------------------
00068 
00069 //----------------------------------------------------------------------
00070 // ctors and dtors
00071 //----------------------------------------------------------------------
00072 // ctor that allows to set only the particles later on
00073 JetMedianBackgroundEstimator::JetMedianBackgroundEstimator(const Selector &rho_range,
00074                                          const JetDefinition &jet_def,
00075                                          const AreaDefinition &area_def)
00076   : _rho_range(rho_range), _jet_def(jet_def), _area_def(area_def) {
00077 
00078   // initialise things decently
00079   reset();
00080 
00081   // make a few checks
00082   _check_jet_alg_good_for_median();
00083 }
00084 
00085 
00086 //----------------------------------------------------------------------
00087 // ctor from a cluster sequence
00088 //  - csa        the ClusterSequenceArea to use
00089 //  - rho_range  the Selector specifying which jets will be considered
00090 JetMedianBackgroundEstimator::JetMedianBackgroundEstimator( const Selector &rho_range, const ClusterSequenceAreaBase &csa)
00091   : _rho_range(rho_range), _jet_def(JetDefinition()){
00092 
00093   // initialise things properly
00094   reset();
00095 
00096   // tell the BGE about the cluster sequence
00097   set_cluster_sequence(csa);
00098 }
00099 
00100 
00101 //----------------------------------------------------------------------
00102 // setting a new event
00103 //----------------------------------------------------------------------
00104 // tell the background estimator that it has a new event, composed
00105 // of the specified particles.
00106 void JetMedianBackgroundEstimator::set_particles(const vector<PseudoJet> & particles) {
00107   // make sure that we have been provided a genuine jet definition 
00108   if (_jet_def.jet_algorithm() == undefined_jet_algorithm)
00109     throw Error("JetMedianBackgroundEstimator::set_particles can only be called if you set the jet (and area) definition explicitly through the class constructor");
00110 
00111   // initialise things decently (including setting uptodate to false!)
00112   reset();
00113 
00114   // cluster the particles
00115   // 
00116   // One may argue that it is better to cache the particles and only
00117   // do the clustering later but clustering the particles now has 2
00118   // practical advantages:
00119   //  - it allows to une only '_included_jets' in all that follows
00120   //  - it avoids adding another flag to ensure particles are 
00121   //    clustered only once
00122   ClusterSequenceArea *csa = new ClusterSequenceArea(particles, _jet_def, _area_def);
00123   _included_jets = csa->inclusive_jets();
00124 
00125   // store the CS for later on
00126   _csi = csa->structure_shared_ptr();
00127   csa->delete_self_when_unused();
00128 }
00129 
00130 //----------------------------------------------------------------------
00131 // (re)set the cluster sequence (with area support) to be used by
00132 // future calls to rho() etc. 
00133 //
00134 // \param csa  the cluster sequence area
00135 //
00136 // Pre-conditions: 
00137 //  - one should be able to estimate the "empty area" (i.e. the area
00138 //    not occupied by jets). This is feasible if at least one of the following
00139 //    conditions is satisfied:
00140 //     ( i) the ClusterSequence has explicit ghosts
00141 //     (ii) the range selected has a computable area.
00142 //  - the jet algorithm must be suited for median computation
00143 //    (otherwise a warning will be issues)
00144 //
00145 // Note that selectors with e.g. hardest-jets exclusion do not have
00146 // a well-defined area. For this reasons, it is STRONGLY advised to
00147 // use an area with explicit ghosts.
00148 void JetMedianBackgroundEstimator::set_cluster_sequence(const ClusterSequenceAreaBase & csa) {
00149   _csi = csa.structure_shared_ptr();
00150 
00151   // sanity checks
00152   //---------------
00153   //  (i) check the alg is appropriate
00154   _check_jet_alg_good_for_median();
00155 
00156   //  (ii) check that, if there are no explicit ghosts, the selector has a finite area
00157   if ((!csa.has_explicit_ghosts()) && (!_rho_range.has_finite_area())){
00158     throw Error("JetMedianBackgroundEstimator: either an area with explicit ghosts (recommended) or a Selector with finite area is needed (to allow for the computation of the empty area)");
00159   }
00160 
00161   // get the initial list of jets
00162   _included_jets = csa.inclusive_jets();
00163 
00164   _uptodate = false;
00165 }
00166 
00167 
00168 //----------------------------------------------------------------------
00169 // (re)set the jets (which must have area support) to be used by future
00170 // calls to rho() etc.; for the conditions that must be satisfied
00171 // by the jets, see the Constructor that takes jets.
00172 void JetMedianBackgroundEstimator::set_jets(const vector<PseudoJet> &jets) {
00173   
00174   if (! jets.size())
00175     throw Error("JetMedianBackgroundEstimator::JetMedianBackgroundEstimator: At least one jet is needed to compute the background properties");
00176 
00177   // sanity checks
00178   //---------------
00179   //  (o) check that there is an underlying CS shared by all the jets
00180   if (! (jets[0].has_associated_cluster_sequence()) && (jets[0].has_area()))
00181     throw Error("JetMedianBackgroundEstimator::JetMedianBackgroundEstimator: the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00182 
00183   _csi = jets[0].structure_shared_ptr();
00184   ClusterSequenceStructure * csi = dynamic_cast<ClusterSequenceStructure*>(_csi());
00185   const ClusterSequenceAreaBase * csab = csi->validated_csab();
00186 
00187   for (unsigned int i=1;i<jets.size(); i++){
00188     if (! jets[i].has_associated_cluster_sequence()) // area automatic if the next test succeeds
00189       throw Error("JetMedianBackgroundEstimator::set_jets(...): the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00190 
00191     if (jets[i].structure_shared_ptr().get() != _csi.get())
00192       throw Error("JetMedianBackgroundEstimator::set_jets(...): all the jets used to estimate the background properties must share the same ClusterSequence");
00193   }
00194 
00195   //  (i) check the alg is appropriate
00196   _check_jet_alg_good_for_median();
00197 
00198   //  (ii) check that, if there are no explicit ghosts, the selector has a finite area
00199   if ((!csab->has_explicit_ghosts()) && (!_rho_range.has_finite_area())){
00200     throw Error("JetMedianBackgroundEstimator: either an area with explicit ghosts (recommended) or a Selector with finite area is needed (to allow for the computation of the empty area)");
00201   }
00202 
00203 
00204   // get the initial list of jets
00205   _included_jets = jets;
00206 
00207   // ensure recalculation of quantities that need it
00208   _uptodate = false;
00209 }
00210 
00211 
00212 //----------------------------------------------------------------------
00213 // retrieving fundamental information
00214 //----------------------------------------------------------------
00215 
00216 // get rho, the median background density per unit area
00217 double JetMedianBackgroundEstimator::rho() const {
00218   if (_rho_range.takes_reference())
00219     throw Error("The background estimation is obtained from a selector that takes a reference jet. rho(PseudoJet) should be used in that case");
00220   _recompute_if_needed();
00221   return _rho;
00222 }
00223 
00224 // get sigma, the background fluctuations per unit area
00225 double JetMedianBackgroundEstimator::sigma() const {
00226   if (_rho_range.takes_reference())
00227     throw Error("The background estimation is obtained from a selector that takes a reference jet. rho(PseudoJet) should be used in that case");
00228   _recompute_if_needed();
00229   return _sigma;
00230 }
00231 
00232 // get rho, the median background density per unit area, locally at
00233 // the position of a given jet.
00234 //
00235 // If the Selector associated with the range takes a reference jet
00236 // (i.e. is relocatable), then for subsequent operations the
00237 // Selector has that jet set as its reference.
00238 double JetMedianBackgroundEstimator::rho(const PseudoJet & jet) {
00239   _recompute_if_needed(jet);
00240   double our_rho = _rho;
00241   if (_rescaling_class != 0) { 
00242     our_rho *= (*_rescaling_class)(jet);
00243   }
00244   return our_rho;
00245 }
00246 
00247 // get sigma, the background fluctuations per unit area,
00248 // locally at the position of a given jet.
00249 //
00250 // If the Selector associated with the range takes a reference jet
00251 // (i.e. is relocatable), then for subsequent operations the
00252 // Selector has that jet set as its reference.
00253 double JetMedianBackgroundEstimator::sigma(const PseudoJet &jet) {
00254   _recompute_if_needed(jet);
00255   double our_sigma = _sigma;
00256   if (_rescaling_class != 0) { 
00257     our_sigma *= (*_rescaling_class)(jet);
00258   }
00259   return our_sigma;
00260 }
00261 
00262 
00263 //----------------------------------------------------------------------
00264 // configuring behaviour
00265 //----------------------------------------------------------------------
00266 // reset to default values
00267 // 
00268 // set the variou options to their default values
00269 void JetMedianBackgroundEstimator::reset(){
00270   // set the remaining default parameters
00271   set_use_area_4vector();  // true by default
00272   set_provide_fj2_sigma(false);
00273 
00274   // reset the computed values
00275   _rho = _sigma = 0.0;
00276   _n_jets_used = _n_empty_jets = 0;
00277   _empty_area = _mean_area = 0.0;
00278 
00279   _included_jets.clear();
00280 
00281   _jet_density_class = 0; // null pointer
00282   _rescaling_class = 0;   // null pointer
00283 
00284   _uptodate = false;
00285 }
00286 
00287 
00288 // Set a pointer to a class that calculates the quantity whose
00289 // median will be calculated; if the pointer is null then pt/area
00290 // is used (as occurs also if this function is not called).
00291 void JetMedianBackgroundEstimator::set_jet_density_class(const FunctionOfPseudoJet<double> * jet_density_class) {
00292   _warnings_preliminary.warn("JetMedianBackgroundEstimator::set_jet_density_class: density classes are still preliminary in FastJet 3.0. Their interface may differ in future releases (without guaranteeing backward compatibility).");
00293   _jet_density_class = jet_density_class;
00294   _uptodate = false;
00295 }
00296 
00297 
00298 
00299 //----------------------------------------------------------------------
00300 // description
00301 //----------------------------------------------------------------------
00302 string JetMedianBackgroundEstimator::description() const { 
00303   ostringstream desc;
00304   desc << "JetMedianBackgroundEstimator, using " << _jet_def.description() 
00305        << " with " << _area_def.description() 
00306        << " and selecting jets with " << _rho_range.description();
00307   return desc.str();
00308 }       
00309 
00310 
00311 
00312 //----------------------------------------------------------------------
00313 // computation of the background properties
00314 //----------------------------------------------------------------------
00315 // for estimation using a relocatable selector (i.e. local range)
00316 // this allows to set its position. Note that this HAS to be called
00317 // before any attempt to compute the background properties
00318 void JetMedianBackgroundEstimator::_recompute_if_needed(const PseudoJet &jet){
00319   // if the range is relocatable, handles its relocation
00320   if (_rho_range.takes_reference()){
00321     // check that the reference is not the same as the previous one
00322     // (would avoid an unnecessary recomputation)
00323     if (jet == _current_reference) return;
00324 
00325     // relocate the range and make sure things get recomputed the next
00326     // time one tries to get some information
00327     _rho_range.set_reference(jet);
00328     _uptodate=false;
00329   }
00330 
00331   _recompute_if_needed();
00332 }
00333 
00334 // do the actual job
00335 void JetMedianBackgroundEstimator::_compute() const {
00336   // check if the clustersequence is still valid
00337   _check_csa_alive();
00338 
00339   // fill the vector of pt/area (or the quantity from the jet density class) 
00340   //  - in the range
00341   vector<double> vector_for_median;
00342   double total_area  = 0.0;
00343   _n_jets_used = 0;
00344 
00345   // apply the selector to the included jets
00346   vector<PseudoJet> selected_jets = _rho_range(_included_jets);
00347 
00348   // compute the pt/area for the selected jets
00349   for (unsigned i = 0; i < selected_jets.size(); i++) {
00350     const PseudoJet & current_jet = selected_jets[i];
00351 
00352     double this_area = (_use_area_4vector) ? current_jet.area_4vector().perp() : current_jet.area(); 
00353 
00354     if (this_area>0){
00355       double median_input;
00356       if (_jet_density_class == 0) {
00357         median_input = current_jet.perp()/this_area;
00358       } else {
00359         median_input = (*_jet_density_class)(current_jet);
00360       }
00361       if (_rescaling_class != 0) {
00362         median_input /= (*_rescaling_class)(current_jet);
00363       }
00364       vector_for_median.push_back(median_input);
00365       total_area  += this_area;
00366       _n_jets_used++;
00367     } else {
00368       _warnings_zero_area.warn("JetMedianBackgroundEstimator::_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).");
00369     }
00370       
00371   }
00372   
00373   // there is nothing inside our region, so answer will always be zero
00374   if (vector_for_median.size() == 0) {
00375     _rho        = 0.0;
00376     _sigma      = 0.0;
00377     _mean_area  = 0.0;
00378     return;
00379   }
00380 
00381   // determine the number of empty jets
00382   const ClusterSequenceAreaBase * csab = (dynamic_cast<ClusterSequenceStructure*>(_csi()))->validated_csab();
00383   if (csab->has_explicit_ghosts()) {
00384     _empty_area = 0.0;
00385     _n_empty_jets = 0;
00386   } else {
00387     _empty_area = csab->empty_area(_rho_range);
00388     _n_empty_jets = csab->n_empty_jets(_rho_range);
00389   }
00390 
00391   double total_njets = _n_jets_used + _n_empty_jets;
00392   total_area  += _empty_area;
00393 
00394   double stand_dev;
00395   _median_and_stddev(vector_for_median, _n_empty_jets, _rho, stand_dev, 
00396                      _provide_fj2_sigma);
00397 
00398   // process and store the results (_rho was already stored above)
00399   _mean_area  = total_area / total_njets;
00400   _sigma      = stand_dev * sqrt(_mean_area);
00401 
00402   // record that the computation has been performed  
00403   _uptodate = true;
00404 }
00405 
00406 
00407 
00408 // check that the underlying structure is still alive;
00409 // throw an error otherwise
00410 void JetMedianBackgroundEstimator::_check_csa_alive() const{
00411   ClusterSequenceStructure* csa = dynamic_cast<ClusterSequenceStructure*>(_csi());
00412   if (csa == 0) {
00413     throw Error("JetMedianBackgroundEstimator: there is no cluster sequence associated with the JetMedianBackgroundEstimator");
00414   }
00415   if (! dynamic_cast<ClusterSequenceStructure*>(_csi())->has_associated_cluster_sequence())
00416     throw Error("JetMedianBackgroundEstimator: modifications are no longer possible as the underlying ClusterSequence has gone out of scope");
00417 }
00418 
00419 
00420 // check that the algorithm used for the clustering is suitable for
00421 // background estimation (i.e. either kt or C/A).
00422 // Issue a warning otherwise
00423 void JetMedianBackgroundEstimator::_check_jet_alg_good_for_median() const{
00424   const JetDefinition * jet_def = &_jet_def;
00425 
00426   // if no explicit jet def has been provided, fall back on the
00427   // cluster sequence
00428   if (_jet_def.jet_algorithm() == undefined_jet_algorithm){
00429     const ClusterSequence * cs = dynamic_cast<ClusterSequenceStructure*>(_csi())->validated_cs();
00430     jet_def = &(cs->jet_def());
00431   }
00432 
00433   if (jet_def->jet_algorithm() != kt_algorithm
00434       && jet_def->jet_algorithm() != cambridge_algorithm
00435       && jet_def->jet_algorithm() != cambridge_for_passive_algorithm) {
00436     _warnings.warn("JetMedianBackgroundEstimator: jet_def being used may not be suitable for estimating diffuse backgrounds (good alternatives are kt, cam)");
00437   }
00438 }
00439 
00440 
00441 
00442 
00443 FASTJET_END_NAMESPACE
00444 
00445 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends