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