Spherocity.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/Projections/Spherocity.hh"
00004 #include "Rivet/Tools/Logging.hh"
00005 
00006 
00007 namespace Rivet {
00008 
00009 
00010   void Spherocity::calc(const FinalState& fs) {
00011     calc(fs.particles());
00012   }
00013 
00014 
00015   void Spherocity::calc(const vector<Particle>& fsparticles) {
00016     vector<Vector3> threeMomenta;
00017     threeMomenta.reserve(fsparticles.size());
00018     foreach (const Particle& p, fsparticles) {
00019       const Vector3 p3 = p.momentum().vector3();
00020       threeMomenta.push_back(p3);
00021     }
00022     _calcSpherocity(threeMomenta);
00023   }
00024 
00025 
00026   void Spherocity::calc(const vector<FourMomentum>& fsmomenta) {
00027     vector<Vector3> threeMomenta;
00028     threeMomenta.reserve(fsmomenta.size());
00029     foreach (const FourMomentum& v, fsmomenta) {
00030       threeMomenta.push_back(v.vector3());
00031     }
00032     _calcSpherocity(threeMomenta);
00033   }
00034 
00035 
00036   void Spherocity::calc(const vector<Vector3>& fsmomenta) {
00037     _calcSpherocity(fsmomenta);
00038   }
00039 
00040 
00041   /////////////////////////////////////////////////
00042 
00043 
00044   // Inline functions to avoid template hell
00045   inline bool mod2Cmp(const Vector<2>& a, const Vector<2>& b) {
00046     return a.mod2() > b.mod2();
00047   }
00048 
00049   inline double dot(const Vector<2>& a, const Vector<2>& b) {
00050     return a[0]*b[0] + a[1]*b[1];
00051   }
00052 
00053   inline Vector<2> unit(const Vector<2>& v) {
00054     assert(mod(v) > 0);
00055     Vector<2> returnthis;
00056     returnthis.set(0, v[0]/mod(v));
00057     returnthis.set(1, v[1]/mod(v));
00058     return returnthis;
00059   }
00060 
00061 
00062 
00063   //// Do the general case spherocity calculation
00064   void _calcS(const vector<Vector3 >& perpmomenta, double& sphero, Vector3& saxis) {
00065     // According to the Salam paper, p5, footnote 4, the
00066     // axis n that minimises the Spherocity value ALWAYS coincides with the
00067     // direction of one of the transverse momentum vectors of the events particles.
00068     // Thus we carry out the calculation of Sphero for all particles and pick the
00069     // one that yields the smallerst values
00070 
00071     vector<Vector3> p = perpmomenta;
00072     vector<double> sval;
00073 
00074 
00075     // Prepare vector to store unit vector representation of all particle momenta
00076     // and also calculate the transverse momentum sum
00077     vector<Vector3> units;
00078     double sumperpmomenta = 0.0;
00079     foreach (const Vector3& p, perpmomenta) {
00080       units.push_back(Vector3(p.x(), p.y(), 0.0).unit());
00081       sumperpmomenta += p.mod();
00082     }
00083 
00084     // Spherocity calculation
00085     //
00086     // The outer loop is for iteration over all unit vectors
00087     foreach (const Vector3& u, units){
00088       double s =0.0;
00089       for (unsigned int k=0 ; k<p.size() ; k++)
00090         s += fabs(p[k].cross(u).mod()  );
00091 
00092       sval.push_back(s);
00093     }
00094 
00095 
00096     // Pick the solution with the smallest spherocity
00097     sphero = 999.;
00098     for (unsigned int i=0 ; i<units.size() ; i++)
00099       if (sval[i] < sphero){
00100         sphero = sval[i];
00101         saxis  = units[i];
00102       }
00103 
00104   }
00105 
00106 
00107 
00108   // Do the full calculation
00109   void Spherocity::_calcSpherocity(const vector<Vector3>& fsmomenta) {
00110 
00111     // Make a vector of the three-momenta in the final state
00112     // Explicitly set the z-component (parallel to beam axis) to zero
00113     // This creates a 3D-vector representation of the transverse momentum
00114     // but take the full information momentum vectors as input
00115 
00116     vector<Vector3> fsperpmomenta;
00117     // A small iteration over full momenta but set z-coord. to 0.0 to get transverse momenta
00118     foreach (const Vector3& p, fsmomenta) {
00119       fsperpmomenta.push_back(Vector3(p.x(), p.y(), 0.0));
00120     }
00121 
00122     // This returns the scalar sum of (transverse) momenta
00123     double perpmomentumSum(0.0);
00124     foreach (const Vector3& p, fsperpmomenta) {
00125       perpmomentumSum += mod(p);
00126     }
00127 
00128     // Clear the caches
00129     _spherocities.clear();
00130     _spherocityAxes.clear();
00131 
00132     // If there are fewer than 2 visible particles, we can't do much
00133     // This is blindly copied from the Thrust projection
00134     if (fsmomenta.size() < 2) {
00135       for (int i = 0; i < 3; ++i) {
00136         _spherocities.push_back(-1);
00137         _spherocityAxes.push_back(Vector3(0,0,0));
00138       }
00139       return;
00140     }
00141 
00142     // Handle special case of spherocity = 1 if there are only 2 particles
00143     // This is blindly copied from the Thrust projection
00144     if (fsmomenta.size() == 2) {
00145       Vector3 axis(0,0,0);
00146       _spherocities.push_back(1.0);
00147       _spherocities.push_back(0.0);
00148       _spherocities.push_back(0.0);
00149       axis = fsmomenta[0].unit();
00150       if (axis.z() < 0) axis = -axis;
00151       _spherocityAxes.push_back(axis);
00152       /// @todo Improve this --- special directions bad...
00153       /// (a,b,c) _|_ 1/(a^2+b^2) (b,-a,0) etc., but which combination minimises error?
00154       if (axis.z() < 0.75)
00155         _spherocityAxes.push_back( (axis.cross(Vector3(0,0,1))).unit() );
00156       else
00157         _spherocityAxes.push_back( (axis.cross(Vector3(0,1,0))).unit() );
00158       _spherocityAxes.push_back( _spherocityAxes[0].cross(_spherocityAxes[1]) );
00159       return;
00160     }
00161 
00162     // Temporary variables for calcs
00163     Vector3 axis(0,0,0);
00164     double val = 0.;
00165 
00166     // Get spherocity
00167     _calcS(fsperpmomenta, val, axis);
00168     MSG_DEBUG("Mom sum = " << perpmomentumSum);
00169     double spherocity = PI*PI* val*val / (4 * perpmomentumSum*perpmomentumSum);
00170     _spherocities.push_back(spherocity);
00171 
00172     // See if calclulated spherocity value makes sense
00173     if (spherocity < 0.0 || spherocity > 1.0) {
00174       MSG_WARNING("Spherocity = " << spherocity);
00175     }
00176 
00177     MSG_DEBUG("Spherocity value = " << spherocity);
00178 
00179     MSG_DEBUG("Sperocity axis = " << axis);
00180 
00181     _spherocityAxes.push_back(axis);
00182 
00183 
00184     //// Get spherocity minor
00185     ////
00186     ////
00187     //// The Beam axis is eZ = (0, 0, 1)
00188     ////
00189     //double perpMinor = 0.0;
00190     //const Vector3 ez = Vector3(0, 0, 1);
00191     //foreach (const Vector3& v, fsperpmomenta) {
00192       //Vector3 temp = Vector3(v[0], v[1], 0.0);
00193       //perpMinor += mod(temp.cross(_spherocityAxes[0]));
00194     //}
00195     //_spherocitys.push_back(perpMinor / perpmomentumSum);
00196 
00197 
00198     //// Manual check
00199     //double test = 0.;
00200     //Vector<2>  ex;
00201     //ex.set(0, 1.0);
00202     //ex.set(1, 0);
00203     //foreach (const Vector<2> & v, fsperpmomenta2D) {
00204       //test+=fabs(dot(ex, v));
00205     //}
00206     //if (test/perpmomentumSum < _spherocities[0]) {
00207       //std::cout << "Warning: " << test/perpmomentumSum << " > " << _spherocitys[0] << "     " << _spherocityAxes[0] << endl;
00208     //}
00209 
00210   }
00211 
00212 
00213 }