1 // Analysis.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2008 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.
6 // Function definitions (not found in the header) for the
7 // Sphericity, Thrust, ClusJet and CellJet classes.
13 //**************************************************************************
16 // This class finds sphericity-related properties of an event.
20 // Constants: could be changed here if desired, but normally should not.
21 // These are of technical nature, as described for each.
23 // Minimum number of particles to perform study.
24 const int Sphericity::NSTUDYMIN = 2;
26 // Maximum number of times that an error warning will be printed.
27 const int Sphericity::TIMESTOPRINT = 1;
29 // Assign mimimum squared momentum in weight to avoid division by zero.
30 const double Sphericity::P2MIN = 1e-20;
32 // Second eigenvalue not too low or not possible to find eigenvectors.
33 const double Sphericity::EIGENVALUEMIN = 1e-10;
39 bool Sphericity::analyze(const Event& event, ostream& os) {
41 // Initial values, tensor and counters zero.
42 eVal1 = eVal2 = eVal3 = 0.;
43 eVec1 = eVec2 = eVec3 = 0.;
45 for (int j = 1; j < 4; ++j)
46 for (int k = j; k < 4; ++k) tt[j][k] = 0.;
50 // Loop over desired particles in the event.
51 for (int i = 0; i < event.size(); ++i)
52 if (event[i].isFinal()) {
53 if (select > 2 && event[i].isNeutral() ) continue;
54 if (select == 2 && !event[i].isVisible() ) continue;
57 // Calculate matrix to be diagonalized. Special cases for speed.
59 pNow[1] = event[i].px();
60 pNow[2] = event[i].py();
61 pNow[3] = event[i].pz();
62 double p2Now = pNow[1]*pNow[1] + pNow[2]*pNow[2] + pNow[3]*pNow[3];
64 if (powerInt == 1) pWeight = 1. / sqrt(max(P2MIN, p2Now));
65 else if (powerInt == 0) pWeight = pow( max(P2MIN, p2Now), powerMod);
66 for (int j = 1; j < 4; ++j)
67 for (int k = j; k < 4; ++k) tt[j][k] += pWeight * pNow[j] * pNow[k];
68 denom += pWeight * p2Now;
71 // Very low multiplicities (0 or 1) not considered.
72 if (nStudy < NSTUDYMIN) {
73 if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
74 "Sphericity::analyze: too few particles" << endl;
79 // Normalize tensor to trace = 1.
80 for (int j = 1; j < 4; ++j)
81 for (int k = j; k < 4; ++k) tt[j][k] /= denom;
83 // Find eigenvalues to matrix (third degree equation).
84 double qCoef = ( tt[1][1] * tt[2][2] + tt[1][1] * tt[3][3]
85 + tt[2][2] * tt[3][3] - pow2(tt[1][2]) - pow2(tt[1][3])
86 - pow2(tt[2][3]) ) / 3. - 1./9.;
87 double qCoefRt = sqrt( -qCoef);
88 double rCoef = -0.5 * ( qCoef + 1./9. + tt[1][1] * pow2(tt[2][3])
89 + tt[2][2] * pow2(tt[1][3]) + tt[3][3] * pow2(tt[1][2])
90 - tt[1][1] * tt[2][2] * tt[3][3] )
91 + tt[1][2] * tt[1][3] * tt[2][3] + 1./27.;
92 double pTemp = max( min( rCoef / pow3(qCoefRt), 1.), -1.);
93 double pCoef = cos( acos(pTemp) / 3.);
94 double pCoefRt = sqrt( 3. * (1. - pow2(pCoef)) );
95 eVal1 = 1./3. + qCoefRt * max( 2. * pCoef, pCoefRt - pCoef);
96 eVal3 = 1./3. + qCoefRt * min( 2. * pCoef, -pCoefRt - pCoef);
97 eVal2 = 1. - eVal1 - eVal3;
99 // Begin find first and last eigenvector.
100 for (int iVal = 0; iVal < 2; ++iVal) {
101 double eVal = (iVal == 0) ? eVal1 : eVal3;
103 // If all particles are back-to-back then only first axis meaningful.
104 if (iVal > 1 && eVal2 < EIGENVALUEMIN) {
105 if (nBack < TIMESTOPRINT) os << " PYTHIA Error in "
106 "Sphericity::analyze: particles too back-to-back" << endl;
111 // Set up matrix to diagonalize.
113 for (int j = 1; j < 4; ++j) {
114 dd[j][j] = tt[j][j] - eVal;
115 for (int k = j + 1; k < 4; ++k) {
121 // Find largest = pivotal element in matrix.
125 for (int j = 1; j < 4; ++j)
126 for (int k = 1; k < 4; ++k)
127 if (abs(dd[j][k]) > ddMax) {
130 ddMax = abs(dd[j][k]);
133 // Subtract one row from the other two; find new largest element.
136 for (int j = 1; j < 4; ++j)
138 double pivot = dd[j][kMax] / dd[jMax][kMax];
139 for (int k = 1; k < 4; ++k) {
140 dd[j][k] -= pivot * dd[jMax][k];
141 if (abs(dd[j][k]) > ddMax) {
143 ddMax = abs(dd[j][k]);
148 // Construct eigenvector. Normalize to unit length. Random sign.
149 int k1 = kMax + 1; if (k1 > 3) k1 -= 3;
150 int k2 = kMax + 2; if (k2 > 3) k2 -= 3;
152 eVec[k1] = -dd[jMax2][k2];
153 eVec[k2] = dd[jMax2][k1];
154 eVec[kMax] = (dd[jMax][k1] * dd[jMax2][k2]
155 - dd[jMax][k2] * dd[jMax2][k1]) / dd[jMax][kMax];
156 double length = sqrt( pow2(eVec[1]) + pow2(eVec[2])
158 if (Rndm::flat() > 0.5) length = -length;
160 // Store eigenvectors.
161 if (iVal == 0) eVec1 = Vec4( eVec[1] / length,
162 eVec[2] / length, eVec[3] / length, 0.);
163 else eVec3 = Vec4( eVec[1] / length,
164 eVec[2] / length, eVec[3] / length, 0.);
167 // Middle eigenvector is orthogonal to the other two.
168 eVec2 = cross3( eVec1, eVec3);
169 if (Rndm::flat() > 0.5) eVec2 = -eVec2;
178 // Provide a listing of the info.
180 void Sphericity::list(ostream& os) {
183 os << "\n -------- PYTHIA Sphericity Listing -------- \n";
184 if (powerInt !=2) os << " Nonstandard momentum power = "
185 << fixed << setprecision(3) << setw(6) << power << "\n";
186 os << "\n no lambda e_x e_y e_z \n";
188 // The three eigenvalues and eigenvectors.
189 os << setprecision(5);
190 os << " 1" << setw(11) << eVal1 << setw(11) << eVec1.px()
191 << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n";
192 os << " 2" << setw(11) << eVal2 << setw(11) << eVec2.px()
193 << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n";
194 os << " 3" << setw(11) << eVal3 << setw(11) << eVec3.px()
195 << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n";
198 os << "\n -------- End PYTHIA Sphericity Listing ----" << endl;
203 //**************************************************************************
206 // This class finds thrust-related properties of an event.
210 // Constants: could be changed here if desired, but normally should not.
211 // These are of technical nature, as described for each.
213 // Minimum number of particles to perform study.
214 const int Thrust::NSTUDYMIN = 2;
216 // Maximum number of times that an error warning will be printed.
217 const int Thrust::TIMESTOPRINT = 1;
219 // Major not too low or not possible to find major axis.
220 const double Thrust::MAJORMIN = 1e-10;
226 bool Thrust::analyze(const Event& event, ostream& os) {
228 // Initial values and counters zero.
229 eVal1 = eVal2 = eVal3 = 0.;
230 eVec1 = eVec2 = eVec3 = 0.;
233 Vec4 pSum, nRef, pPart, pFull, pMax;
235 // Loop over desired particles in the event.
236 for (int i = 0; i < event.size(); ++i)
237 if (event[i].isFinal()) {
238 if (select > 2 && event[i].isNeutral() ) continue;
239 if (select == 2 && !event[i].isVisible() ) continue;
242 // Store momenta. Use energy component for absolute momentum.
243 Vec4 pNow = event[i].p();
246 pOrder.push_back(pNow);
249 // Very low multiplicities (0 or 1) not considered.
250 if (nStudy < NSTUDYMIN) {
251 if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
252 "Thrust::analyze: too few particles" << endl;
257 // Try all combinations of reference vector orthogonal to two particles.
258 for (int i1 = 0; i1 < nStudy - 1; ++i1)
259 for (int i2 = i1 + 1; i2 < nStudy; ++i2) {
260 nRef = cross3( pOrder[i1], pOrder[i2]);
264 // Add all momenta with sign; two choices for each reference particle.
265 for (int i = 0; i < nStudy; ++i) if (i != i1 && i != i2) {
266 if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i];
267 else pPart -= pOrder[i];
269 for (int j = 0; j < 4; ++j) {
270 if (j == 0) pFull = pPart + pOrder[i1] + pOrder[i2];
271 else if (j == 1) pFull = pPart + pOrder[i1] - pOrder[i2];
272 else if (j == 2) pFull = pPart - pOrder[i1] + pOrder[i2];
273 else pFull = pPart - pOrder[i1] - pOrder[i2];
274 pFull.e(pFull.pAbs());
275 if (pFull.e() > pMax.e()) pMax = pFull;
279 // Maximum gives thrust axis and value.
280 eVal1 = pMax.e() / pSum.e();
281 eVec1 = pMax / pMax.e();
284 // Subtract momentum along thrust axis.
286 for (int i = 0; i < nStudy; ++i) {
287 pOrder[i] -= dot3( eVec1, pOrder[i]) * eVec1;
288 pOrder[i].e(pOrder[i].pAbs());
289 pAbsSum += pOrder[i].e();
292 // Simpleminded major and minor axes if too little transverse left.
293 if (pAbsSum < MAJORMIN * pSum.e()) {
294 if ( abs(eVec1.pz()) > 0.5) eVec2 = Vec4( 1., 0., 0., 0.);
295 else eVec2 = Vec4( 0., 0., 1., 0.);
296 eVec2 -= dot3( eVec1, eVec2) * eVec1;
297 eVec2 /= eVec2.pAbs();
298 eVec3 = cross3( eVec1, eVec2);
302 // Try all reference vectors orthogonal to one particles.
304 for (int i1 = 0; i1 < nStudy; ++i1) {
305 nRef = cross3( pOrder[i1], eVec1);
309 // Add all momenta with sign; two choices for each reference particle.
310 for (int i = 0; i < nStudy; ++i) if (i != i1) {
311 if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i];
312 else pPart -= pOrder[i];
314 pFull = pPart + pOrder[i1];
315 pFull.e(pFull.pAbs());
316 if (pFull.e() > pMax.e()) pMax = pFull;
317 pFull = pPart - pOrder[i1];
318 pFull.e(pFull.pAbs());
319 if (pFull.e() > pMax.e()) pMax = pFull;
322 // Maximum gives major axis and value.
323 eVal2 = pMax.e() / pSum.e();
324 eVec2 = pMax / pMax.e();
327 // Orthogonal direction gives minor axis, and from there value.
328 eVec3 = cross3( eVec1, eVec2);
330 for (int i = 0; i < nStudy; ++i)
331 pAbsSum += abs( dot3(eVec3, pOrder[i]) );
332 eVal3 = pAbsSum / pSum.e();
341 // Provide a listing of the info.
343 void Thrust::list(ostream& os) {
346 os << "\n -------- PYTHIA Thrust Listing ------------ \n"
347 << "\n value e_x e_y e_z \n";
349 // The thrust, major and minor values and related event axes.
350 os << setprecision(5);
351 os << " Thr" << setw(11) << eVal1 << setw(11) << eVec1.px()
352 << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n";
353 os << " Maj" << setw(11) << eVal2 << setw(11) << eVec2.px()
354 << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n";
355 os << " Min" << setw(11) << eVal3 << setw(11) << eVec3.px()
356 << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n";
359 os << "\n -------- End PYTHIA Thrust Listing --------" << endl;
363 //**************************************************************************
365 // SingleClusterJet class.
366 // Simple helper class to ClusterJet for a jet and its contents.
370 // Constants: could be changed here if desired, but normally should not.
371 // These are of technical nature, as described for each.
373 // Assign minimal pAbs to avoid division by zero.
374 const double SingleClusterJet::PABSMIN = 1e-10;
378 // Distance measures between two SingleClusterJet objects.
380 double dist2Fun(int measure, const SingleClusterJet& j1,
381 const SingleClusterJet& j2) {
384 if (measure == 2) return 2. * j1.pJet.e() * j2.pJet.e()
385 * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) );
388 if (measure == 3) return 2. * pow2( min( j1.pJet.e(), j2.pJet.e() ) )
389 * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) );
391 // Lund distance; "default".
392 return (j1.pAbs * j2.pAbs - dot3( j1.pJet, j2.pJet))
393 * 2. * j1.pAbs * j2.pAbs / pow2(j1.pAbs + j2.pAbs);
397 //**************************************************************************
400 // This class performs a jet clustering according to different
401 // distance measures: Lund, JADE or Durham.
405 // Constants: could be changed here if desired, but normally should not.
406 // These are of technical nature, as described for each.
408 // Maximum number of times that an error warning will be printed.
409 const int ClusterJet::TIMESTOPRINT = 1;
411 // Assign minimal pAbs to avoid division by zero.
412 const double ClusterJet::PABSMIN = 1e-10;
414 // Initial pT/m preclustering scale as fraction of clustering one.
415 const double ClusterJet::PRECLUSTERFRAC = 0.1;
417 // Step with which pT/m is reduced if preclustering gives too few jets.
418 const double ClusterJet::PRECLUSTERSTEP = 0.8;
424 bool ClusterJet::analyze(const Event& event, double yScaleIn,
425 double pTscaleIn, int nJetMinIn, int nJetMaxIn, ostream& os) {
427 // Input values. Initial values zero.
436 // Loop over desired particles in the event.
437 for (int i = 0; i < event.size(); ++i)
438 if (event[i].isFinal()) {
439 if (select > 2 && event[i].isNeutral() ) continue;
440 if (select == 2 && !event[i].isVisible() ) continue;
442 // Store them, possibly with modified mass => new energy.
443 Vec4 pTemp = event[i].p();
444 if (massSet == 0 || massSet == 1) {
445 double mTemp = (massSet == 0 || event[i].id() == 22)
447 double eTemp = sqrt(pTemp.pAbs2() + pow2(mTemp));
450 particles.push_back( SingleClusterJet(pTemp, i) );
454 // Very low multiplicities not considered.
455 nParticles = particles.size();
456 if (nParticles < nJetMin) {
457 if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " <<
458 "ClusterJet::analyze: too few particles" << endl;
463 // Squared maximum distance in GeV^2 for joining.
464 double p2Sum = pSum.m2Calc();
465 dist2Join = max( yScale * p2Sum, pow2(pTscale));
466 dist2BigMin = 2. * max( dist2Join, p2Sum);
468 // Do preclustering if desired and possible.
469 if (doPrecluster && nParticles > nJetMin + 2) {
471 if (doReassign) reassign();
474 // If no preclustering: each particle is a starting jet.
475 else for (int i = 0; i < nParticles; ++i) {
476 jets.push_back( SingleClusterJet(particles[i]) );
477 particles[i].daughter = i;
480 // Begin iteration towards fewer jets.
483 // Find the two closest jets.
484 double dist2Min = dist2BigMin;
487 for (int j = 0; j < int(jets.size()) - 1; ++j)
488 for (int k = j + 1; k < int(jets.size()); ++k) {
489 double dist2 = dist2Fun( measure, jets[j], jets[k]);
490 if (dist2 < dist2Min) {
497 // Stop if no pair below cut and not more jets than allowed.
498 if ( dist2Min > dist2Join
499 && (nJetMax < nJetMin || int(jets.size()) <= nJetMax) ) break;
501 // Join two closest jets.
502 jets[jMin].pJet += jets[kMin].pJet;
503 jets[jMin].pAbs = max( PABSMIN, jets[jMin].pJet.pAbs());
504 jets[jMin].multiplicity += jets[kMin].multiplicity;
505 for (int i = 0; i < nParticles; ++i)
506 if (particles[i].daughter == kMin) particles[i].daughter = jMin;
508 // Move up last jet to empty slot to shrink list.
509 jets[kMin] = jets.back();
511 int iEnd = jets.size();
512 for (int i = 0; i < nParticles; ++i)
513 if (particles[i].daughter == iEnd) particles[i].daughter = kMin;
515 // Do reassignments of particles to nearest jet if desired.
516 if (doReassign) reassign();
518 // Stop if reached minimum allowed number of jets. Else continue.
519 if (int(jets.size()) <= nJetMin) break;
522 // Order jets in decreasing energy.
523 for (int j = 0; j < int(jets.size()) - 1; ++j)
524 for (int k = int(jets.size()) - 1; k > j; --k)
525 if (jets[k].pJet.e() > jets[k-1].pJet.e()) {
526 swap( jets[k], jets[k-1]);
527 for (int i = 0; i < nParticles; ++i) {
528 if (particles[i].daughter == k) particles[i].daughter = k-1;
529 else if (particles[i].daughter == k-1) particles[i].daughter = k;
539 // Precluster nearby particles to save computer time.
541 void ClusterJet::precluster() {
543 // Begin iteration over preclustering scale.
544 distPre = PRECLUSTERFRAC * sqrt(dist2Join) / PRECLUSTERSTEP;
546 distPre *= PRECLUSTERSTEP;
547 dist2Pre = pow2(distPre);
548 for (int i = 0; i < nParticles; ++i) {
549 particles[i].daughter = -1;
550 particles[i].isAssigned = false;
553 // Sum up low-momentum region. Jet if enough momentum.
556 for (int i = 0; i < nParticles; ++i)
557 if (particles[i].pAbs < 2. * distPre) {
558 pCentral += particles[i].pJet;
559 multCentral += particles[i].multiplicity;
560 particles[i].isAssigned = true;
562 if (pCentral.pAbs() > 2. * distPre) {
563 jets.push_back( SingleClusterJet(pCentral) );
564 jets.back().multiplicity = multCentral;
565 for (int i = 0; i < nParticles; ++i)
566 if (particles[i].isAssigned) particles[i].daughter = 0;
569 // Find fastest remaining particle until none left.
573 for (int i = 0; i < nParticles; ++i)
574 if ( !particles[i].isAssigned && particles[i].pAbs > pMax) {
576 pMax = particles[i].pAbs;
578 if (iMax == -1) break;
580 // Sum up precluster around it according to distance function.
584 for (int i = 0; i < nParticles; ++i)
585 if ( !particles[i].isAssigned) {
586 double dist2 = dist2Fun( measure, particles[iMax],
588 if (dist2 < dist2Pre) {
589 pPre += particles[i].pJet;
591 particles[i].isAssigned = true;
592 particles[i].daughter = jets.size();
595 jets.push_back( SingleClusterJet(pPre) );
596 jets.back().multiplicity = multPre;
598 // Decide whether sensible starting configuration or iterate.
599 if (int(jets.size()) + nRemain < nJetMin) break;
601 if (int(jets.size()) >= nJetMin) break;
608 // Reassign particles to nearest jet to correct misclustering.
610 void ClusterJet::reassign() {
612 // Reset clustered momenta.
613 for (int j = 0; j < int(jets.size()); ++j) {
615 jets[j].multiplicity = 0;
618 // Loop through particles to find closest jet.
619 for (int i = 0; i < nParticles; ++i) {
620 particles[i].daughter = -1;
621 double dist2Min = dist2BigMin;
623 for (int j = 0; j < int(jets.size()); ++j) {
624 double dist2 = dist2Fun( measure, particles[i], jets[j]);
625 if (dist2 < dist2Min) {
630 jets[jMin].pTemp += particles[i].pJet;
631 ++jets[jMin].multiplicity;
632 particles[i].daughter = jMin;
635 // Replace old by new jet momenta.
636 for (int j = 0; j < int(jets.size()); ++j) {
637 jets[j].pJet = jets[j].pTemp;
638 jets[j].pAbs = max( PABSMIN, jets[j].pJet.pAbs());
641 // Check that no empty clusters after reassignments.
644 // If no empty jets then done.
646 for (int j = 0; j < int(jets.size()); ++j)
647 if (jets[j].multiplicity == 0) jEmpty = j;
648 if (jEmpty == -1) return;
650 // Find particle assigned to jet with largest distance to it.
652 double dist2Max = 0.;
653 for (int i = 0; i < nParticles; ++i) {
654 int j = particles[i].daughter;
655 double dist2 = dist2Fun( measure, particles[i], jets[j]);
656 if (dist2 > dist2Max) {
662 // Let this particle form new jet and subtract off from existing.
663 int jSplit = particles[iSplit].daughter;
664 jets[jEmpty] = SingleClusterJet( particles[iSplit].pJet );
665 jets[jSplit].pJet -= particles[iSplit].pJet;
666 jets[jSplit].pAbs = max( PABSMIN,jets[jSplit].pJet.pAbs());
667 particles[iSplit].daughter = jEmpty;
668 --jets[jSplit].multiplicity;
675 // Provide a listing of the info.
677 void ClusterJet::list(ostream& os) {
680 string method = (measure == 1) ? "Lund pT"
681 : ( (measure == 2) ? "JADE m" : "Durham kT" ) ;
682 os << "\n -------- PYTHIA ClusterJet Listing, " << setw(9) << method
683 << " =" << fixed << setprecision(3) << setw(7) << sqrt(dist2Join)
684 << " GeV --- \n \n no mult p_x p_y p_z "
688 for (int i = 0; i < int(jets.size()); ++i) {
689 os << setw(4) << i << setw(6) << jets[i].multiplicity << setw(11)
690 << jets[i].pJet.px() << setw(11) << jets[i].pJet.py()
691 << setw(11) << jets[i].pJet.pz() << setw(11)
692 << jets[i].pJet.e() << setw(11) << jets[i].pJet.mCalc()
697 os << "\n -------- End PYTHIA ClusterJet Listing ---------------"
698 << "--------" << endl;
701 //**************************************************************************
704 // This class performs a cone jet search in (eta, phi, E_T) space.
708 // Constants: could be changed here if desired, but normally should not.
709 // These are of technical nature, as described for each.
711 // Minimum number of particles to perform study.
712 const int CellJet::TIMESTOPRINT = 1;
718 bool CellJet::analyze(const Event& event, double eTjetMinIn,
719 double coneRadiusIn, double eTseedIn, ostream& ) {
721 // Input values. Initial values zero.
722 eTjetMin = eTjetMinIn;
723 coneRadius = coneRadiusIn;
726 vector<SingleCell> cells;
728 // Loop over desired particles in the event.
729 for (int i = 0; i < event.size(); ++i)
730 if (event[i].isFinal()) {
731 if (select > 2 && event[i].isNeutral() ) continue;
732 if (select == 2 && !event[i].isVisible() ) continue;
734 // Find particle position in (eta, phi, pT) space.
735 double etaNow = event[i].eta();
736 if (abs(etaNow) > etaMax) continue;
737 double phiNow = event[i].phi();
738 double pTnow = event[i].pT();
739 int iEtaNow = max(1, min( nEta, 1 + int(nEta * 0.5
740 * (1. + etaNow / etaMax) ) ) );
741 int iPhiNow = max(1, min( nPhi, 1 + int(nPhi * 0.5
742 * (1. + phiNow / M_PI) ) ) );
743 int iCell = nPhi * iEtaNow + iPhiNow;
745 // Add pT to cell already hit or book a new cell.
747 for (int j = 0; j < int(cells.size()); ++j) {
748 if (iCell == cells[j].iCell) {
750 ++cells[j].multiplicity;
751 cells[j].eTcell += pTnow;
756 double etaCell = (etaMax / nEta) * (2 * iEtaNow - 1 - nEta);
757 double phiCell = (M_PI / nPhi) * (2 * iPhiNow - 1 - nPhi);
758 cells.push_back( SingleCell( iCell, etaCell, phiCell, pTnow, 1) );
762 // Smear true bin content by calorimeter resolution.
764 for (int j = 0; j < int(cells.size()); ++j) {
765 double eTeConv = (smear < 2) ? 1. : cosh( cells[j].etaCell );
766 double eBef = cells[j].eTcell * eTeConv;
768 do eAft = eBef + resolution * sqrt(eBef) * Rndm::gauss();
769 while (eAft < 0 || eAft > upperCut * eBef);
770 cells[j].eTcell = eAft / eTeConv;
773 // Remove cells below threshold for seed or for use at all.
774 for (int j = 0; j < int(cells.size()); ++j) {
775 if (cells[j].eTcell < eTseed) cells[j].canBeSeed = false;
776 if (cells[j].eTcell < threshold) cells[j].isUsed = true;
779 // Find seed cell: the one with highest pT of not yet probed ones.
783 for (int j = 0; j < int(cells.size()); ++j)
784 if (cells[j].canBeSeed && cells[j].eTcell > eTmax) {
786 eTmax = cells[j].eTcell;
789 // If too small cell eT then done, else start new trial jet.
790 if (eTmax < eTseed) break;
791 double etaCenterNow = cells[jMax].etaCell;
792 double phiCenterNow = cells[jMax].phiCell;
793 double eTjetNow = 0.;
795 // Sum up unused cells within required distance of seed.
796 for (int j = 0; j < int(cells.size()); ++j) {
797 if (cells[j].isUsed) continue;
798 double dEta = abs( cells[j].etaCell - etaCenterNow );
799 if (dEta > coneRadius) continue;
800 double dPhi = abs( cells[j].phiCell - phiCenterNow );
801 if (dPhi > M_PI) dPhi = 2. * M_PI - dPhi;
802 if (dPhi > coneRadius) continue;
803 if (pow2(dEta) + pow2(dPhi) > pow2(coneRadius)) continue;
804 cells[j].isAssigned = true;
805 eTjetNow += cells[j].eTcell;
808 // Reject cluster below minimum ET.
809 if (eTjetNow < eTjetMin) {
810 cells[jMax].canBeSeed = false;
811 for (int j = 0; j < int(cells.size()); ++j)
812 cells[j].isAssigned = false;
814 // Else find new jet properties.
816 double etaWeightedNow = 0.;
817 double phiWeightedNow = 0.;
818 int multiplicityNow = 0;
820 for (int j = 0; j < int(cells.size()); ++j)
821 if (cells[j].isAssigned) {
822 cells[j].canBeSeed = false;
823 cells[j].isUsed = true;
824 cells[j].isAssigned = false;
825 etaWeightedNow += cells[j].eTcell * cells[j].etaCell;
826 double phiCell = cells[j].phiCell;
827 if (abs(phiCell - phiCenterNow) > M_PI)
828 phiCell += (phiCenterNow > 0.) ? 2. * M_PI : -2. * M_PI;
829 phiWeightedNow += cells[j].eTcell * phiCell;
830 multiplicityNow += cells[j].multiplicity;
831 pMassiveNow += cells[j].eTcell * Vec4(
832 cos(cells[j].phiCell), sin(cells[j].phiCell),
833 sinh(cells[j].etaCell), cosh(cells[j].etaCell) );
835 etaWeightedNow /= eTjetNow;
836 phiWeightedNow /= eTjetNow;
838 // Bookkeep new jet, in decreasing ET order.
839 jets.push_back( SingleCellJet( eTjetNow, etaCenterNow, phiCenterNow,
840 etaWeightedNow, phiWeightedNow, multiplicityNow, pMassiveNow) );
841 for (int i = int(jets.size()) - 1; i > 0; --i) {
842 if (jets[i-1].eTjet > jets[i].eTjet) break;
843 swap( jets[i-1], jets[i]);
854 // Provide a listing of the info.
856 void CellJet::list(ostream& os) {
859 os << "\n -------- PYTHIA CellJet Listing, eTjetMin = "
860 << fixed << setprecision(3) << setw(8) << eTjetMin
861 << ", coneRadius = " << setw(5) << coneRadius
862 << " ------------------------------ \n \n no "
863 << " eTjet etaCtr phiCtr etaWt phiWt mult p_x"
864 << " p_y p_z e m \n";
867 for (int i = 0; i < int(jets.size()); ++i) {
868 os << setw(4) << i << setw(10) << jets[i].eTjet << setw(8)
869 << jets[i].etaCenter << setw(8) << jets[i].phiCenter << setw(8)
870 << jets[i].etaWeighted << setw(8) << jets[i].phiWeighted
871 << setw(5) << jets[i].multiplicity << setw(11)
872 << jets[i].pMassive.px() << setw(11) << jets[i].pMassive.py()
873 << setw(11) << jets[i].pMassive.pz() << setw(11)
874 << jets[i].pMassive.e() << setw(11)
875 << jets[i].pMassive.mCalc() << "\n";
879 os << "\n -------- End PYTHIA CellJet Listing ------------------"
880 << "-------------------------------------------------"
884 //**************************************************************************
886 } // end namespace Pythia8