FastJet 3.0beta1
|
00001 //STARTHEADER 00002 // $Id: Filter.cc 2494 2011-08-03 16:39:25Z salam $ 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/Filter.hh" 00032 #include <fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh> 00033 #include <cassert> 00034 #include <algorithm> 00035 #include <sstream> 00036 00037 using namespace std; 00038 00039 00040 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 00041 00042 //---------------------------------------------------------------------- 00043 // Filter class implementation 00044 //---------------------------------------------------------------------- 00045 00046 // class description 00047 string Filter::description() const { 00048 ostringstream ostr; 00049 ostr << "Filter with subjet_def = "; 00050 if (_Rfiltfunc) 00051 ostr << "Cambridge/Aachen algorithm with dynamic Rfilt"; 00052 else 00053 ostr << _subjet_def.description(); 00054 ostr<< ", selection " << _selector.description(); 00055 if (_subtractor) { 00056 ostr << ", subtractor: " << _subtractor->description(); 00057 } else if (_rho != 0) { 00058 ostr << ", subtracting with rho = " << _rho; 00059 } 00060 return ostr.str(); 00061 } 00062 00063 00064 // core functions 00065 //---------------------------------------------------------------------- 00066 00067 // return a vector of subjets, which are the ones that would be kept 00068 // by the filtering 00069 PseudoJet Filter::result(const PseudoJet &jet) const { 00070 // start by getting the list of subjets (including a list of sanity 00071 // checks) 00072 // NB: subjets is empty to begin with (see the comment for 00073 // _set_filtered_elements_cafilt) 00074 vector<PseudoJet> subjets; 00075 bool discard_area; 00076 _set_filtered_elements(jet, subjets, discard_area); 00077 00078 // now build the vector of kept and rejected subjets 00079 vector<PseudoJet> kept, rejected; 00080 // Note that the following line is the one requiring that _selector 00081 // be declared as mutable 00082 if (_selector.takes_reference()) _selector.set_reference(jet); 00083 _selector.sift(subjets, kept, rejected); 00084 00085 // gather the info under the form of a PseudoJet 00086 return _finalise(jet, kept, rejected, discard_area); 00087 } 00088 00089 00090 // sets filtered_elements to be all the subjets on which filtering will work 00091 void Filter::_set_filtered_elements(const PseudoJet & jet, 00092 vector<PseudoJet> & filtered_elements, 00093 bool & discard_area) const { 00094 // sanity checks 00095 //------------------------------------------------------------------- 00096 // make sure that the jet has constituents 00097 if (! jet.has_constituents()) 00098 throw Error("Filter can only be applied on jets having constituents"); 00099 00100 // for a whole variety of checks, we shall need the "recursive" 00101 // pieces of the jet (the jet itself or recursing down to its most 00102 // fundamental pieces). 00103 // So we do compute these once and for all 00104 all_pieces.clear(); 00105 if ((!_get_all_pieces(jet, all_pieces)) || (all_pieces.size()==0)) 00106 throw Error("Attempt to filter a jet that has no associated ClusterSequence or is not a superposition of jets associated with a ClusterSequence"); 00107 00108 // if the filter uses subtraction, make sure we have a CS that supports area and has 00109 // explicit ghosts 00110 if (_uses_subtraction()) { 00111 if (!jet.has_area()) 00112 throw Error("Attempt to filter and subtract (non-zero rho or subtractor) without area info for the original jet"); 00113 00114 if (!_check_explicit_ghosts()) 00115 throw Error("Attempt to filter and subtract (non-zero rho or subtractor) without explicit ghosts"); 00116 } 00117 00118 // if we're dealing with a dynamic determination of the filtering 00119 // radius, do it now 00120 if ((_Rfilt>=0) || (_Rfiltfunc)){ 00121 const JetDefinition::Recombiner * common_recombiner = _get_common_recombiner(); 00122 double Rfilt = (_Rfiltfunc) ? (*_Rfiltfunc)(jet) : _Rfilt; 00123 if (common_recombiner) 00124 _subjet_def = JetDefinition(cambridge_algorithm, Rfilt, common_recombiner); 00125 else 00126 _subjet_def = JetDefinition(cambridge_algorithm, Rfilt); 00127 } 00128 00129 // get the jet definition to be use and whether we can apply our 00130 // simplified C/A+C/A filter 00131 // 00132 // we apply C/A clustering iff 00133 // - the request subjet_def is C/A 00134 // - the jet is either directly coming from C/A or if it is a 00135 // superposition of C/A jets 00136 // - the pieces agree with the recombination scheme of subjet_def 00137 //------------------------------------------------------------------ 00138 bool simple_cafilt = _check_ca(); 00139 00140 // extract the subjets 00141 //------------------------------------------------------------------- 00142 discard_area = false; 00143 if (simple_cafilt){ 00144 // first make sure that 'filtered_elements' is empty 00145 filtered_elements.clear(); 00146 _set_filtered_elements_cafilt(jet, filtered_elements, _subjet_def.R()); 00147 discard_area = (!_uses_subtraction()) && (jet.has_area()) && (!_check_explicit_ghosts()); 00148 } else { 00149 _set_filtered_elements_generic(jet, filtered_elements); 00150 } 00151 00152 // order the filtered elements in pt 00153 filtered_elements = sorted_by_pt(filtered_elements); 00154 00155 // clear temp pieces cached 00156 all_pieces.clear(); 00157 } 00158 00159 // set the filtered elements in the simple case of C/A+C/A 00160 // 00161 // WATCH OUT: this could be recursively called, so filtered elements 00162 // of 'jet' are APPENDED to 'filtered_elements' 00163 void Filter::_set_filtered_elements_cafilt(const PseudoJet & jet, 00164 vector<PseudoJet> & filtered_elements, 00165 double Rfilt) const{ 00166 // we know that the jet is either a C/A jet or a superposition of 00167 // such pieces 00168 if (jet.has_associated_cluster_sequence()){ 00169 // just extract the exclusive subjets of 'jet' 00170 const ClusterSequence *cs = jet.associated_cluster_sequence(); 00171 vector<PseudoJet> local_fe; 00172 00173 double dcut = Rfilt / cs->jet_def().R(); 00174 if (dcut>=1.0){ 00175 local_fe.push_back(jet); 00176 } else { 00177 dcut *= dcut; 00178 local_fe = jet.exclusive_subjets(dcut); 00179 } 00180 00181 // subtract the jets if needed 00182 // Note that this one would work on pieces!! 00183 //----------------------------------------------------------------- 00184 if (_uses_subtraction()){ 00185 const ClusterSequenceAreaBase * csab = jet.validated_csab(); 00186 for (unsigned int i=0;i<local_fe.size();i++) { 00187 if (_subtractor) { 00188 local_fe[i] = (*_subtractor)(local_fe[i]); 00189 } else { 00190 local_fe[i] = csab->subtracted_jet(local_fe[i], _rho); 00191 } 00192 } 00193 } 00194 00195 copy(local_fe.begin(), local_fe.end(), back_inserter(filtered_elements)); 00196 return; 00197 } 00198 00199 // just recurse into the pieces 00200 const vector<PseudoJet> & pieces = jet.pieces(); 00201 for (vector<PseudoJet>::const_iterator it = pieces.begin(); 00202 it!=pieces.end(); it++) 00203 _set_filtered_elements_cafilt(*it, filtered_elements, Rfilt); 00204 } 00205 00206 00207 // set the filtered elements in the generic re-clustering case (wo 00208 // subtraction) 00209 void Filter::_set_filtered_elements_generic(const PseudoJet & jet, 00210 vector<PseudoJet> & filtered_elements) const{ 00211 // create a new, internal, ClusterSequence from the jet constituents 00212 // get the subjets directly from there 00213 // 00214 // If the jet has area support then we separate the ghosts from the 00215 // "regular" particles so the subjets will also have area 00216 // support. Note that we do this regardless of whether rho is zero 00217 // or not. 00218 // 00219 // Note that to be able to separate the ghosts, one needs explicit 00220 // ghosts!! 00221 // --------------------------------------------------------------- 00222 if ((jet.has_area()) && ((_uses_subtraction()) || (_check_explicit_ghosts()))){ 00223 vector<PseudoJet> all_constituents = jet.constituents(); 00224 vector<PseudoJet> regular_constituents, ghosts; 00225 00226 for (vector<PseudoJet>::iterator it = all_constituents.begin(); 00227 it != all_constituents.end(); it++){ 00228 if (it->is_pure_ghost()) 00229 ghosts.push_back(*it); 00230 else 00231 regular_constituents.push_back(*it); 00232 } 00233 00234 // figure the ghost area from the 1st ghost (if none, any value 00235 // would probably do as the area will be 0 and subtraction will have 00236 // no effect!) 00237 double ghost_area = (ghosts.size()) ? ghosts[0].area() : 0.01; 00238 ClusterSequenceActiveAreaExplicitGhosts * csa 00239 = new ClusterSequenceActiveAreaExplicitGhosts(regular_constituents, 00240 _subjet_def, 00241 ghosts, ghost_area); 00242 00243 // get the subjets: we use the subtracted or unsubtracted ones 00244 // depending on rho or _subtractor being non-zero 00245 if (_uses_subtraction()) { 00246 if (_subtractor) { 00247 filtered_elements = (*_subtractor)(csa->inclusive_jets()); 00248 } else { 00249 filtered_elements = csa->subtracted_jets(_rho); 00250 } 00251 } else { 00252 filtered_elements = csa->inclusive_jets(); 00253 } 00254 00255 // allow the cs to be deleted when it's no longer used 00256 csa->delete_self_when_unused(); 00257 } else { 00258 ClusterSequence * cs = new ClusterSequence(jet.constituents(), _subjet_def); 00259 filtered_elements = cs->inclusive_jets(); 00260 // allow the cs to be deleted when it's no longer used 00261 cs->delete_self_when_unused(); 00262 } 00263 } 00264 00265 00266 // gather the information about what is kept and rejected under the 00267 // form of a PseudoJet with a special ClusterSequenceInfo 00268 PseudoJet Filter::_finalise(const PseudoJet & jet, 00269 vector<PseudoJet> & kept, 00270 vector<PseudoJet> & rejected, 00271 const bool discard_area) const { 00272 // figure out which recombiner to use 00273 const JetDefinition::Recombiner &rec = *(_subjet_def.recombiner()); 00274 00275 // create an appropriate structure and transfer the info to it 00276 PseudoJet filtered_jet = join<StructureType>(kept, rec); 00277 StructureType *fs = (StructureType*) filtered_jet.structure_non_const_ptr(); 00278 // fs->_original_jet = jet; 00279 fs->_rejected = rejected; 00280 00281 if (discard_area){ 00282 // safety check: make sure there is an area to discard!!! 00283 assert(fs->_area_4vector_ptr); 00284 delete fs->_area_4vector_ptr; 00285 fs->_area_4vector_ptr=0; 00286 } 00287 00288 return filtered_jet; 00289 } 00290 00291 // various checks 00292 //---------------------------------------------------------------------- 00293 00294 // get the pieces down to the fundamental pieces 00295 // 00296 // Note that this just checks that there is an associated CS to the 00297 // fundamental pieces, not that it is still valid 00298 bool Filter::_get_all_pieces(const PseudoJet &jet, vector<PseudoJet> &all_pieces) const{ 00299 if (jet.has_associated_cluster_sequence()){ 00300 all_pieces.push_back(jet); 00301 return true; 00302 } 00303 00304 if (jet.has_pieces()){ 00305 const vector<PseudoJet> pieces = jet.pieces(); 00306 for (vector<PseudoJet>::const_iterator it=pieces.begin(); it!=pieces.end(); it++) 00307 if (!_get_all_pieces(*it, all_pieces)) return false; 00308 return true; 00309 } 00310 00311 return false; 00312 } 00313 00314 // get the common recombiner to all pieces (NULL if none) 00315 // 00316 // Note that if the jet has an associated cluster sequence that is no 00317 // longer valid, an error will be thrown (needed since it could be the 00318 // 1st check called after the enumeration of the pieces) 00319 const JetDefinition::Recombiner* Filter::_get_common_recombiner() const{ 00320 const JetDefinition & jd_ref = all_pieces[0].validated_cs()->jet_def(); 00321 for (unsigned int i=1; i<all_pieces.size(); i++) 00322 if (!all_pieces[i].validated_cs()->jet_def().has_same_recombiner(jd_ref)) return NULL; 00323 00324 return jd_ref.recombiner(); 00325 } 00326 00327 // check if the jet (or all its pieces) have explicit ghosts 00328 // (assuming the jet has area support 00329 // 00330 // Note that if the jet has an associated cluster sequence that is no 00331 // longer valid, an error will be thrown (needed since it could be the 00332 // 1st check called after the enumeration of the pieces) 00333 bool Filter::_check_explicit_ghosts() const{ 00334 for (vector<PseudoJet>::const_iterator it=all_pieces.begin(); it!=all_pieces.end(); it++) 00335 if (! it->validated_csab()->has_explicit_ghosts()) return false; 00336 return true; 00337 } 00338 00339 // check if one can apply the simplification for C/A subjets 00340 // 00341 // This includes: 00342 // - the subjet definition asks for C/A subjets 00343 // - all the pieces share the same CS 00344 // - that CS is C/A with the same recombiner as the subjet def 00345 // - the filtering radius is not larger than any of the pairwise 00346 // distance between the pieces 00347 // 00348 // Note that if the jet has an associated cluster sequence that is no 00349 // longer valid, an error will be thrown (needed since it could be the 00350 // 1st check called after the enumeration of the pieces) 00351 bool Filter::_check_ca() const{ 00352 if (_subjet_def.jet_algorithm() != cambridge_algorithm) return false; 00353 00354 // check that the 1st of all the pieces (we're sure there is at 00355 // least one) is coming from a C/A clustering. Then check that all 00356 // the following pieces share the same ClusterSequence 00357 const ClusterSequence * cs_ref = all_pieces[0].validated_cs(); 00358 if (cs_ref->jet_def().jet_algorithm() != cambridge_algorithm) return false; 00359 for (unsigned int i=1; i<all_pieces.size(); i++) 00360 if (all_pieces[i].validated_cs() != cs_ref) return false; 00361 00362 // check that the 1st peice has the same recombiner as the one used 00363 // for the subjet clustering 00364 // Note that since they share the same CS, checking the 2st one is enough 00365 if (!cs_ref->jet_def().has_same_recombiner(_subjet_def)) return false; 00366 00367 // we also have to make sure that the filtering radius is not larger 00368 // than any of the inter-pieces distance 00369 double Rfilt2 = _subjet_def.R(); 00370 Rfilt2 *= Rfilt2; 00371 for (unsigned int i=0; i<all_pieces.size()-1; i++){ 00372 for (unsigned int j=i+1; j<all_pieces.size(); j++){ 00373 if (all_pieces[i].squared_distance(all_pieces[j]) < Rfilt2) return false; 00374 } 00375 } 00376 00377 return true; 00378 } 00379 00380 //---------------------------------------------------------------------- 00381 // FilterInterface implementation 00382 //---------------------------------------------------------------------- 00383 00384 00385 FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh