[35cdc46] | 1 | //FJSTARTHEADER
|
---|
[cb80e6f] | 2 | // $Id: PseudoJet.cc 4442 2020-05-05 07:50:11Z soyez $
|
---|
[d7d2da3] | 3 | //
|
---|
[cb80e6f] | 4 | // Copyright (c) 2005-2020, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
|
---|
[d7d2da3] | 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
|
---|
[35cdc46] | 15 | // development. They are described in the original FastJet paper,
|
---|
| 16 | // hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
|
---|
[d7d2da3] | 17 | // FastJet as part of work towards a scientific publication, please
|
---|
[35cdc46] | 18 | // quote the version you use and include a citation to the manual and
|
---|
| 19 | // optionally also to hep-ph/0512210.
|
---|
[d7d2da3] | 20 | //
|
---|
| 21 | // FastJet is distributed in the hope that it will be useful,
|
---|
| 22 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 23 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 24 | // GNU General Public License for more details.
|
---|
| 25 | //
|
---|
| 26 | // You should have received a copy of the GNU General Public License
|
---|
| 27 | // along with FastJet. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 28 | //----------------------------------------------------------------------
|
---|
[35cdc46] | 29 | //FJENDHEADER
|
---|
[d7d2da3] | 30 |
|
---|
| 31 |
|
---|
| 32 | #include "fastjet/Error.hh"
|
---|
| 33 | #include "fastjet/PseudoJet.hh"
|
---|
| 34 | #include "fastjet/ClusterSequence.hh"
|
---|
[d69dfe4] | 35 | #ifndef __FJCORE__
|
---|
[d7d2da3] | 36 | #include "fastjet/ClusterSequenceAreaBase.hh"
|
---|
[d69dfe4] | 37 | #endif // __FJCORE__
|
---|
[d7d2da3] | 38 | #include "fastjet/CompositeJetStructure.hh"
|
---|
| 39 | #include<valarray>
|
---|
| 40 | #include<iostream>
|
---|
| 41 | #include<sstream>
|
---|
| 42 | #include<cmath>
|
---|
| 43 | #include<algorithm>
|
---|
| 44 | #include <cstdarg>
|
---|
| 45 |
|
---|
| 46 | FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
|
---|
| 47 |
|
---|
| 48 | using namespace std;
|
---|
| 49 |
|
---|
| 50 |
|
---|
| 51 | //----------------------------------------------------------------------
|
---|
| 52 | // another constructor...
|
---|
| 53 | PseudoJet::PseudoJet(const double px_in, const double py_in, const double pz_in, const double E_in) {
|
---|
| 54 |
|
---|
| 55 | _E = E_in ;
|
---|
| 56 | _px = px_in;
|
---|
| 57 | _py = py_in;
|
---|
| 58 | _pz = pz_in;
|
---|
| 59 |
|
---|
| 60 | this->_finish_init();
|
---|
| 61 |
|
---|
| 62 | // some default values for the history and user indices
|
---|
| 63 | _reset_indices();
|
---|
| 64 |
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 |
|
---|
| 68 | //----------------------------------------------------------------------
|
---|
| 69 | /// do standard end of initialisation
|
---|
| 70 | void PseudoJet::_finish_init () {
|
---|
| 71 | _kt2 = this->px()*this->px() + this->py()*this->py();
|
---|
| 72 | _phi = pseudojet_invalid_phi;
|
---|
[d69dfe4] | 73 | // strictly speaking, _rap does not need initialising, because
|
---|
| 74 | // it's never used as long as _phi == pseudojet_invalid_phi
|
---|
| 75 | // (and gets set when _phi is requested). However ATLAS
|
---|
| 76 | // 2013-03-28 complained that they sometimes have NaN's in
|
---|
| 77 | // _rap and this interferes with some of their internal validation.
|
---|
| 78 | // So we initialise it; penalty is about 0.3ns per PseudoJet out of about
|
---|
| 79 | // 10ns total initialisation time (on a intel Core i7 2.7GHz)
|
---|
| 80 | _rap = pseudojet_invalid_rap;
|
---|
[d7d2da3] | 81 | }
|
---|
| 82 |
|
---|
| 83 | //----------------------------------------------------------------------
|
---|
| 84 | void PseudoJet::_set_rap_phi() const {
|
---|
| 85 |
|
---|
| 86 | if (_kt2 == 0.0) {
|
---|
| 87 | _phi = 0.0; }
|
---|
| 88 | else {
|
---|
| 89 | _phi = atan2(this->py(),this->px());
|
---|
| 90 | }
|
---|
| 91 | if (_phi < 0.0) {_phi += twopi;}
|
---|
| 92 | if (_phi >= twopi) {_phi -= twopi;} // can happen if phi=-|eps<1e-15|?
|
---|
| 93 | if (this->E() == abs(this->pz()) && _kt2 == 0) {
|
---|
| 94 | // Point has infinite rapidity -- convert that into a very large
|
---|
| 95 | // number, but in such a way that different 0-pt momenta will have
|
---|
| 96 | // different rapidities (so as to lift the degeneracy between
|
---|
| 97 | // them) [this can be relevant at parton-level]
|
---|
| 98 | double MaxRapHere = MaxRap + abs(this->pz());
|
---|
| 99 | if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
|
---|
| 100 | } else {
|
---|
| 101 | // get the rapidity in a way that's modestly insensitive to roundoff
|
---|
| 102 | // error when things pz,E are large (actually the best we can do without
|
---|
| 103 | // explicit knowledge of mass)
|
---|
| 104 | double effective_m2 = max(0.0,m2()); // force non tachyonic mass
|
---|
| 105 | double E_plus_pz = _E + abs(_pz); // the safer of p+, p-
|
---|
| 106 | // p+/p- = (p+ p-) / (p-)^2 = (kt^2+m^2)/(p-)^2
|
---|
| 107 | _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
|
---|
| 108 | if (_pz > 0) {_rap = - _rap;}
|
---|
| 109 | }
|
---|
| 110 |
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 |
|
---|
| 114 | //----------------------------------------------------------------------
|
---|
| 115 | // return a valarray four-momentum
|
---|
| 116 | valarray<double> PseudoJet::four_mom() const {
|
---|
| 117 | valarray<double> mom(4);
|
---|
| 118 | mom[0] = _px;
|
---|
| 119 | mom[1] = _py;
|
---|
| 120 | mom[2] = _pz;
|
---|
| 121 | mom[3] = _E ;
|
---|
| 122 | return mom;
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | //----------------------------------------------------------------------
|
---|
| 126 | // Return the component corresponding to the specified index.
|
---|
| 127 | // taken from CLHEP
|
---|
| 128 | double PseudoJet::operator () (int i) const {
|
---|
| 129 | switch(i) {
|
---|
| 130 | case X:
|
---|
| 131 | return px();
|
---|
| 132 | case Y:
|
---|
| 133 | return py();
|
---|
| 134 | case Z:
|
---|
| 135 | return pz();
|
---|
| 136 | case T:
|
---|
| 137 | return e();
|
---|
| 138 | default:
|
---|
| 139 | ostringstream err;
|
---|
| 140 | err << "PseudoJet subscripting: bad index (" << i << ")";
|
---|
| 141 | throw Error(err.str());
|
---|
| 142 | }
|
---|
| 143 | return 0.;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | //----------------------------------------------------------------------
|
---|
| 147 | // return the pseudorapidity
|
---|
| 148 | double PseudoJet::pseudorapidity() const {
|
---|
| 149 | if (px() == 0.0 && py() ==0.0) return MaxRap;
|
---|
| 150 | if (pz() == 0.0) return 0.0;
|
---|
| 151 |
|
---|
| 152 | double theta = atan(perp()/pz());
|
---|
| 153 | if (theta < 0) theta += pi;
|
---|
| 154 | return -log(tan(theta/2));
|
---|
| 155 | }
|
---|
| 156 |
|
---|
| 157 | //----------------------------------------------------------------------
|
---|
| 158 | // return "sum" of two pseudojets
|
---|
| 159 | PseudoJet operator+ (const PseudoJet & jet1, const PseudoJet & jet2) {
|
---|
| 160 | //return PseudoJet(jet1.four_mom()+jet2.four_mom());
|
---|
| 161 | return PseudoJet(jet1.px()+jet2.px(),
|
---|
| 162 | jet1.py()+jet2.py(),
|
---|
| 163 | jet1.pz()+jet2.pz(),
|
---|
| 164 | jet1.E() +jet2.E() );
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 | //----------------------------------------------------------------------
|
---|
| 168 | // return difference of two pseudojets
|
---|
| 169 | PseudoJet operator- (const PseudoJet & jet1, const PseudoJet & jet2) {
|
---|
| 170 | //return PseudoJet(jet1.four_mom()-jet2.four_mom());
|
---|
| 171 | return PseudoJet(jet1.px()-jet2.px(),
|
---|
| 172 | jet1.py()-jet2.py(),
|
---|
| 173 | jet1.pz()-jet2.pz(),
|
---|
| 174 | jet1.E() -jet2.E() );
|
---|
| 175 | }
|
---|
| 176 |
|
---|
| 177 | //----------------------------------------------------------------------
|
---|
| 178 | // return the product, coeff * jet
|
---|
| 179 | PseudoJet operator* (double coeff, const PseudoJet & jet) {
|
---|
[35cdc46] | 180 | // see the comment in operator*= about ensuring valid rap phi
|
---|
| 181 | // before a multiplication to handle case of multiplication by
|
---|
| 182 | // zero, while maintaining rapidity and phi
|
---|
| 183 | jet._ensure_valid_rap_phi();
|
---|
[d7d2da3] | 184 | //return PseudoJet(coeff*jet.four_mom());
|
---|
| 185 | // the following code is hopefully more efficient
|
---|
| 186 | PseudoJet coeff_times_jet(jet);
|
---|
| 187 | coeff_times_jet *= coeff;
|
---|
| 188 | return coeff_times_jet;
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | //----------------------------------------------------------------------
|
---|
| 192 | // return the product, coeff * jet
|
---|
| 193 | PseudoJet operator* (const PseudoJet & jet, double coeff) {
|
---|
| 194 | return coeff*jet;
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | //----------------------------------------------------------------------
|
---|
| 198 | // return the ratio, jet / coeff
|
---|
| 199 | PseudoJet operator/ (const PseudoJet & jet, double coeff) {
|
---|
| 200 | return (1.0/coeff)*jet;
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | //----------------------------------------------------------------------
|
---|
| 204 | /// multiply the jet's momentum by the coefficient
|
---|
[b7b836a] | 205 | PseudoJet & PseudoJet::operator*=(double coeff) {
|
---|
[35cdc46] | 206 | // operator*= aims to maintain the rapidity and azimuth
|
---|
| 207 | // for the PseudoJet; if they have already been evaluated
|
---|
| 208 | // this is fine, but if they haven't and coeff is sufficiently
|
---|
| 209 | // small as to cause a zero or underflow result, then a subsequent
|
---|
| 210 | // invocation of rap or phi will lead to a non-sensical result.
|
---|
| 211 | // So, here, we preemptively ensure that rapidity and phi
|
---|
| 212 | // are correctly cached
|
---|
| 213 | _ensure_valid_rap_phi();
|
---|
[d7d2da3] | 214 | _px *= coeff;
|
---|
| 215 | _py *= coeff;
|
---|
| 216 | _pz *= coeff;
|
---|
| 217 | _E *= coeff;
|
---|
| 218 | _kt2*= coeff*coeff;
|
---|
| 219 | // phi and rap are unchanged
|
---|
[b7b836a] | 220 | return *this;
|
---|
[d7d2da3] | 221 | }
|
---|
| 222 |
|
---|
| 223 | //----------------------------------------------------------------------
|
---|
| 224 | /// divide the jet's momentum by the coefficient
|
---|
[b7b836a] | 225 | PseudoJet & PseudoJet::operator/=(double coeff) {
|
---|
[d7d2da3] | 226 | (*this) *= 1.0/coeff;
|
---|
[b7b836a] | 227 | return *this;
|
---|
[d7d2da3] | 228 | }
|
---|
| 229 |
|
---|
| 230 |
|
---|
| 231 | //----------------------------------------------------------------------
|
---|
| 232 | /// add the other jet's momentum to this jet
|
---|
[b7b836a] | 233 | PseudoJet & PseudoJet::operator+=(const PseudoJet & other_jet) {
|
---|
[d7d2da3] | 234 | _px += other_jet._px;
|
---|
| 235 | _py += other_jet._py;
|
---|
| 236 | _pz += other_jet._pz;
|
---|
| 237 | _E += other_jet._E ;
|
---|
| 238 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
[b7b836a] | 239 | return *this;
|
---|
[d7d2da3] | 240 | }
|
---|
| 241 |
|
---|
| 242 |
|
---|
| 243 | //----------------------------------------------------------------------
|
---|
| 244 | /// subtract the other jet's momentum from this jet
|
---|
[b7b836a] | 245 | PseudoJet & PseudoJet::operator-=(const PseudoJet & other_jet) {
|
---|
[d7d2da3] | 246 | _px -= other_jet._px;
|
---|
| 247 | _py -= other_jet._py;
|
---|
| 248 | _pz -= other_jet._pz;
|
---|
| 249 | _E -= other_jet._E ;
|
---|
| 250 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
[b7b836a] | 251 | return *this;
|
---|
[d7d2da3] | 252 | }
|
---|
| 253 |
|
---|
| 254 | //----------------------------------------------------------------------
|
---|
| 255 | bool operator==(const PseudoJet & a, const PseudoJet & b) {
|
---|
| 256 | if (a.px() != b.px()) return false;
|
---|
| 257 | if (a.py() != b.py()) return false;
|
---|
| 258 | if (a.pz() != b.pz()) return false;
|
---|
| 259 | if (a.E () != b.E ()) return false;
|
---|
| 260 |
|
---|
| 261 | if (a.user_index() != b.user_index()) return false;
|
---|
| 262 | if (a.cluster_hist_index() != b.cluster_hist_index()) return false;
|
---|
| 263 | if (a.user_info_ptr() != b.user_info_ptr()) return false;
|
---|
| 264 | if (a.structure_ptr() != b.structure_ptr()) return false;
|
---|
| 265 |
|
---|
| 266 | return true;
|
---|
| 267 | }
|
---|
| 268 |
|
---|
| 269 | //----------------------------------------------------------------------
|
---|
| 270 | // check if the jet has zero momentum
|
---|
| 271 | bool operator==(const PseudoJet & jet, const double val) {
|
---|
| 272 | if (val != 0)
|
---|
| 273 | throw Error("comparing a PseudoJet with a non-zero constant (double) is not allowed.");
|
---|
| 274 | return (jet.px() == 0 && jet.py() == 0 &&
|
---|
| 275 | jet.pz() == 0 && jet.E() == 0);
|
---|
| 276 | }
|
---|
| 277 |
|
---|
| 278 |
|
---|
| 279 |
|
---|
| 280 | //----------------------------------------------------------------------
|
---|
[35cdc46] | 281 | /// transform this jet (given in the rest frame of prest) into a jet
|
---|
| 282 | /// in the lab frame
|
---|
[d7d2da3] | 283 | //
|
---|
| 284 | // NB: code adapted from that in herwig f77 (checked how it worked
|
---|
| 285 | // long ago)
|
---|
| 286 | PseudoJet & PseudoJet::boost(const PseudoJet & prest) {
|
---|
| 287 |
|
---|
| 288 | if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
|
---|
| 289 | return *this;
|
---|
| 290 |
|
---|
| 291 | double m_local = prest.m();
|
---|
| 292 | assert(m_local != 0);
|
---|
| 293 |
|
---|
| 294 | double pf4 = ( px()*prest.px() + py()*prest.py()
|
---|
| 295 | + pz()*prest.pz() + E()*prest.E() )/m_local;
|
---|
| 296 | double fn = (pf4 + E()) / (prest.E() + m_local);
|
---|
| 297 | _px += fn*prest.px();
|
---|
| 298 | _py += fn*prest.py();
|
---|
| 299 | _pz += fn*prest.pz();
|
---|
| 300 | _E = pf4;
|
---|
| 301 |
|
---|
| 302 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
| 303 | return *this;
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 |
|
---|
| 307 | //----------------------------------------------------------------------
|
---|
[35cdc46] | 308 | /// transform this jet (given in lab) into a jet in the rest
|
---|
| 309 | /// frame of prest
|
---|
[d7d2da3] | 310 | //
|
---|
| 311 | // NB: code adapted from that in herwig f77 (checked how it worked
|
---|
| 312 | // long ago)
|
---|
| 313 | PseudoJet & PseudoJet::unboost(const PseudoJet & prest) {
|
---|
| 314 |
|
---|
| 315 | if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
|
---|
| 316 | return *this;
|
---|
| 317 |
|
---|
| 318 | double m_local = prest.m();
|
---|
| 319 | assert(m_local != 0);
|
---|
| 320 |
|
---|
| 321 | double pf4 = ( -px()*prest.px() - py()*prest.py()
|
---|
| 322 | - pz()*prest.pz() + E()*prest.E() )/m_local;
|
---|
| 323 | double fn = (pf4 + E()) / (prest.E() + m_local);
|
---|
| 324 | _px -= fn*prest.px();
|
---|
| 325 | _py -= fn*prest.py();
|
---|
| 326 | _pz -= fn*prest.pz();
|
---|
| 327 | _E = pf4;
|
---|
| 328 |
|
---|
| 329 | _finish_init(); // we need to recalculate phi,rap,kt2
|
---|
| 330 | return *this;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 |
|
---|
| 334 | //----------------------------------------------------------------------
|
---|
| 335 | /// returns true if the momenta of the two input jets are identical
|
---|
| 336 | bool have_same_momentum(const PseudoJet & jeta, const PseudoJet & jetb) {
|
---|
| 337 | return jeta.px() == jetb.px()
|
---|
| 338 | && jeta.py() == jetb.py()
|
---|
| 339 | && jeta.pz() == jetb.pz()
|
---|
| 340 | && jeta.E() == jetb.E();
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | //----------------------------------------------------------------------
|
---|
| 344 | void PseudoJet::set_cached_rap_phi(double rap_in, double phi_in) {
|
---|
| 345 | _rap = rap_in; _phi = phi_in;
|
---|
| 346 | if (_phi >= twopi) _phi -= twopi;
|
---|
| 347 | if (_phi < 0) _phi += twopi;
|
---|
| 348 | }
|
---|
| 349 |
|
---|
| 350 | //----------------------------------------------------------------------
|
---|
| 351 | void PseudoJet::reset_momentum_PtYPhiM(double pt_in, double y_in, double phi_in, double m_in) {
|
---|
| 352 | assert(phi_in < 2*twopi && phi_in > -twopi);
|
---|
| 353 | double ptm = (m_in == 0) ? pt_in : sqrt(pt_in*pt_in+m_in*m_in);
|
---|
| 354 | double exprap = exp(y_in);
|
---|
| 355 | double pminus = ptm/exprap;
|
---|
| 356 | double pplus = ptm*exprap;
|
---|
| 357 | double px_local = pt_in*cos(phi_in);
|
---|
| 358 | double py_local = pt_in*sin(phi_in);
|
---|
| 359 | reset_momentum(px_local,py_local,0.5*(pplus-pminus),0.5*(pplus+pminus));
|
---|
| 360 | set_cached_rap_phi(y_in,phi_in);
|
---|
| 361 | }
|
---|
| 362 |
|
---|
| 363 | //----------------------------------------------------------------------
|
---|
| 364 | /// return a pseudojet with the given pt, y, phi and mass
|
---|
| 365 | PseudoJet PtYPhiM(double pt, double y, double phi, double m) {
|
---|
| 366 | assert(phi < 2*twopi && phi > -twopi);
|
---|
| 367 | double ptm = (m == 0) ? pt : sqrt(pt*pt+m*m);
|
---|
| 368 | double exprap = exp(y);
|
---|
| 369 | double pminus = ptm/exprap;
|
---|
| 370 | double pplus = ptm*exprap;
|
---|
| 371 | double px = pt*cos(phi);
|
---|
| 372 | double py = pt*sin(phi);
|
---|
| 373 | PseudoJet mom(px,py,0.5*(pplus-pminus),0.5*(pplus+pminus));
|
---|
| 374 | mom.set_cached_rap_phi(y,phi);
|
---|
| 375 | return mom;
|
---|
| 376 | //return PseudoJet(pt*cos(phi), pt*sin(phi), ptm*sinh(y), ptm*cosh(y));
|
---|
| 377 | }
|
---|
| 378 |
|
---|
| 379 |
|
---|
| 380 | //----------------------------------------------------------------------
|
---|
| 381 | // return kt-distance between this jet and another one
|
---|
| 382 | double PseudoJet::kt_distance(const PseudoJet & other) const {
|
---|
| 383 | //double distance = min(this->kt2(), other.kt2());
|
---|
| 384 | double distance = min(_kt2, other._kt2);
|
---|
| 385 | double dphi = abs(phi() - other.phi());
|
---|
| 386 | if (dphi > pi) {dphi = twopi - dphi;}
|
---|
| 387 | double drap = rap() - other.rap();
|
---|
| 388 | distance = distance * (dphi*dphi + drap*drap);
|
---|
| 389 | return distance;
|
---|
| 390 | }
|
---|
| 391 |
|
---|
| 392 |
|
---|
| 393 | //----------------------------------------------------------------------
|
---|
| 394 | // return squared cylinder (eta-phi) distance between this jet and another one
|
---|
| 395 | double PseudoJet::plain_distance(const PseudoJet & other) const {
|
---|
| 396 | double dphi = abs(phi() - other.phi());
|
---|
| 397 | if (dphi > pi) {dphi = twopi - dphi;}
|
---|
| 398 | double drap = rap() - other.rap();
|
---|
| 399 | return (dphi*dphi + drap*drap);
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | //----------------------------------------------------------------------
|
---|
| 403 | /// returns other.phi() - this.phi(), i.e. the phi distance to
|
---|
| 404 | /// other, constrained to be in range -pi .. pi
|
---|
| 405 | double PseudoJet::delta_phi_to(const PseudoJet & other) const {
|
---|
| 406 | double dphi = other.phi() - phi();
|
---|
| 407 | if (dphi > pi) dphi -= twopi;
|
---|
| 408 | if (dphi < -pi) dphi += twopi;
|
---|
| 409 | return dphi;
|
---|
| 410 | }
|
---|
| 411 |
|
---|
| 412 |
|
---|
| 413 | string PseudoJet::description() const{
|
---|
| 414 | // the "default" case of a PJ which does not belong to any cluster sequence
|
---|
[1d208a2] | 415 | if (!_structure)
|
---|
[d7d2da3] | 416 | return "standard PseudoJet (with no associated clustering information)";
|
---|
| 417 |
|
---|
| 418 | // for all the other cases, the description comes from the structure
|
---|
[1d208a2] | 419 | return _structure->description();
|
---|
[d7d2da3] | 420 | }
|
---|
| 421 |
|
---|
| 422 |
|
---|
| 423 |
|
---|
| 424 | //----------------------------------------------------------------------
|
---|
| 425 | //
|
---|
| 426 | // The following methods access the associated jet structure (if any)
|
---|
| 427 | //
|
---|
| 428 | //----------------------------------------------------------------------
|
---|
| 429 |
|
---|
| 430 |
|
---|
| 431 | //----------------------------------------------------------------------
|
---|
| 432 | // check whether this PseudoJet has an associated parent
|
---|
| 433 | // ClusterSequence
|
---|
| 434 | bool PseudoJet::has_associated_cluster_sequence() const{
|
---|
[1d208a2] | 435 | return (_structure) && (_structure->has_associated_cluster_sequence());
|
---|
[d7d2da3] | 436 | }
|
---|
| 437 |
|
---|
| 438 | //----------------------------------------------------------------------
|
---|
| 439 | // get a (const) pointer to the associated ClusterSequence (NULL if
|
---|
| 440 | // inexistent)
|
---|
| 441 | const ClusterSequence* PseudoJet::associated_cluster_sequence() const{
|
---|
| 442 | if (! has_associated_cluster_sequence()) return NULL;
|
---|
| 443 |
|
---|
| 444 | return _structure->associated_cluster_sequence();
|
---|
| 445 | }
|
---|
| 446 |
|
---|
| 447 |
|
---|
| 448 | //----------------------------------------------------------------------
|
---|
| 449 | // check whether this PseudoJet has an associated parent
|
---|
| 450 | // ClusterSequence that is still valid
|
---|
| 451 | bool PseudoJet::has_valid_cluster_sequence() const{
|
---|
[1d208a2] | 452 | return (_structure) && (_structure->has_valid_cluster_sequence());
|
---|
[d7d2da3] | 453 | }
|
---|
| 454 |
|
---|
| 455 | //----------------------------------------------------------------------
|
---|
| 456 | // If there is a valid cluster sequence associated with this jet,
|
---|
| 457 | // returns a pointer to it; otherwise throws an Error.
|
---|
| 458 | //
|
---|
| 459 | // Open question: should these errors be upgraded to classes of their
|
---|
| 460 | // own so that they can be caught? [Maybe, but later]
|
---|
| 461 | const ClusterSequence * PseudoJet::validated_cs() const {
|
---|
| 462 | return validated_structure_ptr()->validated_cs();
|
---|
| 463 | }
|
---|
| 464 |
|
---|
| 465 |
|
---|
| 466 | //----------------------------------------------------------------------
|
---|
| 467 | // set the associated structure
|
---|
| 468 | void PseudoJet::set_structure_shared_ptr(const SharedPtr<PseudoJetStructureBase> &structure_in){
|
---|
| 469 | _structure = structure_in;
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | //----------------------------------------------------------------------
|
---|
[1d208a2] | 473 | // return true if there is some structure associated with this PseudoJet
|
---|
[d7d2da3] | 474 | bool PseudoJet::has_structure() const{
|
---|
[1d208a2] | 475 | return bool(_structure);
|
---|
[d7d2da3] | 476 | }
|
---|
| 477 |
|
---|
| 478 | //----------------------------------------------------------------------
|
---|
| 479 | // return a pointer to the structure (of type
|
---|
| 480 | // PseudoJetStructureBase*) associated with this PseudoJet.
|
---|
| 481 | //
|
---|
| 482 | // return NULL if there is no associated structure
|
---|
| 483 | const PseudoJetStructureBase* PseudoJet::structure_ptr() const {
|
---|
[1d208a2] | 484 | //if (!_structure) return NULL;
|
---|
| 485 | return _structure.get();
|
---|
[d7d2da3] | 486 | }
|
---|
| 487 |
|
---|
| 488 | //----------------------------------------------------------------------
|
---|
| 489 | // return a non-const pointer to the structure (of type
|
---|
| 490 | // PseudoJetStructureBase*) associated with this PseudoJet.
|
---|
| 491 | //
|
---|
| 492 | // return NULL if there is no associated structure
|
---|
| 493 | //
|
---|
| 494 | // Only use this if you know what you are doing. In any case,
|
---|
| 495 | // prefer the 'structure_ptr()' (the const version) to this method,
|
---|
| 496 | // unless you really need a write access to the PseudoJet's
|
---|
| 497 | // underlying structure.
|
---|
| 498 | PseudoJetStructureBase* PseudoJet::structure_non_const_ptr(){
|
---|
[1d208a2] | 499 | //if (!_structure) return NULL;
|
---|
| 500 | return _structure.get();
|
---|
[d7d2da3] | 501 | }
|
---|
| 502 |
|
---|
| 503 | //----------------------------------------------------------------------
|
---|
| 504 | // return a pointer to the structure (of type
|
---|
| 505 | // PseudoJetStructureBase*) associated with this PseudoJet.
|
---|
| 506 | //
|
---|
| 507 | // throw an error if there is no associated structure
|
---|
| 508 | const PseudoJetStructureBase* PseudoJet::validated_structure_ptr() const {
|
---|
[1d208a2] | 509 | if (!_structure)
|
---|
[d7d2da3] | 510 | throw Error("Trying to access the structure of a PseudoJet which has no associated structure");
|
---|
[1d208a2] | 511 | return _structure.get();
|
---|
[d7d2da3] | 512 | }
|
---|
| 513 |
|
---|
| 514 | //----------------------------------------------------------------------
|
---|
| 515 | // return a reference to the shared pointer to the
|
---|
| 516 | // PseudoJetStructureBase associated with this PseudoJet
|
---|
| 517 | const SharedPtr<PseudoJetStructureBase> & PseudoJet::structure_shared_ptr() const {
|
---|
| 518 | return _structure;
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 |
|
---|
| 522 | //----------------------------------------------------------------------
|
---|
| 523 | // check if it has been recombined with another PseudoJet in which
|
---|
| 524 | // case, return its partner through the argument. Otherwise,
|
---|
| 525 | // 'partner' is set to 0.
|
---|
| 526 | //
|
---|
| 527 | // false is also returned if this PseudoJet has no associated
|
---|
| 528 | // ClusterSequence
|
---|
| 529 | bool PseudoJet::has_partner(PseudoJet &partner) const{
|
---|
| 530 | return validated_structure_ptr()->has_partner(*this, partner);
|
---|
| 531 | }
|
---|
| 532 |
|
---|
| 533 | //----------------------------------------------------------------------
|
---|
| 534 | // check if it has been recombined with another PseudoJet in which
|
---|
| 535 | // case, return its child through the argument. Otherwise, 'child'
|
---|
| 536 | // is set to 0.
|
---|
| 537 | //
|
---|
| 538 | // false is also returned if this PseudoJet has no associated
|
---|
| 539 | // ClusterSequence, with the child set to 0
|
---|
| 540 | bool PseudoJet::has_child(PseudoJet &child) const{
|
---|
| 541 | return validated_structure_ptr()->has_child(*this, child);
|
---|
| 542 | }
|
---|
| 543 |
|
---|
| 544 | //----------------------------------------------------------------------
|
---|
| 545 | // check if it is the product of a recombination, in which case
|
---|
| 546 | // return the 2 parents through the 'parent1' and 'parent2'
|
---|
| 547 | // arguments. Otherwise, set these to 0.
|
---|
| 548 | //
|
---|
| 549 | // false is also returned if this PseudoJet has no parent
|
---|
| 550 | // ClusterSequence
|
---|
| 551 | bool PseudoJet::has_parents(PseudoJet &parent1, PseudoJet &parent2) const{
|
---|
| 552 | return validated_structure_ptr()->has_parents(*this, parent1, parent2);
|
---|
| 553 | }
|
---|
| 554 |
|
---|
| 555 | //----------------------------------------------------------------------
|
---|
| 556 | // check if the current PseudoJet contains the one passed as
|
---|
| 557 | // argument
|
---|
| 558 | //
|
---|
| 559 | // false is also returned if this PseudoJet has no associated
|
---|
| 560 | // ClusterSequence.
|
---|
| 561 | bool PseudoJet::contains(const PseudoJet &constituent) const{
|
---|
| 562 | return validated_structure_ptr()->object_in_jet(constituent, *this);
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | //----------------------------------------------------------------------
|
---|
| 566 | // check if the current PseudoJet is contained the one passed as
|
---|
| 567 | // argument
|
---|
| 568 | //
|
---|
| 569 | // false is also returned if this PseudoJet has no associated
|
---|
| 570 | // ClusterSequence
|
---|
| 571 | bool PseudoJet::is_inside(const PseudoJet &jet) const{
|
---|
| 572 | return validated_structure_ptr()->object_in_jet(*this, jet);
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 |
|
---|
| 576 | //----------------------------------------------------------------------
|
---|
| 577 | // returns true if the PseudoJet has constituents
|
---|
| 578 | bool PseudoJet::has_constituents() const{
|
---|
[1d208a2] | 579 | return (_structure) && (_structure->has_constituents());
|
---|
[d7d2da3] | 580 | }
|
---|
| 581 |
|
---|
| 582 | //----------------------------------------------------------------------
|
---|
| 583 | // retrieve the constituents.
|
---|
| 584 | vector<PseudoJet> PseudoJet::constituents() const{
|
---|
| 585 | return validated_structure_ptr()->constituents(*this);
|
---|
| 586 | }
|
---|
| 587 |
|
---|
| 588 |
|
---|
| 589 | //----------------------------------------------------------------------
|
---|
| 590 | // returns true if the PseudoJet has support for exclusive subjets
|
---|
| 591 | bool PseudoJet::has_exclusive_subjets() const{
|
---|
[1d208a2] | 592 | return (_structure) && (_structure->has_exclusive_subjets());
|
---|
[d7d2da3] | 593 | }
|
---|
| 594 |
|
---|
| 595 | //----------------------------------------------------------------------
|
---|
| 596 | // return a vector of all subjets of the current jet (in the sense
|
---|
| 597 | // of the exclusive algorithm) that would be obtained when running
|
---|
| 598 | // the algorithm with the given dcut.
|
---|
| 599 | //
|
---|
| 600 | // Time taken is O(m ln m), where m is the number of subjets that
|
---|
| 601 | // are found. If m gets to be of order of the total number of
|
---|
| 602 | // constituents in the jet, this could be substantially slower than
|
---|
| 603 | // just getting that list of constituents.
|
---|
| 604 | //
|
---|
| 605 | // an Error is thrown if this PseudoJet has no currently valid
|
---|
| 606 | // associated ClusterSequence
|
---|
[35cdc46] | 607 | std::vector<PseudoJet> PseudoJet::exclusive_subjets (const double dcut) const {
|
---|
[d7d2da3] | 608 | return validated_structure_ptr()->exclusive_subjets(*this, dcut);
|
---|
| 609 | }
|
---|
| 610 |
|
---|
| 611 | //----------------------------------------------------------------------
|
---|
| 612 | // return the size of exclusive_subjets(...); still n ln n with same
|
---|
| 613 | // coefficient, but marginally more efficient than manually taking
|
---|
| 614 | // exclusive_subjets.size()
|
---|
| 615 | //
|
---|
| 616 | // an Error is thrown if this PseudoJet has no currently valid
|
---|
| 617 | // associated ClusterSequence
|
---|
[35cdc46] | 618 | int PseudoJet::n_exclusive_subjets(const double dcut) const {
|
---|
[d7d2da3] | 619 | return validated_structure_ptr()->n_exclusive_subjets(*this, dcut);
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | //----------------------------------------------------------------------
|
---|
| 623 | // return the list of subjets obtained by unclustering the supplied
|
---|
| 624 | // jet down to n subjets (or all constituents if there are fewer
|
---|
| 625 | // than n).
|
---|
| 626 | //
|
---|
| 627 | // requires n ln n time
|
---|
| 628 | //
|
---|
| 629 | // an Error is thrown if this PseudoJet has no currently valid
|
---|
| 630 | // associated ClusterSequence
|
---|
| 631 | std::vector<PseudoJet> PseudoJet::exclusive_subjets_up_to (int nsub) const {
|
---|
| 632 | return validated_structure_ptr()->exclusive_subjets_up_to(*this, nsub);
|
---|
| 633 | }
|
---|
| 634 |
|
---|
| 635 | //----------------------------------------------------------------------
|
---|
| 636 | // Same as exclusive_subjets_up_to but throws an error if there are
|
---|
| 637 | // fewer than nsub particles in the jet
|
---|
| 638 | std::vector<PseudoJet> PseudoJet::exclusive_subjets (int nsub) const {
|
---|
| 639 | vector<PseudoJet> subjets = exclusive_subjets_up_to(nsub);
|
---|
| 640 | if (int(subjets.size()) < nsub) {
|
---|
| 641 | ostringstream err;
|
---|
| 642 | err << "Requested " << nsub << " exclusive subjets, but there were only "
|
---|
| 643 | << subjets.size() << " particles in the jet";
|
---|
| 644 | throw Error(err.str());
|
---|
| 645 | }
|
---|
| 646 | return subjets;
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 | //----------------------------------------------------------------------
|
---|
| 650 | // return the dij that was present in the merging nsub+1 -> nsub
|
---|
| 651 | // subjets inside this jet.
|
---|
| 652 | //
|
---|
| 653 | // an Error is thrown if this PseudoJet has no currently valid
|
---|
| 654 | // associated ClusterSequence
|
---|
| 655 | double PseudoJet::exclusive_subdmerge(int nsub) const {
|
---|
| 656 | return validated_structure_ptr()->exclusive_subdmerge(*this, nsub);
|
---|
| 657 | }
|
---|
| 658 |
|
---|
| 659 | //----------------------------------------------------------------------
|
---|
| 660 | // return the maximum dij that occurred in the whole event at the
|
---|
| 661 | // stage that the nsub+1 -> nsub merge of subjets occurred inside
|
---|
| 662 | // this jet.
|
---|
| 663 | //
|
---|
| 664 | // an Error is thrown if this PseudoJet has no currently valid
|
---|
| 665 | // associated ClusterSequence
|
---|
| 666 | double PseudoJet::exclusive_subdmerge_max(int nsub) const {
|
---|
| 667 | return validated_structure_ptr()->exclusive_subdmerge_max(*this, nsub);
|
---|
| 668 | }
|
---|
| 669 |
|
---|
| 670 |
|
---|
| 671 | // returns true if a jet has pieces
|
---|
| 672 | //
|
---|
| 673 | // By default a single particle or a jet coming from a
|
---|
| 674 | // ClusterSequence have no pieces and this methos will return false.
|
---|
| 675 | bool PseudoJet::has_pieces() const{
|
---|
[1d208a2] | 676 | return ((_structure) && (_structure->has_pieces(*this)));
|
---|
[d7d2da3] | 677 | }
|
---|
| 678 |
|
---|
| 679 | // retrieve the pieces that make up the jet.
|
---|
| 680 | //
|
---|
| 681 | // By default a jet does not have pieces.
|
---|
| 682 | // If the underlying interface supports "pieces" retrieve the
|
---|
| 683 | // pieces from there.
|
---|
| 684 | std::vector<PseudoJet> PseudoJet::pieces() const{
|
---|
| 685 | return validated_structure_ptr()->pieces(*this);
|
---|
| 686 | // if (!has_pieces())
|
---|
| 687 | // throw Error("Trying to retrieve the pieces of a PseudoJet that has no support for pieces.");
|
---|
| 688 | //
|
---|
| 689 | // return _structure->pieces(*this);
|
---|
| 690 | }
|
---|
| 691 |
|
---|
| 692 |
|
---|
| 693 | //----------------------------------------------------------------------
|
---|
| 694 | // the following ones require a computation of the area in the
|
---|
| 695 | // associated ClusterSequence (See ClusterSequenceAreaBase for details)
|
---|
| 696 | //----------------------------------------------------------------------
|
---|
| 697 |
|
---|
[d69dfe4] | 698 | #ifndef __FJCORE__
|
---|
| 699 |
|
---|
[d7d2da3] | 700 | //----------------------------------------------------------------------
|
---|
| 701 | // if possible, return a valid ClusterSequenceAreaBase pointer; otherwise
|
---|
| 702 | // throw an error
|
---|
| 703 | const ClusterSequenceAreaBase * PseudoJet::validated_csab() const {
|
---|
| 704 | const ClusterSequenceAreaBase *csab = dynamic_cast<const ClusterSequenceAreaBase*>(validated_cs());
|
---|
| 705 | if (csab == NULL) throw Error("you requested jet-area related information, but the PseudoJet does not have associated area information.");
|
---|
| 706 | return csab;
|
---|
| 707 | }
|
---|
| 708 |
|
---|
| 709 |
|
---|
| 710 | //----------------------------------------------------------------------
|
---|
| 711 | // check if it has a defined area
|
---|
| 712 | bool PseudoJet::has_area() const{
|
---|
| 713 | //if (! has_associated_cluster_sequence()) return false;
|
---|
| 714 | if (! has_structure()) return false;
|
---|
| 715 | return (validated_structure_ptr()->has_area() != 0);
|
---|
| 716 | }
|
---|
| 717 |
|
---|
| 718 | //----------------------------------------------------------------------
|
---|
| 719 | // return the jet (scalar) area.
|
---|
| 720 | // throw an Error if there is no support for area in the associated CS
|
---|
| 721 | double PseudoJet::area() const{
|
---|
| 722 | return validated_structure_ptr()->area(*this);
|
---|
| 723 | }
|
---|
| 724 |
|
---|
| 725 | //----------------------------------------------------------------------
|
---|
| 726 | // return the error (uncertainty) associated with the determination
|
---|
| 727 | // of the area of this jet.
|
---|
| 728 | // throws an Error if there is no support for area in the associated CS
|
---|
| 729 | double PseudoJet::area_error() const{
|
---|
| 730 | return validated_structure_ptr()->area_error(*this);
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | //----------------------------------------------------------------------
|
---|
| 734 | // return the jet 4-vector area
|
---|
| 735 | // throws an Error if there is no support for area in the associated CS
|
---|
| 736 | PseudoJet PseudoJet::area_4vector() const{
|
---|
| 737 | return validated_structure_ptr()->area_4vector(*this);
|
---|
| 738 | }
|
---|
| 739 |
|
---|
| 740 | //----------------------------------------------------------------------
|
---|
| 741 | // true if this jet is made exclusively of ghosts
|
---|
| 742 | // throws an Error if there is no support for area in the associated CS
|
---|
| 743 | bool PseudoJet::is_pure_ghost() const{
|
---|
| 744 | return validated_structure_ptr()->is_pure_ghost(*this);
|
---|
| 745 | }
|
---|
| 746 |
|
---|
[d69dfe4] | 747 | #endif // __FJCORE__
|
---|
[d7d2da3] | 748 |
|
---|
| 749 | //----------------------------------------------------------------------
|
---|
| 750 | //
|
---|
| 751 | // end of the methods accessing the information in the associated
|
---|
| 752 | // Cluster Sequence
|
---|
| 753 | //
|
---|
| 754 | //----------------------------------------------------------------------
|
---|
| 755 |
|
---|
| 756 | //----------------------------------------------------------------------
|
---|
| 757 | /// provide a meaningful error message for InexistentUserInfo
|
---|
| 758 | PseudoJet::InexistentUserInfo::InexistentUserInfo() : Error("you attempted to perform a dynamic cast of a PseudoJet's extra info, but the extra info pointer was null")
|
---|
| 759 | {}
|
---|
| 760 |
|
---|
| 761 |
|
---|
| 762 | //----------------------------------------------------------------------
|
---|
| 763 | // sort the indices so that values[indices[0..n-1]] is sorted
|
---|
| 764 | // into increasing order
|
---|
| 765 | void sort_indices(vector<int> & indices,
|
---|
| 766 | const vector<double> & values) {
|
---|
| 767 | IndexedSortHelper index_sort_helper(&values);
|
---|
| 768 | sort(indices.begin(), indices.end(), index_sort_helper);
|
---|
| 769 | }
|
---|
| 770 |
|
---|
| 771 |
|
---|
| 772 | //----------------------------------------------------------------------
|
---|
| 773 | /// return a vector of jets sorted into decreasing kt2
|
---|
| 774 | vector<PseudoJet> sorted_by_pt(const vector<PseudoJet> & jets) {
|
---|
| 775 | vector<double> minus_kt2(jets.size());
|
---|
| 776 | for (size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
|
---|
| 777 | return objects_sorted_by_values(jets, minus_kt2);
|
---|
| 778 | }
|
---|
| 779 |
|
---|
| 780 | //----------------------------------------------------------------------
|
---|
| 781 | /// return a vector of jets sorted into increasing rapidity
|
---|
| 782 | vector<PseudoJet> sorted_by_rapidity(const vector<PseudoJet> & jets) {
|
---|
| 783 | vector<double> rapidities(jets.size());
|
---|
| 784 | for (size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
|
---|
| 785 | return objects_sorted_by_values(jets, rapidities);
|
---|
| 786 | }
|
---|
| 787 |
|
---|
| 788 | //----------------------------------------------------------------------
|
---|
| 789 | /// return a vector of jets sorted into decreasing energy
|
---|
| 790 | vector<PseudoJet> sorted_by_E(const vector<PseudoJet> & jets) {
|
---|
| 791 | vector<double> energies(jets.size());
|
---|
| 792 | for (size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
|
---|
| 793 | return objects_sorted_by_values(jets, energies);
|
---|
| 794 | }
|
---|
| 795 |
|
---|
| 796 | //----------------------------------------------------------------------
|
---|
| 797 | /// return a vector of jets sorted into increasing pz
|
---|
| 798 | vector<PseudoJet> sorted_by_pz(const vector<PseudoJet> & jets) {
|
---|
| 799 | vector<double> pz(jets.size());
|
---|
| 800 | for (size_t i = 0; i < jets.size(); i++) {pz[i] = jets[i].pz();}
|
---|
| 801 | return objects_sorted_by_values(jets, pz);
|
---|
| 802 | }
|
---|
| 803 |
|
---|
| 804 |
|
---|
| 805 |
|
---|
| 806 | //-------------------------------------------------------------------------------
|
---|
| 807 | // helper functions to build a jet made of pieces
|
---|
| 808 | //-------------------------------------------------------------------------------
|
---|
| 809 |
|
---|
| 810 | // build a "CompositeJet" from the vector of its pieces
|
---|
| 811 | //
|
---|
| 812 | // In this case, E-scheme recombination is assumed to compute the
|
---|
| 813 | // total momentum
|
---|
| 814 | PseudoJet join(const vector<PseudoJet> & pieces){
|
---|
| 815 | // compute the total momentum
|
---|
| 816 | //--------------------------------------------------
|
---|
| 817 | PseudoJet result; // automatically initialised to 0
|
---|
| 818 | for (unsigned int i=0; i<pieces.size(); i++)
|
---|
| 819 | result += pieces[i];
|
---|
| 820 |
|
---|
| 821 | // attach a CompositeJetStructure to the result
|
---|
| 822 | //--------------------------------------------------
|
---|
| 823 | CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces);
|
---|
| 824 |
|
---|
| 825 | result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
|
---|
| 826 |
|
---|
| 827 | return result;
|
---|
| 828 | }
|
---|
| 829 |
|
---|
| 830 | // build a "CompositeJet" from a single PseudoJet
|
---|
| 831 | PseudoJet join(const PseudoJet & j1){
|
---|
| 832 | return join(vector<PseudoJet>(1,j1));
|
---|
| 833 | }
|
---|
| 834 |
|
---|
| 835 | // build a "CompositeJet" from two PseudoJet
|
---|
| 836 | PseudoJet join(const PseudoJet & j1, const PseudoJet & j2){
|
---|
| 837 | vector<PseudoJet> pieces;
|
---|
[273e668] | 838 | pieces.reserve(2);
|
---|
[d7d2da3] | 839 | pieces.push_back(j1);
|
---|
| 840 | pieces.push_back(j2);
|
---|
| 841 | return join(pieces);
|
---|
| 842 | }
|
---|
| 843 |
|
---|
| 844 | // build a "CompositeJet" from 3 PseudoJet
|
---|
| 845 | PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3){
|
---|
| 846 | vector<PseudoJet> pieces;
|
---|
[273e668] | 847 | pieces.reserve(3);
|
---|
[d7d2da3] | 848 | pieces.push_back(j1);
|
---|
| 849 | pieces.push_back(j2);
|
---|
| 850 | pieces.push_back(j3);
|
---|
| 851 | return join(pieces);
|
---|
| 852 | }
|
---|
| 853 |
|
---|
| 854 | // build a "CompositeJet" from 4 PseudoJet
|
---|
| 855 | PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4){
|
---|
| 856 | vector<PseudoJet> pieces;
|
---|
[273e668] | 857 | pieces.reserve(4);
|
---|
[d7d2da3] | 858 | pieces.push_back(j1);
|
---|
| 859 | pieces.push_back(j2);
|
---|
| 860 | pieces.push_back(j3);
|
---|
| 861 | pieces.push_back(j4);
|
---|
| 862 | return join(pieces);
|
---|
| 863 | }
|
---|
| 864 |
|
---|
| 865 |
|
---|
| 866 |
|
---|
| 867 |
|
---|
| 868 | FASTJET_END_NAMESPACE
|
---|
| 869 |
|
---|