]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PYTHIA8/pythia8145/src/FragmentationSystems.cxx
o automatic detection of 11a pass4 (Alla)
[u/mrichter/AliRoot.git] / PYTHIA8 / pythia8145 / src / FragmentationSystems.cxx
1 // FragmentationSystems.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2010 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 // ColConfig, StringRegion and StringSystem classes.
8
9 #include "FragmentationSystems.h"
10
11 namespace Pythia8 {
12
13 //==========================================================================
14
15 // The ColConfig class.
16
17 //--------------------------------------------------------------------------
18
19 // Constants: could be changed here if desired, but normally should not.
20 // These are of technical nature, as described for each.
21
22 // A typical u/d constituent mass.
23 const double ColConfig::CONSTITUENTMASS = 0.325;
24
25 //--------------------------------------------------------------------------
26
27 // Initialize and save pointers.
28
29 void ColConfig::init(Info* infoPtrIn, Settings& settings, 
30   StringFlav* flavSelPtrIn) {
31
32   // Save pointers.
33   infoPtr       = infoPtrIn;
34   flavSelPtr    = flavSelPtrIn;
35
36   // Joining of nearby partons along the string.
37   mJoin         = settings.parm("FragmentationSystems:mJoin");
38
39   // For consistency ensure that mJoin is bigger than in StringRegion.
40   mJoin         = max( mJoin, 2. * StringRegion::MJOIN);
41
42   // Simplification of q q q junction topology to quark - diquark one.
43   mJoinJunction = settings.parm("FragmentationSystems:mJoinJunction");
44   mStringMin    = settings.parm("HadronLevel:mStringMin");
45
46 }
47
48 //--------------------------------------------------------------------------
49
50 // Insert a new colour singlet system in ascending mass order. 
51 // Calculate its properties. Join nearby partons.
52
53 bool ColConfig::insert( vector<int>& iPartonIn, Event& event) {
54
55   // Find momentum and invariant mass of system, minus endpoint masses.
56   Vec4 pSumIn;
57   double mSumIn = 0.;
58   bool hasJunctionIn = false;
59   for (int i = 0; i < int(iPartonIn.size()); ++i) {
60     if (iPartonIn[i] < 0) { 
61       hasJunctionIn = true; 
62       continue;
63     }
64     pSumIn += event[ iPartonIn[i] ].p();
65     if (!event[ iPartonIn[i] ].isGluon()) 
66       mSumIn += event[ iPartonIn[i] ].constituentMass();
67   } 
68   double massIn = pSumIn.mCalc(); 
69   double massExcessIn = massIn - mSumIn;
70
71   // Check that momenta do not contain not-a-number.
72   if (abs(massExcessIn) >= 0.);
73   else {
74     infoPtr->errorMsg("Error in ColConfig::insert: "
75       "not-a-number system mass");
76     return false; 
77   }   
78
79   // Identify closed gluon loop. Assign "endpoint" masses as light quarks.
80   bool isClosedIn = (iPartonIn[0] >= 0 && event[ iPartonIn[0] ].isGluon());
81   if (isClosedIn) massExcessIn -= 2. * CONSTITUENTMASS;  
82
83   // For junction topology: join two nearby legs into a diquark.
84   if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn)) 
85     hasJunctionIn = false;
86
87   // Loop while > 2 partons left and hope of finding joining pair.
88   bool hasJoined = true;
89   while (hasJoined && iPartonIn.size() > 2) {
90
91     // Look for the pair of neighbour partons (along string) with 
92     // the smallest invariant mass (subtracting quark masses).
93     int iJoinMin = -1;
94     double mJoinMin = 2. * mJoin;
95     int nSize = iPartonIn.size();
96     int nPair = (isClosedIn) ? nSize : nSize - 1;
97     for (int i = 0; i < nPair; ++i) {
98       // Keep three legs of junction separate.
99       if (iPartonIn[i] < 0 || iPartonIn[(i + 1)%nSize] < 0) continue; 
100       Particle& parton1 = event[ iPartonIn[i] ];
101       Particle& parton2 = event[ iPartonIn[(i + 1)%nSize] ];
102       Vec4 pSumNow;
103       pSumNow += (parton1.isGluon()) ? 0.5 * parton1.p() : parton1.p();  
104       pSumNow += (parton2.isGluon()) ? 0.5 * parton2.p() : parton2.p();  
105       double mJoinNow = pSumNow.mCalc(); 
106       if (!parton1.isGluon()) mJoinNow -= parton1.m();
107       if (!parton2.isGluon()) mJoinNow -= parton2.m();
108       if (mJoinNow < mJoinMin) { iJoinMin = i; mJoinMin = mJoinNow; }
109     }
110
111     // If sufficiently nearby then join into one new parton.
112     // Note: error sensitivity to mJoin indicates unstable precedure??
113     hasJoined = false;
114     if (mJoinMin < mJoin) { 
115       int iJoin1  = iPartonIn[iJoinMin];
116       int iJoin2  = iPartonIn[(iJoinMin + 1)%nSize];
117       int idNew   = (event[iJoin1].isGluon()) ? event[iJoin2].id() 
118                                               : event[iJoin1].id();
119       int colNew  = event[iJoin1].col();
120       int acolNew = event[iJoin2].acol();
121       if (colNew == acolNew) {
122         colNew    = event[iJoin2].col();
123         acolNew   = event[iJoin1].acol();
124       }  
125       Vec4 pNew   = event[iJoin1].p() + event[iJoin2].p();
126
127       // Append joined parton to event record.
128       int iNew = event.append( idNew, 73, min(iJoin1, iJoin2), 
129         max(iJoin1, iJoin2), 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
130
131       // Mark joined partons and reduce remaining system.
132       event[iJoin1].statusNeg();
133       event[iJoin2].statusNeg();
134       event[iJoin1].daughter1(iNew);
135       event[iJoin2].daughter1(iNew);
136       if (iJoinMin == nSize - 1) iPartonIn[0] = iNew;
137       else {
138         iPartonIn[iJoinMin] = iNew;
139         for (int i = iJoinMin + 1; i < nSize - 1; ++i)
140           iPartonIn[i] = iPartonIn[i + 1];
141       }
142       iPartonIn.pop_back();
143
144       // If joined,then loopback to look for more.
145       hasJoined = true;
146     }
147   }
148
149   // Store new colour singlet system at the end.
150   singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
151     massExcessIn, hasJunctionIn, isClosedIn) );
152
153   // Now move around, so that smallest mass excesses come first.
154   int iInsert = singlets.size() - 1;
155   for (int iSub = singlets.size() - 2; iSub >= 0; --iSub) {
156     if (massExcessIn > singlets[iSub].massExcess) break;
157     singlets[iSub + 1] = singlets[iSub];
158     iInsert = iSub;
159   }
160   if (iInsert < int(singlets.size()) - 1) singlets[iInsert] = 
161     ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn, 
162     hasJunctionIn, isClosedIn);
163
164   // Done.
165   return true;
166 }
167
168 //--------------------------------------------------------------------------
169
170 // Join two legs of junction to a diquark for small invariant masses.
171 // Note: for junction system, iPartonIn points to structure
172 // (-code0) g...g.q0 (-code1) g...g.q1 (-code2) g...g.q2 
173
174 bool ColConfig::joinJunction( vector<int>& iPartonIn, Event& event,
175   double massExcessIn) {
176
177   // Find four-momentum and endpoint quarks and masses on the three legs.
178   Vec4   pLeg[3];
179   double mLeg[3];
180   int    idAbsLeg[3];
181   int leg = -1;
182   for (int i = 0; i < int(iPartonIn.size()); ++ i) {
183     if (iPartonIn[i] < 0) ++leg;
184     else {
185       pLeg[leg]    += event[ iPartonIn[i] ].p(); 
186       mLeg[leg]     = event[ iPartonIn[i] ].m();
187       idAbsLeg[leg] = event[ iPartonIn[i] ].idAbs();
188     }
189   }
190
191   // Calculate invariant mass of three pairs, minus endpoint masses. 
192   double m01  = (pLeg[0] + pLeg[1]).mCalc() - mLeg[0] - mLeg[1];
193   double m02  = (pLeg[0] + pLeg[2]).mCalc() - mLeg[0] - mLeg[2];
194   double m12  = (pLeg[1] + pLeg[2]).mCalc() - mLeg[1] - mLeg[2];
195   
196   // Find lowest-mass pair not involving diquark.
197   double mMin = mJoinJunction + 1.;
198   int    legA = -1;
199   int    legB = -1; 
200   if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) {
201     mMin = m01; 
202     legA = 0; 
203     legB = 1;
204   }
205   if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) {
206     mMin = m02; 
207     legA = 0; 
208     legB = 2;
209   }
210   if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) {
211     mMin = m12; 
212     legA = 1; 
213     legB = 2;
214   } 
215   int legC = 3 - legA - legB;  
216
217   // Nothing to do if no two legs have small invariant mass, and 
218   // system as a whole is above MiniStringFragmentation threshold.
219   if (mMin > mJoinJunction && massExcessIn > mStringMin) return false;  
220
221   // Construct separate index arrays for the three legs.
222   vector<int> iLegA, iLegB, iLegC;
223   leg = -1;
224   for (int i = 0; i < int(iPartonIn.size()); ++ i) {
225     if (iPartonIn[i] < 0) ++leg;
226     else if( leg == legA) iLegA.push_back( iPartonIn[i] );
227     else if( leg == legB) iLegB.push_back( iPartonIn[i] );
228     else if( leg == legC) iLegC.push_back( iPartonIn[i] );
229   }
230  
231   // First step: successively combine any gluons on the two legs.
232   // (Presumably overkill; not likely to be (m)any extra gluons.)
233   // (Do as successive binary joinings, so only need two mothers.)
234   for (leg = 0; leg < 2; ++leg) {
235     vector<int>& iLegNow = (leg == 0) ? iLegA : iLegB;
236     int sizeNow = iLegNow.size();
237     for (int i = sizeNow - 2; i >= 0; --i) {      
238       int iQ = iLegNow.back();
239       int iG = iLegNow[i];
240       int colNew = (event[iQ].id() > 0) ? event[iG].col() : 0;
241       int acolNew = (event[iQ].id() < 0) ? event[iG].acol() : 0;
242       Vec4 pNew = event[iQ].p() + event[iG].p();
243       int iNew = event.append( event[iQ].id(), 74, min(iQ, iG), 
244         max(iQ, iG), 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
245
246       // Mark joined partons and update iLeg end. 
247       event[iQ].statusNeg();
248       event[iG].statusNeg();
249       event[iQ].daughter1(iNew);
250       event[iG].daughter1(iNew);
251       iLegNow.back() = iNew;
252     }        
253   }
254
255   // Second step: combine two quarks into a diquark. 
256   int iQA     = iLegA.back();
257   int iQB     = iLegB.back();
258   int idQA    = event[iQA].id();
259   int idQB    = event[iQB].id();
260   int idNew   = flavSelPtr->makeDiquark( idQA, idQB ); 
261   // Diquark colour is opposite to parton closest to junction on third leg.
262   int colNew  = (idNew > 0) ? 0 : event[ iLegC[0] ].acol();
263   int acolNew = (idNew > 0) ? event[ iLegC[0] ].col() : 0;
264   Vec4 pNew   = pLeg[legA] + pLeg[legB];
265   int iNew    = event.append( idNew, 74, min(iQA, iQB), max( iQA, iQB),
266      0, 0, colNew, acolNew, pNew, pNew.mCalc() );
267  
268   // Mark joined partons and reduce remaining system.
269   event[iQA].statusNeg();
270   event[iQB].statusNeg();
271   event[iQA].daughter1(iNew);
272   event[iQB].daughter1(iNew);
273   iPartonIn.resize(0);
274   iPartonIn.push_back( iNew);
275   for (int i = 0; i < int(iLegC.size()) ; ++i) 
276     iPartonIn.push_back( iLegC[i]);
277
278   // Remove junction from event record list, identifying by colour.
279   int iJun = -1;
280   for (int i = 0; i < event.sizeJunction(); ++i) 
281     for (int j = 0; j < 3; ++ j)
282       if ( event.colJunction(i,j) == max(colNew, acolNew) ) iJun = i;
283   if (iJun >= 0) event.eraseJunction(iJun); 
284
285   // Done, having eliminated junction.
286   return true;
287
288 }
289
290 //--------------------------------------------------------------------------
291
292 // Collect all partons of singlet to be consecutively ordered.
293
294 void ColConfig::collect(int iSub, Event& event) {
295
296   // Partons may already have been collected, e.g. at ministring collapse.
297   if (singlets[iSub].isCollected) return;
298   singlets[iSub].isCollected = true;
299
300   // Check if partons already "by chance" happen to be ordered.
301   bool inOrder = true;
302   for (int i = 0; i < singlets[iSub].size() - 1; ++i) {
303     int iFirst = singlets[iSub].iParton[i];
304     if (iFirst < 0) continue;
305     int iSecond = singlets[iSub].iParton[i + 1];
306     if (iSecond < 0) iSecond = singlets[iSub].iParton[i + 2];
307     if (iSecond != iFirst + 1) { inOrder = false; break;}
308   }
309   if (inOrder) return;
310  
311   // Copy down system. Update current partons.
312   for (int i = 0; i < singlets[iSub].size(); ++i) {
313     int iOld = singlets[iSub].iParton[i];
314     if (iOld < 0) continue;
315     int iNew = event.copy(iOld, 71);
316     singlets[iSub].iParton[i] = iNew;
317   }
318
319   // Done.
320 }
321
322 //--------------------------------------------------------------------------
323
324 // List all currently identified singlets.
325
326 void ColConfig::list(ostream& os) const {
327
328   // Header. Loop over all individual singlets.
329   os << "\n --------  Colour Singlet Systems Listing -------------------\n"; 
330   for (int iSub = 0; iSub < int(singlets.size()); ++iSub) {
331
332     // List all partons belonging to each singlet.
333     os << " singlet " << iSub << " contains " ;
334     for (int i = 0; i < singlets[iSub].size(); ++i) 
335       os << singlets[iSub].iParton[i] << " ";  
336     os << "\n"; 
337
338   // Done.
339   }
340 }
341  
342 //==========================================================================
343
344 // The StringRegion class.
345
346 // Currently a number of simplifications, in particular ??
347 // 1) No popcorn baryon production.
348 // 2) Simplified treatment of pT in stepping and joining.
349
350 //--------------------------------------------------------------------------
351
352 // Constants: could be changed here if desired, but normally should not.
353 // These are of technical nature, as described for each.
354
355 // If a string region is smaller thsan this it is assumed empty.
356 const double StringRegion::MJOIN = 0.1;
357
358 // Avoid division by zero.
359 const double StringRegion::TINY  = 1e-20;
360
361 //--------------------------------------------------------------------------
362
363 // Set up four-vectors for longitudinal and transverse directions.
364
365 void StringRegion::setUp(Vec4 p1, Vec4 p2, bool isMassless) {
366
367   // Simple case: the two incoming four-vectors guaranteed massless.
368   if (isMassless) {
369  
370     // Calculate w2, minimum value. Lightcone directions = input.
371     w2 = 2. * (p1 * p2);
372     if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
373     pPos = p1;
374     pNeg = p2;
375
376   // Else allow possibility of masses for incoming partons (also gluons!).
377   } else {
378
379     // Generic four-momentum combinations.
380     double m1Sq = p1 * p1;
381     double m2Sq = p2 * p2;
382     double p1p2 = p1 * p2;
383     w2 = m1Sq + 2. * p1p2 + m2Sq;
384     double rootSq = pow2(p1p2) - m1Sq * m2Sq;
385
386     // If crazy kinematics (should not happen!) modify energies.
387     if (w2 <= 0. || rootSq <= 0.) {
388       if (m1Sq < 0.) m1Sq = 0.;
389       p1.e( sqrt(m1Sq + p1.pAbs2()) ); 
390       if (m2Sq < 0.) m2Sq = 0.;
391       p2.e( sqrt(m2Sq + p2.pAbs2()) ); 
392       p1p2 = p1 * p2;
393       w2 = m1Sq + 2. * p1p2 + m2Sq;
394       rootSq = pow2(p1p2) - m1Sq * m2Sq;
395     }
396
397     // If still small invariant mass then empty region (e.g. in gg system).
398     if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
399
400     // Find two lightconelike longitudinal four-vector directions.
401     double root = sqrt( max(TINY, rootSq) );
402     double k1 = 0.5 * ( (m2Sq + p1p2) / root - 1.); 
403     double k2 = 0.5 * ( (m1Sq + p1p2) / root - 1.); 
404     pPos = (1. + k1) * p1 - k2 * p2;
405     pNeg = (1. + k2) * p2 - k1 * p1;
406   }
407   
408   // Find two spacelike transverse four-vector directions.
409   // Begin by picking two sensible trial directions.
410   Vec4 eDiff = pPos / pPos.e() - pNeg / pNeg.e();
411   double eDx = pow2( eDiff.px() );
412   double eDy = pow2( eDiff.py() );
413   double eDz = pow2( eDiff.pz() );
414   if (eDx < min(eDy, eDz)) {
415     eX = Vec4( 1., 0., 0., 0.);
416     eY = (eDy < eDz) ? Vec4( 0., 1., 0., 0.) : Vec4( 0., 0., 1., 0.);
417   } else if (eDy < eDz) { 
418     eX = Vec4( 0., 1., 0., 0.);
419     eY = (eDx < eDz) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 0., 1., 0.);
420   } else {
421     eX = Vec4( 0., 0., 1., 0.);
422     eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.);
423   }
424
425   // Then construct orthogonal linear combinations.
426   double pPosNeg = pPos * pNeg;
427   double kXPos = eX * pPos / pPosNeg;
428   double kXNeg = eX * pNeg / pPosNeg;
429   double kXX = 1. / sqrt( 1. + 2. * kXPos * kXNeg * pPosNeg );
430   double kYPos = eY * pPos / pPosNeg;
431   double kYNeg = eY * pNeg / pPosNeg;
432   double kYX = kXX * (kXPos * kYNeg + kXNeg * kYPos) * pPosNeg;
433   double kYY = 1. / sqrt(1. + 2. * kYPos * kYNeg * pPosNeg - pow2(kYX));
434   eX = kXX * (eX - kXNeg * pPos - kXPos * pNeg);
435   eY = kYY * (eY - kYNeg * pPos - kYPos * pNeg - kYX * eX);
436
437   // Done.
438   isSetUp = true;
439   isEmpty = false;
440
441 }
442
443 //--------------------------------------------------------------------------
444
445 // Project a four-momentum onto (x+, x-, px, py).
446
447 void StringRegion::project(Vec4 pIn) { 
448
449   // Perform projections by four-vector multiplication.
450   xPosProj = 2. * (pIn * pNeg) / w2; 
451   xNegProj = 2. * (pIn * pPos) / w2; 
452   pxProj = - (pIn * eX);
453   pyProj = - (pIn * eY);   
454
455 }
456  
457 //==========================================================================
458
459 // The StringSystem class.
460
461 //--------------------------------------------------------------------------
462
463 // Set up system from parton list. 
464
465 void StringSystem::setUp(vector<int>& iSys, Event& event) {
466
467   // Figure out how big the system is. (Closed gluon loops?)
468   sizePartons = iSys.size();
469   sizeStrings = sizePartons - 1;
470   sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2;
471   indxReg = 2 * sizeStrings + 1;
472   iMax = sizeStrings - 1; 
473
474   // Reserve space for the required number of regions.
475   system.clear();
476   system.resize(sizeRegions);
477
478   // Set up the lowest-lying regions.
479   for (int i = 0; i < sizeStrings; ++i) {
480     Vec4 p1 = event[ iSys[i] ].p();
481     if ( event[ iSys[i] ].isGluon() ) p1 *= 0.5;
482     Vec4 p2 = event[ iSys[i+1] ].p();
483     if ( event[ iSys[i+1] ].isGluon() ) p2 *= 0.5;
484     system[ iReg(i, iMax - i) ].setUp( p1, p2, false);
485   }
486
487 }
488
489 //==========================================================================
490
491 } // end namespace Pythia8