9 #include "Pythia8/FragmentationSystems.h"
23 const double ColConfig::CONSTITUENTMASS = 0.325;
29 void ColConfig::init(Info* infoPtrIn, Settings& settings,
30 StringFlav* flavSelPtrIn) {
34 flavSelPtr = flavSelPtrIn;
37 mJoin = settings.parm(
"FragmentationSystems:mJoin");
40 mJoin = max( mJoin, 2. * StringRegion::MJOIN);
43 mJoinJunction = settings.parm(
"FragmentationSystems:mJoinJunction");
44 mStringMin = settings.parm(
"HadronLevel:mStringMin");
53 bool ColConfig::insert( vector<int>& iPartonIn,
Event& event) {
58 bool hasJunctionIn =
false;
59 int nJunctionLegs = 0;
60 for (
int i = 0; i < int(iPartonIn.size()); ++i) {
61 if (iPartonIn[i] < 0) {
65 pSumIn +=
event[ iPartonIn[i] ].p();
66 if (!event[ iPartonIn[i] ].isGluon())
67 mSumIn +=
event[ iPartonIn[i] ].constituentMass();
70 double massIn = pSumIn.mCalc();
71 double massExcessIn = massIn - mSumIn;
74 if (nJunctionLegs >= 5) {
75 infoPtr->errorMsg(
"Error in ColConfig::insert: "
76 "junction topology too complicated; too many junction legs");
80 else if (nJunctionLegs > 0 && nJunctionLegs <= 2) {
81 infoPtr->errorMsg(
"Error in ColConfig::insert: "
82 "junction topology inconsistent; too few junction legs");
87 if (abs(massExcessIn) >= 0.);
89 infoPtr->errorMsg(
"Error in ColConfig::insert: "
90 "not-a-number system mass");
95 bool isClosedIn = (iPartonIn[0] >= 0 &&
event[ iPartonIn[0] ].col() != 0
96 &&
event[ iPartonIn[0] ].acol() != 0 );
97 if (isClosedIn) massExcessIn -= 2. * CONSTITUENTMASS;
100 if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn))
101 hasJunctionIn =
false;
104 bool hasJoined =
true;
105 while (hasJoined && iPartonIn.size() > 2) {
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) {
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] ];
119 if (!parton1.isParton() || !parton2.isParton())
continue;
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; }
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);
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();
148 Vec4 pNew =
event[iJoin1].p() +
event[iJoin2].p();
153 if (event[iMoth1].statusAbs() == 74) statusHad = 74;
156 int iNew =
event.append( idNew, statusHad, iMoth1, iMoth2, 0, 0,
157 colNew, acolNew, pNew, pNew.mCalc() );
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() );
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;
171 iPartonIn[iJoinMin] = iNew;
172 for (
int i = iJoinMin + 1; i < nSize - 1; ++i)
173 iPartonIn[i] = iPartonIn[i + 1];
175 iPartonIn.pop_back();
183 singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
184 massExcessIn, hasJunctionIn, isClosedIn) );
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];
193 if (iInsert <
int(singlets.size()) - 1) singlets[iInsert] =
194 ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn,
195 hasJunctionIn, isClosedIn);
207 bool ColConfig::joinJunction( vector<int>& iPartonIn,
Event& event,
208 double massExcessIn) {
212 double mLeg[3] = { 0., 0., 0.};
215 for (
int i = 0; i < int(iPartonIn.size()); ++ i) {
216 if (iPartonIn[i] < 0) ++leg;
218 pLeg[leg] +=
event[ iPartonIn[i] ].p();
219 mLeg[leg] =
event[ iPartonIn[i] ].m();
220 idAbsLeg[leg] =
event[ iPartonIn[i] ].idAbs();
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];
230 double mMin = mJoinJunction + 1.;
233 if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) {
238 if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) {
243 if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) {
248 int legC = 3 - legA - legB;
252 if (legA == -1 || (mMin > mJoinJunction && massExcessIn > mStringMin))
256 vector<int> iLegA, iLegB, iLegC;
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] );
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();
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() );
281 event[iNew].tau( event[iQ].tau() );
282 if (event[iQ].hasVertex())
event[iNew].vProd( event[iQ].vProd() );
285 event[iQ].statusNeg();
286 event[iG].statusNeg();
287 event[iQ].daughter1(iNew);
288 event[iG].daughter1(iNew);
289 iLegNow.back() = iNew;
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 );
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() );
307 event[iNew].tau( event[iQA].tau() );
308 if (event[iQA].hasVertex())
event[iNew].vProd( event[iQA].vProd() );
311 event[iQA].statusNeg();
312 event[iQB].statusNeg();
313 event[iQA].daughter1(iNew);
314 event[iQB].daughter1(iNew);
316 iPartonIn.push_back( iNew);
317 for (
int i = 0; i < int(iLegC.size()) ; ++i)
318 iPartonIn.push_back( iLegC[i]);
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);
336 void ColConfig::collect(
int iSub,
Event& event,
bool skipTrivial) {
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");
347 if (singlets[iSub].isCollected)
return;
348 singlets[iSub].isCollected =
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;}
361 if (inOrder && skipTrivial)
return;
364 for (
int i = 0; i < singlets[iSub].size(); ++i) {
365 int iOld = singlets[iSub].iParton[i];
366 if (iOld < 0)
continue;
368 if (event[iOld].status() == 74) iNew = event.copy(iOld, 74);
369 else iNew =
event.copy(iOld, 71);
370 singlets[iSub].iParton[i] = iNew;
380 int ColConfig::findSinglet(
int i) {
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;
395 void ColConfig::list()
const {
398 cout <<
"\n -------- Colour Singlet Systems Listing -------------------\n";
399 for (
int iSub = 0; iSub < int(singlets.size()); ++iSub) {
402 cout <<
" singlet " << iSub <<
" contains " ;
403 for (
int i = 0; i < singlets[iSub].size(); ++i)
404 cout << singlets[iSub].iParton[i] <<
" ";
425 const double StringRegion::MJOIN = 0.1;
428 const double StringRegion::TINY = 1e-20;
434 Vec4 StringRegion::gluonOffset(vector<int>& iSys,
Event& event,
int iPos,
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();
449 Vec4 StringRegion::gluonOffsetJRF(vector<int>& iSys,
Event& event,
int iPos,
450 int iNeg, RotBstMatrix MtoJRF) {
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;
470 bool StringRegion::massiveOffset(
int iPos,
int iNeg,
int iMax,
471 int id1,
int id2,
double mc,
double mb) {
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;
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;
497 void StringRegion::setUp(Vec4 p1, Vec4 p2,
bool isMassless) {
508 if (w2 < MJOIN*MJOIN) {isSetUp =
true; isEmpty =
true;
return;}
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;
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()) );
529 w2 = m1Sq + 2. * p1p2 + m2Sq;
530 rootSq = pow2(p1p2) - m1Sq * m2Sq;
534 if (w2 < MJOIN*MJOIN) {isSetUp =
true; isEmpty =
true;
return;}
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;}
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.);
559 eX = Vec4( 0., 0., 1., 0.);
560 eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.);
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);
589 void StringRegion::project(Vec4 pIn) {
592 xPosProj = 2. * (pIn * pNeg) / w2;
593 xNegProj = 2. * (pIn * pPos) / w2;
594 pxProj = - (pIn * eX);
595 pyProj = - (pIn * eY);
607 void StringSystem::setUp(vector<int>& iSys,
Event& event) {
610 sizePartons = iSys.size();
611 sizeStrings = sizePartons - 1;
612 sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2;
613 indxReg = 2 * sizeStrings + 1;
614 iMax = sizeStrings - 1;
618 system.resize(sizeRegions);
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);