Particle.h

00001 #ifndef __PARTICLE_DEF__
00002 #define __PARTICLE_DEF__
00003 /**
00004   Single particle class with basic methods such as boost, rotation,
00005   and angle calculation.
00006 */
00007 
00008 #include <cstdio>
00009 #include <iostream>
00010 #include <math.h>
00011 
00012 namespace TauSpinner {
00013 
00014 const double ELECTRON_MASS = 0.0005111;
00015 const double MUON_MASS     = 0.105659;
00016 const double TAU_MASS      = 1.777;
00017 
00018 class Particle
00019 {
00020 public:
00021 /*
00022         Constructors
00023 */
00024   Particle():_px(0),_py(0),_pz(0),_e(0),_pdgid(0)                                                      {}
00025         Particle(double px, double py, double pz, double e, int id):_px(px),_py(py),_pz(pz),_e(e),_pdgid(id) {}
00026   
00027 public:
00028 /*
00029         Accessors
00030 */
00031         double px() const { return _px; }
00032         double py() const { return _py; }
00033         double pz() const { return _pz; }
00034         double e () const { return _e; }
00035         int pdgid() const { return _pdgid; }
00036 
00037         // Invariant mass. If mass is negative then -sqrt(-mass) is returned
00038         double recalculated_mass()  const
00039         {
00040                 double p2 = _px*_px + _py*_py + _pz*_pz;
00041                 double e2 = _e*_e;
00042                 double m2 = e2 - p2;
00043 
00044                 if ( m2 < 0.0 ) return -sqrt( -m2 );
00045 
00046                 return sqrt( m2 );
00047         }
00048 
00049         void   setPx(double px) { _px = px; }
00050         void   setPy(double py) { _py = py; }
00051         void   setPz(double pz) { _pz = pz; }
00052         void   setE (double e ) { _e  = e;  }
00053         void   print()
00054         {
00055                 if(_pdgid) printf("%4d: %15.8e %15.8e %15.8e %15.8e  | %15.8e\n",
00056                                   pdgid(),px(),  py(),  pz(),  e(),    recalculated_mass());
00057                 else       printf(" SUM: %15.8e %15.8e %15.8e %15.8e  | %15.8e\n",
00058                                           px(),  py(),  pz(),  e(),    recalculated_mass());
00059         }
00060 public:
00061 /*
00062         These methods work on above accessors - they don't have to be changed
00063         even if above methods change.
00064 */
00065         double getAnglePhi();
00066         double getAngleTheta();
00067         void   rotateXZ(double theta);
00068         void   rotateXY(double theta);
00069         void   boostAlongZ(double pz, double e);
00070         void   boostToRestFrame(Particle &p);
00071         void   boostFromRestFrame(Particle &p);
00072 private:
00073   double _px,_py,_pz,_e;
00074   int    _pdgid;
00075 };
00076 
00077 inline double Particle::getAnglePhi()
00078 {
00079         // conventions as in ANGFI(X,Y) of tauola.f and PHOAN1 of photos.f
00080         // but now 'phi' in name define that it is rotation in px py
00081   
00082         double buf = 0.;
00083   
00084         if(fabs(py())<fabs(px()))
00085         {
00086                 buf = atan( fabs(py()/px()) );
00087                 if(px()<0.) buf = M_PI-buf;
00088         }
00089         else buf = acos( px()/sqrt(px()*px()+py()*py()) );
00090   
00091         if(py()<0.)     buf = 2.*M_PI-buf;
00092 
00093         return buf;
00094 }
00095 
00096 inline double Particle::getAngleTheta()
00097 {
00098         // conventions as in ANGXY(X,Y) of tauola.f or PHOAN2 of photos.f
00099         // but now 'theta' in name define that it is rotation in pz px 
00100         // note that first argument of PHOAN2 was usually z
00101   
00102         double buf = 0.;
00103   
00104         if(fabs(px())<fabs(pz()))
00105         {
00106                 buf = atan( fabs(px()/pz()) );
00107                 if(pz()<0.) buf = M_PI-buf;
00108         }
00109         else buf = acos( pz()/sqrt(pz()*pz()+px()*px()) );
00110 
00111         return buf;
00112 }
00113 
00114 inline void Particle::rotateXZ(double theta)
00115 {
00116         // as PHORO2 of photos.f
00117         double pX=px();
00118         double pZ=pz();
00119         setPx( cos(theta)*pX + sin(theta)*pZ);
00120         setPz(-sin(theta)*pX + cos(theta)*pZ);
00121 }
00122 
00123 inline void Particle::rotateXY(double theta)
00124 {
00125         // as PHORO3 of photos.f
00126         double pX=px();
00127         double pY=py();
00128         setPx( cos(theta)*pX - sin(theta)*pY);
00129         setPy( sin(theta)*pX + cos(theta)*pY);
00130 }
00131 
00132 inline void Particle::boostAlongZ(double p_pz, double p_e)
00133 {
00134         // as PHOBO3 of photos.f
00135         double m=sqrt(p_e*p_e-p_pz*p_pz);
00136         double buf_pz=pz();
00137         double buf_e=e();
00138 
00139         setPz((p_e *buf_pz + p_pz*buf_e)/m);
00140         setE ((p_pz*buf_pz + p_e *buf_e)/m);
00141 }
00142 
00143 inline void Particle::boostToRestFrame(Particle &p)
00144 {
00145         double p_len = sqrt(p.px()*p.px()+p.py()*p.py()+p.pz()*p.pz());
00146         double phi   = p.getAnglePhi();
00147         p.rotateXY(-phi );
00148         double theta = p.getAngleTheta();
00149         p.rotateXY( phi );
00150 
00151         //Now rotate coordinates to get boost in Z direction.
00152         rotateXY(-phi  );
00153         rotateXZ(-theta);
00154         boostAlongZ(-1*p_len,p.e());
00155         rotateXZ( theta);
00156         rotateXY( phi  );
00157 }
00158 
00159 inline void Particle::boostFromRestFrame(Particle &p)
00160 {
00161         double p_len = sqrt(p.px()*p.px()+p.py()*p.py()+p.pz()*p.pz());
00162         double phi   = p.getAnglePhi();
00163         p.rotateXY(-phi );
00164         double theta = p.getAngleTheta();
00165         p.rotateXY( phi );
00166 
00167         //Now rotate coordinates to get boost in Z direction.
00168         rotateXY(-phi  );
00169         rotateXZ(-theta);
00170         boostAlongZ(p_len,p.e());
00171         rotateXZ( theta);
00172         rotateXY( phi  );
00173 }
00174 
00175 } // namespace TauSpinner
00176 #endif
Generated on Sun Oct 20 20:24:09 2013 for C++InterfacetoTauola by  doxygen 1.6.3