9 #include "Pythia8/MiniStringFragmentation.h"
23 const int MiniStringFragmentation::NTRYDIFFRACTIVE = 200;
26 const int MiniStringFragmentation::NTRYLASTRESORT = 100;
29 const int MiniStringFragmentation::NTRYFLAV = 10;
35 void MiniStringFragmentation::init(StringFlav* flavSelPtrIn,
36 StringPT* pTSelPtrIn, StringZ* zSelPtrIn) {
39 flavSelPtr = flavSelPtrIn;
40 pTSelPtr = pTSelPtrIn;
44 hadronVertex = mode(
"HadronVertex:mode");
45 setVertices = flag(
"Fragmentation:setVertices")
46 || flag(
"HadronLevel:Rescatter");
47 kappaVtx = parm(
"HadronVertex:kappa");
48 smearOn = flag(
"HadronVertex:smearOn");
49 xySmear = parm(
"HadronVertex:xySmear");
50 constantTau = flag(
"HadronVertex:constantTau");
53 mc = particleDataPtr->m0(4);
54 mb = particleDataPtr->m0(5);
57 nTryMass = mode(
"MiniStringFragmentation:nTry");
60 bLund = zSelPtr->bAreaLund();
68 bool MiniStringFragmentation::fragment(
int iSub, ColConfig& colConfig,
69 Event& event,
bool isDiff,
bool systemRecoil) {
72 iParton = colConfig[iSub].iParton;
73 if (iParton.front() < 0) {
74 infoPtr->errorMsg(
"Error in MiniStringFragmentation::fragment: "
75 "very low-mass junction topologies not yet handled");
80 flav1 = FlavContainer( event[ iParton.front() ].id() );
81 flav2 = FlavContainer( event[ iParton.back() ].id() );
82 pSum = colConfig[iSub].pSum;
83 mSum = colConfig[iSub].mass;
85 isClosed = colConfig[iSub].isClosed;
88 int nTryFirst = (isDiff) ? NTRYDIFFRACTIVE : nTryMass;
91 if (ministring2two( nTryFirst, event,
false))
return true;
94 if (ministring2one( iSub, colConfig, event,
false))
return true;
97 if (ministring2two( NTRYLASTRESORT, event,
true))
return true;
100 if (ministring2one( iSub, colConfig, event,
true))
return true;
104 if (ministring2one( iSub, colConfig, event,
false,
false))
return true;
105 if (ministring2one( iSub, colConfig, event,
true,
false))
return true;
109 infoPtr->errorMsg(
"Error in MiniStringFragmentation::fragment: "
110 "no 1- or 2-body state found above mass threshold");
120 bool MiniStringFragmentation::ministring2two(
int nTry,
Event& event,
131 for (
int iTry = 0; iTry < nTry; ++iTry) {
135 int idStart = flavSelPtr->pickLightQ();
136 FlavContainer flavStart(idStart, 1);
137 flavStart = flavSelPtr->pick( flavStart, -1., 0.,
false);
138 flav1 = flavSelPtr->pick( flavStart, -1., 0.,
false);
140 }
while (flav1.id == 0 || flav1.nPop > 0);
145 FlavContainer flav3 =
146 (flav1.isDiquark() || (!flav2.isDiquark() && rndmPtr->flat() < 0.5) )
147 ? flavSelPtr->pick( flav1, -1., 0.,
false)
148 : flavSelPtr->pick( flav2, -1., 0.,
false).anti();
150 idHad1 = flavSelPtr->combineToLightest( flav1.id, flav3.id);
151 idHad2 = flavSelPtr->combineToLightest( flav2.id, -flav3.id);
153 idHad1 = flavSelPtr->combine( flav1, flav3);
154 idHad2 = flavSelPtr->combine( flav2, flav3.anti());
156 }
while (idHad1 == 0 || idHad2 == 0);
159 mHad1 = particleDataPtr->mSel(idHad1);
160 mHad2 = particleDataPtr->mSel(idHad2);
161 mHadSum = mHad1 + mHad2;
162 if (mHadSum < mSum)
break;
166 if (mHadSum >= mSum && findLowMass && !isClosed) {
167 idHad1 = flavSelPtr->combineToLightest( flav1.id, flav2.id);
169 mHad1 = particleDataPtr->mSel(idHad1);
170 mHad2 = particleDataPtr->mSel(idHad2);
171 mHadSum = mHad1 + mHad2;
173 if (mHadSum >= mSum)
return false;
177 Vec4 pSum1 =
event[ iParton.front() ].p();
178 Vec4 pSum2 =
event[ iParton.back() ].p();
179 if (iParton.size() > 2) {
182 Vec4 pEndSum = pEnd1 + pEnd2;
183 for (
int i = 1; i < int(iParton.size()) - 1 ; ++i) {
184 Vec4 pNow =
event[ iParton[i] ].p();
185 double ratio = (pEnd2 * pNow) / (pEndSum * pNow);
186 pSum1 += ratio * pNow;
187 pSum2 += (1. - ratio) * pNow;
193 if (pSum1.mCalc() + pSum2.mCalc() > 0.999999 * mSum) {
194 double cthe = 2. * rndmPtr->flat() - 1.;
195 double sthe = sqrtpos(1. - cthe * cthe);
196 double phi = 2. * M_PI * rndmPtr->flat();
197 Vec4 delta = 0.5 * min( pSum1.e(), pSum2.e())
198 * Vec4( sthe * sin(phi), sthe * cos(phi), cthe, 0.);
201 infoPtr->errorMsg(
"Warning in MiniStringFragmentation::ministring2two: "
202 "random axis needed to break tie");
207 region.setUp( pSum1, pSum2, 0, 0);
211 double pAbs2 = 0.25 * ( pow2(m2Sum - mHad1*mHad1 - mHad2*mHad2)
212 - pow2(2. * mHad1 * mHad2) ) / m2Sum;
215 double cosTheta = rndmPtr->flat();
216 pT2 = (1. - pow2(cosTheta)) * pAbs2;
217 }
while (pTSelPtr->suppressPT2(pT2) < rndmPtr->flat() );
220 double mT21 = mHad1*mHad1 + pT2;
221 double mT22 = mHad2*mHad2 + pT2;
222 double lambda = sqrtpos( pow2(m2Sum - mT21 - mT22) - 4. * mT21 * mT22 );
223 double probReverse = 1. / (1. + exp( min( 50., bLund * lambda) ) );
226 double xpz1 = 0.5 * lambda/ m2Sum;
227 if (probReverse > rndmPtr->flat()) xpz1 = -xpz1;
228 double xmDiff = (mT21 - mT22) / m2Sum;
229 double xe1 = 0.5 * (1. + xmDiff);
230 double xe2 = 0.5 * (1. - xmDiff );
233 double phi = 2. * M_PI * rndmPtr->flat();
234 double pT = sqrt(pT2);
235 double px = pT * cos(phi);
236 double py = pT * sin(phi);
239 Vec4 pHad1 = region.pHad( xe1 + xpz1, xe1 - xpz1, px, py);
240 Vec4 pHad2 = region.pHad( xe2 - xpz1, xe2 + xpz1, -px, -py);
243 int statusHadPos = 82, statusHadNeg = 82;
244 if (abs(idHad1) > 1000 && abs(idHad1) < 10000 &&
245 abs(idHad2) > 1000 && abs(idHad2) < 10000) {
246 if (event[ iParton.front() ].statusAbs() == 74) statusHadPos = 89;
247 if (event[ iParton.back() ].statusAbs() == 74) statusHadNeg = 89;
249 else if (abs(idHad1) > 1000 && abs(idHad1) < 10000) {
250 if (event[ iParton.front() ].statusAbs() == 74 ||
251 event[ iParton.back() ].statusAbs() == 74) statusHadPos = 89;
253 else if (abs(idHad2) > 1000 && abs(idHad2) < 10000) {
254 if (event[ iParton.front() ].statusAbs() == 74 ||
255 event[ iParton.back() ].statusAbs() == 74) statusHadNeg = 89;
258 int iFirst =
event.append( idHad1, statusHadPos, iParton.front(),
259 iParton.back(), 0, 0, 0, 0, pHad1, mHad1);
260 int iLast =
event.append( idHad2, statusHadNeg, iParton.front(),
261 iParton.back(), 0, 0, 0, 0, pHad2, mHad2);
264 if (event[iParton.front()].hasVertex()) {
265 Vec4 vDec =
event[iParton.front()].vDec();
266 event[iFirst].vProd( vDec );
267 event[iLast].vProd( vDec );
271 event[iFirst].tau( event[iFirst].tau0() * rndmPtr->exp() );
272 event[iLast].tau( event[iLast].tau0() * rndmPtr->exp() );
275 for (
int i = 0; i < int(iParton.size()); ++i) {
276 event[ iParton[i] ].statusNeg();
277 event[ iParton[i] ].daughters(iFirst, iLast);
282 ministringVertices.clear();
283 ministringVertices.push_back( StringVertex(
true, 0, 0, 1., 0.) );
284 ministringVertices.push_back(
285 StringVertex(
true, 0, 0, 1. - (xe1 + xpz1), xe1 - xpz1) );
286 ministringVertices.push_back( StringVertex(
true, 0, 0, 0., 1.) );
289 setHadronVertices( event, region, iFirst, iLast);
306 bool MiniStringFragmentation::ministring2one(
int iSub,
307 ColConfig& colConfig,
Event& event,
bool findLowMass,
bool systemRecoil) {
310 if (abs(flav1.id) > 100 && abs(flav2.id) > 100)
return false;
314 int idStart = flavSelPtr->pickLightQ();
315 FlavContainer flavStart(idStart, 1);
316 flav1 = flavSelPtr->pick( flavStart);
317 flav2 = flav1.anti();
318 }
while (abs(flav1.id) > 100);
323 if (findLowMass) idHad = flavSelPtr->combineToLightest( flav1.id, flav2.id);
324 else for (
int iTryFlav = 0; iTryFlav < NTRYFLAV; ++iTryFlav) {
325 idHad = flavSelPtr->combine( flav1, flav2);
326 if (idHad != 0)
break;
328 if (idHad == 0)
return false;
331 double mHad = particleDataPtr->mSel(idHad);
336 double deltaM2 = mHad*mHad - mSum*mSum;
337 double delta2Max = 0.;
339 for (
int iRec = iSub + 1; iRec < colConfig.size(); ++iRec) {
340 double delta2Rec = 2. * (pSum * colConfig[iRec].pSum) - deltaM2
341 - 2. * mHad * colConfig[iRec].mass;
342 if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;}
345 for (
int iRec = 0; iRec <
event.size(); ++iRec)
346 if (event[iRec].isHadron() &&
event[iRec].status() > 80) {
347 double delta2Rec = 2. * (pSum *
event[iRec].p()) - deltaM2
348 - 2. * mHad * event[iRec].m();
349 if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;}
352 if (iMax == -1)
return false;
355 Vec4 pRec = (systemRecoil) ? colConfig[iMax].pSum : event[iMax].p();
356 double mRec = (systemRecoil) ? colConfig[iMax].mass : event[iMax].m();
357 double vecProd = pSum * pRec;
358 double coefOld = mSum*mSum + vecProd;
359 double coefNew = mHad*mHad + vecProd;
360 double coefRec = mRec*mRec + vecProd;
361 double coefSum = coefOld + coefNew;
362 double sHat = coefOld + coefRec;
363 double root = sqrtpos( (pow2(coefSum) - 4. * sHat * mHad*mHad)
364 / (pow2(vecProd) - pow2(mSum * mRec)) );
365 double k2 = 0.5 * (coefOld * root - coefSum) / sHat;
366 double k1 = (coefRec * k2 + 0.5 * deltaM2) / coefOld;
367 Vec4 pHad = (1. + k1) * pSum - k2 * pRec;
368 Vec4 pRecNew = (1. + k2) * pRec - k1 * pSum;
372 if (abs(idHad) > 1000 && abs(idHad) < 10000 &&
373 (
event[ iParton.front() ].statusAbs() == 74 ||
374 event[ iParton.back() ].statusAbs() == 74)) statusHad = 89;
377 int iHad =
event.append( idHad, statusHad, iParton.front(), iParton.back(),
378 0, 0, 0, 0, pHad, mHad);
381 if (event[iParton.front()].hasVertex()) {
382 Vec4 vDec =
event[iParton.front()].vDec();
383 event[iHad].vProd( vDec );
387 event[iHad].tau( event[iHad].tau0() * rndmPtr->exp() );
390 for (
int i = 0; i < int(iParton.size()); ++i) {
391 event[ iParton[i] ].statusNeg();
392 event[ iParton[i] ].daughters(iHad, iHad);
397 M.bst(pRec, pRecNew);
399 for (
int i = 0; i < colConfig[iMax].size(); ++i) {
400 int iOld = colConfig[iMax].iParton[i];
405 if (event[iOld].status() == 74) iNew = event.copy(iOld, 74);
406 else iNew =
event.copy(iOld, 72);
407 event[iNew].rotbst(M);
408 colConfig[iMax].iParton[i] = iNew;
411 colConfig[iMax].pSum = pRecNew;
412 colConfig[iMax].isCollected =
true;
416 int iNew =
event.copy(iMax, event[iMax].status());
417 event[iNew].rotbst(M);
423 Vec4 prodPoint = Vec4( 0., 0., 0., 0.);
424 Vec4 pHadron =
event[iHad].p();
430 Vec4 eX = Vec4( 1., 0., 0., 0.);
431 Vec4 eY = Vec4( 0., 1., 0., 0.);
434 double transX = rndmPtr -> gauss();
435 double transY = rndmPtr -> gauss();
436 prodPoint = xySmear * (transX * eX + transY * eY) / sqrt(2.);
439 if (constantTau) prodPoint.e( prodPoint.pAbs() );
440 else prodPoint = Vec4( 0., 0., 0., 0.);
444 int id1 =
event[ iParton.front() ].idAbs();
445 int id2 =
event[ iParton.back() ].idAbs();
447 if (id1 == 4 || id1 == 5 || id2 == 4 || id2 == 5) {
448 double posMass = (id1 == 4 || id1 == 5) ? particleDataPtr->m0(id1) : 0.;
449 double negMass = (id2 == 4 || id2 == 5) ? particleDataPtr->m0(id2) : 0.;
450 redOsc = sqrtpos( pow2(pow2(mHad) - pow2(posMass) - pow2(negMass))
451 - 4. * pow2(posMass * negMass) ) / pow2(mHad);
455 if (hadronVertex == 0) prodPoint += 0.5 * redOsc * pHadron / kappaVtx;
456 else if (hadronVertex == 1) prodPoint += redOsc * pHadron / kappaVtx;
457 event[iHad].vProd( prodPoint * FM2MM );
469 void MiniStringFragmentation::setHadronVertices(
Event& event,
470 StringRegion& region,
int iFirst,
int iLast) {
473 vector<Vec4> longitudinal;
474 int id1 =
event[ iParton.front() ].idAbs();
475 int id2 =
event[ iParton.back() ].idAbs();
478 for (
int i = 0; i < 3; ++i) {
479 double xPosIn = ministringVertices[i].xRegPos;
480 double xNegIn = ministringVertices[i].xRegNeg;
481 Vec4 noOffset = (xPosIn * region.pPos + xNegIn * region.pNeg) / kappaVtx;
482 longitudinal.push_back( noOffset );
486 if (region.massiveOffset( 0, 0, 0, id1, id2, mc, mb)) {
487 for (
int i = 0; i < 3; ++i) {
490 if (i == 0 && (id1 == 4 || id1 == 5)) {
491 Vec4 v1 = longitudinal[i];
492 Vec4 v2 = longitudinal[i + 1];
493 double mHad =
event[
event.size() - 2].m();
494 double pPosMass = particleDataPtr->m0(id1);
495 longitudinal[i] = v1 + (pPosMass / mHad) * (v2 - v1);
497 if (i == 2 && (id2 == 4 || id2== 5)) {
498 Vec4 v1 = longitudinal[i];
499 Vec4 v2 = longitudinal[i-1] + region.massOffset / kappaVtx;
500 double mHad =
event[i - 1 +
event.size() - 2].m();
501 double pNegMass = particleDataPtr->m0(id2);
502 longitudinal[i] = v1 + (pNegMass / mHad) * (v2 - v1);
503 if (longitudinal[i].m2Calc()
504 < -1e-8 * max(1., pow2(longitudinal[i].e())))
505 infoPtr->errorMsg(
"Warning in MiniStringFragmentation::set"
506 "Vertices: negative tau^2 for endpoint massive correction");
510 Vec4 massOffset = region.massOffset / kappaVtx;
511 Vec4 position = longitudinal[i] - massOffset;
514 if (position.m2Calc() < 0.) {
516 if (position.m2Calc() > -1e-8 * max(1., pow2(position.e())))
517 position.e( position.pAbs() );
519 if(massOffset.m2Calc() > 1e-6)
520 cMinus = (longitudinal[i] * massOffset
521 - sqrt(pow2(longitudinal[i] * massOffset)
522 - longitudinal[i].m2Calc() * massOffset.m2Calc()))
523 / massOffset.m2Calc();
524 else cMinus = 0.5 * longitudinal[i].m2Calc()
525 / (longitudinal[i] * massOffset);
526 position = longitudinal[i] - cMinus * massOffset;
529 longitudinal[i] = position;
534 vector<Vec4> spaceTime;
535 for (
int i = 0; i < 3; ++i) {
536 Vec4 positionTot = longitudinal[i];
539 if (!isClosed && (i == 0 || i == 2)) {
540 spaceTime.push_back(positionTot);
547 for (
int iTry = 0; ; ++iTry) {
548 double transX = rndmPtr->gauss();
549 double transY = rndmPtr->gauss();
550 Vec4 transversePos = xySmear * (transX * eX + transY * eY) / sqrt(2.);
551 positionTot = transversePos + longitudinal[i];
556 double newtime = sqrt(longitudinal[i].m2Calc()
557 + positionTot.pAbs2());
558 positionTot.e(newtime);
561 if (positionTot.m2Calc() >= 0.)
break;
563 positionTot = longitudinal[i];
569 spaceTime.push_back(positionTot);
573 vector<Vec4> prodPoints(2);
574 for(
int i = 0; i < 2; ++i) {
575 Vec4 middlePoint = 0.5 * (spaceTime[i] + spaceTime[i+1]);
576 int iHad = (i == 0) ? iFirst : iLast;
577 Vec4 pHad =
event[iHad].p();
580 double mHad =
event[iHad].m();
581 int idQ = (i == 0) ? id1 : id2;
582 double redOsc = (idQ == 4 || idQ == 5)
583 ? 1. - pow2(particleDataPtr->m0(idQ) / mHad) : 0.;
586 if (hadronVertex == 0) prodPoints[i] = middlePoint;
587 else if (hadronVertex == 1)
588 prodPoints[i] = middlePoint + 0.5 * redOsc * pHad / kappaVtx;
590 prodPoints[i] = middlePoint - 0.5 * redOsc * pHad / kappaVtx;
591 if (prodPoints[i].m2Calc() < 0. || prodPoints[i].e() < 0.) {
592 double tau0fac = 2. * (redOsc * middlePoint * pHad
593 - sqrt(pow2(middlePoint * redOsc * pHad) - middlePoint.m2Calc()
594 * pow2(redOsc * mHad))) / pow2(redOsc * mHad);
595 prodPoints[i] = middlePoint - 0.5 * tau0fac * redOsc * pHad / kappaVtx;
598 event[iHad].vProd( prodPoints[i] * FM2MM );