|
FastJet 3.0alpha3
|
00001 //STARTHEADER 00002 // $Id: Filter.cc 2240 2011-06-03 20:48:02Z 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 #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 00047 // class description 00048 string Filter::description() const { 00049 ostringstream ostr; 00050 ostr << "Filter with subjet_def = "; 00051 if (_Rfiltfunc) 00052 ostr << "Cambridge/Aachen algorithm with dynamic Rfilt"; 00053 else 00054 ostr << _subjet_def.description(); 00055 ostr<< ", and selection " << _selector.description(); 00056 return ostr.str(); 00057 } 00058 00059 00060 // return a vector of subjets, which are the ones that would be kept 00061 // by the filtering 00062 PseudoJet Filter::result(const PseudoJet &jet) const { 00063 // start by getting the list of subjets (including a list of sanity 00064 // checks) 00065 // NB: subjets is empty to begin with (see the comment for 00066 // _set_filtered_elements_cafilt) 00067 vector<PseudoJet> subjets; 00068 _set_filtered_elements(jet, subjets); 00069 00070 // now build the vector of kept and rejected subjets 00071 vector<PseudoJet> kept, rejected; 00072 // Note that the following line is the one requiring that _selector 00073 // be declared as mutable 00074 if (_selector.takes_reference()) _selector.set_reference(jet); 00075 _selector.sift(subjets, kept, rejected); 00076 00077 // gather the info under the form of a PseudoJet 00078 return _finalise(jet, kept, rejected); 00079 } 00080 00081 00082 // sets filtered_elements to be all the subjets on which filtering will work 00083 void Filter::_set_filtered_elements(const PseudoJet & jet, 00084 vector<PseudoJet> & filtered_elements) const { 00085 // sanity checks 00086 //------------------------------------------------------------------- 00087 // make sure that the jet has constituents 00088 if (! jet.has_constituents()) 00089 throw Error("Filter can only be applied on jets having constituents"); 00090 00091 // if rho!=0, make sure we have a CS that supports area and has 00092 // explicit ghosts 00093 // watch out: that will fail for a CompositeJet!! 00094 // TODO: add support for composite jets 00095 if (_rho != 0.0){ 00096 if (!jet.has_area()) 00097 throw Error("Attempt to filter and subtract (non-zero rho) without area info for the original jet"); 00098 00099 if (!jet.has_associated_cluster_sequence()) 00100 throw Error("Attempt to filter and subtract (non-zero rho) without a cluster sequence associated with the jet"); 00101 00102 // note that the validated_csab() used in the next line will 00103 // automatically throw an error if there is no valis CSAB so we 00104 // just have to check for the explicit ghosts 00105 if (!jet.validated_csab()->has_explicit_ghosts()) 00106 throw Error("Attempt to filter and subtract (non-zero rho) without explicit ghosts"); 00107 } 00108 00109 // if we're dealing with a dynamic determination of the filtering 00110 // radius, do it now 00111 if (_Rfiltfunc) 00112 _subjet_def = JetDefinition(cambridge_algorithm, (*_Rfiltfunc)(jet)); 00113 00114 // get the jet definition to be use and whether we can apply our 00115 // simplified C/A+C/A filter 00116 // 00117 // we apply C/A clustering iff 00118 // - the request subjet_def is C/A 00119 // - the jet is either directly coming from C/A or if it is a 00120 // superposition of C/A jets 00121 // - the pieces agree with the recombination scheme of subjet_def 00122 //------------------------------------------------------------------ 00123 bool simple_cafilt = _check_ca(jet); 00124 00125 // extract the subjets 00126 //------------------------------------------------------------------- 00127 if (simple_cafilt){ 00128 _set_filtered_elements_cafilt(jet, filtered_elements, _subjet_def.R()); 00129 } else if (_rho != 0.0){ 00130 _set_filtered_elements_generic_subtracted(jet, filtered_elements); 00131 } else { 00132 _set_filtered_elements_generic_unsubtracted(jet, filtered_elements); 00133 } 00134 00135 // order the filtered elements in pt 00136 filtered_elements = sorted_by_pt(filtered_elements); 00137 } 00138 00139 00140 // gather the information about what is kept and rejected under the 00141 // form of a PseudoJet with a special ClusterSequenceInfo 00142 PseudoJet Filter::_finalise(const PseudoJet & jet, 00143 vector<PseudoJet> & kept, 00144 vector<PseudoJet> & rejected) const { 00145 // figure out which recombiner to use 00146 const JetDefinition::Recombiner &rec = *(_subjet_def.recombiner()); 00147 00148 // create an appropriate structure and transfer the info to it 00149 PseudoJet filtered_jet = join<StructureType>(kept, rec); 00150 StructureType *fs = (StructureType*) filtered_jet.structure_non_const_ptr(); 00151 fs->_original_jet = jet; 00152 fs->_rejected = rejected; 00153 00154 return filtered_jet; 00155 } 00156 00157 00158 // check if one can apply the simplification for C/A subjets 00159 bool Filter::_check_ca(const PseudoJet & jet) const{ 00160 if (_subjet_def.jet_algorithm() != cambridge_algorithm) return false; 00161 00162 vector<PseudoJet> all_pieces; 00163 if (!(_recursively_check_ca(jet, all_pieces))) return false; 00164 if (! all_pieces.size()) return 0; // just in case one passes a CompositeJet with 0 pieces! 00165 00166 // for now we know that all the pieces come from a C/A clustering 00167 // (hence have an associated cluster sequence) 00168 // 00169 // We'll enforce that they all come from the same ClusterSequence 00170 // (otherwise there may be interferences and we'd better recluster 00171 // the whole set of constituents) 00172 // 00173 // Note that we're sure there's at least one piece 00174 const ClusterSequence * cs_ref = all_pieces[0].associated_cluster_sequence(); 00175 for (unsigned int i=1; i<all_pieces.size(); i++) 00176 if (all_pieces[i].associated_cluster_sequence() != cs_ref) return false; 00177 00178 // vector<PseudoJet>::iterator pit = all_pieces.begin(); // there's at least 1 00179 // const ClusterSequence * cs_ref = pit->associated_cluster_sequence(); 00180 // while (++pit != all_pieces.end()) 00181 // if (pit->associated_cluster_sequence() != cs_ref) return false; 00182 00183 // we also have to make sure that the filtering radius is not larger 00184 // than any of the inter-pieces distance 00185 double Rfilt2 = _subjet_def.R(); 00186 Rfilt2 *= Rfilt2; 00187 for (unsigned int i=0; i<all_pieces.size()-1; i++){ 00188 for (unsigned int j=i+1; j<all_pieces.size(); j++){ 00189 if (all_pieces[i].squared_distance(all_pieces[j]) < Rfilt2) return false; 00190 } 00191 } 00192 00193 return true; 00194 } 00195 00196 00197 // check if the jet is obtained from C/A or a superposition of C/A pieces 00198 bool Filter::_recursively_check_ca(const PseudoJet & jet, vector<PseudoJet> &cumulative_pieces) const{ 00199 if (jet.has_valid_cluster_sequence()){ 00200 cumulative_pieces.push_back(jet); 00201 return jet.associated_cluster_sequence()->jet_def().jet_algorithm() == cambridge_algorithm; 00202 } 00203 00204 if (jet.has_pieces()){ 00205 const vector<PseudoJet> pieces = jet.pieces(); 00206 for (vector<PseudoJet>::const_iterator it=pieces.begin(); it!=pieces.end(); it++) 00207 if (!_recursively_check_ca(*it, cumulative_pieces)) return false; 00208 return true; 00209 } 00210 00211 return false; 00212 } 00213 00214 00215 00216 // set the filtered elements in the simple case of C/A+C/A 00217 // 00218 // WATCH OUT: this could be recursively called, so filtered elements 00219 // of 'jet' are APPENDED to 'filtered_elements' 00220 void Filter::_set_filtered_elements_cafilt(const PseudoJet & jet, 00221 vector<PseudoJet> & filtered_elements, 00222 double Rfilt) const{ 00223 // we know that the jet is either a C/A jet or a superposition of 00224 // such pieces 00225 if (jet.has_associated_cluster_sequence()){ 00226 // just extract the exclusive subjets of 'jet' 00227 const ClusterSequence *cs = jet.associated_cluster_sequence(); 00228 vector<PseudoJet> local_fe; 00229 00230 double dcut = Rfilt / cs->jet_def().R(); 00231 if (dcut>=1.0){ 00232 local_fe.push_back(jet); 00233 } else { 00234 dcut *= dcut; 00235 local_fe = jet.exclusive_subjets(dcut); 00236 } 00237 00238 // subtract the jets if needed 00239 // Note that this one would work on pieces!! 00240 //----------------------------------------------------------------- 00241 if (_rho != 0.0){ 00242 const ClusterSequenceAreaBase * csab = jet.validated_csab(); 00243 for (unsigned int i=0;i<local_fe.size();i++) 00244 local_fe[i] = csab->subtracted_jet(local_fe[i], _rho); 00245 } 00246 00247 copy(local_fe.begin(), local_fe.end(), back_inserter(filtered_elements)); 00248 return; 00249 } 00250 00251 // just recurse into the pieces 00252 const vector<PseudoJet> & pieces = jet.pieces(); 00253 for (vector<PseudoJet>::const_iterator it = pieces.begin(); 00254 it!=pieces.end(); it++) 00255 _set_filtered_elements_cafilt(*it, filtered_elements, Rfilt); 00256 } 00257 00258 00259 // set the filtered elements in the generic re-clustering case (wo 00260 // subtraction) 00261 void Filter::_set_filtered_elements_generic_unsubtracted(const PseudoJet & jet, 00262 vector<PseudoJet> & filtered_elements) const{ 00263 // create a new, internal, ClusterSequence from the jet constituents 00264 // get the subjets directly from there 00265 //--------------------------------------------------------------- 00266 ClusterSequence * cs = new ClusterSequence(jet.constituents(), _subjet_def); 00267 filtered_elements = cs->inclusive_jets(); 00268 // allow the cs to be deleted when it's no longer used 00269 cs->delete_self_when_unused(); 00270 } 00271 00272 // set the filtered elements in the generic re-clustering case (with 00273 // subtraction) 00274 void Filter::_set_filtered_elements_generic_subtracted(const PseudoJet & jet, 00275 vector<PseudoJet> & filtered_elements) const{ 00276 // create a new, internal, ClusterSequence from jet constituents 00277 // 00278 // the difference is that we need to separate the ghosts to get a 00279 // reliable area computation 00280 // --------------------------------------------------------------- 00281 vector<PseudoJet> all_constituents = jet.constituents(); 00282 vector<PseudoJet> regular_constituents, ghosts; 00283 00284 for (vector<PseudoJet>::iterator it = all_constituents.begin(); 00285 it != all_constituents.end(); it++){ 00286 if (it->is_pure_ghost()) 00287 ghosts.push_back(*it); 00288 else 00289 regular_constituents.push_back(*it); 00290 } 00291 00292 // figure the ghost area from the 1st ghost (if none, any value 00293 // would probably do as the area will be 0 and subtraction will have 00294 // no effect!) 00295 double ghost_area = (ghosts.size()) ? ghosts[0].area() : 0.01; 00296 ClusterSequenceActiveAreaExplicitGhosts * csa 00297 = new ClusterSequenceActiveAreaExplicitGhosts(regular_constituents, 00298 _subjet_def, 00299 ghosts, ghost_area); 00300 00301 // get the subjets 00302 filtered_elements = csa->subtracted_jets(_rho); 00303 00304 // allow the cs to be deleted when it's no longer used 00305 csa->delete_self_when_unused(); 00306 } 00307 00308 00309 00310 //---------------------------------------------------------------------- 00311 // FilterInterface implementation 00312 //---------------------------------------------------------------------- 00313 00314 00315 FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh
1.7.4