]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx
pythia8130 distributed with AliRoot
[u/mrichter/AliRoot.git] / PYTHIA8 / pythia8130 / src / MiniStringFragmentation.cxx
1 // MiniStringFragmentation.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.
5
6 // Function definitions (not found in the header) for the .
7 // MiniStringFragmentation class
8
9 #include "MiniStringFragmentation.h"
10
11 namespace Pythia8 {
12
13 //**************************************************************************
14
15 // The MiniStringFragmentation 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 // Since diffractive by definition is > 1 particle, try hard. 
23 const int MiniStringFragmentation::NTRYDIFFRACTIVE = 200;
24
25 // After one-body fragmentation failed, try two-body once more. 
26 const int MiniStringFragmentation::NTRYLASTRESORT  = 100;
27
28 // To avoid division by zero one must have sigma > 0.
29 const double MiniStringFragmentation::SIGMAMIN     = 0.01;
30
31 // Loop try to combine available endquarks to valid hadron. 
32 const int MiniStringFragmentation::NTRYFLAV        = 10;
33
34 //*********
35
36 // Initialize and save pointers.
37
38 void MiniStringFragmentation::init(Info* infoPtrIn, 
39   StringFlav* flavSelPtrIn) {
40
41   // Save pointers.
42   infoPtr    = infoPtrIn;
43   flavSelPtr = flavSelPtrIn;
44
45   // Initialize the MiniStringFragmentation class proper.
46   nTryMass   = Settings::mode("MiniStringFragmentation:nTry");
47   sigma      = Settings::parm("StringPT:sigma");
48   sigma2Had  = 2. * pow2( max( SIGMAMIN, sigma) );
49
50   // Initialize the b parameter of the z spectrum, used when joining jets.
51   bLund      = Settings::parm("StringZ:bLund");
52
53 }
54
55 //*********
56
57 // Do the fragmentation: driver routine.
58   
59 bool MiniStringFragmentation::fragment(int iSub, ColConfig& colConfig, 
60   Event& event, bool isDiff) {
61
62   // Read in info on system to be treated.
63   iParton  = colConfig[iSub].iParton;
64   flav1.id = event[ iParton.front() ].id();
65   flav2.id = event[ iParton.back() ].id(); 
66   pSum     = colConfig[iSub].pSum;
67   mSum     = colConfig[iSub].mass;
68   m2Sum    = mSum*mSum;
69   isClosed = colConfig[iSub].isClosed;
70
71   // Do not want diffractive systems to easily collapse to one particle.
72   int nTryFirst = (isDiff) ? NTRYDIFFRACTIVE : nTryMass;
73
74   // First try to produce two particles from the system.
75   if (ministring2two( nTryFirst, event)) return true;  
76
77   // If this fails, then form one hadron and shuffle momentum.
78   if (ministring2one( iSub, colConfig, event)) return true;  
79
80   // If also this fails, then try harder to produce two particles.
81   if (ministring2two( NTRYLASTRESORT, event)) return true;  
82
83   // Else complete failure.
84   infoPtr->errorMsg("Error in MiniStringFragmentation::fragment: "
85       "no 1- or 2-body state found above mass threshold"); 
86   return false;
87
88 }
89
90 //*********
91
92   // Attempt to produce two particles from the ministring.
93   
94 bool MiniStringFragmentation::ministring2two( int nTry, Event& event) {
95
96   // Properties of the produced hadrons.
97   int    idHad1  = 0;
98   int    idHad2  = 0;
99   double mHad1   = 0.;
100   double mHad2   = 0.;
101   double mHadSum = 0.;
102
103   // Allow a few attempts to find a particle pair with low enough masses.
104   for (int iTry = 0; iTry < nTry; ++iTry) {
105
106     // For closed gluon loop need to pick an initial flavour.
107     if (isClosed) do {
108       int idStart = flavSelPtr->pickLightQ();
109       FlavContainer flavStart(idStart, 1);
110       flavStart = flavSelPtr->pick( flavStart);
111       flav1 = flavSelPtr->pick( flavStart);
112       flav2.anti(flav1);
113     } while (flav1.id == 0 || flav1.nPop > 0);
114    
115     // Create a new q qbar flavour to form two hadrons. 
116     // Start from a diquark, if any.
117     do {
118       FlavContainer flav3 =
119         (abs(flav1.id) > 8 || (abs(flav2.id) < 9 && Rndm::flat() < 0.5) )
120         ? flavSelPtr->pick( flav1) : flavSelPtr->pick( flav2).anti();
121       idHad1 = flavSelPtr->combine( flav1, flav3);
122       idHad2 = flavSelPtr->combine( flav2, flav3.anti());
123     } while (idHad1 == 0 || idHad2 == 0);
124
125     // Check whether the mass sum fits inside the available phase space.  
126     mHad1 = ParticleDataTable::mass(idHad1);
127     mHad2 = ParticleDataTable::mass(idHad2);
128     mHadSum = mHad1 + mHad2;
129     if (mHadSum < mSum) break;
130   } 
131   if (mHadSum >= mSum) return false;
132
133   // Define an effective two-parton string, by splitting intermediate
134   // gluon momenta in proportion to their closeness to either endpoint.
135   Vec4 pSum1 = event[ iParton.front() ].p();
136   Vec4 pSum2 = event[ iParton.back() ].p();
137   if (iParton.size() > 2) {
138     Vec4 pEnd1 = pSum1;
139     Vec4 pEnd2 = pSum2;
140     Vec4 pEndSum = pEnd1 + pEnd2; 
141     for (int i = 1; i < int(iParton.size()) - 1 ; ++i) {
142       Vec4 pNow = event[ iParton[i] ].p();
143       double ratio = (pEnd2 * pNow) / (pEndSum * pNow);
144       pSum1 += ratio * pNow;
145       pSum2 += (1. - ratio) * pNow;
146     }
147   }
148
149   // Set up a string region based on the two effective endpoints.
150   StringRegion region;
151   region.setUp( pSum1, pSum2);
152
153   // Generate an isotropic decay in the ministring rest frame, 
154   // suppressed at large pT by a fragmentation pT Gaussian.
155   double pAbs2 = 0.25 * ( pow2(m2Sum - mHad1*mHad1 - mHad2*mHad2)
156     - pow2(2. * mHad1 * mHad2) ) / m2Sum; 
157   double pT2 = 0.;
158   do {
159     double cosTheta = Rndm::flat();
160     if (sigma < SIGMAMIN) cosTheta = 1.;
161     pT2 = (1. - pow2(cosTheta)) * pAbs2;
162   } while ( exp( -pT2 / sigma2Had) < Rndm::flat() ); 
163
164   // Construct the forward-backward asymmetry of the two particles.
165   double mT21 = mHad1*mHad1 + pT2;
166   double mT22 = mHad2*mHad2 + pT2;
167   double lambda = sqrtpos( pow2(m2Sum  - mT21 - mT22) - 4. * mT21 * mT22 );
168   double probReverse = 1. / (1. + exp( min( 50., bLund * lambda) ) ); 
169
170   // Construct kinematics, as viewed in the transverse rest frame. 
171   double xpz1 = 0.5 * lambda/ m2Sum;
172   if (probReverse > Rndm::flat()) xpz1 = -xpz1; 
173   double xmDiff = (mT21 - mT22) / m2Sum;
174   double xe1 = 0.5 * (1. + xmDiff);
175   double xe2 = 0.5 * (1. - xmDiff ); 
176
177   // Distribute pT isotropically in angle.
178   double phi = 2. * M_PI * Rndm::flat();
179   double pT  = sqrt(pT2);
180   double px  = pT * cos(phi);
181   double py  = pT * sin(phi);
182
183   // Translate this into kinematics in the string frame.
184   Vec4 pHad1 = region.pHad( xe1 + xpz1, xe1 - xpz1,  px,  py);
185   Vec4 pHad2 = region.pHad( xe2 - xpz1, xe2 + xpz1, -px, -py);
186
187   // Add produced particles to the event record.
188   int iFirst = event.append( idHad1, 82, iParton.front(), iParton.back(), 
189     0, 0, 0, 0, pHad1, mHad1);
190   int iLast = event.append( idHad2, 82, iParton.front(), iParton.back(), 
191     0, 0, 0, 0, pHad2, mHad2);
192
193   // Set decay vertex when this is displaced.
194   if (event[iParton.front()].hasVertex()) {
195     Vec4 vDec = event[iParton.front()].vDec();
196     event[iFirst].vProd( vDec );
197     event[iLast].vProd( vDec );
198   }
199
200   // Set lifetime of hadrons.
201   event[iFirst].tau( event[iFirst].tau0() * Rndm::exp() );
202   event[iLast].tau( event[iLast].tau0() * Rndm::exp() );
203
204   // Mark original partons as hadronized and set their daughter range.
205   for (int i = 0; i < int(iParton.size()); ++i) {
206     event[ iParton[i] ].statusNeg();
207     event[ iParton[i] ].daughters(iFirst, iLast);
208   }    
209
210   // Successfully done.
211   return true;
212
213 }
214
215 //*********
216
217 // Attempt to produce one particle from a ministring.
218 // Current algorithm: find the system with largest invariant mass
219 // relative to the existing one, and boost that system appropriately.
220 // Try more sophisticated alternatives later?? (Z0 mass shifted??)
221 // Also, if problems, attempt several times to obtain closer mass match??
222   
223 bool MiniStringFragmentation::ministring2one( int iSub, 
224   ColConfig& colConfig, Event& event) {
225
226   // Cannot handle qq + qbarqbar system. 
227   if (abs(flav1.id) > 100 && abs(flav2.id) > 100) return false;
228
229   // For closed gluon loop need to pick an initial flavour.
230   if (isClosed) do {
231     int idStart = flavSelPtr->pickLightQ(); 
232     FlavContainer flavStart(idStart, 1);
233     flav1 = flavSelPtr->pick( flavStart);
234     flav2 = flav1.anti();
235   } while (abs(flav1.id) > 100);
236
237   // Select hadron flavour from available quark flavours.
238   int idHad = 0;
239   for (int iTryFlav = 0; iTryFlav < NTRYFLAV; ++iTryFlav) {
240     idHad = flavSelPtr->combine( flav1, flav2);
241     if (idHad != 0) break;
242   } 
243   if (idHad == 0) return false;
244
245   // Find mass.  
246   double mHad = ParticleDataTable::mass(idHad);
247   
248   // Find the untreated parton system which combines to the largest 
249   // squared mass above mimimum required. 
250   int iMax = -1;
251   double deltaM2 = mHad*mHad - mSum*mSum; 
252   double delta2Max = 0.;
253   for (int iRec = iSub + 1; iRec < colConfig.size(); ++iRec) {
254     double delta2Rec = 2. * (pSum * colConfig[iRec].pSum) - deltaM2 
255       - 2. * mHad * colConfig[iRec].mass; 
256     if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;}
257   }
258   if (iMax == -1) return false;  
259
260   // Construct kinematics of the hadron and recoiling system. 
261   Vec4& pRec     = colConfig[iMax].pSum;
262   double mRec    = colConfig[iMax].mass;
263   double vecProd = pSum * pRec; 
264   double coefOld = mSum*mSum + vecProd;
265   double coefNew = mHad*mHad + vecProd;
266   double coefRec = mRec*mRec + vecProd;
267   double coefSum = coefOld + coefNew;
268   double sHat    = coefOld + coefRec;
269   double root    = sqrtpos( (pow2(coefSum) - 4. * sHat * mHad*mHad)
270     / (pow2(vecProd) - pow2(mSum * mRec)) );
271   double k2      = 0.5 * (coefOld * root - coefSum) / sHat;
272   double k1      = (coefRec * k2 + 0.5 * deltaM2) / coefOld;
273   Vec4 pHad      = (1. + k1) * pSum - k2 * pRec;
274   Vec4 pRecNew   = (1. + k2) * pRec - k1 * pSum;
275   
276   // Add the produced particle to the event record.
277   int iHad = event.append( idHad, 81, iParton.front(), iParton.back(), 
278     0, 0, 0, 0, pHad, mHad);
279
280   // Set decay vertex when this is displaced.
281   if (event[iParton.front()].hasVertex()) {
282     Vec4 vDec = event[iParton.front()].vDec();
283     event[iHad].vProd( vDec );
284   }
285
286   // Set lifetime of hadron.
287   event[iHad].tau( event[iHad].tau0() * Rndm::exp() );
288
289   // Mark original partons as hadronized and set their daughter range.
290   for (int i = 0; i < int(iParton.size()); ++i) {
291     event[ iParton[i] ].statusNeg();
292     event[ iParton[i] ].daughters(iHad, iHad);
293   }    
294    
295   // Copy down recoiling system, with boosted momentum. Update current partons.
296   RotBstMatrix M;
297   M.bst(pRec, pRecNew); 
298   for (int i = 0; i < colConfig[iMax].size(); ++i) {
299     int iOld = colConfig[iMax].iParton[i];
300     // Do not touch negative iOld = beginning of new junction leg.
301     if (iOld >= 0) {
302       int iNew = event.copy(iOld, 72);
303       event[iNew].rotbst(M);
304       colConfig[iMax].iParton[i] = iNew;
305     }
306   }
307   colConfig[iMax].pSum = pRecNew;
308   colConfig[iMax].isCollected = true;
309
310   // Successfully done.
311   return true;
312
313 }
314
315 //**************************************************************************
316
317 } // end namespace Pythia8