1 // FragmentationSystems.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2012 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 // ColConfig, StringRegion and StringSystem classes.
9 #include "FragmentationSystems.h"
13 //==========================================================================
15 // The ColConfig class.
17 //--------------------------------------------------------------------------
19 // Constants: could be changed here if desired, but normally should not.
20 // These are of technical nature, as described for each.
22 // A typical u/d constituent mass.
23 const double ColConfig::CONSTITUENTMASS = 0.325;
25 //--------------------------------------------------------------------------
27 // Initialize and save pointers.
29 void ColConfig::init(Info* infoPtrIn, Settings& settings,
30 StringFlav* flavSelPtrIn) {
34 flavSelPtr = flavSelPtrIn;
36 // Joining of nearby partons along the string.
37 mJoin = settings.parm("FragmentationSystems:mJoin");
39 // For consistency ensure that mJoin is bigger than in StringRegion.
40 mJoin = max( mJoin, 2. * StringRegion::MJOIN);
42 // Simplification of q q q junction topology to quark - diquark one.
43 mJoinJunction = settings.parm("FragmentationSystems:mJoinJunction");
44 mStringMin = settings.parm("HadronLevel:mStringMin");
48 //--------------------------------------------------------------------------
50 // Insert a new colour singlet system in ascending mass order.
51 // Calculate its properties. Join nearby partons.
53 bool ColConfig::insert( vector<int>& iPartonIn, Event& event) {
55 // Find momentum and invariant mass of system, minus endpoint masses.
58 bool hasJunctionIn = false;
59 int nJunctionLegs = 0;
60 for (int i = 0; i < int(iPartonIn.size()); ++i) {
61 if (iPartonIn[i] < 0) {
65 pSumIn += event[ iPartonIn[i] ].p();
66 if (!event[ iPartonIn[i] ].isGluon())
67 mSumIn += event[ iPartonIn[i] ].constituentMass();
70 double massIn = pSumIn.mCalc();
71 double massExcessIn = massIn - mSumIn;
73 // Check for rare triple- and higher junction systems (like J-Jbar-J)
74 if (nJunctionLegs >= 5) {
75 infoPtr->errorMsg("Error in ColConfig::insert: "
76 "junction topology too complicated; too many junction legs");
79 // Check that junction systems have at least three legs.
80 else if (nJunctionLegs > 0 && nJunctionLegs <= 2) {
81 infoPtr->errorMsg("Error in ColConfig::insert: "
82 "junction topology inconsistent; too few junction legs");
86 // Check that momenta do not contain not-a-number.
87 if (abs(massExcessIn) >= 0.);
89 infoPtr->errorMsg("Error in ColConfig::insert: "
90 "not-a-number system mass");
94 // Identify closed gluon loop. Assign "endpoint" masses as light quarks.
95 bool isClosedIn = (iPartonIn[0] >= 0 && event[ iPartonIn[0] ].col() != 0
96 && event[ iPartonIn[0] ].acol() != 0 );
97 if (isClosedIn) massExcessIn -= 2. * CONSTITUENTMASS;
99 // For junction topology: join two nearby legs into a diquark.
100 if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn))
101 hasJunctionIn = false;
103 // Loop while > 2 partons left and hope of finding joining pair.
104 bool hasJoined = true;
105 while (hasJoined && iPartonIn.size() > 2) {
107 // Look for the pair of neighbour partons (along string) with
108 // the smallest invariant mass (subtracting quark masses).
110 double mJoinMin = 2. * mJoin;
111 int nSize = iPartonIn.size();
112 int nPair = (isClosedIn) ? nSize : nSize - 1;
113 for (int i = 0; i < nPair; ++i) {
114 // Keep three legs of junction separate.
115 if (iPartonIn[i] < 0 || iPartonIn[(i + 1)%nSize] < 0) continue;
116 Particle& parton1 = event[ iPartonIn[i] ];
117 Particle& parton2 = event[ iPartonIn[(i + 1)%nSize] ];
118 // Avoid joining non-partons, e.g. gluino/squark for R-hadron.
119 if (!parton1.isParton() || !parton2.isParton()) continue;
121 pSumNow += (parton1.isGluon()) ? 0.5 * parton1.p() : parton1.p();
122 pSumNow += (parton2.isGluon()) ? 0.5 * parton2.p() : parton2.p();
123 double mJoinNow = pSumNow.mCalc();
124 if (!parton1.isGluon()) mJoinNow -= parton1.m();
125 if (!parton2.isGluon()) mJoinNow -= parton2.m();
126 if (mJoinNow < mJoinMin) { iJoinMin = i; mJoinMin = mJoinNow; }
129 // If sufficiently nearby then join into one new parton.
130 // Note: error sensitivity to mJoin indicates unstable precedure??
132 if (mJoinMin < mJoin) {
133 int iJoin1 = iPartonIn[iJoinMin];
134 int iJoin2 = iPartonIn[(iJoinMin + 1)%nSize];
135 int idNew = (event[iJoin1].isGluon()) ? event[iJoin2].id()
136 : event[iJoin1].id();
137 int colNew = event[iJoin1].col();
138 int acolNew = event[iJoin2].acol();
139 if (colNew == acolNew) {
140 colNew = event[iJoin2].col();
141 acolNew = event[iJoin1].acol();
143 Vec4 pNew = event[iJoin1].p() + event[iJoin2].p();
145 // Append joined parton to event record.
146 int iNew = event.append( idNew, 73, min(iJoin1, iJoin2),
147 max(iJoin1, iJoin2), 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
149 // Displaced lifetime/vertex; mothers should be same but prefer quark.
150 int iVtx = (event[iJoin1].isGluon()) ? iJoin2 : iJoin1;
151 event[iNew].tau( event[iVtx].tau() );
152 if (event[iVtx].hasVertex()) event[iNew].vProd( event[iVtx].vProd() );
154 // Mark joined partons and reduce remaining system.
155 event[iJoin1].statusNeg();
156 event[iJoin2].statusNeg();
157 event[iJoin1].daughter1(iNew);
158 event[iJoin2].daughter1(iNew);
159 if (iJoinMin == nSize - 1) iPartonIn[0] = iNew;
161 iPartonIn[iJoinMin] = iNew;
162 for (int i = iJoinMin + 1; i < nSize - 1; ++i)
163 iPartonIn[i] = iPartonIn[i + 1];
165 iPartonIn.pop_back();
167 // If joined,then loopback to look for more.
172 // Store new colour singlet system at the end.
173 singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
174 massExcessIn, hasJunctionIn, isClosedIn) );
176 // Now move around, so that smallest mass excesses come first.
177 int iInsert = singlets.size() - 1;
178 for (int iSub = singlets.size() - 2; iSub >= 0; --iSub) {
179 if (massExcessIn > singlets[iSub].massExcess) break;
180 singlets[iSub + 1] = singlets[iSub];
183 if (iInsert < int(singlets.size()) - 1) singlets[iInsert] =
184 ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn,
185 hasJunctionIn, isClosedIn);
191 //--------------------------------------------------------------------------
193 // Join two legs of junction to a diquark for small invariant masses.
194 // Note: for junction system, iPartonIn points to structure
195 // (-code0) g...g.q0 (-code1) g...g.q1 (-code2) g...g.q2
197 bool ColConfig::joinJunction( vector<int>& iPartonIn, Event& event,
198 double massExcessIn) {
200 // Find four-momentum and endpoint quarks and masses on the three legs.
202 double mLeg[3] = { 0., 0., 0.};
205 for (int i = 0; i < int(iPartonIn.size()); ++ i) {
206 if (iPartonIn[i] < 0) ++leg;
208 pLeg[leg] += event[ iPartonIn[i] ].p();
209 mLeg[leg] = event[ iPartonIn[i] ].m();
210 idAbsLeg[leg] = event[ iPartonIn[i] ].idAbs();
214 // Calculate invariant mass of three pairs, minus endpoint masses.
215 double m01 = (pLeg[0] + pLeg[1]).mCalc() - mLeg[0] - mLeg[1];
216 double m02 = (pLeg[0] + pLeg[2]).mCalc() - mLeg[0] - mLeg[2];
217 double m12 = (pLeg[1] + pLeg[2]).mCalc() - mLeg[1] - mLeg[2];
219 // Find lowest-mass pair not involving diquark.
220 double mMin = mJoinJunction + 1.;
223 if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) {
228 if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) {
233 if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) {
238 int legC = 3 - legA - legB;
240 // Nothing to do if no two legs have small invariant mass, and
241 // system as a whole is above MiniStringFragmentation threshold.
242 if (legA == -1 || (mMin > mJoinJunction && massExcessIn > mStringMin))
245 // Construct separate index arrays for the three legs.
246 vector<int> iLegA, iLegB, iLegC;
248 for (int i = 0; i < int(iPartonIn.size()); ++ i) {
249 if (iPartonIn[i] < 0) ++leg;
250 else if( leg == legA) iLegA.push_back( iPartonIn[i] );
251 else if( leg == legB) iLegB.push_back( iPartonIn[i] );
252 else if( leg == legC) iLegC.push_back( iPartonIn[i] );
255 // First step: successively combine any gluons on the two legs.
256 // (Presumably overkill; not likely to be (m)any extra gluons.)
257 // (Do as successive binary joinings, so only need two mothers.)
258 for (leg = 0; leg < 2; ++leg) {
259 vector<int>& iLegNow = (leg == 0) ? iLegA : iLegB;
260 int sizeNow = iLegNow.size();
261 for (int i = sizeNow - 2; i >= 0; --i) {
262 int iQ = iLegNow.back();
264 int colNew = (event[iQ].id() > 0) ? event[iG].col() : 0;
265 int acolNew = (event[iQ].id() < 0) ? event[iG].acol() : 0;
266 Vec4 pNew = event[iQ].p() + event[iG].p();
267 int iNew = event.append( event[iQ].id(), 74, min(iQ, iG),
268 max(iQ, iG), 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
270 // Mark joined partons and update iLeg end.
271 event[iQ].statusNeg();
272 event[iG].statusNeg();
273 event[iQ].daughter1(iNew);
274 event[iG].daughter1(iNew);
275 iLegNow.back() = iNew;
279 // Second step: combine two quarks into a diquark.
280 int iQA = iLegA.back();
281 int iQB = iLegB.back();
282 int idQA = event[iQA].id();
283 int idQB = event[iQB].id();
284 int idNew = flavSelPtr->makeDiquark( idQA, idQB );
285 // Diquark colour is opposite to parton closest to junction on third leg.
286 int colNew = (idNew > 0) ? 0 : event[ iLegC[0] ].acol();
287 int acolNew = (idNew > 0) ? event[ iLegC[0] ].col() : 0;
288 Vec4 pNew = pLeg[legA] + pLeg[legB];
289 int iNew = event.append( idNew, 74, min(iQA, iQB), max( iQA, iQB),
290 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
292 // Mark joined partons and reduce remaining system.
293 event[iQA].statusNeg();
294 event[iQB].statusNeg();
295 event[iQA].daughter1(iNew);
296 event[iQB].daughter1(iNew);
298 iPartonIn.push_back( iNew);
299 for (int i = 0; i < int(iLegC.size()) ; ++i)
300 iPartonIn.push_back( iLegC[i]);
302 // Remove junction from event record list, identifying by colour.
304 for (int i = 0; i < event.sizeJunction(); ++i)
305 for (int j = 0; j < 3; ++ j)
306 if ( event.colJunction(i,j) == max(colNew, acolNew) ) iJun = i;
307 if (iJun >= 0) event.eraseJunction(iJun);
309 // Done, having eliminated junction.
314 //--------------------------------------------------------------------------
316 // Collect all partons of singlet to be consecutively ordered.
318 void ColConfig::collect(int iSub, Event& event, bool skipTrivial) {
320 // Check that all partons have positive energy.
321 for (int i = 0; i < singlets[iSub].size(); ++i) {
322 int iNow = singlets[iSub].iParton[i];
323 if (iNow > 0 && event[iNow].e() < 0.)
324 infoPtr->errorMsg("Warning in ColConfig::collect: "
325 "negative-energy parton encountered");
328 // Partons may already have been collected, e.g. at ministring collapse.
329 if (singlets[iSub].isCollected) return;
330 singlets[iSub].isCollected = true;
332 // Check if partons already "by chance" happen to be ordered.
334 for (int i = 0; i < singlets[iSub].size() - 1; ++i) {
335 int iFirst = singlets[iSub].iParton[i];
336 if (iFirst < 0) continue;
337 int iSecond = singlets[iSub].iParton[i + 1];
338 if (iSecond < 0) iSecond = singlets[iSub].iParton[i + 2];
339 if (iSecond != iFirst + 1) { inOrder = false; break;}
342 // Normally done if in order, but sometimes may need to copy anyway.
343 if (inOrder && skipTrivial) return;
345 // Copy down system. Update current partons.
346 for (int i = 0; i < singlets[iSub].size(); ++i) {
347 int iOld = singlets[iSub].iParton[i];
348 if (iOld < 0) continue;
349 int iNew = event.copy(iOld, 71);
350 singlets[iSub].iParton[i] = iNew;
356 //--------------------------------------------------------------------------
358 // Find to which singlet system a particle belongs.
360 int ColConfig::findSinglet(int i) {
362 // Loop through all systems and all members in them.
363 for (int iSub = 0; iSub < int(singlets.size()); ++iSub)
364 for (int iMem = 0; iMem < singlets[iSub].size(); ++iMem)
365 if (singlets[iSub].iParton[iMem] == i) return iSub;
367 // Done without having found particle; return -1 = error code.
371 //--------------------------------------------------------------------------
373 // List all currently identified singlets.
375 void ColConfig::list(ostream& os) const {
377 // Header. Loop over all individual singlets.
378 os << "\n -------- Colour Singlet Systems Listing -------------------\n";
379 for (int iSub = 0; iSub < int(singlets.size()); ++iSub) {
381 // List all partons belonging to each singlet.
382 os << " singlet " << iSub << " contains " ;
383 for (int i = 0; i < singlets[iSub].size(); ++i)
384 os << singlets[iSub].iParton[i] << " ";
391 //==========================================================================
393 // The StringRegion class.
395 // Currently a number of simplifications, in particular ??
396 // 1) No popcorn baryon production.
397 // 2) Simplified treatment of pT in stepping and joining.
399 //--------------------------------------------------------------------------
401 // Constants: could be changed here if desired, but normally should not.
402 // These are of technical nature, as described for each.
404 // If a string region is smaller thsan this it is assumed empty.
405 const double StringRegion::MJOIN = 0.1;
407 // Avoid division by zero.
408 const double StringRegion::TINY = 1e-20;
410 //--------------------------------------------------------------------------
412 // Set up four-vectors for longitudinal and transverse directions.
414 void StringRegion::setUp(Vec4 p1, Vec4 p2, bool isMassless) {
416 // Simple case: the two incoming four-vectors guaranteed massless.
419 // Calculate w2, minimum value. Lightcone directions = input.
421 if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
425 // Else allow possibility of masses for incoming partons (also gluons!).
428 // Generic four-momentum combinations.
429 double m1Sq = p1 * p1;
430 double m2Sq = p2 * p2;
431 double p1p2 = p1 * p2;
432 w2 = m1Sq + 2. * p1p2 + m2Sq;
433 double rootSq = pow2(p1p2) - m1Sq * m2Sq;
435 // If crazy kinematics (should not happen!) modify energies.
436 if (w2 <= 0. || rootSq <= 0.) {
437 if (m1Sq < 0.) m1Sq = 0.;
438 p1.e( sqrt(m1Sq + p1.pAbs2()) );
439 if (m2Sq < 0.) m2Sq = 0.;
440 p2.e( sqrt(m2Sq + p2.pAbs2()) );
442 w2 = m1Sq + 2. * p1p2 + m2Sq;
443 rootSq = pow2(p1p2) - m1Sq * m2Sq;
446 // If still small invariant mass then empty region (e.g. in gg system).
447 if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
449 // Find two lightconelike longitudinal four-vector directions.
450 double root = sqrt( max(TINY, rootSq) );
451 double k1 = 0.5 * ( (m2Sq + p1p2) / root - 1.);
452 double k2 = 0.5 * ( (m1Sq + p1p2) / root - 1.);
453 pPos = (1. + k1) * p1 - k2 * p2;
454 pNeg = (1. + k2) * p2 - k1 * p1;
457 // Find two spacelike transverse four-vector directions.
458 // Begin by picking two sensible trial directions.
459 Vec4 eDiff = pPos / pPos.e() - pNeg / pNeg.e();
460 double eDx = pow2( eDiff.px() );
461 double eDy = pow2( eDiff.py() );
462 double eDz = pow2( eDiff.pz() );
463 if (eDx < min(eDy, eDz)) {
464 eX = Vec4( 1., 0., 0., 0.);
465 eY = (eDy < eDz) ? Vec4( 0., 1., 0., 0.) : Vec4( 0., 0., 1., 0.);
466 } else if (eDy < eDz) {
467 eX = Vec4( 0., 1., 0., 0.);
468 eY = (eDx < eDz) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 0., 1., 0.);
470 eX = Vec4( 0., 0., 1., 0.);
471 eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.);
474 // Then construct orthogonal linear combinations.
475 double pPosNeg = pPos * pNeg;
476 double kXPos = eX * pPos / pPosNeg;
477 double kXNeg = eX * pNeg / pPosNeg;
478 double kXX = 1. / sqrt( 1. + 2. * kXPos * kXNeg * pPosNeg );
479 double kYPos = eY * pPos / pPosNeg;
480 double kYNeg = eY * pNeg / pPosNeg;
481 double kYX = kXX * (kXPos * kYNeg + kXNeg * kYPos) * pPosNeg;
482 double kYY = 1. / sqrt(1. + 2. * kYPos * kYNeg * pPosNeg - pow2(kYX));
483 eX = kXX * (eX - kXNeg * pPos - kXPos * pNeg);
484 eY = kYY * (eY - kYNeg * pPos - kYPos * pNeg - kYX * eX);
492 //--------------------------------------------------------------------------
494 // Project a four-momentum onto (x+, x-, px, py).
496 void StringRegion::project(Vec4 pIn) {
498 // Perform projections by four-vector multiplication.
499 xPosProj = 2. * (pIn * pNeg) / w2;
500 xNegProj = 2. * (pIn * pPos) / w2;
501 pxProj = - (pIn * eX);
502 pyProj = - (pIn * eY);
506 //==========================================================================
508 // The StringSystem class.
510 //--------------------------------------------------------------------------
512 // Set up system from parton list.
514 void StringSystem::setUp(vector<int>& iSys, Event& event) {
516 // Figure out how big the system is. (Closed gluon loops?)
517 sizePartons = iSys.size();
518 sizeStrings = sizePartons - 1;
519 sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2;
520 indxReg = 2 * sizeStrings + 1;
521 iMax = sizeStrings - 1;
523 // Reserve space for the required number of regions.
525 system.resize(sizeRegions);
527 // Set up the lowest-lying regions.
528 for (int i = 0; i < sizeStrings; ++i) {
529 Vec4 p1 = event[ iSys[i] ].p();
530 if ( event[ iSys[i] ].isGluon() ) p1 *= 0.5;
531 Vec4 p2 = event[ iSys[i+1] ].p();
532 if ( event[ iSys[i+1] ].isGluon() ) p2 *= 0.5;
533 system[ iReg(i, iMax - i) ].setUp( p1, p2, false);
538 //==========================================================================
540 } // end namespace Pythia8