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