Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-01 08:40:30

0001 #ifndef __FASTJET_CLUSTERSEQUENCE_HH__
0002 #define __FASTJET_CLUSTERSEQUENCE_HH__
0003 
0004 //FJSTARTHEADER
0005 // $Id$
0006 //
0007 // Copyright (c) 2005-2025, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
0008 //
0009 //----------------------------------------------------------------------
0010 // This file is part of FastJet.
0011 //
0012 //  FastJet is free software; you can redistribute it and/or modify
0013 //  it under the terms of the GNU General Public License as published by
0014 //  the Free Software Foundation; either version 2 of the License, or
0015 //  (at your option) any later version.
0016 //
0017 //  The algorithms that underlie FastJet have required considerable
0018 //  development. They are described in the original FastJet paper,
0019 //  hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
0020 //  FastJet as part of work towards a scientific publication, please
0021 //  quote the version you use and include a citation to the manual and
0022 //  optionally also to hep-ph/0512210.
0023 //
0024 //  FastJet is distributed in the hope that it will be useful,
0025 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
0026 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0027 //  GNU General Public License for more details.
0028 //
0029 //  You should have received a copy of the GNU General Public License
0030 //  along with FastJet. If not, see <http://www.gnu.org/licenses/>.
0031 //----------------------------------------------------------------------
0032 //FJENDHEADER
0033 
0034 
0035 #include<vector>
0036 #include<map>
0037 #include "fastjet/PseudoJet.hh"
0038 #include<memory>
0039 #include<cassert>
0040 #include<iostream>
0041 #include<string>
0042 #include<set>
0043 #include<cmath> // needed to get double std::abs(double)
0044 #include "fastjet/Error.hh"
0045 #include "fastjet/JetDefinition.hh"
0046 #include "fastjet/SharedPtr.hh"
0047 #include "fastjet/LimitedWarning.hh"
0048 #include "fastjet/FunctionOfPseudoJet.hh"
0049 #include "fastjet/ClusterSequenceStructure.hh"
0050 #include "fastjet/internal/thread_safety_helpers.hh"  // helpers to write code w&wo thread-safety
0051 #include "fastjet/internal/deprecated.hh"
0052 
0053 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
0054 
0055 
0056 // forward declarations
0057 class ClusterSequenceStructure;
0058 class DynamicNearestNeighbours;
0059 
0060 /// @ingroup basic_classes
0061 /// \class ClusterSequence
0062 /// deals with clustering
0063 class ClusterSequence {
0064 
0065 
0066  public: 
0067 
0068   /// default constructor
0069   ClusterSequence () : _deletes_self_when_unused(false) {}
0070 
0071   /// create a ClusterSequence, starting from the supplied set
0072   /// of PseudoJets and clustering them with jet definition specified
0073   /// by jet_def (which also specifies the clustering strategy)
0074   template<class L> ClusterSequence (
0075                                   const std::vector<L> & pseudojets,
0076                                   const JetDefinition & jet_def,
0077                                   const bool & writeout_combinations = false);
0078   
0079   /// copy constructor for a ClusterSequence
0080   ClusterSequence (const ClusterSequence & cs) : _deletes_self_when_unused(false) {
0081     transfer_from_sequence(cs);
0082   }
0083 
0084   /// explicit assignment operator for a ClusterSequence
0085   ClusterSequence & operator=(const ClusterSequence & cs);
0086   
0087   // virtual ClusterSequence destructor, in case any derived class
0088   // thinks of needing a destructor at some point
0089   virtual ~ClusterSequence (); //{}
0090 
0091   // NB: in the routines that follow, for extracting lists of jets, a
0092   //     list structure might be more efficient, if sometimes a little
0093   //     more awkward to use (at least for old fortran hands).
0094 
0095   /// return a vector of all jets (in the sense of the inclusive
0096   /// algorithm) with pt >= ptmin. Time taken should be of the order
0097   /// of the number of jets returned.
0098   std::vector<PseudoJet> inclusive_jets (const double ptmin = 0.0) const;
0099 
0100   /// return the number of jets (in the sense of the exclusive
0101   /// algorithm) that would be obtained when running the algorithm
0102   /// with the given dcut.
0103   int n_exclusive_jets (const double dcut) const;
0104 
0105   /// return a vector of all jets (in the sense of the exclusive
0106   /// algorithm) that would be obtained when running the algorithm
0107   /// with the given dcut.
0108   std::vector<PseudoJet> exclusive_jets (const double dcut) const;
0109 
0110   /// return a vector of all jets when the event is clustered (in the
0111   /// exclusive sense) to exactly njets. 
0112   ///
0113   /// If there are fewer than njets particles in the ClusterSequence
0114   /// an error is thrown
0115   std::vector<PseudoJet> exclusive_jets (const int njets) const;
0116 
0117   /// return a vector of all jets when the event is clustered (in the
0118   /// exclusive sense) to exactly njets. 
0119   ///
0120   /// If there are fewer than njets particles in the ClusterSequence
0121   /// the function just returns however many particles there were.
0122   std::vector<PseudoJet> exclusive_jets_up_to (const int njets) const;
0123 
0124   /// return the dmin corresponding to the recombination that went
0125   /// from n+1 to n jets (sometimes known as d_{n n+1}). If the number
0126   /// of particles in the event is <= njets, the function returns 0.
0127   double exclusive_dmerge (const int njets) const;
0128 
0129   /// return the maximum of the dmin encountered during all recombinations 
0130   /// up to the one that led to an n-jet final state; identical to
0131   /// exclusive_dmerge, except in cases where the dmin do not increase
0132   /// monotonically.
0133   double exclusive_dmerge_max (const int njets) const;
0134 
0135   /// return the ymin corresponding to the recombination that went from
0136   /// n+1 to n jets (sometimes known as y_{n n+1}).
0137   double exclusive_ymerge (int njets) const {return exclusive_dmerge(njets) / Q2();}
0138 
0139   /// same as exclusive_dmerge_max, but normalised to squared total energy
0140   double exclusive_ymerge_max (int njets) const {return exclusive_dmerge_max(njets)/Q2();}
0141 
0142   /// the number of exclusive jets at the given ycut
0143   int n_exclusive_jets_ycut (double ycut) const {return n_exclusive_jets(ycut*Q2());}
0144 
0145   /// the exclusive jets obtained at the given ycut
0146   std::vector<PseudoJet> exclusive_jets_ycut (double ycut) const {
0147     int njets = n_exclusive_jets_ycut(ycut);
0148     return exclusive_jets(njets);
0149   }
0150 
0151 
0152   //int n_exclusive_jets (const PseudoJet & jet, const double dcut) const;
0153 
0154   /// return a vector of all subjets of the current jet (in the sense
0155   /// of the exclusive algorithm) that would be obtained when running
0156   /// the algorithm with the given dcut. 
0157   ///
0158   /// Time taken is O(m ln m), where m is the number of subjets that
0159   /// are found. If m gets to be of order of the total number of
0160   /// constituents in the jet, this could be substantially slower than
0161   /// just getting that list of constituents.
0162   std::vector<PseudoJet> exclusive_subjets (const PseudoJet & jet, 
0163                                             const double dcut) const;
0164 
0165   /// return the size of exclusive_subjets(...); still n ln n with same
0166   /// coefficient, but marginally more efficient than manually taking
0167   /// exclusive_subjets.size()
0168   int n_exclusive_subjets(const PseudoJet & jet, 
0169                           const double dcut) const;
0170 
0171   /// return the list of subjets obtained by unclustering the supplied
0172   /// jet down to nsub subjets. Throws an error if there are fewer than
0173   /// nsub particles in the jet.
0174   ///
0175   /// This requires nsub ln nsub time
0176   std::vector<PseudoJet> exclusive_subjets (const PseudoJet & jet, 
0177                                             int nsub) const;
0178 
0179   /// return the list of subjets obtained by unclustering the supplied
0180   /// jet down to nsub subjets (or all constituents if there are fewer
0181   /// than nsub).
0182   ///
0183   /// This requires nsub ln nsub time
0184   std::vector<PseudoJet> exclusive_subjets_up_to (const PseudoJet & jet, 
0185                                                   int nsub) const;
0186 
0187   /// returns the dij that was present in the merging nsub+1 -> nsub 
0188   /// subjets inside this jet.
0189   ///
0190   /// Returns 0 if there were nsub or fewer constituents in the jet.
0191   double exclusive_subdmerge(const PseudoJet & jet, int nsub) const;
0192 
0193   /// returns the maximum dij that occurred in the whole event at the
0194   /// stage that the nsub+1 -> nsub merge of subjets occurred inside 
0195   /// this jet.
0196   ///
0197   /// Returns 0 if there were nsub or fewer constituents in the jet.
0198   double exclusive_subdmerge_max(const PseudoJet & jet, int nsub) const;
0199 
0200   //std::vector<PseudoJet> exclusive_jets (const PseudoJet & jet, 
0201   //                                       const int njets) const;
0202   //double exclusive_dmerge (const PseudoJet & jet, const int njets) const;
0203 
0204   /// returns the sum of all energies in the event (relevant mainly for e+e-)
0205   double Q() const {return _Qtot;}
0206   /// return Q()^2
0207   double Q2() const {return _Qtot*_Qtot;}
0208 
0209   /// returns true iff the object is included in the jet. 
0210   ///
0211   /// NB: this is only sensible if the object is already registered
0212   /// within the cluster sequence, so you cannot use it with an input
0213   /// particle to the CS (since the particle won't have the history
0214   /// index set properly).
0215   ///
0216   /// For nice clustering structures it should run in O(ln(N)) time
0217   /// but in worst cases (certain cone plugins) it can take O(n) time,
0218   /// where n is the number of particles in the jet.
0219   bool object_in_jet(const PseudoJet & object, const PseudoJet & jet) const;
0220 
0221   /// if the jet has parents in the clustering, it returns true
0222   /// and sets parent1 and parent2 equal to them.
0223   ///
0224   /// if it has no parents it returns false and sets parent1 and
0225   /// parent2 to zero
0226   bool has_parents(const PseudoJet & jet, PseudoJet & parent1, 
0227                PseudoJet & parent2) const;
0228 
0229   /// if the jet has a child then return true and give the child jet
0230   /// otherwise return false and set the child to zero
0231   bool has_child(const PseudoJet & jet, PseudoJet & child) const;
0232 
0233   /// Version of has_child that sets a pointer to the child if the child
0234   /// exists;
0235   bool has_child(const PseudoJet & jet, const PseudoJet * & childp) const;
0236 
0237   /// if this jet has a child (and so a partner) return true
0238   /// and give the partner, otherwise return false and set the
0239   /// partner to zero
0240   bool has_partner(const PseudoJet & jet, PseudoJet & partner) const;
0241 
0242   
0243   /// return a vector of the particles that make up jet
0244   std::vector<PseudoJet> constituents (const PseudoJet & jet) const;
0245 
0246 
0247   /// output the supplied vector of jets in a format that can be read
0248   /// by an appropriate root script; the format is:
0249   /// jet-n jet-px jet-py jet-pz jet-E 
0250   ///   particle-n particle-rap particle-phi particle-pt
0251   ///   particle-n particle-rap particle-phi particle-pt
0252   ///   ...
0253   /// #END
0254   /// ... [i.e. above repeated]
0255   void print_jets_for_root(const std::vector<PseudoJet> & jets, 
0256                            std::ostream & ostr = std::cout) const;
0257 
0258   /// print jets for root to the file labelled filename, with an
0259   /// optional comment at the beginning
0260   void print_jets_for_root(const std::vector<PseudoJet> & jets, 
0261                            const std::string & filename,
0262                            const std::string & comment = "") const;
0263 
0264 // Not yet. Perhaps in a future release.
0265 //   /// print out all inclusive jets with pt > ptmin
0266 //   virtual void print_jets (const double ptmin=0.0) const;
0267 
0268   /// add on to subjet_vector the constituents of jet (for internal use mainly)
0269   void add_constituents (const PseudoJet & jet, 
0270                          std::vector<PseudoJet> & subjet_vector) const;
0271 
0272   /// return the enum value of the strategy used to cluster the event
0273   inline Strategy strategy_used () const {return _strategy;}
0274 
0275   /// return the name of the strategy used to cluster the event
0276   std::string strategy_string () const {return strategy_string(_strategy);}
0277 
0278   /// return the name of the strategy associated with the enum strategy_in
0279   std::string strategy_string (Strategy strategy_in) const;
0280 
0281 
0282   /// return a reference to the jet definition
0283   const JetDefinition & jet_def() const {return _jet_def;}
0284 
0285   /// by calling this routine you tell the ClusterSequence to delete
0286   /// itself when all the Pseudojets associated with it have gone out
0287   /// of scope. 
0288   ///
0289   /// At the time you call this, there must be at least one jet or
0290   /// other object outside the CS that is associated with the CS
0291   /// (e.g. the result of inclusive_jets()).
0292   ///
0293   /// NB: after having made this call, the user is still allowed to
0294   /// delete the CS. Jets associated with it will then simply not be
0295   /// able to access their substructure after that point.
0296   void delete_self_when_unused();
0297 
0298   /// return true if the object has been told to delete itself
0299   /// when unused
0300   bool will_delete_self_when_unused() const {return _deletes_self_when_unused;}
0301 
0302 //std::shared_ptr: #ifdef FASTJET_HAVE_THREAD_SAFETY
0303 //std::shared_ptr:   /// signals that a jet will no longer use the current CS (internal use only)
0304 //std::shared_ptr:   void release_pseudojet(PseudoJet &jet) const;
0305 //std::shared_ptr: #else
0306   /// tell the ClusterSequence it's about to be self deleted (internal use only)
0307   void signal_imminent_self_deletion() const;
0308 //std::shared_ptr: #endif
0309 
0310   /// returns the scale associated with a jet as required for this
0311   /// clustering algorithm (kt^2 for the kt-algorithm, 1 for the
0312   /// Cambridge algorithm). Intended mainly for internal use and not
0313   /// valid for plugin algorithms.
0314   double jet_scale_for_algorithm(const PseudoJet & jet) const;
0315 
0316   ///
0317 
0318   //----- next follow functions designed specifically for plugins, which
0319   //      may only be called when plugin_activated() returns true
0320 
0321   /// record the fact that there has been a recombination between
0322   /// jets()[jet_i] and jets()[jet_k], with the specified dij, and
0323   /// return the index (newjet_k) allocated to the new jet, whose
0324   /// momentum is assumed to be the 4-vector sum of that of jet_i and
0325   /// jet_j
0326   void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
0327                                       int & newjet_k) {
0328     assert(plugin_activated());
0329     _do_ij_recombination_step(jet_i, jet_j, dij, newjet_k);
0330   }
0331 
0332   /// as for the simpler variant of plugin_record_ij_recombination,
0333   /// except that the new jet is attributed the momentum and
0334   /// user_index of newjet
0335   void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
0336                                       const PseudoJet & newjet, 
0337                                       int & newjet_k);
0338 
0339   /// record the fact that there has been a recombination between
0340   /// jets()[jet_i] and the beam, with the specified diB; when looking
0341   /// for inclusive jets, any iB recombination will returned to the user 
0342   /// as a jet.
0343   void plugin_record_iB_recombination(int jet_i, double diB) {
0344     assert(plugin_activated());
0345     _do_iB_recombination_step(jet_i, diB);
0346   }
0347 
0348   /// return a non-const reference to the jets()[i], to allow plugins to
0349   /// modify its contents. 
0350   ///
0351   /// It can only be called when the plugin is activated.
0352   ///
0353   /// If you reset the jet (or set it equal to another one) you _must_
0354   /// ensure that final jet is given the structure_shared_ptr of the
0355   /// original jet, otherwise you will end up with an inconsistent
0356   /// ClusterSequence. 
0357   ///
0358   /// ONLY USE THIS IF YOU ARE SURE YOU KNOW WHAT YOU ARE DOING (contact
0359   /// FJ authors if you think you need this but are unsure)
0360   PseudoJet & plugin_non_const_jet(unsigned i) {
0361     assert(plugin_activated());
0362     return _jets[i];
0363   }
0364 
0365   /// @ingroup extra_info
0366   /// \class Extras
0367   /// base class to store extra information that plugins may provide
0368   /// 
0369   /// a class intended to serve as a base in case a plugin needs to
0370   /// associate extra information with a ClusterSequence (see
0371   /// SISConePlugin.* for an example).
0372   class Extras {
0373   public:
0374     virtual ~Extras() {}
0375     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";}
0376   };
0377 
0378   /// the plugin can associate some extra information with the
0379   /// ClusterSequence object by calling this function. The
0380   /// ClusterSequence takes ownership of the pointer (and
0381   /// responsibility for deleting it when the CS gets deleted).
0382   inline void plugin_associate_extras(Extras * extras_in) {
0383     _extras.reset(extras_in);
0384   }
0385 
0386   /// the plugin can associate some extra information with the
0387   /// ClusterSequence object by calling this function
0388   /// 
0389   /// As of FJ v3.1, this is deprecated, in line with the deprecation
0390   /// of auto_ptr in C++11
0391 #ifndef SWIG
0392 #ifdef FASTJET_HAVE_AUTO_PTR_INTERFACE
0393   FASTJET_DEPRECATED_MSG("Please use ClusterSequence::plugin_associate_extras(Extras * extras_in)) instead",
0394   inline void plugin_associate_extras(std::auto_ptr<Extras> extras_in)){
0395     _extras.reset(extras_in.release());
0396   }
0397 #endif
0398 #endif //SWIG
0399 
0400   /// returns true when the plugin is allowed to run the show.
0401   inline bool plugin_activated() const {return _plugin_activated;}
0402 
0403   /// returns a pointer to the extras object (may be null)
0404   const Extras * extras() const {return _extras.get();}
0405 
0406   /// allows a plugin to run a templated clustering (nearest-neighbour heuristic)
0407   ///
0408   /// This has N^2 behaviour on "good" distance, but a worst case behaviour
0409   /// of N^3 (and many algs trigger the worst case behaviour)
0410   ///
0411   /// 
0412   /// For more details on how this works, see GenBriefJet below
0413   template<class GBJ> void plugin_simple_N2_cluster () {
0414     assert(plugin_activated());
0415     _simple_N2_cluster<GBJ>();
0416   }
0417 
0418 
0419 public:
0420 //DEP   /// set the default (static) jet finder across all current and future
0421 //DEP   /// ClusterSequence objects -- deprecated and obsolescent (i.e. may be
0422 //DEP   /// suppressed in a future release).
0423 //DEP   static void set_jet_algorithm (JetAlgorithm jet_algorithm) {_default_jet_algorithm = jet_algorithm;}
0424 //DEP   /// same as above for backward compatibility
0425 //DEP   static void set_jet_finder (JetAlgorithm jet_algorithm)    {_default_jet_algorithm = jet_algorithm;}
0426 
0427 
0428   /// \ingroup extra_info
0429   /// \struct history_element
0430   /// a single element in the clustering history
0431   /// 
0432   /// (see vector _history below).
0433   struct history_element{
0434     /// index in _history where first parent of this jet
0435     /// was created (InexistentParent if this jet is an
0436     /// original particle)
0437     int parent1; 
0438 
0439     /// index in _history where second parent of this jet
0440     /// was created (InexistentParent if this jet is an
0441     /// original particle); BeamJet if this history entry
0442     /// just labels the fact that the jet has recombined
0443     /// with the beam)
0444     int parent2; 
0445 
0446     /// index in _history where the current jet is
0447     /// recombined with another jet to form its child. It
0448     /// is Invalid if this jet does not further
0449     /// recombine.
0450     int child;   
0451 
0452     /// index in the _jets vector where we will find the
0453     /// PseudoJet object corresponding to this jet
0454     /// (i.e. the jet created at this entry of the
0455     /// history). NB: if this element of the history
0456     /// corresponds to a beam recombination, then
0457     /// jetp_index=Invalid.
0458     int jetp_index; 
0459 
0460     /// the distance corresponding to the recombination
0461     /// at this stage of the clustering.
0462     double dij;  
0463 
0464     /// the largest recombination distance seen
0465     /// so far in the clustering history.
0466     double max_dij_so_far; 
0467   };
0468 
0469   enum JetType {Invalid=-3, InexistentParent = -2, BeamJet = -1};
0470 
0471   /// allow the user to access the internally stored _jets() array,
0472   /// which contains both the initial particles and the various
0473   /// intermediate and final stages of recombination.
0474   ///
0475   /// The first n_particles() entries are the original particles,
0476   /// in the order in which they were supplied to the ClusterSequence
0477   /// constructor. It can be useful to access them for example when
0478   /// examining whether a given input object is part of a specific
0479   /// jet, via the objects_in_jet(...) member function (which only takes
0480   /// PseudoJets that are registered in the ClusterSequence).
0481   ///
0482   /// One of the other (internal uses) is related to the fact
0483   /// because we don't seem to be able to access protected elements of
0484   /// the class for an object that is not "this" (at least in case where
0485   /// "this" is of a slightly different kind from the object, both
0486   /// derived from ClusterSequence).
0487   const std::vector<PseudoJet> & jets()    const;
0488 
0489   /// allow the user to access the raw internal history.
0490   ///
0491   /// This is present (as for jets()) in part so that protected
0492   /// derived classes can access this information about other
0493   /// ClusterSequences.
0494   ///
0495   /// A user who wishes to follow the details of the ClusterSequence
0496   /// can also make use of this information (and should consult the
0497   /// history_element documentation for more information), but should
0498   /// be aware that these internal structures may evolve in future
0499   /// FastJet versions.
0500   const std::vector<history_element> & history() const;
0501 
0502   /// returns the number of particles that were provided to the
0503   /// clustering algorithm (helps the user find their way around the
0504   /// history and jets objects if they weren't paying attention
0505   /// beforehand).
0506   unsigned int n_particles() const;
0507 
0508   /// returns a vector of size n_particles() which indicates, for 
0509   /// each of the initial particles (in the order in which they were
0510   /// supplied), which of the supplied jets it belongs to; if it does
0511   /// not belong to any of the supplied jets, the index is set to -1;
0512   std::vector<int> particle_jet_indices(const std::vector<PseudoJet> &) const;
0513 
0514   /// routine that returns an order in which to read the history
0515   /// such that clusterings that lead to identical jet compositions
0516   /// but different histories (because of degeneracies in the
0517   /// clustering order) will have matching constituents for each
0518   /// matching entry in the unique_history_order.
0519   ///
0520   /// The order has the property that an entry's parents will always
0521   /// appear prior to that entry itself. 
0522   ///
0523   /// Roughly speaking the order is such that we first provide all
0524   /// steps that lead to the final jet containing particle 1; then we
0525   /// have the steps that lead to reconstruction of the jet containing
0526   /// the next-lowest-numbered unclustered particle, etc...
0527   /// [see GPS CCN28-12 for more info -- of course a full explanation
0528   /// here would be better...]
0529   std::vector<int> unique_history_order() const;
0530 
0531   /// return the set of particles that have not been clustered. For 
0532   /// kt and cam/aachen algorithms this should always be null, but for
0533   /// cone type algorithms it can be non-null;
0534   std::vector<PseudoJet> unclustered_particles() const;
0535 
0536   /// Return the list of pseudojets in the ClusterSequence that do not
0537   /// have children (and are not among the inclusive jets). They may
0538   /// result from a clustering step or may be one of the pseudojets
0539   /// returned by unclustered_particles().
0540   std::vector<PseudoJet> childless_pseudojets() const;
0541 
0542   /// returns true if the object (jet or particle) is contained by (ie
0543   /// belongs to) this cluster sequence.
0544   ///
0545   /// Tests performed: if thejet's interface is this cluster sequence
0546   /// and its cluster history index is in a consistent range.
0547   bool contains(const PseudoJet & object) const;
0548 
0549   /// transfer the sequence contained in other_seq into our own;
0550   /// any plugin "extras" contained in the from_seq will be lost
0551   /// from there.
0552   ///
0553   /// It also sets the ClusterSequence pointers of the PseudoJets in
0554   /// the history to point to this ClusterSequence
0555   ///
0556   /// When specified, the second argument is an action that will be
0557   /// applied on every jets in the resulting ClusterSequence
0558   void transfer_from_sequence(const ClusterSequence & from_seq,
0559                               const FunctionOfPseudoJet<PseudoJet> * action_on_jets = 0);
0560 
0561   /// retrieve a shared pointer to the wrapper to this ClusterSequence
0562   ///
0563   /// this may turn useful if you want to track when this
0564   /// ClusterSequence goes out of scope
0565   const SharedPtr<PseudoJetStructureBase> & structure_shared_ptr() const{
0566     return _structure_shared_ptr;
0567   }
0568 
0569   /// the structure type associated with a jet belonging to a ClusterSequence
0570   typedef ClusterSequenceStructure StructureType;
0571 
0572   /// This is the function that is automatically called during
0573   /// clustering to print the FastJet banner. Only the first call to
0574   /// this function will result in the printout of the banner. Users
0575   /// may wish to call this function themselves, during the
0576   /// initialization phase of their program, in order to ensure that
0577   /// the banner appears before other output. This call will not
0578   /// affect 3rd-party banners, e.g. those from plugins.
0579   static void print_banner();
0580 
0581   /// \cond internal_doc
0582   //  [this line must be left as is to hide the doxygen comment]
0583   /// A call to this function modifies the stream used to print
0584   /// banners (by default cout). If a null pointer is passed, banner
0585   /// printout is suppressed. This affects all banners, including
0586   /// those from plugins.
0587   ///
0588   /// Please note that if you distribute 3rd party code
0589   /// that links with FastJet, that 3rd party code must not
0590   /// use this call turn off the printing of FastJet banners
0591   /// by default. This requirement reflects the spirit of
0592   /// clause 2c of the GNU Public License (v2), under which
0593   /// FastJet and its plugins are distributed.
0594   static void set_fastjet_banner_stream(std::ostream * ostr) {_fastjet_banner_ostr = ostr;}
0595   //  [this line must be left as is to hide the doxygen comment]
0596   /// \endcond
0597 
0598   /// returns a pointer to the stream to be used to print banners
0599   /// (cout by default). This function is used by plugins to determine
0600   /// where to direct their banners. Plugins should properly handle
0601   /// the case where the pointer is null.
0602   static std::ostream * fastjet_banner_stream() {return _fastjet_banner_ostr;}
0603 
0604 private:
0605   
0606   /// \cond internal_doc
0607   /// contains the actual stream to use for banners 
0608 #ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY
0609   static std::atomic<std::ostream*> _fastjet_banner_ostr;
0610 #else
0611   static std::ostream * _fastjet_banner_ostr;
0612 #endif // FASTJET_HAVE_LIMITED_THREAD_SAFETY
0613   /// \endcond
0614 
0615 protected:
0616 //DEP  static JetAlgorithm _default_jet_algorithm;
0617   JetDefinition _jet_def;
0618 
0619   /// transfer the vector<L> of input jets into our own vector<PseudoJet>
0620   /// _jets (with some reserved space for future growth).
0621   template<class L> void _transfer_input_jets(
0622                                      const std::vector<L> & pseudojets);
0623 
0624   /// This is what is called to do all the initialisation and
0625   /// then run the clustering (may be called by various constructors).
0626   /// It assumes _jets contains the momenta to be clustered.
0627   void _initialise_and_run (const JetDefinition & jet_def,
0628                             const bool & writeout_combinations);
0629 
0630   //// this performs the initialisation, minus the option-decanting
0631   //// stage; for low multiplicity, initialising a few things in the
0632   //// constructor, calling the decant_options_partial() and then this
0633   //// is faster than going through _initialise_and_run.
0634   void _initialise_and_run_no_decant();
0635 
0636 //DEP   /// This is an alternative routine for initialising and running the
0637 //DEP   /// clustering, provided for legacy purposes. The jet finder is that
0638 //DEP   /// specified in the static member _default_jet_algorithm.
0639 //DEP   void _initialise_and_run (const double R,
0640 //DEP                             const Strategy & strategy,
0641 //DEP                             const bool & writeout_combinations);
0642 
0643   /// fills in the various member variables with "decanted" options from
0644   /// the jet_definition and writeout_combinations variables
0645   void _decant_options(const JetDefinition & jet_def,
0646                        const bool & writeout_combinations);
0647 
0648   /// assuming that the jet definition, writeout_combinations and
0649   /// _structure_shared_ptr have been set (e.g. in an initialiser list
0650   /// in the constructor), it handles the remaining decanting of
0651   /// options.
0652   void _decant_options_partial();
0653 
0654   /// fill out the history (and jet cross refs) related to the initial
0655   /// set of jets (assumed already to have been "transferred"),
0656   /// without any clustering
0657   void _fill_initial_history();
0658 
0659   /// carry out the recombination between the jets numbered jet_i and
0660   /// jet_j, at distance scale dij; return the index newjet_k of the
0661   /// result of the recombination of i and j.
0662   void _do_ij_recombination_step(const int jet_i, const int jet_j, 
0663                                  const double dij, int & newjet_k);
0664 
0665   /// carry out an recombination step in which _jets[jet_i] merges with
0666   /// the beam, 
0667   void _do_iB_recombination_step(const int jet_i, const double diB);
0668 
0669   /// every time a jet is added internally during clustering, this
0670   /// should be called to set the jet's structure shared ptr to point
0671   /// to the CS (and the count of internally associated objects is
0672   /// also updated). This should not be called outside construction of
0673   /// a CS object.
0674   void _set_structure_shared_ptr(PseudoJet & j);
0675 
0676   /// make sure that the CS's internal tally of the use count matches
0677   /// that of the _structure_shared_ptr
0678   void _update_structure_use_count();
0679   
0680   /// returns a suggestion for the best strategy to use on event
0681   /// multiplicity, algorithm, R, etc.
0682   Strategy _best_strategy() const;
0683   
0684   /// \if internal_doc
0685   /// \class _Parabola
0686   /// returns c*(a*R**2 + b*R + 1);
0687   /// Written as a class in case we want to give names to different
0688   /// parabolas
0689   /// \endif
0690   class _Parabola {
0691   public:
0692     _Parabola(double a, double b, double c) : _a(a), _b(b), _c(c) {}
0693     inline double operator()(const double R) const {return _c*(_a*R*R + _b*R + 1);}
0694   private:
0695     double _a, _b, _c;
0696   };
0697 
0698   /// \if internal_doc
0699   /// \class _Line
0700   /// operator()(R) returns a*R+b;
0701   /// \endif
0702   class _Line {
0703   public:
0704     _Line(double a, double b) : _a(a), _b(b) {}
0705     inline double operator()(const double R) const {return _a*R + _b;}
0706   private:
0707     double _a, _b;
0708   };
0709 
0710   /// This contains the physical PseudoJets; for each PseudoJet one
0711   /// can find the corresponding position in the _history by looking
0712   /// at _jets[i].cluster_hist_index().
0713   std::vector<PseudoJet> _jets;
0714 
0715 
0716   /// this vector will contain the branching history; for each stage,
0717   /// _history[i].jetp_index indicates where to look in the _jets
0718   /// vector to get the physical PseudoJet.
0719   std::vector<history_element> _history;
0720 
0721   /// set subhist to be a set pointers to history entries corresponding to the
0722   /// subjets of this jet; one stops going working down through the
0723   /// subjets either when 
0724   ///   - there is no further to go
0725   ///   - one has found maxjet entries
0726   ///   - max_dij_so_far <= dcut
0727   /// By setting maxjet=0 one can use just dcut; by setting dcut<0
0728   /// one can use jet maxjet
0729   void get_subhist_set(std::set<const history_element*> & subhist,
0730                        const  PseudoJet & jet, double dcut, int maxjet) const;
0731 
0732   bool _writeout_combinations;
0733   int  _initial_n;
0734   double _Rparam, _R2, _invR2;
0735   double _Qtot;
0736   Strategy    _strategy;
0737   JetAlgorithm  _jet_algorithm;
0738 
0739   SharedPtr<PseudoJetStructureBase> _structure_shared_ptr; //< will actually be of type ClusterSequenceStructure
0740   int _structure_use_count_after_construction; //< info of use when CS handles its own memory
0741   /// if true then the CS will delete itself when the last external
0742   /// object referring to it disappears. It is mutable so as to ensure
0743   /// that signal_imminent_self_deletion() [const] can make relevant
0744   /// changes.
0745 #ifdef FASTJET_HAVE_THREAD_SAFETY
0746   mutable std::atomic<bool> _deletes_self_when_unused;
0747 #else
0748   mutable bool _deletes_self_when_unused;
0749 #endif
0750 
0751  private:
0752 
0753   bool _plugin_activated;
0754   SharedPtr<Extras> _extras; // things the plugin might want to add
0755 
0756   void _really_dumb_cluster ();
0757   void _delaunay_cluster ();
0758   //void _simple_N2_cluster ();
0759   template<class BJ> void _simple_N2_cluster ();
0760   void _tiled_N2_cluster ();
0761   void _faster_tiled_N2_cluster ();
0762 
0763   //
0764   void _minheap_faster_tiled_N2_cluster();
0765 
0766   // things needed specifically for Cambridge with Chan's 2D closest
0767   // pairs method
0768   void _CP2DChan_cluster();
0769   void _CP2DChan_cluster_2pi2R ();
0770   void _CP2DChan_cluster_2piMultD ();
0771   void _CP2DChan_limited_cluster(double D);
0772   void _do_Cambridge_inclusive_jets();
0773 
0774   // NSqrtN method for C/A
0775   void _fast_NsqrtN_cluster();
0776 
0777   void _add_step_to_history( //const int step_number,
0778                             const int parent1, 
0779                             const int parent2, const int jetp_index,
0780                             const double dij);
0781 
0782   /// internal routine associated with the construction of the unique
0783   /// history order (following children in the tree)
0784   void _extract_tree_children(int pos, std::valarray<bool> &, 
0785                 const std::valarray<int> &, std::vector<int> &) const;
0786 
0787   /// internal routine associated with the construction of the unique
0788   /// history order (following parents in the tree)
0789   void _extract_tree_parents (int pos, std::valarray<bool> &, 
0790                 const std::valarray<int> &,  std::vector<int> &) const;
0791 
0792 
0793   // these will be useful shorthands in the Voronoi-based code
0794   typedef std::pair<int,int> TwoVertices;
0795   typedef std::pair<double,TwoVertices> DijEntry;
0796   typedef std::multimap<double,TwoVertices> DistMap;
0797 
0798   /// currently used only in the Voronoi based code
0799   void _add_ktdistance_to_map(const int ii, 
0800                               DistMap & DijMap,
0801                                 const DynamicNearestNeighbours * DNN);
0802 
0803 
0804   /// will be set by default to be true for the first run
0805   static thread_safety_helpers::FirstTimeTrue _first_time;
0806 
0807   /// manage warnings related to exclusive jets access
0808   static LimitedWarning _exclusive_warnings;
0809 
0810   /// the limited warning member for notification of user that 
0811   /// their requested strategy has been overridden (usually because
0812   /// they have R>2pi and not all strategies work then)
0813   static LimitedWarning _changed_strategy_warning;
0814 
0815   //----------------------------------------------------------------------
0816   /// the fundamental structure which contains the minimal info about
0817   /// a jet, as needed for our plain N^2 algorithm -- the idea is to
0818   /// put all info that will be accessed N^2 times into an array of
0819   /// BriefJets...
0820   struct BriefJet {
0821     double     eta, phi, kt2, NN_dist;
0822     BriefJet * NN;
0823     int        _jets_index;
0824   };
0825 
0826   /// structure analogous to BriefJet, but with the extra information
0827   /// needed for dealing with tiles
0828   class TiledJet {
0829   public:
0830     double     eta, phi, kt2, NN_dist;
0831     TiledJet * NN, *previous, * next; 
0832     int        _jets_index, tile_index, diJ_posn;
0833     // routines that are useful in the minheap version of tiled
0834     // clustering ("misuse" the otherwise unused diJ_posn, so as
0835     // to indicate whether jets need to have their minheap entries
0836     // updated).
0837     inline void label_minheap_update_needed() {diJ_posn = 1;}
0838     inline void label_minheap_update_done()   {diJ_posn = 0;}
0839     inline bool minheap_update_needed() const {return diJ_posn==1;}
0840   };
0841 
0842   //-- some of the functions that follow are templates and will work
0843   //as well for briefjet and tiled jets
0844 
0845   /// set the kinematic and labelling info for jeta so that it corresponds
0846   /// to _jets[_jets_index]
0847   template <class J> void _bj_set_jetinfo( J * const jet, 
0848                                                  const int _jets_index) const;
0849 
0850   /// "remove" this jet, which implies updating links of neighbours and
0851   /// perhaps modifying the tile structure
0852   void _bj_remove_from_tiles( TiledJet * const jet) const;
0853 
0854   /// return the distance between two BriefJet objects
0855   template <class J> double _bj_dist(const J * const jeta, 
0856                         const J * const jetb) const;
0857 
0858   // return the diJ (multiplied by _R2) for this jet assuming its NN
0859   // info is correct
0860   template <class J> double _bj_diJ(const J * const jeta) const;
0861 
0862   /// for testing purposes only: if in the range head--tail-1 there is a
0863   /// a jet which corresponds to hist_index in the history, then
0864   /// return a pointer to that jet; otherwise return tail.
0865   template <class J> inline J * _bj_of_hindex(
0866                           const int hist_index, 
0867                           J * const head, J * const tail) 
0868     const {
0869     J * res;
0870     for(res = head; res<tail; res++) {
0871       if (_jets[res->_jets_index].cluster_hist_index() == hist_index) {break;}
0872     }
0873     return res;
0874   }
0875 
0876 
0877   //-- remaining functions are different in various cases, so we
0878   //   will use templates but are not sure if they're useful...
0879 
0880   /// updates (only towards smaller distances) the NN for jeta without checking
0881   /// whether in the process jeta itself might be a new NN of one of
0882   /// the jets being scanned -- span the range head to tail-1 with
0883   /// assumption that jeta is not contained in that range
0884   template <class J> void _bj_set_NN_nocross(J * const jeta, 
0885             J * const head, const J * const tail) const;
0886 
0887   /// reset the NN for jeta and DO check whether in the process jeta
0888   /// itself might be a new NN of one of the jets being scanned --
0889   /// span the range head to tail-1 with assumption that jeta is not
0890   /// contained in that range
0891   template <class J> void _bj_set_NN_crosscheck(J * const jeta, 
0892             J * const head, const J * const tail) const;
0893   
0894 
0895 
0896   /// number of neighbours that a tile will have (rectangular geometry
0897   /// gives 9 neighbours).
0898   static const int n_tile_neighbours = 9;
0899   //----------------------------------------------------------------------
0900   /// The fundamental structures to be used for the tiled N^2 algorithm
0901   /// (see CCN27-44 for some discussion of pattern of tiling)
0902   struct Tile {
0903     /// pointers to neighbouring tiles, including self
0904     Tile *   begin_tiles[n_tile_neighbours]; 
0905     /// neighbouring tiles, excluding self
0906     Tile **  surrounding_tiles; 
0907     /// half of neighbouring tiles, no self
0908     Tile **  RH_tiles;  
0909     /// just beyond end of tiles
0910     Tile **  end_tiles; 
0911     /// start of list of BriefJets contained in this tile
0912     TiledJet * head;    
0913     /// sometimes useful to be able to tag a tile
0914     bool     tagged;    
0915   };
0916   std::vector<Tile> _tiles;
0917   double _tiles_eta_min, _tiles_eta_max;
0918   double _tile_size_eta, _tile_size_phi;
0919   int    _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
0920 
0921   // reasonably robust return of tile index given ieta and iphi, in particular
0922   // it works even if iphi is negative
0923   inline int _tile_index (int ieta, int iphi) const {
0924     // note that (-1)%n = -1 so that we have to add _n_tiles_phi
0925     // before performing modulo operation
0926     return (ieta-_tiles_ieta_min)*_n_tiles_phi
0927                   + (iphi+_n_tiles_phi) % _n_tiles_phi;
0928   }
0929 
0930   // routines for tiled case, including some overloads of the plain
0931   // BriefJet cases
0932   int  _tile_index(const double eta, const double phi) const;
0933   void _tj_set_jetinfo ( TiledJet * const jet, const int _jets_index);
0934   void  _bj_remove_from_tiles(TiledJet * const jet);
0935   void _initialise_tiles();
0936   void _print_tiles(TiledJet * briefjets ) const;
0937   void _add_neighbours_to_tile_union(const int tile_index, 
0938                  std::vector<int> & tile_union, int & n_near_tiles) const;
0939   void _add_untagged_neighbours_to_tile_union(const int tile_index, 
0940                  std::vector<int> & tile_union, int & n_near_tiles);
0941 
0942   //----------------------------------------------------------------------
0943   /// fundamental structure for e+e- clustering
0944   struct EEBriefJet {
0945     double NN_dist;  // obligatorily present
0946     double kt2;      // obligatorily present == E^2 in general
0947     EEBriefJet * NN; // must be present too
0948     int    _jets_index; // must also be present!
0949     //...........................................................
0950     double nx, ny, nz;  // our internal storage for fast distance calcs
0951   };
0952 
0953   /// identical to EEBriefJet, but the corresponding distance
0954   /// calculation (_bj_dist) is overloaded to use the more accurate
0955   /// cross-product approach
0956   class EEAccurateBriefJet : public EEBriefJet { };
0957 
0958   /// to help instantiation (fj 2.4.0; did not quite work on gcc 33 and os x 10.3?)
0959   //void _dummy_N2_cluster_instantiation();
0960 
0961 
0962   /// to avoid issues with template instantiation (OS X 10.3, gcc 3.3)
0963   void _simple_N2_cluster_BriefJet();
0964   /// to avoid issues with template instantiation (OS X 10.3, gcc 3.3)
0965   void _simple_N2_cluster_EEBriefJet();
0966   void _simple_N2_cluster_EEAccurateBriefJet();
0967 };
0968 
0969 
0970 //**********************************************************************
0971 //**************    START   OF   INLINE   MATERIAL    ******************
0972 //**********************************************************************
0973 
0974 
0975 //----------------------------------------------------------------------
0976 // Transfer the initial jets into our internal structure
0977 template<class L> void ClusterSequence::_transfer_input_jets(
0978                                        const std::vector<L> & pseudojets) {
0979 
0980   // this will ensure that we can point to jets without difficulties
0981   // arising.
0982   _jets.reserve(pseudojets.size()*2);
0983 
0984   // insert initial jets this way so that any type L that can be
0985   // converted to a pseudojet will work fine (basically PseudoJet
0986   // and any type that has [] subscript access to the momentum
0987   // components, such as CLHEP HepLorentzVector).
0988   for (unsigned int i = 0; i < pseudojets.size(); i++) {
0989     _jets.push_back(pseudojets[i]);}
0990   
0991 }
0992 
0993 // //----------------------------------------------------------------------
0994 // // initialise from some generic type... Has to be made available
0995 // // here in order for it the template aspect of it to work...
0996 // template<class L> ClusterSequence::ClusterSequence (
0997 //                                   const std::vector<L> & pseudojets,
0998 //                                   const double R,
0999 //                                   const Strategy & strategy,
1000 //                                   const bool & writeout_combinations) {
1001 // 
1002 //   // transfer the initial jets (type L) into our own array
1003 //   _transfer_input_jets(pseudojets);
1004 // 
1005 //   // run the clustering
1006 //   _initialise_and_run(R,strategy,writeout_combinations);
1007 // }
1008 
1009 
1010 //----------------------------------------------------------------------
1011 /// constructor of a jet-clustering sequence from a vector of
1012 /// four-momenta, with the jet definition specified by jet_def
1013 template<class L> ClusterSequence::ClusterSequence (
1014                                   const std::vector<L> & pseudojets,
1015                                   const JetDefinition & jet_def_in,
1016                                   const bool & writeout_combinations) :
1017   _jet_def(jet_def_in), _writeout_combinations(writeout_combinations),
1018   _structure_shared_ptr(new ClusterSequenceStructure(this))
1019 {
1020 
1021   // transfer the initial jets (type L) into our own array
1022   _transfer_input_jets(pseudojets);
1023 
1024   // transfer the remaining options
1025   _decant_options_partial();
1026 
1027   // run the clustering
1028   _initialise_and_run_no_decant();
1029 }
1030 
1031 
1032 inline const std::vector<PseudoJet> & ClusterSequence::jets () const {
1033   return _jets;
1034 }
1035 
1036 inline const std::vector<ClusterSequence::history_element> & ClusterSequence::history () const {
1037   return _history;
1038 }
1039 
1040 inline unsigned int ClusterSequence::n_particles() const {return _initial_n;}
1041 
1042 //----------------------------------------------------------------------
1043 // implementation of JetDefinition::operator() is here to avoid nasty
1044 // issues of order of implementations and includes
1045 #ifndef __CINT__
1046 template<class L>
1047 std::vector<PseudoJet> JetDefinition::operator()(const std::vector<L> & particles) const {
1048   // create a new cluster sequence
1049   ClusterSequence * cs = new ClusterSequence(particles, *this);
1050 
1051   // get the jets, and sort them according to whether the algorithm
1052   // is spherical or not
1053   std::vector<PseudoJet> jets;
1054   if (is_spherical()) {
1055     jets = sorted_by_E(cs->inclusive_jets());
1056   } else {
1057     jets = sorted_by_pt(cs->inclusive_jets());
1058   }
1059   
1060   // make sure the ClusterSequence gets deleted once it's no longer
1061   // needed
1062   if (jets.size() != 0) {
1063     cs->delete_self_when_unused();
1064   } else {
1065     delete cs;
1066   }
1067 
1068   return jets;
1069 }
1070 #endif // __CINT__
1071 
1072 
1073 //----------------------------------------------------------------------
1074 template <class J> inline void ClusterSequence::_bj_set_jetinfo(
1075                             J * const jetA, const int _jets_index) const {
1076     jetA->eta  = _jets[_jets_index].rap();
1077     jetA->phi  = _jets[_jets_index].phi_02pi();
1078     jetA->kt2  = jet_scale_for_algorithm(_jets[_jets_index]);
1079     jetA->_jets_index = _jets_index;
1080     // initialise NN info as well
1081     jetA->NN_dist = _R2;
1082     jetA->NN      = NULL;
1083 }
1084 
1085 
1086 
1087 
1088 //----------------------------------------------------------------------
1089 template <class J> inline double ClusterSequence::_bj_dist(
1090                 const J * const jetA, const J * const jetB) const {
1091   //#define FASTJET_NEW_DELTA_PHI
1092 #ifndef FASTJET_NEW_DELTA_PHI
1093   //GPS+MC old version of Delta phi calculation
1094   double dphi = std::abs(jetA->phi - jetB->phi);
1095   double deta = (jetA->eta - jetB->eta);
1096   if (dphi > pi) {dphi = twopi - dphi;}
1097 #else 
1098   //GPS+MC testing for 2015-02-faster-deltaR2
1099   double dphi = pi-std::abs(pi-std::abs(jetA->phi - jetB->phi));
1100   double deta = (jetA->eta - jetB->eta);
1101 #endif 
1102   return dphi*dphi + deta*deta;
1103 }
1104 
1105 //----------------------------------------------------------------------
1106 template <class J> inline double ClusterSequence::_bj_diJ(const J * const jet) const {
1107   double kt2 = jet->kt2;
1108   if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
1109   return jet->NN_dist * kt2;
1110 }
1111 
1112 
1113 //----------------------------------------------------------------------
1114 // set the NN for jet without checking whether in the process you might
1115 // have discovered a new nearest neighbour for another jet
1116 template <class J> inline void ClusterSequence::_bj_set_NN_nocross(
1117                  J * const jet, J * const head, const J * const tail) const {
1118   double NN_dist = _R2;
1119   J * NN  = NULL;
1120   if (head < jet) {
1121     for (J * jetB = head; jetB != jet; jetB++) {
1122       double dist = _bj_dist(jet,jetB);
1123       if (dist < NN_dist) {
1124         NN_dist = dist;
1125         NN = jetB;
1126       }
1127     }
1128   }
1129   if (tail > jet) {
1130     for (J * jetB = jet+1; jetB != tail; jetB++) {
1131       double dist = _bj_dist(jet,jetB);
1132       if (dist < NN_dist) {
1133         NN_dist = dist;
1134         NN = jetB;
1135       }
1136     }
1137   }
1138   jet->NN = NN;
1139   jet->NN_dist = NN_dist;
1140 }
1141 
1142 
1143 //----------------------------------------------------------------------
1144 template <class J> inline void ClusterSequence::_bj_set_NN_crosscheck(J * const jet, 
1145                     J * const head, const J * const tail) const {
1146   double NN_dist = _R2;
1147   J * NN  = NULL;
1148   for (J * jetB = head; jetB != tail; jetB++) {
1149     double dist = _bj_dist(jet,jetB);
1150     if (dist < NN_dist) {
1151       NN_dist = dist;
1152       NN = jetB;
1153     }
1154     if (dist < jetB->NN_dist) {
1155       jetB->NN_dist = dist;
1156       jetB->NN = jet;
1157     }
1158   }
1159   jet->NN = NN;
1160   jet->NN_dist = NN_dist;
1161 }
1162 
1163 FASTJET_END_NAMESPACE
1164 
1165 #endif // __FASTJET_CLUSTERSEQUENCE_HH__