rivet is hosted by Hepforge, IPPP Durham
Thrust.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/Projections/Thrust.hh"
00004 #include "Rivet/Tools/Logging.hh"
00005 
00006 
00007 namespace Rivet {
00008 
00009 
00010   void Thrust::calc(const FinalState& fs) {
00011     calc(fs.particles());
00012   }
00013 
00014   void Thrust::calc(const vector<Particle>& fsparticles) {
00015     vector<Vector3> threeMomenta;
00016     threeMomenta.reserve(fsparticles.size());
00017     foreach (const Particle& p, fsparticles) {
00018       threeMomenta.push_back( p.momentum().vector3() );
00019     }
00020     _calcThrust(threeMomenta);
00021   }
00022 
00023   void Thrust::calc(const vector<FourMomentum>& fsmomenta) {
00024     vector<Vector3> threeMomenta;
00025     threeMomenta.reserve(fsmomenta.size());
00026     foreach (const FourMomentum& v, fsmomenta) {
00027       threeMomenta.push_back(v.vector3());
00028     }
00029     _calcThrust(threeMomenta);
00030   }
00031 
00032   void Thrust::calc(const vector<Vector3>& fsmomenta) {
00033     _calcThrust(fsmomenta);
00034   }
00035 
00036 
00037   /////////////////////////////////////////////////
00038 
00039 
00040 
00041   inline bool mod2Cmp(const Vector3& a, const Vector3& b) {
00042     return a.mod2() > b.mod2();
00043   }
00044 
00045 
00046   // Do the general case thrust calculation
00047   void _calcT(const vector<Vector3>& momenta, double& t, Vector3& taxis) {
00048     // This function implements the iterative algorithm as described in the
00049     // Pythia manual. We take eight (four) different starting vectors
00050     // constructed from the four (three) leading particles to make sure that
00051     // we don't find a local maximum.
00052     vector<Vector3> p = momenta;
00053     assert(p.size() >= 3);
00054     unsigned int n = 3;
00055     if (p.size() == 3) n = 3;
00056     vector<Vector3> tvec;
00057     vector<double> tval;
00058     std::sort(p.begin(), p.end(), mod2Cmp);
00059     for (int i = 0 ; i < intpow(2, n-1); ++i) {
00060       // Create an initial vector from the leading four jets
00061       Vector3 foo(0,0,0);
00062       int sign = i;
00063       for (unsigned int k = 0 ; k < n ; ++k) {
00064         (sign % 2) == 1 ? foo += p[k] : foo -= p[k];
00065         sign /= 2;
00066       }
00067       foo=foo.unit();
00068 
00069       // Iterate
00070       double diff=999.;
00071       while (diff>1e-5) {
00072         Vector3 foobar(0,0,0);
00073         for (unsigned int k=0 ; k<p.size() ; k++)
00074           foo.dot(p[k])>0 ? foobar+=p[k] : foobar-=p[k];
00075         diff=(foo-foobar.unit()).mod();
00076         foo=foobar.unit();
00077       }
00078 
00079       // Calculate the thrust value for the vector we found
00080       t=0.;
00081       for (unsigned int k=0 ; k<p.size() ; k++)
00082         t+=fabs(foo.dot(p[k]));
00083 
00084       // Store everything
00085       tval.push_back(t);
00086       tvec.push_back(foo);
00087     }
00088 
00089     // Pick the solution with the largest thrust
00090     t=0.;
00091     for (unsigned int i=0 ; i<tvec.size() ; i++)
00092       if (tval[i]>t){
00093         t=tval[i];
00094         taxis=tvec[i];
00095       }
00096   }
00097 
00098 
00099 
00100   // Do the full calculation
00101   void Thrust::_calcThrust(const vector<Vector3>& fsmomenta) {
00102     // Make a vector of the three-momenta in the final state
00103     double momentumSum(0.0);
00104     foreach (const Vector3& p3, fsmomenta) {
00105       momentumSum += mod(p3);
00106     }
00107     MSG_DEBUG("Number of particles = " << fsmomenta.size());
00108 
00109 
00110     // Clear the caches
00111     _thrusts.clear();
00112     _thrustAxes.clear();
00113 
00114 
00115     // If there are fewer than 2 visible particles, we can't do much
00116     if (fsmomenta.size() < 2) {
00117       for (int i = 0; i < 3; ++i) {
00118         _thrusts.push_back(-1);
00119         _thrustAxes.push_back(Vector3(0,0,0));
00120       }
00121       return;
00122     }
00123 
00124 
00125     // Handle special case of thrust = 1 if there are only 2 particles
00126     if (fsmomenta.size() == 2) {
00127       Vector3 axis(0,0,0);
00128       _thrusts.push_back(1.0);
00129       _thrusts.push_back(0.0);
00130       _thrusts.push_back(0.0);
00131       axis = fsmomenta[0].unit();
00132       if (axis.z() < 0) axis = -axis;
00133       _thrustAxes.push_back(axis);
00134       /// @todo Improve this --- special directions bad...
00135       /// (a,b,c) _|_ 1/(a^2+b^2) (b,-a,0) etc., but which combination minimises error?
00136       if (axis.z() < 0.75)
00137         _thrustAxes.push_back( (axis.cross(Vector3(0,0,1))).unit() );
00138       else
00139         _thrustAxes.push_back( (axis.cross(Vector3(0,1,0))).unit() );
00140       _thrustAxes.push_back( _thrustAxes[0].cross(_thrustAxes[1]) );
00141       return;
00142     }
00143 
00144 
00145 
00146     // Temporary variables for calcs
00147     Vector3 axis(0,0,0);
00148     double val = 0.;
00149 
00150     // Get thrust
00151     _calcT(fsmomenta, val, axis);
00152     MSG_DEBUG("Mom sum = " << momentumSum);
00153     _thrusts.push_back(val / momentumSum);
00154     // Make sure that thrust always points along the +ve z-axis.
00155     if (axis.z() < 0) axis = -axis;
00156     axis = axis.unit();
00157     MSG_DEBUG("Axis = " << axis);
00158     _thrustAxes.push_back(axis);
00159 
00160     // Get thrust major
00161     vector<Vector3> threeMomenta;
00162     foreach (const Vector3& v, fsmomenta) {
00163       // Get the part of each 3-momentum which is perpendicular to the thrust axis
00164       const Vector3 vpar = dot(v, axis.unit()) * axis.unit();
00165       threeMomenta.push_back(v - vpar);
00166     }
00167     _calcT(threeMomenta, val, axis);
00168     _thrusts.push_back(val / momentumSum);
00169     if (axis.x() < 0) axis = -axis;
00170     axis = axis.unit();
00171     _thrustAxes.push_back(axis);
00172 
00173     // Get thrust minor
00174     if (_thrustAxes[0].dot(_thrustAxes[1]) < 1e-10) {
00175       axis = _thrustAxes[0].cross(_thrustAxes[1]);
00176       _thrustAxes.push_back(axis);
00177       val = 0.0;
00178       foreach (const Vector3& v, fsmomenta) {
00179         val += fabs(dot(axis, v));
00180       }
00181       _thrusts.push_back(val / momentumSum);
00182     } else {
00183       _thrusts.push_back(-1.0);
00184       _thrustAxes.push_back(Vector3(0,0,0));
00185     }
00186 
00187   }
00188 
00189 
00190 
00191 }