StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
FragmentationSystems.cc
1 // FragmentationSystems.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 // ColConfig, StringRegion and StringSystem classes.
8 
9 #include "Pythia8/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, StringFlav* flavSelPtrIn) {
30 
31  Settings* settingsPtr = infoPtrIn->settingsPtr;
32 
33  // Save pointers.
34  infoPtr = infoPtrIn;
35  flavSelPtr = flavSelPtrIn;
36 
37  // Joining of nearby partons along the string.
38  mJoin = settingsPtr->parm("FragmentationSystems:mJoin");
39 
40  // For consistency ensure that mJoin is bigger than in StringRegion.
41  mJoin = max( mJoin, 2. * StringRegion::MJOIN);
42 
43  // Simplification of q q q junction topology to quark - diquark one.
44  mJoinJunction = settingsPtr->parm("FragmentationSystems:mJoinJunction");
45  mStringMin = settingsPtr->parm("HadronLevel:mStringMin");
46 
47 }
48 
49 //--------------------------------------------------------------------------
50 
51 // Insert a new colour singlet system in ascending mass order.
52 // Calculate its properties. Join nearby partons.
53 
54 bool ColConfig::insert( vector<int>& iPartonIn, Event& event) {
55 
56  // Find momentum and invariant mass of system, minus endpoint masses.
57  Vec4 pSumIn;
58  double mSumIn = 0.;
59  bool hasJunctionIn = false;
60  int nJunctionLegs = 0;
61  for (int i = 0; i < int(iPartonIn.size()); ++i) {
62  if (iPartonIn[i] < 0) {
63  hasJunctionIn = true;
64  ++nJunctionLegs;
65  } else {
66  pSumIn += event[ iPartonIn[i] ].p();
67  if (!event[ iPartonIn[i] ].isGluon())
68  mSumIn += event[ iPartonIn[i] ].constituentMass();
69  }
70  }
71  double massIn = pSumIn.mCalc();
72  double massExcessIn = massIn - mSumIn;
73 
74  // Check for rare triple- and higher junction systems (like J-Jbar-J)
75  if (nJunctionLegs >= 5) {
76  infoPtr->errorMsg("Error in ColConfig::insert: "
77  "junction topology too complicated; too many junction legs");
78  return false;
79  }
80  // Check that junction systems have at least three legs.
81  else if (nJunctionLegs > 0 && nJunctionLegs <= 2) {
82  infoPtr->errorMsg("Error in ColConfig::insert: "
83  "junction topology inconsistent; too few junction legs");
84  return false;
85  }
86 
87  // Check that momenta do not contain not-a-number.
88  if (abs(massExcessIn) >= 0.);
89  else {
90  infoPtr->errorMsg("Error in ColConfig::insert: "
91  "not-a-number system mass");
92  return false;
93  }
94 
95  // Identify closed gluon loop. Assign "endpoint" masses as light quarks.
96  bool isClosedIn = (iPartonIn[0] >= 0 && event[ iPartonIn[0] ].col() != 0
97  && event[ iPartonIn[0] ].acol() != 0 );
98  if (isClosedIn) massExcessIn -= 2. * CONSTITUENTMASS;
99 
100  // For junction topology: join two nearby legs into a diquark.
101  if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn))
102  hasJunctionIn = false;
103 
104  // Loop while > 2 partons left and hope of finding joining pair.
105  bool hasJoined = true;
106  while (hasJoined && iPartonIn.size() > 2) {
107 
108  // Look for the pair of neighbour partons (along string) with
109  // the smallest invariant mass (subtracting quark masses).
110  int iJoinMin = -1;
111  double mJoinMin = 2. * mJoin;
112  int nSize = iPartonIn.size();
113  int nPair = (isClosedIn) ? nSize : nSize - 1;
114  for (int i = 0; i < nPair; ++i) {
115  // Keep three legs of junction separate.
116  if (iPartonIn[i] < 0 || iPartonIn[(i + 1)%nSize] < 0) continue;
117  Particle& parton1 = event[ iPartonIn[i] ];
118  Particle& parton2 = event[ iPartonIn[(i + 1)%nSize] ];
119  // Avoid joining non-partons, e.g. gluino/squark for R-hadron.
120  if (!parton1.isParton() || !parton2.isParton()) continue;
121  Vec4 pSumNow;
122  pSumNow += (parton1.isGluon()) ? 0.5 * parton1.p() : parton1.p();
123  pSumNow += (parton2.isGluon()) ? 0.5 * parton2.p() : parton2.p();
124  double mJoinNow = pSumNow.mCalc();
125  if (!parton1.isGluon()) mJoinNow -= parton1.m();
126  if (!parton2.isGluon()) mJoinNow -= parton2.m();
127  if (mJoinNow < mJoinMin) { iJoinMin = i; mJoinMin = mJoinNow; }
128  }
129 
130  // If sufficiently nearby then join into one new parton.
131  // Note: error sensitivity to mJoin indicates unstable precedure??
132  hasJoined = false;
133  if (mJoinMin < mJoin) {
134  int iJoin1 = iPartonIn[iJoinMin];
135  int iJoin2 = iPartonIn[(iJoinMin + 1)%nSize];
136  int idNew = (event[iJoin1].isGluon()) ? event[iJoin2].id()
137  : event[iJoin1].id();
138  int iMoth1 = min(iJoin1, iJoin2);
139  int iMoth2 = max(iJoin1, iJoin2);
140  // When g + q -> q flip to ensure that mother1 = q.
141  if (event[iMoth1].id() == 21 && event[iMoth2].id() != 21)
142  swap( iMoth1, iMoth2);
143  int colNew = event[iJoin1].col();
144  int acolNew = event[iJoin2].acol();
145  if (colNew == acolNew) {
146  colNew = event[iJoin2].col();
147  acolNew = event[iJoin1].acol();
148  }
149  Vec4 pNew = event[iJoin1].p() + event[iJoin2].p();
150 
151  int statusHad = 73;
152  // Need to keep status as 74 for junctions in order to keep track
153  // of them.
154  if (event[iMoth1].statusAbs() == 74) statusHad = 74;
155 
156  // Append joined parton to event record.
157  int iNew = event.append( idNew, statusHad, iMoth1, iMoth2, 0, 0,
158  colNew, acolNew, pNew, pNew.mCalc() );
159 
160  // Displaced lifetime/vertex; mothers should be same but prefer quark.
161  int iVtx = (event[iJoin1].isGluon()) ? iJoin2 : iJoin1;
162  event[iNew].tau( event[iVtx].tau() );
163  if (event[iVtx].hasVertex()) event[iNew].vProd( event[iVtx].vProd() );
164 
165  // Mark joined partons and reduce remaining system.
166  event[iJoin1].statusNeg();
167  event[iJoin2].statusNeg();
168  event[iJoin1].daughter1(iNew);
169  event[iJoin2].daughter1(iNew);
170  if (iJoinMin == nSize - 1) iPartonIn[0] = iNew;
171  else {
172  iPartonIn[iJoinMin] = iNew;
173  for (int i = iJoinMin + 1; i < nSize - 1; ++i)
174  iPartonIn[i] = iPartonIn[i + 1];
175  }
176  iPartonIn.pop_back();
177 
178  // If joined,then loopback to look for more.
179  hasJoined = true;
180  }
181  }
182 
183  // Store new colour singlet system at the end.
184  singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
185  massExcessIn, hasJunctionIn, isClosedIn) );
186 
187  // Now move around, so that smallest mass excesses come first.
188  int iInsert = singlets.size() - 1;
189  for (int iSub = singlets.size() - 2; iSub >= 0; --iSub) {
190  if (massExcessIn > singlets[iSub].massExcess) break;
191  singlets[iSub + 1] = singlets[iSub];
192  iInsert = iSub;
193  }
194  if (iInsert < int(singlets.size()) - 1) singlets[iInsert] =
195  ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn,
196  hasJunctionIn, isClosedIn);
197 
198  // Done.
199  return true;
200 }
201 
202 //--------------------------------------------------------------------------
203 
204 // Insert a new qqbar colour singlet system in ascending mass order.
205 // Simple version for at most two triplet-antitriplet systems.
206 
207 bool ColConfig::simpleInsert( vector<int>& iPartonIn, Event& event,
208  bool fixOrder) {
209 
210  // Find momentum and invariant mass of system, minus endpoint masses.
211  Vec4 pSumIn = event[ iPartonIn[0] ].p() + event[ iPartonIn[1] ].p();
212  double mSumIn = event[ iPartonIn[0] ].constituentMass()
213  + event[ iPartonIn[1] ].constituentMass();
214  double massIn = pSumIn.mCalc();
215  double massExcessIn = massIn - mSumIn;
216 
217  // Store new colour singlet system at the end.
218  singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
219  massExcessIn, false, false) );
220 
221  // If necessary flip so that smallest mass excesses come first.
222  if (!fixOrder && singlets.size() == 2 && massExcessIn
223  < singlets[0].massExcess) swap( singlets[0], singlets[1]);
224 
225  // Done.
226  return true;
227 }
228 
229 //--------------------------------------------------------------------------
230 
231 // Join two legs of junction to a diquark for small invariant masses.
232 // Note: for junction system, iPartonIn points to structure
233 // (-code0) g...g.q0 (-code1) g...g.q1 (-code2) g...g.q2
234 
235 bool ColConfig::joinJunction( vector<int>& iPartonIn, Event& event,
236  double massExcessIn) {
237 
238  // Find four-momentum and endpoint quarks and masses on the three legs.
239  Vec4 pLeg[3];
240  double mLeg[3] = { 0., 0., 0.};
241  int idAbsLeg[3];
242  int leg = -1;
243  for (int i = 0; i < int(iPartonIn.size()); ++ i) {
244  if (iPartonIn[i] < 0) ++leg;
245  else {
246  pLeg[leg] += event[ iPartonIn[i] ].p();
247  mLeg[leg] = event[ iPartonIn[i] ].m();
248  idAbsLeg[leg] = event[ iPartonIn[i] ].idAbs();
249  }
250  }
251 
252  // Calculate invariant mass of three pairs, minus endpoint masses.
253  double m01 = (pLeg[0] + pLeg[1]).mCalc() - mLeg[0] - mLeg[1];
254  double m02 = (pLeg[0] + pLeg[2]).mCalc() - mLeg[0] - mLeg[2];
255  double m12 = (pLeg[1] + pLeg[2]).mCalc() - mLeg[1] - mLeg[2];
256 
257  // Find lowest-mass pair not involving diquark.
258  double mMin = mJoinJunction + 1.;
259  int legA = -1;
260  int legB = -1;
261  if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) {
262  mMin = m01;
263  legA = 0;
264  legB = 1;
265  }
266  if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) {
267  mMin = m02;
268  legA = 0;
269  legB = 2;
270  }
271  if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) {
272  mMin = m12;
273  legA = 1;
274  legB = 2;
275  }
276  int legC = 3 - legA - legB;
277 
278  // Nothing to do if no two legs have small invariant mass, and
279  // system as a whole is above MiniStringFragmentation threshold.
280  if (legA == -1 || (mMin > mJoinJunction && massExcessIn > mStringMin))
281  return false;
282 
283  // Construct separate index arrays for the three legs.
284  vector<int> iLegA, iLegB, iLegC;
285  leg = -1;
286  for (int i = 0; i < int(iPartonIn.size()); ++ i) {
287  if (iPartonIn[i] < 0) ++leg;
288  else if( leg == legA) iLegA.push_back( iPartonIn[i] );
289  else if( leg == legB) iLegB.push_back( iPartonIn[i] );
290  else if( leg == legC) iLegC.push_back( iPartonIn[i] );
291  }
292 
293  // First step: successively combine any gluons on the two legs.
294  // (Presumably overkill; not likely to be (m)any extra gluons.)
295  // (Do as successive binary joinings, so only need two mothers.)
296  for (leg = 0; leg < 2; ++leg) {
297  vector<int>& iLegNow = (leg == 0) ? iLegA : iLegB;
298  int sizeNow = iLegNow.size();
299  for (int i = sizeNow - 2; i >= 0; --i) {
300  int iQ = iLegNow.back();
301  int iG = iLegNow[i];
302  int colNew = (event[iQ].id() > 0) ? event[iG].col() : 0;
303  int acolNew = (event[iQ].id() < 0) ? event[iG].acol() : 0;
304  Vec4 pNew = event[iQ].p() + event[iG].p();
305  int iNew = event.append( event[iQ].id(), 74, iQ, iG, 0, 0,
306  colNew, acolNew, pNew, pNew.mCalc() );
307 
308  // Displaced lifetime/vertex.
309  event[iNew].tau( event[iQ].tau() );
310  if (event[iQ].hasVertex()) event[iNew].vProd( event[iQ].vProd() );
311 
312  // Mark joined partons and update iLeg end.
313  event[iQ].statusNeg();
314  event[iG].statusNeg();
315  event[iQ].daughter1(iNew);
316  event[iG].daughter1(iNew);
317  iLegNow.back() = iNew;
318  }
319  }
320 
321  // Second step: combine two quarks into a diquark.
322  int iQA = iLegA.back();
323  int iQB = iLegB.back();
324  int idQA = event[iQA].id();
325  int idQB = event[iQB].id();
326  int idNew = flavSelPtr->makeDiquark( idQA, idQB );
327  // Diquark colour is opposite to parton closest to junction on third leg.
328  int colNew = (idNew > 0) ? 0 : event[ iLegC[0] ].acol();
329  int acolNew = (idNew > 0) ? event[ iLegC[0] ].col() : 0;
330  Vec4 pNew = pLeg[legA] + pLeg[legB];
331  int iNew = event.append( idNew, 74, min(iQA, iQB), max( iQA, iQB),
332  0, 0, colNew, acolNew, pNew, pNew.mCalc() );
333 
334  // Displaced lifetime/vertex; assume both quarks carry same info.
335  event[iNew].tau( event[iQA].tau() );
336  if (event[iQA].hasVertex()) event[iNew].vProd( event[iQA].vProd() );
337 
338  // Mark joined partons and reduce remaining system.
339  event[iQA].statusNeg();
340  event[iQB].statusNeg();
341  event[iQA].daughter1(iNew);
342  event[iQB].daughter1(iNew);
343  iPartonIn.resize(0);
344  iPartonIn.push_back( iNew);
345  for (int i = 0; i < int(iLegC.size()) ; ++i)
346  iPartonIn.push_back( iLegC[i]);
347 
348  // Remove junction from event record list, identifying by colour.
349  int iJun = -1;
350  for (int i = 0; i < event.sizeJunction(); ++i)
351  for (int j = 0; j < 3; ++ j)
352  if ( event.colJunction(i,j) == max(colNew, acolNew) ) iJun = i;
353  if (iJun >= 0) event.eraseJunction(iJun);
354 
355  // Done, having eliminated junction.
356  return true;
357 
358 }
359 
360 //--------------------------------------------------------------------------
361 
362 // Collect all partons of singlet to be consecutively ordered.
363 
364 void ColConfig::collect(int iSub, Event& event, bool skipTrivial) {
365 
366  // Check that all partons have positive energy.
367  for (int i = 0; i < singlets[iSub].size(); ++i) {
368  int iNow = singlets[iSub].iParton[i];
369  if (iNow > 0 && event[iNow].e() < 0.)
370  infoPtr->errorMsg("Warning in ColConfig::collect: "
371  "negative-energy parton encountered");
372  }
373 
374  // Partons may already have been collected, e.g. at ministring collapse.
375  if (singlets[iSub].isCollected) return;
376  singlets[iSub].isCollected = true;
377 
378  // Check if partons already "by chance" happen to be ordered.
379  bool inOrder = true;
380  for (int i = 0; i < singlets[iSub].size() - 1; ++i) {
381  int iFirst = singlets[iSub].iParton[i];
382  if (iFirst < 0) continue;
383  int iSecond = singlets[iSub].iParton[i + 1];
384  if (iSecond < 0) iSecond = singlets[iSub].iParton[i + 2];
385  if (iSecond != iFirst + 1) { inOrder = false; break;}
386  }
387 
388  // Normally done if in order, but sometimes may need to copy anyway.
389  if (inOrder && skipTrivial) return;
390 
391  // Copy down system. Update current partons.
392  for (int i = 0; i < singlets[iSub].size(); ++i) {
393  int iOld = singlets[iSub].iParton[i];
394  if (iOld < 0) continue;
395  int iNew;
396  if (event[iOld].status() == 74) iNew = event.copy(iOld, 74);
397  else iNew = event.copy(iOld, 71);
398  singlets[iSub].iParton[i] = iNew;
399  }
400 
401  // Done.
402 }
403 
404 //--------------------------------------------------------------------------
405 
406 // Find to which singlet system a particle belongs.
407 
408 int ColConfig::findSinglet(int i) {
409 
410  // Loop through all systems and all members in them.
411  for (int iSub = 0; iSub < int(singlets.size()); ++iSub)
412  for (int iMem = 0; iMem < singlets[iSub].size(); ++iMem)
413  if (singlets[iSub].iParton[iMem] == i) return iSub;
414 
415  // Done without having found particle; return -1 = error code.
416  return -1;
417 }
418 
419 //--------------------------------------------------------------------------
420 
421 // List all currently identified singlets.
422 
423 void ColConfig::list() const {
424 
425  // Header. Loop over all individual singlets.
426  cout << "\n -------- Colour Singlet Systems Listing -------------------\n";
427  for (int iSub = 0; iSub < int(singlets.size()); ++iSub) {
428 
429  // List all partons belonging to each singlet.
430  cout << " singlet " << iSub << " contains " ;
431  for (int i = 0; i < singlets[iSub].size(); ++i)
432  cout << singlets[iSub].iParton[i] << " ";
433  cout << "\n";
434 
435  // Done.
436  }
437 }
438 
439 //==========================================================================
440 
441 // The StringRegion class.
442 
443 // Currently a number of simplifications, in particular ??
444 // 1) No popcorn baryon production.
445 // 2) Simplified treatment of pT in stepping and joining.
446 
447 //--------------------------------------------------------------------------
448 
449 // Constants: could be changed here if desired, but normally should not.
450 // These are of technical nature, as described for each.
451 
452 // If a string region is smaller thsan this it is assumed empty.
453 const double StringRegion::MJOIN = 0.1;
454 
455 // Avoid division by zero.
456 const double StringRegion::TINY = 1e-20;
457 
458 //--------------------------------------------------------------------------
459 
460 // Calculate offset of the region due to presence of gluons from parton list.
461 
462 Vec4 StringRegion::gluonOffset(vector<int>& iSys, Event& event, int iPos,
463  int iNeg) {
464 
465  // Half sum of all intervening gluon momenta.
466  Vec4 offset = Vec4(0., 0., 0., 0.);
467  for (int i = iPos + 1; i < int(iSys.size()) - iNeg - 1; ++i)
468  offset += 0.5 * event[ iSys[i] ].p();
469 
470  return offset;
471 }
472 
473 //--------------------------------------------------------------------------
474 
475 // Calculate offset when calculation needed in junction rest frame.
476 
477 Vec4 StringRegion::gluonOffsetJRF(vector<int>& iSys, Event& event, int iPos,
478  int iNeg, RotBstMatrix MtoJRF) {
479 
480  // Half sum of all intervening gluon momenta, boosted to junction rest frame.
481  Vec4 offset = Vec4( 0., 0., 0., 0.);
482  for (int i = iPos + 1; i < int(iSys.size()) - iNeg; ++i) {
483  Vec4 pGluon = event[ iSys[i] ].p();
484  pGluon.rotbst( MtoJRF );
485  if(pGluon.m2Calc() < -1e-8) pGluon.e( pGluon.pAbs() );
486  offset += 0.5 * pGluon;
487  }
488 
489  return offset;
490 }
491 
492 //--------------------------------------------------------------------------
493 
494 // Calculate offset if system contains c or b quarks, where the location of
495 // energy-momentum-picture breakup points in the initial regions are shifted
496 // with respect to the origin, to be removed for the space-time vertices.
497 
498 bool StringRegion::massiveOffset( int iPos, int iNeg, int iMax,
499  int id1, int id2, double mc, double mb) {
500 
501  // Done if not in either of endpoint regions or no massive endpoint quark.
502  massOffset = Vec4( 0., 0., 0., 0.);
503  if (iPos + iNeg != iMax) return false;
504  bool idcb1 = (iPos == 0 && (id1 == 4 || id1 == 5));
505  bool idcb2 = (iNeg == 0 && (id2 == 4 || id2 == 5));
506  if (!idcb1 && !idcb2) return false;
507 
508  // Calculate the offset of initial-region massive endpoint quark.
509  double posMass2 = (idcb1) ? ((id1 == 4) ? pow2(mc) : pow2(mb)) : 0.;
510  double negMass2 = (idcb2) ? ((id2 == 4) ? pow2(mc) : pow2(mb)) : 0.;
511  double eCM = (pPosMass + pNegMass).mCalc();
512  double ePosMass = 0.5 * (pow2(eCM) + posMass2 - negMass2) / eCM;
513  double eNegMass = 0.5 * (pow2(eCM) + negMass2 - posMass2) / eCM;
514  double p0 = 0.5 * sqrt( pow2(pow2(eCM) - negMass2 - posMass2)
515  - 4. * negMass2 * posMass2) / eCM;
516  massOffset = ((eNegMass - p0) * pPos + (ePosMass - p0) * pNeg) / eCM;
517 
518  return true;
519 }
520 
521 //--------------------------------------------------------------------------
522 
523 // Set up four-vectors for longitudinal and transverse directions.
524 
525 void StringRegion::setUp(Vec4 p1, Vec4 p2, int col1, int col2,
526  bool isMassless) {
527 
528  // Store the original four-momenta; needed for the massive-quark case.
529  pPosMass = p1;
530  pNegMass = p2;
531 
532  // Simple case: the two incoming four-vectors guaranteed massless.
533  if (isMassless) {
534 
535  // Calculate w2, minimum value. Lightcone directions = input.
536  w2 = 2. * (p1 * p2);
537  if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
538  pPos = p1;
539  pNeg = p2;
540 
541  // Else allow possibility of masses for incoming partons (also gluons!).
542  } else {
543 
544  // Generic four-momentum combinations.
545  double m1Sq = p1 * p1;
546  double m2Sq = p2 * p2;
547  double p1p2 = p1 * p2;
548  w2 = m1Sq + 2. * p1p2 + m2Sq;
549  double rootSq = pow2(p1p2) - m1Sq * m2Sq;
550 
551  // If crazy kinematics (should not happen!) modify energies.
552  if (w2 <= 0. || rootSq <= 0.) {
553  if (m1Sq < 0.) m1Sq = 0.;
554  p1.e( sqrt(m1Sq + p1.pAbs2()) );
555  if (m2Sq < 0.) m2Sq = 0.;
556  p2.e( sqrt(m2Sq + p2.pAbs2()) );
557  p1p2 = p1 * p2;
558  w2 = m1Sq + 2. * p1p2 + m2Sq;
559  rootSq = pow2(p1p2) - m1Sq * m2Sq;
560  }
561 
562  // If still small invariant mass then empty region (e.g. in gg system).
563  if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;}
564 
565  // Find two lightconelike longitudinal four-vector directions.
566  double root = sqrt( max(TINY, rootSq) );
567  double k1 = 0.5 * ( (m2Sq + p1p2) / root - 1.);
568  double k2 = 0.5 * ( (m1Sq + p1p2) / root - 1.);
569  pPos = (1. + k1) * p1 - k2 * p2;
570  pNeg = (1. + k2) * p2 - k1 * p1;
571  if (pPos.e() < TINY || pNeg.e() < TINY)
572  {isSetUp = true; isEmpty = true; return;}
573  }
574 
575  // Find two spacelike transverse four-vector directions.
576  // Begin by picking two sensible trial directions.
577  Vec4 eDiff = pPos / pPos.e() - pNeg / pNeg.e();
578  double eDx = pow2( eDiff.px() );
579  double eDy = pow2( eDiff.py() );
580  double eDz = pow2( eDiff.pz() );
581  if (eDx < min(eDy, eDz)) {
582  eX = Vec4( 1., 0., 0., 0.);
583  eY = (eDy < eDz) ? Vec4( 0., 1., 0., 0.) : Vec4( 0., 0., 1., 0.);
584  } else if (eDy < eDz) {
585  eX = Vec4( 0., 1., 0., 0.);
586  eY = (eDx < eDz) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 0., 1., 0.);
587  } else {
588  eX = Vec4( 0., 0., 1., 0.);
589  eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.);
590  }
591 
592  // Then construct orthogonal linear combinations.
593  double pPosNeg = pPos * pNeg;
594  double kXPos = eX * pPos / pPosNeg;
595  double kXNeg = eX * pNeg / pPosNeg;
596  double kXtmp = 1. + 2. * kXPos * kXNeg * pPosNeg;
597  if (kXtmp < TINY) {isSetUp = true; isEmpty = true; return;}
598  double kXX = 1. / sqrt( kXtmp );
599  double kYPos = eY * pPos / pPosNeg;
600  double kYNeg = eY * pNeg / pPosNeg;
601  double kYX = kXX * (kXPos * kYNeg + kXNeg * kYPos) * pPosNeg;
602  double kYtmp = 1. + 2. * kYPos * kYNeg * pPosNeg - pow2(kYX);
603  if (kYtmp < TINY) {isSetUp = true; isEmpty = true; return;}
604  double kYY = 1. / sqrt( kYtmp );
605  eX = kXX * (eX - kXNeg * pPos - kXPos * pNeg);
606  eY = kYY * (eY - kYNeg * pPos - kYPos * pNeg - kYX * eX);
607 
608  // Remember colour indices.
609  colPos = col1;
610  colNeg = col2;
611 
612  // Done.
613  isSetUp = true;
614  isEmpty = false;
615 
616 }
617 
618 //--------------------------------------------------------------------------
619 
620 // Project a four-momentum onto (x+, x-, px, py).
621 
622 void StringRegion::project(Vec4 pIn) {
623 
624  // Perform projections by four-vector multiplication.
625  xPosProj = 2. * (pIn * pNeg) / w2;
626  xNegProj = 2. * (pIn * pPos) / w2;
627  pxProj = - (pIn * eX);
628  pyProj = - (pIn * eY);
629 
630 }
631 
632 //==========================================================================
633 
634 // The StringSystem class.
635 
636 //--------------------------------------------------------------------------
637 
638 // Set up system from parton list.
639 
640 void StringSystem::setUp(vector<int>& iSys, Event& event) {
641 
642  // Figure out how big the system is. (Closed gluon loops?)
643  sizePartons = iSys.size();
644  sizeStrings = sizePartons - 1;
645  sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2;
646  indxReg = 2 * sizeStrings + 1;
647  iMax = sizeStrings - 1;
648 
649  // Reserve space for the required number of regions.
650  system.clear();
651  system.resize(sizeRegions);
652  bool forward = ( event[iSys[0]].col() != 0 );
653 
654  // Set up the lowest-lying regions.
655  for (int i = 0; i < sizeStrings; ++i) {
656  Vec4 p1 = event[ iSys[i] ].p();
657  if ( event[ iSys[i] ].isGluon() ) p1 *= 0.5;
658  Vec4 p2 = event[ iSys[i+1] ].p();
659  if ( event[ iSys[i+1] ].isGluon() ) p2 *= 0.5;
660  int col = forward ? event[ iSys[i] ].col() : event[ iSys[i] ].acol();
661  system[ iReg(i, iMax - i) ].setUp( p1, p2, col, col, false);
662  }
663 
664 }
665 
666 //==========================================================================
667 
668 } // end namespace Pythia8
Definition: AgUStep.h:26