9 #include "Pythia8/BeamRemnants.h"
23 const bool BeamRemnants::ALLOWCOLOURTWICE =
true;
26 const int BeamRemnants::NTRYCOLMATCH = 10;
27 const int BeamRemnants::NTRYKINMATCH = 10;
32 const bool BeamRemnants::CORRECTMISMATCH =
false;
38 bool BeamRemnants::init( Info* infoPtrIn, Settings& settings, Rndm* rndmPtrIn,
39 BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn,
40 PartonSystems* partonSystemsPtrIn, PartonVertex* partonVertexPtrIn,
41 ParticleData* particleDataPtrIn,
42 ColourReconnection* colourReconnectionPtrIn) {
47 beamAPtr = beamAPtrIn;
48 beamBPtr = beamBPtrIn;
49 partonSystemsPtr = partonSystemsPtrIn;
50 partonVertexPtr = partonVertexPtrIn;
51 colourReconnectionPtr = colourReconnectionPtrIn;
52 particleDataPtr = particleDataPtrIn;
55 doPrimordialKT = settings.flag(
"BeamRemnants:primordialKT");
56 primordialKTsoft = settings.parm(
"BeamRemnants:primordialKTsoft");
57 primordialKThard = settings.parm(
"BeamRemnants:primordialKThard");
58 primordialKTremnant = settings.parm(
"BeamRemnants:primordialKTremnant");
59 halfScaleForKT = settings.parm(
"BeamRemnants:halfScaleForKT");
60 halfMassForKT = settings.parm(
"BeamRemnants:halfMassForKT");
61 reducedKTatHighY = settings.parm(
"BeamRemnants:reducedKTatHighY");
64 allowRescatter = settings.flag(
"MultipartonInteractions:allowRescatter");
65 doRescatterRestoreY = settings.flag(
"BeamRemnants:rescatterRestoreY");
68 remnantMode = settings.mode(
"BeamRemnants:remnantMode");
69 doReconnect = settings.flag(
"ColourReconnection:reconnect");
70 reconnectMode = settings.mode(
"ColourReconnection:mode");
73 doMPI = settings.flag(
"PartonLevel:MPI");
76 if (remnantMode == 1 && reconnectMode == 0) {
77 infoPtr->errorMsg(
"Abort from BeamRemnants::init: The remnant model"
78 " and colour reconnection model does not work together");
87 junctionSplitting.init(infoPtr, settings, rndmPtr, particleDataPtrIn);
90 doPartonVertex = settings.flag(
"PartonVertex:setVertex")
91 && (partonVertexPtr != 0);
104 bool BeamRemnants::add(
Event& event,
int iFirst,
bool doDiffCR) {
107 eCM = infoPtr->eCM();
111 for (
int i = 0; i < beamAPtr->size(); ++i) {
112 int j = (*beamAPtr)[i].iPos();
113 if ((*beamAPtr)[i].
id() != event[j].
id()) {
114 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
115 "event and beam flavours do not match");
119 for (
int i = 0; i < beamBPtr->size(); ++i) {
120 int j = (*beamBPtr)[i].iPos();
121 if ((*beamBPtr)[i].
id() != event[j].
id()) {
122 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
123 "event and beam flavours do not match");
130 isDIS = (beamAPtr->isLepton() && !beamBPtr->isLepton()
131 && beamAPtr->getGammaMode() == 0)
132 || (beamBPtr->isLepton() && !beamAPtr->isLepton()
133 && beamBPtr->getGammaMode() == 0);
136 nSys = partonSystemsPtr->sizeSys();
137 oldSize =
event.size();
140 Event eventSave = event;
141 BeamParticle beamAsave = (*beamAPtr);
142 BeamParticle beamBsave = (*beamBPtr);
143 PartonSystems partonSystemsSave = (*partonSystemsPtr);
146 if (remnantMode == 0) {
147 if (!addOld(event))
return false;
149 if (!addNew(event))
return false;
151 if (isDIS)
return true;
154 Event eventTmpSave = event;
155 bool colCorrect =
false;
156 for (
int i = 0; i < 10; ++i) {
157 if (doReconnect && doDiffCR
158 && (reconnectMode == 1 || reconnectMode == 2)) {
159 colourReconnectionPtr->next(event, iFirst);
162 if (!junctionSplitting.checkColours(event))
163 event = eventTmpSave;
170 if (junctionSplitting.checkColours(event))
177 if (doPartonVertex) {
178 BeamParticle* beamPtr = beamAPtr;
181 for (
int i = 0; i < beamPtr->size(); ++i) {
182 int j = (*beamPtr)[i].iPos();
184 vector<int> dList =
event[j].daughterList();
186 partonVertexPtr->vertexBeam(j,
beam, event);
188 for(
int k = 0, N = dList.size(); k < N; ++k )
189 partonVertexPtr->vertexBeam(dList[k],
beam,event);
199 (*beamAPtr) = beamAsave;
200 (*beamBPtr) = beamBsave;
201 (*partonSystemsPtr) = partonSystemsSave;
202 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
203 "failed to find physical colour state after colour reconnection");
215 bool BeamRemnants::addOld(
Event& event) {
219 if ( !beamAPtr->remnantFlavours(event, isDIS)
220 || !beamBPtr->remnantFlavours(event, isDIS) ) {
221 infoPtr->errorMsg(
"Error in BeamRemnants::add:"
222 " remnant flavour setup failed");
227 if (!setKinematics(event))
return false;
230 if (doReconnect && reconnectMode == 0 && !isDIS)
231 colourReconnectionPtr->next(event, oldSize);
235 vector<int> acolSave;
236 for (
int i = oldSize; i <
event.size(); ++i) {
237 colSave.push_back( event[i].col() );
238 acolSave.push_back( event[i].acol() );
240 event.saveJunctionSize();
245 bool physical =
true;
246 for (
int iTry = 0; iTry < NTRYCOLMATCH; ++iTry) {
254 if (!beamAPtr->remnantColours(event, colFrom, colTo))
256 if (!beamBPtr->remnantColours(event, colFrom, colTo))
260 if ( physical && !checkColours(event) ) physical =
false;
264 for (
int i = oldSize; i <
event.size(); ++i)
265 event[i].cols( colSave[i - oldSize], acolSave[i - oldSize] );
266 event.restoreJunctionSize();
267 infoPtr->errorMsg(
"Warning in BeamRemnants::add:"
268 " colour tracing failed; will try again");
273 infoPtr->errorMsg(
"Error in BeamRemnants::add:"
274 " colour tracing failed after several attempts");
286 bool BeamRemnants::addNew(
Event& event) {
289 Event eventSave = event;
290 BeamParticle beamAsave = (*beamAPtr);
291 BeamParticle beamBsave = (*beamBPtr);
292 PartonSystems partonSystemsSave = (*partonSystemsPtr);
295 bool beamRemnantFound =
false;
298 for (
int iTries = 0;iTries < nMaxTries; ++iTries) {
301 beamAPtr->setInitialCol(event);
302 beamBPtr->setInitialCol(event);
305 beamAPtr->findColSetup(event);
306 beamBPtr->updateCol(beamAPtr->getColUpdates());
308 beamBPtr->findColSetup(event);
309 beamAPtr->updateCol(beamBPtr->getColUpdates());
312 beamAPtr->remnantFlavoursNew(event);
313 beamBPtr->remnantFlavoursNew(event);
316 event.saveJunctionSize();
319 if (!setKinematics(event)) {
322 (*beamAPtr) = beamAsave;
323 (*beamBPtr) = beamBsave;
324 (*partonSystemsPtr) = partonSystemsSave;
329 updateColEvent(event, beamAPtr->getColUpdates());
330 updateColEvent(event, beamBPtr->getColUpdates());
333 if (junctionSplitting.checkColours(event)) {
334 beamRemnantFound =
true;
342 (*beamAPtr) = beamAsave;
343 (*beamBPtr) = beamBsave;
344 (*partonSystemsPtr) = partonSystemsSave;
349 if (!beamRemnantFound) {
350 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
351 "failed to find physical colour structure");
354 (*beamAPtr) = beamAsave;
355 (*beamBPtr) = beamBsave;
356 (*partonSystemsPtr) = partonSystemsSave;
369 bool BeamRemnants::setKinematics(
Event& event) {
372 BeamParticle& beamA = *beamAPtr;
373 BeamParticle& beamB = *beamBPtr;
376 if ( beamA.isUnresolvedLepton() && beamB.isUnresolvedLepton() )
380 if ( beamA.isGamma() && beamA[0].id() == 22 ) {
381 beamA.resolvedGamma(
false);
383 if ( beamB.isGamma() && beamB[0].id() == 22 ) {
384 beamB.resolvedGamma(
false);
388 bool beamAisGamma = beamA.isGamma();
389 bool beamBisGamma = beamB.isGamma();
390 bool gammaAResolved = beamA.resolvedGamma();
391 bool gammaBResolved = beamB.resolvedGamma();
392 bool gammaOneResolved =
false;
395 if ( ( beamAisGamma && !gammaAResolved && beamBisGamma && !gammaBResolved )
396 && infoPtr->nMPI() == 1 )
400 if ( beamA.isGamma() && beamA[0].id() == 22 ) { }
401 else if ( beamB.isGamma() && beamB[0].id() == 22 ) { }
402 else if ( ( !(beamA.isLepton() || (beamAisGamma && !gammaAResolved) )
403 && beamA.xMax(-1) <= 0.) ||
404 ( !(beamB.isLepton() || (beamBisGamma && !gammaBResolved) )
405 && beamB.xMax(-1) <= 0.) ) {
406 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
407 " no momentum left for beam remnants");
412 if ( (beamAisGamma && beamBisGamma) &&
413 ( (gammaAResolved && !gammaBResolved) ||
414 (!gammaAResolved && gammaBResolved) ) )
415 gammaOneResolved =
true;
418 if ( ( (beamAisGamma && !gammaAResolved)
419 || (beamBisGamma && !gammaBResolved) )
420 && !(beamAisGamma && beamBisGamma) )
421 gammaOneResolved =
true;
424 if ( ( beamA.getGammaMode() == 2 && beamB.isHadron() )
425 || ( beamB.getGammaMode() == 2 && beamA.isHadron() ) )
426 gammaOneResolved =
true;
429 if ( (gammaOneResolved && infoPtr->nMPI() == 1) || isDIS )
430 return setOneRemnKinematics(event, iDS);
434 for (
int i = 3; i <
event.size(); ++i)
435 if (event[i].statusAbs() < 20) nBeams = i + 1;
436 int nOffset = nBeams - 3;
439 if ( !(beamA.isHadron() || beamB.isHadron()) ) {
440 if (beamA.hasResGamma()) --nOffset;
441 if (beamB.hasResGamma()) --nOffset;
445 int nMaxBeam = max( beamA.size(), beamB.size() );
446 vector<double> sHatSys(nMaxBeam);
447 vector<double> kTwidth(nMaxBeam);
448 vector<double> kTcomp(nMaxBeam);
449 vector<RotBstMatrix> Msys(nSys);
452 double kTcompSumA = 0.;
453 double kTcompSumB = 0.;
454 for (
int iSys = 0; iSys < nSys; ++iSys) {
455 double kTwidthNow = 0.;
456 double mHatDamp = 1.;
457 int iInA = partonSystemsPtr->getInA(iSys);
458 int iInB = partonSystemsPtr->getInB(iSys);
459 double sHatNow = (
event[iInA].p() +
event[iInB].p()).m2Calc();
463 if (doPrimordialKT) {
464 double mHat = sqrt(sHatNow);
465 double yDamp = pow( (event[iInA].e() + event[iInB].e()) / mHat,
467 mHatDamp = mHat / (mHat + halfMassForKT * yDamp);
468 double scale = (iSys == 0) ? infoPtr->QRen(iDS)
469 : partonSystemsPtr->getPTHat(iSys);
470 kTwidthNow = ( (halfScaleForKT * primordialKTsoft
471 + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
476 sHatSys[iSys] = sHatNow;
477 kTwidth[iSys] = kTwidthNow ;
478 kTcomp[iSys] = mHatDamp;
479 if (beamA[iSys].isFromBeam()) kTcompSumA += mHatDamp;
480 else beamA[iSys].m( event[iInA].m() );
481 if (beamB[iSys].isFromBeam()) kTcompSumB += mHatDamp;
482 else beamB[iSys].m( event[iInB].m() );
486 double kTwidthNow = (doPrimordialKT) ? primordialKTremnant : 0.;
487 for (
int iRem = nSys; iRem < nMaxBeam; ++iRem) {
489 kTwidth[iRem] = kTwidthNow ;
492 kTcompSumA += beamA.size() - nSys;
493 kTcompSumB += beamB.size() - nSys;
497 double xSum[2], xInvM[2], w2Beam[2], wPosRem, wNegRem, w2Rem;
498 for (
int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
502 for (
int iBeam = 0; iBeam < 2; ++iBeam) {
503 BeamParticle&
beam = (iBeam == 0) ? beamA : beamB;
504 int nPar = beam.size();
508 if ( (beam.isHadron() || beam.isGamma()) && doPrimordialKT ) {
511 for (
int iPar = 0; iPar < nPar; ++iPar) {
515 if ( iPar == beam.gamVal() || ( beam.gamVal() >= 0 &&
516 ( iPar != beam.gamVal() && beam[iPar].isValence()) ) ) ;
517 else if ( beam[iPar].isFromBeam() ) {
518 pair<double, double> gauss2 = rndmPtr->gauss2();
519 double px = kTwidth[iPar] * gauss2.first;
520 double py = kTwidth[iPar] * gauss2.second;
526 int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
527 : partonSystemsPtr->getInB(iPar);
528 beam[iPar].p( event[iInAB].p() );
533 double kTcompSum = (iBeam == 0) ? kTcompSumA : kTcompSumB;
536 if ( beam.gamVal() >= 0 ) {
539 double pT2corr = beam.pT2gamma2qqbar();
542 double phi = 2*M_PI*rndmPtr->flat();
543 double px = cos(phi) * sqrt(pT2corr);
544 double py = sin(phi) * sqrt(pT2corr);
545 beam[beam.gamVal()].px(px);
546 beam[beam.gamVal()].py(py);
551 kTcompSum -= kTcomp[beam.gamVal()];
555 for (
int iPar = 0; iPar < nPar; ++iPar)
556 if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
565 for (
int iPar = 0; iPar < nPar; ++iPar) {
566 if (beam[iPar].isFromBeam() && iPar != beam.gamVal() ) {
567 beam[iPar].px( beam[iPar].px() - pxSum * kTcomp[iPar] / kTcompSum);
568 beam[iPar].py( beam[iPar].py() - pySum * kTcomp[iPar] / kTcompSum);
573 }
else if ( beam.isHadron() || beam.isGamma() ) {
574 for (
int iPar = 0; iPar < nPar; ++iPar) {
575 if ( !beam[iPar].isFromBeam() ) {
576 int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
577 : partonSystemsPtr->getInB(iPar);
578 beam[iPar].p( event[iInAB].p() );
583 if ( beam.gamVal() >= 0 ) {
584 double phi = 2*M_PI*rndmPtr->flat();
585 double px = cos(phi) * sqrt(beam.pT2gamma2qqbar());
586 double py = sin(phi) * sqrt(beam.pT2gamma2qqbar());
587 beam[beam.gamVal()].px(px);
588 beam[beam.gamVal()].py(py);
592 for (
int iPar = 0; iPar < nPar; ++iPar) {
593 if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
606 for (
int iRem = nSys; iRem < nPar; ++iRem) {
607 double xPrel = beam.xRemnant( iRem);
609 xSum[iBeam] += xPrel;
610 xInvM[iBeam] += beam[iRem].mT2()/xPrel;
614 w2Beam[iBeam] = xSum[iBeam] * xInvM[iBeam];
622 for (
int iSys = 0; iSys < nSys; ++iSys) {
623 int iA = beamA[iSys].iPos();
624 int iB = beamB[iSys].iPos();
625 double sHat = sHatSys[iSys];
628 bool normalA = beamA[iSys].isFromBeam();
629 bool normalB = beamB[iSys].isFromBeam();
630 bool normalSys = normalA && normalB;
631 bool doubleRes = !normalA && !normalB;
634 if (allowRescatter && CORRECTMISMATCH) {
635 Vec4 pInitial =
event[iA].p() +
event[iB].p();
637 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
638 int iAB = partonSystemsPtr->getOut(iSys, iMem);
639 if (event[iAB].isFinal()) pFinal +=
event[iAB].p();
643 if (normalA && pFinal.pPos() > pInitial.pPos())
644 beamA[iSys].scalePT( pInitial.pPos() / pFinal.pPos() );
647 if (normalB && pFinal.pNeg() > pInitial.pNeg())
648 beamB[iSys].scalePT( pInitial.pNeg() / pFinal.pNeg() );
655 && (event[iA].pPos() / beamA[iSys].pPos() < 0
656 || event[iB].pNeg() / beamB[iSys].pNeg() < 0) ) {
657 infoPtr->errorMsg(
"Warning in BeamRemnants::setKinematics:"
658 " change in lightcone momentum sign; retrying kinematics");
664 double sHatTAft = sHat + pow2( beamA[iSys].px() + beamB[iSys].px())
665 + pow2( beamA[iSys].py() + beamB[iSys].py());
666 double w2A = beamA[iSys].mT2();
667 double w2B = beamB[iSys].mT2();
668 double w2Diff = sHatTAft - w2A - w2B;
669 double lambda = pow2(w2Diff) - 4. * w2A * w2B;
676 double lamRoot = sqrtpos( lambda );
679 if (allowRescatter && doubleRes && (event[iA].pPos() * event[iB].pNeg()
680 < event[iA].pNeg() * event[iB].pPos()) ) lamRoot = -lamRoot;
685 if (normalSys || doRescatterRestoreY || doubleRes) {
689 double sHatTBef = sHat;
690 double wPosBef, wNegBef, wPosBefRes, wNegBefRes;
693 wPosBef = beamA[iSys].x() * eCM;
694 wNegBef = beamB[iSys].x() * eCM;
698 }
else if (normalB) {
699 sHatTBef +=
event[iA].pT2();
700 wPosBef =
event[iA].pPos();
701 wNegBef =
event[iA].pNeg() + beamB[iSys].x() * eCM;
702 wPosBefRes = beamA[iSys].pPos();
703 wNegBefRes = beamA[iSys].pNeg();
705 }
else if (normalA) {
706 sHatTBef +=
event[iB].pT2();
707 wPosBef = beamA[iSys].x() * eCM +
event[iB].pPos();
708 wNegBef =
event[iB].pNeg();
709 wPosBefRes = beamB[iSys].pPos();
710 wNegBefRes = beamB[iSys].pNeg();
713 sHatTBef += pow2( event[iA].px() + event[iB].px())
714 + pow2( event[iA].py() + event[iB].py());
715 wPosBef =
event[iA].pPos() +
event[iB].pPos();
716 wNegBef =
event[iA].pNeg() +
event[iB].pNeg();
717 wPosBefRes = beamA[iSys].pPos() + beamB[iSys].pPos();
718 wNegBefRes = beamA[iSys].pNeg() + beamB[iSys].pNeg();
723 double rescale = sqrt(sHatTAft / sHatTBef);
724 double wPosAft = rescale * wPosBef;
725 double wNegAft = rescale * wNegBef;
726 wPosRem -= wPosAft - wPosBefRes;
727 wNegRem -= wNegAft - wNegBefRes;
728 double wPosA = 0.5 * (sHatTAft + w2A - w2B + lamRoot) / wNegAft;
729 double wNegB = 0.5 * (sHatTAft + w2B - w2A + lamRoot) / wPosAft;
732 beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
733 beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
734 beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
735 beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
743 double wPosA = beamA[iSys].pPos();
744 double wNegB = 0.5 * (w2Diff + lamRoot) / wPosA;
745 beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
746 beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
747 wPosRem -= w2B / wNegB;
752 }
else if (normalA) {
753 double wNegB = beamB[iSys].pNeg();
754 double wPosA = 0.5 * (w2Diff + lamRoot) / wNegB;
755 beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
756 beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
758 wNegRem -= w2A / wPosA;
770 Msys[iSys].toCMframe( event[iA].p(), event[iB].p() );
771 Msys[iSys].fromCMframe( beamA[iSys].p(), beamB[iSys].p() );
774 for (
int iSys2 = iSys + 1; iSys2 < nSys; ++iSys2) {
775 if (!beamA[iSys2].isFromBeam()) {
776 int iBefResc =
event[ beamA[iSys2].iPos() ].mother1();
777 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
778 if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
779 Vec4 pTemp =
event[iBefResc].p();
780 pTemp.rotbst( Msys[iSys] );
781 beamA[iSys2].p( pTemp );
786 if (!beamB[iSys2].isFromBeam()) {
787 int iBefResc =
event[ beamB[iSys2].iPos() ].mother1();
788 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
789 if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
790 Vec4 pTemp =
event[iBefResc].p();
791 pTemp.rotbst( Msys[iSys] );
792 beamB[iSys2].p( pTemp );
799 if (wPosRem < 0. || wNegRem < 0.) physical =
false;
800 w2Rem = wPosRem * wNegRem;
801 if (sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1]))
810 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
811 " kinematics construction failed");
817 for (
int iSys = 0; iSys < nSys; ++iSys) {
822 if (beamA[iSys].isFromBeam()) {
823 int iA = beamA[iSys].iPos();
824 int iAcopy =
event.copy(iA, -61);
825 event[iAcopy].rotbst(Msys[iSys]);
826 partonSystemsPtr->setInA(iSys, iAcopy);
827 beamA[iSys].iPos( iAcopy);
829 int mother =
event[iAcopy].mother1();
830 event[mother].daughter1(iAcopy);
833 if (beamB[iSys].isFromBeam()) {
834 int iB = beamB[iSys].iPos();
835 int iBcopy =
event.copy(iB, -61);
836 event[iBcopy].rotbst(Msys[iSys]);
837 partonSystemsPtr->setInB(iSys, iBcopy);
838 beamB[iSys].iPos( iBcopy);
840 int mother =
event[iBcopy].mother1();
841 event[mother].daughter1(iBcopy);
845 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
846 int iAB = partonSystemsPtr->getOut(iSys, iMem);
847 if (event[iAB].isFinal()) {
848 int iABcopy =
event.copy(iAB, 62);
849 event[iABcopy].rotbst(Msys[iSys]);
850 partonSystemsPtr->setOut(iSys, iMem, iABcopy);
851 pSumOut +=
event[iABcopy].p();
859 if (allowRescatter && CORRECTMISMATCH) {
864 for (
int iRem = nSys; iRem < beamA.size(); ++iRem) {
865 pxBeams += beamA[iRem].px();
866 pyBeams += beamA[iRem].py();
868 for (
int iRem = nSys; iRem < beamB.size(); ++iRem) {
869 pxBeams += beamB[iRem].px();
870 pyBeams += beamB[iRem].py();
874 Vec4 pSumTo( -pxBeams, -pyBeams, pSumOut.pz(), sqrt( pow2(pxBeams)
875 + pow2(pyBeams) + pow2(pSumOut.pz()) + pSumOut.m2Calc() ) );
876 RotBstMatrix Mmismatch;
877 Mmismatch.bst( pSumOut, pSumTo);
878 for (
int iSys = 0; iSys < nSys; ++iSys)
879 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
880 int iAB = partonSystemsPtr->getOut(iSys, iMem);
881 if (event[iAB].isFinal())
event[iAB].rotbst(Mmismatch);
883 pSumOut.rotbst(Mmismatch);
886 wPosRem = eCM - (pSumOut.e() + pSumOut.pz());
887 wNegRem = eCM - (pSumOut.e() - pSumOut.pz());
888 w2Rem = wPosRem * wNegRem;
889 if ( wPosRem < 0. || wNegRem < 0.
890 || sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1])) {
891 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
892 " kinematics construction failed owing to recoil mismatch");
898 double lambdaRoot = sqrtpos( pow2(w2Rem - w2Beam[0] - w2Beam[1])
899 - 4. * w2Beam[0] * w2Beam[1] );
900 double rescaleA = (w2Rem + w2Beam[0] - w2Beam[1] + lambdaRoot)
901 / (2. * w2Rem * xSum[0]) ;
902 double rescaleB = (w2Rem + w2Beam[1] - w2Beam[0] + lambdaRoot)
903 / (2. * w2Rem * xSum[1]) ;
906 for (
int iRem = nSys; iRem < beamA.size(); ++iRem) {
907 double pPos = rescaleA * beamA[iRem].x() * wPosRem;
908 double pNeg = beamA[iRem].mT2() / pPos;
909 beamA[iRem].e( 0.5 * (pPos + pNeg) );
910 beamA[iRem].pz( 0.5 * (pPos - pNeg) );
913 int iNew =
event.append( beamA[iRem].
id(), 63, 1 + nOffset, 0, 0, 0,
914 beamA[iRem].col(), beamA[iRem].acol(), beamA[iRem].p(),
916 beamA[iRem].iPos( iNew);
920 for (
int iRem = nSys; iRem < beamB.size(); ++iRem) {
921 double pNeg = rescaleB * beamB[iRem].x() * wNegRem;
922 double pPos = beamB[iRem].mT2() / pNeg;
923 beamB[iRem].e( 0.5 * (pPos + pNeg) );
924 beamB[iRem].pz( 0.5 * (pPos - pNeg) );
927 int iNew =
event.append( beamB[iRem].
id(), 63, 2 + nOffset, 0, 0, 0,
928 beamB[iRem].col(), beamB[iRem].acol(), beamB[iRem].p(),
930 beamB[iRem].iPos( iNew);
944 bool BeamRemnants::setOneRemnKinematics(
Event& event,
int beamOffset) {
948 if ( beamAPtr->isGamma() && beamBPtr->isGamma() )
949 iBeamHad = beamAPtr->resolvedGamma() ? 1 : 2;
950 else iBeamHad = beamAPtr->isHadron() ? 1 : 2;
951 BeamParticle& beamHad = (iBeamHad == 1) ? *beamAPtr : *beamBPtr;
952 BeamParticle& beamOther = (iBeamHad == 2) ? *beamAPtr : *beamBPtr;
955 int iBeamA = 1 + beamOffset;
956 int iBeamB = 2 + beamOffset;
959 int iLepScat = isDIS ? (beamOther[0].iPos() + 2) : -1;
961 for (
int i = 5 + beamOffset; i <
event.size(); ++i)
962 if (event[i].isFinal() && i != iLepScat) pHadScat += event[i].p();
965 Vec4 pLepScat = isDIS ?
event[iLepScat].p() : Vec4();
966 Vec4 pHadTot =
event[iBeamA].p() +
event[iBeamB].p();
967 if ( isDIS ) pHadTot -= pLepScat;
968 Vec4 pRemnant = pHadTot - pHadScat;
969 double w2Tot = pHadTot.m2Calc();
970 double w2Scat = pHadScat.m2Calc();
973 RotBstMatrix MtoHadRest;
974 RotBstMatrix MtoHadRest2;
975 MtoHadRest2.toCMframe( pHadScat, pRemnant);
978 if (iBeamHad == 1) MtoHadRest.toCMframe( pRemnant, pHadScat);
979 else MtoHadRest.toCMframe( pHadScat, pRemnant);
982 event.rotbst( MtoHadRest);
983 pHadScat.rotbst( MtoHadRest);
986 int nBeam = beamHad.size();
987 vector<double> kTwidth(nBeam);
988 vector<double> kTcomp(nBeam);
991 double kTcompSum = 0;
992 if (doPrimordialKT) {
995 int iInA = partonSystemsPtr->getInA(iSys);
996 int iInB = partonSystemsPtr->getInB(iSys);
997 double sHatNow = (
event[iInA].p() +
event[iInB].p()).m2Calc();
998 double mHat = sqrt(sHatNow);
999 double mHatDamp = mHat / (mHat + halfMassForKT);
1000 double scale = (iSys == 0) ? infoPtr->QRen(iDS)
1001 : partonSystemsPtr->getPTHat(iSys);
1002 kTwidth[0] = ( (halfScaleForKT * primordialKTsoft
1003 + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
1004 kTcomp[0] = mHatDamp;
1005 kTcompSum = mHatDamp + nBeam - 1.;
1008 for (
int iRem = 1; iRem < nBeam; ++iRem) {
1009 kTwidth[iRem] = primordialKTremnant;
1016 bool isPhysical =
true;
1017 double xSum, xInvM, w2Remn, wDiff;
1018 for (
int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
1022 if (doPrimordialKT) {
1027 for (
int iPar = 0; iPar < nBeam; ++iPar) {
1028 pair<double, double> gauss2 = rndmPtr->gauss2();
1029 double px = kTwidth[iPar] * gauss2.first;
1030 double py = kTwidth[iPar] * gauss2.second;
1031 beamHad[iPar].px(px);
1032 beamHad[iPar].py(py);
1038 for (
int iPar = 0; iPar < nBeam; ++iPar) {
1039 beamHad[iPar].px( beamHad[iPar].px() - pxSum*kTcomp[iPar]/kTcompSum );
1040 beamHad[iPar].py( beamHad[iPar].py() - pySum*kTcomp[iPar]/kTcompSum );
1047 for (
int iRem = 1; iRem < beamHad.size(); ++iRem) {
1048 double xPrel = beamHad.xRemnant( iRem);
1049 beamHad[iRem].x(xPrel);
1051 xInvM += beamHad[iRem].mT2() / xPrel;
1055 double mT2Scat = w2Scat;
1056 if (doPrimordialKT) mT2Scat += pow2( beamHad[0].pT());
1059 w2Remn = xSum * xInvM;
1060 wDiff = sqrt(w2Tot) - sqrtpos(mT2Scat) - sqrtpos(w2Remn);
1061 if (wDiff < 0.) isPhysical =
false;
1062 if (isPhysical)
break;
1067 MtoHadRest.invert();
1068 event.rotbst( MtoHadRest);
1069 infoPtr->errorMsg(
"Error in BeamRemnants::setOneRemnKinematics:"
1070 " too big beam remnant invariant mass");
1075 if (doPrimordialKT) {
1077 int iInA = partonSystemsPtr->getInA(iSys);
1078 int iInB = partonSystemsPtr->getInB(iSys);
1079 int iInit = (iBeamHad == 1) ? iInA : iInB;
1082 Vec4 pBeam = beamOther.p();
1085 double w2 = (beamOther.p() +
event[iInit].p()).m2Calc();
1086 double m2 = pow2(beamHad.m());
1087 double mT2 = pow2(beamHad[iSys].pT()) + m2;
1088 double eInitNew = beamOther.e()*mT2/(w2-m2) + 0.25*(w2-m2)/beamOther.e();
1089 double pzInitNew = beamOther.e()*mT2/(w2-m2) - 0.25*(w2-m2)/beamOther.e();
1090 if(iBeamHad == 1) pzInitNew *= -1.0;
1091 beamHad[iSys].pz( pzInitNew);
1092 beamHad[iSys].e( eInitNew);
1096 RotBstMatrix MtoInitWithkT;
1099 if (iBeamHad == 1) {
1100 MtoInitWithkT.toCMframe( beamHad[iSys].p(), beamOther.p());
1102 MtoInitWithkT.toCMframe( beamOther.p(), beamHad[iSys].p());
1106 pBeam.rotbst(MtoInitWithkT);
1107 MtoInitWithkT.bst( pBeam, beamOther.p());
1110 MtoInitWithkT.invert();
1113 int iBeam = beamHad[iSys].iPos();
1114 int iCopy =
event.copy(iBeam, -61);
1115 event[iCopy].rotbst(MtoInitWithkT);
1116 if (iBeamHad == 1) partonSystemsPtr->setInA(iSys, iCopy);
1117 else partonSystemsPtr->setInB(iSys, iCopy);
1118 beamHad[iSys].iPos( iCopy);
1120 int mother =
event[iCopy].mother1();
1121 event[mother].daughter1(iCopy);
1125 w2Scat += pow2( beamHad[iSys].pT());
1129 double lambda = pow2( w2Tot - w2Scat - w2Remn) - 4. * w2Scat * w2Remn;
1130 double pzNew = 0.5 * sqrt( lambda / w2Tot);
1132 if(iBeamHad == 1) pzNew *= -1.0;
1133 double eNewScat = 0.5 * (w2Tot + w2Scat - w2Remn) / sqrt(w2Tot);
1134 Vec4 pNewScat( beamHad[iSys].px(), beamHad[iSys].py(), pzNew, eNewScat);
1135 RotBstMatrix MforScat;
1136 MforScat.bst( pHadScat, pNewScat);
1137 int sizeSave =
event.size();
1138 for (
int i = 5 + beamOffset; i < sizeSave; ++i)
1139 if ( i != iLepScat && event[i].isFinal() ) {
1140 int iNew =
event.copy( i, 62);
1141 event[iNew].rotbst( MforScat);
1145 double eNewRemn = 0.5 * (w2Tot + w2Remn - w2Scat) / sqrt(w2Tot);
1146 double wNewRemn = eNewRemn + pzNew;
1147 for (
int iRem = 1; iRem < beamHad.size(); ++iRem) {
1148 double wNegNow = wNewRemn * beamHad[iRem].x() / xSum;
1149 double wPosNow = beamHad[iRem].mT2() / wNegNow;
1150 beamHad[iRem].pz(-0.5 * (wNegNow - wPosNow));
1151 beamHad[iRem].e ( 0.5 * (wPosNow + wNegNow));
1152 int iNew =
event.append( beamHad[iRem].
id(), 63, iBeamHad + beamOffset,
1153 0, 0, 0, beamHad[iRem].col(), beamHad[iRem].acol(), beamHad[iRem].p(),
1154 beamHad[iRem].m() );
1155 beamHad[iRem].iPos( iNew);
1159 MtoHadRest.invert();
1160 event.rotbst( MtoHadRest);
1170 bool BeamRemnants::checkColours(
Event& event) {
1173 if (beamAPtr->isLepton() && beamBPtr->isLepton())
return true;
1177 for (
int iCol = 1; iCol < int(colFrom.size()); ++iCol)
1178 for (
int iColRef = 0; iColRef < iCol; ++iColRef) {
1179 if (colFrom[iCol] == colFrom[iColRef]) {
1180 colFrom[iCol] = colTo[iCol];
1181 colTo[iCol] = colTo[iColRef];
1183 if (colTo[iCol] == colFrom[iColRef]) colTo[iCol] = colTo[iColRef];
1187 for (
int i = oldSize; i <
event.size(); ++i) {
1188 int col =
event[i].col();
1189 int acol =
event[i].acol();
1190 for (
int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1191 if (col == colFrom[iCol]) {col = colTo[iCol];
event[i].col(col);}
1192 if (acol == colFrom[iCol]) {acol = colTo[iCol];
event[i].acol(acol);}
1194 if (col == -colFrom[iCol]) {col = -colTo[iCol];
event[i].col(col);}
1195 if (acol == -colFrom[iCol]) {acol = -colTo[iCol];
event[i].acol(acol);}
1200 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun)
1201 for (
int leg = 0; leg < 3; ++leg) {
1202 int col =
event.colJunction(iJun, leg);
1203 for (
int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1204 if (col == colFrom[iCol]) {
1206 event.colJunction(iJun, leg, col);
1212 vector<int> colList;
1213 vector<int> acolList;
1214 vector<int> iSingletGluon;
1217 for (
int i = oldSize; i <
event.size(); ++i)
1218 if (event[i].isFinal()) {
1219 int id =
event[i].id();
1220 int col =
event[i].col();
1221 int acol =
event[i].acol();
1222 int colType =
event[i].colType();
1225 if ( (
id > 0 &&
id < 9 && (col <= 0 || acol != 0) )
1226 || (id < 0 && id > -9 && (col != 0 || acol <= 0) )
1227 || (
id == 21 && (col <= 0 || acol <= 0) ) ) {
1228 infoPtr->errorMsg(
"Error in BeamRemnants::checkColours: "
1229 "q/qbar/g has wrong colour slots set");
1234 if ( (colType == 3 && (col <= 0 || acol >= 0))
1235 || (colType == -3 && (col >= 0 || acol <= 0)) ) {
1236 infoPtr->errorMsg(
"Error in BeamRemnants::checkColours: "
1237 "sextet has wrong colours");
1241 if ( col > 0) colList.push_back( col );
1242 if (acol > 0) acolList.push_back( acol );
1243 if (col > 0 && acol == col) iSingletGluon.push_back(i);
1245 if ( col < 0) acolList.push_back( -col );
1246 if (acol < 0) colList.push_back( -acol );
1251 for (
int iS = 0; iS < int(iSingletGluon.size()); ++iS) {
1252 int iGlu = iSingletGluon[iS];
1254 double pT2DipMin = sCM;
1255 for (
int iC = oldSize; iC <
event.size(); ++iC)
1256 if (iC != iGlu && event[iC].isFinal()) {
1257 int colDip =
event[iC].col();
1258 if (colDip > 0 && event[iC].acol() !=colDip)
1259 for (
int iA = oldSize; iA <
event.size(); ++iA)
1260 if (iA != iGlu && iA != iC && event[iA].isFinal()
1261 &&
event[iA].acol() == colDip &&
event[iA].col() !=colDip) {
1262 double pT2Dip = (
event[iGlu].p() *
event[iC].p())
1263 * (event[iGlu].p() *
event[iA].p())
1264 / (event[iC].p() *
event[iA].p());
1265 if (pT2Dip < pT2DipMin) {
1273 if (iAcolDip == -1)
return false;
1274 event[iGlu].acol( event[iAcolDip].acol() );
1275 event[iAcolDip].acol( event[iGlu].col() );
1278 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun) {
1281 if (event.kindJunction(iJun) % 2 == 0)
continue;
1282 for (
int leg = 0; leg < 3; ++leg) {
1283 int col =
event.colJunction(iJun, leg);
1284 if (col == event[iGlu].acol())
1285 event.colJunction(iJun, leg, event[iGlu].col());
1292 for (
int iCol = 0; iCol < int(colList.size()) - 1; ++iCol) {
1293 int col = colList[iCol];
1294 for (
int iCol2 = iCol + 1; iCol2 < int(colList.size()); ++iCol2)
1295 if (colList[iCol2] == col) {
1296 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1297 " colour appears twice");
1298 if (!ALLOWCOLOURTWICE)
return false;
1301 for (
int iAcol = 0; iAcol < int(acolList.size()) - 1; ++iAcol) {
1302 int acol = acolList[iAcol];
1303 for (
int iAcol2 = iAcol + 1; iAcol2 < int(acolList.size()); ++iAcol2)
1304 if (acolList[iAcol2] == acol) {
1305 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1306 " anticolour appears twice");
1307 if (!ALLOWCOLOURTWICE)
return false;
1312 bool foundPair =
true;
1313 while (foundPair && colList.size() > 0 && acolList.size() > 0) {
1315 for (
int iCol = 0; iCol < int(colList.size()); ++iCol) {
1316 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) {
1317 if (acolList[iAcol] == colList[iCol]) {
1318 colList[iCol] = colList.back(); colList.pop_back();
1319 acolList[iAcol] = acolList.back(); acolList.pop_back();
1324 if (foundPair)
break;
1329 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun) {
1330 int kindJun =
event.kindJunction(iJun);
1331 for (
int leg = 0; leg < 3; ++leg) {
1332 int colEnd =
event.colJunction(iJun, leg);
1336 for (
int iCol = 0; iCol < int(colList.size()); ++iCol)
1337 if (colList[iCol] == colEnd) {
1339 colList[iCol] = colList.back();
1346 else if (kindJun == 2) {
1347 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1348 if (acolList[iAcol] == colEnd) {
1350 acolList[iAcol] = acolList.back();
1351 acolList.pop_back();
1357 else if ( kindJun == 3 || kindJun == 5) {
1358 for (
int iCol = 0; iCol < int(colList.size()); ++iCol)
1359 if (colList[iCol] == colEnd) {
1361 colList[iCol] = colList.back();
1368 else if ( kindJun == 4 || kindJun == 6) {
1369 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1370 if (acolList[iAcol] == colEnd) {
1372 acolList[iAcol] = acolList.back();
1373 acolList.pop_back();
1384 if (colList.size() > 0 || acolList.size() > 0) {
1385 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1386 " need to repair unmatched colours");
1388 while (colList.size() > 0 && acolList.size() > 0) {
1391 int colMatch = colList.back();
1392 int acolMatch = acolList.back();
1393 int colNew =
event.nextColTag();
1395 acolList.pop_back();
1396 for (
int i = oldSize; i <
event.size(); ++i) {
1397 if (event[i].isFinal() &&
event[i].col() == colMatch) {
1398 event[i].col( colNew);
1401 else if (event[i].isFinal() && event[i].acol() == -colMatch) {
1402 event[i].acol( -colNew);
1406 for (
int i = oldSize; i <
event.size(); ++i) {
1407 if (event[i].isFinal() &&
event[i].acol() == acolMatch) {
1408 event[i].acol( colNew);
1411 if (event[i].isFinal() && event[i].col() == -acolMatch) {
1412 event[i].col( -colNew);
1419 return (colList.size() == 0 && acolList.size() == 0);
1427 void BeamRemnants::updateColEvent(
Event& event,
1428 vector<pair <int,int> > colChanges) {
1430 for (
int iCol = 0; iCol < int(colChanges.size()); ++iCol) {
1432 int oldCol = colChanges[iCol].first;
1433 int newCol = colChanges[iCol].second;
1434 if (oldCol == newCol)
1438 for (
int j = 0; j <
event.size(); ++j) {
1439 if (event[j].isFinal() &&
event[j].col() == oldCol)
1440 event[event.copy(j, 64)].col(newCol);
1441 if (event[j].isFinal() && event[j].acol() == -oldCol)
1442 event[
event.copy(j, 64)].acol(-newCol);
1444 if (event[j].isFinal() && event[j].acol() == oldCol)
1445 event[
event.copy(j,64)].acol(newCol);
1446 if (event[j].isFinal() && event[j].col() == -oldCol)
1447 event[
event.copy(j,64)].col(-newCol);
1451 for (
int j = 0;j <
event.sizeJunction(); ++j)
1452 for (
int jCol = 0; jCol < 3; ++jCol)
1453 if (event.colJunction(j,jCol) == oldCol)
1454 event.colJunction(j,jCol,newCol);