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