FastJet 3.0beta1
Filter.cc
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends