]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx
using option '-treename HLTesdTree' for EsdCollector, adding default parameter for...
[u/mrichter/AliRoot.git] / PYTHIA8 / pythia8130 / src / MiniStringFragmentation.cxx
CommitLineData
5ad4eb21 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
11namespace 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.
23const int MiniStringFragmentation::NTRYDIFFRACTIVE = 200;
24
25// After one-body fragmentation failed, try two-body once more.
26const int MiniStringFragmentation::NTRYLASTRESORT = 100;
27
28// To avoid division by zero one must have sigma > 0.
29const double MiniStringFragmentation::SIGMAMIN = 0.01;
30
31// Loop try to combine available endquarks to valid hadron.
32const int MiniStringFragmentation::NTRYFLAV = 10;
33
34//*********
35
36// Initialize and save pointers.
37
38void 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
59bool 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
94bool 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
223bool 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