Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:18

0001 #ifndef __FASTJET_NNFJN2PLAIN_HH__
0002 #define __FASTJET_NNFJN2PLAIN_HH__
0003 
0004 //FJSTARTHEADER
0005 // $Id$
0006 //
0007 // Copyright (c) 2005-2021, 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 #include "fastjet/NNBase.hh"
0035 
0036 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
0037 
0038 //----------------------------------------------------------------------
0039 /// @ingroup advanced_usage
0040 /// \class NNFJN2Plain
0041 ///
0042 /// Helps solve closest pair problems with factorised interparticle
0043 /// and beam distances (ie satisfying the FastJet lemma)
0044 ///
0045 /// (see NNBase.hh for an introductory description)
0046 ///
0047 /// This variant provides an implementation based on the N2Plain
0048 /// clustering strategy in FastJet. The interparticle and beam
0049 /// distances should be of the form
0050 ///
0051 /// \code
0052 ///   dij = min(mom_factor(i), mom_factor(j)) * geometrical_distance(i,j)
0053 ///   diB = mom_factor(i) * geometrical_beam_distance(i)
0054 /// \endcode
0055 ///
0056 /// The class is templated with a BJ (brief jet) class and can be used
0057 /// with or without an extra "Information" template,
0058 /// i.e. NNFJN2Plain<BJ> or NNFJN2Plain<BJ,I>
0059 ///
0060 /// For the NNH_N2Plain<BJ> version of the class to function, BJ must
0061 /// provide four member functions
0062 ///  
0063 /// \code
0064 ///   void   BJ::init(const PseudoJet & jet);                   // initialise with a PseudoJet
0065 ///   double BJ::geometrical_distance(const BJ * other_bj_jet); // distance between this and other_bj_jet (geometrical part)
0066 ///   double BJ::geometrical_beam_distance();                   // distance to the beam (geometrical part)
0067 ///   double BJ::momentum_factor();                             // extra momentum factor
0068 /// \endcode
0069 ///
0070 /// For the NNH_N2Plain<BJ,I> version to function, the BJ::init(...)
0071 /// member must accept an extra argument
0072 ///
0073 /// \code
0074 ///   void  BJ::init(const PseudoJet & jet, I * info);   // initialise with a PseudoJet + info
0075 /// \endcode
0076 ///
0077 /// NOTE: THE DISTANCE MUST BE SYMMETRIC I.E. SATISFY
0078 /// \code
0079 ///     a.geometrical_distance(b) == b.geometrical_distance(a)
0080 /// \endcode
0081 ///
0082 /// Note that you are strongly advised to add the following lines to
0083 /// your BJ class to allow it to be used also with NNH:
0084 ///
0085 /// \code
0086 ///   /// make this BJ class compatible with the use of NNH
0087 ///   double BJ::distance(const BJ * other_bj_jet){
0088 ///     double mom1 = momentum_factor();
0089 ///     double mom2 = other_bj_jet->momentum_factor();
0090 ///     return (mom1<mom2 ? mom1 : mom2) * geometrical_distance(other_bj_jet);
0091 ///   }
0092 ///   double BJ::beam_distance(){
0093 ///     return momentum_factor() * geometrical_beam_distance();
0094 ///   }
0095 /// \endcode
0096 ///
0097 template<class BJ, class I = _NoInfo> class NNFJN2Plain : public NNBase<I> {
0098 public:
0099 
0100   /// constructor with an initial set of jets (which will be assigned indices
0101   /// `0...jets.size()-1`)
0102   NNFJN2Plain(const std::vector<PseudoJet> & jets)           : NNBase<I>()     {start(jets);}
0103   NNFJN2Plain(const std::vector<PseudoJet> & jets, I * info) : NNBase<I>(info) {start(jets);}
0104   
0105   /// initialisation from a given list of particles
0106   virtual void start(const std::vector<PseudoJet> & jets);
0107 
0108   /// returns the dij_min and indices iA, iB, for the corresponding jets.
0109   /// If iB < 0 then iA recombines with the beam
0110   double dij_min(int & iA, int & iB);
0111 
0112   /// removes the jet pointed to by index iA
0113   void remove_jet(int iA);
0114 
0115   /// merges the jets pointed to by indices A and B and replace them with
0116   /// jet, assigning it an index jet_index.
0117   void merge_jets(int iA, int iB, const PseudoJet & jet, int jet_index);
0118 
0119   /// a destructor
0120   ~NNFJN2Plain() {
0121     delete[] briefjets;
0122     delete[] diJ;
0123   }
0124     
0125 private:
0126   class NNBJ; // forward declaration
0127 
0128   // return the full distance of a particle to its NN
0129   inline double compute_diJ(const NNBJ * const jet) const {
0130     double mom_fact = jet->momentum_factor();
0131     if (jet->NN != NULL) {
0132       double other_mom_fact = jet->NN->momentum_factor();
0133       if (other_mom_fact < mom_fact) {mom_fact = other_mom_fact;}
0134     }
0135     return jet->NN_dist * mom_fact;
0136   }
0137 
0138   /// establish the nearest neighbour for jet, and cross check consistency
0139   /// of distances for the other jets that are encountered. Assumes
0140   /// jet not contained within begin...end
0141   void set_NN_crosscheck(NNBJ * jet, NNBJ * begin, NNBJ * end);
0142 
0143   /// establish the nearest neighbour for jet; don't cross check other jets'
0144   /// distances and allow jet to be contained within begin...end
0145   void set_NN_nocross   (NNBJ * jet, NNBJ * begin, NNBJ * end);
0146 
0147   /// contains the briefjets
0148   NNBJ * briefjets;
0149 
0150   /// semaphores for the current extent of our structure
0151   NNBJ * head, * tail;
0152 
0153   /// currently active number of jets
0154   int n;
0155 
0156   /// where_is[i] contains a pointer to the jet with index i
0157   std::vector<NNBJ *> where_is;
0158 
0159   /// a table containing all the (full) distances to each object's NN
0160   double * diJ;
0161 
0162   /// a class that wraps around the BJ, supplementing it with extra information
0163   /// such as pointers to neighbours, etc.
0164   class NNBJ : public BJ {
0165   public:
0166     void init(const PseudoJet & jet, int index_in) {
0167       BJ::init(jet);
0168       other_init(index_in);
0169     }
0170     void init(const PseudoJet & jet, int index_in, I * info) {
0171       BJ::init(jet, info);
0172       other_init(index_in);
0173     }
0174     void other_init(int index_in) {
0175       _index = index_in;
0176       NN_dist = BJ::geometrical_beam_distance();
0177       NN = NULL;
0178     }
0179     int index() const {return _index;}
0180     
0181     double NN_dist;
0182     NNBJ * NN;
0183     
0184   private:
0185     int _index;
0186   };
0187 
0188 };
0189 
0190 
0191 
0192 //----------------------------------------------------------------------
0193 template<class BJ, class I> void NNFJN2Plain<BJ,I>::start(const std::vector<PseudoJet> & jets) {
0194   n = jets.size();
0195   briefjets = new NNBJ[n];
0196   where_is.resize(2*n);
0197 
0198   NNBJ * jetA = briefjets;
0199   
0200   // initialise the basic jet info 
0201   for (int i = 0; i< n; i++) {
0202     // the this-> in the next line is required by standard compiler
0203     // see e.g. http://stackoverflow.com/questions/10639053/name-lookups-in-c-templates
0204     this->init_jet(jetA, jets[i], i);
0205     where_is[i] = jetA;
0206     jetA++; // move on to next entry of briefjets
0207   }
0208   tail = jetA; // a semaphore for the end of briefjets
0209   head = briefjets; // a nicer way of naming start
0210 
0211   // now initialise the NN distances: jetA will run from 1..n-1; and
0212   // jetB from 0..jetA-1
0213   for (jetA = head + 1; jetA != tail; jetA++) {
0214     // set NN info for jetA based on jets running from head..jetA-1,
0215     // checking in the process whether jetA itself is an undiscovered
0216     // NN of one of those jets.
0217     set_NN_crosscheck(jetA, head, jetA);
0218   }
0219 
0220   // now create the diJ (where J is i's NN) table -- remember that 
0221   // we differ from standard normalisation here by a factor of R2
0222   diJ = new double[n];
0223   jetA = head;
0224   for (int i = 0; i < n; i++) {
0225     diJ[i] = compute_diJ(jetA);
0226     jetA++; // have jetA follow i
0227   }
0228 }
0229 
0230 
0231 //----------------------------------------------------------------------
0232 template<class BJ, class I> double NNFJN2Plain<BJ,I>::dij_min(int & iA, int & iB) {
0233   // find the minimum of the diJ on this round
0234   double diJ_min = diJ[0];
0235   int diJ_min_jet = 0;
0236   for (int i = 1; i < n; i++) {
0237     if (diJ[i] < diJ_min) {
0238       diJ_min_jet = i;
0239       diJ_min  = diJ[i];
0240     }
0241   }
0242 
0243   // return information to user about recombination
0244   NNBJ * jetA = & briefjets[diJ_min_jet];
0245   //std::cout << jetA - briefjets << std::endl; 
0246   iA = jetA->index();
0247   iB = jetA->NN ? jetA->NN->index() : -1;
0248   return diJ_min;
0249 }
0250 
0251 
0252 //----------------------------------------------------------------------
0253 // remove jetA from the list
0254 template<class BJ, class I> void NNFJN2Plain<BJ,I>::remove_jet(int iA) {
0255   NNBJ * jetA = where_is[iA];
0256   // now update our nearest neighbour info and diJ table
0257   // first reduce size of table
0258   tail--; n--;
0259   // Copy last jet contents and diJ info into position of jetA
0260   *jetA = *tail;
0261   // update the info on where the given index is stored
0262   where_is[jetA->index()] = jetA;
0263   diJ[jetA - head] = diJ[tail-head];
0264 
0265   // updating NN infos. 2 cases to watch for (see below)
0266   for (NNBJ * jetI = head; jetI != tail; jetI++) {
0267     // see if jetI had jetA as a NN -- if so recalculate the NN
0268     if (jetI->NN == jetA) {
0269       set_NN_nocross(jetI, head, tail);
0270       diJ[jetI-head] = compute_diJ(jetI); // update diJ 
0271     } 
0272     // if jetI's NN is the new tail then relabel it so that it becomes jetA
0273     if (jetI->NN == tail) {jetI->NN = jetA;}
0274   }
0275 }
0276 
0277 
0278 //----------------------------------------------------------------------
0279 template<class BJ, class I> void NNFJN2Plain<BJ,I>::merge_jets(int iA, int iB, 
0280                     const PseudoJet & jet, int index) {
0281 
0282   NNBJ * jetA = where_is[iA];
0283   NNBJ * jetB = where_is[iB];
0284 
0285   // If necessary relabel A & B to ensure jetB < jetA, that way if
0286   // the larger of them == newtail then that ends up being jetA and 
0287   // the new jet that is added as jetB is inserted in a position that
0288   // has a future!
0289   if (jetA < jetB) std::swap(jetA,jetB);
0290 
0291   // initialise jetB based on the new jet
0292   this->init_jet(jetB, jet, index);
0293   // and record its position (making sure we have the space)
0294   if (index >= int(where_is.size())) where_is.resize(2*index);
0295   where_is[jetB->index()] = jetB;
0296 
0297   // now update our nearest neighbour info
0298   // first reduce size of table
0299   tail--; n--;
0300   // Copy last jet contents into position of jetA
0301   *jetA = *tail;
0302   // update the info on where the tail's index is stored
0303   where_is[jetA->index()] = jetA;
0304   diJ[jetA - head] = diJ[tail-head];
0305 
0306   // initialise jetB NN's distance and update NN infos
0307   for (NNBJ * jetI = head; jetI != tail; jetI++) {
0308     // see if jetI had jetA or jetB as a NN -- if so recalculate the NN
0309     if (jetI->NN == jetA || jetI->NN == jetB) {
0310       set_NN_nocross(jetI, head, tail);
0311       diJ[jetI-head] = compute_diJ(jetI); // update diJ 
0312     } 
0313 
0314     // check whether new jetB is closer than jetI's current NN and
0315     // if need be update things
0316     double dist = jetI->geometrical_distance(jetB);
0317     if (dist < jetI->NN_dist) {  // we need to update I
0318       if (jetI != jetB) {
0319         jetI->NN_dist = dist;
0320         jetI->NN = jetB;
0321         diJ[jetI-head] = compute_diJ(jetI); // update diJ...
0322       }
0323     }
0324     if (dist < jetB->NN_dist) { // we need to update B
0325       if (jetI != jetB) {
0326         jetB->NN_dist = dist;
0327         jetB->NN      = jetI;
0328       }
0329     }
0330 
0331     // if jetI's NN is the new tail then relabel it so that it becomes jetA
0332     if (jetI->NN == tail) {jetI->NN = jetA;}
0333   }
0334 
0335   // update info for jetB
0336   diJ[jetB-head] = compute_diJ(jetB);
0337 }
0338 
0339 
0340 //----------------------------------------------------------------------
0341 // this function assumes that jet is not contained within begin...end
0342 template <class BJ, class I> void NNFJN2Plain<BJ,I>::set_NN_crosscheck(NNBJ * jet, 
0343             NNBJ * begin, NNBJ * end) {
0344   double NN_dist = jet->geometrical_beam_distance();
0345   NNBJ * NN      = NULL;
0346   for (NNBJ * jetB = begin; jetB != end; jetB++) {
0347     double dist = jet->geometrical_distance(jetB);
0348     if (dist < NN_dist) {
0349       NN_dist = dist;
0350       NN = jetB;
0351     }
0352     if (dist < jetB->NN_dist) {
0353       jetB->NN_dist = dist;
0354       jetB->NN = jet;
0355     }
0356   }
0357   jet->NN = NN;
0358   jet->NN_dist = NN_dist;
0359 }
0360 
0361 
0362 //----------------------------------------------------------------------
0363 // set the NN for jet without checking whether in the process you might
0364 // have discovered a new nearest neighbour for another jet
0365 template <class BJ, class I>  void NNFJN2Plain<BJ,I>::set_NN_nocross(
0366                  NNBJ * jet, NNBJ * begin, NNBJ * end) {
0367   double NN_dist = jet->geometrical_beam_distance();
0368   NNBJ * NN      = NULL;
0369   // if (head < jet) {
0370   //   for (NNBJ * jetB = head; jetB != jet; jetB++) {
0371   if (begin < jet) {
0372     for (NNBJ * jetB = begin; jetB != jet; jetB++) {
0373       double dist = jet->geometrical_distance(jetB);
0374       if (dist < NN_dist) {
0375     NN_dist = dist;
0376     NN = jetB;
0377       }
0378     }
0379   }
0380   // if (tail > jet) {
0381   //   for (NNBJ * jetB = jet+1; jetB != tail; jetB++) {
0382   if (end > jet) {
0383     for (NNBJ * jetB = jet+1; jetB != end; jetB++) {
0384       double dist = jet->geometrical_distance(jetB);
0385       if (dist < NN_dist) {
0386     NN_dist = dist;
0387     NN = jetB;
0388       }
0389     }
0390   }
0391   jet->NN = NN;
0392   jet->NN_dist = NN_dist;
0393 }
0394 
0395 
0396 
0397 
0398 FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
0399 
0400 
0401 #endif // __FASTJET_NNFJN2PLAIN_HH__