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 } Generated on Fri Dec 21 2012 15:03:42 for The Rivet MC analysis system by ![]() |