|
||||
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__
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |