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