1 | //STARTHEADER
|
---|
2 | // $Id: PseudoJet.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
|
---|
3 | //
|
---|
4 | // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
|
---|
5 | //
|
---|
6 | //----------------------------------------------------------------------
|
---|
7 | // This file is part of FastJet.
|
---|
8 | //
|
---|
9 | // FastJet is free software; you can redistribute it and/or modify
|
---|
10 | // it under the terms of the GNU General Public License as published by
|
---|
11 | // the Free Software Foundation; either version 2 of the License, or
|
---|
12 | // (at your option) any later version.
|
---|
13 | //
|
---|
14 | // The algorithms that underlie FastJet have required considerable
|
---|
15 | // development and are described in hep-ph/0512210. If you use
|
---|
16 | // FastJet as part of work towards a scientific publication, please
|
---|
17 | // include a citation to the FastJet paper.
|
---|
18 | //
|
---|
19 | // FastJet is distributed in the hope that it will be useful,
|
---|
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
22 | // GNU General Public License for more details.
|
---|
23 | //
|
---|
24 | // You should have received a copy of the GNU General Public License
|
---|
25 | // along with FastJet; if not, write to the Free Software
|
---|
26 | // Foundation, Inc.:
|
---|
27 | // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
28 | //----------------------------------------------------------------------
|
---|
29 | //ENDHEADER
|
---|
30 |
|
---|
31 |
|
---|
32 | #include "../include/fastjet/Error.hh"
|
---|
33 | #include "../include/fastjet/PseudoJet.hh"
|
---|
34 | #include<valarray>
|
---|
35 | #include<iostream>
|
---|
36 | #include<sstream>
|
---|
37 | #include<cmath>
|
---|
38 | #include<algorithm>
|
---|
39 |
|
---|
40 | FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
|
---|
41 |
|
---|
42 | using namespace std;
|
---|
43 |
|
---|
44 |
|
---|
45 | //----------------------------------------------------------------------
|
---|
46 | // another constructor...
|
---|
47 | PseudoJet::PseudoJet(const double px, const double py, const double pz, const double E) {
|
---|
48 |
|
---|
49 | _E = E ;
|
---|
50 | _px = px;
|
---|
51 | _py = py;
|
---|
52 | _pz = pz;
|
---|
53 |
|
---|
54 | this->_finish_init();
|
---|
55 |
|
---|
56 | // some default values for the history and user indices
|
---|
57 | _reset_indices();
|
---|
58 |
|
---|
59 | }
|
---|
60 |
|
---|
61 |
|
---|
62 | //----------------------------------------------------------------------
|
---|
63 | /// do standard end of initialisation
|
---|
64 | void PseudoJet::_finish_init () {
|
---|
65 | _kt2 = this->px()*this->px() + this->py()*this->py();
|
---|
66 | if (_kt2 == 0.0) {
|
---|
67 | _phi = 0.0; }
|
---|
68 | else {
|
---|
69 | _phi = atan2(this->py(),this->px());
|
---|
70 | }
|
---|
71 | if (_phi < 0.0) {_phi += twopi;}
|
---|
72 | if (_phi >= twopi) {_phi -= twopi;} // can happen if phi=-|eps<1e-15|?
|
---|
73 | if (this->E() == abs(this->pz()) && _kt2 == 0) {
|
---|
74 | // Point has infinite rapidity -- convert that into a very large
|
---|
75 | // number, but in such a way that different 0-pt momenta will have
|
---|
76 | // different rapidities (so as to lift the degeneracy between
|
---|
77 | // them) [this can be relevant at parton-level]
|
---|
78 | double MaxRapHere = MaxRap + abs(this->pz());
|
---|
79 | if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
|
---|
80 | } else {
|
---|
81 | // get the rapidity in a way that's modestly insensitive to roundoff
|
---|
82 | // error when things pz,E are large (actually the best we can do without
|
---|
83 | // explicit knowledge of mass)
|
---|
84 | double effective_m2 = max(0.0,m2()); // force non tachyonic mass
|
---|
85 | double E_plus_pz = _E + abs(_pz); // the safer of p+, p-
|
---|
86 | // p+/p- = (p+ p-) / (p-)^2 = (kt^2+m^2)/(p-)^2
|
---|
87 | _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
|
---|
88 | if (_pz > 0) {_rap = - _rap;}
|
---|
89 | }
|
---|
90 |
|
---|
91 | //// original determination
|
---|
92 | //if (this->E() != abs(this->pz())) {
|
---|
93 | // _rap = 0.5*log((this->E() + this->pz())/(this->E() - this->pz()));
|
---|
94 | // } else {
|
---|
95 | // // Overlapping points can give problems. Let's lift the degeneracy
|
---|
96 | // // in case of multiple 0-pT points (can be found at parton-level)
|
---|
97 | // double MaxRapHere = MaxRap + abs(this->pz());
|
---|
98 | // if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
|
---|
99 | //}
|
---|
100 | }
|
---|
101 |
|
---|
102 |
|
---|
103 | //----------------------------------------------------------------------
|
---|
104 | // return a valarray four-momentum
|
---|
105 | valarray<double> PseudoJet::four_mom() const {
|
---|
106 | valarray<double> mom(4);
|
---|
107 | mom[0] = _px;
|
---|
108 | mom[1] = _py;
|
---|
109 | mom[2] = _pz;
|
---|
110 | mom[3] = _E ;
|
---|
111 | return mom;
|
---|
112 | }
|
---|
113 |
|
---|
114 | //----------------------------------------------------------------------
|
---|
115 | // Return the component corresponding to the specified index.
|
---|
116 | // taken from CLHEP
|
---|
117 | double PseudoJet::operator () (int i) const {
|
---|
118 | switch(i) {
|
---|
119 | case X:
|
---|
120 | return px();
|
---|
121 | case Y:
|
---|
122 | return py();
|
---|
123 | case Z:
|
---|
124 | return pz();
|
---|
125 | case T:
|
---|
126 | return e();
|
---|
127 | default:
|
---|
128 | ostringstream err;
|
---|
129 | err << "PseudoJet subscripting: bad index (" << i << ")";
|
---|
130 | throw Error(err.str());
|
---|
131 | }
|
---|
132 | return 0.;
|
---|
133 | }
|
---|
134 |
|
---|
135 | //----------------------------------------------------------------------
|
---|
136 | // return the pseudorapidity
|
---|
137 | double PseudoJet::pseudorapidity() const {
|
---|
138 | if (px() == 0.0 && py() ==0.0) return MaxRap;
|
---|
139 | if (pz() == 0.0) return 0.0;
|
---|
140 |
|
---|
141 | double theta = atan(perp()/pz());
|
---|
142 | if (theta < 0) theta += pi;
|
---|
143 | return -log(tan(theta/2));
|
---|
144 | }
|
---|
145 |
|
---|
146 | //----------------------------------------------------------------------
|
---|
147 | // return "sum" of two pseudojets
|
---|
148 | PseudoJet operator+ (const PseudoJet & jet1, const PseudoJet & jet2) {
|
---|
149 | //return PseudoJet(jet1.four_mom()+jet2.four_mom());
|
---|
150 | return PseudoJet(jet1.px()+jet2.px(),
|
---|
151 | jet1.py()+jet2.py(),
|
---|
152 | jet1.pz()+jet2.pz(),
|
---|
153 | jet1.E() +jet2.E() );
|
---|
154 | }
|
---|
155 |
|
---|
156 | //----------------------------------------------------------------------
|
---|
157 | // return difference of two pseudojets
|
---|
158 | PseudoJet operator- (const PseudoJet & jet1, const PseudoJet & jet2) {
|
---|
159 | //return PseudoJet(jet1.four_mom()-jet2.four_mom());
|
---|
160 | return PseudoJet(jet1.px()-jet2.px(),
|
---|
161 | jet1.py()-jet2.py(),
|
---|
162 | jet1.pz()-jet2.pz(),
|
---|
163 | jet1.E() -jet2.E() );
|
---|
164 | }
|
---|
165 |
|
---|
166 | //----------------------------------------------------------------------
|
---|
167 | // return the product, coeff * jet
|
---|
168 | PseudoJet operator* (double coeff, const PseudoJet & jet) {
|
---|
169 | //return PseudoJet(coeff*jet.four_mom());
|
---|
170 | // the following code is hopefully more efficient
|
---|
171 | PseudoJet coeff_times_jet(jet);
|
---|
172 | coeff_times_jet *= coeff;
|
---|
173 | return coeff_times_jet;
|
---|
174 | }
|
---|
175 |
|
---|
176 | //----------------------------------------------------------------------
|
---|
177 | // return the product, coeff * jet
|
---|
178 | PseudoJet operator* (const PseudoJet & jet, double coeff) {
|
---|
179 | return coeff*jet;
|
---|
180 | }
|
---|
181 |
|
---|
182 | //----------------------------------------------------------------------
|
---|
183 | // return the ratio, jet / coeff
|
---|
184 | PseudoJet operator/ (const PseudoJet & jet, double coeff) {
|
---|
185 | return (1.0/coeff)*jet;
|
---|
186 | }
|
---|
187 |
|
---|
188 | //----------------------------------------------------------------------
|
---|
189 | /// multiply the jet's momentum by the coefficient
|
---|
190 | void PseudoJet::operator*=(double coeff) {
|
---|
191 | _px *= coeff;
|
---|
192 | _py *= coeff;
|
---|
193 | _pz *= coeff;
|
---|
194 | _E *= coeff;
|
---|
195 | _kt2*= coeff*coeff;
|
---|
196 | // phi and rap are unchanged
|
---|
197 | }
|
---|
198 |
|
---|
199 | //----------------------------------------------------------------------
|
---|
200 | /// divide the jet's momentum by the coefficient
|
---|
201 | void PseudoJet::operator/=(double coeff) {
|
---|
202 | (*this) *= 1.0/coeff;
|
---|
203 | }
|
---|
204 |
|
---|
205 |
|
---|
206 | //----------------------------------------------------------------------
|
---|
207 | /// add the other jet's momentum to this jet
|
---|
208 | void PseudoJet::operator+=(const PseudoJet & other_jet) {
|
---|
209 | _px += other_jet._px;
|
---|
210 | _py += other_jet._py;
|
---|
211 | _pz += other_jet._pz;
|
---|
212 | _E += other_jet._E ;
|
---|
213 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
214 | }
|
---|
215 |
|
---|
216 |
|
---|
217 | //----------------------------------------------------------------------
|
---|
218 | /// subtract the other jet's momentum from this jet
|
---|
219 | void PseudoJet::operator-=(const PseudoJet & other_jet) {
|
---|
220 | _px -= other_jet._px;
|
---|
221 | _py -= other_jet._py;
|
---|
222 | _pz -= other_jet._pz;
|
---|
223 | _E -= other_jet._E ;
|
---|
224 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
225 | }
|
---|
226 |
|
---|
227 |
|
---|
228 | //----------------------------------------------------------------------
|
---|
229 | /// transform this jet (given in the rest frame of prest) into a jet
|
---|
230 | /// in the lab frame;
|
---|
231 | //
|
---|
232 | // NB: code adapted from that in herwig f77 (checked how it worked
|
---|
233 | // long ago)
|
---|
234 | PseudoJet & PseudoJet::boost(const PseudoJet & prest) {
|
---|
235 |
|
---|
236 | if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
|
---|
237 | return *this;
|
---|
238 |
|
---|
239 | double m = prest.m();
|
---|
240 | assert(m != 0);
|
---|
241 |
|
---|
242 | double pf4 = ( px()*prest.px() + py()*prest.py()
|
---|
243 | + pz()*prest.pz() + E()*prest.E() )/m;
|
---|
244 | double fn = (pf4 + E()) / (prest.E() + m);
|
---|
245 | _px += fn*prest.px();
|
---|
246 | _py += fn*prest.py();
|
---|
247 | _pz += fn*prest.pz();
|
---|
248 | _E = pf4;
|
---|
249 |
|
---|
250 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
251 | return *this;
|
---|
252 | }
|
---|
253 |
|
---|
254 |
|
---|
255 | //----------------------------------------------------------------------
|
---|
256 | /// transform this jet (given in the rest frame of prest) into a jet
|
---|
257 | /// in the lab frame;
|
---|
258 | //
|
---|
259 | // NB: code adapted from that in herwig f77 (checked how it worked
|
---|
260 | // long ago)
|
---|
261 | PseudoJet & PseudoJet::unboost(const PseudoJet & prest) {
|
---|
262 |
|
---|
263 | if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
|
---|
264 | return *this;
|
---|
265 |
|
---|
266 | double m = prest.m();
|
---|
267 | assert(m != 0);
|
---|
268 |
|
---|
269 | double pf4 = ( -px()*prest.px() - py()*prest.py()
|
---|
270 | - pz()*prest.pz() + E()*prest.E() )/m;
|
---|
271 | double fn = (pf4 + E()) / (prest.E() + m);
|
---|
272 | _px -= fn*prest.px();
|
---|
273 | _py -= fn*prest.py();
|
---|
274 | _pz -= fn*prest.pz();
|
---|
275 | _E = pf4;
|
---|
276 |
|
---|
277 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
278 | return *this;
|
---|
279 | }
|
---|
280 |
|
---|
281 |
|
---|
282 | //----------------------------------------------------------------------
|
---|
283 | /// returns true if the momenta of the two input jets are identical
|
---|
284 | bool have_same_momentum(const PseudoJet & jeta, const PseudoJet & jetb) {
|
---|
285 | return jeta.px() == jetb.px()
|
---|
286 | && jeta.py() == jetb.py()
|
---|
287 | && jeta.pz() == jetb.pz()
|
---|
288 | && jeta.E() == jetb.E();
|
---|
289 | }
|
---|
290 |
|
---|
291 |
|
---|
292 | //----------------------------------------------------------------------
|
---|
293 | /// return a pseudojet with the given pt, y, phi and mass
|
---|
294 | PseudoJet PtYPhiM(double pt, double y, double phi, double m) {
|
---|
295 | double ptm = sqrt(pt*pt+m*m);
|
---|
296 | return PseudoJet(pt*cos(phi), pt*sin(phi), ptm*sinh(y), ptm*cosh(y));
|
---|
297 | }
|
---|
298 |
|
---|
299 |
|
---|
300 | //----------------------------------------------------------------------
|
---|
301 | // return kt-distance between this jet and another one
|
---|
302 | double PseudoJet::kt_distance(const PseudoJet & other) const {
|
---|
303 | //double distance = min(this->kt2(), other.kt2());
|
---|
304 | double distance = min(_kt2, other._kt2);
|
---|
305 | double dphi = abs(_phi - other._phi);
|
---|
306 | if (dphi > pi) {dphi = twopi - dphi;}
|
---|
307 | double drap = _rap - other._rap;
|
---|
308 | distance = distance * (dphi*dphi + drap*drap);
|
---|
309 | return distance;
|
---|
310 | }
|
---|
311 |
|
---|
312 |
|
---|
313 | //----------------------------------------------------------------------
|
---|
314 | // return squared cylinder (eta-phi) distance between this jet and another one
|
---|
315 | double PseudoJet::plain_distance(const PseudoJet & other) const {
|
---|
316 | double dphi = abs(_phi - other._phi);
|
---|
317 | if (dphi > pi) {dphi = twopi - dphi;}
|
---|
318 | double drap = _rap - other._rap;
|
---|
319 | return (dphi*dphi + drap*drap);
|
---|
320 | }
|
---|
321 |
|
---|
322 | //----------------------------------------------------------------------
|
---|
323 | // sort the indices so that values[indices[0..n-1]] is sorted
|
---|
324 | // into increasing order
|
---|
325 | void sort_indices(vector<int> & indices,
|
---|
326 | const vector<double> & values) {
|
---|
327 | IndexedSortHelper index_sort_helper(&values);
|
---|
328 | sort(indices.begin(), indices.end(), index_sort_helper);
|
---|
329 | }
|
---|
330 |
|
---|
331 | //----------------------------------------------------------------------
|
---|
332 | /// given a vector of values with a one-to-one correspondence with the
|
---|
333 | /// vector of objects, sort objects into an order such that the
|
---|
334 | /// associated values would be in increasing order
|
---|
335 | template<class T> vector<T> objects_sorted_by_values(
|
---|
336 | const vector<T> & objects,
|
---|
337 | const vector<double> & values) {
|
---|
338 |
|
---|
339 | assert(objects.size() == values.size());
|
---|
340 |
|
---|
341 | // get a vector of indices
|
---|
342 | vector<int> indices(values.size());
|
---|
343 | for (size_t i = 0; i < indices.size(); i++) {indices[i] = i;}
|
---|
344 |
|
---|
345 | // sort the indices
|
---|
346 | sort_indices(indices, values);
|
---|
347 |
|
---|
348 | // copy the objects
|
---|
349 | vector<T> objects_sorted(objects.size());
|
---|
350 |
|
---|
351 | // place the objects in the correct order
|
---|
352 | for (size_t i = 0; i < indices.size(); i++) {
|
---|
353 | objects_sorted[i] = objects[indices[i]];
|
---|
354 | }
|
---|
355 |
|
---|
356 | return objects_sorted;
|
---|
357 | }
|
---|
358 |
|
---|
359 | //----------------------------------------------------------------------
|
---|
360 | /// return a vector of jets sorted into decreasing kt2
|
---|
361 | vector<PseudoJet> sorted_by_pt(const vector<PseudoJet> & jets) {
|
---|
362 | vector<double> minus_kt2(jets.size());
|
---|
363 | for (size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
|
---|
364 | return objects_sorted_by_values(jets, minus_kt2);
|
---|
365 | }
|
---|
366 |
|
---|
367 | //----------------------------------------------------------------------
|
---|
368 | /// return a vector of jets sorted into increasing rapidity
|
---|
369 | vector<PseudoJet> sorted_by_rapidity(const vector<PseudoJet> & jets) {
|
---|
370 | vector<double> rapidities(jets.size());
|
---|
371 | for (size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
|
---|
372 | return objects_sorted_by_values(jets, rapidities);
|
---|
373 | }
|
---|
374 |
|
---|
375 | //----------------------------------------------------------------------
|
---|
376 | /// return a vector of jets sorted into decreasing energy
|
---|
377 | vector<PseudoJet> sorted_by_E(const vector<PseudoJet> & jets) {
|
---|
378 | vector<double> energies(jets.size());
|
---|
379 | for (size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
|
---|
380 | return objects_sorted_by_values(jets, energies);
|
---|
381 | }
|
---|
382 |
|
---|
383 |
|
---|
384 | FASTJET_END_NAMESPACE
|
---|
385 |
|
---|