LCOV - code coverage report
Current view: top level - PYTHIA8/pythia8210dev/src - BeamRemnants.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 616 0.0 %
Date: 2016-06-14 17:26:59 Functions: 0 8 0.0 %

          Line data    Source code
       1             : // BeamRemnants.cc is a part of the PYTHIA event generator.
       2             : // Copyright (C) 2015 Torbjorn Sjostrand.
       3             : // PYTHIA is licenced under the GNU GPL version 2, see COPYING for details.
       4             : // Please respect the MCnet Guidelines, see GUIDELINES for details.
       5             : 
       6             : // Function definitions (not found in the header) for the
       7             : // BeamRemnants class.
       8             : 
       9             : #include "Pythia8/BeamRemnants.h"
      10             : 
      11             : namespace Pythia8 {
      12             : 
      13             : //==========================================================================
      14             : 
      15             : // The BeamRemnants class.
      16             : 
      17             : //--------------------------------------------------------------------------
      18             : 
      19             : // Constants: could be changed here if desired, but normally should not.
      20             : // These are of technical nature, as described for each.
      21             : 
      22             : // If same (anti)colour appears twice in final state, repair or reject.
      23             : const bool   BeamRemnants::ALLOWCOLOURTWICE = true;
      24             : 
      25             : // Maximum number of tries to match colours and kinematics in the event.
      26             : const int    BeamRemnants::NTRYCOLMATCH     = 10;
      27             : const int    BeamRemnants::NTRYKINMATCH     = 10;
      28             : 
      29             : // Overall correction step for energy-momentum conservation; only
      30             : // becomes relevant in rescattering scenarios when FSR dipole emissions
      31             : // and primordial kT is added. Should hopefully not be needed.
      32             : const bool   BeamRemnants::CORRECTMISMATCH  = false;
      33             : 
      34             : //--------------------------------------------------------------------------
      35             : 
      36             : // Initialization.
      37             : 
      38             : bool BeamRemnants::init( Info* infoPtrIn, Settings& settings, Rndm* rndmPtrIn,
      39             :   BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn,
      40             :   PartonSystems* partonSystemsPtrIn, ParticleData* particleDataPtrIn,
      41             :   ColourReconnection* colourReconnectionPtrIn) {
      42             : 
      43             :   // Save pointers.
      44           0 :   infoPtr               = infoPtrIn;
      45           0 :   rndmPtr               = rndmPtrIn;
      46           0 :   beamAPtr              = beamAPtrIn;
      47           0 :   beamBPtr              = beamBPtrIn;
      48           0 :   partonSystemsPtr      = partonSystemsPtrIn;
      49           0 :   colourReconnectionPtr = colourReconnectionPtrIn;
      50             : 
      51             :   // Width of primordial kT distribution.
      52           0 :   doPrimordialKT      = settings.flag("BeamRemnants:primordialKT");
      53           0 :   primordialKTsoft    = settings.parm("BeamRemnants:primordialKTsoft");
      54           0 :   primordialKThard    = settings.parm("BeamRemnants:primordialKThard");
      55           0 :   primordialKTremnant = settings.parm("BeamRemnants:primordialKTremnant");
      56           0 :   halfScaleForKT      = settings.parm("BeamRemnants:halfScaleForKT");
      57           0 :   halfMassForKT       = settings.parm("BeamRemnants:halfMassForKT");
      58           0 :   reducedKTatHighY    = settings.parm("BeamRemnants:reducedKTatHighY");
      59             : 
      60             :   // Handling of rescattering kinematics uncertainties from primodial kT.
      61           0 :   allowRescatter     = settings.flag("MultipartonInteractions:allowRescatter");
      62           0 :   doRescatterRestoreY = settings.flag("BeamRemnants:rescatterRestoreY");
      63             : 
      64             :   // Choice of beam remnant and colour reconnection scenarios.
      65           0 :   remnantMode         = settings.mode("BeamRemnants:remnantMode");
      66           0 :   doReconnect         = settings.flag("ColourReconnection:reconnect");
      67           0 :   reconnectMode       = settings.mode("ColourReconnection:mode");
      68             : 
      69             :   // Check that remnant model and colour reconnection model work together.
      70           0 :   if (remnantMode == 1 && reconnectMode == 0) {
      71           0 :     infoPtr->errorMsg("Abort from BeamRemnants::init: The remnant model"
      72             :       " and colour reconnection model does not work together");
      73           0 :     return false;
      74             :   }
      75             : 
      76             :   // Total and squared CM energy at nominal energy.
      77           0 :   eCM                 = infoPtr->eCM();
      78           0 :   sCM                 = eCM * eCM;
      79             : 
      80             :   // Initialize junction splitting class.
      81           0 :   junctionSplitting.init(infoPtr, settings, rndmPtr, particleDataPtrIn);
      82             : 
      83             :   // Done.
      84           0 :   return true;
      85             : 
      86           0 : }
      87             : 
      88             : //--------------------------------------------------------------------------
      89             : 
      90             : // Select the flavours/kinematics/colours of the two beam remnants.
      91             : // Notation: iPar = all partons, iSys = matched systems of two beams,
      92             : //           iRem = additional partons in remnants.
      93             : 
      94             : bool BeamRemnants::add( Event& event, int iFirst, bool doDiffCR) {
      95             : 
      96             :   // Update to current CM energy.
      97           0 :   eCM     = infoPtr->eCM();
      98           0 :   sCM     = eCM * eCM;
      99             : 
     100             :   // Check that flavour bookkept in event and in beam particles agree.
     101           0 :   for (int i = 0; i < beamAPtr->size(); ++i) {
     102           0 :     int j = (*beamAPtr)[i].iPos();
     103           0 :     if ((*beamAPtr)[i].id() != event[j].id()) {
     104           0 :       infoPtr->errorMsg("Error in BeamRemnants::add: "
     105             :         "event and beam flavours do not match");
     106           0 :       return false;
     107             :     }
     108           0 :   }
     109           0 :   for (int i = 0; i < beamBPtr->size(); ++i) {
     110           0 :     int j =  (*beamBPtr)[i].iPos();
     111           0 :     if ((*beamBPtr)[i].id() != event[j].id()) {
     112           0 :       infoPtr->errorMsg("Error in BeamRemnants::add: "
     113             :         "event and beam flavours do not match");
     114           0 :       return false;
     115             :     }
     116           0 :   }
     117             : 
     118             :   // Deeply inelastic scattering needs special remnant handling.
     119           0 :   isDIS = (beamAPtr->isLepton() && !beamBPtr->isLepton())
     120           0 :        || (beamBPtr->isLepton() && !beamAPtr->isLepton());
     121             : 
     122             :   // Number of scattering subsystems. Size of event record before treatment.
     123           0 :   nSys    = partonSystemsPtr->sizeSys();
     124           0 :   oldSize = event.size();
     125             : 
     126             :   // Store event as it was before adding anything.
     127           0 :   Event eventSave = event;
     128           0 :   BeamParticle beamAsave = (*beamAPtr);
     129           0 :   BeamParticle beamBsave = (*beamBPtr);
     130           0 :   PartonSystems partonSystemsSave = (*partonSystemsPtr);
     131             : 
     132             :   // Two different methods to add the beam remnants.
     133           0 :   if (remnantMode == 0) {
     134           0 :     if (!addOld(event)) return false;
     135             :   } else
     136           0 :     if (!addNew(event)) return false;
     137             : 
     138           0 :   if (isDIS) return true;
     139             : 
     140             :   // Store event before doing colour reconnections.
     141           0 :   Event eventTmpSave = event;
     142             :   bool colCorrect = false;
     143           0 :   for (int i = 0; i < 10; ++i) {
     144           0 :     if (doReconnect && doDiffCR
     145           0 :     && (reconnectMode == 1 || reconnectMode == 2)) {
     146           0 :       colourReconnectionPtr->next(event, iFirst);
     147             : 
     148             :       // Check that the new colour structure is physical.
     149           0 :       if (!junctionSplitting.checkColours(event))
     150           0 :         event = eventTmpSave;
     151             :       else {
     152             :         colCorrect = true;
     153           0 :         break;
     154             :       }
     155             :       // If no colour reconnection, just check the colour configuration once.
     156             :     } else {
     157           0 :       if (junctionSplitting.checkColours(event))
     158           0 :         colCorrect = true;
     159           0 :       break;
     160             :     }
     161             :   }
     162             : 
     163             :   // Restore event and return false if colour reconnection failed.
     164           0 :   if (!colCorrect) {
     165           0 :     event = eventSave;
     166           0 :     (*beamAPtr) = beamAsave;
     167           0 :     (*beamBPtr) = beamBsave;
     168           0 :     (*partonSystemsPtr) = partonSystemsSave;
     169           0 :     infoPtr->errorMsg("Error in BeamRemnants::Add: "
     170             :       "failed to find physical colour state after colour reconnection");
     171           0 :     return false;
     172             :   }
     173             : 
     174             :   // Done.
     175           0 :   return true;
     176           0 : }
     177             : 
     178             : //--------------------------------------------------------------------------
     179             : 
     180             : // Old function for adding beam remnant.
     181             : 
     182             : bool BeamRemnants::addOld( Event& event) {
     183             : 
     184             :   // Add required extra remnant flavour content.
     185             :   // Start all over if fails (in option where junctions not allowed).
     186           0 :   if ( !beamAPtr->remnantFlavours(event, isDIS)
     187           0 :     || !beamBPtr->remnantFlavours(event, isDIS) ) {
     188           0 :     infoPtr->errorMsg("Error in BeamRemnants::add:"
     189             :       " remnant flavour setup failed");
     190           0 :     return false;
     191             :   }
     192             : 
     193             :   // Do the kinematics of the collision subsystems and two beam remnants.
     194           0 :   if (!setKinematics(event)) return false;
     195             : 
     196             :   // Allow colour reconnections.
     197           0 :   if (doReconnect && reconnectMode == 0 && !isDIS)
     198           0 :     colourReconnectionPtr->next(event, oldSize);
     199             : 
     200             :   // Save current modifiable colour configuration for fast restoration.
     201           0 :   vector<int> colSave;
     202           0 :   vector<int> acolSave;
     203           0 :   for (int i = oldSize; i < event.size(); ++i) {
     204           0 :     colSave.push_back( event[i].col() );
     205           0 :     acolSave.push_back( event[i].acol() );
     206             :   }
     207           0 :   event.saveJunctionSize();
     208             : 
     209             :   // Allow several tries to match colours of initiators and remnants.
     210             :   // Frequent "failures" since shortcutting colours separately on
     211             :   // the two event sides may give "colour singlet gluons" etc.
     212             :   bool physical = true;
     213           0 :   for (int iTry = 0; iTry < NTRYCOLMATCH; ++iTry) {
     214             :     physical = true;
     215             : 
     216             :     // Reset list of colour "collapses" (transformations).
     217           0 :     colFrom.resize(0);
     218           0 :     colTo.resize(0);
     219             : 
     220             :     // First process each set of beam colours on its own.
     221           0 :     if (!beamAPtr->remnantColours(event, colFrom, colTo))
     222           0 :       physical = false;
     223           0 :     if (!beamBPtr->remnantColours(event, colFrom, colTo))
     224           0 :       physical = false;
     225             : 
     226             :     // Then check that colours and anticolours are matched in whole event.
     227           0 :     if ( physical && !checkColours(event) ) physical = false;
     228             : 
     229             :     // If no problems then done, else restore and loop.
     230           0 :     if (physical) break;
     231           0 :     for (int i = oldSize; i < event.size(); ++i)
     232           0 :       event[i].cols( colSave[i - oldSize], acolSave[i - oldSize] );
     233           0 :     event.restoreJunctionSize();
     234           0 :     infoPtr->errorMsg("Warning in BeamRemnants::add:"
     235             :       " colour tracing failed; will try again");
     236             :   }
     237             : 
     238             :   // If no solution after several tries then failed.
     239           0 :   if (!physical) {
     240           0 :     infoPtr->errorMsg("Error in BeamRemnants::add:"
     241             :       " colour tracing failed after several attempts");
     242           0 :     return false;
     243             :   }
     244             : 
     245             :   // Done.
     246           0 :   return true;
     247           0 : }
     248             : 
     249             : //--------------------------------------------------------------------------
     250             : 
     251             : // New function for adding beam remnant.
     252             : 
     253             : bool BeamRemnants::addNew( Event& event) {
     254             : 
     255             :    // Start by saving a copy of the event, if the beam remnant fails.
     256           0 :   Event eventSave = event;
     257           0 :   BeamParticle beamAsave = (*beamAPtr);
     258           0 :   BeamParticle beamBsave = (*beamBPtr);
     259           0 :   PartonSystems partonSystemsSave = (*partonSystemsPtr);
     260             : 
     261             :   // Do several tries in case an unphysical colour contruction is made.
     262             :   bool beamRemnantFound = false;
     263             :   int nMaxTries = 10;
     264             : 
     265           0 :   for (int iTries = 0;iTries < nMaxTries; ++iTries) {
     266             : 
     267             :     // Set the initial colours.
     268           0 :     beamAPtr->setInitialCol(event);
     269           0 :     beamBPtr->setInitialCol(event);
     270             : 
     271             :     // Find colour state of outgoing partons and reconnect colours to match it.
     272           0 :     beamAPtr->findColSetup(event);
     273           0 :     beamBPtr->updateCol(beamAPtr->getColUpdates());
     274             : 
     275           0 :     beamBPtr->findColSetup(event);
     276           0 :     beamAPtr->updateCol(beamBPtr->getColUpdates());
     277             : 
     278             :     // Add beam remnants.
     279           0 :     beamAPtr->remnantFlavoursNew(event);
     280           0 :     beamBPtr->remnantFlavoursNew(event);
     281             : 
     282             :     // It is possible junctions were added, so update list.
     283           0 :     event.saveJunctionSize();
     284             : 
     285             :     // Do the kinematics of the collision subsystems and two beam remnants.
     286           0 :     if (!setKinematics(event)) {
     287             :       // If it does not work, try parton level again.
     288           0 :       event = eventSave;
     289           0 :       (*beamAPtr) = beamAsave;
     290           0 :       (*beamBPtr) = beamBsave;
     291           0 :       (*partonSystemsPtr) = partonSystemsSave;
     292           0 :       return false;
     293             :     }
     294             : 
     295             :     // Update the colour changes for all final state particles.
     296           0 :     updateColEvent(event, beamAPtr->getColUpdates());
     297           0 :     updateColEvent(event, beamBPtr->getColUpdates());
     298             : 
     299             :     // Check whether the new colour structure can be accepted.
     300           0 :     if (junctionSplitting.checkColours(event)) {
     301             :       beamRemnantFound = true;
     302           0 :       break;
     303             :     }
     304             : 
     305             :     // If failed, restore earlier configuration and try to find new
     306             :     // colour structure.
     307             :     else {
     308           0 :       event = eventSave;
     309           0 :       (*beamAPtr) = beamAsave;
     310           0 :       (*beamBPtr) = beamBsave;
     311           0 :       (*partonSystemsPtr) = partonSystemsSave;
     312             :     }
     313             :   }
     314             : 
     315             :   // Return if it was not possible to find physical colour structure.
     316           0 :   if (!beamRemnantFound) {
     317           0 :     infoPtr->errorMsg("Error in BeamRemnants::add: "
     318             :         "failed to find physical colour structure");
     319             :     // Restore event to previous state.
     320           0 :     event = eventSave;
     321           0 :     (*beamAPtr) = beamAsave;
     322           0 :     (*beamBPtr) = beamBsave;
     323           0 :     (*partonSystemsPtr) = partonSystemsSave;
     324           0 :     return false;
     325             :   }
     326             : 
     327             :   // Done.
     328           0 :   return true;
     329           0 : }
     330             : 
     331             : //--------------------------------------------------------------------------
     332             : 
     333             : // Set up trial transverse and longitudinal kinematics for each beam
     334             : // separately. Final decisions involve comparing the two beams.
     335             : 
     336             : bool BeamRemnants::setKinematics( Event& event) {
     337             : 
     338             :   // References to beams to simplify indexing.
     339           0 :   BeamParticle& beamA = *beamAPtr;
     340           0 :   BeamParticle& beamB = *beamBPtr;
     341             : 
     342             :   // Nothing to do for lepton-lepton scattering with all energy already used.
     343           0 :   if ( beamA.isUnresolvedLepton() && beamB.isUnresolvedLepton() )
     344           0 :     return true;
     345             : 
     346             :   // Check that has not already used up beams.
     347           0 :   if ( (!beamA.isLepton() && beamA.xMax(-1) <= 0.)
     348           0 :     || (!beamB.isLepton() && beamB.xMax(-1) <= 0.) ) {
     349           0 :     infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
     350             :       " no momentum left for beam remnants");
     351           0 :     return false;
     352             :   }
     353             : 
     354             :   // Special kinematics setup for DIS.
     355           0 :   if (isDIS) return setDISKinematics(event);
     356             : 
     357             :   // Last beam-status particles. Offset relative to normal beam locations.
     358             :   int nBeams   = 3;
     359           0 :   for (int i = 3; i < event.size(); ++i)
     360           0 :     if (event[i].statusAbs() < 20) nBeams = i + 1;
     361           0 :   int nOffset  = nBeams - 3;
     362             : 
     363             :   // Reserve space for extra information on the systems and beams.
     364           0 :   int nMaxBeam = max( beamA.size(), beamB.size() );
     365           0 :   vector<double> sHatSys(nMaxBeam);
     366           0 :   vector<double> kTwidth(nMaxBeam);
     367           0 :   vector<double> kTcomp(nMaxBeam);
     368           0 :   vector<RotBstMatrix> Msys(nSys);
     369             : 
     370             :   // Loop over all subsystems. Default values. Find invariant mass.
     371             :   double kTcompSumA   = 0.;
     372             :   double kTcompSumB   = 0.;
     373           0 :   for (int iSys = 0; iSys < nSys; ++iSys) {
     374             :     double kTwidthNow = 0.;
     375             :     double mHatDamp   = 1.;
     376           0 :     int iInA          = partonSystemsPtr->getInA(iSys);
     377           0 :     int iInB          = partonSystemsPtr->getInB(iSys);
     378           0 :     double sHatNow    = (event[iInA].p() + event[iInB].p()).m2Calc();
     379             : 
     380             :     // Allow primordial kT reduction for small-mass and small-pT systems
     381             :     // (for hardest interaction pT -> renormalization scale so also 2 -> 1).
     382           0 :     if (doPrimordialKT) {
     383           0 :       double mHat     = sqrt(sHatNow);
     384           0 :       double yDamp    = pow( (event[iInA].e() + event[iInB].e()) / mHat,
     385           0 :                         reducedKTatHighY );
     386           0 :       mHatDamp        = mHat / (mHat + halfMassForKT * yDamp);
     387           0 :       double scale    = (iSys == 0) ? infoPtr->QRen(iDS)
     388           0 :                       : partonSystemsPtr->getPTHat(iSys);
     389           0 :       kTwidthNow      = ( (halfScaleForKT * primordialKTsoft
     390           0 :       + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
     391           0 :     }
     392             : 
     393             :     // Store properties of compensation systems and total compensation power.
     394             :     // Rescattered partons do not compensate, but may be massive.
     395           0 :     sHatSys[iSys] = sHatNow;
     396           0 :     kTwidth[iSys] = kTwidthNow ;
     397           0 :     kTcomp[iSys]  = mHatDamp;
     398           0 :     if (beamA[iSys].isFromBeam()) kTcompSumA += mHatDamp;
     399           0 :     else beamA[iSys].m( event[iInA].m() );
     400           0 :     if (beamB[iSys].isFromBeam()) kTcompSumB += mHatDamp;
     401           0 :     else beamB[iSys].m( event[iInB].m() );
     402             :   }
     403             : 
     404             :   // Primordial kT and compensation power among remnants.
     405           0 :   double kTwidthNow = (doPrimordialKT) ? primordialKTremnant : 0.;
     406           0 :   for (int iRem = nSys; iRem < nMaxBeam; ++iRem) {
     407           0 :     sHatSys[iRem] = 0.;
     408           0 :     kTwidth[iRem] = kTwidthNow ;
     409           0 :     kTcomp[iRem]  = 1.;
     410             :   }
     411           0 :   kTcompSumA += beamA.size() - nSys;
     412           0 :   kTcompSumB += beamB.size() - nSys;
     413             : 
     414             :   // Allow ten tries to construct kinematics (but normally works first).
     415             :   bool physical;
     416           0 :   double xSum[2], xInvM[2], w2Beam[2], wPosRem, wNegRem, w2Rem;
     417           0 :   for (int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
     418             :     physical = true;
     419             : 
     420             :     // Loop over the two beams.
     421           0 :     for (int iBeam = 0; iBeam < 2; ++iBeam) {
     422           0 :       BeamParticle& beam = (iBeam == 0) ? beamA : beamB;
     423           0 :       int nPar = beam.size();
     424             : 
     425             :       // Generate Gaussian pT for initiator partons inside hadrons.
     426             :       // Store/restore rescattered parton momenta before primordial kT.
     427           0 :       if (beam.isHadron() && doPrimordialKT) {
     428             :         double pxSum = 0.;
     429             :         double pySum = 0.;
     430           0 :         for (int iPar = 0; iPar < nPar; ++iPar) {
     431           0 :           if ( beam[iPar].isFromBeam() ) {
     432           0 :             pair<double, double> gauss2 = rndmPtr->gauss2();
     433           0 :             double px = kTwidth[iPar] * gauss2.first;
     434           0 :             double py = kTwidth[iPar] * gauss2.second;
     435           0 :             beam[iPar].px(px);
     436           0 :             beam[iPar].py(py);
     437           0 :             pxSum += px;
     438           0 :             pySum += py;
     439           0 :           } else {
     440           0 :             int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
     441           0 :                                      : partonSystemsPtr->getInB(iPar);
     442           0 :             beam[iPar].p( event[iInAB].p() );
     443             :           }
     444             :         }
     445             : 
     446             :         // Share recoil between all initiator partons, rescatterers excluded.
     447           0 :         double kTcompSum = (iBeam == 0) ? kTcompSumA : kTcompSumB;
     448           0 :         for (int iPar = 0; iPar < nPar; ++iPar)
     449           0 :         if (beam[iPar].isFromBeam() ) {
     450           0 :           beam[iPar].px( beam[iPar].px() - pxSum * kTcomp[iPar] / kTcompSum );
     451           0 :           beam[iPar].py( beam[iPar].py() - pySum * kTcomp[iPar] / kTcompSum );
     452             :         }
     453             : 
     454             :       // Without primordial kT: still need to store rescattered partons.
     455           0 :       } else if (beam.isHadron()) {
     456           0 :         for (int iPar = 0; iPar < nPar; ++iPar)
     457           0 :         if ( !beam[iPar].isFromBeam() ) {
     458           0 :           int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
     459           0 :                                    : partonSystemsPtr->getInB(iPar);
     460           0 :           beam[iPar].p( event[iInAB].p() );
     461           0 :         }
     462           0 :       }
     463             : 
     464             :       // Pick unrescaled x values for remnants. Sum up (unscaled) p+ and p-.
     465           0 :       xSum[iBeam]  = 0.;
     466           0 :       xInvM[iBeam] = 0.;
     467           0 :       for (int iRem = nSys; iRem < nPar; ++iRem) {
     468           0 :         double xPrel = beam.xRemnant( iRem);
     469           0 :         beam[iRem].x(xPrel);
     470           0 :         xSum[iBeam]  += xPrel;
     471           0 :         xInvM[iBeam] += beam[iRem].mT2()/xPrel;
     472             :       }
     473             : 
     474             :       // Squared transverse mass for each beam, using lightcone x.
     475           0 :       w2Beam[iBeam] = xSum[iBeam] * xInvM[iBeam];
     476             : 
     477             :     // End separate treatment of the two beams.
     478             :     }
     479             : 
     480             :     // Recalculate kinematics of initiator systems with primordial kT.
     481           0 :     wPosRem = eCM;
     482             :     wNegRem = eCM;
     483           0 :     for (int iSys = 0; iSys < nSys; ++iSys) {
     484           0 :       int iA          = beamA[iSys].iPos();
     485           0 :       int iB          = beamB[iSys].iPos();
     486           0 :       double sHat     = sHatSys[iSys];
     487             : 
     488             :       // Classify system: rescattering on either or both sides?
     489           0 :       bool normalA    = beamA[iSys].isFromBeam();
     490           0 :       bool normalB    = beamB[iSys].isFromBeam();
     491           0 :       bool normalSys  = normalA && normalB;
     492           0 :       bool doubleRes  = !normalA && !normalB;
     493             : 
     494             :       // Check whether final-state system momentum matches initial-state one.
     495           0 :       if (allowRescatter && CORRECTMISMATCH) {
     496             :         Vec4 pInitial = event[iA].p() + event[iB].p();
     497             :         Vec4 pFinal;
     498             :         for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
     499             :           int iAB      = partonSystemsPtr->getOut(iSys, iMem);
     500             :           if (event[iAB].isFinal()) pFinal += event[iAB].p();
     501             :         }
     502             : 
     503             :         // Scale down primordial kT from side A if p+ increased.
     504             :         if (normalA && pFinal.pPos() > pInitial.pPos())
     505             :           beamA[iSys].scalePT( pInitial.pPos() / pFinal.pPos() );
     506             : 
     507             :         // Scale down primordial kT from side B if p- increased.
     508             :         if (normalB && pFinal.pNeg() > pInitial.pNeg())
     509             :           beamB[iSys].scalePT( pInitial.pNeg() / pFinal.pNeg() );
     510             :       }
     511             : 
     512             :       // Rescatter: possible change in sign of lightcone momentum of a
     513             :       //            rescattered parton. If this happens, try to pick
     514             :       //            new primordial kT values
     515           0 :       if (allowRescatter
     516           0 :          && (event[iA].pPos() / beamA[iSys].pPos() < 0
     517           0 :          ||  event[iB].pNeg() / beamB[iSys].pNeg() < 0) ) {
     518           0 :         infoPtr->errorMsg("Warning in BeamRemnants::setKinematics:"
     519             :           " change in lightcone momentum sign; retrying kinematics");
     520             :         physical = false;
     521           0 :         break;
     522             :       }
     523             : 
     524             :       // Begin kinematics of partons after primordial kT has been added.
     525           0 :       double sHatTAft = sHat + pow2( beamA[iSys].px() + beamB[iSys].px())
     526           0 :                              + pow2( beamA[iSys].py() + beamB[iSys].py());
     527           0 :       double w2A      = beamA[iSys].mT2();
     528           0 :       double w2B      = beamB[iSys].mT2();
     529           0 :       double w2Diff   = sHatTAft - w2A - w2B;
     530           0 :       double lambda   = pow2(w2Diff) - 4. * w2A * w2B;
     531             : 
     532             :       // Too large transverse momenta means that kinematics will not work.
     533           0 :       if (lambda <= 0.) {
     534             :         physical      = false;
     535           0 :         break;
     536             :       }
     537           0 :       double lamRoot  = sqrtpos( lambda );
     538             : 
     539             :       // Mirror solution if the two incoming have reverse rapidity ordering.
     540           0 :       if (allowRescatter && doubleRes && (event[iA].pPos() * event[iB].pNeg()
     541           0 :         < event[iA].pNeg() * event[iB].pPos()) ) lamRoot = -lamRoot;
     542             : 
     543             :       // Two procedures, which agree for normal scattering, separate here.
     544             :       // First option keeps rapidity (and mass) of system unchanged by
     545             :       // primordial kT, by modification of rescattered parton.
     546           0 :       if (normalSys || doRescatterRestoreY || doubleRes) {
     547             : 
     548             :         // Find kinematics of initial system: transverse mass, and
     549             :         // longitudinal momentum carried by all or rescattered partons.
     550             :         double sHatTBef = sHat;
     551             :         double wPosBef, wNegBef, wPosBefRes, wNegBefRes;
     552             :         // Normal scattering.
     553           0 :         if (normalSys) {
     554           0 :           wPosBef       = beamA[iSys].x() * eCM;
     555           0 :           wNegBef       = beamB[iSys].x() * eCM;
     556             :           wPosBefRes    = 0.;
     557             :           wNegBefRes    = 0.;
     558             :         // Rescattering on side A.
     559           0 :         } else if (normalB) {
     560           0 :           sHatTBef     += event[iA].pT2();
     561           0 :           wPosBef       = event[iA].pPos();
     562           0 :           wNegBef       = event[iA].pNeg() + beamB[iSys].x() * eCM;
     563           0 :           wPosBefRes    = beamA[iSys].pPos();
     564           0 :           wNegBefRes    = beamA[iSys].pNeg();
     565             :         // Rescattering on side B.
     566           0 :         } else if (normalA) {
     567           0 :           sHatTBef     += event[iB].pT2();
     568           0 :           wPosBef       = beamA[iSys].x() * eCM + event[iB].pPos();
     569           0 :           wNegBef       = event[iB].pNeg();
     570           0 :           wPosBefRes    = beamB[iSys].pPos();
     571           0 :           wNegBefRes    = beamB[iSys].pNeg();
     572             :         // Rescattering on both sides.
     573           0 :         } else {
     574           0 :           sHatTBef     += pow2( event[iA].px() + event[iB].px())
     575           0 :                         + pow2( event[iA].py() + event[iB].py());
     576           0 :           wPosBef       = event[iA].pPos() + event[iB].pPos();
     577           0 :           wNegBef       = event[iA].pNeg() + event[iB].pNeg();
     578           0 :           wPosBefRes    = beamA[iSys].pPos() + beamB[iSys].pPos();
     579           0 :           wNegBefRes    = beamA[iSys].pNeg() + beamB[iSys].pNeg();
     580             :         }
     581             : 
     582             :         // Rescale outgoing momenta to keep same mass and rapidity of system
     583             :         // as originally, and solve for kinematics.
     584           0 :         double rescale  = sqrt(sHatTAft / sHatTBef);
     585           0 :         double wPosAft  = rescale * wPosBef;
     586           0 :         double wNegAft  = rescale * wNegBef;
     587           0 :         wPosRem        -= wPosAft - wPosBefRes;
     588           0 :         wNegRem        -= wNegAft - wNegBefRes;
     589           0 :         double wPosA    = 0.5 * (sHatTAft + w2A - w2B + lamRoot) / wNegAft;
     590           0 :         double wNegB    = 0.5 * (sHatTAft + w2B - w2A + lamRoot) / wPosAft;
     591             : 
     592             :         // Store modified beam parton momenta.
     593           0 :         beamA[iSys].e(  0.5 * (wPosA + w2A / wPosA) );
     594           0 :         beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
     595           0 :         beamB[iSys].e(  0.5 * (w2B / wNegB + wNegB) );
     596           0 :         beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
     597             : 
     598             :       // Second option keeps rescattered parton (and system mass) unchanged
     599             :       // by primordial kT, by modification of system rapidity.
     600           0 :       } else {
     601             : 
     602             :         // Rescattering on side A: preserve already scattered parton.
     603           0 :         if (normalB) {
     604           0 :           double wPosA  = beamA[iSys].pPos();
     605           0 :           double wNegB  = 0.5 * (w2Diff + lamRoot) / wPosA;
     606           0 :           beamB[iSys].e(  0.5 * (w2B / wNegB + wNegB) );
     607           0 :           beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
     608           0 :           wPosRem      -= w2B / wNegB;
     609           0 :           wNegRem      -= wNegB;
     610             : 
     611             : 
     612             :         // Rescattering on side B: preserve already scattered parton.
     613           0 :         } else if (normalA) {
     614           0 :           double wNegB  = beamB[iSys].pNeg();
     615           0 :           double wPosA  = 0.5 * (w2Diff + lamRoot) / wNegB;
     616           0 :           beamA[iSys].e(  0.5 * (wPosA + w2A / wPosA) );
     617           0 :           beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
     618           0 :           wPosRem      -= wPosA;
     619           0 :           wNegRem      -= w2A / wPosA;
     620             : 
     621             :         // Primordial kT in double rescattering does change the mass of
     622             :         // the system without any possible fix in this framework, which
     623             :         // leads to incorrect boosts. Current choice is therefore always
     624             :         // to handle it with the first procedure, where mass is retained.
     625           0 :         } else {
     626             :         }
     627             :       }
     628             : 
     629             :       // Construct system rotation and boost caused by primordial kT.
     630           0 :       Msys[iSys].reset();
     631           0 :       Msys[iSys].toCMframe( event[iA].p(), event[iB].p() );
     632           0 :       Msys[iSys].fromCMframe( beamA[iSys].p(), beamB[iSys].p() );
     633             : 
     634             :       // Boost rescattered partons in subsequent beam A list.
     635           0 :       for (int iSys2 = iSys + 1; iSys2 < nSys; ++iSys2) {
     636           0 :         if (!beamA[iSys2].isFromBeam()) {
     637           0 :           int iBefResc = event[ beamA[iSys2].iPos() ].mother1();
     638           0 :           for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
     639           0 :           if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
     640           0 :             Vec4 pTemp = event[iBefResc].p();
     641           0 :             pTemp.rotbst( Msys[iSys] );
     642           0 :             beamA[iSys2].p( pTemp );
     643           0 :           }
     644           0 :         }
     645             : 
     646             :         // Boost rescattered partons in subsequent beam B list.
     647           0 :         if (!beamB[iSys2].isFromBeam()) {
     648           0 :           int iBefResc = event[ beamB[iSys2].iPos() ].mother1();
     649           0 :           for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
     650           0 :           if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
     651           0 :             Vec4 pTemp = event[iBefResc].p();
     652           0 :             pTemp.rotbst( Msys[iSys] );
     653           0 :             beamB[iSys2].p( pTemp );
     654           0 :           }
     655           0 :         }
     656             :       }
     657           0 :     }
     658             : 
     659             :     // Check that remaining momentum is enough for remnants.
     660           0 :     if (wPosRem < 0. || wNegRem < 0.) physical = false;
     661           0 :     w2Rem = wPosRem * wNegRem;
     662           0 :     if (sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1]))
     663           0 :       physical = false;
     664             : 
     665             :     // End of loop over ten tries. Do not loop when solution found.
     666           0 :     if (physical) break;
     667             :   }
     668             : 
     669             :   // If no solution after ten tries then failed.
     670           0 :   if (!physical) {
     671           0 :     infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
     672             :       " kinematics construction failed");
     673           0 :     return false;
     674             :   }
     675             : 
     676             :   // For successful initiator kinematics process whole systems.
     677           0 :   Vec4 pSumOut;
     678           0 :   for (int iSys = 0; iSys < nSys; ++iSys) {
     679             : 
     680             :     // Copy initiators and their systems and boost them accordingly.
     681             :     // Update subsystem and beams info on new positions of partons.
     682             :     // Update daughter info of mothers, i.e. of beams, for hardest interaction.
     683           0 :     if (beamA[iSys].isFromBeam()) {
     684           0 :       int iA       = beamA[iSys].iPos();
     685           0 :       int iAcopy   = event.copy(iA, -61);
     686           0 :       event[iAcopy].rotbst(Msys[iSys]);
     687           0 :       partonSystemsPtr->setInA(iSys, iAcopy);
     688           0 :       beamA[iSys].iPos( iAcopy);
     689           0 :       if (iSys == 0) {
     690           0 :         int mother = event[iAcopy].mother1();
     691           0 :         event[mother].daughter1(iAcopy);
     692           0 :       }
     693           0 :     }
     694           0 :     if (beamB[iSys].isFromBeam()) {
     695           0 :       int iB       = beamB[iSys].iPos();
     696           0 :       int iBcopy   = event.copy(iB, -61);
     697           0 :       event[iBcopy].rotbst(Msys[iSys]);
     698           0 :       partonSystemsPtr->setInB(iSys, iBcopy);
     699           0 :       beamB[iSys].iPos( iBcopy);
     700           0 :       if (iSys == 0) {
     701           0 :         int mother = event[iBcopy].mother1();
     702           0 :         event[mother].daughter1(iBcopy);
     703           0 :       }
     704           0 :     }
     705             : 
     706           0 :     for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
     707           0 :       int iAB      = partonSystemsPtr->getOut(iSys, iMem);
     708           0 :       if (event[iAB].isFinal()) {
     709           0 :         int iABcopy = event.copy(iAB, 62);
     710           0 :         event[iABcopy].rotbst(Msys[iSys]);
     711           0 :         partonSystemsPtr->setOut(iSys, iMem, iABcopy);
     712           0 :         pSumOut   += event[iABcopy].p();
     713           0 :       }
     714             :     }
     715             : 
     716             :   }
     717             : 
     718             :   // Colour dipoles spanning systems gives mismatch between FSR recoils
     719             :   // and primordial kT boosts.
     720           0 :   if (allowRescatter && CORRECTMISMATCH) {
     721             : 
     722             :     // Find summed pT of beam remnants = - wanted pT of systems.
     723             :     double pxBeams = 0.;
     724             :     double pyBeams = 0.;
     725             :     for (int iRem = nSys; iRem < beamA.size(); ++iRem) {
     726             :       pxBeams     += beamA[iRem].px();
     727             :       pyBeams     += beamA[iRem].py();
     728             :     }
     729             :     for (int iRem = nSys; iRem < beamB.size(); ++iRem) {
     730             :       pxBeams     += beamB[iRem].px();
     731             :       pyBeams     += beamB[iRem].py();
     732             :     }
     733             : 
     734             :     // Boost all final partons in systems transversely, and also their sum.
     735             :     Vec4 pSumTo( -pxBeams, -pyBeams, pSumOut.pz(), sqrt( pow2(pxBeams)
     736             :       + pow2(pyBeams) + pow2(pSumOut.pz()) + pSumOut.m2Calc() ) );
     737             :     RotBstMatrix Mmismatch;
     738             :     Mmismatch.bst( pSumOut, pSumTo);
     739             :     for (int iSys = 0; iSys < nSys; ++iSys)
     740             :     for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
     741             :       int iAB = partonSystemsPtr->getOut(iSys, iMem);
     742             :       if (event[iAB].isFinal()) event[iAB].rotbst(Mmismatch);
     743             :     }
     744             :     pSumOut.rotbst(Mmismatch);
     745             : 
     746             :    // Reset energy and momentum sum, to be compensated by beam remnants.
     747             :     wPosRem = eCM - (pSumOut.e() + pSumOut.pz());
     748             :     wNegRem = eCM - (pSumOut.e() - pSumOut.pz());
     749             :     w2Rem    = wPosRem * wNegRem;
     750             :     if ( wPosRem < 0. || wNegRem < 0.
     751             :       || sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1])) {
     752             :       infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
     753             :         " kinematics construction failed owing to recoil mismatch");
     754             :       return false;
     755             :     }
     756             :   }
     757             : 
     758             :   // Construct x rescaling factors for the two remants.
     759           0 :   double lambdaRoot = sqrtpos( pow2(w2Rem - w2Beam[0] - w2Beam[1])
     760           0 :     - 4. * w2Beam[0] * w2Beam[1] );
     761           0 :   double rescaleA   = (w2Rem + w2Beam[0] - w2Beam[1] + lambdaRoot)
     762           0 :     / (2. * w2Rem * xSum[0]) ;
     763           0 :   double rescaleB   = (w2Rem + w2Beam[1] - w2Beam[0] + lambdaRoot)
     764           0 :     / (2. * w2Rem * xSum[1]) ;
     765             : 
     766             :   // Construct energy and pz for remnants in first beam.
     767           0 :   for (int iRem = nSys; iRem < beamA.size(); ++iRem) {
     768           0 :     double pPos = rescaleA * beamA[iRem].x() * wPosRem;
     769           0 :     double pNeg = beamA[iRem].mT2() / pPos;
     770           0 :     beamA[iRem].e( 0.5 * (pPos + pNeg) );
     771           0 :     beamA[iRem].pz( 0.5 * (pPos - pNeg) );
     772             : 
     773             :     // Add these partons to the normal event record.
     774           0 :     int iNew = event.append( beamA[iRem].id(), 63, 1 + nOffset, 0, 0, 0,
     775           0 :       beamA[iRem].col(), beamA[iRem].acol(), beamA[iRem].p(),
     776           0 :       beamA[iRem].m() );
     777           0 :     beamA[iRem].iPos( iNew);
     778             :   }
     779             : 
     780             :   // Construct energy and pz for remnants in second beam.
     781           0 :   for (int iRem = nSys; iRem < beamB.size(); ++iRem) {
     782           0 :     double pNeg = rescaleB * beamB[iRem].x() * wNegRem;
     783           0 :     double pPos = beamB[iRem].mT2() / pNeg;
     784           0 :     beamB[iRem].e( 0.5 * (pPos + pNeg) );
     785           0 :     beamB[iRem].pz( 0.5 * (pPos - pNeg) );
     786             : 
     787             :     // Add these partons to the normal event record.
     788           0 :     int iNew = event.append( beamB[iRem].id(), 63, 2 + nOffset, 0, 0, 0,
     789           0 :       beamB[iRem].col(), beamB[iRem].acol(), beamB[iRem].p(),
     790           0 :       beamB[iRem].m() );
     791           0 :     beamB[iRem].iPos( iNew);
     792             :   }
     793             : 
     794             :   // Done.
     795             :   return true;
     796             : 
     797           0 : }
     798             : 
     799             : //--------------------------------------------------------------------------
     800             : 
     801             : // Special beam remnant kinematics for Deeply Inelastic Scattering.
     802             : // Currently assumes unresolved lepton.
     803             : 
     804             : bool BeamRemnants::setDISKinematics( Event& event) {
     805             : 
     806             :   // Identify lepton and hadron beams.
     807           0 :   BeamParticle& beamLep = (beamAPtr->isLepton()) ? *beamAPtr : *beamBPtr;
     808           0 :   BeamParticle& beamHad = (beamBPtr->isLepton()) ? *beamAPtr : *beamBPtr;
     809           0 :   int iBeamHad = (beamBPtr->isLepton()) ? 1 : 2;
     810             : 
     811             :   // Identify scattered lepton and scattered hadronic four-momentum.
     812           0 :   int iLepScat = beamLep[0].iPos() + 2;
     813           0 :   Vec4 pHadScat;
     814           0 :   for (int i = 5; i < event.size(); ++i)
     815           0 :     if (event[i].isFinal() && i != iLepScat) pHadScat += event[i].p();
     816             : 
     817             :   // Boost to hadronic rest frame.
     818           0 :   Vec4 pLepScat = event[iLepScat].p();
     819           0 :   Vec4 pHadTot  = event[0].p() - pLepScat;
     820           0 :   Vec4 pRemnant = pHadTot - pHadScat;
     821           0 :   double w2Tot  = pHadTot.m2Calc();
     822           0 :   double w2Scat = pHadScat.m2Calc();
     823           0 :   RotBstMatrix MtoHadRest;
     824           0 :   MtoHadRest.toCMframe( pHadScat, pRemnant);
     825           0 :   event.rotbst( MtoHadRest);
     826           0 :   pHadScat.rotbst( MtoHadRest);
     827             : 
     828             :   // Allow ten tries to construct kinematics (but normally works first).
     829             :   bool isPhysical = true;
     830             :   double xSum, xInvM, w2Remn, lambda;
     831           0 :   for (int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
     832             :     isPhysical = true;
     833             : 
     834             :     // Pick unrescaled x values for remnants. Sum up (unscaled) p+ and p-.
     835             :     xSum  = 0.;
     836             :     xInvM = 0.;
     837           0 :     for (int iRem = 1; iRem < beamHad.size(); ++iRem) {
     838           0 :       double xPrel = beamHad.xRemnant( iRem);
     839           0 :       beamHad[iRem].x(xPrel);
     840           0 :       xSum  += xPrel;
     841           0 :       xInvM += beamHad[iRem].mT2() / xPrel;
     842             :     }
     843             : 
     844             :     // Squared transverse mass for remnant, may give failure.
     845           0 :     w2Remn = xSum * xInvM;
     846           0 :     lambda = pow2( w2Tot - w2Scat - w2Remn) - 4. * w2Scat * w2Remn;
     847           0 :     if (lambda < 0.) isPhysical = false;
     848           0 :     if (isPhysical) break;
     849             :   }
     850           0 :   if (!isPhysical) {
     851           0 :     infoPtr->errorMsg("Error in BeamRemnants::setDISKinematics:"
     852             :       " too big beam remnant invariant mass");
     853           0 :     return false;
     854             :   }
     855             : 
     856             :   // Boost of scattered system to compensate for remnant mass.
     857           0 :   double pzNew = 0.5 * sqrt( lambda / w2Tot);
     858           0 :   double eNewScat = 0.5 * (w2Tot + w2Scat - w2Remn) / sqrt(w2Tot);
     859           0 :   Vec4 pNewScat( 0., 0., pzNew, eNewScat);
     860           0 :   RotBstMatrix MforScat;
     861           0 :   MforScat.bst( pHadScat, pNewScat);
     862           0 :   int sizeSave = event.size();
     863           0 :   for (int i = 5; i < sizeSave; ++i)
     864           0 :   if (event[i].isFinal() && event[i].id() != beamLep[0].id()) {
     865           0 :     int iNew = event.copy( i, 62);
     866           0 :     event[iNew].rotbst( MforScat);
     867           0 :   }
     868             : 
     869             :   // Calculate kinematics of remnants and insert into event record.
     870           0 :   double eNewRemn = 0.5 * (w2Tot + w2Remn - w2Scat) / sqrt(w2Tot);
     871           0 :   double wNewRemn = eNewRemn + pzNew;
     872           0 :   for (int iRem = 1; iRem < beamHad.size(); ++iRem) {
     873           0 :     double wNegNow = wNewRemn * beamHad[iRem].x() / xSum;
     874           0 :     double wPosNow = beamHad[iRem].mT2() / wNegNow;
     875           0 :     Vec4 pNow( 0., 0., -0.5 * (wNegNow - wPosNow), 0.5 * (wPosNow + wNegNow) );
     876           0 :     int iNew = event.append( beamHad[iRem].id(), 63, iBeamHad, 0, 0, 0,
     877           0 :       beamHad[iRem].col(), beamHad[iRem].acol(), pNow, beamHad[iRem].m() );
     878           0 :     beamHad[iRem].iPos( iNew);
     879           0 :   }
     880             : 
     881             :   // Boost back event.
     882           0 :   MtoHadRest.invert();
     883           0 :   event.rotbst( MtoHadRest);
     884             : 
     885             :   // Done.
     886             :   return true;
     887             : 
     888           0 : }
     889             : 
     890             : //--------------------------------------------------------------------------
     891             : 
     892             : // Collapse colours and check that they are consistent.
     893             : 
     894             : bool BeamRemnants::checkColours( Event& event) {
     895             : 
     896             :   // No colours in lepton beams so no need to do anything.
     897           0 :   if (beamAPtr->isLepton() && beamBPtr->isLepton()) return true;
     898             : 
     899             :   // Remove ambiguities when one colour collapses two ways.
     900             :   // Resolve chains where one colour is mapped to another.
     901           0 :   for (int iCol = 1; iCol < int(colFrom.size()); ++iCol)
     902           0 :   for (int iColRef = 0; iColRef < iCol; ++iColRef) {
     903           0 :     if (colFrom[iCol] == colFrom[iColRef]) {
     904           0 :       colFrom[iCol] = colTo[iCol];
     905           0 :       colTo[iCol] = colTo[iColRef];
     906           0 :     }
     907           0 :     if (colTo[iCol] == colFrom[iColRef]) colTo[iCol] = colTo[iColRef];
     908             :   }
     909             : 
     910             :   // Transform event record colours from beam remnant colour collapses.
     911           0 :   for (int i = oldSize; i < event.size(); ++i) {
     912           0 :     int col = event[i].col();
     913           0 :     int acol = event[i].acol();
     914           0 :     for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
     915           0 :       if (col == colFrom[iCol]) {col = colTo[iCol]; event[i].col(col);}
     916           0 :       if (acol == colFrom[iCol]) {acol = colTo[iCol]; event[i].acol(acol);}
     917             :       // Sextets have extra, negative, tags.
     918           0 :       if (col == -colFrom[iCol]) {col = -colTo[iCol]; event[i].col(col);}
     919           0 :       if (acol == -colFrom[iCol]) {acol = -colTo[iCol]; event[i].acol(acol);}
     920             :     }
     921             :   }
     922             : 
     923             :   // Transform junction colours from beam remnant colour collapses.
     924           0 :   for (int iJun = 0; iJun < event.sizeJunction(); ++iJun)
     925           0 :     for (int leg = 0; leg < 3; ++leg) {
     926           0 :       int col = event.colJunction(iJun, leg);
     927           0 :       for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
     928           0 :         if (col == colFrom[iCol]) {
     929           0 :           col = colTo[iCol];
     930           0 :           event.colJunction(iJun, leg, col);
     931           0 :         }
     932             :       }
     933             :     }
     934             : 
     935             :   // Arrays for current colours and anticolours, and for singlet gluons.
     936           0 :   vector<int> colList;
     937           0 :   vector<int> acolList;
     938           0 :   vector<int> iSingletGluon;
     939             : 
     940             :   // Find current colours and anticolours in the event record.
     941           0 :   for (int i = oldSize; i < event.size(); ++i)
     942           0 :   if (event[i].isFinal()) {
     943           0 :     int id   = event[i].id();
     944           0 :     int col  = event[i].col();
     945           0 :     int acol = event[i].acol();
     946           0 :     int colType = event[i].colType();
     947             : 
     948             :     // Quarks must have colour set, antiquarks anticolour, gluons both.
     949           0 :     if ( (id > 0 && id < 9 && (col <= 0 || acol != 0) )
     950           0 :       || (id < 0 && id > -9 && (col != 0 || acol <= 0) )
     951           0 :       || (id == 21 && (col <= 0 || acol <= 0) ) ) {
     952           0 :       infoPtr->errorMsg("Error in BeamRemnants::checkColours: "
     953             :         "q/qbar/g has wrong colour slots set");
     954           0 :       return false;
     955             :     }
     956             : 
     957             :     // Sextets must have one positive and one negative tag
     958           0 :     if ( (colType == 3 && (col <= 0 || acol >= 0))
     959           0 :          || (colType == -3 && (col >= 0 || acol <= 0)) ) {
     960           0 :       infoPtr->errorMsg("Error in BeamRemnants::checkColours: "
     961             :                         "sextet has wrong colours");
     962           0 :     }
     963             : 
     964             :     // Save colours/anticolours, and position of colour singlet gluons.
     965           0 :     if ( col > 0)  colList.push_back(  col );
     966           0 :     if (acol > 0) acolList.push_back( acol );
     967           0 :     if (col > 0 && acol == col) iSingletGluon.push_back(i);
     968             :     // Colour sextets
     969           0 :     if ( col < 0) acolList.push_back( -col );
     970           0 :     if (acol < 0) colList.push_back( -acol );
     971           0 :   }
     972             : 
     973             :   // Run through list of singlet gluons and put them on final-state dipole
     974             :   // (i,j) that offers smallest (p_g p_i) * (p_g p_j) / (p_i p_j).
     975           0 :   for (int iS = 0; iS < int(iSingletGluon.size()); ++iS) {
     976           0 :     int    iGlu      = iSingletGluon[iS];
     977             :     int    iAcolDip  = -1;
     978           0 :     double pT2DipMin = sCM;
     979           0 :     for (int iC = oldSize; iC < event.size(); ++iC)
     980           0 :       if (iC != iGlu && event[iC].isFinal()) {
     981           0 :       int colDip = event[iC].col();
     982           0 :       if (colDip > 0 && event[iC].acol() !=colDip)
     983           0 :       for (int iA = oldSize; iA < event.size(); ++iA)
     984           0 :         if (iA != iGlu && iA != iC && event[iA].isFinal()
     985           0 :         && event[iA].acol() == colDip && event[iA].col() !=colDip) {
     986           0 :         double pT2Dip = (event[iGlu].p() * event[iC].p())
     987           0 :           * (event[iGlu].p() * event[iA].p())
     988           0 :           / (event[iC].p() * event[iA].p());
     989           0 :         if (pT2Dip < pT2DipMin) {
     990             :           iAcolDip  = iA;
     991             :           pT2DipMin = pT2Dip;
     992           0 :         }
     993           0 :       }
     994           0 :     }
     995             : 
     996             :     // Fail if no dipole. Else insert singlet gluon onto relevant dipole.
     997           0 :     if (iAcolDip == -1)  return false;
     998           0 :     event[iGlu].acol( event[iAcolDip].acol() );
     999           0 :     event[iAcolDip].acol( event[iGlu].col() );
    1000             : 
    1001             :     // Update any junction legs that match reconnected dipole.
    1002           0 :     for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) {
    1003             : 
    1004             :       // Only junctions need to be updated, not antijunctions.
    1005           0 :       if (event.kindJunction(iJun) % 2 == 0) continue;
    1006           0 :       for (int leg = 0; leg < 3; ++leg) {
    1007           0 :         int col = event.colJunction(iJun, leg);
    1008           0 :         if (col == event[iGlu].acol())
    1009           0 :           event.colJunction(iJun, leg, event[iGlu].col());
    1010             :       }
    1011           0 :     }
    1012             : 
    1013           0 :   }
    1014             : 
    1015             :   // Check that not the same colour or anticolour appears twice.
    1016           0 :   for (int iCol = 0; iCol < int(colList.size()) - 1; ++iCol) {
    1017           0 :     int col = colList[iCol];
    1018           0 :     for (int iCol2 = iCol + 1; iCol2 < int(colList.size()); ++iCol2)
    1019           0 :     if (colList[iCol2] == col) {
    1020           0 :       infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
    1021             :         " colour appears twice");
    1022             :       if (!ALLOWCOLOURTWICE) return false;
    1023           0 :     }
    1024             :   }
    1025           0 :   for (int iAcol = 0; iAcol < int(acolList.size()) - 1; ++iAcol) {
    1026           0 :     int acol = acolList[iAcol];
    1027           0 :     for (int iAcol2 = iAcol + 1; iAcol2 < int(acolList.size()); ++iAcol2)
    1028           0 :     if (acolList[iAcol2] == acol) {
    1029           0 :       infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
    1030             :         " anticolour appears twice");
    1031             :       if (!ALLOWCOLOURTWICE) return false;
    1032           0 :     }
    1033             :   }
    1034             : 
    1035             :   // Remove all matching colour-anticolour pairs.
    1036             :   bool foundPair = true;
    1037           0 :   while (foundPair && colList.size() > 0 && acolList.size() > 0) {
    1038             :     foundPair = false;
    1039           0 :     for (int iCol = 0; iCol < int(colList.size()); ++iCol) {
    1040           0 :       for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) {
    1041           0 :         if (acolList[iAcol] == colList[iCol]) {
    1042           0 :           colList[iCol] = colList.back(); colList.pop_back();
    1043           0 :           acolList[iAcol] = acolList.back(); acolList.pop_back();
    1044             :           foundPair = true;
    1045           0 :           break;
    1046             :         }
    1047             :       }
    1048           0 :       if (foundPair) break;
    1049             :     }
    1050             :   }
    1051             : 
    1052             :   // Check that remaining (anti)colours are accounted for by junctions.
    1053           0 :   for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) {
    1054           0 :     int kindJun = event.kindJunction(iJun);
    1055           0 :     for (int leg = 0; leg < 3; ++leg) {
    1056           0 :       int colEnd = event.colJunction(iJun, leg);
    1057             : 
    1058             :       // Junction connected to three colours.
    1059           0 :       if (kindJun == 1) {
    1060           0 :         for (int iCol = 0; iCol < int(colList.size()); ++iCol)
    1061           0 :         if (colList[iCol] == colEnd) {
    1062             :           // Found colour match: remove and exit.
    1063           0 :           colList[iCol] = colList.back();
    1064           0 :           colList.pop_back();
    1065           0 :           break;
    1066             :         }
    1067           0 :       }
    1068             : 
    1069             :       // Junction connected to three anticolours.
    1070           0 :       else if (kindJun == 2) {
    1071           0 :         for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
    1072           0 :         if (acolList[iAcol] == colEnd) {
    1073             :           // Found colour match: remove and exit.
    1074           0 :           acolList[iAcol] = acolList.back();
    1075           0 :           acolList.pop_back();
    1076           0 :           break;
    1077             :         }
    1078           0 :       }
    1079             : 
    1080             :       // Other junction types
    1081           0 :       else if ( kindJun == 3 || kindJun == 5) {
    1082           0 :         for (int iCol = 0; iCol < int(colList.size()); ++iCol)
    1083           0 :         if (colList[iCol] == colEnd) {
    1084             :           // Found colour match: remove and exit.
    1085           0 :           colList[iCol] = colList.back();
    1086           0 :           colList.pop_back();
    1087           0 :           break;
    1088             :         }
    1089           0 :       }
    1090             : 
    1091             :       // Other antijunction types
    1092           0 :       else if ( kindJun == 4 || kindJun == 6) {
    1093           0 :         for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
    1094           0 :         if (acolList[iAcol] == colEnd) {
    1095             :           // Found colour match: remove and exit.
    1096           0 :           acolList[iAcol] = acolList.back();
    1097           0 :           acolList.pop_back();
    1098           0 :           break;
    1099             :         }
    1100           0 :       }
    1101             : 
    1102             :       // End junction check.
    1103             :     }
    1104             :   }
    1105             : 
    1106             : 
    1107             :   // Repair step - sometimes needed when rescattering allowed.
    1108           0 :   if (colList.size() > 0 || acolList.size() > 0) {
    1109           0 :     infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
    1110             :                       " need to repair unmatched colours");
    1111           0 :   }
    1112           0 :   while (colList.size() > 0 && acolList.size() > 0) {
    1113             : 
    1114             :     // Replace one colour and one anticolour index by a new common one.
    1115           0 :     int  colMatch =  colList.back();
    1116           0 :     int acolMatch = acolList.back();
    1117           0 :     int  colNew   = event.nextColTag();
    1118           0 :     colList.pop_back();
    1119           0 :     acolList.pop_back();
    1120           0 :     for (int i = oldSize; i < event.size(); ++i) {
    1121           0 :       if (event[i].isFinal() && event[i].col() == colMatch) {
    1122           0 :         event[i].col( colNew);
    1123           0 :         break;
    1124             :       }
    1125           0 :       else if (event[i].isFinal() && event[i].acol() == -colMatch) {
    1126           0 :         event[i].acol( -colNew);
    1127           0 :         break;
    1128             :       }
    1129             :     }
    1130           0 :     for (int i = oldSize; i < event.size(); ++i) {
    1131           0 :       if (event[i].isFinal() && event[i].acol() == acolMatch) {
    1132           0 :         event[i].acol( colNew);
    1133           0 :         break;
    1134             :       }
    1135           0 :       if (event[i].isFinal() && event[i].col() == -acolMatch) {
    1136           0 :         event[i].col( -colNew);
    1137           0 :         break;
    1138             :       }
    1139             :     }
    1140             :   }
    1141             : 
    1142             :   // Done.
    1143           0 :   return (colList.size() == 0 && acolList.size() == 0);
    1144             : 
    1145           0 : }
    1146             : 
    1147             : //--------------------------------------------------------------------------
    1148             : 
    1149             : // Update colours of outgoing particles in the event record.
    1150             : 
    1151             : void BeamRemnants::updateColEvent( Event& event,
    1152             :   vector<pair <int,int> > colChanges) {
    1153             : 
    1154           0 :   for (int iCol = 0; iCol < int(colChanges.size()); ++iCol) {
    1155             : 
    1156           0 :     int oldCol = colChanges[iCol].first;
    1157           0 :     int newCol = colChanges[iCol].second;
    1158           0 :     if (oldCol == newCol)
    1159           0 :       continue;
    1160             : 
    1161             :     // Add a copy of final particles with old colour and change the colour.
    1162           0 :     for (int j = 0; j < event.size(); ++j) {
    1163           0 :       if (event[j].isFinal() && event[j].col() == oldCol)
    1164           0 :         event[event.copy(j, 64)].col(newCol);
    1165           0 :       if (event[j].isFinal() && event[j].acol() == -oldCol)
    1166           0 :         event[event.copy(j, 64)].acol(-newCol);
    1167             : 
    1168           0 :       if (event[j].isFinal() && event[j].acol() == oldCol)
    1169           0 :         event[event.copy(j,64)].acol(newCol);
    1170           0 :       if (event[j].isFinal() && event[j].col() == -oldCol)
    1171           0 :         event[event.copy(j,64)].col(-newCol);
    1172             :     }
    1173             : 
    1174             :     // Update junction.
    1175           0 :     for (int j = 0;j < event.sizeJunction(); ++j)
    1176           0 :       for (int jCol = 0; jCol < 3; ++jCol)
    1177           0 :         if (event.colJunction(j,jCol) == oldCol)
    1178           0 :           event.colJunction(j,jCol,newCol);
    1179           0 :   }
    1180             : 
    1181           0 : }
    1182             : 
    1183             : //==========================================================================
    1184             : 
    1185             : } // end namespace Pythia8

Generated by: LCOV version 1.11