|
FastJet 3.0alpha3
|
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
1.7.4