9 #include "Pythia8/FragmentationSystems.h"
23 const double ColConfig::CONSTITUENTMASS = 0.325;
29 void ColConfig::init(Info* infoPtrIn, StringFlav* flavSelPtrIn) {
31 Settings* settingsPtr = infoPtrIn->settingsPtr;
35 flavSelPtr = flavSelPtrIn;
38 mJoin = settingsPtr->parm(
"FragmentationSystems:mJoin");
41 mJoin = max( mJoin, 2. * StringRegion::MJOIN);
44 mJoinJunction = settingsPtr->parm(
"FragmentationSystems:mJoinJunction");
45 mStringMin = settingsPtr->parm(
"HadronLevel:mStringMin");
54 bool ColConfig::insert( vector<int>& iPartonIn,
Event& event) {
59 bool hasJunctionIn =
false;
60 int nJunctionLegs = 0;
61 for (
int i = 0; i < int(iPartonIn.size()); ++i) {
62 if (iPartonIn[i] < 0) {
66 pSumIn +=
event[ iPartonIn[i] ].p();
67 if (!event[ iPartonIn[i] ].isGluon())
68 mSumIn +=
event[ iPartonIn[i] ].constituentMass();
71 double massIn = pSumIn.mCalc();
72 double massExcessIn = massIn - mSumIn;
75 if (nJunctionLegs >= 5) {
76 infoPtr->errorMsg(
"Error in ColConfig::insert: "
77 "junction topology too complicated; too many junction legs");
81 else if (nJunctionLegs > 0 && nJunctionLegs <= 2) {
82 infoPtr->errorMsg(
"Error in ColConfig::insert: "
83 "junction topology inconsistent; too few junction legs");
88 if (abs(massExcessIn) >= 0.);
90 infoPtr->errorMsg(
"Error in ColConfig::insert: "
91 "not-a-number system mass");
96 bool isClosedIn = (iPartonIn[0] >= 0 &&
event[ iPartonIn[0] ].col() != 0
97 &&
event[ iPartonIn[0] ].acol() != 0 );
98 if (isClosedIn) massExcessIn -= 2. * CONSTITUENTMASS;
101 if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn))
102 hasJunctionIn =
false;
105 bool hasJoined =
true;
106 while (hasJoined && iPartonIn.size() > 2) {
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) {
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] ];
120 if (!parton1.isParton() || !parton2.isParton())
continue;
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; }
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);
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();
149 Vec4 pNew =
event[iJoin1].p() +
event[iJoin2].p();
154 if (event[iMoth1].statusAbs() == 74) statusHad = 74;
157 int iNew =
event.append( idNew, statusHad, iMoth1, iMoth2, 0, 0,
158 colNew, acolNew, pNew, pNew.mCalc() );
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() );
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;
172 iPartonIn[iJoinMin] = iNew;
173 for (
int i = iJoinMin + 1; i < nSize - 1; ++i)
174 iPartonIn[i] = iPartonIn[i + 1];
176 iPartonIn.pop_back();
184 singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
185 massExcessIn, hasJunctionIn, isClosedIn) );
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];
194 if (iInsert <
int(singlets.size()) - 1) singlets[iInsert] =
195 ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn,
196 hasJunctionIn, isClosedIn);
207 bool ColConfig::simpleInsert( vector<int>& iPartonIn,
Event& event,
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;
218 singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn,
219 massExcessIn,
false,
false) );
222 if (!fixOrder && singlets.size() == 2 && massExcessIn
223 < singlets[0].massExcess) swap( singlets[0], singlets[1]);
235 bool ColConfig::joinJunction( vector<int>& iPartonIn,
Event& event,
236 double massExcessIn) {
240 double mLeg[3] = { 0., 0., 0.};
243 for (
int i = 0; i < int(iPartonIn.size()); ++ i) {
244 if (iPartonIn[i] < 0) ++leg;
246 pLeg[leg] +=
event[ iPartonIn[i] ].p();
247 mLeg[leg] =
event[ iPartonIn[i] ].m();
248 idAbsLeg[leg] =
event[ iPartonIn[i] ].idAbs();
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];
258 double mMin = mJoinJunction + 1.;
261 if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) {
266 if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) {
271 if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) {
276 int legC = 3 - legA - legB;
280 if (legA == -1 || (mMin > mJoinJunction && massExcessIn > mStringMin))
284 vector<int> iLegA, iLegB, iLegC;
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] );
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();
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() );
309 event[iNew].tau( event[iQ].tau() );
310 if (event[iQ].hasVertex())
event[iNew].vProd( event[iQ].vProd() );
313 event[iQ].statusNeg();
314 event[iG].statusNeg();
315 event[iQ].daughter1(iNew);
316 event[iG].daughter1(iNew);
317 iLegNow.back() = iNew;
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 );
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() );
335 event[iNew].tau( event[iQA].tau() );
336 if (event[iQA].hasVertex())
event[iNew].vProd( event[iQA].vProd() );
339 event[iQA].statusNeg();
340 event[iQB].statusNeg();
341 event[iQA].daughter1(iNew);
342 event[iQB].daughter1(iNew);
344 iPartonIn.push_back( iNew);
345 for (
int i = 0; i < int(iLegC.size()) ; ++i)
346 iPartonIn.push_back( iLegC[i]);
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);
364 void ColConfig::collect(
int iSub,
Event& event,
bool skipTrivial) {
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");
375 if (singlets[iSub].isCollected)
return;
376 singlets[iSub].isCollected =
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;}
389 if (inOrder && skipTrivial)
return;
392 for (
int i = 0; i < singlets[iSub].size(); ++i) {
393 int iOld = singlets[iSub].iParton[i];
394 if (iOld < 0)
continue;
396 if (event[iOld].status() == 74) iNew = event.copy(iOld, 74);
397 else iNew =
event.copy(iOld, 71);
398 singlets[iSub].iParton[i] = iNew;
408 int ColConfig::findSinglet(
int i) {
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;
423 void ColConfig::list()
const {
426 cout <<
"\n -------- Colour Singlet Systems Listing -------------------\n";
427 for (
int iSub = 0; iSub < int(singlets.size()); ++iSub) {
430 cout <<
" singlet " << iSub <<
" contains " ;
431 for (
int i = 0; i < singlets[iSub].size(); ++i)
432 cout << singlets[iSub].iParton[i] <<
" ";
453 const double StringRegion::MJOIN = 0.1;
456 const double StringRegion::TINY = 1e-20;
462 Vec4 StringRegion::gluonOffset(vector<int>& iSys,
Event& event,
int iPos,
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();
477 Vec4 StringRegion::gluonOffsetJRF(vector<int>& iSys,
Event& event,
int iPos,
478 int iNeg, RotBstMatrix MtoJRF) {
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;
498 bool StringRegion::massiveOffset(
int iPos,
int iNeg,
int iMax,
499 int id1,
int id2,
double mc,
double mb) {
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;
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;
525 void StringRegion::setUp(Vec4 p1, Vec4 p2,
int col1,
int col2,
537 if (w2 < MJOIN*MJOIN) {isSetUp =
true; isEmpty =
true;
return;}
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;
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()) );
558 w2 = m1Sq + 2. * p1p2 + m2Sq;
559 rootSq = pow2(p1p2) - m1Sq * m2Sq;
563 if (w2 < MJOIN*MJOIN) {isSetUp =
true; isEmpty =
true;
return;}
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;}
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.);
588 eX = Vec4( 0., 0., 1., 0.);
589 eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.);
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);
622 void StringRegion::project(Vec4 pIn) {
625 xPosProj = 2. * (pIn * pNeg) / w2;
626 xNegProj = 2. * (pIn * pPos) / w2;
627 pxProj = - (pIn * eX);
628 pyProj = - (pIn * eY);
640 void StringSystem::setUp(vector<int>& iSys,
Event& event) {
643 sizePartons = iSys.size();
644 sizeStrings = sizePartons - 1;
645 sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2;
646 indxReg = 2 * sizeStrings + 1;
647 iMax = sizeStrings - 1;
651 system.resize(sizeRegions);
652 bool forward = (
event[iSys[0]].col() != 0 );
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);