ClusterSequence.hh

00001 //STARTHEADER
00002 // $Id: ClusterSequence.hh 1881 2011-01-27 14:25:24Z soyez $
00003 //
00004 // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
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 
00032 #ifndef __FASTJET_CLUSTERSEQUENCE_HH__
00033 #define __FASTJET_CLUSTERSEQUENCE_HH__
00034 
00035 #include<vector>
00036 #include<map>
00037 #include "fastjet/internal/DynamicNearestNeighbours.hh"
00038 #include "fastjet/PseudoJet.hh"
00039 #include<memory>
00040 #include<cassert>
00041 #include<iostream>
00042 #include<string>
00043 #include<set>
00044 #include<cmath> // needed to get double std::abs(double)
00045 #include "fastjet/Error.hh"
00046 #include "fastjet/JetDefinition.hh"
00047 #include "fastjet/SharedPtr.hh"
00048 #include "fastjet/internal/LimitedWarning.hh"
00049 
00050 
00051 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00052 
00053 //----------------------------------------------------------------------
00054 // here's where we put the main page for fastjet (as explained in the
00055 // Doxygen faq)
00056 // We put in inside te fastjet namespace to have the links without
00057 // having to specify (fastjet::)
00058 //......................................................................
00103 //----------------------------------------------------------------------
00104 
00105 // forward declaration
00106 //class ClusterSequence;
00107 
00111 class ClusterSequence {
00112 
00113 
00114  public: 
00115 
00117   ClusterSequence () {}
00118 
00128   template<class L> ClusterSequence (const std::vector<L> & pseudojets, 
00129                    const double & R = 1.0,
00130                    const Strategy & strategy = Best,
00131                    const bool & writeout_combinations = false);
00132 
00133 
00137   template<class L> ClusterSequence (
00138                                   const std::vector<L> & pseudojets,
00139                                   const JetDefinition & jet_def,
00140                                   const bool & writeout_combinations = false);
00141 
00142   // virtual ClusterSequence destructor, in case any derived class
00143   // thinks of needing a destructor at some point
00144   virtual ~ClusterSequence (); //{}
00145 
00146   // NB: in the routines that follow, for extracting lists of jets, a
00147   //     list structure might be more efficient, if sometimes a little
00148   //     more awkward to use (at least for old fortran hands).
00149 
00153   std::vector<PseudoJet> inclusive_jets (const double & ptmin = 0.0) const;
00154 
00158   int n_exclusive_jets (const double & dcut) const;
00159 
00163   std::vector<PseudoJet> exclusive_jets (const double & dcut) const;
00164 
00167   std::vector<PseudoJet> exclusive_jets (const int & njets) const;
00168 
00171   double exclusive_dmerge (const int & njets) const;
00172 
00177   double exclusive_dmerge_max (const int & njets) const;
00178 
00181   double exclusive_ymerge (int njets) const {return exclusive_dmerge(njets) / Q2();}
00182 
00184   double exclusive_ymerge_max (int njets) const {return exclusive_dmerge_max(njets)/Q2();}
00185 
00187   int n_exclusive_jets_ycut (double ycut) const {return n_exclusive_jets(ycut*Q2());}
00188 
00190   std::vector<PseudoJet> exclusive_jets_ycut (double ycut) const {
00191     int njets = n_exclusive_jets_ycut(ycut);
00192     return exclusive_jets(njets);
00193   }
00194 
00195 
00196   //int n_exclusive_jets (const PseudoJet & jet, const double & dcut) const;
00197 
00206   std::vector<PseudoJet> exclusive_subjets (const PseudoJet & jet, 
00207                                             const double & dcut) const;
00208 
00212   int n_exclusive_subjets(const PseudoJet & jet, 
00213                           const double & dcut) const;
00214 
00220   std::vector<PseudoJet> exclusive_subjets (const PseudoJet & jet, 
00221                                             int nsub) const;
00222 
00225   double exclusive_subdmerge(const PseudoJet & jet, int nsub) const;
00226 
00230   double exclusive_subdmerge_max(const PseudoJet & jet, int nsub) const;
00231 
00232   //std::vector<PseudoJet> exclusive_jets (const PseudoJet & jet, 
00233   //                                       const int & njets) const;
00234   //double exclusive_dmerge (const PseudoJet & jet, const int & njets) const;
00235 
00237   double Q() const {return _Qtot;}
00239   double Q2() const {return _Qtot*_Qtot;}
00240 
00251   bool object_in_jet(const PseudoJet & object, const PseudoJet & jet) const;
00252 
00258   bool has_parents(const PseudoJet & jet, PseudoJet & parent1, 
00259                PseudoJet & parent2) const;
00260 
00263   bool has_child(const PseudoJet & jet, PseudoJet & child) const;
00264 
00267   bool has_child(const PseudoJet & jet, const PseudoJet * & childp) const;
00268 
00272   bool has_partner(const PseudoJet & jet, PseudoJet & partner) const;
00273 
00274   
00276   std::vector<PseudoJet> constituents (const PseudoJet & jet) const;
00277 
00278 
00287   void print_jets_for_root(const std::vector<PseudoJet> & jets, 
00288                            std::ostream & ostr = std::cout) const;
00289 
00292   void print_jets_for_root(const std::vector<PseudoJet> & jets, 
00293                            const std::string & filename,
00294                            const std::string & comment = "") const;
00295 
00296 // Not yet. Perhaps in a future release.
00297 //   /// print out all inclusive jets with pt > ptmin
00298 //   virtual void print_jets (const double & ptmin=0.0) const;
00299 
00301   void add_constituents (const PseudoJet & jet, 
00302                          std::vector<PseudoJet> & subjet_vector) const;
00303 
00305   inline Strategy strategy_used () const {return _strategy;}
00306 
00308   std::string strategy_string () const {return strategy_string(_strategy);}
00309 
00311   std::string strategy_string (Strategy strategy_in) const;
00312 
00313 
00315   const JetDefinition & jet_def() const {return _jet_def;}
00316 
00320   double jet_scale_for_algorithm(const PseudoJet & jet) const;
00321 
00322   //----- next follow functions designed specifically for plugins, which
00323   //      may only be called when plugin_activated() returns true
00324 
00330   void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
00331                                       int & newjet_k) {
00332     assert(plugin_activated());
00333     _do_ij_recombination_step(jet_i, jet_j, dij, newjet_k);
00334   }
00335 
00339   void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
00340                                       const PseudoJet & newjet, 
00341                                       int & newjet_k);
00342 
00347   void plugin_record_iB_recombination(int jet_i, double diB) {
00348     assert(plugin_activated());
00349     _do_iB_recombination_step(jet_i, diB);
00350   }
00351 
00359   class Extras {
00360   public:
00361     virtual ~Extras() {}
00362     virtual std::string description() const {return "This is a dummy extras class that contains no extra information! Derive from it if you want to use it to provide extra information from a plugin jet finder";}
00363   };
00364 
00367   inline void plugin_associate_extras(std::auto_ptr<Extras> extras_in) {
00368     _extras = extras_in;
00369   }
00370 
00372   inline bool plugin_activated() const {return _plugin_activated;}
00373 
00375   const Extras * extras() const {return _extras.get();}
00376 
00384   template<class GBJ> void plugin_simple_N2_cluster () {
00385     assert(plugin_activated());
00386     _simple_N2_cluster<GBJ>();
00387   }
00388 
00389 
00390 public:
00394   static void set_jet_algorithm (JetAlgorithm jet_algorithm) {_default_jet_algorithm = jet_algorithm;}
00396   static void set_jet_finder (JetAlgorithm jet_algorithm)    {_default_jet_algorithm = jet_algorithm;}
00397 
00398 
00404   struct history_element{
00405     int parent1; 
00406 
00407 
00408 
00409     int parent2; 
00410 
00411 
00412 
00413 
00414 
00415     int child;   
00416 
00417 
00418 
00419 
00420     int jetp_index; 
00421 
00422 
00423 
00424 
00425 
00426 
00427     double dij;  
00428 
00429 
00430     double max_dij_so_far; 
00431 
00432   };
00433 
00434   enum JetType {Invalid=-3, InexistentParent = -2, BeamJet = -1};
00435 
00452   const std::vector<PseudoJet> & jets()    const;
00453 
00465   const std::vector<history_element> & history() const;
00466 
00471   unsigned int n_particles() const;
00472 
00477   std::vector<int> particle_jet_indices(const std::vector<PseudoJet> &) const;
00478 
00494   std::vector<int> unique_history_order() const;
00495 
00499   std::vector<PseudoJet> unclustered_particles() const;
00500 
00508   void transfer_from_sequence(ClusterSequence & from_seq, bool transfer_ownership=true);
00509 
00510 
00511 protected:
00512   static JetAlgorithm _default_jet_algorithm;
00513   JetDefinition _jet_def;
00514 
00517   bool _potentially_valid(const PseudoJet & jet) const {
00518     return jet.cluster_hist_index() >= 0 
00519       && jet.cluster_hist_index() < int(_history.size());
00520   }
00521 
00524   template<class L> void _transfer_input_jets(
00525                                      const std::vector<L> & pseudojets);
00526 
00530   void _initialise_and_run (const JetDefinition & jet_def,
00531                             const bool & writeout_combinations);
00532 
00536   void _initialise_and_run (const double & R,
00537                             const Strategy & strategy,
00538                             const bool & writeout_combinations);
00539 
00542   void _decant_options(const JetDefinition & jet_def,
00543                        const bool & writeout_combinations);
00544 
00548   void _fill_initial_history();
00549 
00553   void _do_ij_recombination_step(const int & jet_i, const int & jet_j, 
00554                                  const double & dij, int & newjet_k);
00555 
00558   void _do_iB_recombination_step(const int & jet_i, const double & diB);
00559 
00560 
00564   std::vector<PseudoJet> _jets;
00565 
00566 
00570   std::vector<history_element> _history;
00571 
00580   void get_subhist_set(std::set<const history_element*> & subhist,
00581                        const  PseudoJet & jet, double dcut, int maxjet) const;
00582 
00583   bool _writeout_combinations;
00584   int  _initial_n;
00585   double _Rparam, _R2, _invR2;
00586   double _Qtot;
00587   Strategy    _strategy;
00588   JetAlgorithm  _jet_algorithm;
00589 
00590   SharedPtr<ClusterSequenceWrapper> _wrapper_to_this;
00591 
00592  private:
00593 
00594   bool _plugin_activated;
00595   std::auto_ptr<Extras> _extras; // things the plugin might want to add
00596 
00597   void _really_dumb_cluster ();
00598   void _delaunay_cluster ();
00599   //void _simple_N2_cluster ();
00600   template<class BJ> void _simple_N2_cluster ();
00601   void _tiled_N2_cluster ();
00602   void _faster_tiled_N2_cluster ();
00603 
00604   //
00605   void _minheap_faster_tiled_N2_cluster();
00606 
00607   // things needed specifically for Cambridge with Chan's 2D closest
00608   // pairs method
00609   void _CP2DChan_cluster();
00610   void _CP2DChan_cluster_2pi2R ();
00611   void _CP2DChan_cluster_2piMultD ();
00612   void _CP2DChan_limited_cluster(double D);
00613   void _do_Cambridge_inclusive_jets();
00614 
00615   // NSqrtN method for C/A
00616   void _fast_NsqrtN_cluster();
00617 
00618   void _add_step_to_history(const int & step_number, const int & parent1, 
00619                                const int & parent2, const int & jetp_index,
00620                                const double & dij);
00621 
00624   void _extract_tree_children(int pos, std::valarray<bool> &, 
00625                 const std::valarray<int> &, std::vector<int> &) const;
00626 
00629   void _extract_tree_parents (int pos, std::valarray<bool> &, 
00630                 const std::valarray<int> &,  std::vector<int> &) const;
00631 
00632 
00633   // these will be useful shorthands in the Voronoi-based code
00634   typedef std::pair<int,int> TwoVertices;
00635   typedef std::pair<double,TwoVertices> DijEntry;
00636   typedef std::multimap<double,TwoVertices> DistMap;
00637 
00639   void _add_ktdistance_to_map(const int & ii, 
00640                               DistMap & DijMap,
00641                               const DynamicNearestNeighbours * DNN);
00642 
00644   void _print_banner();
00646   static bool _first_time;
00647 
00651   static int _n_exclusive_warnings;
00652 
00656   static LimitedWarning _changed_strategy_warning;
00657 
00658   //----------------------------------------------------------------------
00663   struct BriefJet {
00664     double     eta, phi, kt2, NN_dist;
00665     BriefJet * NN;
00666     int        _jets_index;
00667   };
00668 
00669 
00672   class TiledJet {
00673   public:
00674     double     eta, phi, kt2, NN_dist;
00675     TiledJet * NN, *previous, * next; 
00676     int        _jets_index, tile_index, diJ_posn;
00677     // routines that are useful in the minheap version of tiled
00678     // clustering ("misuse" the otherwise unused diJ_posn, so as
00679     // to indicate whether jets need to have their minheap entries
00680     // updated).
00681     inline void label_minheap_update_needed() {diJ_posn = 1;}
00682     inline void label_minheap_update_done()   {diJ_posn = 0;}
00683     inline bool minheap_update_needed() const {return diJ_posn==1;}
00684   };
00685 
00686   //-- some of the functions that follow are templates and will work
00687   //as well for briefjet and tiled jets
00688 
00691   template <class J> void _bj_set_jetinfo( J * const jet, 
00692                                                  const int _jets_index) const;
00693 
00696   void _bj_remove_from_tiles( TiledJet * const jet) const;
00697 
00699   template <class J> double _bj_dist(const J * const jeta, 
00700                         const J * const jetb) const;
00701 
00702   // return the diJ (multiplied by _R2) for this jet assuming its NN
00703   // info is correct
00704   template <class J> double _bj_diJ(const J * const jeta) const;
00705 
00709   template <class J> inline J * _bj_of_hindex(
00710                           const int hist_index, 
00711                           J * const head, J * const tail) 
00712     const {
00713     J * res;
00714     for(res = head; res<tail; res++) {
00715       if (_jets[res->_jets_index].cluster_hist_index() == hist_index) {break;}
00716     }
00717     return res;
00718   }
00719 
00720 
00721   //-- remaining functions are different in various cases, so we
00722   //   will use templates but are not sure if they're useful...
00723 
00728   template <class J> void _bj_set_NN_nocross(J * const jeta, 
00729             J * const head, const J * const tail) const;
00730 
00735   template <class J> void _bj_set_NN_crosscheck(J * const jeta, 
00736             J * const head, const J * const tail) const;
00737   
00738 
00739 
00742   static const int n_tile_neighbours = 9;
00743   //----------------------------------------------------------------------
00746   struct Tile {
00748     Tile *   begin_tiles[n_tile_neighbours]; 
00750     Tile **  surrounding_tiles; 
00752     Tile **  RH_tiles;  
00754     Tile **  end_tiles; 
00756     TiledJet * head;    
00758     bool     tagged;    
00759   };
00760   std::vector<Tile> _tiles;
00761   double _tiles_eta_min, _tiles_eta_max;
00762   double _tile_size_eta, _tile_size_phi;
00763   int    _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
00764 
00765   // reasonably robust return of tile index given ieta and iphi, in particular
00766   // it works even if iphi is negative
00767   inline int _tile_index (int ieta, int iphi) const {
00768     // note that (-1)%n = -1 so that we have to add _n_tiles_phi
00769     // before performing modulo operation
00770     return (ieta-_tiles_ieta_min)*_n_tiles_phi
00771                   + (iphi+_n_tiles_phi) % _n_tiles_phi;
00772   }
00773 
00774   // routines for tiled case, including some overloads of the plain
00775   // BriefJet cases
00776   int  _tile_index(const double & eta, const double & phi) const;
00777   void _tj_set_jetinfo ( TiledJet * const jet, const int _jets_index);
00778   void  _bj_remove_from_tiles(TiledJet * const jet);
00779   void _initialise_tiles();
00780   void _print_tiles(TiledJet * briefjets ) const;
00781   void _add_neighbours_to_tile_union(const int tile_index, 
00782                  std::vector<int> & tile_union, int & n_near_tiles) const;
00783   void _add_untagged_neighbours_to_tile_union(const int tile_index, 
00784                  std::vector<int> & tile_union, int & n_near_tiles);
00785 
00786 
00787   //----------------------------------------------------------------------
00789   struct EEBriefJet {
00790     double NN_dist;  // obligatorily present
00791     double kt2;      // obligatorily present == E^2 in general
00792     EEBriefJet * NN; // must be present too
00793     int    _jets_index; // must also be present!
00794     //...........................................................
00795     double nx, ny, nz;  // our internal storage for fast distance calcs
00796   };
00797 
00799   //void _dummy_N2_cluster_instantiation();
00800 
00801 
00803   void _simple_N2_cluster_BriefJet();
00805   void _simple_N2_cluster_EEBriefJet();
00806 };
00807 
00808 
00809 //**********************************************************************
00810 //**************    START   OF   INLINE   MATERIAL    ******************
00811 //**********************************************************************
00812 
00813 
00814 //----------------------------------------------------------------------
00815 // Transfer the initial jets into our internal structure
00816 template<class L> void ClusterSequence::_transfer_input_jets(
00817                                        const std::vector<L> & pseudojets) {
00818 
00819   // this will ensure that we can point to jets without difficulties
00820   // arising.
00821   _jets.reserve(pseudojets.size()*2);
00822 
00823   // insert initial jets this way so that any type L that can be
00824   // converted to a pseudojet will work fine (basically PseudoJet
00825   // and any type that has [] subscript access to the momentum
00826   // components, such as CLHEP HepLorentzVector).
00827   for (unsigned int i = 0; i < pseudojets.size(); i++) {
00828     _jets.push_back(pseudojets[i]);}
00829   
00830 }
00831 
00832 //----------------------------------------------------------------------
00833 // initialise from some generic type... Has to be made available
00834 // here in order for it the template aspect of it to work...
00835 template<class L> ClusterSequence::ClusterSequence (
00836                                   const std::vector<L> & pseudojets,
00837                                   const double & R,
00838                                   const Strategy & strategy,
00839                                   const bool & writeout_combinations) {
00840 
00841   // transfer the initial jets (type L) into our own array
00842   _transfer_input_jets(pseudojets);
00843 
00844   // run the clustering
00845   _initialise_and_run(R,strategy,writeout_combinations);
00846 }
00847 
00848 
00849 //----------------------------------------------------------------------
00852 template<class L> ClusterSequence::ClusterSequence (
00853                                   const std::vector<L> & pseudojets,
00854                                   const JetDefinition & jet_def,
00855                                   const bool & writeout_combinations) {
00856 
00857   // transfer the initial jets (type L) into our own array
00858   _transfer_input_jets(pseudojets);
00859 
00860   // run the clustering
00861   _initialise_and_run(jet_def,writeout_combinations);
00862 }
00863 
00864 
00865 inline const std::vector<PseudoJet> & ClusterSequence::jets () const {
00866   return _jets;
00867 }
00868 
00869 inline const std::vector<ClusterSequence::history_element> & ClusterSequence::history () const {
00870   return _history;
00871 }
00872 
00873 inline unsigned int ClusterSequence::n_particles() const {return _initial_n;}
00874 
00875 
00876 
00877 //----------------------------------------------------------------------
00878 template <class J> inline void ClusterSequence::_bj_set_jetinfo(
00879                             J * const jetA, const int _jets_index) const {
00880     jetA->eta  = _jets[_jets_index].rap();
00881     jetA->phi  = _jets[_jets_index].phi_02pi();
00882     jetA->kt2  = jet_scale_for_algorithm(_jets[_jets_index]);
00883     jetA->_jets_index = _jets_index;
00884     // initialise NN info as well
00885     jetA->NN_dist = _R2;
00886     jetA->NN      = NULL;
00887 }
00888 
00889 
00890 
00891 
00892 //----------------------------------------------------------------------
00893 template <class J> inline double ClusterSequence::_bj_dist(
00894                 const J * const jetA, const J * const jetB) const {
00895   double dphi = std::abs(jetA->phi - jetB->phi);
00896   double deta = (jetA->eta - jetB->eta);
00897   if (dphi > pi) {dphi = twopi - dphi;}
00898   return dphi*dphi + deta*deta;
00899 }
00900 
00901 //----------------------------------------------------------------------
00902 template <class J> inline double ClusterSequence::_bj_diJ(const J * const jet) const {
00903   double kt2 = jet->kt2;
00904   if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
00905   return jet->NN_dist * kt2;
00906 }
00907 
00908 
00909 //----------------------------------------------------------------------
00910 // set the NN for jet without checking whether in the process you might
00911 // have discovered a new nearest neighbour for another jet
00912 template <class J> inline void ClusterSequence::_bj_set_NN_nocross(
00913                  J * const jet, J * const head, const J * const tail) const {
00914   double NN_dist = _R2;
00915   J * NN  = NULL;
00916   if (head < jet) {
00917     for (J * jetB = head; jetB != jet; jetB++) {
00918       double dist = _bj_dist(jet,jetB);
00919       if (dist < NN_dist) {
00920         NN_dist = dist;
00921         NN = jetB;
00922       }
00923     }
00924   }
00925   if (tail > jet) {
00926     for (J * jetB = jet+1; jetB != tail; jetB++) {
00927       double dist = _bj_dist(jet,jetB);
00928       if (dist < NN_dist) {
00929         NN_dist = dist;
00930         NN = jetB;
00931       }
00932     }
00933   }
00934   jet->NN = NN;
00935   jet->NN_dist = NN_dist;
00936 }
00937 
00938 
00939 //----------------------------------------------------------------------
00940 template <class J> inline void ClusterSequence::_bj_set_NN_crosscheck(J * const jet, 
00941                     J * const head, const J * const tail) const {
00942   double NN_dist = _R2;
00943   J * NN  = NULL;
00944   for (J * jetB = head; jetB != tail; jetB++) {
00945     double dist = _bj_dist(jet,jetB);
00946     if (dist < NN_dist) {
00947       NN_dist = dist;
00948       NN = jetB;
00949     }
00950     if (dist < jetB->NN_dist) {
00951       jetB->NN_dist = dist;
00952       jetB->NN = jet;
00953     }
00954   }
00955   jet->NN = NN;
00956   jet->NN_dist = NN_dist;
00957 }
00958 
00959 
00960 
00961 FASTJET_END_NAMESPACE
00962 
00963 #endif // __FASTJET_CLUSTERSEQUENCE_HH__