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