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( PartonVertexPtr partonVertexPtrIn,
39 ColRecPtr colourReconnectionPtrIn) {
42 partonVertexPtr = partonVertexPtrIn;
43 colourReconnectionPtr = colourReconnectionPtrIn;
46 doPrimordialKT = flag(
"BeamRemnants:primordialKT");
47 primordialKTsoft = parm(
"BeamRemnants:primordialKTsoft");
48 primordialKThard = parm(
"BeamRemnants:primordialKThard");
49 primordialKTremnant = parm(
"BeamRemnants:primordialKTremnant");
50 halfScaleForKT = parm(
"BeamRemnants:halfScaleForKT");
51 halfMassForKT = parm(
"BeamRemnants:halfMassForKT");
52 reducedKTatHighY = parm(
"BeamRemnants:reducedKTatHighY");
55 allowRescatter = flag(
"MultipartonInteractions:allowRescatter");
56 doRescatterRestoreY = flag(
"BeamRemnants:rescatterRestoreY");
59 remnantMode = mode(
"BeamRemnants:remnantMode");
60 doReconnect = flag(
"ColourReconnection:reconnect");
61 reconnectMode = mode(
"ColourReconnection:mode");
64 doMPI = flag(
"PartonLevel:MPI");
67 beamA2gamma = flag(
"PDF:beamA2gamma");
68 beamB2gamma = flag(
"PDF:beamB2gamma");
71 if (remnantMode == 1 && reconnectMode == 0) {
72 infoPtr->errorMsg(
"Abort from BeamRemnants::init: The remnant model"
73 " and colour reconnection model does not work together");
82 junctionSplitting.init();
85 doPartonVertex = flag(
"PartonVertex:setVertex")
86 && (partonVertexPtr != 0);
99 bool BeamRemnants::add(
Event& event,
int iFirst,
bool doDiffCR) {
102 eCM = infoPtr->eCM();
106 for (
int i = 0; i < beamAPtr->size(); ++i) {
107 int j = (*beamAPtr)[i].iPos();
108 if ((*beamAPtr)[i].
id() != event[j].
id()) {
109 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
110 "event and beam flavours do not match");
114 for (
int i = 0; i < beamBPtr->size(); ++i) {
115 int j = (*beamBPtr)[i].iPos();
116 if ((*beamBPtr)[i].
id() != event[j].
id()) {
117 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
118 "event and beam flavours do not match");
125 isDIS = (beamAPtr->isLepton() && !beamBPtr->isLepton()
126 && beamAPtr->getGammaMode() == 0)
127 || (beamBPtr->isLepton() && !beamAPtr->isLepton()
128 && beamBPtr->getGammaMode() == 0);
131 nSys = partonSystemsPtr->sizeSys();
132 oldSize =
event.size();
135 Event eventSave = event;
136 BeamParticle beamAsave = (*beamAPtr);
137 BeamParticle beamBsave = (*beamBPtr);
138 PartonSystems partonSystemsSave = (*partonSystemsPtr);
141 if (remnantMode == 0) {
142 if (!addOld(event))
return false;
144 if (!addNew(event))
return false;
145 if (isDIS)
return true;
148 Event eventTmpSave = event;
149 bool colCorrect =
false;
150 for (
int i = 0; i < 10; ++i) {
151 if (doReconnect && doDiffCR
152 && (reconnectMode == 1 || reconnectMode == 2)) {
153 colourReconnectionPtr->next(event, iFirst);
156 if (!junctionSplitting.checkColours(event))
157 event = eventTmpSave;
164 if (junctionSplitting.checkColours(event))
171 if (doPartonVertex)
for (
int iBeam = 0; iBeam < 2; ++iBeam) {
172 BeamParticle& beamNow = (iBeam == 0) ? *beamAPtr : *beamBPtr;
173 vector<int> iRemn, iInit;
174 for (
int i = beamNow.sizeInit(); i < beamNow.size(); ++i)
175 iRemn.push_back( beamNow[i].iPos() );
176 for (
int i = 0; i < beamNow.sizeInit(); ++i)
177 iInit.push_back( beamNow[i].iPos() );
178 partonVertexPtr->vertexBeam(iBeam, iRemn, iInit, event);
184 (*beamAPtr) = beamAsave;
185 (*beamBPtr) = beamBsave;
186 (*partonSystemsPtr) = partonSystemsSave;
187 infoPtr->errorMsg(
"Error in BeamRemnants::add: "
188 "failed to find physical colour state after colour reconnection");
200 bool BeamRemnants::addOld(
Event& event) {
204 if ( !beamAPtr->remnantFlavours(event, isDIS)
205 || !beamBPtr->remnantFlavours(event, isDIS) ) {
206 infoPtr->errorMsg(
"Error in BeamRemnants::add:"
207 " remnant flavour setup failed");
212 if (!setKinematics(event))
return false;
215 if (doReconnect && reconnectMode == 0 && !isDIS)
216 colourReconnectionPtr->next(event, oldSize);
220 vector<int> acolSave;
221 for (
int i = oldSize; i <
event.size(); ++i) {
222 colSave.push_back( event[i].col() );
223 acolSave.push_back( event[i].acol() );
225 event.saveJunctionSize();
230 bool physical =
true;
231 for (
int iTry = 0; iTry < NTRYCOLMATCH; ++iTry) {
239 if (!beamAPtr->remnantColours(event, colFrom, colTo))
241 if (!beamBPtr->remnantColours(event, colFrom, colTo))
245 if ( physical && !checkColours(event) ) physical =
false;
249 for (
int i = oldSize; i <
event.size(); ++i)
250 event[i].cols( colSave[i - oldSize], acolSave[i - oldSize] );
251 event.restoreJunctionSize();
252 infoPtr->errorMsg(
"Warning in BeamRemnants::addOld:"
253 " colour tracing failed; will try again");
258 infoPtr->errorMsg(
"Error in BeamRemnants::addOld:"
259 " colour tracing failed after several attempts");
271 bool BeamRemnants::addNew(
Event& event) {
274 Event eventSave = event;
275 BeamParticle beamAsave = (*beamAPtr);
276 BeamParticle beamBsave = (*beamBPtr);
277 PartonSystems partonSystemsSave = (*partonSystemsPtr);
280 bool beamRemnantFound =
false;
283 for (
int iTries = 0;iTries < nMaxTries; ++iTries) {
286 beamAPtr->setInitialCol(event);
287 beamBPtr->setInitialCol(event);
290 beamAPtr->findColSetup(event);
291 beamBPtr->updateCol(beamAPtr->getColUpdates());
293 beamBPtr->findColSetup(event);
294 beamAPtr->updateCol(beamBPtr->getColUpdates());
297 beamAPtr->remnantFlavoursNew(event);
298 beamBPtr->remnantFlavoursNew(event);
301 event.saveJunctionSize();
304 if (!setKinematics(event)) {
307 (*beamAPtr) = beamAsave;
308 (*beamBPtr) = beamBsave;
309 (*partonSystemsPtr) = partonSystemsSave;
314 updateColEvent(event, beamAPtr->getColUpdates());
315 updateColEvent(event, beamBPtr->getColUpdates());
318 if (junctionSplitting.checkColours(event)) {
319 beamRemnantFound =
true;
327 (*beamAPtr) = beamAsave;
328 (*beamBPtr) = beamBsave;
329 (*partonSystemsPtr) = partonSystemsSave;
334 if (!beamRemnantFound) {
335 infoPtr->errorMsg(
"Error in BeamRemnants::addNew: "
336 "failed to find physical colour structure");
339 (*beamAPtr) = beamAsave;
340 (*beamBPtr) = beamBsave;
341 (*partonSystemsPtr) = partonSystemsSave;
354 bool BeamRemnants::setKinematics(
Event& event) {
357 BeamParticle& beamA = *beamAPtr;
358 BeamParticle& beamB = *beamBPtr;
361 if (beamA.isLepton() && beamB.isLepton()) {
362 if (!beamA.isUnresolvedLepton()) {
363 double eGamma = max(0., event[1].e() - event[event[1].daughter1()].e() );
364 event.append( 22, 63, 1, 0, 0, 0, 0, 0, 0., 0., eGamma, eGamma, 0.);
366 if (!beamB.isUnresolvedLepton()) {
367 double eGamma = max(0., event[2].e() - event[event[2].daughter1()].e() );
368 event.append( 22, 63, 2, 0, 0, 0, 0, 0, 0., 0., -eGamma, eGamma, 0.);
374 if ( beamA.isGamma() && beamA[0].id() == 22 ) {
375 beamA.resolvedGamma(
false);
377 if ( beamB.isGamma() && beamB[0].id() == 22 ) {
378 beamB.resolvedGamma(
false);
382 bool beamAisGamma = beamA.isGamma();
383 bool beamBisGamma = beamB.isGamma();
384 bool gammaAResolved = beamA.resolvedGamma();
385 bool gammaBResolved = beamB.resolvedGamma();
386 bool gammaOneResolved =
false;
389 if ( ( beamAisGamma && !gammaAResolved && beamBisGamma && !gammaBResolved )
390 && infoPtr->nMPI() == 1 )
394 if ( beamAisGamma && beamA[0].
id() == 22 ) { }
395 else if ( beamBisGamma && beamB[0].
id() == 22 ) { }
396 else if ( ( !(beamA.isLepton() || (beamAisGamma && !gammaAResolved) )
397 && beamA.xMax(-1) <= 0.) ||
398 ( !(beamB.isLepton() || (beamBisGamma && !gammaBResolved) )
399 && beamB.xMax(-1) <= 0.) ) {
400 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
401 " no momentum left for beam remnants");
406 if ( beamAisGamma && beamBisGamma && gammaAResolved != gammaBResolved)
407 gammaOneResolved =
true;
410 if ( ( (beamAisGamma && !gammaAResolved)
411 || (beamBisGamma && !gammaBResolved) )
412 && !(beamAisGamma && beamBisGamma) )
413 gammaOneResolved =
true;
416 if ( ( beamA.getGammaMode() == 2 && !beamB2gamma )
417 || ( beamB.getGammaMode() == 2 && !beamA2gamma ) )
418 gammaOneResolved =
true;
421 if ( (gammaOneResolved && infoPtr->nMPI() == 1) || isDIS )
422 return setOneRemnKinematics(event);
426 for (
int i = 3; i <
event.size(); ++i)
427 if (event[i].statusAbs() < 20) nBeams = i + 1;
428 int nOffset = nBeams - 3;
431 if ( beamA2gamma || beamB2gamma ) {
432 if (beamA.hasResGamma()) --nOffset;
433 if (beamB.hasResGamma()) --nOffset;
437 int nMaxBeam = max( beamA.size(), beamB.size() );
438 vector<double> sHatSys(nMaxBeam);
439 vector<double> kTwidth(nMaxBeam);
440 vector<double> kTcomp(nMaxBeam);
441 vector<RotBstMatrix> Msys(nSys);
444 double kTcompSumA = 0.;
445 double kTcompSumB = 0.;
446 for (
int iSys = 0; iSys < nSys; ++iSys) {
448 if (!partonSystemsPtr->hasInAB(iSys)) {
450 ss <<
"iSys = "<<iSys;
451 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
452 " Encountered parton system without beam partons.",ss.str());
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();
462 if (doPrimordialKT) {
464 if (iSys == 0 && infoPtr->isLHA()) {
465 kTwidthNow = primordialKThard;
471 double scale = (iSys == 0) ? infoPtr->QRen(iDS)
472 : partonSystemsPtr->getPTHat(iSys);
473 kTwidthNow = (halfScaleForKT * primordialKTsoft
474 + scale * primordialKThard) / (halfScaleForKT + scale);
477 double mHat = sqrt(sHatNow);
479 pow( (event[iInA].e() + event[iInB].e()) / mHat, reducedKTatHighY );
480 mHatDamp = mHat / (mHat + halfMassForKT * yDamp);
481 kTwidthNow *= mHatDamp;
486 sHatSys[iSys] = sHatNow;
487 kTwidth[iSys] = kTwidthNow ;
488 kTcomp[iSys] = mHatDamp;
489 if (beamA[iSys].isFromBeam()) kTcompSumA += mHatDamp;
490 else beamA[iSys].m( event[iInA].m() );
491 if (beamB[iSys].isFromBeam()) kTcompSumB += mHatDamp;
492 else beamB[iSys].m( event[iInB].m() );
496 double kTwidthNow = (doPrimordialKT) ? primordialKTremnant : 0.;
497 for (
int iRem = nSys; iRem < nMaxBeam; ++iRem) {
499 kTwidth[iRem] = kTwidthNow ;
502 kTcompSumA += beamA.size() - nSys;
503 kTcompSumB += beamB.size() - nSys;
507 double xSum[2], xInvM[2], w2Beam[2], wPosRem, wNegRem, w2Rem;
508 for (
int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
512 for (
int iBeam = 0; iBeam < 2; ++iBeam) {
513 BeamParticle&
beam = (iBeam == 0) ? beamA : beamB;
514 int nPar = beam.size();
518 if ( (beam.isHadron() || beam.isGamma()) && doPrimordialKT ) {
521 for (
int iPar = 0; iPar < nPar; ++iPar) {
525 if ( iPar == beam.gamVal() || ( beam.gamVal() >= 0 &&
526 ( iPar != beam.gamVal() && beam[iPar].isValence()) ) ) ;
527 else if ( beam[iPar].isFromBeam() ) {
528 pair<double, double> gauss2 = rndmPtr->gauss2();
529 double px = kTwidth[iPar] * gauss2.first;
530 double py = kTwidth[iPar] * gauss2.second;
536 int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
537 : partonSystemsPtr->getInB(iPar);
538 beam[iPar].p( event[iInAB].p() );
543 double kTcompSum = (iBeam == 0) ? kTcompSumA : kTcompSumB;
546 if ( beam.gamVal() >= 0 ) {
549 double pT2corr = beam.pT2gamma2qqbar();
552 double phi = 2*M_PI*rndmPtr->flat();
553 double px = cos(phi) * sqrt(pT2corr);
554 double py = sin(phi) * sqrt(pT2corr);
555 beam[beam.gamVal()].px(px);
556 beam[beam.gamVal()].py(py);
561 kTcompSum -= kTcomp[beam.gamVal()];
565 for (
int iPar = 0; iPar < nPar; ++iPar)
566 if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
575 for (
int iPar = 0; iPar < nPar; ++iPar) {
576 if (beam[iPar].isFromBeam() && iPar != beam.gamVal() ) {
577 beam[iPar].px( beam[iPar].px() - pxSum * kTcomp[iPar] / kTcompSum);
578 beam[iPar].py( beam[iPar].py() - pySum * kTcomp[iPar] / kTcompSum);
583 }
else if ( beam.isHadron() || beam.isGamma() ) {
584 for (
int iPar = 0; iPar < nPar; ++iPar) {
585 if ( !beam[iPar].isFromBeam() ) {
586 int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
587 : partonSystemsPtr->getInB(iPar);
588 beam[iPar].p( event[iInAB].p() );
593 if ( beam.gamVal() >= 0 ) {
594 double phi = 2*M_PI*rndmPtr->flat();
595 double px = cos(phi) * sqrt(beam.pT2gamma2qqbar());
596 double py = sin(phi) * sqrt(beam.pT2gamma2qqbar());
597 beam[beam.gamVal()].px(px);
598 beam[beam.gamVal()].py(py);
602 for (
int iPar = 0; iPar < nPar; ++iPar) {
603 if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
616 for (
int iRem = nSys; iRem < nPar; ++iRem) {
617 double xPrel = beam.xRemnant( iRem);
619 xSum[iBeam] += xPrel;
620 xInvM[iBeam] += beam[iRem].mT2()/xPrel;
624 w2Beam[iBeam] = xSum[iBeam] * xInvM[iBeam];
632 for (
int iSys = 0; iSys < nSys; ++iSys) {
633 int iA = beamA[iSys].iPos();
634 int iB = beamB[iSys].iPos();
635 double sHat = sHatSys[iSys];
638 bool normalA = beamA[iSys].isFromBeam();
639 bool normalB = beamB[iSys].isFromBeam();
640 bool normalSys = normalA && normalB;
641 bool doubleRes = !normalA && !normalB;
644 if (allowRescatter && CORRECTMISMATCH) {
645 Vec4 pInitial =
event[iA].p() +
event[iB].p();
647 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
648 int iAB = partonSystemsPtr->getOut(iSys, iMem);
649 if (event[iAB].isFinal()) pFinal +=
event[iAB].p();
653 if (normalA && pFinal.pPos() > pInitial.pPos())
654 beamA[iSys].scalePT( pInitial.pPos() / pFinal.pPos() );
657 if (normalB && pFinal.pNeg() > pInitial.pNeg())
658 beamB[iSys].scalePT( pInitial.pNeg() / pFinal.pNeg() );
665 && (event[iA].pPos() / beamA[iSys].pPos() < 0
666 || event[iB].pNeg() / beamB[iSys].pNeg() < 0) ) {
667 infoPtr->errorMsg(
"Warning in BeamRemnants::setKinematics:"
668 " change in lightcone momentum sign; retrying kinematics");
674 double sHatTAft = sHat + pow2( beamA[iSys].px() + beamB[iSys].px())
675 + pow2( beamA[iSys].py() + beamB[iSys].py());
676 double w2A = beamA[iSys].mT2();
677 double w2B = beamB[iSys].mT2();
678 double w2Diff = sHatTAft - w2A - w2B;
679 double lambda = pow2(w2Diff) - 4. * w2A * w2B;
686 double lamRoot = sqrtpos( lambda );
689 if (allowRescatter && doubleRes && (event[iA].pPos() * event[iB].pNeg()
690 < event[iA].pNeg() * event[iB].pPos()) ) lamRoot = -lamRoot;
695 if (normalSys || doRescatterRestoreY || doubleRes) {
699 double sHatTBef = sHat;
700 double wPosBef, wNegBef, wPosBefRes, wNegBefRes;
703 wPosBef = beamA[iSys].x() * eCM;
704 wNegBef = beamB[iSys].x() * eCM;
708 }
else if (normalB) {
709 sHatTBef +=
event[iA].pT2();
710 wPosBef =
event[iA].pPos();
711 wNegBef =
event[iA].pNeg() + beamB[iSys].x() * eCM;
712 wPosBefRes = beamA[iSys].pPos();
713 wNegBefRes = beamA[iSys].pNeg();
715 }
else if (normalA) {
716 sHatTBef +=
event[iB].pT2();
717 wPosBef = beamA[iSys].x() * eCM +
event[iB].pPos();
718 wNegBef =
event[iB].pNeg();
719 wPosBefRes = beamB[iSys].pPos();
720 wNegBefRes = beamB[iSys].pNeg();
723 sHatTBef += pow2( event[iA].px() + event[iB].px())
724 + pow2( event[iA].py() + event[iB].py());
725 wPosBef =
event[iA].pPos() +
event[iB].pPos();
726 wNegBef =
event[iA].pNeg() +
event[iB].pNeg();
727 wPosBefRes = beamA[iSys].pPos() + beamB[iSys].pPos();
728 wNegBefRes = beamA[iSys].pNeg() + beamB[iSys].pNeg();
733 double rescale = sqrt(sHatTAft / sHatTBef);
734 double wPosAft = rescale * wPosBef;
735 double wNegAft = rescale * wNegBef;
736 wPosRem -= wPosAft - wPosBefRes;
737 wNegRem -= wNegAft - wNegBefRes;
738 double wPosA = 0.5 * (sHatTAft + w2A - w2B + lamRoot) / wNegAft;
739 double wNegB = 0.5 * (sHatTAft + w2B - w2A + lamRoot) / wPosAft;
742 beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
743 beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
744 beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
745 beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
753 double wPosA = beamA[iSys].pPos();
754 double wNegB = 0.5 * (w2Diff + lamRoot) / wPosA;
755 beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
756 beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
757 wPosRem -= w2B / wNegB;
762 }
else if (normalA) {
763 double wNegB = beamB[iSys].pNeg();
764 double wPosA = 0.5 * (w2Diff + lamRoot) / wNegB;
765 beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
766 beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
768 wNegRem -= w2A / wPosA;
780 Msys[iSys].toCMframe( event[iA].p(), event[iB].p() );
781 Msys[iSys].fromCMframe( beamA[iSys].p(), beamB[iSys].p() );
784 for (
int iSys2 = iSys + 1; iSys2 < nSys; ++iSys2) {
785 if (!beamA[iSys2].isFromBeam()) {
786 int iBefResc =
event[ beamA[iSys2].iPos() ].mother1();
787 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
788 if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
789 Vec4 pTemp =
event[iBefResc].p();
790 pTemp.rotbst( Msys[iSys] );
791 beamA[iSys2].p( pTemp );
796 if (!beamB[iSys2].isFromBeam()) {
797 int iBefResc =
event[ beamB[iSys2].iPos() ].mother1();
798 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
799 if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
800 Vec4 pTemp =
event[iBefResc].p();
801 pTemp.rotbst( Msys[iSys] );
802 beamB[iSys2].p( pTemp );
809 if (wPosRem < 0. || wNegRem < 0.) physical =
false;
810 w2Rem = wPosRem * wNegRem;
811 if (sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1]))
820 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
821 " kinematics construction failed");
827 for (
int iSys = 0; iSys < nSys; ++iSys) {
832 if (beamA[iSys].isFromBeam()) {
833 int iA = beamA[iSys].iPos();
834 int iAcopy =
event.copy(iA, -61);
835 event[iAcopy].rotbst(Msys[iSys],
false);
836 partonSystemsPtr->setInA(iSys, iAcopy);
837 beamA[iSys].iPos( iAcopy);
839 int mother =
event[iAcopy].mother1();
840 event[mother].daughter1(iAcopy);
843 if (beamB[iSys].isFromBeam()) {
844 int iB = beamB[iSys].iPos();
845 int iBcopy =
event.copy(iB, -61);
846 event[iBcopy].rotbst(Msys[iSys],
false);
847 partonSystemsPtr->setInB(iSys, iBcopy);
848 beamB[iSys].iPos( iBcopy);
850 int mother =
event[iBcopy].mother1();
851 event[mother].daughter1(iBcopy);
855 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
856 int iAB = partonSystemsPtr->getOut(iSys, iMem);
857 if (event[iAB].isFinal()) {
858 int iABcopy =
event.copy(iAB, 62);
859 event[iABcopy].rotbst(Msys[iSys],
false);
860 partonSystemsPtr->setOut(iSys, iMem, iABcopy);
861 pSumOut +=
event[iABcopy].p();
869 if (allowRescatter && CORRECTMISMATCH) {
874 for (
int iRem = nSys; iRem < beamA.size(); ++iRem) {
875 pxBeams += beamA[iRem].px();
876 pyBeams += beamA[iRem].py();
878 for (
int iRem = nSys; iRem < beamB.size(); ++iRem) {
879 pxBeams += beamB[iRem].px();
880 pyBeams += beamB[iRem].py();
884 Vec4 pSumTo( -pxBeams, -pyBeams, pSumOut.pz(), sqrt( pow2(pxBeams)
885 + pow2(pyBeams) + pow2(pSumOut.pz()) + pSumOut.m2Calc() ) );
886 RotBstMatrix Mmismatch;
887 Mmismatch.bst( pSumOut, pSumTo);
888 for (
int iSys = 0; iSys < nSys; ++iSys)
889 for (
int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
890 int iAB = partonSystemsPtr->getOut(iSys, iMem);
891 if (event[iAB].isFinal())
event[iAB].rotbst(Mmismatch,
false);
893 pSumOut.rotbst(Mmismatch);
896 wPosRem = eCM - (pSumOut.e() + pSumOut.pz());
897 wNegRem = eCM - (pSumOut.e() - pSumOut.pz());
898 w2Rem = wPosRem * wNegRem;
899 if ( wPosRem < 0. || wNegRem < 0.
900 || sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1])) {
901 infoPtr->errorMsg(
"Error in BeamRemnants::setKinematics:"
902 " kinematics construction failed owing to recoil mismatch");
908 double lambdaRoot = sqrtpos( pow2(w2Rem - w2Beam[0] - w2Beam[1])
909 - 4. * w2Beam[0] * w2Beam[1] );
910 double rescaleA = (w2Rem + w2Beam[0] - w2Beam[1] + lambdaRoot)
911 / (2. * w2Rem * xSum[0]) ;
912 double rescaleB = (w2Rem + w2Beam[1] - w2Beam[0] + lambdaRoot)
913 / (2. * w2Rem * xSum[1]) ;
916 for (
int iRem = nSys; iRem < beamA.size(); ++iRem) {
917 double pPos = rescaleA * beamA[iRem].x() * wPosRem;
918 double pNeg = beamA[iRem].mT2() / pPos;
919 beamA[iRem].e( 0.5 * (pPos + pNeg) );
920 beamA[iRem].pz( 0.5 * (pPos - pNeg) );
923 int iNew =
event.append( beamA[iRem].
id(), 63, 1 + nOffset, 0, 0, 0,
924 beamA[iRem].col(), beamA[iRem].acol(), beamA[iRem].p(),
926 beamA[iRem].iPos( iNew);
930 for (
int iRem = nSys; iRem < beamB.size(); ++iRem) {
931 double pNeg = rescaleB * beamB[iRem].x() * wNegRem;
932 double pPos = beamB[iRem].mT2() / pNeg;
933 beamB[iRem].e( 0.5 * (pPos + pNeg) );
934 beamB[iRem].pz( 0.5 * (pPos - pNeg) );
937 int iNew =
event.append( beamB[iRem].
id(), 63, 2 + nOffset, 0, 0, 0,
938 beamB[iRem].col(), beamB[iRem].acol(), beamB[iRem].p(),
940 beamB[iRem].iPos( iNew);
954 bool BeamRemnants::setOneRemnKinematics(
Event& event) {
958 if ( beamAPtr->isGamma() && beamBPtr->isGamma() )
959 iBeamHad = beamAPtr->resolvedGamma() ? 1 : 2;
960 else iBeamHad = beamAPtr->isHadron() ? 1 : 2;
961 BeamParticle& beamHad = (iBeamHad == 1) ? *beamAPtr : *beamBPtr;
962 BeamParticle& beamOther = (iBeamHad == 2) ? *beamAPtr : *beamBPtr;
971 if (event.size() < 4) {
972 infoPtr->errorMsg(
"Error in BeamRemnants::setOneRemnKinematics:"
973 " unexpected number of particles in the event record");
979 for (
int i = 3; i <
event.size(); ++i) {
980 if ( abs(event[i].status()) > 20 ) {
989 int iLepScat = isDIS ? (beamOther[0].iPos() + 2) : -1;
993 int iLepOut = particleDataPtr->isLepton(beamAPtr->id())
994 ? iBeamA + 2 + 2 : iBeamB + 2 + 2;
995 if ( !beamOther.isGamma()
996 && (iLepScat >
event.size()-1
997 || !
event[iLepOut].isLepton()
998 || !
event[iLepScat].isLepton()
999 || !
event[iLepScat].isFinal())) {
1001 for (
int i = event.size()-1; i > 0 ; --i) {
1002 if ( event[i].isFinal()
1003 &&
event[iLepOut].id() ==
event[i].id()
1004 &&
event[i].e() > eMax) {
1006 eMax =
event[i].e();
1015 if (beamAPtr->isLepton() && beamBPtr->isHadron())
1016 { iBeamA = (*beamAPtr)[0].iPos(); }
1017 if (beamBPtr->isLepton() && beamAPtr->isHadron())
1018 { iBeamB = (*beamBPtr)[0].iPos(); }
1019 double etot = (
event[iBeamA].p() +
event[iBeamB].p()).mCalc();
1020 RotBstMatrix MtoRest;
1021 MtoRest.bst( event[iBeamA].p() + event[iBeamB].p(), Vec4(0.,0.,0.,etot));
1022 if ( abs(event[iBeamA].pz() + event[iBeamB].pz()) > 1e-5)
1023 event.rotbst(MtoRest);
1026 for (
int i = 5 + beamOffset; i <
event.size(); ++i)
1027 if (event[i].isFinal() && i != iLepScat) pHadScat += event[i].p();
1030 Vec4 pLepScat = isDIS ?
event[iLepScat].p() : Vec4();
1031 Vec4 pHadTot =
event[iBeamA].p() +
event[iBeamB].p();
1032 if ( isDIS ) pHadTot -= pLepScat;
1033 Vec4 pRemnant = pHadTot - pHadScat;
1034 double w2Tot = pHadTot.m2Calc();
1035 double w2Scat = pHadScat.m2Calc();
1038 RotBstMatrix MtoHadRest;
1040 if (iBeamHad == 1) MtoHadRest.toCMframe( pRemnant, pHadScat);
1041 else MtoHadRest.toCMframe( pHadScat, pRemnant);
1044 event.rotbst( MtoHadRest);
1045 pHadScat.rotbst( MtoHadRest);
1048 int nBeam = beamHad.size();
1049 vector<double> kTwidth(nBeam);
1050 vector<double> kTcomp(nBeam);
1053 double kTcompSum = 0;
1054 if (doPrimordialKT) {
1057 int iInA = partonSystemsPtr->getInA(iSys);
1058 int iInB = partonSystemsPtr->getInB(iSys);
1059 double sHatNow = (
event[iInA].p() +
event[iInB].p()).m2Calc();
1060 double mHat = sqrt(sHatNow);
1061 double mHatDamp = mHat / (mHat + halfMassForKT);
1062 double scale = infoPtr->QRen(iDS);
1063 kTwidth[0] = ( (halfScaleForKT * primordialKTsoft
1064 + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
1065 kTcomp[0] = mHatDamp;
1066 kTcompSum = mHatDamp + nBeam - 1.;
1069 for (
int iRem = 1; iRem < nBeam; ++iRem) {
1070 kTwidth[iRem] = primordialKTremnant;
1077 bool isPhysical =
true;
1078 double xSum, xInvM, w2Remn, wDiff;
1079 for (
int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
1083 if (doPrimordialKT) {
1088 for (
int iPar = 0; iPar < nBeam; ++iPar) {
1089 pair<double, double> gauss2 = rndmPtr->gauss2();
1090 double px = kTwidth[iPar] * gauss2.first;
1091 double py = kTwidth[iPar] * gauss2.second;
1092 beamHad[iPar].px(px);
1093 beamHad[iPar].py(py);
1099 for (
int iPar = 0; iPar < nBeam; ++iPar) {
1100 beamHad[iPar].px( beamHad[iPar].px() - pxSum*kTcomp[iPar]/kTcompSum );
1101 beamHad[iPar].py( beamHad[iPar].py() - pySum*kTcomp[iPar]/kTcompSum );
1108 for (
int iRem = 1; iRem < beamHad.size(); ++iRem) {
1109 double xPrel = beamHad.xRemnant( iRem);
1110 beamHad[iRem].x(xPrel);
1112 xInvM += beamHad[iRem].mT2() / xPrel;
1116 double mT2Scat = w2Scat;
1117 if (doPrimordialKT) mT2Scat += pow2( beamHad[0].pT());
1120 w2Remn = xSum * xInvM;
1121 wDiff = sqrt(w2Tot) - sqrtpos(mT2Scat) - sqrtpos(w2Remn);
1122 if (wDiff < 0.) isPhysical =
false;
1123 if (isPhysical)
break;
1128 MtoHadRest.invert();
1129 event.rotbst( MtoHadRest);
1130 infoPtr->errorMsg(
"Error in BeamRemnants::setOneRemnKinematics:"
1131 " too big beam remnant invariant mass");
1136 if (doPrimordialKT) {
1138 int iInA = partonSystemsPtr->getInA(iSys);
1139 int iInB = partonSystemsPtr->getInB(iSys);
1140 int iInit = (iBeamHad == 1) ? iInA : iInB;
1143 Vec4 pBeam = beamOther.p();
1146 double w2 = (beamOther.p() +
event[iInit].p()).m2Calc();
1147 double m2 = pow2(beamHad.m());
1148 double mT2 = pow2(beamHad[iSys].pT()) + m2;
1149 double eInitNew = beamOther.e()*mT2/(w2-m2) + 0.25*(w2-m2)/beamOther.e();
1150 double pzInitNew = beamOther.e()*mT2/(w2-m2) - 0.25*(w2-m2)/beamOther.e();
1151 if(iBeamHad == 1) pzInitNew *= -1.0;
1152 beamHad[iSys].pz( pzInitNew);
1153 beamHad[iSys].e( eInitNew);
1157 RotBstMatrix MtoInitWithkT;
1160 if (iBeamHad == 1) {
1161 MtoInitWithkT.toCMframe( beamHad[iSys].p(), beamOther.p());
1163 MtoInitWithkT.toCMframe( beamOther.p(), beamHad[iSys].p());
1167 pBeam.rotbst(MtoInitWithkT);
1168 MtoInitWithkT.bst( pBeam, beamOther.p());
1171 MtoInitWithkT.invert();
1174 int iBeam = beamHad[iSys].iPos();
1175 int iCopy =
event.copy(iBeam, -61);
1176 event[iCopy].rotbst(MtoInitWithkT);
1177 if (iBeamHad == 1) partonSystemsPtr->setInA(iSys, iCopy);
1178 else partonSystemsPtr->setInB(iSys, iCopy);
1179 beamHad[iSys].iPos( iCopy);
1180 int mother =
event[iCopy].mother1();
1181 event[mother].daughter1(iCopy);
1184 w2Scat += pow2( beamHad[iSys].pT());
1188 double lambda = pow2( w2Tot - w2Scat - w2Remn) - 4. * w2Scat * w2Remn;
1189 double pzNew = 0.5 * sqrt( lambda / w2Tot);
1191 if(iBeamHad == 1) pzNew *= -1.0;
1192 double eNewScat = 0.5 * (w2Tot + w2Scat - w2Remn) / sqrt(w2Tot);
1193 Vec4 pNewScat( beamHad[iSys].px(), beamHad[iSys].py(), pzNew, eNewScat);
1194 RotBstMatrix MforScat;
1195 MforScat.bst( pHadScat, pNewScat);
1196 int sizeSave =
event.size();
1197 for (
int i = 5 + beamOffset; i < sizeSave; ++i)
1198 if ( i != iLepScat && event[i].isFinal() ) {
1199 int iNew =
event.copy( i, 62);
1200 event[iNew].rotbst( MforScat,
false);
1204 double eNewRemn = 0.5 * (w2Tot + w2Remn - w2Scat) / sqrt(w2Tot);
1205 double wNewRemn = eNewRemn + pzNew;
1206 for (
int iRem = 1; iRem < beamHad.size(); ++iRem) {
1207 double wNegNow = wNewRemn * beamHad[iRem].x() / xSum;
1208 double wPosNow = beamHad[iRem].mT2() / wNegNow;
1209 beamHad[iRem].pz(-0.5 * (wNegNow - wPosNow));
1210 beamHad[iRem].e ( 0.5 * (wPosNow + wNegNow));
1211 int iNew =
event.append( beamHad[iRem].
id(), 63, iBeamHad + beamOffset,
1212 0, 0, 0, beamHad[iRem].col(), beamHad[iRem].acol(), beamHad[iRem].p(),
1213 beamHad[iRem].m() );
1214 beamHad[iRem].iPos( iNew);
1218 MtoHadRest.invert();
1219 event.rotbst( MtoHadRest);
1229 bool BeamRemnants::checkColours(
Event& event) {
1232 if (beamAPtr->isLepton() && beamBPtr->isLepton())
return true;
1236 for (
int iCol = 1; iCol < int(colFrom.size()); ++iCol)
1237 for (
int iColRef = 0; iColRef < iCol; ++iColRef) {
1238 if (colFrom[iCol] == colFrom[iColRef]) {
1239 colFrom[iCol] = colTo[iCol];
1240 colTo[iCol] = colTo[iColRef];
1242 if (colTo[iCol] == colFrom[iColRef]) colTo[iCol] = colTo[iColRef];
1246 for (
int i = oldSize; i <
event.size(); ++i) {
1247 int col =
event[i].col();
1248 int acol =
event[i].acol();
1249 for (
int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1250 if (col == colFrom[iCol]) {col = colTo[iCol];
event[i].col(col);}
1251 if (acol == colFrom[iCol]) {acol = colTo[iCol];
event[i].acol(acol);}
1253 if (col == -colFrom[iCol]) {col = -colTo[iCol];
event[i].col(col);}
1254 if (acol == -colFrom[iCol]) {acol = -colTo[iCol];
event[i].acol(acol);}
1259 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun)
1260 for (
int leg = 0; leg < 3; ++leg) {
1261 int col =
event.colJunction(iJun, leg);
1262 for (
int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1263 if (col == colFrom[iCol]) {
1265 event.colJunction(iJun, leg, col);
1271 vector<int> colList;
1272 vector<int> acolList;
1273 vector<int> iSingletGluon;
1276 for (
int i = oldSize; i <
event.size(); ++i)
1277 if (event[i].isFinal()) {
1278 int id =
event[i].id();
1279 int col =
event[i].col();
1280 int acol =
event[i].acol();
1281 int colType =
event[i].colType();
1284 if ( (
id > 0 &&
id < 9 && (col <= 0 || acol != 0) )
1285 || (id < 0 && id > -9 && (col != 0 || acol <= 0) )
1286 || (
id == 21 && (col <= 0 || acol <= 0) ) ) {
1287 infoPtr->errorMsg(
"Error in BeamRemnants::checkColours: "
1288 "q/qbar/g has wrong colour slots set");
1293 if ( (colType == 3 && (col <= 0 || acol >= 0))
1294 || (colType == -3 && (col >= 0 || acol <= 0)) ) {
1295 infoPtr->errorMsg(
"Error in BeamRemnants::checkColours: "
1296 "sextet has wrong colours");
1300 if ( col > 0) colList.push_back( col );
1301 if (acol > 0) acolList.push_back( acol );
1302 if (col > 0 && acol == col) iSingletGluon.push_back(i);
1304 if ( col < 0) acolList.push_back( -col );
1305 if (acol < 0) colList.push_back( -acol );
1310 for (
int iS = 0; iS < int(iSingletGluon.size()); ++iS) {
1311 int iGlu = iSingletGluon[iS];
1313 double pT2DipMin = sCM;
1314 for (
int iC = oldSize; iC <
event.size(); ++iC)
1315 if (iC != iGlu && event[iC].isFinal()) {
1316 int colDip =
event[iC].col();
1317 if (colDip > 0 && event[iC].acol() !=colDip)
1318 for (
int iA = oldSize; iA <
event.size(); ++iA)
1319 if (iA != iGlu && iA != iC && event[iA].isFinal()
1320 &&
event[iA].acol() == colDip &&
event[iA].col() !=colDip) {
1321 double pT2Dip = (
event[iGlu].p() *
event[iC].p())
1322 * (event[iGlu].p() *
event[iA].p())
1323 / (event[iC].p() *
event[iA].p());
1324 if (pT2Dip < pT2DipMin) {
1332 if (iAcolDip == -1)
return false;
1333 event[iGlu].acol( event[iAcolDip].acol() );
1334 event[iAcolDip].acol( event[iGlu].col() );
1337 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun) {
1340 if (event.kindJunction(iJun) % 2 == 0)
continue;
1341 for (
int leg = 0; leg < 3; ++leg) {
1342 int col =
event.colJunction(iJun, leg);
1343 if (col == event[iGlu].acol())
1344 event.colJunction(iJun, leg, event[iGlu].col());
1351 for (
int iCol = 0; iCol < int(colList.size()) - 1; ++iCol) {
1352 int col = colList[iCol];
1353 for (
int iCol2 = iCol + 1; iCol2 < int(colList.size()); ++iCol2)
1354 if (colList[iCol2] == col) {
1355 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1356 " colour appears twice");
1357 if (!ALLOWCOLOURTWICE)
return false;
1360 for (
int iAcol = 0; iAcol < int(acolList.size()) - 1; ++iAcol) {
1361 int acol = acolList[iAcol];
1362 for (
int iAcol2 = iAcol + 1; iAcol2 < int(acolList.size()); ++iAcol2)
1363 if (acolList[iAcol2] == acol) {
1364 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1365 " anticolour appears twice");
1366 if (!ALLOWCOLOURTWICE)
return false;
1371 bool foundPair =
true;
1372 while (foundPair && colList.size() > 0 && acolList.size() > 0) {
1374 for (
int iCol = 0; iCol < int(colList.size()); ++iCol) {
1375 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) {
1376 if (acolList[iAcol] == colList[iCol]) {
1377 colList[iCol] = colList.back(); colList.pop_back();
1378 acolList[iAcol] = acolList.back(); acolList.pop_back();
1383 if (foundPair)
break;
1388 for (
int iJun = 0; iJun <
event.sizeJunction(); ++iJun) {
1389 int kindJun =
event.kindJunction(iJun);
1390 for (
int leg = 0; leg < 3; ++leg) {
1391 int colEnd =
event.colJunction(iJun, leg);
1395 for (
int iCol = 0; iCol < int(colList.size()); ++iCol)
1396 if (colList[iCol] == colEnd) {
1398 colList[iCol] = colList.back();
1405 else if (kindJun == 2) {
1406 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1407 if (acolList[iAcol] == colEnd) {
1409 acolList[iAcol] = acolList.back();
1410 acolList.pop_back();
1416 else if ( kindJun == 3 || kindJun == 5) {
1417 for (
int iCol = 0; iCol < int(colList.size()); ++iCol)
1418 if (colList[iCol] == colEnd) {
1420 colList[iCol] = colList.back();
1427 else if ( kindJun == 4 || kindJun == 6) {
1428 for (
int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1429 if (acolList[iAcol] == colEnd) {
1431 acolList[iAcol] = acolList.back();
1432 acolList.pop_back();
1443 if (colList.size() > 0 || acolList.size() > 0) {
1444 infoPtr->errorMsg(
"Warning in BeamRemnants::checkColours:"
1445 " need to repair unmatched colours");
1447 while (colList.size() > 0 && acolList.size() > 0) {
1450 int colMatch = colList.back();
1451 int acolMatch = acolList.back();
1452 int colNew =
event.nextColTag();
1454 acolList.pop_back();
1455 for (
int i = oldSize; i <
event.size(); ++i) {
1456 if (event[i].isFinal() &&
event[i].col() == colMatch) {
1457 event[i].col( colNew);
1460 else if (event[i].isFinal() && event[i].acol() == -colMatch) {
1461 event[i].acol( -colNew);
1465 for (
int i = oldSize; i <
event.size(); ++i) {
1466 if (event[i].isFinal() &&
event[i].acol() == acolMatch) {
1467 event[i].acol( colNew);
1470 if (event[i].isFinal() && event[i].col() == -acolMatch) {
1471 event[i].col( -colNew);
1478 return (colList.size() == 0 && acolList.size() == 0);
1486 void BeamRemnants::updateColEvent(
Event& event,
1487 vector<pair <int,int> > colChanges) {
1489 for (
int iCol = 0; iCol < int(colChanges.size()); ++iCol) {
1491 int oldCol = colChanges[iCol].first;
1492 int newCol = colChanges[iCol].second;
1493 if (oldCol == newCol)
1497 for (
int j = 0; j <
event.size(); ++j) {
1498 if (event[j].isFinal() &&
event[j].col() == oldCol)
1499 event[event.copy(j, 64)].col(newCol);
1500 if (event[j].isFinal() && event[j].acol() == -oldCol)
1501 event[
event.copy(j, 64)].acol(-newCol);
1503 if (event[j].isFinal() && event[j].acol() == oldCol)
1504 event[
event.copy(j,64)].acol(newCol);
1505 if (event[j].isFinal() && event[j].col() == -oldCol)
1506 event[
event.copy(j,64)].col(-newCol);
1510 for (
int j = 0;j <
event.sizeJunction(); ++j)
1511 for (
int jCol = 0; jCol < 3; ++jCol)
1512 if (event.colJunction(j,jCol) == oldCol)
1513 event.colJunction(j,jCol,newCol);