00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "fastjet/tools/BackgroundEstimator.hh"
00023 #include <fastjet/ClusterSequenceAreaBase.hh>
00024 #include <fastjet/ClusterSequenceStructure.hh>
00025 #include <iostream>
00026
00027 FASTJET_BEGIN_NAMESPACE
00028
00029 using namespace std;
00030
00031
00032
00033 LimitedWarning BackgroundEstimator::_warnings;
00034 LimitedWarning BackgroundEstimator::_warnings_zero_area;
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 BackgroundEstimator::BackgroundEstimator(const ClusterSequenceAreaBase &csa, const Selector &rho_range)
00046 : _rho_range(rho_range){
00047
00048 _csi = csa.structure_shared_ptr();
00049
00050
00051
00052
00053 _check_jet_alg_good_for_median();
00054
00055
00056 if ((!csa.has_explicit_ghosts()) && (!_rho_range.has_area())){
00057 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)");
00058 }
00059
00060
00061 _included_jets = csa.inclusive_jets();
00062
00063
00064 reset();
00065 }
00066
00067
00068
00069
00070
00071 BackgroundEstimator::BackgroundEstimator(const vector<PseudoJet> &jets, const Selector &rho_range)
00072 : _rho_range(rho_range){
00073
00074 if (! jets.size())
00075 throw Error("BackgroundEstimator::BackgroundEstimator: At least one jet is needed to compute the background properties");
00076
00077
00078
00079
00080 if (! (jets[0].has_associated_cluster_sequence()) && (jets[0].has_area()))
00081 throw Error("BackgroundEstimator::BackgroundEstimator: the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00082
00083 _csi = jets[0].structure_shared_ptr();
00084 ClusterSequenceStructure * csi = dynamic_cast<ClusterSequenceStructure*>(_csi());
00085 const ClusterSequenceAreaBase * csab = csi->validated_csab();
00086
00087 for (unsigned int i=1;i<jets.size(); i++){
00088 if (! jets[i].has_associated_cluster_sequence())
00089 throw Error("BackgroundEstimator::BackgroundEstimator: the jets used to estimate the background properties must be associated with a valid ClusterSequenceAreaBase");
00090
00091 if (jets[i].structure_shared_ptr().get() != _csi.get())
00092 throw Error("BackgroundEstimator::BackgroundEstimator: all the jets used to estimate the background properties must share the same ClusterSequence");
00093 }
00094
00095
00096 _check_jet_alg_good_for_median();
00097
00098
00099 if ((!csab->has_explicit_ghosts()) && (!_rho_range.has_area())){
00100 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)");
00101 }
00102
00103
00104
00105 _included_jets = jets;
00106
00107
00108 reset();
00109 }
00110
00111
00112
00113 BackgroundEstimator::~BackgroundEstimator(){
00114
00115 }
00116
00117
00118
00119
00120
00121 BackgroundEstimator & BackgroundEstimator::set_reference(const PseudoJet &jet){
00122
00123 if (_rho_range.takes_reference()){
00124
00125
00126 _rho_range.set_reference(jet);
00127 _uptodate=false;
00128 }
00129
00130 return *this;
00131 }
00132
00133
00134
00135
00136 void BackgroundEstimator::reset(){
00137
00138 set_use_area_4vector();
00139
00140
00141 _rho = _sigma = 0.0;
00142 _n_jets_used = _n_empty_jets = 0;
00143 _empty_area = _mean_area = 0.0;
00144
00145 _uptodate = false;
00146 }
00147
00148
00149
00150 void BackgroundEstimator::_compute(){
00151
00152 _check_csa_alive();
00153
00154
00155
00156
00157
00158 vector<double> pt_over_areas;
00159 double total_area = 0.0;
00160
00161 _n_jets_used = 0;
00162
00163
00164 _selected_jets = _rho_range(_included_jets);
00165
00166
00167 for (unsigned i = 0; i < _selected_jets.size(); i++) {
00168 const PseudoJet & current_jet = _selected_jets[i];
00169
00170 double this_area = (_use_area_4vector) ? current_jet.area_4vector().perp() : current_jet.area();
00171
00172 if (this_area>0){
00173 pt_over_areas.push_back(current_jet.perp()/this_area);
00174 total_area += this_area;
00175 _n_jets_used++;
00176 } else {
00177 _warnings_zero_area.warn("BackgroundEstimator::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).");
00178 }
00179
00180 }
00181
00182
00183 if (pt_over_areas.size() == 0) {
00184 _rho = 0.0;
00185 _sigma = 0.0;
00186 _mean_area = 0.0;
00187 return;
00188 }
00189
00190
00191
00192
00193 sort(pt_over_areas.begin(), pt_over_areas.end());
00194
00195
00196 _empty_area = 0.0;
00197 _n_empty_jets = 0.0;
00198 const ClusterSequenceAreaBase * csab = dynamic_cast<ClusterSequenceStructure*>(_csi())->validated_csab();
00199
00200 if (csab->has_explicit_ghosts()) {
00201 _empty_area = 0.0;
00202 _n_empty_jets = 0;
00203 } else {
00204
00205 _empty_area = _rho_range.area() - total_area;
00206 if (_empty_area<0) _empty_area = 0;
00207 _n_empty_jets = _empty_area / (0.55*pi*csab->jet_def().R());
00208 }
00209
00210 double total_njets = _n_jets_used + _n_empty_jets;
00211 total_area += _empty_area;
00212
00213
00214
00215 double posn[2] = {0.5, (1.0-0.6827)/2.0};
00216 double res[2];
00217
00218 for (int i = 0; i < 2; i++) {
00219 double nj_median_pos = (total_njets-1)*posn[i] - _n_empty_jets;
00220 double nj_median_ratio;
00221 if (nj_median_pos >= 0 && pt_over_areas.size() > 1) {
00222 int int_nj_median = int(nj_median_pos);
00223 nj_median_ratio =
00224 pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos)
00225 + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median);
00226 } else {
00227 nj_median_ratio = 0.0;
00228 }
00229 res[i] = nj_median_ratio;
00230 }
00231
00232
00233 double error = res[0] - res[1];
00234 _rho = res[0];
00235 _mean_area = total_area / total_njets;
00236 _sigma = error * sqrt(_mean_area);
00237
00238
00239 _uptodate = true;
00240 }
00241
00242
00243
00244
00245 void BackgroundEstimator::_check_csa_alive(){
00246 if (! dynamic_cast<ClusterSequenceStructure*>(_csi())->has_associated_cluster_sequence())
00247 throw Error("BackgroundEstimator: modifications are no longer possible as the underlying ClusterSequence has gone out of scope");
00248 }
00249
00250
00251
00252
00253
00254 void BackgroundEstimator::_check_jet_alg_good_for_median(){
00255 const ClusterSequence * cs = dynamic_cast<ClusterSequenceStructure*>(_csi())->validated_cs();
00256
00257 if (cs->jet_def().jet_algorithm() != kt_algorithm
00258 && cs->jet_def().jet_algorithm() != cambridge_algorithm
00259 && cs->jet_def().jet_algorithm() != cambridge_for_passive_algorithm) {
00260 _warnings.warn("BackgroundEstimator: jet_def being used may not be suitable for estimating diffuse backgrounds (good options are kt, cam)");
00261 }
00262 }
00263
00264 FASTJET_END_NAMESPACE
00265
00266