File indexing completed on 2026-08-06 09:38:33
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef ThePEG_LorentzVector_H
0010 #define ThePEG_LorentzVector_H
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include "LorentzVector.fh"
0020 #include "ThePEG/Utilities/Direction.h"
0021 #include "ThePEG/Utilities/UnitIO.h"
0022 #include "LorentzRotation.h"
0023 #include "ThreeVector.h"
0024
0025
0026 #ifdef NDEBUG
0027 #define ERROR_IF(condition,message) if (false) {}
0028 #else
0029 #define ERROR_IF(condition,message) \
0030 if ( condition ) throw ThePEG::Exception( (message) , ThePEG::Exception::eventerror)
0031 #endif
0032
0033 namespace ThePEG {
0034
0035 template <typename Value> class LorentzVector;
0036
0037
0038
0039
0040
0041
0042
0043 template <typename Value> class LorentzVector
0044 {
0045 private:
0046
0047 using Value2 = decltype(sqr(std::declval<Value>()));
0048
0049 public:
0050
0051
0052 LorentzVector()
0053 : theX(), theY(), theZ(), theT() {}
0054
0055 LorentzVector(Value x, Value y, Value z, Value t)
0056 : theX(x), theY(y), theZ(z), theT(t) {}
0057
0058 LorentzVector(const ThreeVector<Value> & v, Value t)
0059 : theX(v.x()), theY(v.y()), theZ(v.z()), theT(t) {}
0060
0061 template<typename U>
0062 LorentzVector(const LorentzVector<U> & v)
0063 : theX(v.x()), theY(v.y()), theZ(v.z()), theT(v.t()) {}
0064
0065
0066
0067 template <typename ValueB>
0068 LorentzVector<Value> & operator=(const LorentzVector<ValueB> & b) {
0069 setX(b.x());
0070 setY(b.y());
0071 setZ(b.z());
0072 setT(b.t());
0073 return *this;
0074 }
0075
0076 public:
0077
0078
0079 Value x() const { return theX; }
0080 Value y() const { return theY; }
0081 Value z() const { return theZ; }
0082 Value t() const { return theT; }
0083 Value e() const { return t(); }
0084
0085
0086
0087
0088 void setX(Value x) { theX = x; }
0089 void setY(Value y) { theY = y; }
0090 void setZ(Value z) { theZ = z; }
0091 void setT(Value t) { theT = t; }
0092 void setE(Value e) { setT(e); }
0093
0094
0095 public:
0096
0097 ThreeVector<Value> vect() const {
0098 return ThreeVector<Value>(x(),y(),z());
0099 }
0100
0101
0102 operator ThreeVector<Value>() const { return vect(); }
0103
0104
0105 void setVect(const ThreeVector<Value> & p) {
0106 theX = p.x();
0107 theY = p.y();
0108 theZ = p.z();
0109 }
0110
0111 public:
0112
0113 LorentzVector<Value> conjugate() const
0114 {
0115 return LorentzVector<Value>(conj(x()),conj(y()),conj(z()),conj(t()));
0116 }
0117
0118
0119 Value2 m2() const
0120 {
0121 return (t()-z())*(t()+z()) - sqr(x()) - sqr(y());
0122 }
0123
0124
0125 Value2 m2(const LorentzVector<Value> & a) const {
0126 Value tt(a.t()+t()),zz(a.z()+z());
0127 return (tt-zz)*(tt+zz)-sqr(a.x()+x())-sqr(a.y()+y());
0128 }
0129
0130
0131 Value m() const
0132 {
0133 Value2 tmp = m2();
0134 return tmp < Value2() ? -Value(sqrt(-tmp)) : Value(sqrt(tmp));
0135 }
0136
0137
0138 Value2 mt2() const { return (t()-z())*(t()+z()); }
0139
0140
0141 Value mt() const
0142 {
0143 Value2 tmp = mt2();
0144 return tmp < Value2() ? -Value(sqrt(-tmp)) : Value(sqrt(tmp));
0145 }
0146
0147
0148 Value2 perp2() const { return sqr(x()) + sqr(y()); }
0149
0150
0151 Value perp() const { return sqrt(perp2()); }
0152
0153
0154
0155
0156
0157 template <typename U>
0158 Value2 perp2(const ThreeVector<U> & p) const
0159 {
0160 return vect().perp2(p);
0161 }
0162
0163
0164
0165
0166
0167 template <typename U>
0168 Value perp(const ThreeVector<U> & p) const
0169 {
0170 return vect().perp(p);
0171 }
0172
0173
0174 Value2 et2() const
0175 {
0176 Value2 pt2 = vect().perp2();
0177 return pt2 == Value2() ? Value2() : e()*e() * pt2/(pt2+z()*z());
0178 }
0179
0180
0181 Value et() const
0182 {
0183 Value2 etet = et2();
0184 return e() < Value() ? -sqrt(etet) : sqrt(etet);
0185 }
0186
0187
0188 Value2 et2(const ThreeVector<double> & v) const
0189 {
0190 Value2 pt2 = vect().perp2(v);
0191 Value pv = vect().dot(v.unit());
0192 return pt2 == Value2() ? Value2() : e()*e() * pt2/(pt2+pv*pv);
0193 }
0194
0195
0196 Value et(const ThreeVector<double> & v) const
0197 {
0198 Value2 etet = et2(v);
0199 return e() < Value() ? -sqrt(etet) : sqrt(etet);
0200 }
0201
0202
0203
0204
0205 Value2 rho2() const { return sqr(x()) + sqr(y()) + sqr(z()); }
0206
0207
0208 Value rho() const { return sqrt(rho2()); }
0209
0210
0211 void setRho(Value newRho)
0212 {
0213 Value oldRho = rho();
0214 if (oldRho == Value())
0215 return;
0216 double factor = newRho / oldRho;
0217 setX(x()*factor);
0218 setY(y()*factor);
0219 setZ(z()*factor);
0220 }
0221
0222
0223 double theta() const
0224 {
0225 assert(!(x() == Value() && y() == Value() && z() == Value()));
0226 return atan2(perp(),z());
0227 }
0228
0229
0230 double cosTheta() const
0231 {
0232 Value ptot = rho();
0233 assert( ptot > Value() );
0234 return z() / ptot;
0235 }
0236
0237
0238 double phi() const {
0239 return atan2(y(),x()) ;
0240 }
0241
0242
0243
0244 double eta() const {
0245 Value m = rho();
0246 if ( m == Value() ) return 0.0;
0247 Value pt = max(Constants::epsilon*m, perp());
0248 double rap = log((m + abs(z()))/pt);
0249 return z() > ZERO? rap: -rap;
0250 }
0251
0252
0253 double angle(const LorentzVector<Value> & w) const
0254 {
0255 return vect().angle(w.vect());
0256 }
0257
0258
0259 double rapidity() const {
0260 if ( z() == ZERO ) return 0.0;
0261 ERROR_IF(t() <= ZERO, "Tried to take rapidity of negative-energy Lorentz vector");
0262 Value pt = sqrt(max(sqr(t()*Constants::epsilon), perp2() + m2()));
0263 double rap = log((t() + abs(z()))/pt);
0264 return z() > ZERO? rap: -rap;
0265 }
0266
0267
0268 double rapidity(const Axis & ref) const {
0269 double r = ref.mag2();
0270 ERROR_IF(r == 0,"A zero vector used as reference to LorentzVector rapidity");
0271 Value vdotu = vect().dot(ref)/sqrt(r);
0272 if ( vdotu == ZERO ) return 0.0;
0273 ERROR_IF(t() <= ZERO, "Tried to take rapidity of negative-energy Lorentz vector");
0274 Value pt = sqrt(max(sqr(t()*Constants::epsilon), perp2(ref) + m2()));
0275 double rap = log((t() + abs(z()))/pt);
0276 return z() > ZERO? rap: -rap;
0277 }
0278
0279
0280
0281
0282
0283 Boost boostVector() const {
0284 if (t() == Value()) {
0285 if (rho2() == Value2())
0286 return Boost();
0287 else
0288 ERROR_IF(true,"boostVector computed for LorentzVector with t=0 -- infinite result");
0289 }
0290
0291 ERROR_IF(m2() <= Value2(),"boostVector computed for a non-timelike LorentzVector");
0292 return vect() * (1./t());
0293 }
0294
0295
0296
0297
0298
0299 Boost findBoostToCM() const
0300 {
0301 return -boostVector();
0302 }
0303
0304
0305 Value plus() const { return t() + z(); }
0306
0307 Value minus() const { return t() - z(); }
0308
0309
0310 bool isNear(const LorentzVector<Value> & w, double epsilon) const
0311 {
0312 Value2 limit = abs(vect().dot(w.vect()));
0313 limit += 0.25 * sqr( t() + w.t() );
0314 limit *= sqr(epsilon);
0315 Value2 delta = (vect() - w.vect()).mag2();
0316 delta += sqr( t() - w.t() );
0317 return (delta <= limit);
0318 }
0319
0320
0321 LorentzVector<Value> & transform(const SpinOneLorentzRotation & m)
0322 {
0323 return *this = m.operator*(*this);
0324 }
0325
0326
0327 LorentzVector<Value> & operator*=(const SpinOneLorentzRotation & m)
0328 {
0329 return transform(m);
0330 }
0331
0332
0333 template <typename U>
0334 auto dot(const LorentzVector<U> & a) const -> decltype(this->t() * a.t())
0335 {
0336 return t() * a.t() - ( x() * a.x() + y() * a.y() + z() * a.z() );
0337 }
0338
0339
0340 public:
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 LorentzVector<Value> &
0354 boost(double bx, double by, double bz, double gamma=-1.)
0355 {
0356 const double b2 = bx*bx + by*by + bz*bz;
0357 if ( b2 == 0.0 ) return *this;
0358 if ( gamma < 0.0 ) {
0359 gamma = 1.0 / sqrt(1.0 - b2);
0360 }
0361 const Value bp = bx*x() + by*y() + bz*z();
0362 const double gamma2 = (gamma - 1.0)/b2;
0363
0364 setX(x() + gamma2*bp*bx + gamma*bx*t());
0365 setY(y() + gamma2*bp*by + gamma*by*t());
0366 setZ(z() + gamma2*bp*bz + gamma*bz*t());
0367 setT(gamma*(t() + bp));
0368 return *this;
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 LorentzVector<Value> & boost(Boost b, double gamma=-1.) {
0382 return boost(b.x(), b.y(), b.z(),gamma);
0383 }
0384
0385
0386
0387
0388
0389
0390 LorentzVector<Value> & rotateX (double phi) {
0391 double sinphi = sin(phi);
0392 double cosphi = cos(phi);
0393 Value ty = y() * cosphi - z() * sinphi;
0394 theZ = z() * cosphi + y() * sinphi;
0395 theY = ty;
0396 return *this;
0397 }
0398
0399
0400
0401
0402
0403
0404 LorentzVector<Value> & rotateY (double phi) {
0405 double sinphi = sin(phi);
0406 double cosphi = cos(phi);
0407 Value tz = z() * cosphi - x() * sinphi;
0408 theX = x() * cosphi + z() * sinphi;
0409 theZ = tz;
0410 return *this;
0411 }
0412
0413
0414
0415
0416
0417
0418 LorentzVector<Value> & rotateZ (double phi) {
0419 double sinphi = sin(phi);
0420 double cosphi = cos(phi);
0421 Value tx = x() * cosphi - y() * sinphi;
0422 theY = y() * cosphi + x() * sinphi;
0423 theX = tx;
0424 return *this;
0425 }
0426
0427
0428
0429
0430 LorentzVector<Value> & rotateUz (const Axis & axis) {
0431 Axis ax = axis.unit();
0432 double u1 = ax.x();
0433 double u2 = ax.y();
0434 double u3 = ax.z();
0435 double up = u1*u1 + u2*u2;
0436 if (up>0) {
0437 up = sqrt(up);
0438 Value px = x(), py = y(), pz = z();
0439 setX( (u1*u3*px - u2*py)/up + u1*pz );
0440 setY( (u2*u3*px + u1*py)/up + u2*pz );
0441 setZ( -up*px + u3*pz );
0442 }
0443 else if (u3 < 0.) {
0444 setX(-x());
0445 setZ(-z());
0446 }
0447 return *this;
0448 }
0449
0450
0451
0452
0453
0454
0455 template <typename U>
0456 LorentzVector<Value> & rotate(double angle, const ThreeVector<U> & axis) {
0457 if (angle == 0.0)
0458 return *this;
0459 const U ll = axis.mag();
0460 assert( ll > U() );
0461
0462 const double sa = sin(angle), ca = cos(angle);
0463 const double dx = axis.x()/ll, dy = axis.y()/ll, dz = axis.z()/ll;
0464 const Value xx = x(), yy = y(), zz = z();
0465
0466 setX((ca+(1-ca)*dx*dx) * xx
0467 +((1-ca)*dx*dy-sa*dz) * yy
0468 +((1-ca)*dx*dz+sa*dy) * zz
0469 );
0470 setY(((1-ca)*dy*dx+sa*dz) * xx
0471 +(ca+(1-ca)*dy*dy) * yy
0472 +((1-ca)*dy*dz-sa*dx) * zz
0473 );
0474 setZ(((1-ca)*dz*dx-sa*dy) * xx
0475 +((1-ca)*dz*dy+sa*dx) * yy
0476 +(ca+(1-ca)*dz*dz) * zz
0477 );
0478 return *this;
0479 }
0480
0481
0482
0483
0484 public:
0485
0486
0487 LorentzVector<Complex> & operator+=(const LorentzVector<complex<QtyDouble> > & a) {
0488 theX += a.x();
0489 theY += a.y();
0490 theZ += a.z();
0491 theT += a.t();
0492 return *this;
0493 }
0494
0495 template <typename ValueB>
0496 LorentzVector<Value> & operator+=(const LorentzVector<ValueB> & a) {
0497 theX += a.x();
0498 theY += a.y();
0499 theZ += a.z();
0500 theT += a.t();
0501 return *this;
0502 }
0503
0504 LorentzVector<Complex> & operator-=(const LorentzVector<complex<QtyDouble> > & a) {
0505 theX -= Complex(a.x());
0506 theY -= Complex(a.y());
0507 theZ -= Complex(a.z());
0508 theT -= Complex(a.t());
0509 return *this;
0510 }
0511
0512 template <typename ValueB>
0513 LorentzVector<Value> & operator-=(const LorentzVector<ValueB> & a) {
0514 theX -= a.x();
0515 theY -= a.y();
0516 theZ -= a.z();
0517 theT -= a.t();
0518 return *this;
0519 }
0520
0521 LorentzVector<Value> & operator*=(double a) {
0522 theX *= a;
0523 theY *= a;
0524 theZ *= a;
0525 theT *= a;
0526 return *this;
0527 }
0528
0529 LorentzVector<Value> & operator/=(double a) {
0530 theX /= a;
0531 theY /= a;
0532 theZ /= a;
0533 theT /= a;
0534 return *this;
0535 }
0536
0537
0538 private:
0539
0540
0541 Value theX;
0542 Value theY;
0543 Value theZ;
0544 Value theT;
0545
0546 };
0547
0548
0549
0550 template <typename Value>
0551 inline LorentzVector<double>
0552 operator/(const LorentzVector<Value> & v, Value a) {
0553 return LorentzVector<double>(v.x()/a, v.y()/a, v.z()/a, v.t()/a);
0554 }
0555
0556 inline LorentzVector<Complex>
0557 operator/(const LorentzVector<Complex> & v, Complex a) {
0558 return LorentzVector<Complex>(v.x()/a, v.y()/a, v.z()/a, v.t()/a);
0559 }
0560
0561 template <typename Value>
0562 inline LorentzVector<Value> operator-(const LorentzVector<Value> & v) {
0563 return LorentzVector<Value>(-v.x(),-v.y(),-v.z(),-v.t());
0564 }
0565
0566 template <typename ValueA, typename ValueB>
0567 inline LorentzVector<ValueA>
0568 operator+(LorentzVector<ValueA> a, const LorentzVector<ValueB> & b) {
0569 return a += b;
0570 }
0571
0572 template <typename ValueA, typename ValueB>
0573 inline LorentzVector<ValueA>
0574 operator-(LorentzVector<ValueA> a, const LorentzVector<ValueB> & b) {
0575 return a -= b;
0576 }
0577
0578 template <typename Value>
0579 inline LorentzVector<Value>
0580 operator*(const LorentzVector<Value> & a, double b) {
0581 return LorentzVector<Value>(a.x()*b, a.y()*b, a.z()*b, a.t()*b);
0582 }
0583
0584 template <typename Value>
0585 inline LorentzVector<Value>
0586 operator*(double b, LorentzVector<Value> a) {
0587 return a *= b;
0588 }
0589
0590 template <typename ValueA, typename ValueB>
0591 inline auto operator*(ValueB a, const LorentzVector<ValueA> & v)
0592 -> LorentzVector<decltype(a*v.x())>
0593 {
0594 return {a*v.x(), a*v.y(), a*v.z(), a*v.t()};
0595 }
0596
0597 template <typename ValueA, typename ValueB>
0598 inline auto operator*(const LorentzVector<ValueA> & v, ValueB b)
0599 -> LorentzVector<decltype(b*v.x())>
0600 {
0601 return b*v;
0602 }
0603
0604 template <typename ValueA, typename ValueB>
0605 inline auto operator/(const LorentzVector<ValueA> & v, ValueB b)
0606 -> LorentzVector<decltype(v.x()/b)>
0607 {
0608 return {v.x()/b, v.y()/b, v.z()/b, v.t()/b};
0609 }
0610
0611
0612
0613
0614 template <typename ValueA, typename ValueB>
0615 inline auto
0616 operator*(const LorentzVector<ValueA> & a, const LorentzVector<ValueB> & b)
0617 -> decltype(a.dot(b))
0618 {
0619 return a.dot(b);
0620 }
0621
0622
0623
0624
0625 template <typename Value>
0626 inline bool
0627 operator==(const LorentzVector<Value> & a, const LorentzVector<Value> & b) {
0628 return a.x() == b.x() && a.y() == b.y() && a.z() == b.z() && a.t() == b.t();
0629 }
0630
0631
0632 inline ostream & operator<< (ostream & os, const LorentzVector<double> & v) {
0633 return os << "(" << v.x() << "," << v.y() << "," << v.z()
0634 << ";" << v.t() << ")";
0635 }
0636
0637
0638
0639 template <typename Value>
0640 inline Value dirPlus(const LorentzVector<Value> & p) {
0641 return Direction<0>::pos()? p.plus(): p.minus();
0642 }
0643
0644
0645
0646 template <typename Value>
0647 inline Value dirMinus(const LorentzVector<Value> & p) {
0648 return Direction<0>::neg()? p.plus(): p.minus();
0649 }
0650
0651
0652
0653 template <typename Value>
0654 inline Value dirZ(const LorentzVector<Value> & p) {
0655 return Direction<0>::dir()*p.z();
0656 }
0657
0658
0659
0660 template <typename Value>
0661 inline double dirTheta(const LorentzVector<Value> & p) {
0662 return Direction<0>::pos()? p.theta(): Constants::pi - p.theta();
0663 }
0664
0665
0666
0667 template <typename Value>
0668 inline double dirCosTheta(const LorentzVector<Value> & p) {
0669 return Direction<0>::pos()? p.cosTheta(): -p.cosTheta();
0670 }
0671
0672
0673
0674 template <typename Value>
0675 inline ThreeVector<Value> dirBoostVector(const LorentzVector<Value> & p) {
0676 ThreeVector<Value> b(p.boostVector());
0677 if ( Direction<0>::neg() ) b.setZ(-b.z());
0678 return b;
0679 }
0680
0681
0682
0683 template <typename Value>
0684 inline LorentzVector<Value>
0685 lightCone(Value plus, Value minus, Value x, Value y) {
0686 LorentzVector<Value> r(x, y, 0.5*(plus-minus), 0.5*(plus+minus));
0687 return r;
0688 }
0689
0690
0691 template <typename Value>
0692 inline LorentzVector<Value>
0693 lightCone(Value plus, Value minus) {
0694
0695
0696 static const Value zero = Value();
0697 LorentzVector<Value> r(zero, zero,
0698 0.5*(plus-minus), 0.5*(plus+minus));
0699 return r;
0700 }
0701
0702 }
0703
0704
0705
0706
0707 #include "Transverse.h"
0708
0709
0710
0711 namespace ThePEG {
0712
0713
0714
0715 template <typename Value>
0716 inline LorentzVector<Value>
0717 lightCone(Value plus, Value minus, Transverse<Value> pt) {
0718 LorentzVector<Value> r(pt.x(), pt.y(), 0.5*(plus-minus), 0.5*(plus+minus));
0719 return r;
0720 }
0721
0722
0723
0724
0725 template <typename Value>
0726 inline LorentzVector<Value>
0727 lightConeDir(Value plus, Value minus,
0728 Value x = Value(), Value y = Value()) {
0729 LorentzVector<Value> r(x, y, Direction<0>::dir()*0.5*(plus - minus),
0730 0.5*(plus + minus));
0731 return r;
0732 }
0733
0734
0735
0736
0737 template <typename Value>
0738 inline LorentzVector<Value>
0739 lightConeDir(Value plus, Value minus, Transverse<Value> pt) {
0740 LorentzVector<Value> r(pt.x(), pt.y(), Direction<0>::dir()*0.5*(plus - minus),
0741 0.5*(plus + minus));
0742 return r;
0743
0744 }
0745
0746
0747 template <typename OStream, typename UnitT, typename Value>
0748 void ounitstream(OStream & os, const LorentzVector<Value> & p, UnitT & u) {
0749 os << ounit(p.x(), u) << ounit(p.y(), u) << ounit(p.z(), u)
0750 << ounit(p.e(), u);
0751 }
0752
0753
0754 template <typename IStream, typename UnitT, typename Value>
0755 void iunitstream(IStream & is, LorentzVector<Value> & p, UnitT & u) {
0756 Value x, y, z, e;
0757 is >> iunit(x, u) >> iunit(y, u) >> iunit(z, u) >> iunit(e, u);
0758 p = LorentzVector<Value>(x, y, z, e);
0759 }
0760
0761
0762 }
0763
0764 #undef ERROR_IF
0765 #endif