Thrust.cc
Go to the documentation of this file.
00001 // -*- C++ -*- 00002 #include "Rivet/Config/RivetCommon.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 += p3.mod(); 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 } Generated on Thu Mar 10 2016 08:29:53 for The Rivet MC analysis system by ![]() |