|
fastjet 3.0alpha2
|
00001 //STARTHEADER 00002 // $Id: Filter.cc 1737 2010-07-08 16:19:56Z soyez $ 00003 // 00004 // Copyright (c) 2009-2010, 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 ostr << _subjet_def.description(); 00052 ostr<< ", and selection " << _selector.description(); 00053 return ostr.str(); 00054 } 00055 00056 00057 // return a vector of subjets, which are the ones that would be kept by the filtering 00058 PseudoJet Filter::operator()(const PseudoJet &jet) const { 00059 ClusterSequence *internal_cs; 00060 00061 // start by getting the list of subjets (including a sanity check 00062 // that all the jets in the argument vector share the same 00063 // underlying ClusterSequence) 00064 vector<PseudoJet> subjets; // NB: empty to begin with (see the comment for _set_filtered_elements_cafilt) 00065 _set_filtered_elements(jet, subjets, internal_cs); 00066 00067 // decide what to keep and what to reject 00068 // we first make a copy of the pointers then apply the selector 00069 vector<const PseudoJet*> subjet_pointers; 00070 for (unsigned int i=0;i<subjets.size(); i++) 00071 subjet_pointers.push_back(&(subjets[i])); 00072 00073 // Note that the following line is the one requiring that _seelector be declared as mutable 00074 if (_selector.takes_reference()) _selector.set_reference(jet); 00075 _selector.nullify_non_selected(subjet_pointers); 00076 00077 // now build the vector of kept and rejected subjets 00078 vector<PseudoJet> kept, rejected; 00079 for (unsigned int i=0;i<subjets.size(); i++){ 00080 if (subjet_pointers[i]==0) 00081 rejected.push_back(subjets[i]); 00082 else 00083 kept.push_back(subjets[i]); 00084 } 00085 00086 // gather the info under the form of a PseudoJet 00087 return _finalise(jet, kept, rejected, internal_cs); 00088 } 00089 00090 00091 // sets filtered_elements to be all the subjets on which filtering will work 00092 void Filter::_set_filtered_elements(const PseudoJet & jet, 00093 vector<PseudoJet> & filtered_elements, 00094 ClusterSequence * &internal_cs) const { 00095 // sanity checks 00096 //------------------------------------------------------------------- 00097 // make sure that the jet has constituents 00098 if (! jet.has_constituents()) 00099 throw Error("Filter can only be applied on jets having constituents"); 00100 00101 // if rho!=0, make sure we have a CS that supports area and has explicit ghosts 00102 // watch out: that will fail for a MergedJet!!x 00103 if (_rho != 0.0){ 00104 if (!jet.has_area()) 00105 throw Error("Attempt to filter and subtract (non-zero rho) without area info for the original jet"); 00106 00107 if (!jet.has_associated_cluster_sequence()) 00108 throw Error("Attempt to filter and subtract (non-zero rho) without a cluster sequence associated with the jet"); 00109 00110 // note theat the validated_csab() used in the next line will 00111 // automatically throw an error if there is no valis CSAB so we 00112 // just have to check for the explicit ghosts 00113 if (!jet.validated_csab()->has_explicit_ghosts()) 00114 throw Error("Attempt to filter and subtract (non-zero rho) without explicit ghosts"); 00115 } 00116 00117 00118 // get the jet definition to be use and whether we can apply our simplified C/A+C/A filter 00119 // 00120 // we apply C/A clustering iff 00121 // - the request subjet_def is C/A 00122 // - the jet is either directly coming from C/A or if it is a superposition of C/A jets 00123 // - the pieces agree with the recombination scheme of subjet_def 00124 //------------------------------------------------------------------- 00125 bool simple_cafilt = (_subjet_def.jet_algorithm() == cambridge_algorithm) && (_recursively_check_ca(jet)); 00126 00127 // extract the subjets 00128 //------------------------------------------------------------------- 00129 if (simple_cafilt){ 00130 _set_filtered_elements_cafilt(jet, filtered_elements, _subjet_def.R()); 00131 internal_cs = NULL; 00132 } else { 00133 if (_rho != 0.0){ 00134 internal_cs = _set_filtered_elements_generic_subtracted(jet, filtered_elements); 00135 } else { 00136 internal_cs = _set_filtered_elements_generic_unsubtracted(jet, filtered_elements); 00137 } 00138 } 00139 00140 // order the filtered elements in pt 00141 filtered_elements = sorted_by_pt(filtered_elements); 00142 } 00143 00144 00145 // gather the information about what is kept and rejected under the 00146 // form of a PseudoJet with a special ClusterSequenceInfo 00147 PseudoJet Filter::_finalise(const PseudoJet & jet, vector<PseudoJet> & kept, vector<PseudoJet> & rejected, ClusterSequence * &internal_cs) const { 00148 PseudoJet filtered_jet(0.0,0.0,0.0,0.0); 00149 00150 // create an appropriate structure and transfer the info to it 00151 FilteredJetStructure *fi = new FilteredJetStructure(); 00152 00153 fi->_original_jet = jet; 00154 fi->_pieces = kept; // in the base interface 00155 fi->_rejected = rejected; 00156 00157 if (internal_cs) 00158 fi->_internal_cs.reset(internal_cs); 00159 00160 // to sum the kept pieces, extract the recombiner used for the sub-clustering 00161 const JetDefinition::Recombiner &rec = *(_subjet_def.recombiner()); 00162 for (unsigned i = 0; i < kept.size(); i++) 00163 rec.plus_equal(filtered_jet, kept[i]); 00164 00165 // make sure the filtered jet has the same index (cluster and user) 00166 // (i.e. "looks like") the original jet 00167 // what about extra info? 00168 // TODO: do we want this: in principle, this could interfere with teh recombiner?? 00169 filtered_jet.set_cluster_hist_index(jet.cluster_hist_index()); 00170 filtered_jet.set_user_index(jet.user_index()); 00171 00172 // finally attach the clustering info to the PJ 00173 filtered_jet.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(fi)); 00174 00175 return filtered_jet; 00176 } 00177 00178 00179 // check if the jet is obtained from C/A or a superposition of C/A pieces 00180 bool Filter::_recursively_check_ca(const PseudoJet & jet) const{ 00181 if (jet.has_associated_cluster_sequence()) 00182 return jet.associated_cluster_sequence()->jet_def().jet_algorithm() == cambridge_algorithm; 00183 00184 if (jet.has_pieces()){ 00185 const vector<PseudoJet> pieces = jet.pieces(); 00186 for (vector<PseudoJet>::const_iterator it=pieces.begin(); it!=pieces.end(); it++) 00187 if (!_recursively_check_ca(*it)) return false; 00188 return true; 00189 } 00190 00191 return false; 00192 } 00193 00194 00195 00196 // set the filtered elements in the simple case of C/A+C/A 00197 // 00198 // WATCH OUT: this could be recursively called, so filtered elements 00199 // of 'jet' are APPENDED to 'filtered_elements' 00200 void Filter::_set_filtered_elements_cafilt(const PseudoJet & jet, vector<PseudoJet> & filtered_elements, double Rfilt) const{ 00201 // we know that the jet is either a C/A jet or a superposition of such pieces 00202 if (jet.has_associated_cluster_sequence()){ 00203 // just extract the exclusive subjets of 'jet' 00204 const ClusterSequence *cs = jet.associated_cluster_sequence(); 00205 vector<PseudoJet> local_fe; 00206 00207 double dcut = Rfilt / cs->jet_def().R(); 00208 if (dcut>=1.0){ 00209 local_fe.push_back(jet); 00210 } else { 00211 dcut *= dcut; 00212 local_fe = jet.exclusive_subjets(dcut); 00213 } 00214 00215 // subtract the jets if needed 00216 // Note that this one would work on pieces!! 00217 //----------------------------------------------------------------- 00218 if (_rho != 0.0){ 00219 const ClusterSequenceAreaBase * csab = jet.validated_csab(); 00220 for (unsigned int i=0;i<local_fe.size();i++) 00221 local_fe[i] = csab->subtracted_jet(local_fe[i], _rho); 00222 } 00223 00224 copy(local_fe.begin(), local_fe.end(), back_inserter(filtered_elements)); 00225 return; 00226 } 00227 00228 // just recurse into the pieces 00229 const vector<PseudoJet> & pieces = jet.pieces(); 00230 for (vector<PseudoJet>::const_iterator it = pieces.begin(); it!=pieces.end(); it++) 00231 _set_filtered_elements_cafilt(*it, filtered_elements, Rfilt); 00232 } 00233 00234 00235 // set the filtered elements in the generic re-clustering case (wo subtraction) 00236 ClusterSequence * Filter::_set_filtered_elements_generic_unsubtracted(const PseudoJet & jet, 00237 vector<PseudoJet> & filtered_elements) const{ 00238 // create a new, internal, ClusterSequence from the jet constituents 00239 // get the subjets directly from there 00240 //--------------------------------------------------------------- 00241 ClusterSequence * cs = new ClusterSequence(jet.constituents(), _subjet_def); 00242 filtered_elements = cs->inclusive_jets(); 00243 00244 return cs; 00245 } 00246 00247 // set the filtered elements in the generic re-clustering case (with subtraction) 00248 ClusterSequence * Filter::_set_filtered_elements_generic_subtracted(const PseudoJet & jet, 00249 vector<PseudoJet> & filtered_elements) const{ 00250 // create a new, internal, ClusterSequence from jet constituents 00251 // 00252 // the difference is that we need to separate the ghosts to get a 00253 // reliable area computation 00254 // --------------------------------------------------------------- 00255 vector<PseudoJet> all_constituents = jet.constituents(); 00256 vector<PseudoJet> regular_constituents, ghosts; 00257 00258 for (vector<PseudoJet>::iterator it = all_constituents.begin(); 00259 it != all_constituents.end(); it++){ 00260 if (it->is_pure_ghost()) 00261 ghosts.push_back(*it); 00262 else 00263 regular_constituents.push_back(*it); 00264 } 00265 00266 // figure the ghost area from the 1st ghost (if none, any value 00267 // would probably do as the area will be 0 and subtraction will have 00268 // no effect!) 00269 double ghost_area = (ghosts.size()) ? ghosts[0].area() : 0.01; 00270 ClusterSequenceActiveAreaExplicitGhosts * csa 00271 = new ClusterSequenceActiveAreaExplicitGhosts(regular_constituents, _subjet_def, 00272 ghosts, ghost_area); 00273 00274 // get the subjets 00275 filtered_elements = csa->subtracted_jets(_rho); 00276 00277 return csa; 00278 } 00279 00280 00281 00282 //---------------------------------------------------------------------- 00283 // FilterInterface implementation 00284 //---------------------------------------------------------------------- 00285 00286 00287 FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh
1.7.3