StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
MiniStringFragmentation.cc
1 // MiniStringFragmentation.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2020 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, 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 "Pythia8/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 // Loop try to combine available endquarks to valid hadron.
29 const int MiniStringFragmentation::NTRYFLAV = 10;
30 
31 //--------------------------------------------------------------------------
32 
33 // Initialize and save pointers.
34 
35 void MiniStringFragmentation::init(StringFlav* flavSelPtrIn,
36  StringPT* pTSelPtrIn, StringZ* zSelPtrIn) {
37 
38  // Save pointers.
39  flavSelPtr = flavSelPtrIn;
40  pTSelPtr = pTSelPtrIn;
41  zSelPtr = zSelPtrIn;
42 
43  // Calculation and definition of hadron space-time production vertices.
44  hadronVertex = mode("HadronVertex:mode");
45  setVertices = flag("Fragmentation:setVertices")
46  || flag("HadronLevel:Rescatter");
47  kappaVtx = parm("HadronVertex:kappa");
48  smearOn = flag("HadronVertex:smearOn");
49  xySmear = parm("HadronVertex:xySmear");
50  constantTau = flag("HadronVertex:constantTau");
51 
52  // Charm and bottom quark masses used for space-time offset.
53  mc = particleDataPtr->m0(4);
54  mb = particleDataPtr->m0(5);
55 
56  // Initialize the MiniStringFragmentation class proper.
57  nTryMass = mode("MiniStringFragmentation:nTry");
58 
59  // Initialize the b parameter of the z spectrum, used when joining jets.
60  bLund = zSelPtr->bAreaLund();
61 
62 }
63 
64 //--------------------------------------------------------------------------
65 
66 // Do the fragmentation: driver routine.
67 
68 bool MiniStringFragmentation::fragment(int iSub, ColConfig& colConfig,
69  Event& event, bool isDiff, bool systemRecoil) {
70 
71  // Junction topologies not yet considered - is very rare.
72  iParton = colConfig[iSub].iParton;
73  if (iParton.front() < 0) {
74  infoPtr->errorMsg("Error in MiniStringFragmentation::fragment: "
75  "very low-mass junction topologies not yet handled");
76  return false;
77  }
78 
79  // Read in info on system to be treated.
80  flav1 = FlavContainer( event[ iParton.front() ].id() );
81  flav2 = FlavContainer( event[ iParton.back() ].id() );
82  pSum = colConfig[iSub].pSum;
83  mSum = colConfig[iSub].mass;
84  m2Sum = mSum*mSum;
85  isClosed = colConfig[iSub].isClosed;
86 
87  // Do not want diffractive systems to easily collapse to one particle.
88  int nTryFirst = (isDiff) ? NTRYDIFFRACTIVE : nTryMass;
89 
90  // First try to produce two hadrons from the system.
91  if (ministring2two( nTryFirst, event, false)) return true;
92 
93  // If this fails, then form one hadron and shuffle momentum.
94  if (ministring2one( iSub, colConfig, event, false)) return true;
95 
96  // If also this fails, try to produce two hadrons with lower mass.
97  if (ministring2two( NTRYLASTRESORT, event, true)) return true;
98 
99  // If also this fails, try to form a hadron with lower mass.
100  if (ministring2one( iSub, colConfig, event, true)) return true;
101 
102  // For low-energy systems may also search for a single hadron recoiler.
103  if (!systemRecoil) {
104  if (ministring2one( iSub, colConfig, event, false, false)) return true;
105  if (ministring2one( iSub, colConfig, event, true, false)) return true;
106  }
107 
108  // Else complete failure.
109  infoPtr->errorMsg("Error in MiniStringFragmentation::fragment: "
110  "no 1- or 2-body state found above mass threshold");
111  return false;
112 
113 }
114 
115 //--------------------------------------------------------------------------
116 
117 // Attempt to produce two particles from the ministring.
118 // Note that popcorn baryons not allowed.
119 
120 bool MiniStringFragmentation::ministring2two( int nTry, Event& event,
121  bool findLowMass) {
122 
123  // Properties of the produced hadrons.
124  int idHad1 = 0;
125  int idHad2 = 0;
126  double mHad1 = 0.;
127  double mHad2 = 0.;
128  double mHadSum = 0.;
129 
130  // Allow a few attempts to find a particle pair with low enough masses.
131  for (int iTry = 0; iTry < nTry; ++iTry) {
132 
133  // For closed gluon loop need to pick an initial flavour.
134  if (isClosed) do {
135  int idStart = flavSelPtr->pickLightQ();
136  FlavContainer flavStart(idStart, 1);
137  flavStart = flavSelPtr->pick( flavStart, -1., 0., false);
138  flav1 = flavSelPtr->pick( flavStart, -1., 0., false);
139  flav2.anti(flav1);
140  } while (flav1.id == 0 || flav1.nPop > 0);
141 
142  // Create a new q qbar flavour to form two hadrons.
143  // Start from a diquark, if any.
144  do {
145  FlavContainer flav3 =
146  (flav1.isDiquark() || (!flav2.isDiquark() && rndmPtr->flat() < 0.5) )
147  ? flavSelPtr->pick( flav1, -1., 0., false)
148  : flavSelPtr->pick( flav2, -1., 0., false).anti();
149  if (findLowMass) {
150  idHad1 = flavSelPtr->combineToLightest( flav1.id, flav3.id);
151  idHad2 = flavSelPtr->combineToLightest( flav2.id, -flav3.id);
152  } else {
153  idHad1 = flavSelPtr->combine( flav1, flav3);
154  idHad2 = flavSelPtr->combine( flav2, flav3.anti());
155  }
156  } while (idHad1 == 0 || idHad2 == 0);
157 
158  // Check whether the mass sum fits inside the available phase space.
159  mHad1 = particleDataPtr->mSel(idHad1);
160  mHad2 = particleDataPtr->mSel(idHad2);
161  mHadSum = mHad1 + mHad2;
162  if (mHadSum < mSum) break;
163  }
164 
165  // As last resort keep original flavours and split off pi0. Else fail.
166  if (mHadSum >= mSum && findLowMass && !isClosed) {
167  idHad1 = flavSelPtr->combineToLightest( flav1.id, flav2.id);
168  idHad2 = 111;
169  mHad1 = particleDataPtr->mSel(idHad1);
170  mHad2 = particleDataPtr->mSel(idHad2);
171  mHadSum = mHad1 + mHad2;
172  }
173  if (mHadSum >= mSum) return false;
174 
175  // Define an effective two-parton string, by splitting intermediate
176  // gluon momenta in proportion to their closeness to either endpoint.
177  Vec4 pSum1 = event[ iParton.front() ].p();
178  Vec4 pSum2 = event[ iParton.back() ].p();
179  if (iParton.size() > 2) {
180  Vec4 pEnd1 = pSum1;
181  Vec4 pEnd2 = pSum2;
182  Vec4 pEndSum = pEnd1 + pEnd2;
183  for (int i = 1; i < int(iParton.size()) - 1 ; ++i) {
184  Vec4 pNow = event[ iParton[i] ].p();
185  double ratio = (pEnd2 * pNow) / (pEndSum * pNow);
186  pSum1 += ratio * pNow;
187  pSum2 += (1. - ratio) * pNow;
188  }
189  }
190 
191  // If split did not provide an axis then pick random axis to break tie.
192  // (Needed for low-mass q-g-qbar with q-qbar perfectly parallel.)
193  if (pSum1.mCalc() + pSum2.mCalc() > 0.999999 * mSum) {
194  double cthe = 2. * rndmPtr->flat() - 1.;
195  double sthe = sqrtpos(1. - cthe * cthe);
196  double phi = 2. * M_PI * rndmPtr->flat();
197  Vec4 delta = 0.5 * min( pSum1.e(), pSum2.e())
198  * Vec4( sthe * sin(phi), sthe * cos(phi), cthe, 0.);
199  pSum1 += delta;
200  pSum2 -= delta;
201  infoPtr->errorMsg("Warning in MiniStringFragmentation::ministring2two: "
202  "random axis needed to break tie");
203  }
204 
205  // Set up a string region based on the two effective endpoints.
206  StringRegion region;
207  region.setUp( pSum1, pSum2, 0, 0);
208 
209  // Generate an isotropic decay in the ministring rest frame,
210  // suppressed at large pT by a fragmentation pT Gaussian.
211  double pAbs2 = 0.25 * ( pow2(m2Sum - mHad1*mHad1 - mHad2*mHad2)
212  - pow2(2. * mHad1 * mHad2) ) / m2Sum;
213  double pT2 = 0.;
214  do {
215  double cosTheta = rndmPtr->flat();
216  pT2 = (1. - pow2(cosTheta)) * pAbs2;
217  } while (pTSelPtr->suppressPT2(pT2) < rndmPtr->flat() );
218 
219  // Construct the forward-backward asymmetry of the two particles.
220  double mT21 = mHad1*mHad1 + pT2;
221  double mT22 = mHad2*mHad2 + pT2;
222  double lambda = sqrtpos( pow2(m2Sum - mT21 - mT22) - 4. * mT21 * mT22 );
223  double probReverse = 1. / (1. + exp( min( 50., bLund * lambda) ) );
224 
225  // Construct kinematics, as viewed in the transverse rest frame.
226  double xpz1 = 0.5 * lambda/ m2Sum;
227  if (probReverse > rndmPtr->flat()) xpz1 = -xpz1;
228  double xmDiff = (mT21 - mT22) / m2Sum;
229  double xe1 = 0.5 * (1. + xmDiff);
230  double xe2 = 0.5 * (1. - xmDiff );
231 
232  // Distribute pT isotropically in angle.
233  double phi = 2. * M_PI * rndmPtr->flat();
234  double pT = sqrt(pT2);
235  double px = pT * cos(phi);
236  double py = pT * sin(phi);
237 
238  // Translate this into kinematics in the string frame.
239  Vec4 pHad1 = region.pHad( xe1 + xpz1, xe1 - xpz1, px, py);
240  Vec4 pHad2 = region.pHad( xe2 - xpz1, xe2 + xpz1, -px, -py);
241 
242  // Mark hadrons from junction fragmentation with different status.
243  int statusHadPos = 82, statusHadNeg = 82;
244  if (abs(idHad1) > 1000 && abs(idHad1) < 10000 &&
245  abs(idHad2) > 1000 && abs(idHad2) < 10000) {
246  if (event[ iParton.front() ].statusAbs() == 74) statusHadPos = 89;
247  if (event[ iParton.back() ].statusAbs() == 74) statusHadNeg = 89;
248  }
249  else if (abs(idHad1) > 1000 && abs(idHad1) < 10000) {
250  if (event[ iParton.front() ].statusAbs() == 74 ||
251  event[ iParton.back() ].statusAbs() == 74) statusHadPos = 89;
252  }
253  else if (abs(idHad2) > 1000 && abs(idHad2) < 10000) {
254  if (event[ iParton.front() ].statusAbs() == 74 ||
255  event[ iParton.back() ].statusAbs() == 74) statusHadNeg = 89;
256  }
257  // Add produced particles to the event record.
258  int iFirst = event.append( idHad1, statusHadPos, iParton.front(),
259  iParton.back(), 0, 0, 0, 0, pHad1, mHad1);
260  int iLast = event.append( idHad2, statusHadNeg, iParton.front(),
261  iParton.back(), 0, 0, 0, 0, pHad2, mHad2);
262 
263  // Set decay vertex when this is displaced.
264  if (event[iParton.front()].hasVertex()) {
265  Vec4 vDec = event[iParton.front()].vDec();
266  event[iFirst].vProd( vDec );
267  event[iLast].vProd( vDec );
268  }
269 
270  // Set lifetime of hadrons.
271  event[iFirst].tau( event[iFirst].tau0() * rndmPtr->exp() );
272  event[iLast].tau( event[iLast].tau0() * rndmPtr->exp() );
273 
274  // Mark original partons as hadronized and set their daughter range.
275  for (int i = 0; i < int(iParton.size()); ++i) {
276  event[ iParton[i] ].statusNeg();
277  event[ iParton[i] ].daughters(iFirst, iLast);
278  }
279 
280  // Store breakup vertex information from the fragmentation process.
281  if (setVertices) {
282  ministringVertices.clear();
283  ministringVertices.push_back( StringVertex(true, 0, 0, 1., 0.) );
284  ministringVertices.push_back(
285  StringVertex(true, 0, 0, 1. - (xe1 + xpz1), xe1 - xpz1) );
286  ministringVertices.push_back( StringVertex(true, 0, 0, 0., 1.) );
287 
288  // Store hadron production space-time vertices.
289  setHadronVertices( event, region, iFirst, iLast);
290  }
291 
292  // Successfully done.
293  return true;
294 
295 }
296 
297 //--------------------------------------------------------------------------
298 
299 // Attempt to produce one particle from a ministring.
300 // Current algorithm: find the system with largest invariant mass
301 // relative to the existing one, and boost that system appropriately.
302 // Optionally force pick lightest hadron possible to increase chances.
303 // Optionally let existing hadron take recoil instead of system.
304 // Try more sophisticated alternatives later?? (Z0 mass shifted??)
305 
306 bool MiniStringFragmentation::ministring2one( int iSub,
307  ColConfig& colConfig, Event& event, bool findLowMass, bool systemRecoil) {
308 
309  // Cannot handle qq + qbarqbar system.
310  if (abs(flav1.id) > 100 && abs(flav2.id) > 100) return false;
311 
312  // For closed gluon loop need to pick an initial flavour.
313  if (isClosed) do {
314  int idStart = flavSelPtr->pickLightQ();
315  FlavContainer flavStart(idStart, 1);
316  flav1 = flavSelPtr->pick( flavStart);
317  flav2 = flav1.anti();
318  } while (abs(flav1.id) > 100);
319 
320  // Select hadron flavour from available quark flavours,
321  // optionally with lowest possible mass.
322  int idHad = 0;
323  if (findLowMass) idHad = flavSelPtr->combineToLightest( flav1.id, flav2.id);
324  else for (int iTryFlav = 0; iTryFlav < NTRYFLAV; ++iTryFlav) {
325  idHad = flavSelPtr->combine( flav1, flav2);
326  if (idHad != 0) break;
327  }
328  if (idHad == 0) return false;
329 
330  // Find mass.
331  double mHad = particleDataPtr->mSel(idHad);
332 
333  // Find the untreated parton system, alternatively final hadron,
334  // which combines to the largest squared mass above mimimum required.
335  int iMax = -1;
336  double deltaM2 = mHad*mHad - mSum*mSum;
337  double delta2Max = 0.;
338  if (systemRecoil) {
339  for (int iRec = iSub + 1; iRec < colConfig.size(); ++iRec) {
340  double delta2Rec = 2. * (pSum * colConfig[iRec].pSum) - deltaM2
341  - 2. * mHad * colConfig[iRec].mass;
342  if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;}
343  }
344  } else {
345  for (int iRec = 0; iRec < event.size(); ++iRec)
346  if (event[iRec].isHadron() && event[iRec].status() > 80) {
347  double delta2Rec = 2. * (pSum * event[iRec].p()) - deltaM2
348  - 2. * mHad * event[iRec].m();
349  if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;}
350  }
351  }
352  if (iMax == -1) return false;
353 
354  // Construct kinematics of the hadron and recoiling system (or hadron).
355  Vec4 pRec = (systemRecoil) ? colConfig[iMax].pSum : event[iMax].p();
356  double mRec = (systemRecoil) ? colConfig[iMax].mass : event[iMax].m();
357  double vecProd = pSum * pRec;
358  double coefOld = mSum*mSum + vecProd;
359  double coefNew = mHad*mHad + vecProd;
360  double coefRec = mRec*mRec + vecProd;
361  double coefSum = coefOld + coefNew;
362  double sHat = coefOld + coefRec;
363  double root = sqrtpos( (pow2(coefSum) - 4. * sHat * mHad*mHad)
364  / (pow2(vecProd) - pow2(mSum * mRec)) );
365  double k2 = 0.5 * (coefOld * root - coefSum) / sHat;
366  double k1 = (coefRec * k2 + 0.5 * deltaM2) / coefOld;
367  Vec4 pHad = (1. + k1) * pSum - k2 * pRec;
368  Vec4 pRecNew = (1. + k2) * pRec - k1 * pSum;
369 
370  // Mark hadrons from junction split off with status 89.
371  int statusHad = 81;
372  if (abs(idHad) > 1000 && abs(idHad) < 10000 &&
373  (event[ iParton.front() ].statusAbs() == 74 ||
374  event[ iParton.back() ].statusAbs() == 74)) statusHad = 89;
375 
376  // Add the produced particle to the event record.
377  int iHad = event.append( idHad, statusHad, iParton.front(), iParton.back(),
378  0, 0, 0, 0, pHad, mHad);
379 
380  // Set decay vertex when this is displaced.
381  if (event[iParton.front()].hasVertex()) {
382  Vec4 vDec = event[iParton.front()].vDec();
383  event[iHad].vProd( vDec );
384  }
385 
386  // Set lifetime of hadron.
387  event[iHad].tau( event[iHad].tau0() * rndmPtr->exp() );
388 
389  // Mark original partons as hadronized and set their daughter range.
390  for (int i = 0; i < int(iParton.size()); ++i) {
391  event[ iParton[i] ].statusNeg();
392  event[ iParton[i] ].daughters(iHad, iHad);
393  }
394 
395  // Copy down recoiling system, with boosted momentum. Update current partons.
396  RotBstMatrix M;
397  M.bst(pRec, pRecNew);
398  if (systemRecoil) {
399  for (int i = 0; i < colConfig[iMax].size(); ++i) {
400  int iOld = colConfig[iMax].iParton[i];
401  // Do not touch negative iOld = beginning of new junction leg.
402  if (iOld >= 0) {
403  int iNew;
404  // Keep track of 74 throughout the event.
405  if (event[iOld].status() == 74) iNew = event.copy(iOld, 74);
406  else iNew = event.copy(iOld, 72);
407  event[iNew].rotbst(M);
408  colConfig[iMax].iParton[i] = iNew;
409  }
410  }
411  colConfig[iMax].pSum = pRecNew;
412  colConfig[iMax].isCollected = true;
413 
414  // Alternatively copy down modified hadron and boost it (including vertex).
415  } else {
416  int iNew = event.copy(iMax, event[iMax].status());
417  event[iNew].rotbst(M);
418  }
419 
420  // Calculate hadron production points from breakup vertices
421  // using one of the three definitions.
422  if (setVertices) {
423  Vec4 prodPoint = Vec4( 0., 0., 0., 0.);
424  Vec4 pHadron = event[iHad].p();
425 
426  // Smearing in transverse space.
427  if (smearOn) {
428 
429  // Find two spacelike transverse four-vector directions.
430  Vec4 eX = Vec4( 1., 0., 0., 0.);
431  Vec4 eY = Vec4( 0., 1., 0., 0.);
432 
433  // Introduce smearing in transverse space.
434  double transX = rndmPtr -> gauss();
435  double transY = rndmPtr -> gauss();
436  prodPoint = xySmear * (transX * eX + transY * eY) / sqrt(2.);
437  // Keep proper or actual time constant when including the smearing.
438  // Latter case to be done better when introducing MPI vertices.
439  if (constantTau) prodPoint.e( prodPoint.pAbs() );
440  else prodPoint = Vec4( 0., 0., 0., 0.);
441  }
442 
443  // Reduced oscillation period if hadron contains massive quarks.
444  int id1 = event[ iParton.front() ].idAbs();
445  int id2 = event[ iParton.back() ].idAbs();
446  double redOsc = 1.;
447  if (id1 == 4 || id1 == 5 || id2 == 4 || id2 == 5) {
448  double posMass = (id1 == 4 || id1 == 5) ? particleDataPtr->m0(id1) : 0.;
449  double negMass = (id2 == 4 || id2 == 5) ? particleDataPtr->m0(id2) : 0.;
450  redOsc = sqrtpos( pow2(pow2(mHad) - pow2(posMass) - pow2(negMass))
451  - 4. * pow2(posMass * negMass) ) / pow2(mHad);
452  }
453 
454  // Find hadron production points according to chosen definition.
455  if (hadronVertex == 0) prodPoint += 0.5 * redOsc * pHadron / kappaVtx;
456  else if (hadronVertex == 1) prodPoint += redOsc * pHadron / kappaVtx;
457  event[iHad].vProd( prodPoint * FM2MM );
458  }
459 
460  // Successfully done.
461  return true;
462 
463 }
464 
465 //--------------------------------------------------------------------------
466 
467 // Store two hadron production points in the event record.
468 
469 void MiniStringFragmentation::setHadronVertices(Event& event,
470  StringRegion& region, int iFirst, int iLast) {
471 
472  // Initial values.
473  vector<Vec4> longitudinal;
474  int id1 = event[ iParton.front() ].idAbs();
475  int id2 = event[ iParton.back() ].idAbs();
476 
477  // Longitudinal space-time location of breakup points.
478  for (int i = 0; i < 3; ++i) {
479  double xPosIn = ministringVertices[i].xRegPos;
480  double xNegIn = ministringVertices[i].xRegNeg;
481  Vec4 noOffset = (xPosIn * region.pPos + xNegIn * region.pNeg) / kappaVtx;
482  longitudinal.push_back( noOffset );
483  }
484 
485  // Longitudinal offset of breakup points for massive quarks.
486  if (region.massiveOffset( 0, 0, 0, id1, id2, mc, mb)) {
487  for (int i = 0; i < 3; ++i) {
488 
489  // Endpoint correction separately for each end.
490  if (i == 0 && (id1 == 4 || id1 == 5)) {
491  Vec4 v1 = longitudinal[i];
492  Vec4 v2 = longitudinal[i + 1];
493  double mHad = event[event.size() - 2].m();
494  double pPosMass = particleDataPtr->m0(id1);
495  longitudinal[i] = v1 + (pPosMass / mHad) * (v2 - v1);
496  }
497  if (i == 2 && (id2 == 4 || id2== 5)) {
498  Vec4 v1 = longitudinal[i];
499  Vec4 v2 = longitudinal[i-1] + region.massOffset / kappaVtx;
500  double mHad = event[i - 1 + event.size() - 2].m();
501  double pNegMass = particleDataPtr->m0(id2);
502  longitudinal[i] = v1 + (pNegMass / mHad) * (v2 - v1);
503  if (longitudinal[i].m2Calc()
504  < -1e-8 * max(1., pow2(longitudinal[i].e())))
505  infoPtr->errorMsg("Warning in MiniStringFragmentation::set"
506  "Vertices: negative tau^2 for endpoint massive correction");
507  }
508 
509  // Add mass offset for all breakup points.
510  Vec4 massOffset = region.massOffset / kappaVtx;
511  Vec4 position = longitudinal[i] - massOffset;
512 
513  // Correction for non-physical situations.
514  if (position.m2Calc() < 0.) {
515  double cMinus = 0.;
516  if (position.m2Calc() > -1e-8 * max(1., pow2(position.e())))
517  position.e( position.pAbs() );
518  else {
519  if(massOffset.m2Calc() > 1e-6)
520  cMinus = (longitudinal[i] * massOffset
521  - sqrt(pow2(longitudinal[i] * massOffset)
522  - longitudinal[i].m2Calc() * massOffset.m2Calc()))
523  / massOffset.m2Calc();
524  else cMinus = 0.5 * longitudinal[i].m2Calc()
525  / (longitudinal[i] * massOffset);
526  position = longitudinal[i] - cMinus * massOffset;
527  }
528  }
529  longitudinal[i] = position;
530  }
531  }
532 
533  // Smearing in transverse space.
534  vector<Vec4> spaceTime;
535  for (int i = 0; i < 3; ++i) {
536  Vec4 positionTot = longitudinal[i];
537  if (smearOn) {
538 
539  if (!isClosed && (i == 0 || i == 2)) {
540  spaceTime.push_back(positionTot);
541  continue;
542  }
543  Vec4 eX = region.eX;
544  Vec4 eY = region.eY;
545 
546  // Smearing calculated randomly following a gaussian.
547  for (int iTry = 0; ; ++iTry) {
548  double transX = rndmPtr->gauss();
549  double transY = rndmPtr->gauss();
550  Vec4 transversePos = xySmear * (transX * eX + transY * eY) / sqrt(2.);
551  positionTot = transversePos + longitudinal[i];
552 
553  // Keep proper or actual time constant when including the smearing.
554  // Latter case to be done better when introducing MPI vertices.
555  if (constantTau) {
556  double newtime = sqrt(longitudinal[i].m2Calc()
557  + positionTot.pAbs2());
558  positionTot.e(newtime);
559  break;
560  } else {
561  if (positionTot.m2Calc() >= 0.) break;
562  if (iTry == 100) {
563  positionTot = longitudinal[i];
564  break;
565  }
566  }
567  }
568  }
569  spaceTime.push_back(positionTot);
570  }
571 
572  // Find hadron production points according to chosen definition.
573  vector<Vec4> prodPoints(2);
574  for(int i = 0; i < 2; ++i) {
575  Vec4 middlePoint = 0.5 * (spaceTime[i] + spaceTime[i+1]);
576  int iHad = (i == 0) ? iFirst : iLast;
577  Vec4 pHad = event[iHad].p();
578 
579  // Reduced oscillation period if hadron contains massive quarks.
580  double mHad = event[iHad].m();
581  int idQ = (i == 0) ? id1 : id2;
582  double redOsc = (idQ == 4 || idQ == 5)
583  ? 1. - pow2(particleDataPtr->m0(idQ) / mHad) : 0.;
584 
585  // Set production point according to chosen definition.
586  if (hadronVertex == 0) prodPoints[i] = middlePoint;
587  else if (hadronVertex == 1)
588  prodPoints[i] = middlePoint + 0.5 * redOsc * pHad / kappaVtx;
589  else {
590  prodPoints[i] = middlePoint - 0.5 * redOsc * pHad / kappaVtx;
591  if (prodPoints[i].m2Calc() < 0. || prodPoints[i].e() < 0.) {
592  double tau0fac = 2. * (redOsc * middlePoint * pHad
593  - sqrt(pow2(middlePoint * redOsc * pHad) - middlePoint.m2Calc()
594  * pow2(redOsc * mHad))) / pow2(redOsc * mHad);
595  prodPoints[i] = middlePoint - 0.5 * tau0fac * redOsc * pHad / kappaVtx;
596  }
597  }
598  event[iHad].vProd( prodPoints[i] * FM2MM );
599  }
600 
601 }
602 
603 //==========================================================================
604 
605 } // end namespace Pythia8
Definition: AgUStep.h:26