Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Thrust.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 #include "Rivet/Projections/Thrust.hh"
00004 #include "Rivet/RivetCLHEP.hh"
00005 
00006 using namespace CLHEP;
00007 
00008 namespace Rivet {
00009 
00010 
00011   int Thrust::compare(const Projection& p) const {
00012     return 0;
00013   }
00014 
00015 
00016   void Thrust::calcT(const vector<Vector3>& p, double& t, Vector3& taxis) const {
00017     t = 0.0;
00018     Vector3 tv, ptot;
00019     vector<Vector3> cpm(4);
00020     const size_t psize = p.size();
00021     for (size_t k = 1; k < psize; ++k) {
00022       for (size_t j = 0; j < k; ++j) {
00023         tv = p[j].cross(p[k]);
00024         ptot = Vector3();
00025         for (size_t l = 0; l < psize; ++l) {
00026           if (l != j && l != k) {
00027             if (p[l].dot(tv) > 0.0) { 
00028               ptot += p[l];
00029             } else {
00030               ptot -= p[l];
00031             }
00032           }
00033         }
00034         cpm[0] = ptot - p[j] - p[k];
00035         cpm[1] = ptot - p[j] + p[k];
00036         cpm[2] = ptot + p[j] - p[k];
00037         cpm[3] = ptot + p[j] + p[k];
00038         for (size_t i = 0; i < 4; ++i) {
00039           double tval = cpm[i].mag2();
00040           if (tval > t) {
00041             t = tval;
00042             taxis = cpm[i];
00043           }
00044         }
00045       } // j loop
00046     } // k loop
00047   }
00048 
00049 
00050 
00051   void Thrust::calcM(const vector<Vector3>& p, double& m, Vector3& maxis) const {
00052     double mval;
00053     m = 0.0;
00054     Vector3 tv, ptot;
00055     vector<Vector3> cpm;
00056     for (unsigned int j = 0; j < p.size(); ++j) {
00057       tv = p[j];
00058       ptot = Vector3();
00059       for (unsigned int l = 0; l < p.size(); ++l) {
00060         if (l != j) {
00061           if (p[l].dot(tv) > 0.0) { 
00062             ptot += p[l];
00063           } else {
00064             ptot -= p[l];
00065           }
00066         }
00067       }
00068       cpm.clear();
00069       cpm.push_back(ptot - p[j]);
00070       cpm.push_back(ptot + p[j]);
00071       for (vector<Vector3>::iterator it = cpm.begin(); it != cpm.end(); ++it) {
00072         mval = it->mag2();
00073         if (mval > m) {
00074           m = mval;
00075           maxis = *it;
00076         }
00077       }
00078     } // j loop
00079   }
00080 
00081 
00082 
00083   void Thrust::calcThrust(const FinalState& fs) {
00084     // If we've already been here, stop
00085     //if (_calculatedThrust) return;
00086 
00087     // Make a vector of the three-momenta in the final state
00088     vector<Vector3> threeMomenta;
00089     double momentumSum(0.0);
00090     for (ParticleVector::const_iterator p = fs.particles().begin(); p != fs.particles().end(); ++p) {
00091       Vector3 p3 = p->getMomentum().vect();
00092       threeMomenta.push_back(p3);
00093       momentumSum += threeMomenta.back().mag();
00094     }
00095 
00096     // Clear the caches
00097     _thrusts.clear();
00098     _thrustAxes.clear(); 
00099     //_calculatedThrust = true; // Pre-emptive strike to avoid repeats in each special case
00100 
00101 
00102     // If there are fewer than 2 visible particles, we can't do much
00103     if (threeMomenta.size() < 2) {
00104       for (int i = 0; i < 3; ++i) {
00105         _thrusts.push_back(-1);
00106         _thrustAxes.push_back(Vector3());
00107       }
00108       return;
00109     }
00110 
00111 
00112     // Handle special case of thrust = 1 if there are only 2 particles
00113     if (threeMomenta.size() == 2) {
00114       Vector3 axis;
00115       _thrusts.push_back(1.0);
00116       _thrusts.push_back(0.0);
00117       _thrusts.push_back(0.0);
00118       axis = threeMomenta[0].unit();
00119       if (axis.z() < 0) axis = -axis;
00120       _thrustAxes.push_back(axis);
00121       _thrustAxes.push_back(axis.orthogonal());
00122       _thrustAxes.push_back( _thrustAxes[0].cross(_thrustAxes[1]) );
00123       return;
00124     }
00125 
00126 
00127     // Handle special case where thrust = max{x1,x2,x3} if there are 3 particles
00128     if (threeMomenta.size() == 3) {
00129       Vector3 axis;
00130       // Order by magnitude
00131       /// @todo rsort with mag2() functor is much neater
00132       if (threeMomenta[0].mag2() < threeMomenta[1].mag2()) std::swap(threeMomenta[0], threeMomenta[1]);
00133       if (threeMomenta[0].mag2() < threeMomenta[2].mag2()) std::swap(threeMomenta[0], threeMomenta[2]);
00134       if (threeMomenta[1].mag2() < threeMomenta[2].mag2()) std::swap(threeMomenta[1], threeMomenta[2]);
00135       // Thrust
00136       axis = threeMomenta[0].unit();
00137       if (axis.z() < 0) axis = -axis;
00138       _thrusts.push_back(2.0 * threeMomenta[0].mag() / momentumSum);
00139       _thrustAxes.push_back(axis);
00140       // Thrust major (independent part of next largest momentum)
00141       axis = ( threeMomenta[1] - (axis.dot(threeMomenta[1])) * axis ).unit();
00142       if (axis.x() < 0) axis = -axis;
00143       _thrusts.push_back( (fabs(threeMomenta[1].dot(axis)) + 
00144                            fabs(threeMomenta[2].dot(axis)))  / momentumSum);
00145       _thrustAxes.push_back(axis);
00146       // Thrust minor
00147       _thrusts.push_back(0.0);
00148       _thrustAxes.push_back( _thrustAxes[0].cross(_thrustAxes[1]) );
00149       return;
00150     }
00151 
00152 
00153     // If the special cases don't apply, we have to use a general method. Here
00154     // we explicitly calculate in units of MeV using an algorithm based on 
00155     // Brandt/Dahmen Z Phys C1 (1978) and 'tasso' code from HERWIG. Re-coded
00156     // from Herwig++ implementation by Stefan Gieseke by Andy Buckley.
00157     // NB. special case with >= 4 coplanar particles will still fail. 
00158     // probably not too important... 
00159     /// @todo Thrust assumes all momenta are in the CoM system: no explicit boost is performed.
00160 
00161     // Temporary variables for calcs
00162     Vector3 axis; double val;
00163 
00164     // Get thrust
00165     calcT(threeMomenta, val, axis);
00166     _thrusts.push_back(sqrt(val) / momentumSum);
00167     if (axis.z() < 0) axis = -axis;
00168     _thrustAxes.push_back(axis.unit()); 
00169 
00170     // Get thrust major 
00171     threeMomenta.clear();
00172     for (ParticleVector::const_iterator p = fs.particles().begin(); p != fs.particles().end(); ++p) {
00173       // Get the part of each 3-momentum which is perpendicular to the thrust axis
00174       Vector3 v = p->getMomentum().vect();
00175       Vector3 vpar = v.dot(axis.unit()) * axis.unit();
00176       threeMomenta.push_back(v - vpar);
00177     }
00178     calcM(threeMomenta, val, axis);
00179     _thrusts.push_back(sqrt(val) / momentumSum);
00180     if (axis.x() < 0) axis = -axis;
00181     _thrustAxes.push_back(axis.unit()); 
00182 
00183     // Get thrust minor
00184     if (_thrustAxes[0].dot(_thrustAxes[1]) < 1e-10) {
00185       axis = _thrustAxes[0].cross(_thrustAxes[1]);
00186       _thrustAxes.push_back(axis);
00187       val = 0.0;
00188       for (ParticleVector::const_iterator p = fs.particles().begin(); p != fs.particles().end(); ++p) {
00189         val += fabs(axis * p->getMomentum().vect());
00190       }
00191       _thrusts.push_back(val / momentumSum);
00192     } else {
00193       _thrusts.push_back(-1.0);
00194       _thrustAxes.push_back(Vector3());
00195     }
00196 
00197   }
00198 
00199 
00200   void Thrust::project(const Event& e) {
00201     const FinalState& fs = e.applyProjection(*_fsproj);
00202     calcThrust(fs);
00203   }
00204 
00205 
00206 }