LCOV - code coverage report
Current view: top level - PYTHIA8/pythia8210dev/src - Analysis.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 638 0.0 %
Date: 2016-06-14 17:26:59 Functions: 0 16 0.0 %

          Line data    Source code
       1             : // Analysis.cc is a part of the PYTHIA event generator.
       2             : // Copyright (C) 2015 Torbjorn Sjostrand.
       3             : // PYTHIA is licenced under the GNU GPL version 2, see COPYING for details.
       4             : // Please respect the MCnet Guidelines, see GUIDELINES for details.
       5             : 
       6             : // Function definitions (not found in the header) for the
       7             : // Sphericity, Thrust, ClusJet, CellJet and SlowJet classes.
       8             : 
       9             : #include "Pythia8/Analysis.h"
      10             : #include "Pythia8/FJcore.h"
      11             : 
      12             : namespace Pythia8 {
      13             : 
      14             : //==========================================================================
      15             : 
      16             : // Sphericity class.
      17             : // This class finds sphericity-related properties of an event.
      18             : 
      19             : //--------------------------------------------------------------------------
      20             : 
      21             : // Constants: could be changed here if desired, but normally should not.
      22             : // These are of technical nature, as described for each.
      23             : 
      24             : // Minimum number of particles to perform study.
      25             : const int    Sphericity::NSTUDYMIN     = 2;
      26             : 
      27             : // Maximum number of times that an error warning will be printed.
      28             : const int    Sphericity::TIMESTOPRINT  = 1;
      29             : 
      30             : // Assign mimimum squared momentum in weight to avoid division by zero.
      31             : const double Sphericity::P2MIN         = 1e-20;
      32             : 
      33             : // Second eigenvalue not too low or not possible to find eigenvectors.
      34             : const double Sphericity::EIGENVALUEMIN = 1e-10;
      35             : 
      36             : //--------------------------------------------------------------------------
      37             : 
      38             : // Analyze event.
      39             : 
      40             : bool Sphericity::analyze(const Event& event, ostream& os) {
      41             : 
      42             :   // Initial values, tensor and counters zero.
      43           0 :   eVal1 = eVal2 = eVal3 = 0.;
      44           0 :   eVec1 = eVec2 = eVec3 = 0.;
      45           0 :   double tt[4][4];
      46           0 :   for (int j = 1; j < 4; ++j)
      47           0 :   for (int k = j; k < 4; ++k) tt[j][k] = 0.;
      48             :   int nStudy = 0;
      49             :   double denom = 0.;
      50             : 
      51             :   // Loop over desired particles in the event.
      52           0 :   for (int i = 0; i < event.size(); ++i)
      53           0 :   if (event[i].isFinal()) {
      54           0 :     if (select >  2 &&  event[i].isNeutral() ) continue;
      55           0 :     if (select == 2 && !event[i].isVisible() ) continue;
      56           0 :     ++nStudy;
      57             : 
      58             :     // Calculate matrix to be diagonalized. Special cases for speed.
      59           0 :     double pNow[4];
      60           0 :     pNow[1] = event[i].px();
      61           0 :     pNow[2] = event[i].py();
      62           0 :     pNow[3] = event[i].pz();
      63           0 :     double p2Now = pNow[1]*pNow[1] + pNow[2]*pNow[2] + pNow[3]*pNow[3];
      64             :     double pWeight = 1.;
      65           0 :     if (powerInt == 1) pWeight = 1. / sqrt(max(P2MIN, p2Now));
      66           0 :     else if (powerInt == 0) pWeight = pow( max(P2MIN, p2Now), powerMod);
      67           0 :     for (int j = 1; j < 4; ++j)
      68           0 :     for (int k = j; k < 4; ++k) tt[j][k] += pWeight * pNow[j] * pNow[k];
      69           0 :     denom += pWeight * p2Now;
      70           0 :   }
      71             : 
      72             :   // Very low multiplicities (0 or 1) not considered.
      73           0 :   if (nStudy < NSTUDYMIN) {
      74           0 :     if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
      75           0 :     "Sphericity::analyze: too few particles" << endl;
      76           0 :     ++nFew;
      77           0 :     return false;
      78             :   }
      79             : 
      80             :   // Normalize tensor to trace = 1.
      81           0 :   for (int j = 1; j < 4; ++j)
      82           0 :   for (int k = j; k < 4; ++k) tt[j][k] /= denom;
      83             : 
      84             :   // Find eigenvalues to matrix (third degree equation).
      85           0 :   double qCoef = ( tt[1][1] * tt[2][2] + tt[1][1] * tt[3][3]
      86           0 :     + tt[2][2] * tt[3][3] - pow2(tt[1][2]) - pow2(tt[1][3])
      87           0 :     - pow2(tt[2][3]) ) / 3. - 1./9.;
      88           0 :   double qCoefRt = sqrt( -qCoef);
      89           0 :   double rCoef = -0.5 * ( qCoef + 1./9. + tt[1][1] * pow2(tt[2][3])
      90           0 :     + tt[2][2] * pow2(tt[1][3]) + tt[3][3] * pow2(tt[1][2])
      91           0 :     - tt[1][1] * tt[2][2] * tt[3][3] )
      92           0 :     + tt[1][2] * tt[1][3] * tt[2][3] + 1./27.;
      93           0 :   double pTemp = max( min( rCoef / pow3(qCoefRt), 1.), -1.);
      94           0 :   double pCoef = cos( acos(pTemp) / 3.);
      95           0 :   double pCoefRt = sqrt( 3. * (1. - pow2(pCoef)) );
      96           0 :   eVal1 = 1./3. + qCoefRt * max( 2. * pCoef,  pCoefRt - pCoef);
      97           0 :   eVal3 = 1./3. + qCoefRt * min( 2. * pCoef, -pCoefRt - pCoef);
      98           0 :   eVal2 = 1. - eVal1 - eVal3;
      99             : 
     100             :   // Begin find first and last eigenvector.
     101           0 :   for (int iVal = 0; iVal < 2; ++iVal) {
     102           0 :     double eVal = (iVal == 0) ? eVal1 : eVal3;
     103             : 
     104             :     // If all particles are back-to-back then simpleminded third axis.
     105           0 :     if (iVal > 0 && eVal2 < EIGENVALUEMIN) {
     106           0 :       if ( abs(eVec1.pz()) > 0.5) eVec3 = Vec4( 1., 0., 0., 0.);
     107           0 :       else                        eVec3 = Vec4( 0., 0., 1., 0.);
     108           0 :       eVec3 -= dot3( eVec1, eVec3) * eVec1;
     109           0 :       eVec3 /= eVec3.pAbs();
     110           0 :       eVec2  = cross3( eVec1, eVec3);
     111           0 :       return true;
     112             :     }
     113             : 
     114             :     // Set up matrix to diagonalize.
     115           0 :     double dd[4][4];
     116           0 :     for (int j = 1; j < 4; ++j) {
     117           0 :       dd[j][j] = tt[j][j] - eVal;
     118           0 :       for (int k = j + 1; k < 4; ++k) {
     119           0 :         dd[j][k] = tt[j][k];
     120           0 :         dd[k][j] = tt[j][k];
     121             :       }
     122             :     }
     123             : 
     124             :     // Find largest = pivotal element in matrix.
     125             :     int jMax = 0;
     126             :     int kMax = 0;
     127             :     double ddMax = 0.;
     128           0 :     for (int j = 1; j < 4; ++j)
     129           0 :     for (int k = 1; k < 4; ++k)
     130           0 :     if (abs(dd[j][k]) > ddMax) {
     131             :       jMax = j;
     132             :       kMax = k;
     133           0 :       ddMax = abs(dd[j][k]);
     134           0 :     }
     135             : 
     136             :     // Subtract one row from the other two; find new largest element.
     137             :     int jMax2 = 0;
     138             :     ddMax = 0.;
     139           0 :     for (int j = 1; j < 4; ++j)
     140           0 :     if ( j != jMax) {
     141           0 :       double pivot = dd[j][kMax] / dd[jMax][kMax];
     142           0 :       for (int k = 1; k < 4; ++k) {
     143           0 :         dd[j][k] -= pivot * dd[jMax][k];
     144           0 :         if (abs(dd[j][k]) > ddMax) {
     145             :           jMax2 = j;
     146           0 :           ddMax = abs(dd[j][k]);
     147           0 :         }
     148             :       }
     149           0 :     }
     150             : 
     151             :     // Construct eigenvector. Normalize to unit length; sign irrelevant.
     152           0 :     int k1 = kMax + 1; if (k1 > 3) k1 -= 3;
     153           0 :     int k2 = kMax + 2; if (k2 > 3) k2 -= 3;
     154           0 :     double eVec[4];
     155           0 :     eVec[k1]   = -dd[jMax2][k2];
     156           0 :     eVec[k2]   =  dd[jMax2][k1];
     157           0 :     eVec[kMax] = (dd[jMax][k1] * dd[jMax2][k2]
     158           0 :       - dd[jMax][k2] * dd[jMax2][k1]) / dd[jMax][kMax];
     159           0 :     double length = sqrt( pow2(eVec[1]) + pow2(eVec[2])
     160           0 :       + pow2(eVec[3]) );
     161             : 
     162             :     // Store eigenvectors.
     163           0 :     if (iVal == 0) eVec1 = Vec4( eVec[1] / length,
     164           0 :       eVec[2] / length, eVec[3] / length, 0.);
     165           0 :     else eVec3 = Vec4( eVec[1] / length,
     166           0 :       eVec[2] / length, eVec[3] / length, 0.);
     167           0 :   }
     168             : 
     169             :   // Middle eigenvector is orthogonal to the other two; sign irrelevant.
     170           0 :   eVec2 = cross3( eVec1, eVec3);
     171             : 
     172             :   // Done.
     173           0 :   return true;
     174             : 
     175           0 : }
     176             : 
     177             : //--------------------------------------------------------------------------
     178             : 
     179             : // Provide a listing of the info.
     180             : 
     181             : void Sphericity::list(ostream& os) const {
     182             : 
     183             :   // Header.
     184           0 :   os << "\n --------  PYTHIA Sphericity Listing  -------- \n";
     185           0 :   if (powerInt !=2) os << "      Nonstandard momentum power = "
     186           0 :      << fixed << setprecision(3) << setw(6) << power << "\n";
     187           0 :   os << "\n  no     lambda      e_x       e_y       e_z \n";
     188             : 
     189             :   // The three eigenvalues and eigenvectors.
     190           0 :   os << setprecision(5);
     191           0 :   os << "   1" << setw(11) << eVal1 << setw(11) << eVec1.px()
     192           0 :      << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n";
     193           0 :   os << "   2" << setw(11) << eVal2 << setw(11) << eVec2.px()
     194           0 :      << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n";
     195           0 :   os << "   3" << setw(11) << eVal3 << setw(11) << eVec3.px()
     196           0 :      << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n";
     197             : 
     198             :   // Listing finished.
     199           0 :   os << "\n --------  End PYTHIA Sphericity Listing  ----" << endl;
     200             : 
     201           0 : }
     202             : 
     203             : 
     204             : //==========================================================================
     205             : 
     206             : // Thrust class.
     207             : // This class finds thrust-related properties of an event.
     208             : 
     209             : //--------------------------------------------------------------------------
     210             : 
     211             : // Constants: could be changed here if desired, but normally should not.
     212             : // These are of technical nature, as described for each.
     213             : 
     214             : // Minimum number of particles to perform study.
     215             : const int    Thrust::NSTUDYMIN    = 2;
     216             : 
     217             : // Maximum number of times that an error warning will be printed.
     218             : const int    Thrust::TIMESTOPRINT = 1;
     219             : 
     220             : // Major not too low or not possible to find major axis.
     221             : const double Thrust::MAJORMIN     = 1e-10;
     222             : 
     223             : //--------------------------------------------------------------------------
     224             : 
     225             : // Analyze event.
     226             : 
     227             : bool Thrust::analyze(const Event& event, ostream& os) {
     228             : 
     229             :   // Initial values and counters zero.
     230           0 :   eVal1 = eVal2 = eVal3 = 0.;
     231           0 :   eVec1 = eVec2 = eVec3 = 0.;
     232             :   int nStudy = 0;
     233           0 :   vector<Vec4> pOrder;
     234           0 :   Vec4 pSum, nRef, pPart, pFull, pMax;
     235             : 
     236             :   // Loop over desired particles in the event.
     237           0 :   for (int i = 0; i < event.size(); ++i)
     238           0 :   if (event[i].isFinal()) {
     239           0 :     if (select >  2 &&  event[i].isNeutral() ) continue;
     240           0 :     if (select == 2 && !event[i].isVisible() ) continue;
     241           0 :     ++nStudy;
     242             : 
     243             :     // Store momenta. Use energy component for absolute momentum.
     244           0 :     Vec4 pNow = event[i].p();
     245           0 :     pNow.e(pNow.pAbs());
     246           0 :     pSum += pNow;
     247           0 :     pOrder.push_back(pNow);
     248           0 :   }
     249             : 
     250             :   // Very low multiplicities (0 or 1) not considered.
     251           0 :   if (nStudy < NSTUDYMIN) {
     252           0 :     if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
     253           0 :     "Thrust::analyze: too few particles" << endl;
     254           0 :     ++nFew;
     255           0 :     return false;
     256             :   }
     257             : 
     258             :   // Try all combinations of reference vector orthogonal to two particles.
     259           0 :   for (int i1 = 0; i1 < nStudy - 1; ++i1)
     260           0 :   for (int i2 = i1 + 1; i2 < nStudy; ++i2) {
     261           0 :     nRef = cross3( pOrder[i1], pOrder[i2]);
     262           0 :     nRef /= nRef.pAbs();
     263           0 :     pPart = 0.;
     264             : 
     265             :     // Add all momenta with sign; two choices for each reference particle.
     266           0 :     for (int i = 0; i < nStudy; ++i) if (i != i1 && i != i2) {
     267           0 :       if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i];
     268           0 :       else                            pPart -= pOrder[i];
     269             :     }
     270           0 :     for (int j = 0; j < 4; ++j) {
     271           0 :       if      (j == 0) pFull = pPart + pOrder[i1] + pOrder[i2];
     272           0 :       else if (j == 1) pFull = pPart + pOrder[i1] - pOrder[i2];
     273           0 :       else if (j == 2) pFull = pPart - pOrder[i1] + pOrder[i2];
     274           0 :       else             pFull = pPart - pOrder[i1] - pOrder[i2];
     275           0 :       pFull.e(pFull.pAbs());
     276           0 :       if (pFull.e() > pMax.e()) pMax = pFull;
     277             :     }
     278             :   }
     279             : 
     280             :   // Maximum gives thrust axis and value.
     281           0 :   eVal1 = pMax.e() / pSum.e();
     282           0 :   eVec1 = pMax / pMax.e();
     283           0 :   eVec1.e(0.);
     284             : 
     285             :   // Subtract momentum along thrust axis.
     286             :   double pAbsSum = 0.;
     287           0 :   for (int i = 0; i < nStudy; ++i) {
     288           0 :     pOrder[i] -= dot3( eVec1, pOrder[i]) * eVec1;
     289           0 :     pOrder[i].e(pOrder[i].pAbs());
     290           0 :     pAbsSum += pOrder[i].e();
     291             :   }
     292             : 
     293             :   // Simpleminded major and minor axes if too little transverse left.
     294           0 :   if (pAbsSum < MAJORMIN * pSum.e()) {
     295           0 :     if ( abs(eVec1.pz()) > 0.5) eVec2 = Vec4( 1., 0., 0., 0.);
     296           0 :     else                        eVec2 = Vec4( 0., 0., 1., 0.);
     297           0 :     eVec2 -= dot3( eVec1, eVec2) * eVec1;
     298           0 :     eVec2 /= eVec2.pAbs();
     299           0 :     eVec3  = cross3( eVec1, eVec2);
     300           0 :     return true;
     301             :   }
     302             : 
     303             :   // Try all reference vectors orthogonal to one particles.
     304           0 :   pMax = 0.;
     305           0 :   for (int i1 = 0; i1 < nStudy; ++i1) {
     306           0 :     nRef = cross3( pOrder[i1], eVec1);
     307           0 :     nRef /= nRef.pAbs();
     308           0 :     pPart = 0.;
     309             : 
     310             :     // Add all momenta with sign; two choices for each reference particle.
     311           0 :     for (int i = 0; i < nStudy; ++i) if (i != i1) {
     312           0 :       if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i];
     313           0 :       else                            pPart -= pOrder[i];
     314             :     }
     315           0 :     pFull = pPart + pOrder[i1];
     316           0 :     pFull.e(pFull.pAbs());
     317           0 :     if (pFull.e() > pMax.e()) pMax = pFull;
     318           0 :     pFull = pPart - pOrder[i1];
     319           0 :     pFull.e(pFull.pAbs());
     320           0 :     if (pFull.e() > pMax.e()) pMax = pFull;
     321             :   }
     322             : 
     323             :   // Maximum gives major axis and value.
     324           0 :   eVal2 = pMax.e() / pSum.e();
     325           0 :   eVec2 = pMax / pMax.e();
     326           0 :   eVec2.e(0.);
     327             : 
     328             :   // Orthogonal direction gives minor axis, and from there value.
     329           0 :   eVec3 = cross3( eVec1, eVec2);
     330             :   pAbsSum = 0.;
     331           0 :   for (int i = 0; i < nStudy; ++i)
     332           0 :     pAbsSum += abs( dot3(eVec3, pOrder[i]) );
     333           0 :   eVal3 = pAbsSum / pSum.e();
     334             : 
     335             :    // Done.
     336           0 :   return true;
     337             : 
     338           0 : }
     339             : 
     340             : //--------------------------------------------------------------------------
     341             : 
     342             : // Provide a listing of the info.
     343             : 
     344             : void Thrust::list(ostream& os) const {
     345             : 
     346             :   // Header.
     347           0 :   os << "\n --------  PYTHIA Thrust Listing  ------------ \n"
     348           0 :      << "\n          value      e_x       e_y       e_z \n";
     349             : 
     350             :   // The thrust, major and minor values and related event axes.
     351           0 :   os << setprecision(5);
     352           0 :   os << " Thr" << setw(11) << eVal1 << setw(11) << eVec1.px()
     353           0 :      << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n";
     354           0 :   os << " Maj" << setw(11) << eVal2 << setw(11) << eVec2.px()
     355           0 :      << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n";
     356           0 :   os << " Min" << setw(11) << eVal3 << setw(11) << eVec3.px()
     357           0 :      << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n";
     358             : 
     359             :   // Listing finished.
     360           0 :   os << "\n --------  End PYTHIA Thrust Listing  --------" << endl;
     361             : 
     362           0 : }
     363             : 
     364             : //==========================================================================
     365             : 
     366             : // SingleClusterJet class.
     367             : // Simple helper class to ClusterJet for a jet and its contents.
     368             : 
     369             : //--------------------------------------------------------------------------
     370             : 
     371             : // Constants: could be changed here if desired, but normally should not.
     372             : // These are of technical nature, as described for each.
     373             : 
     374             : // Assign minimal pAbs to avoid division by zero.
     375             : const double SingleClusterJet::PABSMIN  = 1e-10;
     376             : 
     377             : //--------------------------------------------------------------------------
     378             : 
     379             : // Distance measures between two SingleClusterJet objects.
     380             : 
     381             : double dist2Fun(int measure, const SingleClusterJet& j1,
     382             :   const SingleClusterJet& j2) {
     383             : 
     384             :   // JADE distance.
     385           0 :   if (measure == 2) return 2. * j1.pJet.e() * j2.pJet.e()
     386           0 :     * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) );
     387             : 
     388             :   // Durham distance.
     389           0 :   if (measure == 3) return 2. * pow2( min( j1.pJet.e(), j2.pJet.e() ) )
     390           0 :     * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) );
     391             : 
     392             :   // Lund distance; "default".
     393           0 :   return (j1.pAbs * j2.pAbs - dot3( j1.pJet, j2.pJet))
     394           0 :     * 2. * j1.pAbs * j2.pAbs / pow2(j1.pAbs + j2.pAbs);
     395             : 
     396           0 : }
     397             : 
     398             : //==========================================================================
     399             : 
     400             : // ClusterJet class.
     401             : // This class performs a jet clustering according to different
     402             : // distance measures: Lund, JADE or Durham.
     403             : 
     404             : //--------------------------------------------------------------------------
     405             : 
     406             : // Constants: could be changed here if desired, but normally should not.
     407             : // These are of technical nature, as described for each.
     408             : 
     409             : // Maximum number of times that an error warning will be printed.
     410             : const int    ClusterJet::TIMESTOPRINT   = 1;
     411             : 
     412             : // Assume the pi+- mass for all particles, except the photon, in one option.
     413             : const double ClusterJet::PIMASS        = 0.13957;
     414             : 
     415             : // Assign minimal pAbs to avoid division by zero.
     416             : const double ClusterJet::PABSMIN        = 1e-10;
     417             : 
     418             : // Initial pT/m preclustering scale as fraction of clustering one.
     419             : const double ClusterJet::PRECLUSTERFRAC = 0.1;
     420             : 
     421             : // Step with which pT/m is reduced if preclustering gives too few jets.
     422             : const double ClusterJet::PRECLUSTERSTEP = 0.8;
     423             : 
     424             : //--------------------------------------------------------------------------
     425             : 
     426             : // Analyze event.
     427             : 
     428             : bool ClusterJet::analyze(const Event& event, double yScaleIn,
     429             :   double pTscaleIn, int nJetMinIn, int nJetMaxIn, ostream& os) {
     430             : 
     431             :   // Input values. Initial values zero.
     432           0 :   yScale  = yScaleIn;
     433           0 :   pTscale = pTscaleIn;
     434           0 :   nJetMin = nJetMinIn;
     435           0 :   nJetMax = nJetMaxIn;
     436           0 :   particles.resize(0);
     437           0 :   jets.resize(0);
     438           0 :   Vec4 pSum;
     439           0 :   distances.clear();
     440             : 
     441             :   // Loop over desired particles in the event.
     442           0 :   for (int i = 0; i < event.size(); ++i)
     443           0 :   if (event[i].isFinal()) {
     444           0 :     if (select >  2 &&  event[i].isNeutral() ) continue;
     445           0 :     if (select == 2 && !event[i].isVisible() ) continue;
     446             : 
     447             :     // Store them, possibly with modified mass => new energy.
     448           0 :     Vec4 pTemp = event[i].p();
     449           0 :     if (massSet == 0 || massSet == 1) {
     450           0 :       double mTemp = (massSet == 0 || event[i].id() == 22)
     451             :         ? 0. : PIMASS;
     452           0 :       double eTemp = sqrt(pTemp.pAbs2() + pow2(mTemp));
     453           0 :       pTemp.e(eTemp);
     454           0 :     }
     455           0 :     particles.push_back( SingleClusterJet(pTemp, i) );
     456           0 :     pSum += pTemp;
     457           0 :   }
     458             : 
     459             :   // Very low multiplicities not considered.
     460           0 :   nParticles = particles.size();
     461           0 :   if (nParticles < nJetMin) {
     462           0 :     if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
     463           0 :     "ClusterJet::analyze: too few particles" << endl;
     464           0 :     ++nFew;
     465           0 :     return false;
     466             :   }
     467             : 
     468             :   // Squared maximum distance in GeV^2 for joining.
     469           0 :   double p2Sum = pSum.m2Calc();
     470           0 :   dist2Join = max( yScale * p2Sum, pow2(pTscale));
     471           0 :   dist2BigMin = 2. * max( dist2Join, p2Sum);
     472             : 
     473             :   // Do preclustering if desired and possible.
     474           0 :   if (doPrecluster && nParticles > nJetMin + 2) {
     475           0 :     precluster();
     476           0 :     if (doReassign) reassign();
     477             :   }
     478             : 
     479             :   // If no preclustering: each particle is a starting jet.
     480           0 :   else for (int i = 0; i < nParticles; ++i) {
     481           0 :     jets.push_back( SingleClusterJet(particles[i]) );
     482           0 :     particles[i].daughter = i;
     483             :   }
     484             : 
     485             :   // Begin iteration towards fewer jets.
     486             :   for ( ; ; ) {
     487             : 
     488             :     // Find the two closest jets.
     489           0 :     double dist2Min = dist2BigMin;
     490             :     int jMin = 0;
     491             :     int kMin = 0;
     492           0 :     for (int j = 0; j < int(jets.size()) - 1; ++j)
     493           0 :     for (int k = j + 1; k < int(jets.size()); ++k) {
     494           0 :       double dist2 = dist2Fun( measure, jets[j], jets[k]);
     495           0 :       if (dist2 < dist2Min) {
     496           0 :         dist2Min = dist2;
     497             :         jMin = j;
     498             :         kMin = k;
     499           0 :       }
     500             :     }
     501             : 
     502             :     // Stop if no pair below cut and not more jets than allowed.
     503           0 :     if ( dist2Min > dist2Join
     504           0 :       && (nJetMax < nJetMin || int(jets.size()) <= nJetMax) ) break;
     505             : 
     506             :     // Stop if reached minimum allowed number of jets. Else continue.
     507           0 :     if (int(jets.size()) <= nJetMin) break;
     508             : 
     509             :     // Join two closest jets.
     510           0 :     jets[jMin].pJet         += jets[kMin].pJet;
     511           0 :     jets[jMin].pAbs          = max( PABSMIN, jets[jMin].pJet.pAbs());
     512           0 :     jets[jMin].multiplicity += jets[kMin].multiplicity;
     513           0 :     for (int i = 0; i < nParticles; ++i)
     514           0 :     if (particles[i].daughter == kMin) particles[i].daughter = jMin;
     515             : 
     516             :     // Save the last 5 distances.
     517           0 :     distances.push_front(dist2Min);
     518           0 :     if (distances.size() > 5) distances.pop_back();
     519             : 
     520             :     // Move up last jet to empty slot to shrink list.
     521           0 :     jets[kMin]               = jets.back();
     522           0 :     jets.pop_back();
     523           0 :     int iEnd                 = jets.size();
     524           0 :     for (int i = 0; i < nParticles; ++i)
     525           0 :     if (particles[i].daughter == iEnd) particles[i].daughter = kMin;
     526             : 
     527             :     // Do reassignments of particles to nearest jet if desired.
     528           0 :     if (doReassign) reassign();
     529           0 :   }
     530             : 
     531             :   // Order jets in decreasing energy.
     532           0 :   for (int j = 0; j < int(jets.size()) - 1; ++j)
     533           0 :   for (int k = int(jets.size()) - 1; k > j; --k)
     534           0 :   if (jets[k].pJet.e() > jets[k-1].pJet.e()) {
     535           0 :     swap( jets[k], jets[k-1]);
     536           0 :     for (int i = 0; i < nParticles; ++i) {
     537           0 :       if (particles[i].daughter == k) particles[i].daughter = k-1;
     538           0 :       else if (particles[i].daughter == k-1) particles[i].daughter = k;
     539             :     }
     540           0 :   }
     541             : 
     542             :   // Done.
     543             :   return true;
     544           0 : }
     545             : 
     546             : //--------------------------------------------------------------------------
     547             : 
     548             : // Precluster nearby particles to save computer time.
     549             : 
     550             : void ClusterJet::precluster() {
     551             : 
     552             :   // Begin iteration over preclustering scale.
     553           0 :   distPre = PRECLUSTERFRAC * sqrt(dist2Join) / PRECLUSTERSTEP;
     554           0 :   for ( ; ;) {
     555           0 :     distPre *= PRECLUSTERSTEP;
     556           0 :     dist2Pre = pow2(distPre);
     557           0 :     for (int i = 0; i < nParticles; ++i) {
     558           0 :       particles[i].daughter   = -1;
     559           0 :       particles[i].isAssigned = false;
     560             :     }
     561             : 
     562             :     // Sum up low-momentum region. Jet if enough momentum.
     563           0 :     Vec4 pCentral;
     564             :     int multCentral = 0;
     565           0 :     for (int i = 0; i < nParticles; ++i)
     566           0 :     if (particles[i].pAbs < 2. * distPre) {
     567           0 :       pCentral    += particles[i].pJet;
     568           0 :       multCentral += particles[i].multiplicity;
     569           0 :       particles[i].isAssigned = true;
     570           0 :     }
     571           0 :     if (pCentral.pAbs() > 2. * distPre) {
     572           0 :       jets.push_back( SingleClusterJet(pCentral) );
     573           0 :       jets.back().multiplicity = multCentral;
     574           0 :       for (int i = 0; i < nParticles; ++i)
     575           0 :       if (particles[i].isAssigned) particles[i].daughter = 0;
     576           0 :     }
     577             : 
     578             :     // Find fastest remaining particle until none left.
     579             :     for ( ; ;) {
     580             :       int iMax = -1;
     581             :       double pMax = 0.;
     582           0 :       for (int i = 0; i < nParticles; ++i)
     583           0 :       if ( !particles[i].isAssigned && particles[i].pAbs > pMax) {
     584             :         iMax = i;
     585           0 :         pMax = particles[i].pAbs;
     586           0 :       }
     587           0 :       if (iMax == -1) break;
     588             : 
     589             :       // Sum up precluster around it according to distance function.
     590           0 :       Vec4 pPre;
     591             :       int multPre = 0;
     592             :       int nRemain = 0;
     593           0 :       for (int i = 0; i < nParticles; ++i)
     594           0 :       if ( !particles[i].isAssigned) {
     595           0 :         double dist2 = dist2Fun( measure, particles[iMax],
     596           0 :           particles[i]);
     597           0 :         if (dist2 < dist2Pre) {
     598           0 :           pPre += particles[i].pJet;
     599           0 :           ++multPre;
     600           0 :           particles[i].isAssigned = true;
     601           0 :           particles[i].daughter   = jets.size();
     602           0 :         } else ++nRemain;
     603           0 :       }
     604           0 :       jets.push_back( SingleClusterJet(pPre) );
     605           0 :       jets.back().multiplicity = multPre;
     606             : 
     607             :       // Decide whether sensible starting configuration or iterate.
     608           0 :       if (int(jets.size()) + nRemain < nJetMin) break;
     609           0 :     }
     610           0 :     if (int(jets.size()) >= nJetMin) break;
     611           0 :   }
     612             : 
     613           0 : }
     614             : 
     615             : //--------------------------------------------------------------------------
     616             : 
     617             : // Reassign particles to nearest jet to correct misclustering.
     618             : 
     619             : void ClusterJet::reassign() {
     620             : 
     621             :   // Reset clustered momenta.
     622           0 :   for (int j = 0; j < int(jets.size()); ++j) {
     623           0 :     jets[j].pTemp        = 0.;
     624           0 :     jets[j].multiplicity = 0;
     625             :   }
     626             : 
     627             :   // Loop through particles to find closest jet.
     628           0 :   for (int i = 0; i < nParticles; ++i) {
     629           0 :     particles[i].daughter = -1;
     630           0 :     double dist2Min = dist2BigMin;
     631             :     int jMin = 0;
     632           0 :     for (int j = 0; j < int(jets.size()); ++j) {
     633           0 :       double dist2 = dist2Fun( measure, particles[i], jets[j]);
     634           0 :       if (dist2 < dist2Min) {
     635             :         dist2Min = dist2;
     636             :         jMin = j;
     637           0 :       }
     638             :     }
     639           0 :     jets[jMin].pTemp += particles[i].pJet;
     640           0 :     ++jets[jMin].multiplicity;
     641           0 :     particles[i].daughter = jMin;
     642             :   }
     643             : 
     644             :   // Replace old by new jet momenta.
     645           0 :   for (int j = 0; j < int(jets.size()); ++j) {
     646           0 :     jets[j].pJet = jets[j].pTemp;
     647           0 :     jets[j].pAbs =  max( PABSMIN, jets[j].pJet.pAbs());
     648             :   }
     649             : 
     650             :   // Check that no empty clusters after reassignments.
     651           0 :   for ( ;  ; ) {
     652             : 
     653             :     // If no empty jets then done.
     654             :     int jEmpty = -1;
     655           0 :     for (int j = 0; j < int(jets.size()); ++j)
     656           0 :       if (jets[j].multiplicity == 0) jEmpty = j;
     657           0 :     if (jEmpty == -1) return;
     658             : 
     659             :     // Find particle assigned to jet with largest distance to it.
     660             :     int iSplit = -1;
     661             :     double dist2Max = 0.;
     662           0 :     for (int i = 0; i < nParticles; ++i) {
     663           0 :       int j = particles[i].daughter;
     664           0 :       double dist2 = dist2Fun( measure, particles[i], jets[j]);
     665           0 :       if (dist2 > dist2Max) {
     666             :         iSplit = i;
     667             :         dist2Max = dist2;
     668           0 :       }
     669             :     }
     670             : 
     671             :     // Let this particle form new jet and subtract off from existing.
     672           0 :     int jSplit         = particles[iSplit].daughter;
     673           0 :     jets[jEmpty]       = SingleClusterJet( particles[iSplit].pJet );
     674           0 :     jets[jSplit].pJet -=  particles[iSplit].pJet;
     675           0 :     jets[jSplit].pAbs  =  max( PABSMIN,jets[jSplit].pJet.pAbs());
     676           0 :     particles[iSplit].daughter = jEmpty;
     677           0 :     --jets[jSplit].multiplicity;
     678           0 :   }
     679             : 
     680           0 : }
     681             : 
     682             : //--------------------------------------------------------------------------
     683             : 
     684             : // Provide a listing of the info.
     685             : 
     686             : void ClusterJet::list(ostream& os) const {
     687             : 
     688             :   // Header.
     689           0 :   string method = (measure == 1) ? "Lund pT"
     690           0 :         : ( (measure == 2) ? "JADE m" : "Durham kT" ) ;
     691           0 :   os << "\n --------  PYTHIA ClusterJet Listing, " << setw(9) <<  method
     692           0 :      << " =" << fixed << setprecision(3) << setw(7) << sqrt(dist2Join)
     693           0 :      << " GeV  --- \n \n  no  mult      p_x        p_y        p_z    "
     694           0 :      << "     e          m \n";
     695             : 
     696             :   // The jets.
     697           0 :   for (int i = 0; i < int(jets.size()); ++i) {
     698           0 :     os << setw(4) << i << setw(6) << jets[i].multiplicity << setw(11)
     699           0 :        << jets[i].pJet.px() << setw(11) << jets[i].pJet.py()
     700           0 :        << setw(11) << jets[i].pJet.pz() << setw(11)
     701           0 :        << jets[i].pJet.e() << setw(11) << jets[i].pJet.mCalc()
     702           0 :        << "\n";
     703             :   }
     704             : 
     705             :   // Listing finished.
     706           0 :   os << "\n --------  End PYTHIA ClusterJet Listing  ---------------"
     707           0 :      << "--------" << endl;
     708           0 : }
     709             : 
     710             : //==========================================================================
     711             : 
     712             : // CellJet class.
     713             : // This class performs a cone jet search in (eta, phi, E_T) space.
     714             : 
     715             : //--------------------------------------------------------------------------
     716             : 
     717             : // Constants: could be changed here if desired, but normally should not.
     718             : // These are of technical nature, as described for each.
     719             : 
     720             : // Minimum number of particles to perform study.
     721             : const int CellJet::TIMESTOPRINT = 1;
     722             : 
     723             : //--------------------------------------------------------------------------
     724             : 
     725             : // Analyze event.
     726             : 
     727             : bool CellJet::analyze(const Event& event, double eTjetMinIn,
     728             :   double coneRadiusIn, double eTseedIn, ostream& ) {
     729             : 
     730             :   // Input values. Initial values zero.
     731           0 :   eTjetMin   = eTjetMinIn;
     732           0 :   coneRadius = coneRadiusIn;
     733           0 :   eTseed     = eTseedIn;
     734           0 :   jets.resize(0);
     735           0 :   vector<SingleCell> cells;
     736             : 
     737             :   // Loop over desired particles in the event.
     738           0 :   for (int i = 0; i < event.size(); ++i)
     739           0 :   if (event[i].isFinal()) {
     740           0 :     if (select >  2 &&  event[i].isNeutral() ) continue;
     741           0 :     if (select == 2 && !event[i].isVisible() ) continue;
     742             : 
     743             :     // Find particle position in (eta, phi, pT) space.
     744           0 :     double etaNow = event[i].eta();
     745           0 :     if (abs(etaNow) > etaMax) continue;
     746           0 :     double phiNow = event[i].phi();
     747           0 :     double pTnow  = event[i].pT();
     748           0 :     int iEtaNow   = max(1, min( nEta, 1 + int(nEta * 0.5
     749           0 :       * (1. + etaNow / etaMax) ) ) );
     750           0 :     int iPhiNow   = max(1, min( nPhi, 1 + int(nPhi * 0.5
     751           0 :       * (1. + phiNow / M_PI) ) ) );
     752           0 :     int iCell     = nPhi * iEtaNow + iPhiNow;
     753             : 
     754             :     // Add pT to cell already hit or book a new cell.
     755             :     bool found = false;
     756           0 :     for (int j = 0; j < int(cells.size()); ++j) {
     757           0 :       if (iCell == cells[j].iCell) {
     758             :         found = true;
     759           0 :         ++cells[j].multiplicity;
     760           0 :         cells[j].eTcell += pTnow;
     761           0 :         continue;
     762             :       }
     763             :     }
     764           0 :     if (!found) {
     765           0 :       double etaCell = (etaMax / nEta) * (2 * iEtaNow - 1 - nEta);
     766           0 :       double phiCell = (M_PI / nPhi) * (2 * iPhiNow - 1 - nPhi);
     767           0 :       cells.push_back( SingleCell( iCell, etaCell, phiCell, pTnow, 1) );
     768           0 :     }
     769           0 :   }
     770             : 
     771             :   // Smear true bin content by calorimeter resolution.
     772           0 :   if (smear > 0 && rndmPtr != 0)
     773           0 :   for (int j = 0; j < int(cells.size()); ++j) {
     774           0 :     double eTeConv = (smear < 2) ? 1. : cosh( cells[j].etaCell );
     775           0 :     double eBef = cells[j].eTcell * eTeConv;
     776             :     double eAft = 0.;
     777           0 :     do eAft = eBef + resolution * sqrt(eBef) * rndmPtr->gauss();
     778           0 :     while (eAft < 0 || eAft > upperCut * eBef);
     779           0 :     cells[j].eTcell = eAft / eTeConv;
     780           0 :   }
     781             : 
     782             :   // Remove cells below threshold for seed or for use at all.
     783           0 :   for (int j = 0; j < int(cells.size()); ++j) {
     784           0 :     if (cells[j].eTcell < eTseed)    cells[j].canBeSeed = false;
     785           0 :     if (cells[j].eTcell < threshold) cells[j].isUsed    = true;
     786             :   }
     787             : 
     788             :   // Find seed cell: the one with highest pT of not yet probed ones.
     789           0 :   for ( ; ; ) {
     790             :     int jMax = 0;
     791             :     double eTmax = 0.;
     792           0 :     for (int j = 0; j < int(cells.size()); ++j)
     793           0 :     if (cells[j].canBeSeed && cells[j].eTcell > eTmax) {
     794             :       jMax = j;
     795           0 :       eTmax = cells[j].eTcell;
     796           0 :     }
     797             : 
     798             :     // If too small cell eT then done, else start new trial jet.
     799           0 :     if (eTmax < eTseed) break;
     800           0 :     double etaCenterNow = cells[jMax].etaCell;
     801           0 :     double phiCenterNow = cells[jMax].phiCell;
     802             :     double eTjetNow     = 0.;
     803             : 
     804             :     //  Sum up unused cells within required distance of seed.
     805           0 :     for (int j = 0; j < int(cells.size()); ++j) {
     806           0 :       if (cells[j].isUsed) continue;
     807           0 :       double dEta = abs( cells[j].etaCell - etaCenterNow );
     808           0 :       if (dEta > coneRadius) continue;
     809           0 :       double dPhi = abs( cells[j].phiCell - phiCenterNow );
     810           0 :       if (dPhi > M_PI) dPhi = 2. * M_PI - dPhi;
     811           0 :       if (dPhi > coneRadius) continue;
     812           0 :       if (pow2(dEta) + pow2(dPhi) > pow2(coneRadius)) continue;
     813           0 :       cells[j].isAssigned = true;
     814           0 :       eTjetNow += cells[j].eTcell;
     815           0 :     }
     816             : 
     817             :     // Reject cluster below minimum ET.
     818           0 :     if (eTjetNow < eTjetMin) {
     819           0 :       cells[jMax].canBeSeed = false;
     820           0 :       for (int j = 0; j < int(cells.size()); ++j)
     821           0 :         cells[j].isAssigned = false;
     822             : 
     823             :     // Else find new jet properties.
     824           0 :     } else {
     825             :       double etaWeightedNow = 0.;
     826             :       double phiWeightedNow = 0.;
     827             :       int multiplicityNow   = 0;
     828           0 :       Vec4 pMassiveNow;
     829           0 :       for (int j = 0; j < int(cells.size()); ++j)
     830           0 :       if (cells[j].isAssigned) {
     831           0 :         cells[j].canBeSeed  = false;
     832           0 :         cells[j].isUsed     = true;
     833           0 :         cells[j].isAssigned = false;
     834           0 :         etaWeightedNow += cells[j].eTcell * cells[j].etaCell;
     835           0 :         double phiCell = cells[j].phiCell;
     836           0 :         if (abs(phiCell - phiCenterNow) > M_PI)
     837           0 :           phiCell += (phiCenterNow > 0.) ? 2. * M_PI : -2. * M_PI;
     838           0 :         phiWeightedNow  += cells[j].eTcell * phiCell;
     839           0 :         multiplicityNow += cells[j].multiplicity;
     840           0 :         pMassiveNow     += cells[j].eTcell * Vec4(
     841           0 :            cos(cells[j].phiCell),  sin(cells[j].phiCell),
     842           0 :           sinh(cells[j].etaCell), cosh(cells[j].etaCell) );
     843           0 :       }
     844           0 :       etaWeightedNow /= eTjetNow;
     845           0 :       phiWeightedNow /= eTjetNow;
     846             : 
     847             :       // Bookkeep new jet, in decreasing ET order.
     848           0 :       jets.push_back( SingleCellJet( eTjetNow, etaCenterNow, phiCenterNow,
     849           0 :         etaWeightedNow, phiWeightedNow, multiplicityNow, pMassiveNow) );
     850           0 :       for (int i = int(jets.size()) - 1; i > 0; --i) {
     851           0 :         if (jets[i-1].eTjet > jets[i].eTjet) break;
     852           0 :         swap( jets[i-1], jets[i]);
     853             :       }
     854           0 :     }
     855           0 :   }
     856             : 
     857             :   // Done.
     858             :   return true;
     859           0 : }
     860             : 
     861             : //--------------------------------------------------------------------------
     862             : 
     863             : // Provide a listing of the info.
     864             : 
     865             : void CellJet::list(ostream& os) const {
     866             : 
     867             :   // Header.
     868           0 :   os << "\n --------  PYTHIA CellJet Listing, eTjetMin = "
     869           0 :      << fixed << setprecision(3) << setw(8) << eTjetMin
     870           0 :      << ", coneRadius = " << setw(5) << coneRadius
     871           0 :      << "  ------------------------------ \n \n  no    "
     872           0 :      << " eTjet  etaCtr  phiCtr   etaWt   phiWt mult      p_x"
     873           0 :      << "        p_y        p_z         e          m \n";
     874             : 
     875             :   // The jets.
     876           0 :   for (int i = 0; i < int(jets.size()); ++i) {
     877           0 :     os << setw(4) << i << setw(10) << jets[i].eTjet << setw(8)
     878           0 :        << jets[i].etaCenter << setw(8) << jets[i].phiCenter << setw(8)
     879           0 :        << jets[i].etaWeighted << setw(8) << jets[i].phiWeighted
     880           0 :        << setw(5) << jets[i].multiplicity << setw(11)
     881           0 :        << jets[i].pMassive.px() << setw(11) << jets[i].pMassive.py()
     882           0 :        << setw(11) << jets[i].pMassive.pz() << setw(11)
     883           0 :        << jets[i].pMassive.e() << setw(11)
     884           0 :        << jets[i].pMassive.mCalc() << "\n";
     885             :   }
     886             : 
     887             :   // Listing finished.
     888           0 :   os << "\n --------  End PYTHIA CellJet Listing  ------------------"
     889           0 :      << "-------------------------------------------------"
     890           0 :      << endl;
     891           0 : }
     892             : 
     893             : //==========================================================================
     894             : 
     895             : // SlowJet class.
     896             : // This class performs clustering in (y, phi, pT) space.
     897             : 
     898             : //--------------------------------------------------------------------------
     899             : 
     900             : // Constants: could be changed here if desired, but normally should not.
     901             : // These are of technical nature, as described for each.
     902             : 
     903             : // Minimum number of particles to perform study.
     904             : const int    SlowJet::TIMESTOPRINT = 1;
     905             : 
     906             : // Assume the pi+- mass for all particles, except the photon, in one option.
     907             : const double SlowJet::PIMASS       = 0.13957;
     908             : 
     909             : // Small number to avoid division by zero.
     910             : const double SlowJet::TINY         = 1e-20;
     911             : 
     912             : //--------------------------------------------------------------------------
     913             : 
     914             : // Set up list of particles to analyze, and initial distances.
     915             : 
     916             : bool SlowJet::setup(const Event& event) {
     917             : 
     918             :   // Initial values zero.
     919           0 :   clusters.resize(0);
     920           0 :   jets.resize(0);
     921           0 :   jtSize = 0;
     922             : 
     923             :   // Loop over final particles in the event.
     924           0 :   Vec4   pTemp;
     925           0 :   double mTemp, pT2Temp, mTTemp, yTemp, phiTemp;
     926           0 :   for (int i = 0; i < event.size(); ++i)
     927           0 :   if (event[i].isFinal()) {
     928             : 
     929             :     // Always apply selection options for visible or charged particles.
     930           0 :     if      (chargedOnly &&  event[i].isNeutral() ) continue;
     931           0 :     else if (visibleOnly && !event[i].isVisible() ) continue;
     932             : 
     933             :     // Normally use built-in selection machinery.
     934           0 :     if (noHook) {
     935             : 
     936             :       // Pseudorapidity cut to describe detector range.
     937           0 :       if (cutInEta    && abs(event[i].eta()) > etaMax) continue;
     938             : 
     939             :       // Optionally modify mass and energy.
     940           0 :       pTemp = event[i].p();
     941           0 :       mTemp = event[i].m();
     942           0 :       if (modifyMass) {
     943           0 :         mTemp = (massSet == 0 || event[i].id() == 22) ? 0. : PIMASS;
     944           0 :         pTemp.e( sqrt(pTemp.pAbs2() + mTemp*mTemp) );
     945           0 :       }
     946             : 
     947             :     // Alternatively pass info to SlowJetHook for decision.
     948             :     // User can also modify pTemp and mTemp.
     949             :     } else {
     950           0 :       pTemp = event[i].p();
     951           0 :       mTemp = event[i].m();
     952           0 :       if ( !sjHookPtr->include( i, event, pTemp, mTemp) ) continue;
     953             :     }
     954             : 
     955             :     // Store particle momentum, including some derived quantities.
     956           0 :     pT2Temp  = max( TINY*TINY, pTemp.pT2());
     957           0 :     mTTemp  = sqrt( mTemp*mTemp + pT2Temp);
     958           0 :     yTemp   = (pTemp.pz() > 0)
     959           0 :             ? log( max( TINY, pTemp.e() + pTemp.pz() ) / mTTemp )
     960           0 :             : log( mTTemp / max( TINY, pTemp.e() - pTemp.pz() ) );
     961           0 :     phiTemp = pTemp.phi();
     962           0 :     clusters.push_back( SingleSlowJet(pTemp, pT2Temp, yTemp, phiTemp, i) );
     963           0 :   }
     964           0 :   origSize = clusters.size();
     965             : 
     966             :   // Done here for FJcore machinery.
     967           0 :   if (useFJcore) return true;
     968             : 
     969             :   // Resize arrays to store distances between clusters.
     970           0 :   clSize = origSize;
     971           0 :   clLast = clSize - 1;
     972           0 :   diB.resize(clSize);
     973           0 :   dij.resize(clSize * (clSize - 1) / 2);
     974             : 
     975             :   // Loop through particles and find distance to beams.
     976           0 :   for (int i = 0; i < clSize; ++i) {
     977           0 :     if (isAnti)    diB[i] = 1. / clusters[i].pT2;
     978           0 :     else if (isKT) diB[i] = clusters[i].pT2;
     979           0 :     else           diB[i] = 1.;
     980             : 
     981             :     // Loop through pairs and find relative distance.
     982           0 :     for (int j = 0; j < i; ++j) {
     983           0 :       dPhi = abs( clusters[i].phi - clusters[j].phi );
     984           0 :       if (dPhi > M_PI) dPhi = 2. * M_PI - dPhi;
     985           0 :       dijTemp = (useStandardR)
     986           0 :               ? (pow2( clusters[i].y - clusters[j].y) + dPhi*dPhi) / R2
     987           0 :          : 2. * (cosh( clusters[i].y - clusters[j].y) - cos(dPhi)) / R2 ;
     988           0 :       if (isAnti)    dijTemp /= max(clusters[i].pT2, clusters[j].pT2);
     989           0 :       else if (isKT) dijTemp *= min(clusters[i].pT2, clusters[j].pT2);
     990           0 :       dij[i*(i-1)/2 + j] = dijTemp;
     991             : 
     992             :     // End of original-particle loops.
     993             :     }
     994             :   }
     995             : 
     996             :   // Find first particle pair to join.
     997           0 :   findNext();
     998             : 
     999             :   // Done.
    1000           0 :   return true;
    1001             : 
    1002           0 : }
    1003             : 
    1004             : //--------------------------------------------------------------------------
    1005             : 
    1006             : // Do one recombination step, possibly giving a jet.
    1007             : 
    1008             : bool SlowJet::doStep() {
    1009             : 
    1010             :   // Fail if using FJcore or if no possibility to take a step.
    1011           0 :   if (useFJcore) return false;
    1012           0 :   if (clSize == 0) return false;
    1013             : 
    1014             :   // When distance to beam is smallest the cluster is promoted to jet.
    1015           0 :   if (jMin == -1) {
    1016             : 
    1017             :     // Store new jet if its pT is above pTMin.
    1018           0 :     if (clusters[iMin].pT2 > pT2jetMin) {
    1019           0 :       jets.push_back( SingleSlowJet(clusters[iMin]) );
    1020           0 :       ++jtSize;
    1021             : 
    1022             :       // Order jets in decreasing pT.
    1023           0 :       for (int i = jtSize - 1; i > 0; --i) {
    1024           0 :         if (jets[i].pT2 < jets[i-1].pT2) break;
    1025           0 :         swap( jets[i], jets[i-1]);
    1026             :       }
    1027           0 :     }
    1028             :   }
    1029             : 
    1030             :   // When distance between two clusters is smallest they are joined.
    1031             :   else {
    1032             : 
    1033             :     // Add iMin cluster to jMin.
    1034           0 :     clusters[jMin].p  += clusters[iMin].p;
    1035           0 :     clusters[jMin].pT2 = max( TINY*TINY, clusters[jMin].p.pT2());
    1036           0 :     double mTTemp  = sqrt(clusters[jMin].p.m2Calc() + clusters[jMin].pT2);
    1037           0 :     clusters[jMin].y = (clusters[jMin].p.pz() > 0)
    1038           0 :       ? log( max( TINY, clusters[jMin].p.e() + clusters[jMin].p.pz() )
    1039           0 :       / mTTemp ) : log( mTTemp
    1040           0 :       / max( TINY, clusters[jMin].p.e() - clusters[jMin].p.pz() ) );
    1041           0 :     clusters[jMin].phi = clusters[jMin].p.phi();
    1042           0 :     clusters[jMin].mult += clusters[iMin].mult;
    1043           0 :     clusters[jMin].idx.insert(clusters[iMin].idx.begin(),
    1044           0 :                               clusters[iMin].idx.end());
    1045             : 
    1046             :     // Update distances for and to new jMin.
    1047           0 :     if (isAnti)    diB[jMin] = 1. / clusters[jMin].pT2;
    1048           0 :     else if (isKT) diB[jMin] = clusters[jMin].pT2;
    1049           0 :     else           diB[jMin] = 1.;
    1050           0 :     for (int i = 0; i < clSize; ++i) if (i != jMin && i != iMin) {
    1051           0 :       dPhi = abs( clusters[i].phi - clusters[jMin].phi );
    1052           0 :       if (dPhi > M_PI) dPhi = 2. * M_PI - dPhi;
    1053           0 :       dijTemp = (useStandardR)
    1054           0 :               ? (pow2( clusters[i].y - clusters[jMin].y) + dPhi*dPhi) / R2
    1055           0 :          : 2. * (cosh( clusters[i].y - clusters[jMin].y) - cos(dPhi)) / R2 ;
    1056           0 :       if (isAnti)    dijTemp /= max(clusters[i].pT2, clusters[jMin].pT2);
    1057           0 :       else if (isKT) dijTemp *= min(clusters[i].pT2, clusters[jMin].pT2);
    1058           0 :       if (i < jMin) dij[jMin*(jMin-1)/2 + i] = dijTemp;
    1059           0 :       else          dij[i*(i-1)/2 + jMin]    = dijTemp;
    1060             :     }
    1061             :   }
    1062             : 
    1063             :   // Move up last cluster and distances to vacated position iMin.
    1064           0 :   if (iMin < clLast) {
    1065           0 :     clusters[iMin] = clusters[clLast];
    1066           0 :     diB[iMin] = diB[clLast];
    1067           0 :     for (int j = 0; j < iMin; ++j)
    1068           0 :       dij[iMin*(iMin-1)/2 + j] = dij[clLast*(clLast-1)/2 + j];
    1069           0 :     for (int j = iMin + 1; j < clLast; ++j)
    1070           0 :       dij[j*(j-1)/2 + iMin] = dij[clLast*(clLast-1)/2 + j];
    1071           0 :   }
    1072             : 
    1073             :   // Shrink cluster list by one.
    1074           0 :   clusters.pop_back();
    1075           0 :   --clSize;
    1076           0 :   --clLast;
    1077             : 
    1078             :   // Find next cluster pair to join.
    1079           0 :   findNext();
    1080             : 
    1081             :   // Done.
    1082           0 :   return true;
    1083             : 
    1084           0 : }
    1085             : 
    1086             : //--------------------------------------------------------------------------
    1087             : 
    1088             : // Provide a listing of the info.
    1089             : 
    1090             : void SlowJet::list(bool listAll, ostream& os) const {
    1091             : 
    1092             :   // Header.
    1093           0 :   if (useFJcore) os << "\n --  PYTHIA SlowJet(fjcore) Listing, p = ";
    1094           0 :   else           os << "\n --  PYTHIA SlowJet(native) Listing, p = ";
    1095           0 :   os << setw(2) << power << ", R = " << fixed << setprecision(3) << setw(5)
    1096           0 :      << R << ", pTjetMin =" << setw(8) << pTjetMin << ", etaMax = "
    1097           0 :      << setw(6) << etaMax << "  -- \n \n   no      pTjet      y       phi"
    1098           0 :      << "   mult      p_x        p_y        p_z         e          m \n";
    1099             : 
    1100             :   // The jets.
    1101           0 :   for (int i = 0; i < jtSize; ++i) {
    1102           0 :     os << setw(5) << i << setw(11) << sqrt(jets[i].pT2) << setw(9)
    1103           0 :        << jets[i].y << setw(9) << jets[i].phi << setw(6)
    1104           0 :        << jets[i].mult << setw(11) << jets[i].p.px() << setw(11)
    1105           0 :        << jets[i].p.py() << setw(11) << jets[i].p.pz() << setw(11)
    1106           0 :        << jets[i].p.e() << setw(11) << jets[i].p.mCalc() << "\n";
    1107             :   }
    1108             : 
    1109             :   // Optionally list also clusters not yet jets.
    1110           0 :   if (listAll && clSize > 0) {
    1111           0 :     os << " --------  Below this line follows remaining clusters,"
    1112           0 :        << " still pT-unordered  -------------------\n";
    1113           0 :     for (int i = 0; i < clSize; ++i) {
    1114           0 :       os << setw(5) << i + jtSize << setw(11) << sqrt(clusters[i].pT2)
    1115           0 :          << setw(9) << clusters[i].y << setw(9) << clusters[i].phi
    1116           0 :          << setw(6) << clusters[i].mult << setw(11) << clusters[i].p.px()
    1117           0 :          << setw(11) << clusters[i].p.py() << setw(11) << clusters[i].p.pz()
    1118           0 :          << setw(11) << clusters[i].p.e() << setw(11)
    1119           0 :          << clusters[i].p.mCalc() << "\n";
    1120             :     }
    1121           0 :   }
    1122             : 
    1123             :   // Listing finished.
    1124           0 :   os << "\n --------  End PYTHIA SlowJet Listing  ------------------"
    1125           0 :      << "--------------------------------------" << endl;
    1126             : 
    1127           0 : }
    1128             : 
    1129             : //--------------------------------------------------------------------------
    1130             : 
    1131             : // Find next cluster pair to join.
    1132             : 
    1133             : void SlowJet::findNext() {
    1134             : 
    1135             :   // Find smallest of diB, dij.
    1136           0 :   if (clSize > 0) {
    1137           0 :     iMin =  0;
    1138           0 :     jMin = -1;
    1139           0 :     dMin = diB[0];
    1140           0 :     for (int i = 1; i < clSize; ++i) {
    1141           0 :       if (diB[i] < dMin) {
    1142           0 :         iMin = i;
    1143           0 :         jMin = -1;
    1144           0 :         dMin = diB[i];
    1145           0 :       }
    1146           0 :       for (int j = 0; j < i; ++j) {
    1147           0 :         if (dij[i*(i-1)/2 + j] < dMin) {
    1148           0 :           iMin = i;
    1149           0 :           jMin = j;
    1150           0 :           dMin = dij[i*(i-1)/2 + j];
    1151           0 :         }
    1152             :       }
    1153             :     }
    1154             : 
    1155             :   // If no clusters left then instead default values.
    1156           0 :   } else {
    1157           0 :     iMin = -1;
    1158           0 :     jMin = -1;
    1159           0 :     dMin = 0.;
    1160             :   }
    1161             : 
    1162           0 : }
    1163             : 
    1164             : //--------------------------------------------------------------------------
    1165             : 
    1166             : // Use FJcore interface to perform clustering.
    1167             : 
    1168             : bool SlowJet::clusterFJ() {
    1169             : 
    1170             :   // Read in input configuration of particles.
    1171           0 :   vector<fjcore::PseudoJet> inFJ;
    1172           0 :   for (int i = 0; i < int(clusters.size()); ++i) {
    1173           0 :     inFJ.push_back( fjcore::PseudoJet( clusters[i].p.px(),
    1174           0 :       clusters[i].p.py(),  clusters[i].p.pz(),  clusters[i].p.e() ) );
    1175           0 :     set<int>::iterator idxTmp = clusters[i].idx.begin();
    1176           0 :     inFJ[i].set_user_index( *idxTmp);
    1177           0 :   }
    1178             : 
    1179             :   // Create a jet definition = jet algorithm + radius parameter.
    1180             :   fjcore::JetAlgorithm  jetAlg = fjcore::cambridge_algorithm;
    1181           0 :   if (isAnti)           jetAlg = fjcore::antikt_algorithm;
    1182           0 :   if (isKT)             jetAlg = fjcore::kt_algorithm;
    1183           0 :   fjcore::JetDefinition jetDef( jetAlg, R);
    1184             : 
    1185             :   // Run the jet clustering with the above jet definition.
    1186           0 :   fjcore::ClusterSequence clust_seq( inFJ, jetDef);
    1187             : 
    1188             :   // Get the resulting jets above pTmin, ordered in pT.
    1189           0 :   vector<fjcore::PseudoJet> outFJ
    1190           0 :     = sorted_by_pt( clust_seq.inclusive_jets( pTjetMin) );
    1191             : 
    1192             :   // Store the FJcore output in the standard SlowJet format.
    1193           0 :   Vec4   pTemp;
    1194             :   double pT2Temp, yTemp, phiTemp;
    1195           0 :   for (int i = 0; i < int(outFJ.size()); ++i) {
    1196           0 :     pTemp = Vec4( outFJ[i].px(), outFJ[i].py(), outFJ[i].pz(), outFJ[i].e() );
    1197           0 :     pT2Temp = outFJ[i].pt2();
    1198           0 :     yTemp   = outFJ[i].rap();
    1199           0 :     phiTemp = outFJ[i].phi_std();
    1200           0 :     jets.push_back( SingleSlowJet(pTemp, pT2Temp, yTemp, phiTemp, 0) );
    1201             : 
    1202             :     // Also find constituents of jet.
    1203           0 :     jets[i].idx.clear();
    1204           0 :     vector<fjcore::PseudoJet> constFJ = outFJ[i].constituents();
    1205           0 :     for (int j = 0; j < int(constFJ.size()); ++j)
    1206           0 :       jets[i].idx.insert( constFJ[j].user_index() );
    1207           0 :     jets[i].mult = constFJ.size();
    1208           0 :   }
    1209             : 
    1210             :   // Set counters and some dummy (for FJcore) information.
    1211           0 :   clSize = 0;
    1212           0 :   clLast = 0;
    1213           0 :   jtSize = outFJ.size();
    1214           0 :   iMin   = -1;
    1215           0 :   jMin   = -1;
    1216           0 :   dMin   = 0.;
    1217             : 
    1218             :   // Done.
    1219             :   return true;
    1220             : 
    1221           0 : }
    1222             : 
    1223             : //==========================================================================
    1224             : 
    1225             : } // end namespace Pythia8

Generated by: LCOV version 1.11