Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:06:47

0001 #ifndef RIVET_MATH_VECTOR4
0002 #define RIVET_MATH_VECTOR4
0003 
0004 #include "Rivet/Tools/TypeTraits.hh"
0005 #include "Rivet/Math/MathConstants.hh"
0006 #include "Rivet/Math/MathUtils.hh"
0007 #include "Rivet/Math/VectorN.hh"
0008 #include "Rivet/Math/Vector3.hh"
0009 
0010 // Forward declaration
0011 namespace fastjet { class PseudoJet; }
0012 
0013 namespace Rivet {
0014 
0015 
0016   class FourVector;
0017   typedef FourVector Vector4;
0018   typedef FourVector V4;
0019 
0020   class FourMomentum;
0021   typedef FourMomentum P4;
0022 
0023   class LorentzTransform;
0024   FourVector transform(const LorentzTransform& lt, const FourVector& v4);
0025 
0026 
0027   /// @brief Specialisation of VectorN to a general (non-momentum) Lorentz 4-vector.
0028   ///
0029   /// @todo Add composite set/mk methods from different coord systems
0030   class FourVector : public Vector<4> {
0031     friend FourVector multiply(const double a, const FourVector& v);
0032     friend FourVector multiply(const FourVector& v, const double a);
0033     friend FourVector add(const FourVector& a, const FourVector& b);
0034     friend FourVector transform(const LorentzTransform& lt, const FourVector& v4);
0035 
0036   public:
0037 
0038     FourVector() : Vector<4>() { }
0039 
0040     template<typename V4TYPE, typename std::enable_if<HasXYZT<V4TYPE>::value, int>::type DUMMY=0>
0041     FourVector(const V4TYPE& other) {
0042       this->setT(other.t());
0043       this->setX(other.x());
0044       this->setY(other.y());
0045       this->setZ(other.z());
0046     }
0047 
0048     FourVector(const Vector<4>& other)
0049       : Vector<4>(other) { }
0050 
0051     FourVector(const double t, const double x, const double y, const double z) {
0052       this->setT(t);
0053       this->setX(x);
0054       this->setY(y);
0055       this->setZ(z);
0056     }
0057 
0058     virtual ~FourVector() { }
0059 
0060     /// @brief Cast operator to FastJet PseudoJet
0061     ///
0062     /// Needed, since otherwise the PseudoJet template constructor assumes
0063     /// the indices [0-3] mean px,py,pz,E... but Rivet uses E,px,py,pz ordering.
0064     operator fastjet::PseudoJet () const;
0065 
0066 
0067   public:
0068 
0069     double t() const { return get(0); }
0070     double t2() const { return sqr(t()); }
0071     FourVector& setT(const double t) { set(0, t); return *this; }
0072 
0073     double x() const { return get(1); }
0074     double x2() const { return sqr(x()); }
0075     FourVector& setX(const double x) { set(1, x); return *this; }
0076 
0077     double y() const { return get(2); }
0078     double y2() const { return sqr(y()); }
0079     FourVector& setY(const double y) { set(2, y); return *this; }
0080 
0081     double z() const { return get(3); }
0082     double z2() const { return sqr(z()); }
0083     FourVector& setZ(const double z) { set(3, z); return *this; }
0084 
0085     double invariant() const {
0086       // Done this way for numerical precision
0087       return (t() + z())*(t() - z()) - x()*x() - y()*y();
0088     }
0089 
0090     bool isNull() const {
0091       return Rivet::isZero(invariant());
0092     }
0093 
0094     /// Angle between this vector and another
0095     double angle(const FourVector& v) const {
0096       return vector3().angle( v.vector3() );
0097     }
0098     /// Angle between this vector and another (3-vector)
0099     double angle(const Vector3& v3) const {
0100       return vector3().angle(v3);
0101     }
0102 
0103     /// @brief Mod-square of the projection of the 3-vector on to the \f$ x-y \f$ plane
0104     /// This is a more efficient function than @c polarRadius, as it avoids the square root.
0105     /// Use it if you only need the squared value, or e.g. an ordering by magnitude.
0106     double polarRadius2() const {
0107       return vector3().polarRadius2();
0108     }
0109     /// Synonym for polarRadius2
0110     double perp2() const {
0111       return vector3().perp2();
0112     }
0113     /// Synonym for polarRadius2
0114     double rho2() const {
0115       return vector3().rho2();
0116     }
0117 
0118     /// Magnitude of projection of 3-vector on to the \f$ x-y \f$ plane
0119     double polarRadius() const {
0120       return vector3().polarRadius();
0121     }
0122     /// Synonym for polarRadius
0123     double perp() const {
0124       return vector3().perp();
0125     }
0126     /// Synonym for polarRadius
0127     double rho() const {
0128       return vector3().rho();
0129     }
0130 
0131     /// Projection of 3-vector on to the \f$ x-y \f$ plane
0132     Vector3 polarVec() const {
0133       return vector3().polarVec();
0134     }
0135     /// Synonym for polarVec
0136     Vector3 perpVec() const {
0137       return vector3().perpVec();
0138     }
0139     /// Synonym for polarVec
0140     Vector3 rhoVec() const {
0141       return vector3().rhoVec();
0142     }
0143 
0144     /// Angle subtended by the 3-vector's projection in x-y and the x-axis.
0145     double azimuthalAngle(const PhiMapping mapping=ZERO_2PI) const {
0146       return vector3().azimuthalAngle(mapping);
0147     }
0148     /// Synonym for azimuthalAngle.
0149     double phi(const PhiMapping mapping=ZERO_2PI) const {
0150       return vector3().phi(mapping);
0151     }
0152 
0153     /// Angle subtended by the 3-vector and the z-axis.
0154     double polarAngle() const {
0155       return vector3().polarAngle();
0156     }
0157     /// Synonym for polarAngle.
0158     double theta() const {
0159       return vector3().theta();
0160     }
0161 
0162     /// Pseudorapidity (defined purely by the 3-vector components)
0163     double pseudorapidity() const {
0164       return vector3().pseudorapidity();
0165     }
0166     /// Synonym for pseudorapidity.
0167     double eta() const {
0168       return vector3().eta();
0169     }
0170 
0171     /// Get the \f$ |\eta| \f$ directly.
0172     double abspseudorapidity() const { return fabs(eta()); }
0173     /// Get the \f$ |\eta| \f$ directly (alias).
0174     double abseta() const { return fabs(eta()); }
0175 
0176     /// Get the spatial part of the 4-vector as a 3-vector.
0177     Vector3 vector3() const {
0178       return Vector3(get(1), get(2), get(3));
0179     }
0180 
0181     /// Implicit cast to a 3-vector
0182     operator Vector3 () const { return vector3(); }
0183 
0184 
0185   public:
0186 
0187     /// Contract two 4-vectors, with metric signature (+ - - -).
0188     double contract(const FourVector& v) const {
0189       const double result = t()*v.t() - x()*v.x() - y()*v.y() - z()*v.z();
0190       return result;
0191     }
0192 
0193     /// Contract two 4-vectors, with metric signature (+ - - -).
0194     double dot(const FourVector& v) const {
0195       return contract(v);
0196     }
0197 
0198     /// Contract two 4-vectors, with metric signature (+ - - -).
0199     double operator * (const FourVector& v) const {
0200       return contract(v);
0201     }
0202 
0203     /// Multiply by a scalar.
0204     FourVector& operator *= (double a) {
0205       _vec = multiply(a, *this)._vec;
0206       return *this;
0207     }
0208 
0209     /// Divide by a scalar.
0210     FourVector& operator /= (double a) {
0211       _vec = multiply(1.0/a, *this)._vec;
0212       return *this;
0213     }
0214 
0215     /// Add to this 4-vector.
0216     FourVector& operator += (const FourVector& v) {
0217       _vec = add(*this, v)._vec;
0218       return *this;
0219     }
0220 
0221     /// Subtract from this 4-vector. NB time as well as space components are subtracted.
0222     FourVector& operator -= (const FourVector& v) {
0223       _vec = add(*this, -v)._vec;
0224       return *this;
0225     }
0226 
0227     /// Multiply all components (space and time) by -1.
0228     FourVector operator - () const {
0229       FourVector result;
0230       result._vec = -_vec;
0231       return result;
0232     }
0233 
0234     /// Multiply space components only by -1.
0235     FourVector reverse() const {
0236       FourVector result = -*this;
0237       result.setT(-result.t());
0238       return result;
0239     }
0240 
0241   };
0242 
0243 
0244   /// Contract two 4-vectors, with metric signature (+ - - -).
0245   inline double contract(const FourVector& a, const FourVector& b) {
0246     return a.contract(b);
0247   }
0248 
0249   /// Contract two 4-vectors, with metric signature (+ - - -).
0250   inline double dot(const FourVector& a, const FourVector& b) {
0251     return contract(a, b);
0252   }
0253 
0254   inline FourVector multiply(const double a, const FourVector& v) {
0255     FourVector result;
0256     result._vec = a * v._vec;
0257     return result;
0258   }
0259 
0260   inline FourVector multiply(const FourVector& v, const double a) {
0261     return multiply(a, v);
0262   }
0263 
0264   inline FourVector operator * (const double a, const FourVector& v) {
0265     return multiply(a, v);
0266   }
0267 
0268   inline FourVector operator * (const FourVector& v, const double a) {
0269     return multiply(a, v);
0270   }
0271 
0272   inline FourVector operator / (const FourVector& v, const double a) {
0273     return multiply(1.0/a, v);
0274   }
0275 
0276   inline FourVector add(const FourVector& a, const FourVector& b) {
0277     FourVector result;
0278     result._vec = a._vec + b._vec;
0279     return result;
0280   }
0281 
0282   inline FourVector operator+(const FourVector& a, const FourVector& b) {
0283     return add(a, b);
0284   }
0285 
0286   inline FourVector operator-(const FourVector& a, const FourVector& b) {
0287     return add(a, -b);
0288   }
0289 
0290   /// Calculate the Lorentz self-invariant of a 4-vector.
0291   /// \f$ v_\mu v^\mu = g_{\mu\nu} x^\mu x^\nu \f$.
0292   inline double invariant(const FourVector& lv) {
0293     return lv.invariant();
0294   }
0295 
0296   /// Angle (in radians) between spatial parts of two Lorentz vectors.
0297   inline double angle(const FourVector& a, const FourVector& b) {
0298     return a.angle(b);
0299   }
0300 
0301   /// Angle (in radians) between spatial parts of two Lorentz vectors.
0302   inline double angle(const Vector3& a, const FourVector& b) {
0303     return angle( a, b.vector3() );
0304   }
0305 
0306   /// Angle (in radians) between spatial parts of two Lorentz vectors.
0307   inline double angle(const FourVector& a, const Vector3& b) {
0308     return a.angle(b);
0309   }
0310 
0311 
0312   ////////////////////////////////////////////////
0313 
0314 
0315   /// Specialized version of the FourVector with momentum/energy functionality.
0316   class FourMomentum : public FourVector {
0317     friend FourMomentum multiply(const double a, const FourMomentum& v);
0318     friend FourMomentum multiply(const FourMomentum& v, const double a);
0319     friend FourMomentum add(const FourMomentum& a, const FourMomentum& b);
0320     friend FourMomentum transform(const LorentzTransform& lt, const FourMomentum& v4);
0321 
0322   public:
0323     FourMomentum() { }
0324 
0325    template<typename V4TYPE, typename std::enable_if<HasXYZT<V4TYPE>::value, int>::type DUMMY=0>
0326     FourMomentum(const V4TYPE& other) {
0327       this->setE(other.t());
0328       this->setPx(other.x());
0329       this->setPy(other.y());
0330       this->setPz(other.z());
0331     }
0332 
0333     FourMomentum(const Vector<4>& other)
0334       : FourVector(other) { }
0335 
0336     FourMomentum(const double E, const double px, const double py, const double pz) {
0337       this->setE(E);
0338       this->setPx(px);
0339       this->setPy(py);
0340       this->setPz(pz);
0341     }
0342 
0343     ~FourMomentum() {}
0344 
0345   public:
0346 
0347 
0348     /// @name Coordinate setters
0349     /// @{
0350 
0351     /// Set energy \f$ E \f$ (time component of momentum).
0352     FourMomentum& setE(double E) {
0353       setT(E);
0354       return *this;
0355     }
0356 
0357     /// Set x-component of momentum \f$ p_x \f$.
0358     FourMomentum& setPx(double px) {
0359       setX(px);
0360       return *this;
0361     }
0362 
0363     /// Set y-component of momentum \f$ p_y \f$.
0364     FourMomentum& setPy(double py) {
0365       setY(py);
0366       return *this;
0367     }
0368 
0369     /// Set z-component of momentum \f$ p_z \f$.
0370     FourMomentum& setPz(double pz) {
0371       setZ(pz);
0372       return *this;
0373     }
0374 
0375 
0376     /// Set the p coordinates and energy simultaneously
0377     FourMomentum& setPE(double px, double py, double pz, double E) {
0378       if (E < 0)
0379         throw std::invalid_argument("Negative energy given as argument: " + to_str(E));
0380       setPx(px); setPy(py); setPz(pz); setE(E);
0381       return *this;
0382     }
0383     /// Alias for setPE
0384     FourMomentum& setXYZE(double px, double py, double pz, double E) {
0385       return setPE(px, py, pz, E);
0386     }
0387     // /// Near-alias with switched arg order
0388     // FourMomentum& setEP(double E, double px, double py, double pz) {
0389     //   return setPE(px, py, pz, E);
0390     // }
0391     // /// Alias for setEP
0392     // FourMomentum& setEXYZ(double E, double px, double py, double pz) {
0393     //   return setEP(E, px, py, pz);
0394     // }
0395 
0396 
0397     /// Set the p coordinates and mass simultaneously
0398     FourMomentum& setPM(double px, double py, double pz, double mass) {
0399       if (mass < 0)
0400         throw std::invalid_argument("Negative mass given as argument: " + to_str(mass));
0401       const double E = sqrt( sqr(mass) + sqr(px) + sqr(py) + sqr(pz) );
0402       // setPx(px); setPy(py); setPz(pz); setE(E);
0403       return setPE(px, py, pz, E);
0404     }
0405     /// Alias for setPM
0406     FourMomentum& setXYZM(double px, double py, double pz, double mass) {
0407       return setPM(px, py, pz, mass);
0408     }
0409 
0410 
0411     /// Set the vector state from (eta,phi,energy) coordinates and the mass
0412     ///
0413     /// eta = -ln(tan(theta/2))
0414     /// -> theta = 2 atan(exp(-eta))
0415     FourMomentum& setEtaPhiME(double eta, double phi, double mass, double E) {
0416       if (mass < 0)
0417         throw std::invalid_argument("Negative mass given as argument");
0418       if (E < 0)
0419         throw std::invalid_argument("Negative energy given as argument");
0420       const double theta = 2 * atan(exp(-eta));
0421       if (theta < 0 || theta > M_PI)
0422         throw std::domain_error("Polar angle outside 0..pi in calculation");
0423       setThetaPhiME(theta, phi, mass, E);
0424       return *this;
0425     }
0426 
0427     /// Set the vector state from (eta,phi,pT) coordinates and the mass
0428     ///
0429     /// eta = -ln(tan(theta/2))
0430     /// -> theta = 2 atan(exp(-eta))
0431     FourMomentum& setEtaPhiMPt(double eta, double phi, double mass, double pt) {
0432       if (mass < 0)
0433         throw std::invalid_argument("Negative mass given as argument");
0434       if (pt < 0)
0435         throw std::invalid_argument("Negative transverse momentum given as argument");
0436       const double theta = 2 * atan(exp(-eta));
0437       if (theta < 0 || theta > M_PI)
0438         throw std::domain_error("Polar angle outside 0..pi in calculation");
0439       const double p = pt / sin(theta);
0440       const double E = sqrt( sqr(p) + sqr(mass) );
0441       setThetaPhiME(theta, phi, mass, E);
0442       return *this;
0443     }
0444 
0445     /// Set the vector state from (y,phi,energy) coordinates and the mass
0446     ///
0447     /// y = 0.5 * ln((E+pz)/(E-pz))
0448     /// -> (E^2 - pz^2) exp(2y) = (E+pz)^2
0449     ///  & (E^2 - pz^2) exp(-2y) = (E-pz)^2
0450     /// -> E = sqrt(pt^2 + m^2) cosh(y)
0451     /// -> pz = sqrt(pt^2 + m^2) sinh(y)
0452     /// -> sqrt(pt^2 + m^2) = E / cosh(y)
0453     FourMomentum& setRapPhiME(double y, double phi, double mass, double E) {
0454       if (mass < 0)
0455         throw std::invalid_argument("Negative mass given as argument");
0456       if (E < 0)
0457         throw std::invalid_argument("Negative energy given as argument");
0458       const double sqrt_pt2_m2 = E / cosh(y);
0459       const double pt = sqrt( sqr(sqrt_pt2_m2) - sqr(mass) );
0460       if (pt < 0)
0461         throw std::domain_error("Negative transverse momentum in calculation");
0462       const double pz = sqrt_pt2_m2 * sinh(y);
0463       const double px = pt * cos(phi);
0464       const double py = pt * sin(phi);
0465       setPE(px, py, pz, E);
0466       return *this;
0467     }
0468 
0469     /// Set the vector state from (y,phi,pT) coordinates and the mass
0470     ///
0471     /// y = 0.5 * ln((E+pz)/(E-pz))
0472     /// -> E = sqrt(pt^2 + m^2) cosh(y)  [see above]
0473     FourMomentum& setRapPhiMPt(double y, double phi, double mass, double pt) {
0474       if (mass < 0)
0475         throw std::invalid_argument("Negative mass given as argument");
0476       if (pt < 0)
0477         throw std::invalid_argument("Negative transverse mass given as argument");
0478       const double E = sqrt( sqr(pt) + sqr(mass) ) * cosh(y);
0479       if (E < 0)
0480         throw std::domain_error("Negative energy in calculation");
0481       setRapPhiME(y, phi, mass, E);
0482       return *this;
0483     }
0484 
0485     /// Set the vector state from (theta,phi,energy) coordinates and the mass
0486     ///
0487     /// p = sqrt(E^2 - mass^2)
0488     /// pz = p cos(theta)
0489     /// pt = p sin(theta)
0490     FourMomentum& setThetaPhiME(double theta, double phi, double mass, double E) {
0491       if (theta < 0 || theta > M_PI)
0492         throw std::invalid_argument("Polar angle outside 0..pi given as argument");
0493       if (mass < 0)
0494         throw std::invalid_argument("Negative mass given as argument");
0495       if (E < 0)
0496         throw std::invalid_argument("Negative energy given as argument");
0497       const double p = sqrt( sqr(E) - sqr(mass) );
0498       const double pz = p * cos(theta);
0499       const double pt = p * sin(theta);
0500       if (pt < 0)
0501         throw std::invalid_argument("Negative transverse momentum in calculation");
0502       const double px = pt * cos(phi);
0503       const double py = pt * sin(phi);
0504       setPE(px, py, pz, E);
0505       return *this;
0506     }
0507 
0508     /// Set the vector state from (theta,phi,pT) coordinates and the mass
0509     ///
0510     /// p = pt / sin(theta)
0511     /// pz = p cos(theta)
0512     /// E = sqrt(p^2 + mass^2)
0513     FourMomentum& setThetaPhiMPt(double theta, double phi, double mass, double pt) {
0514       if (theta < 0 || theta > M_PI)
0515         throw std::invalid_argument("Polar angle outside 0..pi given as argument");
0516       if (mass < 0)
0517         throw std::invalid_argument("Negative mass given as argument");
0518       if (pt < 0)
0519         throw std::invalid_argument("Negative transverse momentum given as argument");
0520       const double p = pt / sin(theta);
0521       const double px = pt * cos(phi);
0522       const double py = pt * sin(phi);
0523       const double pz = p * cos(theta);
0524       const double E = sqrt( sqr(p) + sqr(mass) );
0525       setPE(px, py, pz, E);
0526       return *this;
0527     }
0528 
0529     /// Set the vector state from (pT,phi,energy) coordinates and the mass
0530     ///
0531     /// pz = sqrt(E^2 - mass^2 - pt^2)
0532     FourMomentum& setPtPhiME(double pt, double phi, double mass, double E) {
0533       if (pt < 0)
0534         throw std::invalid_argument("Negative transverse momentum given as argument");
0535       if (mass < 0)
0536         throw std::invalid_argument("Negative mass given as argument");
0537       if (E < 0)
0538         throw std::invalid_argument("Negative energy given as argument");
0539       const double px = pt * cos(phi);
0540       const double py = pt * sin(phi);
0541       const double pz = sqrt(sqr(E) - sqr(mass) - sqr(pt));
0542       setPE(px, py, pz, E);
0543       return *this;
0544     }
0545 
0546     /// @}
0547 
0548 
0549     /// @name Accessors
0550     /// @{
0551 
0552     /// Get energy \f$ E \f$ (time component of momentum).
0553     double E() const { return t(); }
0554     /// Get energy-squared \f$ E^2 \f$.
0555     double E2() const { return t2(); }
0556 
0557     /// Get x-component of momentum \f$ p_x \f$.
0558     double px() const { return x(); }
0559     /// Get x-squared \f$ p_x^2 \f$.
0560     double px2() const { return x2(); }
0561 
0562     /// Get y-component of momentum \f$ p_y \f$.
0563     double py() const { return y(); }
0564     /// Get y-squared \f$ p_y^2 \f$.
0565     double py2() const { return y2(); }
0566 
0567     /// Get z-component of momentum \f$ p_z \f$.
0568     double pz() const { return z(); }
0569     /// Get z-squared \f$ p_z^2 \f$.
0570     double pz2() const { return z2(); }
0571 
0572 
0573     /// @brief Get the mass \f$ m = \sqrt{E^2 - p^2} \f$ (the Lorentz self-invariant).
0574     ///
0575     /// For spacelike momenta, the mass will be -sqrt(|mass2|).
0576     double mass() const {
0577       // assert(Rivet::isZero(mass2()) || mass2() > 0);
0578       // if (Rivet::isZero(mass2())) {
0579       //   return 0.0;
0580       // } else {
0581       //   return sqrt(mass2());
0582       // }
0583       return sign(mass2()) * sqrt(fabs(mass2()));
0584     }
0585 
0586     /// Get the squared mass \f$ m^2 = E^2 - p^2 \f$ (the Lorentz self-invariant).
0587     double mass2() const {
0588       return invariant();
0589     }
0590 
0591 
0592     /// Get 3-momentum part, \f$ p \f$.
0593     Vector3 p3() const { return vector3(); }
0594 
0595     /// Get the modulus of the 3-momentum
0596     double p() const {
0597       return p3().mod();
0598     }
0599 
0600     /// Get the modulus-squared of the 3-momentum
0601     double p2() const {
0602       return p3().mod2();
0603     }
0604 
0605 
0606     /// Calculate the rapidity.
0607     double rapidity() const {
0608       if (E() == 0.0) return 0.0; ///< @todo Add [[ unlikely ]] with C++20
0609       if (E() == fabs(pz())) return std::copysign(INF, pz()); ///< @todo Add [[ unlikely ]] with C++20
0610       return 0.5 * std::log( (E() + pz()) / (E() - pz()) );
0611     }
0612     /// Alias for rapidity.
0613     double rap() const {
0614       return rapidity();
0615     }
0616 
0617     /// Absolute rapidity.
0618     double absrapidity() const {
0619       return fabs(rapidity());
0620     }
0621     /// Absolute rapidity.
0622     double absrap() const {
0623       return fabs(rap());
0624     }
0625 
0626     /// Calculate the transverse momentum vector \f$ \vec{p}_T \f$.
0627     Vector3 pTvec() const {
0628       return p3().polarVec();
0629     }
0630     /// Synonym for pTvec
0631     Vector3 ptvec() const {
0632       return pTvec();
0633     }
0634 
0635     /// Calculate the squared transverse momentum \f$ p_T^2 \f$.
0636     double pT2() const {
0637       return vector3().polarRadius2();
0638     }
0639     /// Calculate the squared transverse momentum \f$ p_T^2 \f$.
0640     double pt2() const {
0641       return vector3().polarRadius2();
0642     }
0643 
0644     /// Calculate the transverse momentum \f$ p_T \f$.
0645     double pT() const {
0646       return sqrt(pT2());
0647     }
0648     /// Calculate the transverse momentum \f$ p_T \f$.
0649     double pt() const {
0650       return sqrt(pT2());
0651     }
0652 
0653     /// Calculate the transverse energy \f$ E_T^2 = E^2 \sin^2{\theta} \f$.
0654     double Et2() const {
0655       return Et() * Et();
0656     }
0657     /// Calculate the transverse energy \f$ E_T = E \sin{\theta} \f$.
0658     double Et() const {
0659       return E() * sin(polarAngle());
0660     }
0661 
0662     /// @}
0663 
0664 
0665     /// @name Lorentz boost factors and vectors
0666     /// @{
0667 
0668     /// Calculate the boost factor \f$ \gamma \f$.
0669     /// @note \f$ \gamma = E/mc^2 \f$ so we rely on the c=1 convention
0670     double gamma() const {
0671       return sqrt(E2()/mass2());
0672     }
0673 
0674     /// Calculate the boost vector \f$ \vec{\gamma} \f$.
0675     /// @note \f$ \gamma = E/mc^2 \f$ so we rely on the c=1 convention
0676     Vector3 gammaVec() const {
0677       return gamma() * p3().unit();
0678     }
0679 
0680     /// Calculate the boost factor \f$ \beta \f$.
0681     /// @note \f$ \beta = pc/E \f$ so we rely on the c=1 convention
0682     double beta() const {
0683       return p()/E();
0684     }
0685 
0686     /// Calculate the boost vector \f$ \vec{\beta} \f$.
0687     /// @note \f$ \beta = pc/E \f$ so we rely on the c=1 convention
0688     Vector3 betaVec() const {
0689       // return Vector3(px()/E(), py()/E(), pz()/E());
0690       return p3()/E();
0691     }
0692 
0693     /// @}
0694 
0695 
0696     ////////////////////////////////////////
0697 
0698     /// @name Arithmetic operators
0699     /// @{
0700 
0701     /// Multiply by a scalar
0702     FourMomentum& operator*=(double a) {
0703       _vec = multiply(a, *this)._vec;
0704       return *this;
0705     }
0706 
0707     /// Divide by a scalar
0708     FourMomentum& operator/=(double a) {
0709       _vec = multiply(1.0/a, *this)._vec;
0710       return *this;
0711     }
0712 
0713     /// Add to this 4-vector. NB time as well as space components are added.
0714     FourMomentum& operator+=(const FourMomentum& v) {
0715       _vec = add(*this, v)._vec;
0716       return *this;
0717     }
0718 
0719     /// Subtract from this 4-vector. NB time as well as space components are subtracted.
0720     FourMomentum& operator-=(const FourMomentum& v) {
0721       _vec = add(*this, -v)._vec;
0722       return *this;
0723     }
0724 
0725     /// Multiply all components (time and space) by -1.
0726     FourMomentum operator-() const {
0727       FourMomentum result;
0728       result._vec = -_vec;
0729       return result;
0730     }
0731 
0732     /// Multiply space components only by -1.
0733     FourMomentum reverse() const {
0734       FourMomentum result = -*this;
0735       result.setE(-result.E());
0736       return result;
0737     }
0738 
0739     /// @}
0740 
0741 
0742     ////////////////////////////////////////
0743 
0744 
0745     /// @name Factory functions
0746     /// @{
0747 
0748     /// Make a vector from (px,py,pz,E) coordinates
0749     static FourMomentum mkXYZE(double px, double py, double pz, double E) {
0750       return FourMomentum().setPE(px, py, pz, E);
0751     }
0752 
0753     /// Make a vector from (px,py,pz) coordinates and the mass
0754     static FourMomentum mkXYZM(double px, double py, double pz, double mass) {
0755       return FourMomentum().setPM(px, py, pz, mass);
0756     }
0757 
0758     /// Make a vector from (eta,phi,energy) coordinates and the mass
0759     static FourMomentum mkEtaPhiME(double eta, double phi, double mass, double E) {
0760       return FourMomentum().setEtaPhiME(eta, phi, mass, E);
0761     }
0762 
0763     /// Make a vector from (eta,phi,pT) coordinates and the mass
0764     static FourMomentum mkEtaPhiMPt(double eta, double phi, double mass, double pt) {
0765       return FourMomentum().setEtaPhiMPt(eta, phi, mass, pt);
0766     }
0767 
0768     /// Make a vector from (y,phi,energy) coordinates and the mass
0769     static FourMomentum mkRapPhiME(double y, double phi, double mass, double E) {
0770       return FourMomentum().setRapPhiME(y, phi, mass, E);
0771     }
0772 
0773     /// Make a vector from (y,phi,pT) coordinates and the mass
0774     static FourMomentum mkRapPhiMPt(double y, double phi, double mass, double pt) {
0775       return FourMomentum().setRapPhiMPt(y, phi, mass, pt);
0776     }
0777 
0778     /// Make a vector from (theta,phi,energy) coordinates and the mass
0779     static FourMomentum mkThetaPhiME(double theta, double phi, double mass, double E) {
0780       return FourMomentum().setThetaPhiME(theta, phi, mass, E);
0781     }
0782 
0783     /// Make a vector from (theta,phi,pT) coordinates and the mass
0784     static FourMomentum mkThetaPhiMPt(double theta, double phi, double mass, double pt) {
0785       return FourMomentum().setThetaPhiMPt(theta, phi, mass, pt);
0786     }
0787 
0788     /// Make a vector from (pT,phi,energy) coordinates and the mass
0789     static FourMomentum mkPtPhiME(double pt, double phi, double mass, double E) {
0790       return FourMomentum().setPtPhiME(pt, phi, mass, E);
0791     }
0792 
0793     /// @}
0794 
0795 
0796   };
0797 
0798 
0799   inline FourMomentum multiply(const double a, const FourMomentum& v) {
0800     FourMomentum result;
0801     result._vec = a * v._vec;
0802     return result;
0803   }
0804 
0805   inline FourMomentum multiply(const FourMomentum& v, const double a) {
0806     return multiply(a, v);
0807   }
0808 
0809   inline FourMomentum operator*(const double a, const FourMomentum& v) {
0810     return multiply(a, v);
0811   }
0812 
0813   inline FourMomentum operator*(const FourMomentum& v, const double a) {
0814     return multiply(a, v);
0815   }
0816 
0817   inline FourMomentum operator/(const FourMomentum& v, const double a) {
0818     return multiply(1.0/a, v);
0819   }
0820 
0821   inline FourMomentum add(const FourMomentum& a, const FourMomentum& b) {
0822     FourMomentum result;
0823     result._vec = a._vec + b._vec;
0824     return result;
0825   }
0826 
0827   inline FourMomentum operator+(const FourMomentum& a, const FourMomentum& b) {
0828     return add(a, b);
0829   }
0830 
0831   inline FourMomentum operator-(const FourMomentum& a, const FourMomentum& b) {
0832     return add(a, -b);
0833   }
0834 
0835 
0836   //////////////////////////////////////////////////////
0837 
0838 
0839   /// @name \f$ \Delta R \f$ calculations from 4-vectors
0840   /// @{
0841 
0842   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0843   ///
0844   /// There is a scheme ambiguity for momentum-type four vectors as to whether
0845   /// the pseudorapidity (a purely geometric concept) or the rapidity (a
0846   /// relativistic energy-momentum quantity) is to be used: this can be chosen
0847   /// via the optional scheme parameter. Use of this scheme option is
0848   /// discouraged in this case since @c RAPIDITY is only a valid option for
0849   /// vectors whose type is really the FourMomentum derived class.
0850   inline double deltaR2(const FourVector& a, const FourVector& b,
0851                        RapScheme scheme=PSEUDORAPIDITY) {
0852     switch (scheme) {
0853     case PSEUDORAPIDITY :
0854       return deltaR2(a.vector3(), b.vector3());
0855     case RAPIDITY:
0856       {
0857         const FourMomentum* ma = dynamic_cast<const FourMomentum*>(&a);
0858         const FourMomentum* mb = dynamic_cast<const FourMomentum*>(&b);
0859         if (!ma || !mb) {
0860           string err = "deltaR with scheme RAPIDITY can only be called with FourMomentum objects, not FourVectors";
0861           throw std::runtime_error(err);
0862         }
0863         return deltaR2(*ma, *mb, scheme);
0864       }
0865     default:
0866       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
0867     }
0868   }
0869 
0870   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0871   ///
0872   /// There is a scheme ambiguity for momentum-type four vectors as to whether
0873   /// the pseudorapidity (a purely geometric concept) or the rapidity (a
0874   /// relativistic energy-momentum quantity) is to be used: this can be chosen
0875   /// via the optional scheme parameter. Use of this scheme option is
0876   /// discouraged in this case since @c RAPIDITY is only a valid option for
0877   /// vectors whose type is really the FourMomentum derived class.
0878   inline double deltaR(const FourVector& a, const FourVector& b,
0879                        RapScheme scheme=PSEUDORAPIDITY) {
0880     return sqrt(deltaR2(a, b, scheme));
0881   }
0882 
0883 
0884 
0885   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0886   ///
0887   /// There is a scheme ambiguity for momentum-type four vectors
0888   /// as to whether the pseudorapidity (a purely geometric concept) or the
0889   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0890   /// be chosen via the optional scheme parameter.
0891   inline double deltaR2(const FourVector& v,
0892                        double eta2, double phi2,
0893                        RapScheme scheme=PSEUDORAPIDITY) {
0894     switch (scheme) {
0895     case PSEUDORAPIDITY :
0896       return deltaR2(v.vector3(), eta2, phi2);
0897     case RAPIDITY:
0898       {
0899         const FourMomentum* mv = dynamic_cast<const FourMomentum*>(&v);
0900         if (!mv) {
0901           string err = "deltaR with scheme RAPIDITY can only be called with FourMomentum objects, not FourVectors";
0902           throw std::runtime_error(err);
0903         }
0904         return deltaR2(*mv, eta2, phi2, scheme);
0905       }
0906     default:
0907       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
0908     }
0909   }
0910 
0911   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0912   ///
0913   /// There is a scheme ambiguity for momentum-type four vectors
0914   /// as to whether the pseudorapidity (a purely geometric concept) or the
0915   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0916   /// be chosen via the optional scheme parameter.
0917   inline double deltaR(const FourVector& v,
0918                        double eta2, double phi2,
0919                        RapScheme scheme=PSEUDORAPIDITY) {
0920     return sqrt(deltaR2(v, eta2, phi2, scheme));
0921   }
0922 
0923 
0924   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0925   ///
0926   /// There is a scheme ambiguity for momentum-type four vectors
0927   /// as to whether the pseudorapidity (a purely geometric concept) or the
0928   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0929   /// be chosen via the optional scheme parameter.
0930   inline double deltaR2(double eta1, double phi1,
0931                         const FourVector& v,
0932                         RapScheme scheme=PSEUDORAPIDITY) {
0933     switch (scheme) {
0934     case PSEUDORAPIDITY :
0935       return deltaR2(eta1, phi1, v.vector3());
0936     case RAPIDITY:
0937       {
0938         const FourMomentum* mv = dynamic_cast<const FourMomentum*>(&v);
0939         if (!mv) {
0940           string err = "deltaR with scheme RAPIDITY can only be called with FourMomentum objects, not FourVectors";
0941           throw std::runtime_error(err);
0942         }
0943         return deltaR2(eta1, phi1, *mv, scheme);
0944       }
0945     default:
0946       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
0947     }
0948   }
0949 
0950   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0951   ///
0952   /// There is a scheme ambiguity for momentum-type four vectors
0953   /// as to whether the pseudorapidity (a purely geometric concept) or the
0954   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0955   /// be chosen via the optional scheme parameter.
0956   inline double deltaR(double eta1, double phi1,
0957                        const FourVector& v,
0958                        RapScheme scheme=PSEUDORAPIDITY) {
0959     return sqrt(deltaR2(eta1, phi1, v, scheme));
0960   }
0961 
0962 
0963   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0964   ///
0965   /// There is a scheme ambiguity for momentum-type four vectors
0966   /// as to whether the pseudorapidity (a purely geometric concept) or the
0967   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0968   /// be chosen via the optional scheme parameter.
0969   inline double deltaR2(const FourMomentum& a, const FourMomentum& b,
0970                        RapScheme scheme=PSEUDORAPIDITY) {
0971     switch (scheme) {
0972     case PSEUDORAPIDITY:
0973       return deltaR2(a.vector3(), b.vector3());
0974     case RAPIDITY:
0975       return deltaR2(a.rapidity(), a.azimuthalAngle(), b.rapidity(), b.azimuthalAngle());
0976     default:
0977       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
0978     }
0979   }
0980 
0981   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0982   ///
0983   /// There is a scheme ambiguity for momentum-type four vectors
0984   /// as to whether the pseudorapidity (a purely geometric concept) or the
0985   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0986   /// be chosen via the optional scheme parameter.
0987   inline double deltaR(const FourMomentum& a, const FourMomentum& b,
0988                        RapScheme scheme=PSEUDORAPIDITY) {
0989     return sqrt(deltaR2(a, b, scheme));
0990   }
0991 
0992 
0993   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
0994   /// There is a scheme ambiguity for momentum-type four vectors
0995   /// as to whether the pseudorapidity (a purely geometric concept) or the
0996   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
0997   /// be chosen via the optional scheme parameter.
0998   inline double deltaR2(const FourMomentum& v,
0999                         double eta2, double phi2,
1000                         RapScheme scheme=PSEUDORAPIDITY) {
1001     switch (scheme) {
1002     case PSEUDORAPIDITY:
1003       return deltaR2(v.vector3(), eta2, phi2);
1004     case RAPIDITY:
1005       return deltaR2(v.rapidity(), v.azimuthalAngle(), eta2, phi2);
1006     default:
1007       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
1008     }
1009   }
1010 
1011   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1012   /// There is a scheme ambiguity for momentum-type four vectors
1013   /// as to whether the pseudorapidity (a purely geometric concept) or the
1014   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1015   /// be chosen via the optional scheme parameter.
1016   inline double deltaR(const FourMomentum& v,
1017                        double eta2, double phi2,
1018                        RapScheme scheme=PSEUDORAPIDITY) {
1019     return sqrt(deltaR2(v, eta2, phi2, scheme));
1020   }
1021 
1022 
1023   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1024   /// There is a scheme ambiguity for momentum-type four vectors
1025   /// as to whether the pseudorapidity (a purely geometric concept) or the
1026   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1027   /// be chosen via the optional scheme parameter.
1028   inline double deltaR2(double eta1, double phi1,
1029                         const FourMomentum& v,
1030                         RapScheme scheme=PSEUDORAPIDITY) {
1031     switch (scheme) {
1032     case PSEUDORAPIDITY:
1033       return deltaR2(eta1, phi1, v.vector3());
1034     case RAPIDITY:
1035       return deltaR2(eta1, phi1, v.rapidity(), v.azimuthalAngle());
1036     default:
1037       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
1038     }
1039   }
1040 
1041   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1042   /// There is a scheme ambiguity for momentum-type four vectors
1043   /// as to whether the pseudorapidity (a purely geometric concept) or the
1044   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1045   /// be chosen via the optional scheme parameter.
1046   inline double deltaR(double eta1, double phi1,
1047                         const FourMomentum& v,
1048                         RapScheme scheme=PSEUDORAPIDITY) {
1049     return sqrt(deltaR2(eta1, phi1, v, scheme));
1050   }
1051 
1052 
1053   /// @brief Calculate the squared 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1054   /// There is a scheme ambiguity for momentum-type four vectors
1055   /// as to whether the pseudorapidity (a purely geometric concept) or the
1056   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1057   /// be chosen via the optional scheme parameter.
1058   inline double deltaR2(const FourMomentum& a, const FourVector& b,
1059                         RapScheme scheme=PSEUDORAPIDITY) {
1060     switch (scheme) {
1061     case PSEUDORAPIDITY:
1062       return deltaR2(a.vector3(), b.vector3());
1063     case RAPIDITY:
1064       return deltaR2(a.rapidity(), a.azimuthalAngle(), FourMomentum(b).rapidity(), b.azimuthalAngle());
1065     default:
1066       throw std::runtime_error("The specified deltaR scheme is not yet implemented");
1067     }
1068   }
1069 
1070   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1071   /// There is a scheme ambiguity for momentum-type four vectors
1072   /// as to whether the pseudorapidity (a purely geometric concept) or the
1073   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1074   /// be chosen via the optional scheme parameter.
1075   inline double deltaR(const FourMomentum& a, const FourVector& b,
1076                        RapScheme scheme=PSEUDORAPIDITY) {
1077     return sqrt(deltaR2(a, b, scheme));
1078   }
1079 
1080 
1081   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1082   /// There is a scheme ambiguity for momentum-type four vectors
1083   /// as to whether the pseudorapidity (a purely geometric concept) or the
1084   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1085   /// be chosen via the optional scheme parameter.
1086   inline double deltaR2(const FourVector& a, const FourMomentum& b,
1087                         RapScheme scheme=PSEUDORAPIDITY) {
1088     return deltaR2(b, a, scheme); //< note reversed args
1089   }
1090 
1091   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two four-vectors.
1092   /// There is a scheme ambiguity for momentum-type four vectors
1093   /// as to whether the pseudorapidity (a purely geometric concept) or the
1094   /// rapidity (a relativistic energy-momentum quantity) is to be used: this can
1095   /// be chosen via the optional scheme parameter.
1096   inline double deltaR(const FourVector& a, const FourMomentum& b,
1097                        RapScheme scheme=PSEUDORAPIDITY) {
1098     return deltaR(b, a, scheme); //< note reversed args
1099   }
1100 
1101 
1102   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1103   /// three-vector and a four-vector.
1104   inline double deltaR2(const FourMomentum& a, const Vector3& b) {
1105     return deltaR2(a.vector3(), b);
1106   }
1107 
1108   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1109   /// three-vector and a four-vector.
1110   inline double deltaR(const FourMomentum& a, const Vector3& b) {
1111     return deltaR(a.vector3(), b);
1112   }
1113 
1114   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1115   /// three-vector and a four-vector.
1116   inline double deltaR2(const Vector3& a, const FourMomentum& b) {
1117     return deltaR2(a, b.vector3());
1118   }
1119 
1120   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1121   /// three-vector and a four-vector.
1122   inline double deltaR(const Vector3& a, const FourMomentum& b) {
1123     return deltaR(a, b.vector3());
1124   }
1125 
1126   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1127   /// three-vector and a four-vector.
1128   inline double deltaR2(const FourVector& a, const Vector3& b) {
1129     return deltaR2(a.vector3(), b);
1130   }
1131 
1132   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1133   /// three-vector and a four-vector.
1134   inline double deltaR(const FourVector& a, const Vector3& b) {
1135     return deltaR(a.vector3(), b);
1136   }
1137 
1138   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1139   /// three-vector and a four-vector.
1140   inline double deltaR2(const Vector3& a, const FourVector& b) {
1141     return deltaR2(a, b.vector3());
1142   }
1143 
1144   /// @brief Calculate the 2D rapidity-azimuthal ("eta-phi") distance between a
1145   /// three-vector and a four-vector.
1146   inline double deltaR(const Vector3& a, const FourVector& b) {
1147     return deltaR(a, b.vector3());
1148   }
1149 
1150   /// @}
1151 
1152 
1153   //////////////////////////////////////////////////////
1154 
1155 
1156   /// @name \f$ \Delta phi \f$ calculations from 4-vectors
1157   /// @{
1158 
1159   /// Calculate the difference in azimuthal angle between two vectors.
1160   inline double deltaPhi(const FourMomentum& a, const FourMomentum& b, bool sign=false) {
1161     return deltaPhi(a.vector3(), b.vector3(), sign);
1162   }
1163 
1164   /// Calculate the difference in azimuthal angle between two vectors.
1165   inline double deltaPhi(const FourMomentum& v, double phi2, bool sign=false) {
1166     return deltaPhi(v.vector3(), phi2, sign);
1167   }
1168 
1169   /// Calculate the difference in azimuthal angle between two vectors.
1170   inline double deltaPhi(double phi1, const FourMomentum& v, bool sign=false) {
1171     return deltaPhi(phi1, v.vector3(), sign);
1172   }
1173 
1174   /// Calculate the difference in azimuthal angle between two vectors.
1175   inline double deltaPhi(const FourVector& a, const FourVector& b, bool sign=false) {
1176     return deltaPhi(a.vector3(), b.vector3(), sign);
1177   }
1178 
1179   /// Calculate the difference in azimuthal angle between two vectors.
1180   inline double deltaPhi(const FourVector& v, double phi2, bool sign=false) {
1181     return deltaPhi(v.vector3(), phi2, sign);
1182   }
1183 
1184   /// Calculate the difference in azimuthal angle between two vectors.
1185   inline double deltaPhi(double phi1, const FourVector& v, bool sign=false) {
1186     return deltaPhi(phi1, v.vector3(), sign);
1187   }
1188 
1189   /// Calculate the difference in azimuthal angle between two vectors.
1190   inline double deltaPhi(const FourVector& a, const FourMomentum& b, bool sign=false) {
1191     return deltaPhi(a.vector3(), b.vector3(), sign);
1192   }
1193 
1194   /// Calculate the difference in azimuthal angle between two vectors.
1195   inline double deltaPhi(const FourMomentum& a, const FourVector& b, bool sign=false) {
1196     return deltaPhi(a.vector3(), b.vector3(), sign);
1197   }
1198 
1199   /// Calculate the difference in azimuthal angle between two vectors.
1200   inline double deltaPhi(const FourVector& a, const Vector3& b, bool sign=false) {
1201     return deltaPhi(a.vector3(), b, sign);
1202   }
1203 
1204   /// Calculate the difference in azimuthal angle between two vectors.
1205   inline double deltaPhi(const Vector3& a, const FourVector& b, bool sign=false) {
1206     return deltaPhi(a, b.vector3(), sign);
1207   }
1208 
1209   /// Calculate the difference in azimuthal angle between two vectors.
1210   inline double deltaPhi(const FourMomentum& a, const Vector3& b, bool sign=false) {
1211     return deltaPhi(a.vector3(), b, sign);
1212   }
1213 
1214   /// Calculate the difference in azimuthal angle between two vectors.
1215   inline double deltaPhi(const Vector3& a, const FourMomentum& b, bool sign=false) {
1216     return deltaPhi(a, b.vector3(), sign);
1217   }
1218 
1219   /// @}
1220 
1221 
1222   //////////////////////////////////////////////////////
1223 
1224 
1225   /// @name \f$ |\Delta eta| \f$ calculations from 4-vectors
1226   /// @{
1227 
1228   /// Calculate the difference in pseudorapidity between two vectors.
1229   inline double deltaEta(const FourMomentum& a, const FourMomentum& b, bool sign=false) {
1230     return deltaEta(a.vector3(), b.vector3(), sign);
1231   }
1232 
1233   /// Calculate the difference in pseudorapidity between two vectors.
1234   inline double deltaEta(const FourMomentum& v, double eta2, bool sign=false) {
1235     return deltaEta(v.vector3(), eta2, sign);
1236   }
1237 
1238   /// Calculate the difference in pseudorapidity between two vectors.
1239   inline double deltaEta(double eta1, const FourMomentum& v, bool sign=false) {
1240     return deltaEta(eta1, v.vector3(), sign);
1241   }
1242 
1243   /// Calculate the difference in pseudorapidity between two vectors.
1244   inline double deltaEta(const FourVector& a, const FourVector& b, bool sign=false) {
1245     return deltaEta(a.vector3(), b.vector3(), sign);
1246   }
1247 
1248   /// Calculate the difference in pseudorapidity between two vectors.
1249   inline double deltaEta(const FourVector& v, double eta2, bool sign=false) {
1250     return deltaEta(v.vector3(), eta2, sign);
1251   }
1252 
1253   /// Calculate the difference in pseudorapidity between two vectors.
1254   inline double deltaEta(double eta1, const FourVector& v, bool sign=false) {
1255     return deltaEta(eta1, v.vector3(), sign);
1256   }
1257 
1258   /// Calculate the difference in pseudorapidity between two vectors.
1259   inline double deltaEta(const FourVector& a, const FourMomentum& b, bool sign=false) {
1260     return deltaEta(a.vector3(), b.vector3(), sign);
1261   }
1262 
1263   /// Calculate the difference in pseudorapidity between two vectors.
1264   inline double deltaEta(const FourMomentum& a, const FourVector& b, bool sign=false) {
1265     return deltaEta(a.vector3(), b.vector3(), sign);
1266   }
1267 
1268   /// Calculate the difference in pseudorapidity between two vectors.
1269   inline double deltaEta(const FourVector& a, const Vector3& b, bool sign=false) {
1270     return deltaEta(a.vector3(), b, sign);
1271   }
1272 
1273   /// Calculate the difference in pseudorapidity between two vectors.
1274   inline double deltaEta(const Vector3& a, const FourVector& b, bool sign=false) {
1275     return deltaEta(a, b.vector3(), sign);
1276   }
1277 
1278   /// Calculate the difference in pseudorapidity between two vectors.
1279   inline double deltaEta(const FourMomentum& a, const Vector3& b, bool sign=false) {
1280     return deltaEta(a.vector3(), b, sign);
1281   }
1282 
1283   /// Calculate the difference in pseudorapidity between two vectors.
1284   inline double deltaEta(const Vector3& a, const FourMomentum& b, bool sign=false) {
1285     return deltaEta(a, b.vector3(), sign);
1286   }
1287 
1288   /// @}
1289 
1290 
1291   /// @name \f$ |\Delta y| \f$ calculations from 4-momentum vectors
1292   /// @{
1293 
1294   /// Calculate the difference in rapidity between two 4-momentum vectors.
1295   inline double deltaRap(const FourMomentum& a, const FourMomentum& b, bool sign=false) {
1296     return deltaRap(a.rapidity(), b.rapidity(), sign);
1297   }
1298 
1299   /// Calculate the difference in rapidity between two 4-momentum vectors.
1300   inline double deltaRap(const FourMomentum& v, double y2, bool sign=false) {
1301     return deltaRap(v.rapidity(), y2, sign);
1302   }
1303 
1304   /// Calculate the difference in rapidity between two 4-momentum vectors.
1305   inline double deltaRap(double y1, const FourMomentum& v, bool sign=false) {
1306     return deltaRap(y1, v.rapidity(), sign);
1307   }
1308 
1309   /// @}
1310 
1311 
1312   //////////////////////////////////////////////////////
1313 
1314 
1315   /// @defgroup momutils Functions for 4-momenta
1316   /// @{
1317 
1318   /// @defgroup momutils_cmp 4-vector comparison functions (for sorting)
1319   /// @{
1320 
1321   /// Comparison to give a sorting by decreasing pT
1322   inline bool cmpMomByPt(const FourMomentum& a, const FourMomentum& b) {
1323     return a.pt() > b.pt();
1324   }
1325   /// Comparison to give a sorting by increasing pT
1326   inline bool cmpMomByAscPt(const FourMomentum& a, const FourMomentum& b) {
1327     return a.pt() < b.pt();
1328   }
1329 
1330   /// Comparison to give a sorting by decreasing 3-momentum magnitude |p|
1331   inline bool cmpMomByP(const FourMomentum& a, const FourMomentum& b) {
1332     return a.vector3().mod() > b.vector3().mod();
1333   }
1334   /// Comparison to give a sorting by increasing 3-momentum magnitude |p|
1335   inline bool cmpMomByAscP(const FourMomentum& a, const FourMomentum& b) {
1336     return a.vector3().mod() < b.vector3().mod();
1337   }
1338 
1339   /// Comparison to give a sorting by decreasing transverse energy
1340   inline bool cmpMomByEt(const FourMomentum& a, const FourMomentum& b) {
1341     return a.Et() > b.Et();
1342   }
1343   /// Comparison to give a sorting by increasing transverse energy
1344   inline bool cmpMomByAscEt(const FourMomentum& a, const FourMomentum& b) {
1345     return a.Et() < b.Et();
1346   }
1347 
1348   /// Comparison to give a sorting by decreasing energy
1349   inline bool cmpMomByE(const FourMomentum& a, const FourMomentum& b) {
1350     return a.E() > b.E();
1351   }
1352   /// Comparison to give a sorting by increasing energy
1353   inline bool cmpMomByAscE(const FourMomentum& a, const FourMomentum& b) {
1354     return a.E() < b.E();
1355   }
1356 
1357   /// Comparison to give a sorting by decreasing mass
1358   inline bool cmpMomByMass(const FourMomentum& a, const FourMomentum& b) {
1359     return a.mass() > b.mass();
1360   }
1361   /// Comparison to give a sorting by increasing mass
1362   inline bool cmpMomByAscMass(const FourMomentum& a, const FourMomentum& b) {
1363     return a.mass() < b.mass();
1364   }
1365 
1366   /// Comparison to give a sorting by increasing eta (pseudorapidity)
1367   inline bool cmpMomByEta(const FourMomentum& a, const FourMomentum& b) {
1368     return a.eta() < b.eta();
1369   }
1370 
1371   /// Comparison to give a sorting by decreasing eta (pseudorapidity)
1372   inline bool cmpMomByDescEta(const FourMomentum& a, const FourMomentum& b) {
1373     return a.pseudorapidity() > b.pseudorapidity();
1374   }
1375 
1376   /// Comparison to give a sorting by increasing absolute eta (pseudorapidity)
1377   inline bool cmpMomByAbsEta(const FourMomentum& a, const FourMomentum& b) {
1378     return fabs(a.eta()) < fabs(b.eta());
1379   }
1380 
1381   /// Comparison to give a sorting by increasing absolute eta (pseudorapidity)
1382   inline bool cmpMomByDescAbsEta(const FourMomentum& a, const FourMomentum& b) {
1383     return fabs(a.eta()) > fabs(b.eta());
1384   }
1385 
1386   /// Comparison to give a sorting by increasing rapidity
1387   inline bool cmpMomByRap(const FourMomentum& a, const FourMomentum& b) {
1388     return a.rapidity() < b.rapidity();
1389   }
1390 
1391   /// Comparison to give a sorting by decreasing rapidity
1392   inline bool cmpMomByDescRap(const FourMomentum& a, const FourMomentum& b) {
1393     return a.rapidity() > b.rapidity();
1394   }
1395 
1396   /// Comparison to give a sorting by increasing absolute rapidity
1397   inline bool cmpMomByAbsRap(const FourMomentum& a, const FourMomentum& b) {
1398     return fabs(a.rapidity()) < fabs(b.rapidity());
1399   }
1400 
1401   /// Comparison to give a sorting by decreasing absolute rapidity
1402   inline bool cmpMomByDescAbsRap(const FourMomentum& a, const FourMomentum& b) {
1403     return fabs(a.rapidity()) > fabs(b.rapidity());
1404   }
1405 
1406   /// @todo Add sorting by phi [0..2PI]
1407 
1408 
1409   /// Sort a container of momenta by cmp and return by reference for non-const inputs
1410   template<typename MOMS, typename CMP>
1411   inline MOMS& isortBy(MOMS& pbs, const CMP& cmp) {
1412     std::sort(pbs.begin(), pbs.end(), cmp);
1413     return pbs;
1414   }
1415   /// Sort a container of momenta by cmp and return by value for const inputs
1416   template<typename MOMS, typename CMP>
1417   inline MOMS sortBy(const MOMS& pbs, const CMP& cmp) {
1418     MOMS rtn = pbs;
1419     std::sort(rtn.begin(), rtn.end(), cmp);
1420     return rtn;
1421   }
1422 
1423   /// Sort a container of momenta by pT (decreasing) and return by reference for non-const inputs
1424   template<typename MOMS>
1425   inline MOMS& isortByPt(MOMS& pbs) {
1426     return isortBy(pbs, cmpMomByPt);
1427   }
1428   /// Sort a container of momenta by pT (decreasing) and return by value for const inputs
1429   template<typename MOMS>
1430   inline MOMS sortByPt(const MOMS& pbs) {
1431     return sortBy(pbs, cmpMomByPt);
1432   }
1433 
1434   /// Sort a container of momenta by E (decreasing) and return by reference for non-const inputs
1435   template<typename MOMS>
1436   inline MOMS& isortByE(MOMS& pbs) {
1437     return isortBy(pbs, cmpMomByE);
1438   }
1439   /// Sort a container of momenta by E (decreasing) and return by value for const inputs
1440   template<typename MOMS>
1441   inline MOMS sortByE(const MOMS& pbs) {
1442     return sortBy(pbs, cmpMomByE);
1443   }
1444 
1445   /// Sort a container of momenta by Et (decreasing) and return by reference for non-const inputs
1446   template<typename MOMS>
1447   inline MOMS& isortByEt(MOMS& pbs) {
1448     return isortBy(pbs, cmpMomByEt);
1449   }
1450   /// Sort a container of momenta by Et (decreasing) and return by value for const inputs
1451   template<typename MOMS>
1452   inline MOMS sortByEt(const MOMS& pbs) {
1453     return sortBy(pbs, cmpMomByEt);
1454   }
1455 
1456   /// @}
1457 
1458 
1459   /// @defgroup momutils_mt Mass and MT calculations
1460   /// @{
1461 
1462   /// Calculate mass of two 4-vectors
1463   inline double mass(const FourMomentum& a, const FourMomentum& b) {
1464     return (a + b).mass();
1465   }
1466 
1467   /// Calculate mass^2 of two 4-vectors
1468   inline double mass2(const FourMomentum& a, const FourMomentum& b) {
1469     return (a + b).mass2();
1470   }
1471 
1472   /// Calculate transverse mass of a visible and an invisible 4-vector
1473   ///
1474   /// @note This is implemented in terms of massless 3-vectors,
1475   /// ignoring actual masses in the 4-vectors.
1476   inline double mT(const FourMomentum& vis, const FourMomentum& invis) {
1477     return mT(vis.p3(), invis.p3());
1478   }
1479 
1480   /// Calculate transverse mass of a visible 4-vector and an invisible 3-vector
1481   ///
1482   /// @note This is implemented in terms of massless 3-vectors,
1483   /// ignoring actual masses in the 4-vectors.
1484   inline double mT(const FourMomentum& vis, const Vector3& invis) {
1485     return mT(vis.p3(), invis);
1486   }
1487 
1488   /// Calculate transverse mass of a visible 4-vector and an invisible 3-vector
1489   ///
1490   /// @note This is implemented in terms of massless 3-vectors,
1491   /// ignoring actual masses in the 4-vectors.
1492   inline double mT(const Vector3& vis, const FourMomentum& invis) {
1493     return mT(vis, invis.p3());
1494   }
1495 
1496   /// Calculate transverse momentum of two 4-vectors
1497   inline double pT(const FourMomentum& vis, const FourMomentum& invis) {
1498     return pT(vis.p3(), invis.p3());
1499   }
1500 
1501   /// Calculate transverse momentum of a 4-vector and a 3-vector
1502   inline double pT(const FourMomentum& vis, const Vector3& invis) {
1503     return pT(vis.p3(), invis);
1504   }
1505 
1506   /// Calculate transverse momentum of a 4-vector and a 3-vector
1507   inline double pT(const Vector3& vis, const FourMomentum& invis) {
1508     return pT(vis, invis.p3());
1509   }
1510 
1511   /// @}
1512 
1513 
1514   //////////////////////////////////////////////////////
1515 
1516 
1517   /// @defgroup momutils_str 4-vector string representations
1518   /// @{
1519 
1520   /// Render a 4-vector as a string.
1521   inline std::string toString(const FourVector& lv) {
1522     std::ostringstream out;
1523     out << "("  << (fabs(lv.t()) < 1E-30 ? 0.0 : lv.t())
1524         << "; " << (fabs(lv.x()) < 1E-30 ? 0.0 : lv.x())
1525         << ", " << (fabs(lv.y()) < 1E-30 ? 0.0 : lv.y())
1526         << ", " << (fabs(lv.z()) < 1E-30 ? 0.0 : lv.z())
1527         << ")";
1528     return out.str();
1529   }
1530 
1531   /// Write a 4-vector to an ostream.
1532   inline std::ostream& operator<<(std::ostream& out, const FourVector& lv) {
1533     out << toString(lv);
1534     return out;
1535   }
1536 
1537   /// @}
1538 
1539   /// Typedefs for lists of vector types
1540   /// @{
1541   typedef std::vector<FourVector> FourVectors;
1542   typedef std::vector<FourMomentum> FourMomenta;
1543   /// @}
1544 
1545   /// @}
1546 
1547 
1548 }
1549 
1550 #endif