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

          Line data    Source code
       1             : // StringFragmentation.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 StringEnd and
       7             : // StringFragmentation classes.
       8             : 
       9             : #include "Pythia8/StringFragmentation.h"
      10             : 
      11             : namespace Pythia8 {
      12             : 
      13             : //==========================================================================
      14             : 
      15             : // The StringEnd class.
      16             : 
      17             : //--------------------------------------------------------------------------
      18             : 
      19             : // Constants: could be changed here if desired, but normally should not.
      20             : 
      21             : // Avoid unphysical solutions to equation system.
      22             : const double StringEnd::TINY = 1e-6;
      23             : 
      24             : // Assume two (eX, eY) regions are related if pT2 differs by less.
      25             : const double StringEnd::PT2SAME = 0.01;
      26             : 
      27             : //--------------------------------------------------------------------------
      28             : 
      29             : // Set up initial endpoint values from input.
      30             : 
      31             : void StringEnd::setUp(bool fromPosIn, int iEndIn, int idOldIn, int iMaxIn,
      32             :   double pxIn, double pyIn, double GammaIn, double xPosIn, double xNegIn) {
      33             : 
      34             :   // Simple transcription from input.
      35           0 :   fromPos  = fromPosIn;
      36           0 :   iEnd     = iEndIn;
      37           0 :   iMax     = iMaxIn;
      38           0 :   flavOld  = FlavContainer(idOldIn);
      39           0 :   pxOld    = pxIn;
      40           0 :   pyOld    = pyIn;
      41           0 :   GammaOld = GammaIn;
      42           0 :   iPosOld  = (fromPos) ? 0 : iMax;
      43           0 :   iNegOld  = (fromPos) ? iMax : 0;
      44           0 :   xPosOld  = xPosIn;
      45           0 :   xNegOld  = xNegIn;
      46             : 
      47           0 : }
      48             : 
      49             : //--------------------------------------------------------------------------
      50             : 
      51             : // Fragment off one hadron from the string system, in flavour and pT.
      52             : 
      53             : void StringEnd::newHadron() {
      54             : 
      55             :   // Pick new flavour and form a new hadron.
      56           0 :   do {
      57           0 :     flavNew = flavSelPtr->pick( flavOld);
      58           0 :     idHad   = flavSelPtr->combine( flavOld, flavNew);
      59           0 :   } while (idHad == 0);
      60             : 
      61             :   // Pick its transverse momentum.
      62           0 :   pair<double, double> pxy = pTSelPtr->pxy();
      63           0 :   pxNew = pxy.first;
      64           0 :   pyNew = pxy.second;
      65           0 :   pxHad = pxOld + pxNew;
      66           0 :   pyHad = pyOld + pyNew;
      67             : 
      68             :   // Pick its mass and thereby define its transverse mass.
      69           0 :   mHad   = particleDataPtr->mSel(idHad);
      70           0 :   mT2Had = pow2(mHad) + pow2(pxHad) + pow2(pyHad);
      71             : 
      72           0 : }
      73             : 
      74             : //--------------------------------------------------------------------------
      75             : 
      76             : // Fragment off one hadron from the string system, in momentum space,
      77             : // by taking steps from positive end.
      78             : 
      79             : Vec4 StringEnd::kinematicsHadron( StringSystem& system) {
      80             : 
      81             :   // Pick fragmentation step z and calculate new Gamma.
      82           0 :   zHad = zSelPtr->zFrag( flavOld.id, flavNew.id, mT2Had);
      83           0 :   GammaNew = (1. - zHad) * (GammaOld + mT2Had / zHad);
      84             : 
      85             :   // Set up references that are direction-neutral;
      86             :   // ...Dir for direction of iteration and ...Inv for its inverse.
      87           0 :   int&    iDirOld = (fromPos) ? iPosOld : iNegOld;
      88           0 :   int&    iInvOld = (fromPos) ? iNegOld : iPosOld;
      89           0 :   int&    iDirNew = (fromPos) ? iPosNew : iNegNew;
      90           0 :   int&    iInvNew = (fromPos) ? iNegNew : iPosNew;
      91           0 :   double& xDirOld = (fromPos) ? xPosOld : xNegOld;
      92           0 :   double& xInvOld = (fromPos) ? xNegOld : xPosOld;
      93           0 :   double& xDirNew = (fromPos) ? xPosNew : xNegNew;
      94           0 :   double& xInvNew = (fromPos) ? xNegNew : xPosNew;
      95           0 :   double& xDirHad = (fromPos) ? xPosHad : xNegHad;
      96           0 :   double& xInvHad = (fromPos) ? xNegHad : xPosHad;
      97             : 
      98             :   // Start search for new breakup in the old region.
      99           0 :   iDirNew = iDirOld;
     100           0 :   iInvNew = iInvOld;
     101           0 :   Vec4 pTNew;
     102             : 
     103             :   // Each step corresponds to trying a new string region.
     104           0 :   for (int iStep = 0; ; ++iStep) {
     105             : 
     106             :     // Referance to current string region.
     107           0 :     StringRegion& region = system.region( iPosNew, iNegNew);
     108             : 
     109             :     // Now begin special section for rapid processing of low region.
     110           0 :     if (iStep == 0 && iPosOld + iNegOld == iMax) {
     111             : 
     112             :       // A first step within a low region is easy.
     113           0 :       if (mT2Had < zHad * xDirOld * (1. - xInvOld) * region.w2) {
     114             : 
     115             :         // Translate into x coordinates.
     116           0 :         xDirHad = zHad * xDirOld;
     117           0 :         xInvHad = mT2Had / (xDirHad * region.w2);
     118           0 :         xDirNew = xDirOld - xDirHad;
     119           0 :         xInvNew = xInvOld + xInvHad;
     120             : 
     121             :         // Find and return four-momentum of the produced particle.
     122           0 :         return region.pHad( xPosHad, xNegHad, pxHad, pyHad);
     123             : 
     124             :       // A first step out of a low region also OK, if there are more regions.
     125             :       // Negative energy signals failure, i.e. in last region.
     126             :       } else {
     127           0 :         --iInvNew;
     128           0 :         if (iInvNew < 0) return Vec4(0., 0., 0., -1.);
     129             : 
     130             :         // Momentum taken by stepping out of region. Continue to next region.
     131           0 :         xInvHad = 1. - xInvOld;
     132           0 :         xDirHad = 0.;
     133           0 :         pSoFar  = region.pHad( xPosHad, xNegHad, pxOld, pyOld);
     134           0 :         continue;
     135             :       }
     136             : 
     137             :     // Else, for first step, take into account starting pT.
     138           0 :     } else if (iStep == 0) {
     139           0 :       pSoFar = region.pHad( 0., 0., pxOld, pyOld);
     140           0 :       pTNew  = region.pHad( 0., 0., pxNew, pyNew);
     141           0 :     }
     142             : 
     143             :     // Now begin normal treatment of nontrivial regions.
     144             :     // Set up four-vectors in a region not visited before.
     145           0 :     if (!region.isSetUp) region.setUp(
     146           0 :       system.regionLowPos(iPosNew).pPos,
     147           0 :       system.regionLowNeg(iNegNew).pNeg, true);
     148             : 
     149             :     // If new region is vanishingly small, continue immediately to next.
     150             :     // Negative energy signals failure to do this, i.e. moved too low.
     151           0 :     if (region.isEmpty) {
     152           0 :       xDirHad = (iDirNew == iDirOld) ? xDirOld : 1.;
     153           0 :       xInvHad = 0.;
     154           0 :       pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.);
     155           0 :       ++iDirNew;
     156           0 :       if (iDirNew + iInvNew > iMax) return Vec4(0., 0., 0., -1.);
     157           0 :       continue;
     158             :     }
     159             : 
     160             :     // Reexpress pTNew w.r.t. base vectors in new region, if possible.
     161             :     // Recall minus sign from normalization e_x^2 = e_y^2 = -1.
     162           0 :     double pxNewTemp = -pTNew * region.eX;
     163           0 :     double pyNewTemp = -pTNew * region.eY;
     164           0 :     if (abs( pxNewTemp * pxNewTemp + pyNewTemp * pyNewTemp
     165           0 :       - pxNew * pxNew - pyNew * pyNew) < PT2SAME) {
     166           0 :       pxNew = pxNewTemp;
     167           0 :       pyNew = pyNewTemp;
     168           0 :     }
     169             : 
     170             :     // Four-momentum taken so far, including new pT.
     171           0 :     Vec4 pTemp = pSoFar + region.pHad( 0., 0., pxNew, pyNew);
     172             : 
     173             :     // Derive coefficients for m2 expression.
     174             :     // cM2 * x+ + cM3 * x- + cM4 * x+ * x- = m^2 - cM1;
     175           0 :     double cM1 = pTemp.m2Calc();
     176           0 :     double cM2 = 2. * (pTemp * region.pPos);
     177           0 :     double cM3 = 2. * (pTemp * region.pNeg);
     178           0 :     double cM4 = region.w2;
     179           0 :     if (!fromPos) swap( cM2, cM3);
     180             : 
     181             :     // Derive coefficients for Gamma expression.
     182             :     // cGam2 * x+ + cGam3 * x- + cGam4 * x+ * x- = Gamma_new - cGam1;
     183             :     double cGam1 = 0.;
     184             :     double cGam2 = 0.;
     185             :     double cGam3 = 0.;
     186             :     double cGam4 = 0.;
     187           0 :     for (int iInv = iInvNew; iInv <= iMax - iDirNew; ++iInv) {
     188             :       double xInv = 1.;
     189           0 :       if (iInv == iInvNew) xInv = (iInvNew == iInvOld) ? xInvOld : 0.;
     190           0 :       for (int iDir = iDirNew; iDir <= iMax - iInv; ++iDir) {
     191           0 :         double xDir = (iDir == iDirOld) ? xDirOld : 1.;
     192           0 :         int iPos = (fromPos) ? iDir : iInv;
     193           0 :         int iNeg = (fromPos) ? iInv : iDir;
     194           0 :         StringRegion& regionGam =  system.region( iPos, iNeg);
     195           0 :         if (!regionGam.isSetUp) regionGam.setUp(
     196           0 :           system.regionLowPos(iPos).pPos,
     197           0 :           system.regionLowNeg(iNeg).pNeg, true);
     198           0 :         double w2 = regionGam.w2;
     199           0 :         cGam1 += xDir * xInv * w2;
     200           0 :         if (iDir == iDirNew) cGam2 -= xInv * w2;
     201           0 :         if (iInv == iInvNew) cGam3 += xDir * w2;
     202           0 :         if (iDir == iDirNew && iInv == iInvNew) cGam4 -= w2;
     203             :       }
     204             :     }
     205             : 
     206             :     // Solve (m2, Gamma) equation system => r2 * x-^2 + r1 * x- + r0 = 0.
     207           0 :     double cM0   = pow2(mHad) - cM1;
     208           0 :     double cGam0 = GammaNew - cGam1;
     209           0 :     double r2    = cM3 * cGam4 - cM4 * cGam3;
     210           0 :     double r1    = cM4 * cGam0 - cM0 * cGam4 + cM3 * cGam2 - cM2 * cGam3;
     211           0 :     double r0    = cM2 * cGam0 - cM0 * cGam2;
     212           0 :     double root  = sqrtpos( r1*r1 - 4. * r2 * r0 );
     213           0 :     if (abs(r2) < TINY || root < TINY) return Vec4(0., 0., 0., -1.);
     214           0 :     xInvHad      = 0.5 * (root / abs(r2) - r1 / r2);
     215           0 :     xDirHad      = (cM0 - cM3 * xInvHad) / (cM2 + cM4 * xInvHad);
     216             : 
     217             :     // Define position of new trial vertex.
     218           0 :     xDirNew = (iDirNew == iDirOld) ? xDirOld - xDirHad : 1. - xDirHad;
     219           0 :     xInvNew = (iInvNew == iInvOld) ? xInvOld + xInvHad : xInvHad;
     220             : 
     221             :     // Step up to new region if new x- > 1.
     222           0 :     if (xInvNew > 1.) {
     223           0 :       xInvHad = (iInvNew == iInvOld) ? 1. - xInvOld : 1.;
     224           0 :       xDirHad = 0.;
     225           0 :       pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.);
     226           0 :       --iInvNew;
     227           0 :       if (iInvNew < 0) return Vec4(0., 0., 0., -1.);
     228           0 :       continue;
     229             : 
     230             :     // Step down to new region if new x+ < 0.
     231           0 :     } else if (xDirNew < 0.) {
     232           0 :       xDirHad = (iDirNew == iDirOld) ? xDirOld : 1.;
     233           0 :       xInvHad = 0.;
     234           0 :       pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.);
     235           0 :       ++iDirNew;
     236           0 :       if (iDirNew + iInvNew > iMax) return Vec4(0., 0., 0., -1.);
     237           0 :       continue;
     238             :     }
     239             : 
     240             :     // Else we have found the correct region, and can return four-momentum.
     241           0 :     return pSoFar + region.pHad( xPosHad, xNegHad, pxNew, pyNew);
     242             : 
     243             :   // End of "infinite" loop of stepping to new region.
     244           0 :   }
     245             : 
     246           0 : }
     247             : 
     248             : //--------------------------------------------------------------------------
     249             : 
     250             : // Update string end information after a hadron has been removed.
     251             : 
     252             : void StringEnd::update() {
     253             : 
     254           0 :   flavOld.anti(flavNew);
     255           0 :   iPosOld  = iPosNew;
     256           0 :   iNegOld  = iNegNew;
     257           0 :   pxOld    = -pxNew;
     258           0 :   pyOld    = -pyNew;
     259           0 :   GammaOld = GammaNew;
     260           0 :   xPosOld  = xPosNew;
     261           0 :   xNegOld  = xNegNew;
     262             : 
     263           0 : }
     264             : 
     265             : //==========================================================================
     266             : 
     267             : // The StringFragmentation class.
     268             : 
     269             : //--------------------------------------------------------------------------
     270             : 
     271             : // Constants: could be changed here if desired, but normally should not.
     272             : // These are of technical nature, as described for each.
     273             : 
     274             : // Maximum number of tries to (flavour-, energy) join the two string ends.
     275             : const int    StringFragmentation::NTRYFLAV      = 10;
     276             : const int    StringFragmentation::NTRYJOIN      = 30;
     277             : 
     278             : // The last few times gradually increase the stop mass to make it easier.
     279             : const int    StringFragmentation::NSTOPMASS     = 15;
     280             : const double StringFragmentation::FACSTOPMASS   = 1.05;
     281             : 
     282             : // For closed string, pick a Gamma by taking a step with fictitious mass.
     283             : const double StringFragmentation::CLOSEDM2MAX   = 25.;
     284             : const double StringFragmentation::CLOSEDM2FRAC  = 0.1;
     285             : 
     286             : // Do not allow too large argument to exp function.
     287             : const double StringFragmentation::EXPMAX        = 50.;
     288             : 
     289             : // Matching criterion that p+ and p- not the same (can happen in gg loop).
     290             : const double StringFragmentation::MATCHPOSNEG   = 1e-4;
     291             : 
     292             : // For pull on junction, do not trace too far down each leg.
     293             : const double StringFragmentation::EJNWEIGHTMAX  = 10.;
     294             : 
     295             : // Iterate junction rest frame boost until convergence or too many tries.
     296             : const double StringFragmentation::CONVJNREST   = 1e-5;
     297             : const int    StringFragmentation::NTRYJNREST   = 20;
     298             : 
     299             : // Fail and try again when two legs combined to diquark (3 loops).
     300             : const int    StringFragmentation::NTRYJNMATCH   = 20;
     301             : const double StringFragmentation::EEXTRAJNMATCH = 0.5;
     302             : const double StringFragmentation::MDIQUARKMIN   = -2.0;
     303             : 
     304             : // Consider junction-leg parton as massless if m2 tiny.
     305             : const double StringFragmentation::M2MAXJRF      = 1e-4;
     306             : 
     307             : // Protect against numerical precision giving zero or negative m2.
     308             : const double StringFragmentation::M2MINJRF      = 1e-4;
     309             : 
     310             : // Iterate junction rest frame equation until convergence or too many tries.
     311             : const double StringFragmentation::CONVJRFEQ     = 1e-12;
     312             : const int    StringFragmentation::NTRYJRFEQ     = 40;
     313             : 
     314             : //--------------------------------------------------------------------------
     315             : 
     316             : // Initialize and save pointers.
     317             : 
     318             : void StringFragmentation::init(Info* infoPtrIn, Settings& settings,
     319             :   ParticleData* particleDataPtrIn, Rndm* rndmPtrIn, StringFlav* flavSelPtrIn,
     320             :   StringPT* pTSelPtrIn, StringZ* zSelPtrIn) {
     321             : 
     322             :   // Save pointers.
     323           0 :   infoPtr         = infoPtrIn;
     324           0 :   particleDataPtr = particleDataPtrIn;
     325           0 :   rndmPtr         = rndmPtrIn;
     326           0 :   flavSelPtr      = flavSelPtrIn;
     327           0 :   pTSelPtr        = pTSelPtrIn;
     328           0 :   zSelPtr         = zSelPtrIn;
     329             : 
     330             :   // Initialize the StringFragmentation class.
     331           0 :   stopMass        = zSelPtr->stopMass();
     332           0 :   stopNewFlav     = zSelPtr->stopNewFlav();
     333           0 :   stopSmear       = zSelPtr->stopSmear();
     334           0 :   eNormJunction   = settings.parm("StringFragmentation:eNormJunction");
     335           0 :   eBothLeftJunction
     336           0 :      = settings.parm("StringFragmentation:eBothLeftJunction");
     337           0 :   eMaxLeftJunction
     338           0 :     = settings.parm("StringFragmentation:eMaxLeftJunction");
     339           0 :   eMinLeftJunction
     340           0 :     = settings.parm("StringFragmentation:eMinLeftJunction");
     341             : 
     342             :   // Joining of nearby partons along the string.
     343           0 :   mJoin           = settings.parm("FragmentationSystems:mJoin");
     344             : 
     345             :   // Initialize the b parameter of the z spectrum, used when joining jets.
     346           0 :   bLund           = zSelPtr->bAreaLund();
     347             : 
     348             :   // Initialize the hadrons instance of an event record.
     349           0 :   hadrons.init( "(string fragmentation)", particleDataPtr);
     350             : 
     351             :   // Send on pointers to the two StringEnd instances.
     352           0 :   posEnd.init( particleDataPtr, flavSelPtr, pTSelPtr, zSelPtr);
     353           0 :   negEnd.init( particleDataPtr, flavSelPtr, pTSelPtr, zSelPtr);
     354             : 
     355           0 : }
     356             : 
     357             : //--------------------------------------------------------------------------
     358             : 
     359             : // Perform the fragmentation.
     360             : 
     361             : bool StringFragmentation::fragment( int iSub, ColConfig& colConfig,
     362             :   Event& event) {
     363             : 
     364             :   // Find partons and their total four-momentum.
     365           0 :   iParton            = colConfig[iSub].iParton;
     366           0 :   iPos               = iParton[0];
     367           0 :   if (iPos < 0) iPos = iParton[1];
     368           0 :   int idPos          = event[iPos].id();
     369           0 :   iNeg               = iParton.back();
     370           0 :   int idNeg          = event[iNeg].id();
     371           0 :   pSum               = colConfig[iSub].pSum;
     372             : 
     373             :   // Reset the local event record.
     374           0 :   hadrons.clear();
     375             : 
     376             :   // For closed gluon string: pick first breakup region.
     377           0 :   isClosed = colConfig[iSub].isClosed;
     378           0 :   if (isClosed) iParton = findFirstRegion(iParton, event);
     379             : 
     380             :   // For junction topology: fragment off two of the string legs.
     381             :   // Then iParton overwritten to remaining leg + leftover diquark.
     382           0 :   pJunctionHadrons = 0.;
     383           0 :   hasJunction = colConfig[iSub].hasJunction;
     384           0 :   if (hasJunction && !fragmentToJunction(event)) return false;
     385           0 :   int junctionHadrons = hadrons.size();
     386           0 :   if (hasJunction) {
     387           0 :     idPos  = event[ iParton[0] ].id();
     388           0 :     idNeg  = event.back().id();
     389           0 :     pSum  -= pJunctionHadrons;
     390           0 :   }
     391             : 
     392             :   // Set up kinematics of string evolution ( = motion).
     393           0 :   system.setUp(iParton, event);
     394           0 :   stopMassNow = stopMass;
     395             :   int nExtraJoin = 0;
     396             : 
     397             :   // Fallback loop, when joining in the middle fails.  Bailout if stuck.
     398           0 :   for ( int iTry = 0; ; ++iTry) {
     399           0 :     if (iTry > NTRYJOIN) {
     400           0 :       infoPtr->errorMsg("Error in StringFragmentation::fragment: "
     401             :         "stuck in joining");
     402           0 :       if (hasJunction) ++nExtraJoin;
     403           0 :       if (nExtraJoin > 0) event.popBack(nExtraJoin);
     404           0 :       return false;
     405             :     }
     406             : 
     407             :     // After several failed tries join some (extra) nearby partons.
     408           0 :     if (iTry == NTRYJOIN / 3) nExtraJoin = extraJoin( 2., event);
     409           0 :     if (iTry == 2 * NTRYJOIN / 3) nExtraJoin += extraJoin( 4., event);
     410             : 
     411             :     // After several failed tries gradually allow larger stop mass.
     412           0 :     if (iTry > NTRYJOIN - NSTOPMASS) stopMassNow *= FACSTOPMASS;
     413             : 
     414             :     // Set up flavours of two string ends, and reset other info.
     415           0 :     setStartEnds(idPos, idNeg, system);
     416           0 :     pRem = pSum;
     417             : 
     418             :     // Begin fragmentation loop, interleaved from the two ends.
     419             :     bool fromPos;
     420             : 
     421             :     // Variables used to help identifying baryons from junction splittings.
     422             :     bool usedPosJun = false, usedNegJun = false;
     423             : 
     424           0 :     for ( ; ; ) {
     425             : 
     426             :       // Take a step either from the positive or the negative end.
     427           0 :       fromPos           = (rndmPtr->flat() < 0.5);
     428           0 :       StringEnd& nowEnd = (fromPos) ? posEnd : negEnd;
     429             : 
     430             :       // Construct trial hadron and check that energy remains.
     431           0 :       nowEnd.newHadron();
     432           0 :       if ( energyUsedUp(fromPos) ) break;
     433             : 
     434             :       // Construct kinematics of the new hadron and store it.
     435           0 :       Vec4 pHad = nowEnd.kinematicsHadron(system);
     436           0 :       int statusHad = (fromPos) ? 83 : 84;
     437             : 
     438             :       // Change status code if hadron from junction.
     439           0 :       if (abs(nowEnd.idHad) > 1000 && abs(nowEnd.idHad) < 10000) {
     440           0 :         if (fromPos && event[iPos].statusAbs() == 74 && !usedPosJun)  {
     441             :           statusHad = 87;
     442             :           usedPosJun = true;
     443           0 :         }
     444           0 :         if (!fromPos && event[iNeg].statusAbs() == 74 && !usedNegJun)  {
     445             :           statusHad = 88;
     446             :           usedNegJun = true;
     447           0 :         }
     448           0 :         if (!fromPos && hasJunction && !usedNegJun) {
     449             :           statusHad = 88;
     450             :           usedNegJun = true;
     451           0 :         }
     452             :       }
     453           0 :       hadrons.append( nowEnd.idHad, statusHad, iPos, iNeg,
     454           0 :         0, 0, 0, 0, pHad, nowEnd.mHad);
     455           0 :       if (pHad.e() < 0.) break;
     456             : 
     457             :       // Update string end and remaining momentum.
     458           0 :       nowEnd.update();
     459           0 :       pRem -= pHad;
     460             : 
     461             :     // End of fragmentation loop.
     462           0 :     }
     463             : 
     464             :     // When done, join in the middle. If this works, then really done.
     465           0 :     if ( finalTwo(fromPos, event, usedPosJun, usedNegJun) ) break;
     466             : 
     467             :     // Else remove produced particles (except from first two junction legs)
     468             :     // and start all over.
     469           0 :     int newHadrons = hadrons.size() - junctionHadrons;
     470           0 :     hadrons.popBack(newHadrons);
     471           0 :   }
     472             : 
     473             : 
     474             :   // Junctions & extra joins: remove fictitious end, restore original partons.
     475           0 :   if (hasJunction) ++nExtraJoin;
     476           0 :   if (nExtraJoin > 0) {
     477           0 :     event.popBack(nExtraJoin);
     478           0 :     iParton = colConfig[iSub].iParton;
     479           0 :   }
     480             : 
     481             :   // Store the hadrons in the normal event record, ordered from one end.
     482           0 :   store(event);
     483             : 
     484             :   // Done.
     485           0 :   return true;
     486             : 
     487           0 : }
     488             : 
     489             : //--------------------------------------------------------------------------
     490             : 
     491             : // Find region where to put first string break for closed gluon loop.
     492             : 
     493             : vector<int> StringFragmentation::findFirstRegion(vector<int>& iPartonIn,
     494             :   Event& event) {
     495             : 
     496             :   // Evaluate mass-squared for all adjacent gluon pairs.
     497           0 :   vector<double> m2Pair;
     498             :   double m2Sum = 0.;
     499           0 :   int size = iPartonIn.size();
     500           0 :   for (int i = 0; i < size; ++i) {
     501           0 :     double m2Now = 0.5 * event[ iPartonIn[i] ].p()
     502           0 :       * event[ iPartonIn[(i + 1)%size] ].p();
     503           0 :     m2Pair.push_back(m2Now);
     504           0 :     m2Sum += m2Now;
     505           0 :   }
     506             : 
     507             :   // Pick breakup region with probability proportional to mass-squared.
     508           0 :   double m2Reg = m2Sum * rndmPtr->flat();
     509             :   int iReg = -1;
     510           0 :   do m2Reg -= m2Pair[++iReg];
     511           0 :   while (m2Reg > 0. && iReg < size - 1);
     512             : 
     513             :   // Create reordered parton list, with breakup string region duplicated.
     514           0 :   vector<int> iPartonOut;
     515           0 :   for (int i = 0; i < size + 2; ++i)
     516           0 :     iPartonOut.push_back( iPartonIn[(i + iReg)%size] );
     517             : 
     518             :   // Done.
     519             :   return iPartonOut;
     520             : 
     521           0 : }
     522             : 
     523             : //--------------------------------------------------------------------------
     524             : 
     525             : // Set flavours and momentum position for initial string endpoints.
     526             : 
     527             : void StringFragmentation::setStartEnds( int idPos, int idNeg,
     528             :   StringSystem systemNow) {
     529             : 
     530             :   // Variables characterizing string endpoints: defaults for open string.
     531             :   double px          = 0.;
     532             :   double py          = 0.;
     533             :   double Gamma       = 0.;
     534             :   double xPosFromPos = 1.;
     535             :   double xNegFromPos = 0.;
     536             :   double xPosFromNeg = 0.;
     537             :   double xNegFromNeg = 1.;
     538             : 
     539             :   // For closed gluon loop need to pick an initial flavour.
     540           0 :   if (isClosed) {
     541             :     do {
     542           0 :       int idTry = flavSelPtr->pickLightQ();
     543           0 :       FlavContainer flavTry(idTry, 1);
     544           0 :       flavTry = flavSelPtr->pick( flavTry);
     545           0 :       flavTry = flavSelPtr->pick( flavTry);
     546           0 :       idPos   = flavTry.id;
     547           0 :       idNeg   = -idPos;
     548           0 :     } while (idPos == 0);
     549             : 
     550             :     // Also need pT and breakup vertex position in region.
     551           0 :    pair<double, double> pxy = pTSelPtr->pxy();
     552             :    px = pxy.first;
     553             :    py = pxy.second;
     554           0 :     double m2Region = systemNow.regionLowPos(0).w2;
     555           0 :     double m2Temp   = min( CLOSEDM2MAX, CLOSEDM2FRAC * m2Region);
     556           0 :     do {
     557           0 :       double zTemp = zSelPtr->zFrag( idPos, idNeg, m2Temp);
     558           0 :       xPosFromPos  = 1. - zTemp;
     559           0 :       xNegFromPos  = m2Temp / (zTemp * m2Region);
     560           0 :     } while (xNegFromPos > 1.);
     561           0 :     Gamma = xPosFromPos * xNegFromPos * m2Region;
     562             :     xPosFromNeg = xPosFromPos;
     563             :     xNegFromNeg = xNegFromPos;
     564           0 :   }
     565             : 
     566             :   // Initialize two string endpoints.
     567           0 :   posEnd.setUp(  true, iPos, idPos, systemNow.iMax,  px,  py,
     568             :     Gamma, xPosFromPos, xNegFromPos);
     569           0 :   negEnd.setUp( false, iNeg, idNeg, systemNow.iMax, -px, -py,
     570             :     Gamma, xPosFromNeg, xNegFromNeg);
     571             : 
     572             :   // For closed gluon loop can allow popcorn on one side but not both.
     573           0 :   if (isClosed) {
     574           0 :     flavSelPtr->assignPopQ(posEnd.flavOld);
     575           0 :     flavSelPtr->assignPopQ(negEnd.flavOld);
     576           0 :     if (rndmPtr->flat() < 0.5) posEnd.flavOld.nPop = 0;
     577           0 :     else                    negEnd.flavOld.nPop = 0;
     578           0 :     posEnd.flavOld.rank = 1;
     579           0 :     negEnd.flavOld.rank = 1;
     580           0 :   }
     581             : 
     582             :   // Done.
     583             : 
     584           0 : }
     585             : 
     586             : //--------------------------------------------------------------------------
     587             : 
     588             : // Check remaining energy-momentum whether it is OK to continue.
     589             : 
     590             : bool StringFragmentation::energyUsedUp(bool fromPos) {
     591             : 
     592             :   // If remaining negative energy then abort right away.
     593           0 :   if (pRem.e() < 0.) return true;
     594             : 
     595             :   // Calculate W2_minimum and done if remaining W2 is below it.
     596           0 :   double wMin = stopMassNow
     597           0 :     + particleDataPtr->constituentMass(posEnd.flavOld.id)
     598           0 :     + particleDataPtr->constituentMass(negEnd.flavOld.id);
     599           0 :   if (fromPos) wMin += stopNewFlav
     600           0 :     * particleDataPtr->constituentMass(posEnd.flavNew.id);
     601           0 :   else         wMin += stopNewFlav
     602           0 :     * particleDataPtr->constituentMass(negEnd.flavNew.id);
     603           0 :   wMin *= 1. + (2. * rndmPtr->flat() - 1.) * stopSmear;
     604           0 :   w2Rem = pRem.m2Calc();
     605           0 :   if (w2Rem < pow2(wMin)) return true;
     606             : 
     607             :   // Else still enough energy left to continue iteration.
     608           0 :   return false;
     609             : 
     610           0 : }
     611             : 
     612             : //--------------------------------------------------------------------------
     613             : 
     614             : // Produce the final two partons to complete the system.
     615             : 
     616             : bool StringFragmentation::finalTwo(bool fromPos, Event& event, bool usedPosJun,
     617             :   bool usedNegJun) {
     618             : 
     619             :   // Check whether we went too far in p+-.
     620           0 :   if (pRem.e() < 0.  || w2Rem < 0. || (hadrons.size() > 0
     621           0 :     && hadrons.back().e() < 0.) ) return false;
     622           0 :   if ( posEnd.iPosOld > negEnd.iPosOld || negEnd.iNegOld > posEnd.iNegOld)
     623           0 :     return false;
     624           0 :   if ( posEnd.iPosOld == negEnd.iPosOld && posEnd.xPosOld < negEnd.xPosOld)
     625           0 :     return false;
     626           0 :   if ( posEnd.iNegOld == negEnd.iNegOld && posEnd.xNegOld > negEnd.xNegOld)
     627           0 :     return false;
     628             : 
     629             :   // Construct the final hadron from the leftover flavours.
     630             :   // Impossible to join two diquarks. Also break if stuck for other reason.
     631           0 :   FlavContainer flav1 = (fromPos) ? posEnd.flavNew.anti() : posEnd.flavOld;
     632           0 :   FlavContainer flav2 = (fromPos) ? negEnd.flavOld : negEnd.flavNew.anti();
     633           0 :   if (flav1.isDiquark() && flav2.isDiquark()) return false;
     634             :   int idHad;
     635           0 :   for (int iTry = 0; iTry < NTRYFLAV; ++iTry) {
     636           0 :     idHad = flavSelPtr->combine( flav1, flav2);
     637           0 :     if (idHad != 0) break;
     638             :   }
     639           0 :   if (idHad == 0) return false;
     640             : 
     641             :   // Store the final particle and its new pT, and construct its mass.
     642           0 :   if (fromPos) {
     643           0 :     negEnd.idHad = idHad;
     644           0 :     negEnd.pxNew = -posEnd.pxNew;
     645           0 :     negEnd.pyNew = -posEnd.pyNew;
     646           0 :     negEnd.mHad  = particleDataPtr->mSel(idHad);
     647           0 :   } else {
     648           0 :     posEnd.idHad = idHad;
     649           0 :     posEnd.pxNew = -negEnd.pxNew;
     650           0 :     posEnd.pyNew = -negEnd.pyNew;
     651           0 :     posEnd.mHad  = particleDataPtr->mSel(idHad);
     652             :   }
     653             : 
     654             :   // String region in which to do the joining.
     655           0 :   StringRegion region = finalRegion();
     656           0 :   if (region.isEmpty) return false;
     657             : 
     658             :   // Project remaining momentum along longitudinal and transverse directions.
     659           0 :   region.project( pRem);
     660           0 :   double pxRem   = region.px() - posEnd.pxOld - negEnd.pxOld;
     661           0 :   double pyRem   = region.py() - posEnd.pyOld - negEnd.pyOld;
     662           0 :   double xPosRem = region.xPos();
     663           0 :   double xNegRem = region.xNeg();
     664             : 
     665             :   // Share extra pT kick evenly between final two hadrons.
     666           0 :   posEnd.pxOld += 0.5 * pxRem;
     667           0 :   posEnd.pyOld += 0.5 * pyRem;
     668           0 :   negEnd.pxOld += 0.5 * pxRem;
     669           0 :   negEnd.pyOld += 0.5 * pyRem;
     670             : 
     671             :   // Construct new pT and mT of the final two particles.
     672           0 :   posEnd.pxHad  = posEnd.pxOld + posEnd.pxNew;
     673           0 :   posEnd.pyHad  = posEnd.pyOld + posEnd.pyNew;
     674           0 :   posEnd.mT2Had = pow2(posEnd.mHad) + pow2(posEnd.pxHad)
     675           0 :     + pow2(posEnd.pyHad);
     676           0 :   negEnd.pxHad  = negEnd.pxOld + negEnd.pxNew;
     677           0 :   negEnd.pyHad  = negEnd.pyOld + negEnd.pyNew;
     678           0 :   negEnd.mT2Had = pow2(negEnd.mHad) + pow2(negEnd.pxHad)
     679           0 :     + pow2(negEnd.pyHad);
     680             : 
     681             :   // Construct remaining system transverse mass.
     682           0 :   double wT2Rem = w2Rem + pow2( posEnd.pxHad + negEnd.pxHad)
     683           0 :     + pow2( posEnd.pyHad + negEnd.pyHad);
     684             : 
     685             :   // Check that kinematics possible.
     686           0 :   if ( sqrt(wT2Rem) < sqrt(posEnd.mT2Had) + sqrt(negEnd.mT2Had) )
     687           0 :     return false;
     688           0 :   double lambda2 = pow2( wT2Rem - posEnd.mT2Had - negEnd.mT2Had)
     689           0 :     - 4. * posEnd.mT2Had * negEnd.mT2Had;
     690           0 :   if (lambda2 <= 0.) return false;
     691             : 
     692             :   // Construct kinematics, as viewed in the transverse rest frame.
     693           0 :   double lambda = sqrt(lambda2);
     694           0 :   double probReverse = 1. / (1. + exp( min( EXPMAX, bLund * lambda) ) );
     695           0 :   double xpzPos = 0.5 * lambda/ wT2Rem;
     696           0 :   if (probReverse > rndmPtr->flat()) xpzPos = -xpzPos;
     697           0 :   double xmDiff = (posEnd.mT2Had - negEnd.mT2Had) / wT2Rem;
     698           0 :   double xePos  = 0.5 * (1. + xmDiff);
     699           0 :   double xeNeg  = 0.5 * (1. - xmDiff );
     700             : 
     701             :   // Translate this into kinematics in the string frame.
     702           0 :   Vec4 pHadPos = region.pHad( (xePos + xpzPos) *  xPosRem,
     703           0 :     (xePos - xpzPos) *  xNegRem, posEnd.pxHad, posEnd.pyHad);
     704           0 :   Vec4 pHadNeg = region.pHad( (xeNeg - xpzPos) *  xPosRem,
     705           0 :     (xeNeg + xpzPos) *  xNegRem, negEnd.pxHad, negEnd.pyHad);
     706             : 
     707             :   // Update status codes for junction baryons.
     708             :   int statusHadPos = 83;
     709             :   int statusHadNeg = 84;
     710             : 
     711           0 :   if (fromPos) {
     712           0 :     if (abs(posEnd.idHad) > 1000 && abs(posEnd.idHad) < 10000) {
     713           0 :       if (event[iPos].statusAbs() == 74 && !usedPosJun)  {
     714             :         statusHadPos = 87;
     715             :         usedPosJun = true;
     716           0 :       }
     717             :     }
     718           0 :     if (abs(idHad) > 1000 && abs(idHad) < 10000) {
     719           0 :       if ((!usedNegJun && (event[iNeg].statusAbs() == 74 || hasJunction))
     720           0 :           || (!usedPosJun && event[iPos].statusAbs() == 74)) {
     721             :         statusHadNeg = 88;
     722           0 :       }
     723             :     }
     724             :   } else {
     725           0 :     if (abs(negEnd.idHad) > 1000 && abs(negEnd.idHad) < 10000) {
     726           0 :         if (!usedNegJun && (event[iNeg].statusAbs() == 74 || hasJunction)) {
     727             :           statusHadNeg = 87;
     728             :           usedNegJun = true;
     729           0 :         }
     730             :       }
     731           0 :     if (abs(idHad) > 1000 && abs(idHad) < 10000) {
     732           0 :       if ((!usedNegJun && (event[iNeg].statusAbs() == 74 || hasJunction))
     733           0 :           || (!usedPosJun && event[iPos].statusAbs() == 74)) {
     734             :         statusHadPos = 88;
     735           0 :       }
     736             :     }
     737             :   }
     738             : 
     739             :   // Add produced particles to the event record.
     740           0 :   hadrons.append( posEnd.idHad, statusHadPos, posEnd.iEnd, negEnd.iEnd,
     741           0 :     0, 0, 0, 0, pHadPos, posEnd.mHad);
     742           0 :   hadrons.append( negEnd.idHad, statusHadNeg, posEnd.iEnd, negEnd.iEnd,
     743           0 :     0, 0, 0, 0, pHadNeg, negEnd.mHad);
     744             : 
     745             :   // It worked.
     746             :   return true;
     747             : 
     748           0 : }
     749             : 
     750             : //--------------------------------------------------------------------------
     751             : 
     752             : //  Construct a special joining region for the final two hadrons.
     753             : 
     754             : StringRegion StringFragmentation::finalRegion() {
     755             : 
     756             :   // Simple case when both string ends are in the same region.
     757           0 :   if (posEnd.iPosOld == negEnd.iPosOld && posEnd.iNegOld == negEnd.iNegOld)
     758           0 :     return system.region( posEnd.iPosOld, posEnd.iNegOld);
     759             : 
     760             :   // Start out with empty region. (Empty used for error returns.)
     761           0 :   StringRegion region;
     762             : 
     763             :   // Add up all remaining p+.
     764           0 :   Vec4 pPosJoin;
     765           0 :   if ( posEnd.iPosOld == negEnd.iPosOld) {
     766           0 :     double xPosJoin = posEnd.xPosOld - negEnd.xPosOld;
     767           0 :     if (xPosJoin < 0.) return region;
     768           0 :     pPosJoin = system.regionLowPos(posEnd.iPosOld).pHad( xPosJoin, 0., 0., 0.);
     769           0 :   } else {
     770           0 :     for (int iPosNow = posEnd.iPosOld; iPosNow <= negEnd.iPosOld; ++iPosNow) {
     771           0 :       if (iPosNow == posEnd.iPosOld) pPosJoin
     772           0 :         += system.regionLowPos(iPosNow).pHad( posEnd.xPosOld, 0., 0., 0.);
     773           0 :       else if (iPosNow == negEnd.iPosOld) pPosJoin
     774           0 :         += system.regionLowPos(iPosNow).pHad( 1. - negEnd.xPosOld, 0., 0., 0.);
     775           0 :       else pPosJoin += system.regionLowPos(iPosNow).pHad( 1., 0., 0., 0.);
     776             :     }
     777             :   }
     778             : 
     779             :   // Add up all remaining p-.
     780           0 :   Vec4 pNegJoin;
     781           0 :   if ( negEnd.iNegOld == posEnd.iNegOld) {
     782           0 :     double xNegJoin = negEnd.xNegOld - posEnd.xNegOld;
     783           0 :     if (xNegJoin < 0.) return region;
     784           0 :     pNegJoin = system.regionLowNeg(negEnd.iNegOld).pHad( 0., xNegJoin, 0., 0.);
     785           0 :   } else {
     786           0 :     for (int iNegNow = negEnd.iNegOld; iNegNow <= posEnd.iNegOld; ++iNegNow) {
     787           0 :       if (iNegNow == negEnd.iNegOld) pNegJoin
     788           0 :         += system.regionLowNeg(iNegNow).pHad( 0., negEnd.xNegOld, 0., 0.);
     789           0 :       else if (iNegNow == posEnd.iNegOld) pNegJoin
     790           0 :         += system.regionLowNeg(iNegNow).pHad( 0., 1. - posEnd.xNegOld, 0., 0.);
     791           0 :       else pNegJoin += system.regionLowNeg(iNegNow).pHad( 0., 1., 0., 0.);
     792             :     }
     793             :   }
     794             : 
     795             :   // For a closed gluon loop pPosJoin == pNegJoin and the above does not work.
     796             :   // So reshuffle; "perfect" for g g systems, OK in general.
     797           0 :   Vec4 pTest = pPosJoin - pNegJoin;
     798           0 :   if ( abs(pTest.px()) + abs(pTest.py()) + abs(pTest.pz()) + abs(pTest.e())
     799           0 :     < MATCHPOSNEG * (pPosJoin.e() + pNegJoin.e()) ) {
     800           0 :     Vec4 delta
     801           0 :       = system.regionLowPos(posEnd.iPosOld + 1).pHad( 1., 0., 0., 0.)
     802           0 :       - system.regionLowNeg(negEnd.iNegOld + 1).pHad( 0., 1., 0., 0.);
     803             :     // If reshuffle did not help then pick random axis to break tie.
     804             :     // (Needed for low-mass q-g-qbar with q-qbar perfectly parallel.)
     805           0 :     if ( abs(delta.px()) + abs(delta.py()) + abs(delta.pz()) + abs(delta.e())
     806           0 :       < MATCHPOSNEG * (pPosJoin.e() + pNegJoin.e()) ) {
     807           0 :       double cthe = 2. * rndmPtr->flat() - 1.;
     808           0 :       double sthe = sqrtpos(1. - cthe * cthe);
     809           0 :       double phi  = 2. * M_PI * rndmPtr->flat();
     810           0 :       delta = 0.5 * min( pPosJoin.e(), pNegJoin.e())
     811           0 :         * Vec4( sthe * sin(phi), sthe * cos(phi), cthe, 0.);
     812           0 :       infoPtr->errorMsg("Warning in StringFragmentation::finalRegion: "
     813             :         "random axis needed to break tie");
     814           0 :     }
     815           0 :     pPosJoin -= delta;
     816           0 :     pNegJoin += delta;
     817           0 :   }
     818             : 
     819             :   // Construct a new region from remaining p+ and p-.
     820           0 :   region.setUp( pPosJoin, pNegJoin);
     821           0 :   if (region.isEmpty) return region;
     822             : 
     823             :   // Project the existing pTold vectors onto the new directions.
     824           0 :   Vec4 pTposOld = system.region( posEnd.iPosOld, posEnd.iNegOld).pHad(
     825           0 :     0., 0.,  posEnd.pxOld, posEnd.pyOld);
     826           0 :   region.project( pTposOld);
     827           0 :   posEnd.pxOld = region.px();
     828           0 :   posEnd.pyOld = region.py();
     829           0 :   Vec4 pTnegOld = system.region( negEnd.iPosOld, negEnd.iNegOld).pHad(
     830           0 :       0., 0.,  negEnd.pxOld, negEnd.pyOld);
     831           0 :   region.project( pTnegOld);
     832           0 :   negEnd.pxOld = region.px();
     833           0 :   negEnd.pyOld = region.py();
     834             : 
     835             :   // Done.
     836           0 :   return region;
     837             : 
     838           0 : }
     839             : 
     840             : //--------------------------------------------------------------------------
     841             : 
     842             : // Store the hadrons in the normal event record, ordered from one end.
     843             : 
     844             : void StringFragmentation::store(Event& event) {
     845             : 
     846             :   // Starting position.
     847           0 :   int iFirst = event.size();
     848             : 
     849             :   // Copy straight over from first two junction legs.
     850           0 :   if (hasJunction) {
     851           0 :     for (int i = 0; i < hadrons.size(); ++i)
     852           0 :     if (hadrons[i].status() == 85 || hadrons[i].status() == 86)
     853           0 :       event.append( hadrons[i] );
     854           0 :   }
     855             : 
     856             :   // Loop downwards, copying all from the positive end.
     857           0 :   for (int i = 0; i < hadrons.size(); ++i)
     858           0 :     if (hadrons[i].status() == 83 || hadrons[i].status() == 87)
     859           0 :       event.append( hadrons[i] );
     860             : 
     861             :   // Loop upwards, copying all from the negative end.
     862           0 :   for (int i = hadrons.size() - 1; i >= 0 ; --i)
     863           0 :     if (hadrons[i].status() == 84 || hadrons[i].status() == 88)
     864           0 :       event.append( hadrons[i] );
     865             : 
     866           0 :   int iLast = event.size() - 1;
     867             : 
     868             :   // Set decay vertex when this is displaced.
     869           0 :   if (event[posEnd.iEnd].hasVertex()) {
     870           0 :     Vec4 vDec = event[posEnd.iEnd].vDec();
     871           0 :     for (int i = iFirst; i <= iLast; ++i) event[i].vProd( vDec );
     872           0 :   }
     873             : 
     874             :   // Set lifetime of hadrons.
     875           0 :   for (int i = iFirst; i <= iLast; ++i)
     876           0 :     event[i].tau( event[i].tau0() * rndmPtr->exp() );
     877             : 
     878             :   // Mark original partons as hadronized and set their daughter range.
     879           0 :   for (int i = 0; i < int(iParton.size()); ++i)
     880           0 :   if (iParton[i] >= 0) {
     881           0 :     event[ iParton[i] ].statusNeg();
     882           0 :     event[ iParton[i] ].daughters(iFirst, iLast);
     883           0 :   }
     884             : 
     885           0 : }
     886             : 
     887             : //--------------------------------------------------------------------------
     888             : 
     889             : // Fragment off two of the string legs in to a junction.
     890             : 
     891             : bool StringFragmentation::fragmentToJunction(Event& event) {
     892             : 
     893             :   // Identify range of partons on the three legs.
     894             :   // (Each leg begins with an iParton[i] = -(10 + 10*junctionNumber + leg),
     895             :   // and partons then appear ordered from the junction outwards.)
     896           0 :   int legBeg[3] = { 0, 0, 0};
     897           0 :   int legEnd[3] = { 0, 0, 0};
     898             :   int leg = -1;
     899             :   // PS (4/10/2011) Protect against invalid systems
     900           0 :   if (iParton[0] > 0) {
     901           0 :     infoPtr->errorMsg("Error in StringFragmentation::fragment"
     902             :                       "ToJunction: iParton[0] not a valid junctionNumber");
     903           0 :     return false;
     904             :   }
     905           0 :   for (int i = 0; i < int(iParton.size()); ++i) {
     906           0 :     if (iParton[i] < 0) {
     907           0 :       if (leg == 2) {
     908           0 :         infoPtr->errorMsg("Error in StringFragmentation::fragment"
     909             :                           "ToJunction: unprocessed multi-junction system");
     910           0 :         return false;
     911             :       }
     912           0 :       legBeg[++leg] = i + 1;
     913           0 :     }
     914           0 :     else legEnd[leg] = i;
     915             :   }
     916             : 
     917             :   // Iterate from system rest frame towards the junction rest frame (JRF).
     918           0 :   RotBstMatrix MtoJRF, Mstep;
     919           0 :   MtoJRF.bstback(pSum);
     920           0 :   Vec4 pWTinJRF[3];
     921             :   int iter = 0;
     922             :   double errInCM = 0.;
     923           0 :   do {
     924           0 :     ++iter;
     925             : 
     926             :     // Find weighted sum of momenta on the three sides of the junction.
     927           0 :     for (leg = 0; leg < 3; ++ leg) {
     928           0 :       pWTinJRF[leg] = 0.;
     929             :       double eWeight = 0.;
     930           0 :       for (int i = legBeg[leg]; i <= legEnd[leg]; ++i) {
     931           0 :         Vec4 pTemp = event[ iParton[i] ].p();
     932           0 :         pTemp.rotbst(MtoJRF);
     933           0 :         pWTinJRF[leg] += pTemp * exp(-eWeight);
     934           0 :         eWeight += pTemp.e() / eNormJunction;
     935           0 :         if (eWeight > EJNWEIGHTMAX) break;
     936           0 :       }
     937             :     }
     938             : 
     939             :     // Store original deviation from 120 degree topology.
     940           0 :     if (iter == 1) errInCM = pow2(costheta(pWTinJRF[0], pWTinJRF[1]) + 0.5)
     941           0 :       + pow2(costheta(pWTinJRF[0], pWTinJRF[2]) + 0.5)
     942           0 :       + pow2(costheta(pWTinJRF[1], pWTinJRF[2]) + 0.5);
     943             : 
     944             :     // Check that no two legs has unreasonably small invariant mass.
     945           0 :     if ( (pWTinJRF[0] + pWTinJRF[1]).m2Calc() < M2MINJRF
     946           0 :       || (pWTinJRF[0] + pWTinJRF[2]).m2Calc() < M2MINJRF
     947           0 :       || (pWTinJRF[1] + pWTinJRF[2]).m2Calc() < M2MINJRF ) {
     948           0 :       infoPtr->errorMsg("Error in StringFragmentation::fragmentToJunction: "
     949             :         "too small leg-leg invariant mass");
     950           0 :       return false;
     951             :     } 
     952             :     
     953             :     // Find new JRF from the set of weighted momenta.
     954           0 :     Mstep = junctionRestFrame( pWTinJRF[0], pWTinJRF[1], pWTinJRF[2]);
     955             :     // Fortran code will not take full step after the first few
     956             :     // iterations. How implement this in terms of an M matrix??
     957           0 :     MtoJRF.rotbst( Mstep );
     958           0 :   } while (iter < 3 || (Mstep.deviation() > CONVJNREST && iter < NTRYJNREST) );
     959             : 
     960             :   // If final deviation from 120 degrees is bigger than in CM then revert.
     961           0 :   double errInJRF = pow2(costheta(pWTinJRF[0], pWTinJRF[1]) + 0.5)
     962           0 :     + pow2(costheta(pWTinJRF[0], pWTinJRF[2]) + 0.5)
     963           0 :     + pow2(costheta(pWTinJRF[1], pWTinJRF[2]) + 0.5);
     964           0 :   if (errInJRF > errInCM + CONVJNREST) {
     965           0 :     infoPtr->errorMsg("Warning in StringFragmentation::fragmentTo"
     966             :       "Junction: bad convergence junction rest frame");
     967           0 :     MtoJRF.reset();
     968           0 :     MtoJRF.bstback(pSum);
     969           0 :   }
     970             : 
     971             :   // Opposite operation: boost from JRF to original system.
     972           0 :   RotBstMatrix MfromJRF = MtoJRF;
     973           0 :   MfromJRF.invert();
     974             : 
     975             :   // Sum leg four-momenta in original frame and in JRF.
     976           0 :   Vec4 pInLeg[3], pInJRF[3];
     977           0 :   for (leg = 0; leg < 3; ++leg) {
     978           0 :     pInLeg[leg] = 0.;
     979           0 :     for (int i = legBeg[leg]; i <= legEnd[leg]; ++i)
     980           0 :       pInLeg[leg] += event[ iParton[i] ].p();
     981           0 :     pInJRF[leg] = pInLeg[leg];
     982           0 :     pInJRF[leg].rotbst(MtoJRF);
     983             :   }
     984             : 
     985             :   // Pick the two legs with lowest energy in JRF.
     986           0 :   int legMin = (pInJRF[0].e() < pInJRF[1].e()) ? 0 : 1;
     987           0 :   int legMax = 1 - legMin;
     988           0 :   if (pInJRF[2].e() < min(pInJRF[0].e(), pInJRF[1].e()) ) legMin = 2;
     989           0 :   else if (pInJRF[2].e() > max(pInJRF[0].e(), pInJRF[1].e()) ) legMax = 2;
     990           0 :   int legMid = 3 - legMin - legMax;
     991             : 
     992             :   // Save info on which status codes belong with the three legs.
     993           0 :   int iJunction = (-iParton[0]) / 10 - 1;
     994           0 :   event.statusJunction( iJunction, legMin, 85);
     995           0 :   event.statusJunction( iJunction, legMid, 86);
     996           0 :   event.statusJunction( iJunction, legMax, 83);
     997             : 
     998             :   // Temporarily copy the partons on the low-energy legs, into the JRF,
     999             :   // in reverse order, so (anti)quark leg end first.
    1000           0 :   vector<int> iPartonMin;
    1001           0 :   for (int i = legEnd[legMin]; i >= legBeg[legMin]; --i) {
    1002           0 :     int iNew = event.append( event[ iParton[i] ] );
    1003           0 :     event[iNew].rotbst(MtoJRF);
    1004           0 :     iPartonMin.push_back( iNew );
    1005           0 :   }
    1006           0 :   vector<int> iPartonMid;
    1007           0 :   for (int i = legEnd[legMid]; i >= legBeg[legMid]; --i) {
    1008           0 :     int iNew = event.append( event[ iParton[i] ] );
    1009           0 :     event[iNew].rotbst(MtoJRF);
    1010           0 :     iPartonMid.push_back( iNew );
    1011           0 :   }
    1012             : 
    1013             :   // Find final weighted sum of momenta on each of the two legs.
    1014             :   double eWeight = 0.;
    1015           0 :   pWTinJRF[legMin] = 0.;
    1016           0 :   for (int i = iPartonMin.size() - 1; i >= 0; --i) {
    1017           0 :     pWTinJRF[legMin] += event[ iPartonMin[i] ].p() * exp(-eWeight);
    1018           0 :     eWeight += event[ iPartonMin[i] ].e() / eNormJunction;
    1019           0 :     if (eWeight > EJNWEIGHTMAX) break;
    1020             :   }
    1021             :   eWeight = 0.;
    1022           0 :   pWTinJRF[legMid] = 0.;
    1023           0 :   for (int i = iPartonMid.size() - 1; i >= 0; --i) {
    1024           0 :     pWTinJRF[legMid] += event[ iPartonMid[i] ].p() * exp(-eWeight);
    1025           0 :     eWeight += event[ iPartonMid[i] ].e() / eNormJunction;
    1026           0 :     if (eWeight > EJNWEIGHTMAX) break;
    1027             :   }
    1028             : 
    1029             :   // Define fictitious opposing partons in JRF and store as string ends.
    1030           0 :   Vec4 pOppose = pWTinJRF[legMin];
    1031           0 :   pOppose.flip3();
    1032           0 :   int idOppose = (rndmPtr->flat() > 0.5) ? 2 : 1;
    1033           0 :   if (event[ iPartonMin[0] ].col() > 0) idOppose = -idOppose;
    1034           0 :   int iOppose = event.append( idOppose, 77, 0, 0, 0, 0, 0, 0,
    1035           0 :     pOppose, 0.);
    1036           0 :   iPartonMin.push_back( iOppose);
    1037           0 :   pOppose = pWTinJRF[legMid];
    1038           0 :   pOppose.flip3();
    1039           0 :   idOppose = (rndmPtr->flat() > 0.5) ? 2 : 1;
    1040           0 :   if (event[ iPartonMid[0] ].col() > 0) idOppose = -idOppose;
    1041           0 :   iOppose = event.append( idOppose, 77, 0, 0, 0, 0, 0, 0,
    1042           0 :     pOppose, 0.);
    1043           0 :   iPartonMid.push_back( iOppose);
    1044             : 
    1045             :   // Set up kinematics of string evolution in low-energy temporary systems.
    1046           0 :   systemMin.setUp(iPartonMin, event);
    1047           0 :   systemMid.setUp(iPartonMid, event);
    1048             : 
    1049             :   // Outer fallback loop, when too little energy left for third leg.
    1050             :   int idMin = 0;
    1051             :   int idMid = 0;
    1052           0 :   Vec4 pDiquark;
    1053           0 :   for ( int iTryOuter = 0; ; ++iTryOuter) {
    1054             : 
    1055             :     // Middle fallback loop, when much unused energy in leg remnants.
    1056           0 :     double eLeftMin = 0.;
    1057           0 :     double eLeftMid = 0.;
    1058           0 :     for ( int iTryMiddle = 0; ; ++iTryMiddle) {
    1059             : 
    1060             :       // Loop over the two lowest-energy legs.
    1061           0 :       for (int legLoop = 0; legLoop < 2; ++ legLoop) {
    1062           0 :         int legNow = (legLoop == 0) ? legMin : legMid;
    1063             : 
    1064             :         // Read in properties specific to this leg.
    1065           0 :         StringSystem& systemNow = (legLoop == 0) ? systemMin : systemMid;
    1066           0 :         int idPos = (legLoop == 0) ? event[ iPartonMin[0] ].id()
    1067           0 :           : event[ iPartonMid[0] ].id();
    1068           0 :         idOppose = (legLoop == 0) ? event[ iPartonMin.back() ].id()
    1069           0 :           : event[ iPartonMid.back() ].id();
    1070           0 :         double eInJRF = pInJRF[legNow].e();
    1071           0 :         int statusHad = (legLoop == 0) ? 85 : 86;
    1072             : 
    1073             :         // Inner fallback loop, when a diquark comes in to junction.
    1074             :         double eUsed = 0.;
    1075           0 :         for ( int iTryInner = 0; ; ++iTryInner) {
    1076           0 :           if (iTryInner > 2 * NTRYJNMATCH) {
    1077           0 :             infoPtr->errorMsg("Error in StringFragmentation::fragment"
    1078             :               "ToJunction: caught in junction flavour loop");
    1079           0 :             event.popBack( iPartonMin.size() + iPartonMid.size() );
    1080           0 :             return false;
    1081             :           }
    1082           0 :           bool needBaryon = (abs(idPos) > 10 && iTryInner > NTRYJNMATCH);
    1083           0 :           double eExtra   = (iTryInner > NTRYJNMATCH) ? EEXTRAJNMATCH : 0.;
    1084             : 
    1085             :           // Set up two string ends, and begin fragmentation loop.
    1086           0 :           setStartEnds(idPos, idOppose, systemNow);
    1087             :           eUsed = 0.;
    1088             :           int nHadrons = 0;
    1089             :           bool noNegE = true;
    1090           0 :           for ( ; ; ++nHadrons) {
    1091             : 
    1092             :             // Construct trial hadron from positive end.
    1093           0 :             posEnd.newHadron();
    1094           0 :             Vec4 pHad = posEnd.kinematicsHadron(systemNow);
    1095             : 
    1096             :             // Negative energy signals failure in construction.
    1097           0 :             if (pHad.e() < 0. ) { noNegE = false; break; }
    1098             : 
    1099             :             // Break if passed system midpoint ( = junction) in energy.
    1100             :             // Exceptions: small systems, and/or with diquark end.
    1101             :             bool delayedBreak = false;
    1102           0 :             if (eUsed + pHad.e() + eExtra > eInJRF) {
    1103           0 :               if (nHadrons > 0 || !needBaryon) break;
    1104             :               delayedBreak = true;
    1105           0 :             }
    1106             : 
    1107             :             // Else construct kinematics of the new hadron and store it.
    1108           0 :             hadrons.append( posEnd.idHad, statusHad, iPos, iNeg,
    1109           0 :               0, 0, 0, 0, pHad, posEnd.mHad);
    1110             : 
    1111             :             // Update string end and remaining momentum.
    1112           0 :             posEnd.update();
    1113           0 :             eUsed += pHad.e();
    1114             : 
    1115             :             // Delayed break in small systems, and/or with diquark end.
    1116           0 :             if (delayedBreak) {
    1117           0 :               ++nHadrons;
    1118           0 :               break;
    1119             :             }
    1120           0 :           }
    1121             : 
    1122             :           // Possible to produce zero hadrons if the endpoint is not a diquark.
    1123           0 :           if (iTryInner > NTRYJNMATCH && !noNegE && nHadrons == 0 &&
    1124           0 :             abs(idPos) < 10) break;
    1125             : 
    1126             :           // End of fragmentation loop. Inner loopback if ends on a diquark.
    1127           0 :           if ( noNegE && abs(posEnd.flavOld.id) < 10 ) break;
    1128           0 :           hadrons.popBack(nHadrons);
    1129           0 :         }
    1130             : 
    1131             :         // End of one-leg fragmentation. Store end quark and remnant energy.
    1132           0 :         if (legNow == legMin) {
    1133           0 :           idMin = posEnd.flavOld.id;
    1134           0 :           eLeftMin = eInJRF - eUsed;
    1135           0 :         } else {
    1136             :           idMid = posEnd.flavOld.id;
    1137           0 :           eLeftMid = eInJRF - eUsed;
    1138             :         }
    1139           0 :       }
    1140             : 
    1141             :       // End of both-leg fragmentation.
    1142             :       // Middle loopback if too much energy left.
    1143           0 :       double eTrial = eBothLeftJunction + rndmPtr->flat() * eMaxLeftJunction;
    1144           0 :       if (iTryMiddle > NTRYJNMATCH
    1145           0 :         || ( min( eLeftMin, eLeftMid) < eBothLeftJunction
    1146           0 :         && max( eLeftMin, eLeftMid) < eTrial ) ) break;
    1147           0 :       hadrons.clear();
    1148           0 :     }
    1149             : 
    1150             :     // Boost hadrons away from the JRF to the original frame.
    1151           0 :     for (int i = 0; i < hadrons.size(); ++i) {
    1152           0 :       hadrons[i].rotbst(MfromJRF);
    1153             :       // Recalculate energy to compensate for numerical precision loss
    1154             :       // in iterative calculation of MfromJRF.
    1155           0 :       hadrons[i].e( hadrons[i].eCalc() );
    1156           0 :       pJunctionHadrons += hadrons[i].p();
    1157             :     }
    1158             : 
    1159             :     // Outer loopback if combined diquark mass too negative
    1160             :     // or too little energy left in third leg.
    1161           0 :     pDiquark = pInLeg[legMin] + pInLeg[legMid] - pJunctionHadrons;
    1162           0 :     double m2Left = m2( pInLeg[legMax], pDiquark);
    1163           0 :     if (iTryOuter >  NTRYJNMATCH || (pDiquark.mCalc() > MDIQUARKMIN
    1164           0 :       && m2Left > eMinLeftJunction * pInLeg[legMax].e()) ) break;
    1165           0 :     hadrons.clear();
    1166           0 :     pJunctionHadrons = 0.;
    1167           0 :   }
    1168             : 
    1169             :   // Now found solution; no more loopback. Remove temporary parton copies.
    1170           0 :   event.popBack( iPartonMin.size() + iPartonMid.size() );
    1171             : 
    1172             :   // Construct and store an effective diquark string end from the
    1173             :   // two remnant quark ends, for temporary usage.
    1174           0 :   int    idDiquark = flavSelPtr->makeDiquark( idMin, idMid);
    1175           0 :   double mDiquark  = pDiquark.mCalc();
    1176           0 :   int    iDiquark  = event.append( idDiquark, 78, 0, 0, 0, 0, 0, 0,
    1177           0 :     pDiquark, mDiquark);
    1178             : 
    1179             :   // Find the partons on the last leg, again in reverse order.
    1180           0 :   vector<int> iPartonMax;
    1181           0 :   for (int i = legEnd[legMax]; i >= legBeg[legMax]; --i)
    1182           0 :     iPartonMax.push_back( iParton[i] );
    1183           0 :   iPartonMax.push_back( iDiquark );
    1184             : 
    1185             :   // Recluster gluons nearby to diquark end when taken too much energy.
    1186           0 :   int iPsize       = iPartonMax.size();
    1187           0 :   double m0Diquark = event[iDiquark].m0();
    1188           0 :   while (iPsize > 2) {
    1189           0 :     Vec4 pGluNear = event[ iPartonMax[iPsize - 2] ].p();
    1190           0 :     if ( (pDiquark + 0.5 * pGluNear).mCalc() > m0Diquark + mJoin ) break;
    1191           0 :     pDiquark += pGluNear;
    1192           0 :     event[iDiquark].p( pDiquark );
    1193           0 :     event[iDiquark].m( pDiquark.mCalc() );
    1194           0 :     iPartonMax.pop_back();
    1195           0 :     --iPsize;
    1196           0 :     iPartonMax[iPsize - 1] = iDiquark;
    1197           0 :   }
    1198             : 
    1199             :   // Modify parton list to remaining leg + remnant of the first two.
    1200           0 :   iParton = iPartonMax;
    1201             : 
    1202             :   // Done.
    1203             :   return true;
    1204           0 : }
    1205             : 
    1206             : //--------------------------------------------------------------------------
    1207             : 
    1208             : // Find the boost matrix to the rest frame of a junction,
    1209             : // given the three respective endpoint four-momenta.
    1210             : 
    1211             : RotBstMatrix StringFragmentation::junctionRestFrame(Vec4& p0, Vec4& p1,
    1212             :   Vec4& p2) {
    1213             : 
    1214             :   // Calculate masses and other invariants.
    1215           0 :   Vec4 pSumJun  = p0 + p1 + p2;
    1216           0 :   double sHat   = pSumJun.m2Calc();
    1217           0 :   double pp[3][3];
    1218           0 :   pp[0][0]      = p0.m2Calc();
    1219           0 :   pp[1][1]      = p1.m2Calc();
    1220           0 :   pp[2][2]      = p2.m2Calc();
    1221           0 :   pp[0][1] = pp[1][0] = p0 * p1;
    1222           0 :   pp[0][2] = pp[2][0] = p0 * p2;
    1223           0 :   pp[1][2] = pp[2][1] = p1 * p2;
    1224             : 
    1225             :   // Requirement (eiMax)_j = pi*pj/mj < (eiMax)_k = pi*pk/mk, used below,
    1226             :   // here rewritten as pi*pj * mk < pi*pk * mj and squared.
    1227           0 :   double eMax01 = pow2(pp[0][1]) * pp[2][2];
    1228           0 :   double eMax02 = pow2(pp[0][2]) * pp[1][1];
    1229           0 :   double eMax12 = pow2(pp[1][2]) * pp[0][0];
    1230             : 
    1231             :   // Initially pick i to be the most massive parton. but allow other tries.
    1232           0 :   int i = (pp[1][1] > pp[0][0]) ? 1 : 0;
    1233           0 :   if (pp[2][2] > max(pp[0][0], pp[1][1])) i = 2;
    1234             :   int j, k;
    1235             :   double ei     = 0.;
    1236             :   double ej     = 0.;
    1237             :   double ek     = 0.;
    1238           0 :   for (int iTry = 0; iTry < 3; ++iTry) {
    1239             : 
    1240             :     // Pick j to give minimal eiMax, and k the third vector.
    1241           0 :     if (i == 0) j = (eMax02 < eMax01) ? 2 : 1;
    1242           0 :     else if (i == 1) j = (eMax12 < eMax01) ? 2 : 0;
    1243           0 :     else j = (eMax12 < eMax02) ? 1 : 0;
    1244           0 :     k = 3 - i - j;
    1245             : 
    1246             :     // Alternative names according to i, j, k conventions.
    1247           0 :     double m2i  = pp[i][i];
    1248           0 :     double m2j  = pp[j][j];
    1249           0 :     double m2k  = pp[k][k];
    1250           0 :     double pipj = pp[i][j];
    1251           0 :     double pipk = pp[i][k];
    1252           0 :     double pjpk = pp[j][k];
    1253             :     
    1254             :     // avoid too small or negative values
    1255           0 :     if (pipj < 1e-6)
    1256           0 :       pipj = 1e-6;
    1257           0 :     if (pipk < 1e-6)
    1258           0 :       pipk = 1e-6;
    1259           0 :     if (pjpk < 1e-6)
    1260           0 :       pjpk = 1e-6;
    1261             : 
    1262             :     // Trivial to find new parton energies if all three partons are massless.
    1263           0 :     if (m2i < M2MAXJRF) {
    1264           0 :       ei        = sqrt( 2. * pipk * pipj / (3. * pjpk) );
    1265           0 :       ej        = sqrt( 2. * pjpk * pipj / (3. * pipk) );
    1266           0 :       ek        = sqrt( 2. * pipk * pjpk / (3. * pipj) );
    1267             : 
    1268             :     // Else find three-momentum range for parton i and values at extremes.
    1269           0 :     } else {
    1270             :       // Minimum when i is at rest.
    1271             :       double piMin = 0.;
    1272           0 :       double eiMin = sqrt(m2i);
    1273           0 :       double ejMin = pipj / eiMin;
    1274           0 :       double ekMin = pipk / eiMin;
    1275           0 :       double pjMin = sqrtpos( ejMin*ejMin - m2j );
    1276           0 :       double pkMin = sqrtpos( ekMin*ekMin - m2k );
    1277           0 :       double fMin  = ejMin * ekMin + 0.5 * pjMin * pkMin - pjpk;
    1278             :       // Maximum estimated when j + k is at rest, alternatively j at rest.
    1279           0 :       double eiMax = (pipj + pipk) / sqrt(max(0., m2j) + max(0., m2k) + 2. * pjpk);
    1280           0 :       if (m2j > M2MAXJRF) eiMax = min( eiMax, pipj / sqrt(m2j) );
    1281           0 :       double piMax = sqrtpos( eiMax*eiMax - m2i );
    1282           0 :       double temp  = eiMax*eiMax - 0.25 *piMax*piMax;
    1283           0 :       double pjMax = (eiMax * sqrtpos( pipj*pipj - m2j * temp )
    1284           0 :         - 0.5 * piMax * pipj) / temp;
    1285           0 :       double pkMax = (eiMax * sqrtpos( pipk*pipk - m2k * temp )
    1286           0 :         - 0.5 * piMax * pipk) / temp;
    1287             :       double ejMax = 1e-06;
    1288           0 :       if(pjMax*pjMax + m2j > 1e-06) ejMax = sqrt(pjMax*pjMax + m2j);
    1289             :       double ekMax = 1e-06;
    1290           0 :       if(pkMax*pkMax + m2k > 1e-06) ekMax = sqrt(pkMax*pkMax + m2k);
    1291           0 :       double fMax  = ejMax * ekMax + 0.5 * pjMax * pkMax - pjpk;
    1292             : 
    1293             :       // If unexpected values at upper endpoint then pick another parton.
    1294           0 :       if (fMax > 0.) {
    1295           0 :         int iPrel = (i + 1)%3;
    1296           0 :         if (pp[iPrel][iPrel] > M2MAXJRF) {i = iPrel; continue;}
    1297           0 :         ++iTry;
    1298           0 :         iPrel = (i + 2)%3;
    1299           0 :         if (iTry < 3 && pp[iPrel][iPrel] > M2MAXJRF) {i = iPrel; continue;}
    1300           0 :       }
    1301             : 
    1302             :       // Start binary + linear search to find solution inside range.
    1303             :       int iterMin = 0;
    1304             :       int iterMax = 0;
    1305           0 :       double pi   = 0.5 * (piMin + piMax);
    1306           0 :       for (int iter = 0; iter < NTRYJRFEQ; ++iter) {
    1307             : 
    1308             :         // Derive momentum of other two partons and distance to root.
    1309           0 :         ei = sqrt(pi*pi + m2i);
    1310           0 :         temp = ei*ei - 0.25 * pi*pi;
    1311           0 :         double pj = (ei * sqrtpos( pipj*pipj - m2j * temp )
    1312           0 :           - 0.5 * pi * pipj) / temp;
    1313           0 :         double pk = (ei * sqrtpos( pipk*pipk - m2k * temp )
    1314           0 :           - 0.5 * pi * pipk) / temp;
    1315           0 :         ej = sqrt(pj*pj + max(0., m2j));
    1316           0 :         ek = sqrt(pk*pk + max(0., m2k));
    1317           0 :         double fNow = ej * ek + 0.5 * pj * pk - pjpk;
    1318             : 
    1319             :         // Replace lower or upper bound by new value.
    1320           0 :         if (fNow > 0.) { ++iterMin; piMin = pi; fMin = fNow;}
    1321           0 :         else {++iterMax; piMax = pi; fMax = fNow;}
    1322             : 
    1323             :         // Pick next i momentum to explore, hopefully closer to root.
    1324           0 :         if (2 * iter < NTRYJRFEQ
    1325           0 :           && (iterMin < 2 || iterMax < 2 || 4 * iter < NTRYJRFEQ))
    1326           0 :           { pi = 0.5 * (piMin + piMax); continue;}
    1327           0 :         if (fMin < 0. || fMax > 0. || abs(fNow) < CONVJRFEQ * sHat) break;
    1328           0 :         pi = piMin + (piMax - piMin) * fMin / (fMin - fMax);
    1329           0 :       }
    1330             : 
    1331             :     // If arrived here then either succeeded or exhausted possibilities.
    1332           0 :     } break;
    1333           0 :   }
    1334             : 
    1335             :   // Now we know the energies in the junction rest frame.
    1336           0 :   double eNew[3] = { 0., 0., 0.};
    1337           0 :   eNew[i] = ei;
    1338           0 :   eNew[j] = ej;
    1339           0 :   eNew[k] = ek;
    1340             : 
    1341             :   // Boost (copy of) partons to their rest frame.
    1342           0 :   RotBstMatrix Mmove;
    1343           0 :   Vec4 p0cm = p0;
    1344           0 :   Vec4 p1cm = p1;
    1345           0 :   Vec4 p2cm = p2;
    1346           0 :   Mmove.bstback(pSumJun);
    1347           0 :   p0cm.rotbst(Mmove);
    1348           0 :   p1cm.rotbst(Mmove);
    1349           0 :   p2cm.rotbst(Mmove);
    1350             : 
    1351             :   // Construct difference vectors and the boost to junction rest frame.
    1352           0 :   Vec4 pDir01      = p0cm / p0cm.e() - p1cm / p1cm.e();
    1353           0 :   Vec4 pDir02      = p0cm / p0cm.e() - p2cm / p2cm.e();
    1354           0 :   double pDiff01   = pDir01.pAbs2();
    1355           0 :   double pDiff02   = pDir02.pAbs2();
    1356           0 :   double pDiff0102 = dot3(pDir01, pDir02);
    1357           0 :   double eDiff01   = eNew[0] / p0cm.e() - eNew[1] / p1cm.e();
    1358           0 :   double eDiff02   = eNew[0] / p0cm.e() - eNew[2] / p2cm.e();
    1359           0 :   double denom     = max(1e-6, pDiff01 * pDiff02 - pDiff0102 * pDiff0102);
    1360           0 :   double coef01    = (eDiff01 * pDiff02 - eDiff02 * pDiff0102) / denom;
    1361           0 :   double coef02    = (eDiff02 * pDiff01 - eDiff01 * pDiff0102) / denom;
    1362           0 :   Vec4 vJunction   = coef01 * pDir01 + coef02 * pDir02;
    1363           0 :   vJunction.e( sqrt(1. + vJunction.pAbs2()) );
    1364             : 
    1365             :   // Add two boosts, giving final result.
    1366           0 :   Mmove.bst(vJunction);
    1367             :   return Mmove;
    1368             : 
    1369           0 : }
    1370             : 
    1371             : //--------------------------------------------------------------------------
    1372             : 
    1373             : // When string fragmentation has failed several times,
    1374             : // try to join some more nearby partons.
    1375             : 
    1376             : int StringFragmentation::extraJoin(double facExtra, Event& event) {
    1377             : 
    1378             :   // Keep on looping while pairs found below joining threshold.
    1379             :   int nJoin  = 0;
    1380           0 :   int iPsize = iParton.size();
    1381           0 :   while (iPsize > 2) {
    1382             : 
    1383             :     // Look for the pair of neighbour partons (along string) with
    1384             :     // the smallest invariant mass (subtracting quark masses).
    1385             :     int iJoinMin    = -1;
    1386           0 :     double mJoinMin = 2. * facExtra * mJoin;
    1387           0 :     for (int i = 0; i < iPsize - 1; ++i) {
    1388           0 :       Particle& parton1 = event[ iParton[i] ];
    1389           0 :       Particle& parton2 = event[ iParton[i + 1] ];
    1390           0 :       Vec4 pSumNow;
    1391           0 :       pSumNow += (parton2.isGluon()) ? 0.5 * parton1.p() : parton1.p();
    1392           0 :       pSumNow += (parton2.isGluon()) ? 0.5 * parton2.p() : parton2.p();
    1393           0 :       double mJoinNow = pSumNow.mCalc();
    1394           0 :       if (!parton1.isGluon()) mJoinNow -= parton1.m0();
    1395           0 :       if (!parton2.isGluon()) mJoinNow -= parton2.m0();
    1396           0 :       if (mJoinNow < mJoinMin) { iJoinMin = i; mJoinMin = mJoinNow; }
    1397           0 :     }
    1398             : 
    1399             :     // Decide whether to join, if not finished.
    1400           0 :     if (iJoinMin < 0 || mJoinMin > facExtra * mJoin) return nJoin;
    1401           0 :     ++nJoin;
    1402             : 
    1403             :     // Create new joined parton.
    1404           0 :     int iJoin1  = iParton[iJoinMin];
    1405           0 :     int iJoin2  = iParton[iJoinMin + 1];
    1406           0 :     int idNew   = (event[iJoin1].isGluon()) ? event[iJoin2].id()
    1407           0 :                                             : event[iJoin1].id();
    1408           0 :     int colNew  = event[iJoin1].col();
    1409           0 :     int acolNew = event[iJoin2].acol();
    1410           0 :     if (colNew == acolNew) {
    1411           0 :       colNew    = event[iJoin2].col();
    1412           0 :       acolNew   = event[iJoin1].acol();
    1413           0 :     }
    1414           0 :     Vec4 pNew   = event[iJoin1].p() + event[iJoin2].p();
    1415             : 
    1416             :     // Append joined parton to event record and reduce parton list.
    1417           0 :     int iNew = event.append( idNew, 73, min(iJoin1, iJoin2),
    1418           0 :       max(iJoin1, iJoin2), 0, 0, colNew, acolNew, pNew, pNew.mCalc() );
    1419           0 :     iParton[iJoinMin] = iNew;
    1420           0 :     for (int i = iJoinMin + 1; i < iPsize - 1; ++i)
    1421           0 :       iParton[i] = iParton[i + 1];
    1422           0 :     iParton.pop_back();
    1423           0 :     --iPsize;
    1424             : 
    1425             :   // Done.
    1426           0 :   }
    1427           0 :   return nJoin;
    1428           0 : }
    1429             : 
    1430             : //==========================================================================
    1431             : 
    1432             : } // end namespace Pythia8

Generated by: LCOV version 1.11