Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/Rivet/Math/Vector4.hh was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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