PseudoJet.cc

00001 //STARTHEADER
00002 // $Id: PseudoJet.cc 1830 2010-12-09 17:10:25Z salam $
00003 //
00004 // Copyright (c) 2005-2010, Matteo Cacciari, Gavin Salam and Gregory Soyez
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 
00032 #include "fastjet/Error.hh"
00033 #include "fastjet/PseudoJet.hh"
00034 #include "fastjet/ClusterSequence.hh"
00035 #include "fastjet/ClusterSequenceAreaBase.hh"
00036 #include<valarray>
00037 #include<iostream>
00038 #include<sstream>
00039 #include<cmath>
00040 #include<algorithm>
00041 
00042 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00043 
00044 using namespace std;
00045 
00046 
00047 //----------------------------------------------------------------------
00048 // another constructor...
00049 PseudoJet::PseudoJet(const double px, const double py, const double pz, const double E) {
00050   
00051   _E  = E ;
00052   _px = px;
00053   _py = py;
00054   _pz = pz;
00055 
00056   this->_finish_init();
00057 
00058   // some default values for the history and user indices
00059   _reset_indices();
00060 
00061 }
00062 
00063 
00064 //----------------------------------------------------------------------
00066 void PseudoJet::_finish_init () {
00067   _kt2 = this->px()*this->px() + this->py()*this->py();
00068   _phi = pseudojet_invalid_phi;
00069 }
00070 
00071 //----------------------------------------------------------------------
00072 void PseudoJet::_set_rap_phi() const {
00073 
00074   if (_kt2 == 0.0) {
00075     _phi = 0.0; } 
00076   else {
00077     _phi = atan2(this->py(),this->px());
00078   }
00079   if (_phi < 0.0) {_phi += twopi;}
00080   if (_phi >= twopi) {_phi -= twopi;} // can happen if phi=-|eps<1e-15|?
00081   if (this->E() == abs(this->pz()) && _kt2 == 0) {
00082     // Point has infinite rapidity -- convert that into a very large
00083     // number, but in such a way that different 0-pt momenta will have
00084     // different rapidities (so as to lift the degeneracy between
00085     // them) [this can be relevant at parton-level]
00086     double MaxRapHere = MaxRap + abs(this->pz());
00087     if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
00088   } else {
00089     // get the rapidity in a way that's modestly insensitive to roundoff
00090     // error when things pz,E are large (actually the best we can do without
00091     // explicit knowledge of mass)
00092     double effective_m2 = max(0.0,m2()); // force non tachyonic mass
00093     double E_plus_pz    = _E + abs(_pz); // the safer of p+, p-
00094     // p+/p- = (p+ p-) / (p-)^2 = (kt^2+m^2)/(p-)^2
00095     _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
00096     if (_pz > 0) {_rap = - _rap;}
00097   }
00098 
00099 }
00100 
00101 
00102 //----------------------------------------------------------------------
00103 // return a valarray four-momentum
00104 valarray<double> PseudoJet::four_mom() const {
00105   valarray<double> mom(4);
00106   mom[0] = _px;
00107   mom[1] = _py;
00108   mom[2] = _pz;
00109   mom[3] = _E ;
00110   return mom;
00111 }
00112 
00113 //----------------------------------------------------------------------
00114 // Return the component corresponding to the specified index.
00115 // taken from CLHEP
00116 double PseudoJet::operator () (int i) const {
00117   switch(i) {
00118   case X:
00119     return px();
00120   case Y:
00121     return py();
00122   case Z:
00123     return pz();
00124   case T:
00125     return e();
00126   default:
00127     ostringstream err;
00128     err << "PseudoJet subscripting: bad index (" << i << ")";
00129     throw Error(err.str());
00130   }
00131   return 0.;
00132 }  
00133 
00134 //----------------------------------------------------------------------
00135 // return the pseudorapidity
00136 double PseudoJet::pseudorapidity() const {
00137   if (px() == 0.0 && py() ==0.0) return MaxRap;
00138   if (pz() == 0.0) return 0.0;
00139 
00140   double theta = atan(perp()/pz());
00141   if (theta < 0) theta += pi;
00142   return -log(tan(theta/2));
00143 }
00144 
00145 //----------------------------------------------------------------------
00146 // return "sum" of two pseudojets
00147 PseudoJet operator+ (const PseudoJet & jet1, const PseudoJet & jet2) {
00148   //return PseudoJet(jet1.four_mom()+jet2.four_mom());
00149   return PseudoJet(jet1.px()+jet2.px(),
00150                    jet1.py()+jet2.py(),
00151                    jet1.pz()+jet2.pz(),
00152                    jet1.E() +jet2.E()  );
00153 } 
00154 
00155 //----------------------------------------------------------------------
00156 // return difference of two pseudojets
00157 PseudoJet operator- (const PseudoJet & jet1, const PseudoJet & jet2) {
00158   //return PseudoJet(jet1.four_mom()-jet2.four_mom());
00159   return PseudoJet(jet1.px()-jet2.px(),
00160                    jet1.py()-jet2.py(),
00161                    jet1.pz()-jet2.pz(),
00162                    jet1.E() -jet2.E()  );
00163 } 
00164 
00165 //----------------------------------------------------------------------
00166 // return the product, coeff * jet
00167 PseudoJet operator* (double coeff, const PseudoJet & jet) {
00168   //return PseudoJet(coeff*jet.four_mom());
00169   // the following code is hopefully more efficient
00170   PseudoJet coeff_times_jet(jet);
00171   coeff_times_jet *= coeff;
00172   return coeff_times_jet;
00173 } 
00174 
00175 //----------------------------------------------------------------------
00176 // return the product, coeff * jet
00177 PseudoJet operator* (const PseudoJet & jet, double coeff) {
00178   return coeff*jet;
00179 } 
00180 
00181 //----------------------------------------------------------------------
00182 // return the ratio, jet / coeff
00183 PseudoJet operator/ (const PseudoJet & jet, double coeff) {
00184   return (1.0/coeff)*jet;
00185 } 
00186 
00187 //----------------------------------------------------------------------
00189 void PseudoJet::operator*=(double coeff) {
00190   _px *= coeff;
00191   _py *= coeff;
00192   _pz *= coeff;
00193   _E  *= coeff;
00194   _kt2*= coeff*coeff;
00195   // phi and rap are unchanged
00196 }
00197 
00198 //----------------------------------------------------------------------
00200 void PseudoJet::operator/=(double coeff) {
00201   (*this) *= 1.0/coeff;
00202 }
00203 
00204 
00205 //----------------------------------------------------------------------
00207 void PseudoJet::operator+=(const PseudoJet & other_jet) {
00208   _px += other_jet._px;
00209   _py += other_jet._py;
00210   _pz += other_jet._pz;
00211   _E  += other_jet._E ;
00212   _finish_init(); // we need to recalculate phi,rap,kt2
00213 }
00214 
00215 
00216 //----------------------------------------------------------------------
00218 void PseudoJet::operator-=(const PseudoJet & other_jet) {
00219   _px -= other_jet._px;
00220   _py -= other_jet._py;
00221   _pz -= other_jet._pz;
00222   _E  -= other_jet._E ;
00223   _finish_init(); // we need to recalculate phi,rap,kt2
00224 }
00225 
00226 
00227 //----------------------------------------------------------------------
00230 //
00231 // NB: code adapted from that in herwig f77 (checked how it worked
00232 // long ago)
00233 PseudoJet & PseudoJet::boost(const PseudoJet & prest) {
00234   
00235   if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0) 
00236     return *this;
00237 
00238   double m = prest.m();
00239   assert(m != 0);
00240 
00241   double pf4  = (  px()*prest.px() + py()*prest.py()
00242                  + pz()*prest.pz() + E()*prest.E() )/m;
00243   double fn   = (pf4 + E()) / (prest.E() + m);
00244   _px +=  fn*prest.px();
00245   _py +=  fn*prest.py();
00246   _pz +=  fn*prest.pz();
00247   _E = pf4;
00248 
00249   _finish_init(); // we need to recalculate phi,rap,kt2
00250   return *this;
00251 }
00252 
00253 
00254 //----------------------------------------------------------------------
00257 //
00258 // NB: code adapted from that in herwig f77 (checked how it worked
00259 // long ago)
00260 PseudoJet & PseudoJet::unboost(const PseudoJet & prest) {
00261   
00262   if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0) 
00263     return *this;
00264 
00265   double m = prest.m();
00266   assert(m != 0);
00267 
00268   double pf4  = ( -px()*prest.px() - py()*prest.py()
00269                  - pz()*prest.pz() + E()*prest.E() )/m;
00270   double fn   = (pf4 + E()) / (prest.E() + m);
00271   _px -=  fn*prest.px();
00272   _py -=  fn*prest.py();
00273   _pz -=  fn*prest.pz();
00274   _E = pf4;
00275 
00276   _finish_init(); // we need to recalculate phi,rap,kt2
00277   return *this;
00278 }
00279 
00280 
00281 //----------------------------------------------------------------------
00283 bool have_same_momentum(const PseudoJet & jeta, const PseudoJet & jetb) {
00284   return jeta.px() == jetb.px()
00285     &&   jeta.py() == jetb.py()
00286     &&   jeta.pz() == jetb.pz()
00287     &&   jeta.E()  == jetb.E();
00288 }
00289 
00290 
00291 //----------------------------------------------------------------------
00293 PseudoJet PtYPhiM(double pt, double y, double phi, double m) {
00294   double ptm = sqrt(pt*pt+m*m);
00295   return PseudoJet(pt*cos(phi), pt*sin(phi), ptm*sinh(y), ptm*cosh(y));
00296 }
00297 
00298 
00299 //----------------------------------------------------------------------
00300 // return kt-distance between this jet and another one
00301 double PseudoJet::kt_distance(const PseudoJet & other) const {
00302   //double distance = min(this->kt2(), other.kt2());
00303   double distance = min(_kt2, other._kt2);
00304   double dphi = abs(phi() - other.phi());
00305   if (dphi > pi) {dphi = twopi - dphi;}
00306   double drap = rap() - other.rap();
00307   distance = distance * (dphi*dphi + drap*drap);
00308   return distance;
00309 }
00310 
00311 
00312 //----------------------------------------------------------------------
00313 // return squared cylinder (eta-phi) distance between this jet and another one
00314 double PseudoJet::plain_distance(const PseudoJet & other) const {
00315   double dphi = abs(phi() - other.phi());
00316   if (dphi > pi) {dphi = twopi - dphi;}
00317   double drap = rap() - other.rap();
00318   return (dphi*dphi + drap*drap);
00319 }
00320 
00321 //----------------------------------------------------------------------
00324 double PseudoJet::delta_phi_to(const PseudoJet & other) const {
00325   double dphi = other.phi() - phi();
00326   if (dphi >  pi) dphi -= twopi;
00327   if (dphi < -pi) dphi += twopi;
00328   return dphi;
00329 }
00330 
00331 
00332 //----------------------------------------------------------------------
00333 //
00334 // The following methods access the associated cluster sequence (if any)
00335 //
00336 //----------------------------------------------------------------------
00337 
00338 
00339 //----------------------------------------------------------------------
00340 // check whether this PseudoJet has an associated parent
00341 // ClusterSequence
00342 bool PseudoJet::has_associated_cluster_sequence() const{
00343   return (_associated_csw()) && (_associated_csw->is_alive());
00344 }
00345 
00346 //----------------------------------------------------------------------
00347 // get a (const) pointer to the associated ClusterSequence (NULL if
00348 // inexistent)
00349 const ClusterSequence* PseudoJet::associated_cluster_sequence() const{
00350   if (! has_associated_cluster_sequence()) return NULL;
00351 
00352   return _associated_csw->cs();
00353 }
00354 
00355 
00356 //----------------------------------------------------------------------
00357 // If there is a valid cluster sequence associated with this jet,
00358 // returns a pointer to it; otherwise throws an Error.
00359 //
00360 // Open question: should these errors be upgraded to classes of their
00361 // own so that they can be caught? [Maybe, but later]
00362 const ClusterSequence * PseudoJet::validated_cs() const {
00363   if (!_associated_csw()) 
00364     throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence.");
00365   if (!_associated_csw->is_alive()) 
00366     throw Error("you requested information about the internal structure of a jet, but its associated ClusterSequence has gone out of scope.");
00367   return _associated_csw->cs();
00368 }
00369 
00370 
00371 //----------------------------------------------------------------------
00372 // check if it has been recombined with another PseudoJet in which
00373 // case, return its partner through the argument. Otherwise,
00374 // 'partner' is set to 0.
00375 //
00376 // false is also returned if this PseudoJet has no associated
00377 // ClusterSequence
00378 bool PseudoJet::has_partner(PseudoJet &partner) const{
00379   return validated_cs()->has_partner(*this, partner);
00380 }
00381 
00382 //----------------------------------------------------------------------
00383 // check if it has been recombined with another PseudoJet in which
00384 // case, return its child through the argument. Otherwise, 'child'
00385 // is set to 0.
00386 // 
00387 // false is also returned if this PseudoJet has no associated
00388 // ClusterSequence, with the child set to 0
00389 bool PseudoJet::has_child(PseudoJet &child) const{
00390   return validated_cs()->has_child(*this, child);
00391 }
00392 
00393 //----------------------------------------------------------------------
00394 // check if it is the product of a recombination, in which case
00395 // return the 2 parents through the 'parent1' and 'parent2'
00396 // arguments. Otherwise, set these to 0.
00397 //
00398 // false is also returned if this PseudoJet has no parent
00399 // ClusterSequence
00400 bool PseudoJet::has_parents(PseudoJet &parent1, PseudoJet &parent2) const{
00401   return validated_cs()->has_parents(*this, parent1, parent2);
00402 }
00403 
00404 //----------------------------------------------------------------------
00405 // check if the current PseudoJet contains the one passed as
00406 // argument
00407 //
00408 // false is also returned if this PseudoJet has no associated
00409 // ClusterSequence.
00410 bool PseudoJet::contains(const PseudoJet &constituent) const{
00411   return validated_cs()->object_in_jet(constituent, *this);
00412 }
00413 
00414 //----------------------------------------------------------------------
00415 // check if the current PseudoJet is contained the one passed as
00416 // argument
00417 //
00418 // false is also returned if this PseudoJet has no associated
00419 // ClusterSequence
00420 bool PseudoJet::is_inside(const PseudoJet &jet) const{
00421   return validated_cs()->object_in_jet(*this, jet);
00422 }
00423 
00424 
00425 //----------------------------------------------------------------------
00426 // retrieve the constituents. An empty vector is returned if there is
00427 // no associated ClusterSequence
00428 vector<PseudoJet> PseudoJet::constituents() const{
00429   return validated_cs()->constituents(*this);
00430 }
00431 
00432 
00433 //----------------------------------------------------------------------
00434 // return a vector of all subjets of the current jet (in the sense
00435 // of the exclusive algorithm) that would be obtained when running
00436 // the algorithm with the given dcut. 
00437 //
00438 // Time taken is O(m ln m), where m is the number of subjets that
00439 // are found. If m gets to be of order of the total number of
00440 // constituents in the jet, this could be substantially slower than
00441 // just getting that list of constituents.
00442 //
00443 // an Error is thrown if this PseudoJet has no currently valid
00444 // associated ClusterSequence
00445 std::vector<PseudoJet> PseudoJet::exclusive_subjets (const double & dcut) const {
00446   return validated_cs()->exclusive_subjets(*this, dcut);
00447 }
00448 
00449 //----------------------------------------------------------------------
00450 // return the size of exclusive_subjets(...); still n ln n with same
00451 // coefficient, but marginally more efficient than manually taking
00452 // exclusive_subjets.size()
00453 //
00454 // an Error is thrown if this PseudoJet has no currently valid
00455 // associated ClusterSequence
00456 int PseudoJet::n_exclusive_subjets(const double & dcut) const {
00457   return validated_cs()->n_exclusive_subjets(*this, dcut);
00458 }
00459 
00460 //----------------------------------------------------------------------
00461 // return the list of subjets obtained by unclustering the supplied
00462 // jet down to n subjets (or all constituents if there are fewer
00463 // than n).
00464 //
00465 // requires n ln n time
00466 //
00467 // an Error is thrown if this PseudoJet has no currently valid
00468 // associated ClusterSequence
00469 std::vector<PseudoJet> PseudoJet::exclusive_subjets (int nsub) const {
00470   return validated_cs()->exclusive_subjets(*this, nsub);
00471 }
00472 
00473 //----------------------------------------------------------------------
00474 // return the dij that was present in the merging nsub+1 -> nsub 
00475 // subjets inside this jet.
00476 //
00477 // an Error is thrown if this PseudoJet has no currently valid
00478 // associated ClusterSequence
00479 double PseudoJet::exclusive_subdmerge(int nsub) const {
00480   return validated_cs()->exclusive_subdmerge(*this, nsub);
00481 }
00482 
00483 //----------------------------------------------------------------------
00484 // return the maximum dij that occurred in the whole event at the
00485 // stage that the nsub+1 -> nsub merge of subjets occurred inside 
00486 // this jet.
00487 //
00488 // an Error is thrown if this PseudoJet has no currently valid
00489 // associated ClusterSequence
00490 double PseudoJet::exclusive_subdmerge_max(int nsub) const {
00491   return validated_cs()->exclusive_subdmerge_max(*this, nsub);
00492 }
00493 
00494 //----------------------------------------------------------------------
00495 // the following ones require a computation of the area in the
00496 // associated ClusterSequence (See ClusterSequenceAreaBase for details)
00497 //----------------------------------------------------------------------
00498 
00499 //----------------------------------------------------------------------
00500 // if possible, return a valid ClusterSequenceAreaBase pointer; otherwise
00501 // throw an error
00502 const ClusterSequenceAreaBase * PseudoJet::validated_csab() const {
00503   const ClusterSequenceAreaBase *csab = dynamic_cast<const ClusterSequenceAreaBase*>(validated_cs());
00504   if (csab == NULL) throw Error("you requested jet-area related information, but the PseudoJet does not have associated area information.");
00505   return csab;
00506 }
00507 
00508 
00509 //----------------------------------------------------------------------
00510 // check if it has a defined area
00511 bool PseudoJet::has_area() const{
00512   if (! has_associated_cluster_sequence()) return false;
00513   return (dynamic_cast<const ClusterSequenceAreaBase*>(_associated_csw->cs()) != NULL);
00514 }
00515 
00516 //----------------------------------------------------------------------
00517 // return the jet (scalar) area.
00518 // throw an Error if there is no support for area in the associated CS
00519 double PseudoJet::area() const{
00520   return validated_csab()->area(*this);
00521 }
00522 
00523 //----------------------------------------------------------------------
00524 // return the error (uncertainty) associated with the determination
00525 // of the area of this jet.
00526 // throws an Error if there is no support for area in the associated CS
00527 double PseudoJet::area_error() const{
00528   return validated_csab()->area_error(*this);
00529 }
00530 
00531 //----------------------------------------------------------------------
00532 // return the jet 4-vector area
00533 // throws an Error if there is no support for area in the associated CS
00534 PseudoJet PseudoJet::area_4vector() const{
00535   return validated_csab()->area_4vector(*this);
00536 }
00537 
00538 //----------------------------------------------------------------------
00539 // true if this jet is made exclusively of ghosts
00540 // throws an Error if there is no support for area in the associated CS
00541 bool PseudoJet::is_pure_ghost() const{
00542   return validated_csab()->is_pure_ghost(*this);
00543 }
00544 
00545 
00546 //----------------------------------------------------------------------
00547 //
00548 // end of the methods accessing the information in the associated
00549 // Cluster Sequence
00550 //
00551 //----------------------------------------------------------------------
00552 
00553 //----------------------------------------------------------------------
00555 PseudoJet::InexistentExtraInfo::InexistentExtraInfo() : Error("you attempted to perform a dynamic cast of a PseudoJet's extra info, but the extra info pointer was null")
00556 {}
00557 
00558 
00559 //----------------------------------------------------------------------
00560 // sort the indices so that values[indices[0..n-1]] is sorted
00561 // into increasing order 
00562 void sort_indices(vector<int> & indices, 
00563                          const vector<double> & values) {
00564   IndexedSortHelper index_sort_helper(&values);
00565   sort(indices.begin(), indices.end(), index_sort_helper);
00566 }
00567 
00568 
00569 
00570 //----------------------------------------------------------------------
00574 template<class T> vector<T>  objects_sorted_by_values(
00575                        const vector<T> & objects, 
00576                        const vector<double> & values) {
00577 
00578   assert(objects.size() == values.size());
00579 
00580   // get a vector of indices
00581   vector<int> indices(values.size());
00582   for (size_t i = 0; i < indices.size(); i++) {indices[i] = i;}
00583   
00584   // sort the indices
00585   sort_indices(indices, values);
00586   
00587   // copy the objects 
00588   vector<T> objects_sorted(objects.size());
00589   
00590   // place the objects in the correct order
00591   for (size_t i = 0; i < indices.size(); i++) {
00592     objects_sorted[i] = objects[indices[i]];
00593   }
00594 
00595   return objects_sorted;
00596 }
00597 
00598 //----------------------------------------------------------------------
00600 vector<PseudoJet> sorted_by_pt(const vector<PseudoJet> & jets) {
00601   vector<double> minus_kt2(jets.size());
00602   for (size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
00603   return objects_sorted_by_values(jets, minus_kt2);
00604 }
00605 
00606 //----------------------------------------------------------------------
00608 vector<PseudoJet> sorted_by_rapidity(const vector<PseudoJet> & jets) {
00609   vector<double> rapidities(jets.size());
00610   for (size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
00611   return objects_sorted_by_values(jets, rapidities);
00612 }
00613 
00614 //----------------------------------------------------------------------
00616 vector<PseudoJet> sorted_by_E(const vector<PseudoJet> & jets) {
00617   vector<double> energies(jets.size());
00618   for (size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
00619   return objects_sorted_by_values(jets, energies);
00620 }
00621 
00622 //----------------------------------------------------------------------
00624 vector<PseudoJet> sorted_by_pz(const vector<PseudoJet> & jets) {
00625   vector<double> pz(jets.size());
00626   for (size_t i = 0; i < jets.size(); i++) {pz[i] = jets[i].pz();}
00627   return objects_sorted_by_values(jets, pz);
00628 }
00629 
00630 
00631 FASTJET_END_NAMESPACE
00632