|
FastJet 3.0alpha3
|
00001 00002 //STARTHEADER 00003 // $Id: ClusterSequenceAreaBase.cc 2103 2011-05-13 09:58:53Z salam $ 00004 // 00005 // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam 00006 // 00007 //---------------------------------------------------------------------- 00008 // This file is part of FastJet. 00009 // 00010 // FastJet is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU General Public License as published by 00012 // the Free Software Foundation; either version 2 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // The algorithms that underlie FastJet have required considerable 00016 // development and are described in hep-ph/0512210. If you use 00017 // FastJet as part of work towards a scientific publication, please 00018 // include a citation to the FastJet paper. 00019 // 00020 // FastJet is distributed in the hope that it will be useful, 00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 // GNU General Public License for more details. 00024 // 00025 // You should have received a copy of the GNU General Public License 00026 // along with FastJet; if not, write to the Free Software 00027 // Foundation, Inc.: 00028 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00029 //---------------------------------------------------------------------- 00030 //ENDHEADER 00031 00032 00033 00034 00035 #include "fastjet/ClusterSequenceAreaBase.hh" 00036 #include <algorithm> 00037 00038 FASTJET_BEGIN_NAMESPACE 00039 00040 using namespace std; 00041 00042 00043 /// allow for warnings 00044 LimitedWarning ClusterSequenceAreaBase::_warnings; 00045 LimitedWarning ClusterSequenceAreaBase::_warnings_zero_area; 00046 00047 //---------------------------------------------------------------------- 00048 /// return the total area, within the selector's range, that is free 00049 /// of jets. 00050 /// 00051 /// Calculate this as (range area) - \sum_{i in range} A_i 00052 /// 00053 /// for ClusterSequences with explicit ghosts, assume that there will 00054 /// never be any empty area, i.e. it is always filled in by pure 00055 /// ghosts jets. This holds for seq.rec. algorithms 00056 double ClusterSequenceAreaBase::empty_area(const Selector & selector) const { 00057 00058 if (has_explicit_ghosts()) {return 0.0;} 00059 else { return empty_area_from_jets(inclusive_jets(0.0), selector);} 00060 00061 } 00062 00063 //---------------------------------------------------------------------- 00064 /// return the total area, within range, that is free of jets. 00065 /// 00066 /// Calculate this as (range area) - \sum_{i in range} A_i 00067 /// 00068 double ClusterSequenceAreaBase::empty_area_from_jets( 00069 const std::vector<PseudoJet> & all_jets, 00070 const Selector & selector) const { 00071 _check_selector_good_for_median(selector); 00072 00073 double empty = selector.area(); 00074 for (unsigned i = 0; i < all_jets.size(); i++) { 00075 if (selector.pass(all_jets[i])) empty -= area(all_jets[i]); 00076 } 00077 return empty; 00078 } 00079 00080 double ClusterSequenceAreaBase::median_pt_per_unit_area(const Selector & selector) const { 00081 return median_pt_per_unit_something(selector,false); 00082 } 00083 00084 double ClusterSequenceAreaBase::median_pt_per_unit_area_4vector(const Selector & selector) const { 00085 return median_pt_per_unit_something(selector,true); 00086 } 00087 00088 00089 //---------------------------------------------------------------------- 00090 /// the median of (pt/area) for jets contained within range, counting 00091 /// the empty area as if it were made up of a collection of empty 00092 /// jets each of area (0.55 * pi R^2). 00093 double ClusterSequenceAreaBase::median_pt_per_unit_something( 00094 const Selector & selector, bool use_area_4vector) const { 00095 00096 double median, sigma, mean_area; 00097 get_median_rho_and_sigma(selector, use_area_4vector, median, sigma, mean_area); 00098 return median; 00099 00100 } 00101 00102 00103 //---------------------------------------------------------------------- 00104 /// fits a form pt_per_unit_area(y) = a + b*y^2 for jets in range. 00105 /// exclude_above allows one to exclude large values of pt/area from fit. 00106 /// use_area_4vector = true uses the 4vector areas. 00107 void ClusterSequenceAreaBase::parabolic_pt_per_unit_area( 00108 double & a, double & b, const Selector & selector, 00109 double exclude_above, bool use_area_4vector) const { 00110 // sanity check on the selector: we require a finite area and that 00111 // it applies jet by jet (see BackgroundEstimator for more advanced 00112 // usage) 00113 _check_selector_good_for_median(selector); 00114 00115 int n=0; 00116 int n_excluded = 0; 00117 double mean_f=0, mean_x2=0, mean_x4=0, mean_fx2=0; 00118 00119 vector<PseudoJet> incl_jets = inclusive_jets(); 00120 00121 for (unsigned i = 0; i < incl_jets.size(); i++) { 00122 if (selector.pass(incl_jets[i])) { 00123 double this_area; 00124 if ( use_area_4vector ) { 00125 this_area = area_4vector(incl_jets[i]).perp(); 00126 } else { 00127 this_area = area(incl_jets[i]); 00128 } 00129 double f = incl_jets[i].perp()/this_area; 00130 if (exclude_above <= 0.0 || f < exclude_above) { 00131 double x = incl_jets[i].rap(); double x2 = x*x; 00132 mean_f += f; 00133 mean_x2 += x2; 00134 mean_x4 += x2*x2; 00135 mean_fx2 += f*x2; 00136 n++; 00137 } else { 00138 n_excluded++; 00139 } 00140 } 00141 } 00142 00143 if (n <= 1) { 00144 // meaningful results require at least two jets inside the 00145 // area -- mind you if there are empty jets we should be in 00146 // any case doing something special... 00147 a = 0.0; 00148 b = 0.0; 00149 } else { 00150 mean_f /= n; 00151 mean_x2 /= n; 00152 mean_x4 /= n; 00153 mean_fx2 /= n; 00154 00155 b = (mean_f*mean_x2 - mean_fx2)/(mean_x2*mean_x2 - mean_x4); 00156 a = mean_f - b*mean_x2; 00157 } 00158 //cerr << "n_excluded = "<< n_excluded << endl; 00159 } 00160 00161 00162 00163 void ClusterSequenceAreaBase::get_median_rho_and_sigma( 00164 const Selector & selector, bool use_area_4vector, 00165 double & median, double & sigma, double & mean_area) const { 00166 00167 vector<PseudoJet> incl_jets = inclusive_jets(); 00168 get_median_rho_and_sigma(incl_jets, selector, use_area_4vector, 00169 median, sigma, mean_area, true); 00170 } 00171 00172 00173 void ClusterSequenceAreaBase::get_median_rho_and_sigma( 00174 const vector<PseudoJet> & all_jets, 00175 const Selector & selector, bool use_area_4vector, 00176 double & median, double & sigma, double & mean_area, 00177 bool all_are_incl) const { 00178 00179 _check_jet_alg_good_for_median(); 00180 00181 // sanity check on the selector: we require a finite area and that 00182 // it applies jet by jet (see BackgroundEstimator for more advanced 00183 // usage) 00184 _check_selector_good_for_median(selector); 00185 00186 vector<double> pt_over_areas; 00187 double total_area = 0.0; 00188 double total_njets = 0; 00189 00190 for (unsigned i = 0; i < all_jets.size(); i++) { 00191 if (selector.pass(all_jets[i])) { 00192 double this_area; 00193 if (use_area_4vector) { 00194 this_area = area_4vector(all_jets[i]).perp(); 00195 } else { 00196 this_area = area(all_jets[i]); 00197 } 00198 00199 if (this_area>0) { 00200 pt_over_areas.push_back(all_jets[i].perp()/this_area); 00201 } else { 00202 _warnings_zero_area.warn("ClusterSequenceAreaBase::get_median_rho_and_sigma(...): 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)."); 00203 } 00204 00205 total_area += this_area; 00206 total_njets += 1.0; 00207 } 00208 } 00209 00210 // there is nothing inside our region, so answer will always be zero 00211 if (pt_over_areas.size() == 0) { 00212 median = 0.0; 00213 sigma = 0.0; 00214 mean_area = 0.0; 00215 return; 00216 } 00217 00218 // get median (pt/area) [this is the "old" median definition. It considers 00219 // only the "real" jets in calculating the median, i.e. excluding the 00220 // only-ghost ones; it will be supplemented with more info below] 00221 sort(pt_over_areas.begin(), pt_over_areas.end()); 00222 00223 // now get the median & error, accounting for empty jets 00224 // define the fractions of distribution at median, median-1sigma 00225 double posn[2] = {0.5, (1.0-0.6827)/2.0}; 00226 double res[2]; 00227 00228 double n_empty, empty_a; 00229 if (has_explicit_ghosts()) { 00230 // NB: the following lines of code are potentially incorrect in cases 00231 // where there are unclustered particles (empty_area would do a better job, 00232 // at least for active areas). This is not an issue with kt or C/A, or other 00233 // algorithms that cluster all particles (and the median estimation should in 00234 // any case only be done with kt or C/A!) 00235 empty_a = 0.0; 00236 n_empty = 0; 00237 } else if (all_are_incl) { 00238 // the default case 00239 empty_a = empty_area(selector); 00240 n_empty = n_empty_jets(selector); 00241 } else { 00242 // this one is intended to be used when e.g. one runs C/A, then looks at its 00243 // exclusive jets in order to get an effective smaller R value, and passes those 00244 // to this routine. 00245 empty_a = empty_area_from_jets(all_jets, selector); 00246 mean_area = total_area / total_njets; // temporary value 00247 n_empty = empty_a / mean_area; 00248 } 00249 //cout << "*** tot_area = " << total_area << ", empty_a = " << empty_a << endl; 00250 //cout << "*** n_empty = " << n_empty << ", ntotal = " << total_njets << endl; 00251 total_njets += n_empty; 00252 total_area += empty_a; 00253 00254 for (int i = 0; i < 2; i++) { 00255 double nj_median_pos = 00256 (pt_over_areas.size()-1 + n_empty)*posn[i] - n_empty; 00257 double nj_median_ratio; 00258 if (nj_median_pos >= 0 && pt_over_areas.size() > 1) { 00259 int int_nj_median = int(nj_median_pos); 00260 nj_median_ratio = 00261 pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos) 00262 + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median); 00263 } else { 00264 nj_median_ratio = 0.0; 00265 } 00266 res[i] = nj_median_ratio; 00267 } 00268 median = res[0]; 00269 double error = res[0] - res[1]; 00270 mean_area = total_area / total_njets; 00271 sigma = error * sqrt(mean_area); 00272 } 00273 00274 00275 /// return a vector of all subtracted jets, using area_4vector, given rho. 00276 /// Only inclusive_jets above ptmin are subtracted and returned. 00277 /// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()), 00278 /// i.e. not necessarily ordered in pt once subtracted 00279 vector<PseudoJet> ClusterSequenceAreaBase::subtracted_jets(const double rho, 00280 const double ptmin) 00281 const { 00282 vector<PseudoJet> sub_jets; 00283 vector<PseudoJet> jets = sorted_by_pt(inclusive_jets(ptmin)); 00284 for (unsigned i=0; i<jets.size(); i++) { 00285 PseudoJet sub_jet = subtracted_jet(jets[i],rho); 00286 sub_jets.push_back(sub_jet); 00287 } 00288 return sub_jets; 00289 } 00290 00291 /// return a vector of subtracted jets, using area_4vector. 00292 /// Only inclusive_jets above ptmin are subtracted and returned. 00293 /// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()), 00294 /// i.e. not necessarily ordered in pt once subtracted 00295 vector<PseudoJet> ClusterSequenceAreaBase::subtracted_jets( 00296 const Selector & selector, 00297 const double ptmin) 00298 const { 00299 double rho = median_pt_per_unit_area_4vector(selector); 00300 return subtracted_jets(rho,ptmin); 00301 } 00302 00303 00304 /// return a subtracted jet, using area_4vector, given rho 00305 PseudoJet ClusterSequenceAreaBase::subtracted_jet(const PseudoJet & jet, 00306 const double rho) const { 00307 PseudoJet area4vect = area_4vector(jet); 00308 PseudoJet sub_jet; 00309 // sanity check 00310 if (rho*area4vect.perp() < jet.perp() ) { 00311 sub_jet = jet - rho*area4vect; 00312 } else { sub_jet = PseudoJet(0.0,0.0,0.0,0.0); } 00313 00314 // make sure the subtracted jet has the same index (cluster, user, csw) 00315 // (i.e. "looks like") the original jet 00316 sub_jet.set_cluster_hist_index(jet.cluster_hist_index()); 00317 sub_jet.set_user_index(jet.user_index()); 00318 // do not use CS::_set_structure_shared_ptr here, which should 00319 // only be called to maintain the tally during construction 00320 sub_jet.set_structure_shared_ptr(jet.structure_shared_ptr()); 00321 return sub_jet; 00322 } 00323 00324 00325 /// return a subtracted jet, using area_4vector; note that this is 00326 /// potentially inefficient if repeatedly used for many different 00327 /// jets, because rho will be recalculated each time around. 00328 PseudoJet ClusterSequenceAreaBase::subtracted_jet(const PseudoJet & jet, 00329 const Selector & selector) const { 00330 double rho = median_pt_per_unit_area_4vector(selector); 00331 PseudoJet sub_jet = subtracted_jet(jet, rho); 00332 return sub_jet; 00333 } 00334 00335 00336 /// return the subtracted pt, given rho 00337 double ClusterSequenceAreaBase::subtracted_pt(const PseudoJet & jet, 00338 const double rho, 00339 bool use_area_4vector) const { 00340 if ( use_area_4vector ) { 00341 PseudoJet sub_jet = subtracted_jet(jet,rho); 00342 return sub_jet.perp(); 00343 } else { 00344 return jet.perp() - rho*area(jet); 00345 } 00346 } 00347 00348 00349 /// return the subtracted pt; note that this is 00350 /// potentially inefficient if repeatedly used for many different 00351 /// jets, because rho will be recalculated each time around. 00352 double ClusterSequenceAreaBase::subtracted_pt(const PseudoJet & jet, 00353 const Selector & selector, 00354 bool use_area_4vector) const { 00355 if ( use_area_4vector ) { 00356 PseudoJet sub_jet = subtracted_jet(jet,selector); 00357 return sub_jet.perp(); 00358 } else { 00359 double rho = median_pt_per_unit_area(selector); 00360 return subtracted_pt(jet,rho,false); 00361 } 00362 } 00363 00364 // check the selector is suited for the computations i.e. applies jet 00365 // by jet and has a finite area 00366 void ClusterSequenceAreaBase::_check_selector_good_for_median(const Selector &selector) const{ 00367 // make sure the selector has a finite area 00368 if ((! has_explicit_ghosts()) && (! selector.has_finite_area())){ 00369 throw Error("ClusterSequenceAreaBase: empty area can only be computed from selectors with a finite area"); 00370 } 00371 00372 // make sure the selector applies jet by jet 00373 if (! selector.applies_jet_by_jet()){ 00374 throw Error("ClusterSequenceAreaBase: empty area can only be computed from selectors that apply jet by jet"); 00375 } 00376 } 00377 00378 00379 /// check the jet algorithm is suitable (and if not issue a warning) 00380 void ClusterSequenceAreaBase::_check_jet_alg_good_for_median() const { 00381 if (jet_def().jet_algorithm() != kt_algorithm 00382 && jet_def().jet_algorithm() != cambridge_algorithm 00383 && jet_def().jet_algorithm() != cambridge_for_passive_algorithm) { 00384 _warnings.warn("ClusterSequenceAreaBase: jet_def being used may not be suitable for estimating diffuse backgrounds (good options are kt, cam)"); 00385 } 00386 } 00387 00388 00389 00390 FASTJET_END_NAMESPACE
1.7.4