FastJet 3.0beta1
|
00001 //STARTHEADER 00002 // $Id: ClusterSequence_CP2DChan.cc 1938 2011-02-08 15:06:00Z 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 #include "fastjet/ClusterSequence.hh" 00032 #include "fastjet/internal/ClosestPair2D.hh" 00033 #include<limits> 00034 #include<vector> 00035 #include<cmath> 00036 #include<iostream> 00037 00038 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 00039 00040 using namespace std; 00041 00042 // place for things we don't want outside world to run into 00043 namespace Private { 00044 /// class for helping us deal with mirror-image particles. 00045 class MirrorInfo{ 00046 public: 00047 int orig, mirror; 00048 MirrorInfo(int a, int b) : orig(a), mirror(b) {}; 00049 MirrorInfo() {}; 00050 }; 00051 00052 /// if there is a need for a mirror when looking for closest pairs 00053 /// up to distance D, then return true and turn the supplied point 00054 /// into its mirror copy 00055 bool make_mirror(Coord2D & point, double Dlim) { 00056 if (point.y < Dlim) {point.y += twopi; return true;} 00057 if (twopi-point.y < Dlim) {point.y -= twopi; return true;} 00058 return false; 00059 } 00060 00061 } 00062 00063 using namespace Private; 00064 00065 00066 //---------------------------------------------------------------------- 00067 /// clusters only up to a distance Dlim -- does not deal with "inclusive" jets 00068 /// -- these are left to some other part of the program 00069 void ClusterSequence::_CP2DChan_limited_cluster (double Dlim) { 00070 00071 unsigned int n = _initial_n; 00072 00073 vector<MirrorInfo> coordIDs(2*n); // coord IDs of a given jetID 00074 vector<int> jetIDs(2*n); // jet ID for a given coord ID 00075 vector<Coord2D> coords(2*n); // our coordinates (and copies) 00076 00077 // particles within a distance Dlim of the phi edges (phi<Dlim || 00078 // phi>2pi-Dli;) will be mirrored. For Dlim>pi, this could lead to 00079 // particles copies outside the fixed range in phi which is 00080 // [-pi:3pi] (see make_mirror above). Since in that case all 00081 // particles get copied anywaym we can just copy particles up to a 00082 // distance "pi" from the edges 00083 double Dlim4mirror = min(Dlim,pi); 00084 00085 // start things off... 00086 double minrap = numeric_limits<double>::max(); 00087 double maxrap = -minrap; 00088 int coord_index = -1; 00089 int n_active = 0; 00090 for (unsigned jet_i = 0; jet_i < _jets.size(); jet_i++) { 00091 00092 // skip jets that already have children or that have infinite 00093 // rapidity 00094 if (_history[_jets[jet_i].cluster_hist_index()].child != Invalid || 00095 (_jets[jet_i].E() == abs(_jets[jet_i].pz()) && 00096 _jets[jet_i].perp2() == 0.0) 00097 ) {continue;} 00098 00099 n_active++; 00100 00101 coordIDs[jet_i].orig = ++coord_index; 00102 coords[coord_index] = Coord2D(_jets[jet_i].rap(), _jets[jet_i].phi_02pi()); 00103 jetIDs[coord_index] = jet_i; 00104 minrap = min(coords[coord_index].x,minrap); 00105 maxrap = max(coords[coord_index].x,maxrap); 00106 00107 Coord2D mirror_point(coords[coord_index]); 00108 if (make_mirror(mirror_point, Dlim4mirror)) { 00109 coordIDs[jet_i].mirror = ++coord_index; 00110 coords[coord_index] = mirror_point; 00111 jetIDs[coord_index] = jet_i; 00112 } else { 00113 coordIDs[jet_i].mirror = Invalid; 00114 } 00115 } 00116 00117 // set them to their actual size... 00118 coords.resize(coord_index+1); 00119 00120 // establish limits (with some leeway on rapidity) 00121 Coord2D left_edge(minrap-1.0, -3.15); // a security margin below -pi 00122 Coord2D right_edge(maxrap+1.0, 9.45); // a security margin above 3*pi 00123 00124 //cerr << "minrap, maxrap = " << minrap << " " << maxrap << endl; 00125 00126 // now create the closest pair search object 00127 ClosestPair2D cp(coords, left_edge, right_edge); 00128 00129 // cross check to see what's going on... 00130 //cerr << "Tree depths before: "; 00131 //cp.print_tree_depths(cerr); 00132 00133 // and start iterating... 00134 vector<Coord2D> new_points(2); 00135 vector<unsigned int> cIDs_to_remove(4); 00136 vector<unsigned int> new_cIDs(2); 00137 00138 do { 00139 // find out which pair we recombine 00140 unsigned int cID1, cID2; 00141 double distance2; 00142 cp.closest_pair(cID1,cID2,distance2); 00143 00144 // if the closest distance > Dlim, we exit and go to "inclusive" stage 00145 if (distance2 > Dlim*Dlim) {break;} 00146 00147 // normalise distance as we like it 00148 distance2 *= _invR2; 00149 00150 // do the recombination... 00151 int jet_i = jetIDs[cID1]; 00152 int jet_j = jetIDs[cID2]; 00153 assert (jet_i != jet_j); // to catch issue of recombining with mirror point 00154 int newjet_k; 00155 _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k); 00156 00157 // don't bother with any further action if only one active particle 00158 // is left (also avoid closest-pair error [cannot remove last particle]). 00159 if (--n_active == 1) {break;} 00160 00161 // now prepare operations on CP structure 00162 cIDs_to_remove.resize(0); 00163 cIDs_to_remove.push_back(coordIDs[jet_i].orig); 00164 cIDs_to_remove.push_back(coordIDs[jet_j].orig); 00165 if (coordIDs[jet_i].mirror != Invalid) 00166 cIDs_to_remove.push_back(coordIDs[jet_i].mirror); 00167 if (coordIDs[jet_j].mirror != Invalid) 00168 cIDs_to_remove.push_back(coordIDs[jet_j].mirror); 00169 00170 Coord2D new_point(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi()); 00171 new_points.resize(0); 00172 new_points.push_back(new_point); 00173 if (make_mirror(new_point, Dlim4mirror)) new_points.push_back(new_point); //< same warning as before concerning the mirroring 00174 00175 // carry out actions on search tree 00176 cp.replace_many(cIDs_to_remove, new_points, new_cIDs); 00177 00178 // now fill in info for new points... 00179 coordIDs[newjet_k].orig = new_cIDs[0]; 00180 jetIDs[new_cIDs[0]] = newjet_k; 00181 if (new_cIDs.size() == 2) { 00182 coordIDs[newjet_k].mirror = new_cIDs[1]; 00183 jetIDs[new_cIDs[1]] = newjet_k; 00184 } else {coordIDs[newjet_k].mirror = Invalid;} 00185 00186 //// if we've reached one "active" jet we should exit... 00187 //n_active--; 00188 //if (n_active == 1) {break;} 00189 00190 } while(true); 00191 00192 // cross check to see what's going on... 00193 //cerr << "Max tree depths after: "; 00194 //cp.print_tree_depths(cerr); 00195 00196 } 00197 00198 00199 //---------------------------------------------------------------------- 00200 /// a variant of the closest pair clustering which uses a region of 00201 /// size 2pi+2R in phi. 00202 void ClusterSequence::_CP2DChan_cluster_2pi2R () { 00203 00204 if (_jet_algorithm != cambridge_algorithm) throw Error("CP2DChan clustering method called for a jet-finder that is not the cambridge algorithm"); 00205 00206 // run the clustering with mirror copies kept such that only things 00207 // within _Rparam of a border are mirrored 00208 _CP2DChan_limited_cluster(_Rparam); 00209 00210 // 00211 _do_Cambridge_inclusive_jets(); 00212 } 00213 00214 00215 //---------------------------------------------------------------------- 00216 /// a variant of the closest pair clustering which uses a region of 00217 /// size 2pi + 2*0.3 and then carries on with 2pi+2*R 00218 void ClusterSequence::_CP2DChan_cluster_2piMultD () { 00219 00220 // do a first run of clustering up to a small distance parameter, 00221 if (_Rparam >= 0.39) { 00222 _CP2DChan_limited_cluster(min(_Rparam/2,0.3)); 00223 } 00224 00225 // and then the final round of clustering 00226 _CP2DChan_cluster_2pi2R (); 00227 } 00228 00229 00230 //---------------------------------------------------------------------- 00231 /// a 4pi variant of the closest pair clustering 00232 void ClusterSequence::_CP2DChan_cluster () { 00233 00234 if (_jet_algorithm != cambridge_algorithm) throw Error("_CP2DChan_cluster called for a jet-finder that is not the cambridge algorithm"); 00235 00236 unsigned int n = _jets.size(); 00237 00238 vector<MirrorInfo> coordIDs(2*n); // link from original to mirror indices 00239 vector<int> jetIDs(2*n); // link from mirror to original indices 00240 vector<Coord2D> coords(2*n); // our coordinates (and copies) 00241 00242 // start things off... 00243 double minrap = numeric_limits<double>::max(); 00244 double maxrap = -minrap; 00245 int coord_index = 0; 00246 for (unsigned i = 0; i < n; i++) { 00247 // separate out points with infinite rapidity 00248 if (_jets[i].E() == abs(_jets[i].pz()) && _jets[i].perp2() == 0.0) { 00249 coordIDs[i] = MirrorInfo(BeamJet,BeamJet); 00250 } else { 00251 coordIDs[i].orig = coord_index; 00252 coordIDs[i].mirror = coord_index+1; 00253 coords[coord_index] = Coord2D(_jets[i].rap(), _jets[i].phi_02pi()); 00254 coords[coord_index+1] = Coord2D(_jets[i].rap(), _jets[i].phi_02pi()+twopi); 00255 jetIDs[coord_index] = i; 00256 jetIDs[coord_index+1] = i; 00257 minrap = min(coords[coord_index].x,minrap); 00258 maxrap = max(coords[coord_index].x,maxrap); 00259 coord_index += 2; 00260 } 00261 } 00262 // label remaining "mirror info" as saying that there are no jets 00263 for (unsigned i = n; i < 2*n; i++) {coordIDs[i].orig = Invalid;} 00264 00265 // set them to their actual size... 00266 coords.resize(coord_index); 00267 00268 // establish limits (with some leeway on rapidity) 00269 Coord2D left_edge(minrap-1.0, 0.0); 00270 Coord2D right_edge(maxrap+1.0, 2*twopi); 00271 00272 // now create the closest pair search object 00273 ClosestPair2D cp(coords, left_edge, right_edge); 00274 00275 // and start iterating... 00276 vector<Coord2D> new_points(2); 00277 vector<unsigned int> cIDs_to_remove(4); 00278 vector<unsigned int> new_cIDs(2); 00279 do { 00280 // find out which pair we recombine 00281 unsigned int cID1, cID2; 00282 double distance2; 00283 cp.closest_pair(cID1,cID2,distance2); 00284 distance2 *= _invR2; 00285 00286 // if the closest distance > 1, we exit and go to "inclusive" stage 00287 if (distance2 > 1.0) {break;} 00288 00289 // do the recombination... 00290 int jet_i = jetIDs[cID1]; 00291 int jet_j = jetIDs[cID2]; 00292 assert (jet_i != jet_j); // to catch issue of recombining with mirror point 00293 int newjet_k; 00294 _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k); 00295 00296 // now prepare operations on CP structure 00297 cIDs_to_remove[0] = coordIDs[jet_i].orig; 00298 cIDs_to_remove[1] = coordIDs[jet_i].mirror; 00299 cIDs_to_remove[2] = coordIDs[jet_j].orig; 00300 cIDs_to_remove[3] = coordIDs[jet_j].mirror; 00301 new_points[0] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi()); 00302 new_points[1] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi()+twopi); 00303 // carry out the CP operation 00304 //cp.replace_many(cIDs_to_remove, new_points, new_cIDs); 00305 // remarkable the following is faster... 00306 new_cIDs[0] = cp.replace(cIDs_to_remove[0], cIDs_to_remove[2], new_points[0]); 00307 new_cIDs[1] = cp.replace(cIDs_to_remove[1], cIDs_to_remove[3], new_points[1]); 00308 // signal that the following jets no longer exist 00309 coordIDs[jet_i].orig = Invalid; 00310 coordIDs[jet_j].orig = Invalid; 00311 // and do bookkeeping for new jet 00312 coordIDs[newjet_k] = MirrorInfo(new_cIDs[0], new_cIDs[1]); 00313 jetIDs[new_cIDs[0]] = newjet_k; 00314 jetIDs[new_cIDs[1]] = newjet_k; 00315 00316 // if we've reached one jet we should exit... 00317 n--; 00318 if (n == 1) {break;} 00319 00320 } while(true); 00321 00322 00323 // now do "beam" recombinations 00324 //for (unsigned int jet_i = 0; jet_i < coordIDs.size(); jet_i++) { 00325 // // if we have a predeclared beam jet or a valid set of mirror 00326 // // coordinates, recombine then recombine this jet with the beam 00327 // if (coordIDs[jet_i].orig == BeamJet || coordIDs[jet_i].orig > 0) { 00328 // // diB = 1 _always_ (for the cambridge alg.) 00329 // _do_iB_recombination_step(jet_i, 1.0); 00330 // } 00331 //} 00332 00333 _do_Cambridge_inclusive_jets(); 00334 00335 //n = _history.size(); 00336 //for (unsigned int hist_i = 0; hist_i < n; hist_i++) { 00337 // if (_history[hist_i].child == Invalid) { 00338 // _do_iB_recombination_step(_history[hist_i].jetp_index, 1.0); 00339 // } 00340 //} 00341 00342 } 00343 00344 00345 //---------------------------------------------------------------------- 00346 void ClusterSequence::_do_Cambridge_inclusive_jets () { 00347 unsigned int n = _history.size(); 00348 for (unsigned int hist_i = 0; hist_i < n; hist_i++) { 00349 if (_history[hist_i].child == Invalid) { 00350 _do_iB_recombination_step(_history[hist_i].jetp_index, 1.0); 00351 } 00352 } 00353 } 00354 00355 FASTJET_END_NAMESPACE 00356