LCOV - code coverage report
Current view: top level - PYTHIA8/pythia8210dev/src - PhaseSpace.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 2319 0.1 %
Date: 2016-06-14 17:26:59 Functions: 2 45 4.4 %

          Line data    Source code
       1             : // PhaseSpace.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             : // PhaseSpace and PhaseSpace2to2tauyz classes.
       8             : 
       9             : #include "Pythia8/PhaseSpace.h"
      10             : 
      11             : namespace Pythia8 {
      12             : 
      13             : //==========================================================================
      14             : 
      15             : // The PhaseSpace class.
      16             : // Base class for phase space generators.
      17             : 
      18             : //--------------------------------------------------------------------------
      19             : 
      20             : // Constants: could be changed here if desired, but normally should not.
      21             : // These are of technical nature, as described for each.
      22             : 
      23             : // Number of trial maxima around which maximum search is performed.
      24             : const int    PhaseSpace::NMAXTRY        = 2;
      25             : 
      26             : // Number of three-body trials in phase space optimization.
      27             : const int    PhaseSpace::NTRY3BODY      = 20;
      28             : 
      29             : // Maximum cross section increase, just in case true maximum not found.
      30             : const double PhaseSpace::SAFETYMARGIN   = 1.05;
      31             : 
      32             : // Small number to avoid division by zero.
      33             : const double PhaseSpace::TINY           = 1e-20;
      34             : 
      35             : // Fraction of total weight that is shared evenly between all shapes.
      36             : const double PhaseSpace::EVENFRAC       = 0.4;
      37             : 
      38             : // Two cross sections with a small relative error are assumed same.
      39             : const double PhaseSpace::SAMESIGMA      = 1e-6;
      40             : 
      41             : // Do not include resonances peaked too far outside allowed mass region.
      42             : const double PhaseSpace::WIDTHMARGIN    = 20.;
      43             : 
      44             : // Special optimization treatment when two resonances at almost same mass.
      45             : const double PhaseSpace::SAMEMASS       = 0.01;
      46             : 
      47             : // Minimum phase space left when kinematics constraints are combined.
      48             : const double PhaseSpace::MASSMARGIN     = 0.01;
      49             : 
      50             : // When using Breit-Wigners in 2 -> 2 raise maximum weight estimate.
      51             : const double PhaseSpace::EXTRABWWTMAX   = 1.25;
      52             : 
      53             : // Size of Breit-Wigner threshold region, for mass selection biasing.
      54             : const double PhaseSpace::THRESHOLDSIZE  = 3.;
      55             : 
      56             : // Step size in optimal-mass search, for mass selection biasing.
      57             : const double PhaseSpace::THRESHOLDSTEP  = 0.2;
      58             : 
      59             : // Minimal rapidity range for allowed open range (in 2 -> 3).
      60             : const double PhaseSpace::YRANGEMARGIN  = 1e-6;
      61             : 
      62             : // Cutoff for f_e^e at x < 1 - 10^{-10} to be used in phase space selection.
      63             : // Note: the ...MIN quantities come from 1 - x_max or 1 - tau_max.
      64             : const double PhaseSpace::LEPTONXMIN     = 1e-10;
      65             : const double PhaseSpace::LEPTONXMAX     = 1. - 1e-10;
      66           6 : const double PhaseSpace::LEPTONXLOGMIN  = log(1e-10);
      67           6 : const double PhaseSpace::LEPTONXLOGMAX  = log(1. - 1e-10);
      68             : const double PhaseSpace::LEPTONTAUMIN   = 2e-10;
      69             : 
      70             : // Safety to avoid division with unreasonably small value for z selection.
      71             : const double PhaseSpace::SHATMINZ       = 1.;
      72             : 
      73             : // Regularization for small pT2min in z = cos(theta) selection.
      74             : const double PhaseSpace::PT2RATMINZ     = 0.0001;
      75             : 
      76             : // These numbers are hardwired empirical parameters,
      77             : // intended to speed up the M-generator.
      78             : const double PhaseSpace::WTCORRECTION[11] = { 1., 1., 1.,
      79             :   2., 5., 15., 60., 250., 1250., 7000., 50000. };
      80             : 
      81             : // MBR: form factor appoximation with two exponents, [FFB1,FFB2] = GeV-2.
      82             : const double PhaseSpace::FFA1 = 0.9;
      83             : const double PhaseSpace::FFA2 = 0.1;
      84             : const double PhaseSpace::FFB1 = 4.6;
      85             : const double PhaseSpace::FFB2 = 0.6;
      86             : 
      87             : //--------------------------------------------------------------------------
      88             : 
      89             : // Perform simple initialization and store pointers.
      90             : 
      91             : void PhaseSpace::init(bool isFirst, SigmaProcess* sigmaProcessPtrIn,
      92             :   Info* infoPtrIn, Settings* settingsPtrIn, ParticleData* particleDataPtrIn,
      93             :   Rndm* rndmPtrIn, BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn,
      94             :   Couplings* couplingsPtrIn, SigmaTotal* sigmaTotPtrIn,
      95             :   UserHooks* userHooksPtrIn) {
      96             : 
      97             :   // Store input pointers for future use.
      98           0 :   sigmaProcessPtr = sigmaProcessPtrIn;
      99           0 :   infoPtr         = infoPtrIn;
     100           0 :   settingsPtr     = settingsPtrIn;
     101           0 :   particleDataPtr = particleDataPtrIn;
     102           0 :   rndmPtr         = rndmPtrIn;
     103           0 :   beamAPtr        = beamAPtrIn;
     104           0 :   beamBPtr        = beamBPtrIn;
     105           0 :   couplingsPtr    = couplingsPtrIn;
     106           0 :   sigmaTotPtr     = sigmaTotPtrIn;
     107           0 :   userHooksPtr    = userHooksPtrIn;
     108             : 
     109             :   // Some commonly used beam information.
     110           0 :   idA             = beamAPtr->id();
     111           0 :   idB             = beamBPtr->id();
     112           0 :   mA              = beamAPtr->m();
     113           0 :   mB              = beamBPtr->m();
     114           0 :   eCM             = infoPtr->eCM();
     115           0 :   s               = eCM * eCM;
     116             : 
     117             :   // Flag if lepton beams, and if non-resolved ones.
     118           0 :   hasLeptonBeamA      = beamAPtr->isLepton();
     119           0 :   hasLeptonBeamB      = beamBPtr->isLepton();
     120           0 :   hasTwoLeptonBeams   = hasLeptonBeamA && hasLeptonBeamB;
     121           0 :   hasOneLeptonBeam = (hasLeptonBeamA || hasLeptonBeamB) && !hasTwoLeptonBeams;
     122           0 :   bool hasPointLepton = (hasLeptonBeamA && beamAPtr->isUnresolved())
     123           0 :                      || (hasLeptonBeamB && beamBPtr->isUnresolved());
     124           0 :   hasOnePointLepton   = hasOneLeptonBeam  && hasPointLepton;
     125           0 :   hasTwoPointLeptons  = hasTwoLeptonBeams && hasPointLepton;
     126             : 
     127             :   // Standard phase space cuts.
     128           0 :   if (isFirst || settingsPtr->flag("PhaseSpace:sameForSecond")) {
     129           0 :     mHatGlobalMin      = settingsPtr->parm("PhaseSpace:mHatMin");
     130           0 :     mHatGlobalMax      = settingsPtr->parm("PhaseSpace:mHatMax");
     131           0 :     pTHatGlobalMin     = settingsPtr->parm("PhaseSpace:pTHatMin");
     132           0 :     pTHatGlobalMax     = settingsPtr->parm("PhaseSpace:pTHatMax");
     133             : 
     134             :   // Optionally separate phase space cuts for second hard process.
     135           0 :   } else {
     136           0 :     mHatGlobalMin      = settingsPtr->parm("PhaseSpace:mHatMinSecond");
     137           0 :     mHatGlobalMax      = settingsPtr->parm("PhaseSpace:mHatMaxSecond");
     138           0 :     pTHatGlobalMin     = settingsPtr->parm("PhaseSpace:pTHatMinSecond");
     139           0 :     pTHatGlobalMax     = settingsPtr->parm("PhaseSpace:pTHatMaxSecond");
     140             :   }
     141             : 
     142             :   // Cutoff against divergences at pT -> 0.
     143           0 :   pTHatMinDiverge      = settingsPtr->parm("PhaseSpace:pTHatMinDiverge");
     144             : 
     145             :   // When to use Breit-Wigners.
     146           0 :   useBreitWigners      = settingsPtr->flag("PhaseSpace:useBreitWigners");
     147           0 :   minWidthBreitWigners = settingsPtr->parm("PhaseSpace:minWidthBreitWigners");
     148             : 
     149             :   // Whether generation is with variable energy.
     150           0 :   doEnergySpread       = settingsPtr->flag("Beams:allowMomentumSpread");
     151             : 
     152             :   // Flags for maximization information and violation handling.
     153           0 :   showSearch           = settingsPtr->flag("PhaseSpace:showSearch");
     154           0 :   showViolation        = settingsPtr->flag("PhaseSpace:showViolation");
     155           0 :   increaseMaximum      = settingsPtr->flag("PhaseSpace:increaseMaximum");
     156             : 
     157             :   // Know whether a Z0 is pure Z0 or admixed with gamma*.
     158           0 :   gmZmodeGlobal        = settingsPtr->mode("WeakZ0:gmZmode");
     159             : 
     160             :   // Flags if user should be allowed to reweight cross section.
     161           0 :   canModifySigma   = (userHooksPtr != 0)
     162           0 :                    ? userHooksPtr->canModifySigma() : false;
     163           0 :   canBiasSelection = (userHooksPtr != 0)
     164           0 :                    ? userHooksPtr->canBiasSelection() : false;
     165             : 
     166             :   // Parameters for simplified reweighting of 2 -> 2 processes.
     167           0 :   canBias2Sel      = settingsPtr->flag("PhaseSpace:bias2Selection");
     168           0 :   bias2SelPow      = settingsPtr->parm("PhaseSpace:bias2SelectionPow");
     169           0 :   bias2SelRef      = settingsPtr->parm("PhaseSpace:bias2SelectionRef");
     170             : 
     171             :   // Default event-specific kinematics properties.
     172           0 :   x1H             = 1.;
     173           0 :   x2H             = 1.;
     174           0 :   m3              = 0.;
     175           0 :   m4              = 0.;
     176           0 :   m5              = 0.;
     177           0 :   s3              = m3 * m3;
     178           0 :   s4              = m4 * m4;
     179           0 :   s5              = m5 * m5;
     180           0 :   mHat            = eCM;
     181           0 :   sH              = s;
     182           0 :   tH              = 0.;
     183           0 :   uH              = 0.;
     184           0 :   pTH             = 0.;
     185           0 :   theta           = 0.;
     186           0 :   phi             = 0.;
     187           0 :   runBW3H         = 1.;
     188           0 :   runBW4H         = 1.;
     189           0 :   runBW5H         = 1.;
     190             : 
     191             :   // Default cross section information.
     192           0 :   sigmaNw         = 0.;
     193           0 :   sigmaMx         = 0.;
     194           0 :   sigmaPos        = 0.;
     195           0 :   sigmaNeg        = 0.;
     196           0 :   newSigmaMx      = false;
     197           0 :   biasWt          = 1.;
     198             : 
     199           0 : }
     200             : 
     201             : //--------------------------------------------------------------------------
     202             : 
     203             : // Allow for nonisotropic decays when ME's available.
     204             : 
     205             : void PhaseSpace::decayKinematics( Event& process) {
     206             : 
     207             :   // Identify sets of sister partons.
     208             :   int iResEnd = 4;
     209           0 :   for (int iResBeg = 5; iResBeg < process.size(); ++iResBeg) {
     210           0 :     if (iResBeg <= iResEnd) continue;
     211             :     iResEnd = iResBeg;
     212           0 :     while ( iResEnd < process.size() - 1
     213           0 :       && process[iResEnd + 1].mother1() == process[iResBeg].mother1()
     214           0 :       && process[iResEnd + 1].mother2() == process[iResBeg].mother2() )
     215             :       ++iResEnd;
     216             : 
     217             :     // Check that at least one of them is a resonance.
     218             :     bool hasRes = false;
     219           0 :     for (int iRes = iResBeg; iRes <= iResEnd; ++iRes)
     220           0 :       if ( !process[iRes].isFinal() ) hasRes = true;
     221           0 :     if ( !hasRes ) continue;
     222             : 
     223             :     // Evaluate matrix element and decide whether to keep kinematics.
     224           0 :     double decWt = sigmaProcessPtr->weightDecay( process, iResBeg, iResEnd);
     225           0 :     if (decWt < 0.) infoPtr->errorMsg("Warning in PhaseSpace::decay"
     226             :       "Kinematics: negative angular weight");
     227           0 :     if (decWt > 1.) infoPtr->errorMsg("Warning in PhaseSpace::decay"
     228             :       "Kinematics: angular weight above unity");
     229           0 :     while (decWt < rndmPtr->flat() ) {
     230             : 
     231             :       // Find resonances for which to redo decay angles.
     232           0 :       for (int iRes = iResBeg; iRes < process.size(); ++iRes) {
     233           0 :         if ( process[iRes].isFinal() ) continue;
     234             :         int iResMother = iRes;
     235           0 :         while (iResMother > iResEnd)
     236           0 :           iResMother = process[iResMother].mother1();
     237           0 :         if (iResMother < iResBeg) continue;
     238             : 
     239             :         // Do decay of this mother isotropically in phase space.
     240           0 :         decayKinematicsStep( process, iRes);
     241             : 
     242             :       // End loop over resonance decay chains.
     243           0 :       }
     244             : 
     245             :       // Ready to allow new test of matrix element.
     246           0 :       decWt = sigmaProcessPtr->weightDecay( process, iResBeg, iResEnd);
     247           0 :       if (decWt < 0.) infoPtr->errorMsg("Warning in PhaseSpace::decay"
     248             :         "Kinematics: negative angular weight");
     249           0 :       if (decWt > 1.) infoPtr->errorMsg("Warning in PhaseSpace::decay"
     250             :         "Kinematics: angular weight above unity");
     251             :     }
     252             : 
     253             :   // End loop over sets of sister resonances/partons.
     254           0 :   }
     255             : 
     256           0 : }
     257             : 
     258             : //--------------------------------------------------------------------------
     259             : 
     260             : // Reselect decay products momenta isotropically in phase space.
     261             : // Does not redo secondary vertex position!
     262             : 
     263             : void PhaseSpace::decayKinematicsStep( Event& process, int iRes) {
     264             : 
     265             :    // Multiplicity and mother mass and four-momentum.
     266           0 :    int    i1   = process[iRes].daughter1();
     267           0 :    int    mult = process[iRes].daughter2() + 1 - i1;
     268           0 :    double m0   = process[iRes].m();
     269           0 :    Vec4   pRes = process[iRes].p();
     270             : 
     271             :   // Description of two-body decays as simple special case.
     272           0 :   if (mult == 2) {
     273             : 
     274             :     // Products and product masses.
     275           0 :     int    i2   = i1 + 1;
     276           0 :     double m1t  = process[i1].m();
     277           0 :     double m2t  = process[i2].m();
     278             : 
     279             :     // Energies and absolute momentum in the rest frame.
     280           0 :     double e1   = 0.5 * (m0*m0 + m1t*m1t - m2t*m2t) / m0;
     281           0 :     double e2   = 0.5 * (m0*m0 + m2t*m2t - m1t*m1t) / m0;
     282           0 :     double p12  = 0.5 * sqrtpos( (m0 - m1t - m2t) * (m0 + m1t + m2t)
     283           0 :       * (m0 + m1t - m2t) * (m0 - m1t + m2t) ) / m0;
     284             : 
     285             :     // Pick isotropic angles to give three-momentum.
     286           0 :     double cosTheta = 2. * rndmPtr->flat() - 1.;
     287           0 :     double sinTheta = sqrt(1. - cosTheta*cosTheta);
     288           0 :     double phi12    = 2. * M_PI * rndmPtr->flat();
     289           0 :     double pX       = p12 * sinTheta * cos(phi12);
     290           0 :     double pY       = p12 * sinTheta * sin(phi12);
     291           0 :     double pZ       = p12 * cosTheta;
     292             : 
     293             :     // Fill four-momenta in mother rest frame and then boost to lab frame.
     294           0 :     Vec4 p1(  pX,  pY,  pZ, e1);
     295           0 :     Vec4 p2( -pX, -pY, -pZ, e2);
     296           0 :     p1.bst( pRes );
     297           0 :     p2.bst( pRes );
     298             : 
     299             :     // Done for two-body decay.
     300           0 :     process[i1].p( p1 );
     301           0 :     process[i2].p( p2 );
     302             :     return;
     303           0 :   }
     304             : 
     305             :   // Description of three-body decays as semi-simple special case.
     306           0 :   if (mult == 3) {
     307             : 
     308             :     // Products and product masses.
     309           0 :     int    i2      = i1 + 1;
     310           0 :     int    i3      = i2 + 1;
     311           0 :     double m1t     = process[i1].m();
     312           0 :     double m2t     = process[i2].m();
     313           0 :     double m3t     = process[i3].m();
     314           0 :     double mDiff   = m0 - (m1t + m2t + m3t);
     315             : 
     316             :     // Kinematical limits for 2+3 mass. Maximum phase-space weight.
     317           0 :     double m23Min  = m2t + m3t;
     318           0 :     double m23Max  = m0 - m1t;
     319           0 :     double p1Max   = 0.5 * sqrtpos( (m0 - m1t - m23Min)
     320           0 :       * (m0 + m1t + m23Min) * (m0 + m1t - m23Min)
     321           0 :       * (m0 - m1t + m23Min) ) / m0;
     322           0 :     double p23Max  = 0.5 * sqrtpos( (m23Max - m2t - m3t)
     323           0 :       * (m23Max + m2t + m3t) * (m23Max + m2t - m3t)
     324           0 :       * (m23Max - m2t + m3t) ) / m23Max;
     325           0 :     double wtPSmax = 0.5 * p1Max * p23Max;
     326             : 
     327             :     // Pick an intermediate mass m23 flat in the allowed range.
     328             :     double wtPS, m23, p1Abs, p23Abs;
     329           0 :     do {
     330           0 :       m23 = m23Min + rndmPtr->flat() * mDiff;
     331             : 
     332             :       // Translate into relative momenta and find phase-space weight.
     333           0 :       p1Abs  = 0.5 * sqrtpos( (m0 - m1t - m23) * (m0 + m1t + m23)
     334           0 :         * (m0 + m1t - m23) * (m0 - m1t + m23) ) / m0;
     335           0 :       p23Abs = 0.5 * sqrtpos( (m23 - m2t - m3t) * (m23 + m2t + m3t)
     336           0 :         * (m23 + m2t - m3t) * (m23 - m2t + m3t) ) / m23;
     337           0 :       wtPS   = p1Abs * p23Abs;
     338             : 
     339             :     // If rejected, try again with new invariant masses.
     340           0 :     } while ( wtPS < rndmPtr->flat() * wtPSmax );
     341             : 
     342             :     // Set up m23 -> m2 + m3 isotropic in its rest frame.
     343           0 :     double cosTheta = 2. * rndmPtr->flat() - 1.;
     344           0 :     double sinTheta = sqrt(1. - cosTheta*cosTheta);
     345           0 :     double phi23    = 2. * M_PI * rndmPtr->flat();
     346           0 :     double pX       = p23Abs * sinTheta * cos(phi23);
     347           0 :     double pY       = p23Abs * sinTheta * sin(phi23);
     348           0 :     double pZ       = p23Abs * cosTheta;
     349           0 :     double e2       = sqrt( m2t*m2t + p23Abs*p23Abs);
     350           0 :     double e3       = sqrt( m3t*m3t + p23Abs*p23Abs);
     351           0 :     Vec4 p2(  pX,  pY,  pZ, e2);
     352           0 :     Vec4 p3( -pX, -pY, -pZ, e3);
     353             : 
     354             :     // Set up 0 -> 1 + 23 isotropic in its rest frame.
     355           0 :     cosTheta        = 2. * rndmPtr->flat() - 1.;
     356           0 :     sinTheta        = sqrt(1. - cosTheta*cosTheta);
     357           0 :     phi23           = 2. * M_PI * rndmPtr->flat();
     358           0 :     pX              = p1Abs * sinTheta * cos(phi23);
     359           0 :     pY              = p1Abs * sinTheta * sin(phi23);
     360           0 :     pZ              = p1Abs * cosTheta;
     361           0 :     double e1       = sqrt( m1t*m1t + p1Abs*p1Abs);
     362           0 :     double e23      = sqrt( m23*m23 + p1Abs*p1Abs);
     363           0 :     Vec4 p1( pX, pY, pZ, e1);
     364             : 
     365             :     // Boost 2 + 3 to the 0 rest frame and then boost to lab frame.
     366           0 :     Vec4 p23( -pX, -pY, -pZ, e23);
     367           0 :     p2.bst( p23 );
     368           0 :     p3.bst( p23 );
     369           0 :     p1.bst( pRes );
     370           0 :     p2.bst( pRes );
     371           0 :     p3.bst( pRes );
     372             : 
     373             :     // Done for three-body decay.
     374           0 :     process[i1].p( p1 );
     375           0 :     process[i2].p( p2 );
     376           0 :     process[i3].p( p3 );
     377             :     return;
     378           0 :   }
     379             : 
     380             :   // Do a multibody decay using the M-generator algorithm.
     381             : 
     382             :   // Set up masses and four-momenta in a vector, with mother in slot 0.
     383           0 :   vector<double> mProd;
     384           0 :   mProd.push_back( m0);
     385           0 :   for (int i = i1; i <= process[iRes].daughter2(); ++i)
     386           0 :     mProd.push_back( process[i].m() );
     387           0 :   vector<Vec4> pProd;
     388           0 :   pProd.push_back( pRes);
     389             : 
     390             :   // Sum of daughter masses.
     391           0 :   double mSum    = mProd[1];
     392           0 :   for (int i = 2; i <= mult; ++i) mSum += mProd[i];
     393           0 :   double mDiff   = m0 - mSum;
     394             : 
     395             :   // Begin setup of intermediate invariant masses.
     396           0 :   vector<double> mInv;
     397           0 :   for (int i = 0; i <= mult; ++i) mInv.push_back( mProd[i]);
     398             : 
     399             :   // Calculate the maximum weight in the decay.
     400           0 :   double wtPSmax = 1. / WTCORRECTION[mult];
     401           0 :   double mMaxWT  = mDiff + mProd[mult];
     402             :   double mMinWT  = 0.;
     403           0 :   for (int i = mult - 1; i > 0; --i) {
     404           0 :     mMaxWT      += mProd[i];
     405           0 :     mMinWT      += mProd[i+1];
     406           0 :     double mNow  = mProd[i];
     407           0 :     wtPSmax *= 0.5 * sqrtpos( (mMaxWT - mMinWT - mNow)
     408           0 :       * (mMaxWT + mMinWT + mNow) * (mMaxWT + mMinWT - mNow)
     409           0 :       * (mMaxWT - mMinWT + mNow) ) / mMaxWT;
     410             :   }
     411             : 
     412             :   // Begin loop to find the set of intermediate invariant masses.
     413           0 :   vector<double> rndmOrd;
     414             :   double wtPS;
     415           0 :   do {
     416             :     wtPS  = 1.;
     417             : 
     418             :     // Find and order random numbers in descending order.
     419           0 :     rndmOrd.resize(0);
     420           0 :     rndmOrd.push_back(1.);
     421           0 :     for (int i = 1; i < mult - 1; ++i) {
     422           0 :       double rndm = rndmPtr->flat();
     423           0 :       rndmOrd.push_back(rndm);
     424           0 :       for (int j = i - 1; j > 0; --j) {
     425           0 :         if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] );
     426           0 :         else break;
     427             :       }
     428           0 :     }
     429           0 :     rndmOrd.push_back(0.);
     430             : 
     431             :     // Translate into intermediate masses and find weight.
     432           0 :     for (int i = mult - 1; i > 0; --i) {
     433           0 :       mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff;
     434           0 :       wtPS   *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i])
     435           0 :         * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i])
     436           0 :         * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i];
     437             :     }
     438             : 
     439             :   // If rejected, try again with new invariant masses.
     440           0 :   } while ( wtPS < rndmPtr->flat() * wtPSmax );
     441             : 
     442             :   // Perform two-particle decays in the respective rest frame.
     443           0 :   vector<Vec4> pInv;
     444           0 :   pInv.resize(mult + 1);
     445           0 :   for (int i = 1; i < mult; ++i) {
     446           0 :     double p12 = 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i])
     447           0 :       * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i])
     448           0 :       * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i];
     449             : 
     450             :     // Isotropic angles give three-momentum.
     451           0 :     double cosTheta = 2. * rndmPtr->flat() - 1.;
     452           0 :     double sinTheta = sqrt(1. - cosTheta*cosTheta);
     453           0 :     double phiLoc   = 2. * M_PI * rndmPtr->flat();
     454           0 :     double pX       = p12 * sinTheta * cos(phiLoc);
     455           0 :     double pY       = p12 * sinTheta * sin(phiLoc);
     456           0 :     double pZ       = p12 * cosTheta;
     457             : 
     458             :     // Calculate energies, fill four-momenta.
     459           0 :     double eHad     = sqrt( mProd[i]*mProd[i] + p12*p12);
     460           0 :     double eInv     = sqrt( mInv[i+1]*mInv[i+1] + p12*p12);
     461           0 :     pProd.push_back( Vec4( pX, pY, pZ, eHad) );
     462           0 :     pInv[i+1].p( -pX, -pY, -pZ, eInv);
     463             :   }
     464           0 :   pProd.push_back( pInv[mult] );
     465             : 
     466             :   // Boost decay products to the mother rest frame and on to lab frame.
     467           0 :   pInv[1] = pProd[0];
     468           0 :   for (int iFrame = mult - 1; iFrame > 0; --iFrame)
     469           0 :     for (int i = iFrame; i <= mult; ++i) pProd[i].bst(pInv[iFrame]);
     470             : 
     471             :   // Done for multibody decay.
     472           0 :   for (int i = 1; i < mult; ++i)
     473           0 :     process[i1 + i - 1].p( pProd[i] );
     474             :   return;
     475             : 
     476           0 : }
     477             : 
     478             : //--------------------------------------------------------------------------
     479             : 
     480             : // Determine how 3-body phase space should be sampled.
     481             : 
     482             : void PhaseSpace::setup3Body() {
     483             : 
     484             :   // Check for massive t-channel propagator particles.
     485           0 :   int idTchan1    = abs( sigmaProcessPtr->idTchan1() );
     486           0 :   int idTchan2    = abs( sigmaProcessPtr->idTchan2() );
     487           0 :   mTchan1         = (idTchan1 == 0) ? pTHatMinDiverge
     488           0 :                                     : particleDataPtr->m0(idTchan1);
     489           0 :   mTchan2         = (idTchan2 == 0) ? pTHatMinDiverge
     490           0 :                                     : particleDataPtr->m0(idTchan2);
     491           0 :   sTchan1         = mTchan1 * mTchan1;
     492           0 :   sTchan2         = mTchan2 * mTchan2;
     493             : 
     494             :   // Find coefficients of different pT2 selection terms. Mirror choice.
     495           0 :   frac3Pow1       = sigmaProcessPtr->tChanFracPow1();
     496           0 :   frac3Pow2       = sigmaProcessPtr->tChanFracPow2();
     497           0 :   frac3Flat       = 1. - frac3Pow1 - frac3Pow2;
     498           0 :   useMirrorWeight = sigmaProcessPtr->useMirrorWeight();
     499             : 
     500           0 : }
     501             : 
     502             : //--------------------------------------------------------------------------
     503             : 
     504             : // Determine how phase space should be sampled.
     505             : 
     506             : bool PhaseSpace::setupSampling123(bool is2, bool is3, ostream& os) {
     507             : 
     508             :   // Optional printout.
     509           0 :   if (showSearch) os <<  "\n PYTHIA Optimization printout for "
     510           0 :     << sigmaProcessPtr->name() << "\n \n" << scientific << setprecision(3);
     511             : 
     512             :   // Check that open range in tau (+ set tauMin, tauMax).
     513           0 :   if (!limitTau(is2, is3)) return false;
     514             : 
     515             :   // Reset coefficients and matrices of equation system to solve.
     516           0 :   int binTau[8], binY[8], binZ[8];
     517           0 :   double vecTau[8], matTau[8][8], vecY[8], matY[8][8], vecZ[8], matZ[8][8];
     518           0 :   for (int i = 0; i < 8; ++i) {
     519           0 :     tauCoef[i] = 0.;
     520           0 :     yCoef[i]   = 0.;
     521           0 :     zCoef[i]   = 0.;
     522           0 :     binTau[i]  = 0;
     523           0 :     binY[i]    = 0;
     524           0 :     binZ[i]    = 0;
     525           0 :     vecTau[i]  = 0.;
     526           0 :     vecY[i]    = 0.;
     527           0 :     vecZ[i]    = 0.;
     528           0 :     for (int j = 0; j < 8; ++j) {
     529           0 :       matTau[i][j] = 0.;
     530           0 :       matY[i][j]   = 0.;
     531           0 :       matZ[i][j]   = 0.;
     532             :     }
     533             :   }
     534           0 :   sigmaMx  = 0.;
     535           0 :   sigmaNeg = 0.;
     536             : 
     537             :   // Number of used coefficients/points for each dimension: tau, y, c.
     538           0 :   nTau = (hasTwoPointLeptons) ? 1 : 2;
     539           0 :   nY   = (hasOnePointLepton || hasTwoPointLeptons) ? 1 : 5;
     540           0 :   nZ   = (is2) ? 5 : 1;
     541             : 
     542             :   // Identify if any resonances contribute in s-channel.
     543           0 :   idResA = sigmaProcessPtr->resonanceA();
     544           0 :   if (idResA != 0) {
     545           0 :      mResA = particleDataPtr->m0(idResA);
     546           0 :      GammaResA = particleDataPtr->mWidth(idResA);
     547           0 :      if (mHatMin > mResA + WIDTHMARGIN * GammaResA || (mHatMax > 0.
     548           0 :        && mHatMax < mResA - WIDTHMARGIN * GammaResA) ) idResA = 0;
     549             :   }
     550           0 :   idResB = sigmaProcessPtr->resonanceB();
     551           0 :   if (idResB != 0) {
     552           0 :      mResB = particleDataPtr->m0(idResB);
     553           0 :      GammaResB = particleDataPtr->mWidth(idResB);
     554           0 :      if (mHatMin > mResB + WIDTHMARGIN * GammaResB || (mHatMax > 0.
     555           0 :        && mHatMax < mResB - WIDTHMARGIN * GammaResB) ) idResB = 0;
     556             :   }
     557           0 :   if (idResA == 0 && idResB != 0) {
     558           0 :     idResA = idResB;
     559           0 :     mResA = mResB;
     560           0 :     GammaResA = GammaResB;
     561           0 :     idResB = 0;
     562           0 :   }
     563             : 
     564             :   // More sampling in tau if resonances in s-channel.
     565           0 :   if (idResA !=0 && !hasTwoPointLeptons) {
     566           0 :     nTau += 2;
     567           0 :     tauResA = mResA * mResA / s;
     568           0 :     widResA = mResA * GammaResA / s;
     569           0 :   }
     570           0 :   if (idResB != 0 && !hasTwoPointLeptons) {
     571           0 :     nTau += 2;
     572           0 :     tauResB = mResB * mResB / s;
     573           0 :     widResB = mResB * GammaResB / s;
     574           0 :   }
     575             : 
     576             :   // More sampling in tau (and different in y) if incoming lepton beams.
     577           0 :   if (hasTwoLeptonBeams && !hasTwoPointLeptons) ++nTau;
     578             : 
     579             :   // Special case when both resonances have same mass.
     580           0 :   sameResMass = false;
     581           0 :   if (idResB != 0 && abs(mResA - mResB) < SAMEMASS * (GammaResA + GammaResB))
     582           0 :     sameResMass = true;
     583             : 
     584             :   // Default z value and weight required for 2 -> 1. Number of dimensions.
     585           0 :   z = 0.;
     586           0 :   wtZ = 1.;
     587           0 :   int nVar = (is2) ? 3 : 2;
     588             : 
     589             :   // Initial values, to be modified later.
     590           0 :   tauCoef[0] = 1.;
     591           0 :   yCoef[1]   = 0.5;
     592           0 :   yCoef[2]   = 0.5;
     593           0 :   zCoef[0]   = 1.;
     594             : 
     595             :   // Step through grid in tau. Set limits on y and z generation.
     596           0 :   for (int iTau = 0; iTau < nTau; ++iTau) {
     597             :     double posTau = 0.5;
     598           0 :     if (sameResMass && iTau > 1 && iTau < 6) posTau = (iTau < 4) ? 0.4 : 0.6;
     599           0 :     selectTau( iTau, posTau, is2);
     600           0 :     if (!limitY()) continue;
     601           0 :     if (is2 && !limitZ()) continue;
     602             : 
     603             :     // Step through grids in y and z.
     604           0 :     for (int iY = 0; iY < nY; ++iY) {
     605           0 :       selectY( iY, 0.5);
     606           0 :       for (int iZ = 0; iZ < nZ; ++iZ) {
     607           0 :         if (is2) selectZ( iZ, 0.5);
     608             :         double sigmaTmp = 0.;
     609             : 
     610             :         // 2 -> 1: calculate cross section, weighted by phase-space volume.
     611           0 :         if (!is2 && !is3) {
     612           0 :           sigmaProcessPtr->set1Kin( x1H, x2H, sH);
     613           0 :           sigmaTmp = sigmaProcessPtr->sigmaPDF();
     614           0 :           sigmaTmp *= wtTau * wtY;
     615             : 
     616             :         // 2 -> 2: calculate cross section, weighted by phase-space volume
     617             :         // and Breit-Wigners for masses
     618           0 :         } else if (is2) {
     619           0 :           sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4,
     620           0 :             runBW3H, runBW4H);
     621           0 :           sigmaTmp = sigmaProcessPtr->sigmaPDF();
     622           0 :           sigmaTmp *= wtTau * wtY * wtZ * wtBW;
     623             : 
     624             :         // 2 -> 3: repeat internal 3-body phase space several times and
     625             :         // keep maximal cross section, weighted by phase-space volume
     626             :         // and Breit-Wigners for masses
     627           0 :         } else if (is3) {
     628           0 :           for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) {
     629           0 :             if (!select3Body()) continue;
     630           0 :             sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
     631           0 :               m3, m4, m5, runBW3H, runBW4H, runBW5H);
     632           0 :             double sigmaTry = sigmaProcessPtr->sigmaPDF();
     633           0 :             sigmaTry *= wtTau * wtY * wt3Body * wtBW;
     634           0 :             if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry;
     635           0 :           }
     636           0 :         }
     637             : 
     638             :         // Allow possibility for user to modify cross section. (3body??)
     639           0 :         if (canModifySigma) sigmaTmp
     640           0 :            *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false);
     641           0 :         if (canBiasSelection) sigmaTmp
     642           0 :            *= userHooksPtr->biasSelectionBy( sigmaProcessPtr, this, false);
     643           0 :         if (canBias2Sel) sigmaTmp *= pow( pTH / bias2SelRef, bias2SelPow);
     644             : 
     645             :         // Check if current maximum exceeded.
     646           0 :         if (sigmaTmp > sigmaMx) sigmaMx = sigmaTmp;
     647             : 
     648             :         // Optional printout. Protect against negative cross sections.
     649           0 :         if (showSearch) os << " tau =" << setw(11) << tau << "  y ="
     650           0 :           << setw(11) << y << "  z =" << setw(11) << z
     651           0 :           << "  sigma =" << setw(11) << sigmaTmp << "\n";
     652           0 :         if (sigmaTmp < 0.) sigmaTmp = 0.;
     653             : 
     654             :         // Sum up tau cross-section pieces in points used.
     655           0 :         if (!hasTwoPointLeptons) {
     656           0 :           binTau[iTau]      += 1;
     657           0 :           vecTau[iTau]      += sigmaTmp;
     658           0 :           matTau[iTau][0]   += 1. / intTau0;
     659           0 :           matTau[iTau][1]   += (1. / intTau1) / tau;
     660           0 :           if (idResA != 0) {
     661           0 :             matTau[iTau][2] += (1. / intTau2) / (tau + tauResA);
     662           0 :             matTau[iTau][3] += (1. / intTau3)
     663           0 :               * tau / ( pow2(tau - tauResA) + pow2(widResA) );
     664           0 :           }
     665           0 :           if (idResB != 0) {
     666           0 :             matTau[iTau][4] += (1. / intTau4) / (tau + tauResB);
     667           0 :             matTau[iTau][5] += (1. / intTau5)
     668           0 :               * tau / ( pow2(tau - tauResB) + pow2(widResB) );
     669           0 :           }
     670           0 :           if (hasTwoLeptonBeams) matTau[iTau][nTau - 1] += (1. / intTau6)
     671           0 :               * tau / max( LEPTONTAUMIN, 1. - tau);
     672             :         }
     673             : 
     674             :         // Sum up y cross-section pieces in points used.
     675           0 :         if (!hasOnePointLepton && !hasTwoPointLeptons) {
     676           0 :           binY[iY]      += 1;
     677           0 :           vecY[iY]      += sigmaTmp;
     678           0 :           matY[iY][0]   += (yMax / intY0) / cosh(y);
     679           0 :           matY[iY][1]   += (yMax / intY12) * (y + yMax);
     680           0 :           matY[iY][2]   += (yMax / intY12) * (yMax - y);
     681           0 :           if (!hasTwoLeptonBeams) {
     682           0 :             matY[iY][3] += (yMax / intY34) * exp(y);
     683           0 :             matY[iY][4] += (yMax / intY34) * exp(-y);
     684           0 :           } else {
     685           0 :             matY[iY][3] += (yMax / intY56)
     686           0 :               / max( LEPTONXMIN, 1. - exp( y - yMax) );
     687           0 :             matY[iY][4] += (yMax / intY56)
     688           0 :               / max( LEPTONXMIN, 1. - exp(-y - yMax) );
     689             :           }
     690             :         }
     691             : 
     692             :         // Integrals over z expressions at tauMax, to be used below.
     693           0 :         if (is2) {
     694           0 :           double p2AbsMax   = 0.25 * (pow2(tauMax * s - s3 - s4)
     695           0 :             - 4. * s3 * s4) / (tauMax * s);
     696           0 :           double zMaxMax    = sqrtpos( 1. - pT2HatMin / p2AbsMax );
     697           0 :           double zPosMaxMax = max(ratio34, unity34 + zMaxMax);
     698           0 :           double zNegMaxMax = max(ratio34, unity34 - zMaxMax);
     699           0 :           double intZ0Max   = 2. * zMaxMax;
     700           0 :           double intZ12Max  = log( zPosMaxMax / zNegMaxMax);
     701           0 :           double intZ34Max  = 1. / zNegMaxMax - 1. / zPosMaxMax;
     702             : 
     703             :           // Sum up z cross-section pieces in points used.
     704           0 :           binZ[iZ]    += 1;
     705           0 :           vecZ[iZ]    += sigmaTmp;
     706           0 :           matZ[iZ][0] += 1.;
     707           0 :           matZ[iZ][1] += (intZ0Max / intZ12Max) / zNeg;
     708           0 :           matZ[iZ][2] += (intZ0Max / intZ12Max) / zPos;
     709           0 :           matZ[iZ][3] += (intZ0Max / intZ34Max) / pow2(zNeg);
     710           0 :           matZ[iZ][4] += (intZ0Max / intZ34Max) / pow2(zPos);
     711           0 :         }
     712             : 
     713             :       // End of loops over phase space points.
     714             :       }
     715             :     }
     716           0 :   }
     717             : 
     718             :   // Fail if no non-vanishing cross sections.
     719           0 :   if (sigmaMx <= 0.) {
     720           0 :     sigmaMx = 0.;
     721           0 :     return false;
     722             :   }
     723             : 
     724             :   // Solve respective equation system for better phase space coefficients.
     725           0 :   if (!hasTwoPointLeptons) solveSys( nTau, binTau, vecTau, matTau, tauCoef);
     726           0 :   if (!hasOnePointLepton && !hasTwoPointLeptons)
     727           0 :     solveSys( nY, binY, vecY, matY, yCoef);
     728           0 :   if (is2) solveSys( nZ, binZ, vecZ, matZ, zCoef);
     729           0 :   if (showSearch) os << "\n";
     730             : 
     731             :   // Provide cumulative sum of coefficients.
     732           0 :   tauCoefSum[0] = tauCoef[0];
     733           0 :     yCoefSum[0] =   yCoef[0];
     734           0 :     zCoefSum[0] =   zCoef[0];
     735           0 :   for (int i = 1; i < 8; ++ i) {
     736           0 :     tauCoefSum[i] = tauCoefSum[i - 1] + tauCoef[i];
     737           0 :       yCoefSum[i] =   yCoefSum[i - 1] +   yCoef[i];
     738           0 :       zCoefSum[i] =   zCoefSum[i - 1] +   zCoef[i];
     739             :   }
     740             :   // The last element should be > 1 to be on safe side in selection below.
     741           0 :   tauCoefSum[nTau - 1] = 2.;
     742           0 :     yCoefSum[nY   - 1] = 2.;
     743           0 :     zCoefSum[nZ   - 1] = 2.;
     744             : 
     745             : 
     746             :   // Begin find two most promising maxima among same points as before.
     747           0 :   int iMaxTau[NMAXTRY + 2], iMaxY[NMAXTRY + 2], iMaxZ[NMAXTRY + 2];
     748           0 :   double sigMax[NMAXTRY + 2];
     749             :   int nMax = 0;
     750             : 
     751             :   // Scan same grid as before in tau, y, z.
     752           0 :   for (int iTau = 0; iTau < nTau; ++iTau) {
     753             :     double posTau = 0.5;
     754           0 :     if (sameResMass && iTau > 1 && iTau < 6) posTau = (iTau < 4) ? 0.4 : 0.6;
     755           0 :     selectTau( iTau, posTau, is2);
     756           0 :     if (!limitY()) continue;
     757           0 :     if (is2 && !limitZ()) continue;
     758           0 :     for (int iY = 0; iY < nY; ++iY) {
     759           0 :       selectY( iY, 0.5);
     760           0 :       for (int iZ = 0; iZ < nZ; ++iZ) {
     761           0 :         if (is2) selectZ( iZ, 0.5);
     762             :         double sigmaTmp = 0.;
     763             : 
     764             :         // 2 -> 1: calculate cross section, weighted by phase-space volume.
     765           0 :         if (!is2 && !is3) {
     766           0 :           sigmaProcessPtr->set1Kin( x1H, x2H, sH);
     767           0 :           sigmaTmp = sigmaProcessPtr->sigmaPDF();
     768           0 :           sigmaTmp *= wtTau * wtY;
     769             : 
     770             :         // 2 -> 2: calculate cross section, weighted by phase-space volume
     771             :         // and Breit-Wigners for masses
     772           0 :         } else if (is2) {
     773           0 :           sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4,
     774           0 :             runBW3H, runBW4H);
     775           0 :           sigmaTmp = sigmaProcessPtr->sigmaPDF();
     776           0 :           sigmaTmp *= wtTau * wtY * wtZ * wtBW;
     777             : 
     778             :         // 2 -> 3: repeat internal 3-body phase space several times and
     779             :         // keep maximal cross section, weighted by phase-space volume
     780             :         // and Breit-Wigners for masses
     781           0 :         } else if (is3) {
     782           0 :           for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) {
     783           0 :             if (!select3Body()) continue;
     784           0 :             sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
     785           0 :               m3, m4, m5, runBW3H, runBW4H, runBW5H);
     786           0 :             double sigmaTry = sigmaProcessPtr->sigmaPDF();
     787           0 :             sigmaTry *= wtTau * wtY * wt3Body * wtBW;
     788           0 :             if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry;
     789           0 :           }
     790           0 :         }
     791             : 
     792             :         // Allow possibility for user to modify cross section. (3body??)
     793           0 :         if (canModifySigma) sigmaTmp
     794           0 :            *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false);
     795           0 :         if (canBiasSelection) sigmaTmp
     796           0 :            *= userHooksPtr->biasSelectionBy( sigmaProcessPtr, this, false);
     797           0 :         if (canBias2Sel) sigmaTmp *= pow( pTH / bias2SelRef, bias2SelPow);
     798             : 
     799             :         // Optional printout. Protect against negative cross section.
     800           0 :         if (showSearch) os << " tau =" << setw(11) << tau << "  y ="
     801           0 :           << setw(11) << y << "  z =" << setw(11) << z
     802           0 :           << "  sigma =" << setw(11) << sigmaTmp << "\n";
     803           0 :         if (sigmaTmp < 0.) sigmaTmp = 0.;
     804             : 
     805             :         // Check that point is not simply mirror of already found one.
     806             :         bool mirrorPoint = false;
     807           0 :         for (int iMove = 0; iMove < nMax; ++iMove)
     808           0 :           if (abs(sigmaTmp - sigMax[iMove]) < SAMESIGMA
     809           0 :             * (sigmaTmp + sigMax[iMove])) mirrorPoint = true;
     810             : 
     811             :         // Add to or insert in maximum list. Only first two count.
     812           0 :         if (!mirrorPoint) {
     813             :           int iInsert = 0;
     814           0 :           for (int iMove = nMax - 1; iMove >= -1; --iMove) {
     815           0 :             iInsert = iMove + 1;
     816           0 :             if (iInsert == 0 || sigmaTmp < sigMax[iMove]) break;
     817           0 :             iMaxTau[iMove + 1] = iMaxTau[iMove];
     818           0 :             iMaxY[iMove + 1] = iMaxY[iMove];
     819           0 :             iMaxZ[iMove + 1] = iMaxZ[iMove];
     820           0 :             sigMax[iMove + 1] = sigMax[iMove];
     821             :           }
     822           0 :           iMaxTau[iInsert] = iTau;
     823           0 :           iMaxY[iInsert] = iY;
     824           0 :           iMaxZ[iInsert] = iZ;
     825           0 :           sigMax[iInsert] = sigmaTmp;
     826           0 :           if (nMax < NMAXTRY) ++nMax;
     827           0 :         }
     828             : 
     829             :       // Found two most promising maxima.
     830             :       }
     831             :     }
     832           0 :   }
     833           0 :   if (showSearch) os << "\n";
     834             : 
     835             :   // Read out starting position for search.
     836           0 :   sigmaMx = sigMax[0];
     837           0 :   int beginVar = (hasTwoPointLeptons) ? 2 : 0;
     838           0 :   if (hasOnePointLepton) beginVar = 1;
     839           0 :   for (int iMax = 0; iMax < nMax; ++iMax) {
     840           0 :     int iTau = iMaxTau[iMax];
     841           0 :     int iY = iMaxY[iMax];
     842           0 :     int iZ = iMaxZ[iMax];
     843             :     double tauVal = 0.5;
     844             :     double yVal = 0.5;
     845             :     double zVal = 0.5;
     846             :     int iGrid;
     847           0 :     double varVal, varNew, deltaVar, marginVar, sigGrid[3];
     848             : 
     849             :     // Starting point and step size in parameter space.
     850           0 :     for (int iRepeat = 0; iRepeat < 2; ++iRepeat) {
     851             :       // Run through (possibly a subset of) tau, y and z.
     852           0 :       for (int iVar = beginVar; iVar < nVar; ++iVar) {
     853           0 :         bool isTauVar = iVar == 0 || (beginVar == 1 && iVar == 1);
     854           0 :         if (isTauVar) varVal = tauVal;
     855           0 :         else if (iVar == 1) varVal = yVal;
     856             :         else varVal = zVal;
     857           0 :         deltaVar = (iRepeat == 0) ? 0.1
     858           0 :           : max( 0.01, min( 0.05, min( varVal - 0.02, 0.98 - varVal) ) );
     859           0 :         marginVar = (iRepeat == 0) ? 0.02 : 0.002;
     860           0 :         int moveStart = (iRepeat == 0 && isTauVar) ? 0 : 1;
     861           0 :         for (int move = moveStart; move < 9; ++move) {
     862             : 
     863             :           // Define new parameter-space point by step in one dimension.
     864           0 :           if (move == 0) {
     865             :             iGrid = 1;
     866             :             varNew = varVal;
     867           0 :           } else if (move == 1) {
     868             :             iGrid = 2;
     869           0 :             varNew = varVal + deltaVar;
     870           0 :           } else if (move == 2) {
     871             :             iGrid = 0;
     872           0 :             varNew = varVal - deltaVar;
     873           0 :           } else if (sigGrid[2] >= max( sigGrid[0], sigGrid[1])
     874           0 :             && varVal + 2. * deltaVar < 1. - marginVar) {
     875           0 :             varVal += deltaVar;
     876           0 :             sigGrid[0] = sigGrid[1];
     877           0 :             sigGrid[1] = sigGrid[2];
     878             :             iGrid = 2;
     879           0 :             varNew = varVal + deltaVar;
     880           0 :           } else if (sigGrid[0] >= max( sigGrid[1], sigGrid[2])
     881           0 :             && varVal - 2. * deltaVar > marginVar) {
     882           0 :             varVal -= deltaVar;
     883           0 :             sigGrid[2] = sigGrid[1];
     884           0 :             sigGrid[1] = sigGrid[0];
     885             :             iGrid = 0;
     886           0 :             varNew = varVal - deltaVar;
     887           0 :           } else if (sigGrid[2] >= sigGrid[0]) {
     888           0 :             deltaVar *= 0.5;
     889           0 :             varVal += deltaVar;
     890           0 :             sigGrid[0] = sigGrid[1];
     891             :             iGrid = 1;
     892             :             varNew = varVal;
     893           0 :           } else {
     894             :             deltaVar *= 0.5;
     895           0 :             varVal -= deltaVar;
     896           0 :             sigGrid[2] = sigGrid[1];
     897             :             iGrid = 1;
     898             :             varNew = varVal;
     899             :           }
     900             : 
     901             :           // Convert to relevant variables and find derived new limits.
     902             :           bool insideLimits = true;
     903           0 :           if (isTauVar) {
     904             :             tauVal = varNew;
     905           0 :             selectTau( iTau, tauVal, is2);
     906           0 :             if (!limitY()) insideLimits = false;
     907           0 :             if (is2 && !limitZ()) insideLimits = false;
     908           0 :             if (insideLimits) {
     909           0 :               selectY( iY, yVal);
     910           0 :               if (is2) selectZ( iZ, zVal);
     911             :             }
     912           0 :           } else if (iVar == 1) {
     913             :             yVal = varNew;
     914           0 :             selectY( iY, yVal);
     915           0 :           } else if (iVar == 2) {
     916             :             zVal = varNew;
     917           0 :             selectZ( iZ, zVal);
     918           0 :           }
     919             : 
     920             :           // Evaluate cross-section.
     921             :           double sigmaTmp = 0.;
     922           0 :           if (insideLimits) {
     923             : 
     924             :             // 2 -> 1: calculate cross section, weighted by phase-space volume.
     925           0 :             if (!is2 && !is3) {
     926           0 :               sigmaProcessPtr->set1Kin( x1H, x2H, sH);
     927           0 :               sigmaTmp = sigmaProcessPtr->sigmaPDF();
     928           0 :               sigmaTmp *= wtTau * wtY;
     929             : 
     930             :             // 2 -> 2: calculate cross section, weighted by phase-space volume
     931             :             // and Breit-Wigners for masses
     932           0 :             } else if (is2) {
     933           0 :               sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4,
     934           0 :                 runBW3H, runBW4H);
     935           0 :               sigmaTmp = sigmaProcessPtr->sigmaPDF();
     936           0 :               sigmaTmp *= wtTau * wtY * wtZ * wtBW;
     937             : 
     938             :             // 2 -> 3: repeat internal 3-body phase space several times and
     939             :             // keep maximal cross section, weighted by phase-space volume
     940             :             // and Breit-Wigners for masses
     941           0 :             } else if (is3) {
     942           0 :               for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) {
     943           0 :                 if (!select3Body()) continue;
     944           0 :                 sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
     945           0 :                   m3, m4, m5, runBW3H, runBW4H, runBW5H);
     946           0 :                 double sigmaTry = sigmaProcessPtr->sigmaPDF();
     947           0 :                 sigmaTry *= wtTau * wtY * wt3Body * wtBW;
     948           0 :                 if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry;
     949           0 :               }
     950           0 :             }
     951             : 
     952             :             // Allow possibility for user to modify cross section.
     953           0 :             if (canModifySigma) sigmaTmp
     954           0 :               *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false);
     955           0 :             if (canBiasSelection) sigmaTmp
     956           0 :               *= userHooksPtr->biasSelectionBy( sigmaProcessPtr, this, false);
     957           0 :             if (canBias2Sel) sigmaTmp *= pow( pTH / bias2SelRef, bias2SelPow);
     958             : 
     959             :             // Optional printout. Protect against negative cross section.
     960           0 :             if (showSearch) os << " tau =" << setw(11) << tau << "  y ="
     961           0 :               << setw(11) << y << "  z =" << setw(11) << z
     962           0 :               << "  sigma =" << setw(11) << sigmaTmp << "\n";
     963           0 :             if (sigmaTmp < 0.) sigmaTmp = 0.;
     964             :           }
     965             : 
     966             :           // Save new maximum. Final maximum.
     967           0 :           sigGrid[iGrid] = sigmaTmp;
     968           0 :           if (sigmaTmp > sigmaMx) sigmaMx = sigmaTmp;
     969             :         }
     970             :       }
     971             :     }
     972           0 :   }
     973           0 :   sigmaMx *= SAFETYMARGIN;
     974           0 :   sigmaPos = sigmaMx;
     975             : 
     976             :   // Optional printout.
     977           0 :   if (showSearch) os << "\n Final maximum = "  << setw(11) << sigmaMx << endl;
     978             : 
     979             :   // Done.
     980             :   return true;
     981           0 : }
     982             : 
     983             : //--------------------------------------------------------------------------
     984             : 
     985             : // Select a trial kinematics phase space point.
     986             : // Note: by In is meant the integral over the quantity multiplying
     987             : // coefficient cn. The sum of cn is normalized to unity.
     988             : 
     989             : bool PhaseSpace::trialKin123(bool is2, bool is3, bool inEvent, ostream& os) {
     990             : 
     991             :   // Allow for possibility that energy varies from event to event.
     992           0 :   if (doEnergySpread) {
     993           0 :     eCM       = infoPtr->eCM();
     994           0 :     s         = eCM * eCM;
     995             : 
     996             :     // Find shifted tauRes values.
     997           0 :     if (idResA !=0 && !hasTwoPointLeptons) {
     998           0 :       tauResA = mResA * mResA / s;
     999           0 :       widResA = mResA * GammaResA / s;
    1000           0 :     }
    1001           0 :     if (idResB != 0 && !hasTwoPointLeptons) {
    1002           0 :       tauResB = mResB * mResB / s;
    1003           0 :       widResB = mResB * GammaResB / s;
    1004           0 :     }
    1005             :   }
    1006             : 
    1007             :   // Choose tau according to h1(tau)/tau, where
    1008             :   // h1(tau) = c0/I0 + (c1/I1) * 1/tau
    1009             :   // + (c2/I2) / (tau + tauResA)
    1010             :   // + (c3/I3) * tau / ((tau - tauResA)^2 + widResA^2)
    1011             :   // + (c4/I4) / (tau + tauResB)
    1012             :   // + (c5/I5) * tau / ((tau - tauResB)^2 + widResB^2)
    1013             :   // + (c6/I6) * tau / (1 - tau).
    1014           0 :   if (!limitTau(is2, is3)) return false;
    1015             :   int iTau = 0;
    1016           0 :   if (!hasTwoPointLeptons) {
    1017           0 :     double rTau = rndmPtr->flat();
    1018           0 :     while (rTau > tauCoefSum[iTau]) ++iTau;
    1019           0 :   }
    1020           0 :   selectTau( iTau, rndmPtr->flat(), is2);
    1021             : 
    1022             :   // Choose y according to h2(y), where
    1023             :   // h2(y) = (c0/I0) * 1/cosh(y)
    1024             :   // + (c1/I1) * (y-ymin) + (c2/I2) * (ymax-y)
    1025             :   // + (c3/I3) * exp(y) + (c4/i4) * exp(-y) (for hadron; for lepton instead)
    1026             :   // + (c5/I5) * 1 / (1 - exp(y-ymax)) + (c6/I6) * 1 / (1 - exp(ymin-y)).
    1027           0 :   if (!limitY()) return false;
    1028             :   int iY = 0;
    1029           0 :   if (!hasOnePointLepton && !hasTwoPointLeptons) {
    1030           0 :     double rY = rndmPtr->flat();
    1031           0 :     while (rY > yCoefSum[iY]) ++iY;
    1032           0 :   }
    1033           0 :   selectY( iY, rndmPtr->flat());
    1034             : 
    1035             :   // Choose z = cos(thetaHat) according to h3(z), where
    1036             :   // h3(z) = c0/I0 + (c1/I1) * 1/(A - z) + (c2/I2) * 1/(A + z)
    1037             :   // + (c3/I3) * 1/(A - z)^2 + (c4/I4) * 1/(A + z)^2,
    1038             :   // where A = 1 + 2*(m3*m4/sH)^2 (= 1 for massless products).
    1039           0 :   if (is2) {
    1040           0 :     if (!limitZ()) return false;
    1041             :     int iZ = 0;
    1042           0 :     double rZ = rndmPtr->flat();
    1043           0 :     while (rZ > zCoefSum[iZ]) ++iZ;
    1044           0 :     selectZ( iZ, rndmPtr->flat());
    1045           0 :   }
    1046             : 
    1047             :   // 2 -> 1: calculate cross section, weighted by phase-space volume.
    1048           0 :   if (!is2 && !is3) {
    1049           0 :     sigmaProcessPtr->set1Kin( x1H, x2H, sH);
    1050           0 :     sigmaNw  = sigmaProcessPtr->sigmaPDF();
    1051           0 :     sigmaNw *= wtTau * wtY;
    1052             : 
    1053             :   // 2 -> 2: calculate cross section, weighted by phase-space volume
    1054             :   // and Breit-Wigners for masses
    1055           0 :   } else if (is2) {
    1056           0 :     sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4, runBW3H, runBW4H);
    1057           0 :     sigmaNw  = sigmaProcessPtr->sigmaPDF();
    1058           0 :     sigmaNw *= wtTau * wtY * wtZ * wtBW;
    1059             : 
    1060             :   // 2 -> 3: also sample internal 3-body phase, weighted by
    1061             :   // 2 -> 1 phase-space volume and Breit-Wigners for masses
    1062           0 :   } else if (is3) {
    1063           0 :     if (!select3Body()) sigmaNw = 0.;
    1064             :     else {
    1065           0 :       sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
    1066           0 :          m3, m4, m5, runBW3H, runBW4H, runBW5H);
    1067           0 :       sigmaNw  = sigmaProcessPtr->sigmaPDF();
    1068           0 :       sigmaNw *= wtTau * wtY * wt3Body * wtBW;
    1069             :     }
    1070             :   }
    1071             : 
    1072             :   // Allow possibility for user to modify cross section.
    1073           0 :   if (canModifySigma) sigmaNw
    1074           0 :     *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, inEvent);
    1075           0 :   if (canBiasSelection) sigmaNw
    1076           0 :     *= userHooksPtr->biasSelectionBy( sigmaProcessPtr, this, inEvent);
    1077           0 :   if (canBias2Sel) sigmaNw *= pow( pTH / bias2SelRef, bias2SelPow);
    1078             : 
    1079             :   // Check if maximum violated.
    1080           0 :   newSigmaMx = false;
    1081           0 :   if (sigmaNw > sigmaMx) {
    1082           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::trialKin: "
    1083             :       "maximum for cross section violated");
    1084             : 
    1085             :     // Violation strategy 1: increase maximum (always during initialization).
    1086           0 :     if (increaseMaximum || !inEvent) {
    1087           0 :       double violFact = SAFETYMARGIN * sigmaNw / sigmaMx;
    1088           0 :       sigmaMx = SAFETYMARGIN * sigmaNw;
    1089           0 :       newSigmaMx = true;
    1090           0 :       if (showViolation) {
    1091           0 :         if (violFact < 9.99) os << fixed;
    1092           0 :         else                 os << scientific;
    1093           0 :         os << " PYTHIA Maximum for " << sigmaProcessPtr->name()
    1094           0 :            << " increased by factor " << setprecision(3) << violFact
    1095           0 :            << " to " << scientific << sigmaMx << endl;
    1096           0 :       }
    1097             : 
    1098             :     // Violation strategy 2: weight event (done in ProcessContainer).
    1099           0 :     } else if (showViolation && sigmaNw > sigmaPos) {
    1100           0 :       double violFact = sigmaNw / sigmaMx;
    1101           0 :       if (violFact < 9.99) os << fixed;
    1102           0 :       else                 os << scientific;
    1103           0 :       os << " PYTHIA Maximum for " << sigmaProcessPtr->name()
    1104           0 :          << " exceeded by factor " << setprecision(3) << violFact << endl;
    1105           0 :       sigmaPos = sigmaNw;
    1106           0 :     }
    1107             :   }
    1108             : 
    1109             :   // Check if negative cross section.
    1110           0 :   if (sigmaNw < sigmaNeg) {
    1111           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::trialKin:"
    1112           0 :       " negative cross section set 0", "for " +  sigmaProcessPtr->name() );
    1113           0 :     sigmaNeg = sigmaNw;
    1114             : 
    1115             :     // Optional printout of (all) violations.
    1116           0 :     if (showViolation) os << " PYTHIA Negative minimum for "
    1117           0 :       << sigmaProcessPtr->name() << " changed to " << scientific
    1118           0 :       << setprecision(3) << sigmaNeg << endl;
    1119             :   }
    1120           0 :   if (sigmaNw < 0.) sigmaNw = 0.;
    1121             : 
    1122             :   // Set event weight, where relevant.
    1123           0 :   biasWt = (canBiasSelection) ? userHooksPtr->biasedSelectionWeight() : 1.;
    1124           0 :   if (canBias2Sel) biasWt /= pow( pTH / bias2SelRef, bias2SelPow);
    1125             : 
    1126             :   // Done.
    1127           0 :   return true;
    1128           0 : }
    1129             : 
    1130             : //--------------------------------------------------------------------------
    1131             : 
    1132             : // Find range of allowed tau values.
    1133             : 
    1134             : bool PhaseSpace::limitTau(bool is2, bool is3) {
    1135             : 
    1136             :   // Trivial reply for unresolved lepton beams.
    1137           0 :   if (hasTwoPointLeptons) {
    1138           0 :     tauMin = 1.;
    1139           0 :     tauMax = 1.;
    1140           0 :     return true;
    1141             :   }
    1142             : 
    1143             :   // Requirements from allowed mHat range.
    1144           0 :   tauMin = sHatMin / s;
    1145           0 :   tauMax = (mHatMax < mHatMin) ? 1. : min( 1., sHatMax / s);
    1146             : 
    1147             :   // Requirements from allowed pT range and masses.
    1148           0 :   if (is2 || is3) {
    1149           0 :     double mT3Min = sqrt(s3 + pT2HatMin);
    1150           0 :     double mT4Min = sqrt(s4 + pT2HatMin);
    1151           0 :     double mT5Min = (is3) ? sqrt(s5 + pT2HatMin) : 0.;
    1152           0 :     tauMin = max( tauMin, pow2(mT3Min + mT4Min + mT5Min) / s);
    1153           0 :   }
    1154             : 
    1155             :   // Check that there is an open range.
    1156           0 :   return (tauMax > tauMin);
    1157           0 : }
    1158             : 
    1159             : //--------------------------------------------------------------------------
    1160             : 
    1161             : // Find range of allowed y values.
    1162             : 
    1163             : bool PhaseSpace::limitY() {
    1164             : 
    1165             :   // Trivial reply for unresolved lepton beams.
    1166           0 :   if (hasTwoPointLeptons) {
    1167           0 :     yMax = 1.;
    1168           0 :     return true;
    1169             :   }
    1170             : 
    1171             :   // Requirements from selected tau value. Trivial for one unresolved beam.
    1172           0 :   yMax = -0.5 * log(tau);
    1173           0 :   if (hasOnePointLepton) return true;
    1174             : 
    1175             :   // For lepton beams requirements from cutoff for f_e^e.
    1176           0 :   double yMaxMargin = (hasTwoLeptonBeams) ? yMax + LEPTONXLOGMAX : yMax;
    1177             : 
    1178             :   // Check that there is an open range.
    1179           0 :   return (yMaxMargin > 0.);
    1180           0 : }
    1181             : 
    1182             : //--------------------------------------------------------------------------
    1183             : 
    1184             : // Find range of allowed z = cos(theta) values.
    1185             : 
    1186             : bool PhaseSpace::limitZ() {
    1187             : 
    1188             :   // Default limits.
    1189           0 :   zMin = 0.;
    1190           0 :   zMax = 1.;
    1191             : 
    1192             :   // Requirements from pTHat limits.
    1193           0 :   zMax = sqrtpos( 1. - pT2HatMin / p2Abs );
    1194           0 :   if (pTHatMax > pTHatMin) zMin = sqrtpos( 1. - pT2HatMax / p2Abs );
    1195             : 
    1196             :   // Check that there is an open range.
    1197           0 :   return (zMax > zMin);
    1198             : }
    1199             : 
    1200             : //--------------------------------------------------------------------------
    1201             : 
    1202             : // Select tau according to a choice of shapes.
    1203             : 
    1204             : void PhaseSpace::selectTau(int iTau, double tauVal, bool is2) {
    1205             : 
    1206             :   // Trivial reply for unresolved lepton beams.
    1207           0 :   if (hasTwoPointLeptons) {
    1208           0 :     tau = 1.;
    1209           0 :     wtTau = 1.;
    1210           0 :     sH = s;
    1211           0 :     mHat = sqrt(sH);
    1212           0 :     if (is2) {
    1213           0 :       p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH;
    1214           0 :       pAbs = sqrtpos( p2Abs );
    1215           0 :     }
    1216             :     return;
    1217             :   }
    1218             : 
    1219             :   // Contributions from s-channel resonances.
    1220             :   double tRatA = 0.;
    1221             :   double aLowA = 0.;
    1222             :   double aUppA = 0.;
    1223           0 :   if (idResA !=0) {
    1224           0 :     tRatA = ((tauResA + tauMax) / (tauResA + tauMin)) * (tauMin / tauMax);
    1225           0 :     aLowA = atan( (tauMin - tauResA) / widResA);
    1226           0 :     aUppA = atan( (tauMax - tauResA) / widResA);
    1227           0 :   }
    1228             :   double tRatB = 0.;
    1229             :   double aLowB = 0.;
    1230             :   double aUppB = 0.;
    1231           0 :   if (idResB != 0) {
    1232           0 :     tRatB = ((tauResB + tauMax) / (tauResB + tauMin)) * (tauMin / tauMax);
    1233           0 :     aLowB = atan( (tauMin - tauResB) / widResB);
    1234           0 :     aUppB = atan( (tauMax - tauResB) / widResB);
    1235           0 :   }
    1236             : 
    1237             :   // Contributions from 1 / (1 - tau)  for lepton beams.
    1238             :   double aLowT = 0.;
    1239             :   double aUppT = 0.;
    1240           0 :   if (hasTwoLeptonBeams) {
    1241           0 :     aLowT = log( max( LEPTONTAUMIN, 1. - tauMin) );
    1242           0 :     aUppT = log( max( LEPTONTAUMIN, 1. - tauMax) );
    1243           0 :     intTau6 = aLowT - aUppT;
    1244           0 :   }
    1245             : 
    1246             :   // Select according to 1/tau or 1/tau^2.
    1247           0 :   if (iTau == 0) tau = tauMin * pow( tauMax / tauMin, tauVal);
    1248           0 :   else if (iTau == 1) tau = tauMax * tauMin
    1249           0 :     / (tauMin + (tauMax - tauMin) * tauVal);
    1250             : 
    1251             :   // Select according to 1 / (1 - tau) for lepton beams.
    1252           0 :   else if (hasTwoLeptonBeams && iTau == nTau - 1)
    1253           0 :     tau = 1. - exp( aUppT + intTau6 * tauVal );
    1254             : 
    1255             :   // Select according to 1 / (tau * (tau + tauRes)) or
    1256             :   // 1 / ((tau - tauRes)^2 + widRes^2) for resonances A and B.
    1257           0 :   else if (iTau == 2) tau = tauResA * tauMin
    1258           0 :     / ((tauResA + tauMin) * pow( tRatA, tauVal) - tauMin);
    1259           0 :   else if (iTau == 3) tau = tauResA + widResA
    1260           0 :     * tan( aLowA + (aUppA - aLowA) * tauVal);
    1261           0 :   else if (iTau == 4) tau = tauResB * tauMin
    1262           0 :     / ((tauResB + tauMin) * pow( tRatB, tauVal) - tauMin);
    1263           0 :   else if (iTau == 5) tau = tauResB + widResB
    1264           0 :     * tan( aLowB + (aUppB - aLowB) * tauVal);
    1265             : 
    1266             :   // Phase space weight in tau.
    1267           0 :   intTau0 = log( tauMax / tauMin);
    1268           0 :   intTau1 = (tauMax - tauMin) / (tauMax * tauMin);
    1269           0 :   double invWtTau = (tauCoef[0] / intTau0) + (tauCoef[1] / intTau1) / tau;
    1270           0 :   if (idResA != 0) {
    1271           0 :     intTau2 = -log(tRatA) / tauResA;
    1272           0 :     intTau3 = (aUppA - aLowA) / widResA;
    1273           0 :     invWtTau += (tauCoef[2] / intTau2) / (tau + tauResA)
    1274           0 :       + (tauCoef[3] / intTau3) * tau / ( pow2(tau - tauResA) + pow2(widResA) );
    1275           0 :   }
    1276           0 :   if (idResB != 0) {
    1277           0 :     intTau4 = -log(tRatB) / tauResB;
    1278           0 :     intTau5 = (aUppB - aLowB) / widResB;
    1279           0 :     invWtTau += (tauCoef[4] / intTau4) / (tau + tauResB)
    1280           0 :       + (tauCoef[5] / intTau5) * tau / ( pow2(tau - tauResB) + pow2(widResB) );
    1281           0 :   }
    1282           0 :   if (hasTwoLeptonBeams)
    1283           0 :     invWtTau += (tauCoef[nTau - 1] / intTau6)
    1284           0 :       * tau / max( LEPTONTAUMIN, 1. - tau);
    1285           0 :   wtTau = 1. / invWtTau;
    1286             : 
    1287             :   // Calculate sHat and absolute momentum of outgoing partons.
    1288           0 :   sH = tau * s;
    1289           0 :   mHat = sqrt(sH);
    1290           0 :   if (is2) {
    1291           0 :     p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH;
    1292           0 :     pAbs = sqrtpos( p2Abs );
    1293           0 :   }
    1294             : 
    1295           0 : }
    1296             : 
    1297             : //--------------------------------------------------------------------------
    1298             : 
    1299             : // Select y according to a choice of shapes.
    1300             : 
    1301             : void PhaseSpace::selectY(int iY, double yVal) {
    1302             : 
    1303             :   // Trivial reply for two unresolved lepton beams.
    1304           0 :   if (hasTwoPointLeptons) {
    1305           0 :     y = 0.;
    1306           0 :     wtY = 1.;
    1307           0 :     x1H = 1.;
    1308           0 :     x2H = 1.;
    1309           0 :     return;
    1310             :   }
    1311             : 
    1312             :   // Trivial replies for one unresolved lepton beam.
    1313           0 :   if (hasOnePointLepton) {
    1314           0 :     if (hasLeptonBeamA) {
    1315           0 :       y   = yMax;
    1316           0 :       x1H = 1.;
    1317           0 :       x2H = tau;
    1318           0 :     } else {
    1319           0 :       y   = -yMax;
    1320           0 :       x1H = tau;
    1321           0 :       x2H = 1.;
    1322             :     }
    1323           0 :     wtY = 1.;
    1324           0 :     return;
    1325             :   }
    1326             : 
    1327             :   // For lepton beams skip options 3&4 and go straight to 5&6.
    1328           0 :   if (hasTwoLeptonBeams && iY > 2) iY += 2;
    1329             : 
    1330             :   // Standard expressions used below.
    1331           0 :   double expYMax = exp( yMax );
    1332           0 :   double expYMin = exp(-yMax );
    1333           0 :   double atanMax = atan( expYMax );
    1334           0 :   double atanMin = atan( expYMin );
    1335           0 :   double aUppY = (hasTwoLeptonBeams)
    1336           0 :     ? log( max( LEPTONXMIN, LEPTONXMAX / tau - 1. ) ) : 0.;
    1337           0 :   double aLowY = LEPTONXLOGMIN;
    1338             : 
    1339             :   // 1 / cosh(y).
    1340           0 :   if (iY == 0) y = log( tan( atanMin + (atanMax - atanMin) * yVal ) );
    1341             : 
    1342             :   // y - y_min or mirrored y_max - y.
    1343           0 :   else if (iY <= 2) y = yMax * (2. * sqrt(yVal) - 1.);
    1344             : 
    1345             :   // exp(y) or mirrored exp(-y).
    1346           0 :   else if (iY <= 4) y = log( expYMin + (expYMax - expYMin) * yVal );
    1347             : 
    1348             :   // 1 / (1 - exp(y - y_max)) or mirrored 1 / (1 - exp(y_min - y)).
    1349           0 :   else y = yMax - log( 1. + exp(aLowY + (aUppY - aLowY) * yVal) );
    1350             : 
    1351             :   // Mirror two cases.
    1352           0 :   if (iY == 2 || iY == 4 || iY == 6) y = -y;
    1353             : 
    1354             :   // Phase space integral in y.
    1355           0 :   intY0  = 2. * (atanMax - atanMin);
    1356           0 :   intY12 = 0.5 * pow2(2. * yMax);
    1357           0 :   intY34 = expYMax - expYMin;
    1358           0 :   intY56 = aUppY - aLowY;
    1359           0 :   double invWtY = (yCoef[0] / intY0) / cosh(y)
    1360           0 :      + (yCoef[1] / intY12) * (y + yMax) + (yCoef[2] / intY12) * (yMax - y);
    1361           0 :   if (!hasTwoLeptonBeams) invWtY
    1362           0 :     += (yCoef[3] / intY34) * exp(y)     + (yCoef[4] / intY34) * exp(-y);
    1363             :   else invWtY
    1364           0 :     += (yCoef[3] / intY56) / max( LEPTONXMIN, 1. - exp( y - yMax) )
    1365           0 :     +  (yCoef[4] / intY56) / max( LEPTONXMIN, 1. - exp(-y - yMax) );
    1366           0 :   wtY = 1. / invWtY;
    1367             : 
    1368             :   // Calculate x1 and x2.
    1369           0 :   x1H = sqrt(tau) * exp(y);
    1370           0 :   x2H = sqrt(tau) * exp(-y);
    1371           0 : }
    1372             : 
    1373             : //--------------------------------------------------------------------------
    1374             : 
    1375             : // Select z = cos(theta) according to a choice of shapes.
    1376             : // The selection is split in the positive- and negative-z regions,
    1377             : // since a pTmax cut can remove the region around z = 0.
    1378             : 
    1379             : void PhaseSpace::selectZ(int iZ, double zVal) {
    1380             : 
    1381             :   // Mass-dependent dampening of pT -> 0 limit.
    1382           0 :   ratio34 = max(TINY, 2. * s3 * s4 / pow2(sH));
    1383           0 :   unity34 = 1. + ratio34;
    1384           0 :   double ratiopT2 = 2. * pT2HatMin / max( SHATMINZ, sH);
    1385           0 :   if (ratiopT2 < PT2RATMINZ) ratio34 = max( ratio34, ratiopT2);
    1386             : 
    1387             :   // Common expressions in z limits.
    1388           0 :   double zPosMax = max(ratio34, unity34 + zMax);
    1389           0 :   double zNegMax = max(ratio34, unity34 - zMax);
    1390           0 :   double zPosMin = max(ratio34, unity34 + zMin);
    1391           0 :   double zNegMin = max(ratio34, unity34 - zMin);
    1392             : 
    1393             :   // Flat in z.
    1394           0 :   if (iZ == 0) {
    1395           0 :     if (zVal < 0.5) z = -(zMax + (zMin - zMax) * 2. * zVal);
    1396           0 :     else z = zMin + (zMax - zMin) * (2. * zVal - 1.);
    1397             : 
    1398             :   // 1 / (unity34 - z).
    1399           0 :   } else if (iZ == 1) {
    1400           0 :     double areaNeg = log(zPosMax / zPosMin);
    1401           0 :     double areaPos = log(zNegMin / zNegMax);
    1402           0 :     double area = areaNeg + areaPos;
    1403           0 :     if (zVal * area < areaNeg) {
    1404           0 :       double zValMod = zVal * area / areaNeg;
    1405           0 :       z = unity34 - zPosMax * pow(zPosMin / zPosMax, zValMod);
    1406           0 :     } else {
    1407           0 :       double zValMod = (zVal * area - areaNeg)/ areaPos;
    1408           0 :       z = unity34 - zNegMin * pow(zNegMax / zNegMin, zValMod);
    1409             :     }
    1410             : 
    1411             :   // 1 / (unity34 + z).
    1412           0 :   } else if (iZ == 2) {
    1413           0 :     double areaNeg = log(zNegMin / zNegMax);
    1414           0 :     double areaPos = log(zPosMax / zPosMin);
    1415           0 :     double area = areaNeg + areaPos;
    1416           0 :     if (zVal * area < areaNeg) {
    1417           0 :       double zValMod = zVal * area / areaNeg;
    1418           0 :       z = zNegMax * pow(zNegMin / zNegMax, zValMod) - unity34;
    1419           0 :     } else {
    1420           0 :       double zValMod = (zVal * area - areaNeg)/ areaPos;
    1421           0 :       z = zPosMin * pow(zPosMax / zPosMin, zValMod) - unity34;
    1422             :     }
    1423             : 
    1424             :   // 1 / (unity34 - z)^2.
    1425           0 :   } else if (iZ == 3) {
    1426           0 :     double areaNeg = 1. / zPosMin - 1. / zPosMax;
    1427           0 :     double areaPos = 1. / zNegMax - 1. / zNegMin;
    1428           0 :     double area = areaNeg + areaPos;
    1429           0 :     if (zVal * area < areaNeg) {
    1430           0 :       double zValMod = zVal * area / areaNeg;
    1431           0 :       z = unity34 - 1. / (1./zPosMax + areaNeg * zValMod);
    1432           0 :     } else {
    1433           0 :       double zValMod = (zVal * area - areaNeg)/ areaPos;
    1434           0 :       z = unity34 - 1. / (1./zNegMin + areaPos * zValMod);
    1435             :     }
    1436             : 
    1437             :   // 1 / (unity34 + z)^2.
    1438           0 :   } else if (iZ == 4) {
    1439           0 :     double areaNeg = 1. / zNegMax - 1. / zNegMin;
    1440           0 :     double areaPos = 1. / zPosMin - 1. / zPosMax;
    1441           0 :     double area = areaNeg + areaPos;
    1442           0 :     if (zVal * area < areaNeg) {
    1443           0 :       double zValMod = zVal * area / areaNeg;
    1444           0 :       z = 1. / (1./zNegMax - areaNeg * zValMod) - unity34;
    1445           0 :     } else {
    1446           0 :       double zValMod = (zVal * area - areaNeg)/ areaPos;
    1447           0 :       z = 1. / (1./zPosMin - areaPos * zValMod) - unity34;
    1448             :     }
    1449           0 :   }
    1450             : 
    1451             :   // Safety check for roundoff errors. Combinations with z.
    1452           0 :   if (z < 0.) z = min(-zMin, max(-zMax, z));
    1453           0 :   else z = min(zMax, max(zMin, z));
    1454           0 :   zNeg = max(ratio34, unity34 - z);
    1455           0 :   zPos = max(ratio34, unity34 + z);
    1456             : 
    1457             :   // Phase space integral in z.
    1458           0 :   double intZ0 = 2. * (zMax - zMin);
    1459           0 :   double intZ12 = log( (zPosMax * zNegMin) / (zPosMin * zNegMax) );
    1460           0 :   double intZ34 = 1. / zPosMin - 1. / zPosMax + 1. / zNegMax
    1461           0 :     - 1. / zNegMin;
    1462           0 :   wtZ = mHat * pAbs / ( (zCoef[0] / intZ0) + (zCoef[1] / intZ12) / zNeg
    1463           0 :     + (zCoef[2] / intZ12) / zPos + (zCoef[3] / intZ34) / pow2(zNeg)
    1464           0 :     + (zCoef[4] / intZ34) / pow2(zPos) );
    1465             : 
    1466             :   // Calculate tHat and uHat. Also gives pTHat.
    1467           0 :   double sH34 = -0.5 * (sH - s3 - s4);
    1468           0 :   tH  = sH34 + mHat * pAbs * z;
    1469           0 :   uH  = sH34 - mHat * pAbs * z;
    1470           0 :   pTH = sqrtpos( (tH * uH - s3 * s4) / sH);
    1471             : 
    1472           0 : }
    1473             : 
    1474             : //--------------------------------------------------------------------------
    1475             : 
    1476             : // Select three-body phase space according to a cylindrically based form
    1477             : // that can be chosen to favour low pT based on the form of propagators.
    1478             : 
    1479             : bool PhaseSpace::select3Body() {
    1480             : 
    1481             :   // Upper and lower limits of pT choice for 4 and 5.
    1482           0 :   double m35S = pow2(m3 + m5);
    1483           0 :   double pT4Smax = 0.25 * ( pow2(sH - s4 - m35S) - 4. * s4 * m35S ) / sH;
    1484           0 :   if (pTHatMax > pTHatMin) pT4Smax = min( pT2HatMax, pT4Smax);
    1485           0 :   double pT4Smin = pT2HatMin;
    1486           0 :   double m34S = pow2(m3 + m4);
    1487           0 :   double pT5Smax = 0.25 * ( pow2(sH - s5 - m34S) - 4. * s5 * m34S ) / sH;
    1488           0 :   if (pTHatMax > pTHatMin) pT5Smax = min( pT2HatMax, pT5Smax);
    1489           0 :   double pT5Smin = pT2HatMin;
    1490             : 
    1491             :   // Check that pT ranges not closed.
    1492           0 :   if ( pT4Smax < pow2(pTHatMin + MASSMARGIN) ) return false;
    1493           0 :   if ( pT5Smax < pow2(pTHatMin + MASSMARGIN) ) return false;
    1494             : 
    1495             :   // Select pT4S according to c0 + c1/(M^2 + pT^2) + c2/(M^2 + pT^2)^2.
    1496           0 :   double pTSmaxProp = pT4Smax + sTchan1;
    1497           0 :   double pTSminProp = pT4Smin + sTchan1;
    1498           0 :   double pTSratProp = pTSmaxProp / pTSminProp;
    1499           0 :   double pTSdiff    = pT4Smax - pT4Smin;
    1500           0 :   double rShape     = rndmPtr->flat();
    1501             :   double pT4S       = 0.;
    1502           0 :   if (rShape < frac3Flat) pT4S = pT4Smin + rndmPtr->flat() * pTSdiff;
    1503           0 :   else if (rShape < frac3Flat + frac3Pow1) pT4S = max( pT2HatMin,
    1504           0 :     pTSminProp * pow( pTSratProp, rndmPtr->flat() ) - sTchan1 );
    1505           0 :   else pT4S = max( pT2HatMin, pTSminProp * pTSmaxProp
    1506           0 :     / (pTSminProp + rndmPtr->flat()* pTSdiff) - sTchan1 );
    1507           0 :   double wt4 = pTSdiff / ( frac3Flat
    1508           0 :     + frac3Pow1 * pTSdiff / (log(pTSratProp) * (pT4S + sTchan1))
    1509           0 :     + frac3Pow2 * pTSminProp * pTSmaxProp / pow2(pT4S + sTchan1) );
    1510             : 
    1511             :   // Select pT5S according to c0 + c1/(M^2 + pT^2) + c2/(M^2 + pT^2)^2.
    1512           0 :   pTSmaxProp  = pT5Smax + sTchan2;
    1513           0 :   pTSminProp  = pT5Smin + sTchan2;
    1514           0 :   pTSratProp  = pTSmaxProp / pTSminProp;
    1515           0 :   pTSdiff     = pT5Smax - pT5Smin;
    1516           0 :   rShape      = rndmPtr->flat();
    1517             :   double pT5S = 0.;
    1518           0 :   if (rShape < frac3Flat) pT5S = pT5Smin + rndmPtr->flat() * pTSdiff;
    1519           0 :   else if (rShape < frac3Flat + frac3Pow1) pT5S = max( pT2HatMin,
    1520           0 :     pTSminProp * pow( pTSratProp, rndmPtr->flat() ) - sTchan2 );
    1521           0 :   else pT5S = max( pT2HatMin, pTSminProp * pTSmaxProp
    1522           0 :     / (pTSminProp + rndmPtr->flat()* pTSdiff) - sTchan2 );
    1523           0 :   double wt5 = pTSdiff / ( frac3Flat
    1524           0 :     + frac3Pow1 * pTSdiff / (log(pTSratProp) * (pT5S + sTchan2))
    1525           0 :     + frac3Pow2 * pTSminProp * pTSmaxProp / pow2(pT5S + sTchan2) );
    1526             : 
    1527             :   // Select azimuthal angles and check that third pT in range.
    1528           0 :   double phi4 = 2. * M_PI * rndmPtr->flat();
    1529           0 :   double phi5 = 2. * M_PI * rndmPtr->flat();
    1530           0 :   double pT3S = max( 0., pT4S + pT5S + 2. * sqrt(pT4S * pT5S)
    1531           0 :     * cos(phi4 - phi5) );
    1532           0 :   if ( pT3S < pT2HatMin || (pTHatMax > pTHatMin && pT3S > pT2HatMax) )
    1533           0 :     return false;
    1534             : 
    1535             :   // Calculate transverse masses and check that phase space not closed.
    1536           0 :   double sT3 = s3 + pT3S;
    1537           0 :   double sT4 = s4 + pT4S;
    1538           0 :   double sT5 = s5 + pT5S;
    1539           0 :   double mT3 = sqrt(sT3);
    1540           0 :   double mT4 = sqrt(sT4);
    1541           0 :   double mT5 = sqrt(sT5);
    1542           0 :   if ( mT3 + mT4 + mT5 + MASSMARGIN > mHat ) return false;
    1543             : 
    1544             :   // Select rapidity for particle 3 and check that phase space not closed.
    1545           0 :   double m45S = pow2(mT4 + mT5);
    1546           0 :   double y3max = log( ( sH + sT3 - m45S + sqrtpos( pow2(sH - sT3 - m45S)
    1547           0 :     - 4 * sT3 * m45S ) ) / (2. * mHat * mT3) );
    1548           0 :   if (y3max < YRANGEMARGIN) return false;
    1549           0 :   double y3    = (2. * rndmPtr->flat() - 1.) * (1. -  YRANGEMARGIN) * y3max;
    1550           0 :   double pz3   = mT3 * sinh(y3);
    1551           0 :   double e3    = mT3 * cosh(y3);
    1552             : 
    1553             :   // Find momentum transfers in the two mirror solutions (in 4-5 frame).
    1554           0 :   double pz45  = -pz3;
    1555           0 :   double e45   = mHat - e3;
    1556           0 :   double sT45  = e45 * e45 - pz45 * pz45;
    1557           0 :   double lam45 = sqrtpos( pow2(sT45 - sT4 - sT5) - 4. * sT4 * sT5 );
    1558           0 :   if (lam45 < YRANGEMARGIN * sH) return false;
    1559           0 :   double lam4e = sT45 + sT4 - sT5;
    1560           0 :   double lam5e = sT45 + sT5 - sT4;
    1561           0 :   double tFac  = -0.5 * mHat / sT45;
    1562           0 :   double t1Pos = tFac * (e45 - pz45) * (lam4e - lam45);
    1563           0 :   double t1Neg = tFac * (e45 - pz45) * (lam4e + lam45);
    1564           0 :   double t2Pos = tFac * (e45 + pz45) * (lam5e - lam45);
    1565           0 :   double t2Neg = tFac * (e45 + pz45) * (lam5e + lam45);
    1566             : 
    1567             :   // Construct relative mirror weights and make choice.
    1568             :   double wtPosUnnorm = 1.;
    1569             :   double wtNegUnnorm = 1.;
    1570           0 :   if (useMirrorWeight) {
    1571           0 :     wtPosUnnorm  = 1./ pow2( (t1Pos - sTchan1) * (t2Pos - sTchan2) );
    1572           0 :     wtNegUnnorm  = 1./ pow2( (t1Neg - sTchan1) * (t2Neg - sTchan2) );
    1573           0 :   }
    1574           0 :   double wtPos   = wtPosUnnorm / (wtPosUnnorm + wtNegUnnorm);
    1575           0 :   double wtNeg   = wtNegUnnorm / (wtPosUnnorm + wtNegUnnorm);
    1576           0 :   double epsilon = (rndmPtr->flat() < wtPos) ? 1. : -1.;
    1577             : 
    1578             :   // Construct four-vectors in rest frame of subprocess.
    1579           0 :   double px4 = sqrt(pT4S) * cos(phi4);
    1580           0 :   double py4 = sqrt(pT4S) * sin(phi4);
    1581           0 :   double px5 = sqrt(pT5S) * cos(phi5);
    1582           0 :   double py5 = sqrt(pT5S) * sin(phi5);
    1583           0 :   double pz4 = 0.5 * (pz45 * lam4e + epsilon * e45 * lam45) / sT45;
    1584           0 :   double pz5 = pz45 - pz4;
    1585           0 :   double e4  = sqrt(sT4 + pz4 * pz4);
    1586           0 :   double e5  = sqrt(sT5 + pz5 * pz5);
    1587           0 :   p3cm       = Vec4( -(px4 + px5), -(py4 + py5), pz3, e3);
    1588           0 :   p4cm       = Vec4( px4, py4, pz4, e4);
    1589           0 :   p5cm       = Vec4( px5, py5, pz5, e5);
    1590             : 
    1591             :   // Total weight to associate with kinematics choice.
    1592           0 :   wt3Body    = wt4 * wt5 * (2. * y3max) / (128. * pow3(M_PI) * lam45);
    1593           0 :   wt3Body   *= (epsilon > 0.) ? 1. / wtPos : 1. / wtNeg;
    1594             : 
    1595             :   // Cross section of form |M|^2/(2 sHat) dPS_3 so need 1/(2 sHat).
    1596           0 :   wt3Body   /= (2. * sH);
    1597             : 
    1598             :   // Done.
    1599             :   return true;
    1600             : 
    1601           0 : }
    1602             : 
    1603             : //--------------------------------------------------------------------------
    1604             : 
    1605             : // Solve linear equation system for better phase space coefficients.
    1606             : 
    1607             : void PhaseSpace::solveSys( int n, int bin[8], double vec[8],
    1608             :   double mat[8][8], double coef[8], ostream& os) {
    1609             : 
    1610             :   // Optional printout.
    1611           0 :   if (showSearch) {
    1612           0 :     os << "\n Equation system: " << setw(5) << bin[0];
    1613           0 :     for (int j = 0; j < n; ++j) os << setw(12) << mat[0][j];
    1614           0 :     os << setw(12) << vec[0] << "\n";
    1615           0 :     for (int i = 1; i < n; ++i) {
    1616           0 :       os << "                  " << setw(5) << bin[i];
    1617           0 :       for (int j = 0; j < n; ++j) os << setw(12) << mat[i][j];
    1618           0 :       os << setw(12) << vec[i] << "\n";
    1619             :     }
    1620           0 :   }
    1621             : 
    1622             :   // Local variables.
    1623           0 :   double vecNor[8], coefTmp[8];
    1624           0 :   for (int i = 0; i < n; ++i) coefTmp[i] = 0.;
    1625             : 
    1626             :   // Check if equation system solvable.
    1627             :   bool canSolve = true;
    1628           0 :   for (int i = 0; i < n; ++i) if (bin[i] == 0) canSolve = false;
    1629             :   double vecSum = 0.;
    1630           0 :   for (int i = 0; i < n; ++i) vecSum += vec[i];
    1631           0 :   if (abs(vecSum) < TINY) canSolve = false;
    1632             : 
    1633             :   // Solve to find relative importance of cross-section pieces.
    1634           0 :   if (canSolve) {
    1635           0 :     for (int i = 0; i < n; ++i) vecNor[i] = max( 0.1, vec[i] / vecSum);
    1636           0 :     for (int k = 0; k < n - 1; ++k) {
    1637           0 :       for (int i = k + 1; i < n; ++i) {
    1638           0 :         if (abs(mat[k][k]) < TINY) {canSolve = false; break;}
    1639           0 :         double ratio = mat[i][k] / mat[k][k];
    1640           0 :         vec[i] -= ratio * vec[k];
    1641           0 :         for (int j = k; j < n; ++j) mat[i][j] -= ratio * mat[k][j];
    1642             :       }
    1643           0 :       if (!canSolve) break;
    1644             :     }
    1645           0 :     if (canSolve) {
    1646           0 :       for (int k = n - 1; k >= 0; --k) {
    1647           0 :         for (int j = k + 1; j < n; ++j) vec[k] -= mat[k][j] * coefTmp[j];
    1648           0 :         coefTmp[k] = vec[k] / mat[k][k];
    1649             :       }
    1650           0 :     }
    1651             :   }
    1652             : 
    1653             :   // Share evenly if failure.
    1654           0 :   if (!canSolve) for (int i = 0; i < n; ++i) {
    1655           0 :     coefTmp[i] = 1.;
    1656           0 :     vecNor[i] = 0.1;
    1657           0 :     if (vecSum > TINY) vecNor[i] = max(0.1, vec[i] / vecSum);
    1658           0 :   }
    1659             : 
    1660             :   // Normalize coefficients, with piece shared democratically.
    1661             :   double coefSum = 0.;
    1662             :   vecSum = 0.;
    1663           0 :   for (int i = 0; i < n; ++i) {
    1664           0 :     coefTmp[i] = max( 0., coefTmp[i]);
    1665           0 :     coefSum += coefTmp[i];
    1666           0 :     vecSum += vecNor[i];
    1667             :   }
    1668           0 :   if (coefSum > 0.) for (int i = 0; i < n; ++i) coef[i] = EVENFRAC / n
    1669           0 :     + (1. - EVENFRAC) * 0.5 * (coefTmp[i] / coefSum + vecNor[i] / vecSum);
    1670           0 :   else for (int i = 0; i < n; ++i) coef[i] = 1. / n;
    1671             : 
    1672             :   // Optional printout.
    1673           0 :   if (showSearch) {
    1674           0 :     os << " Solution:             ";
    1675           0 :     for (int i = 0; i < n; ++i) os << setw(12) << coef[i];
    1676           0 :     os << "\n";
    1677           0 :   }
    1678           0 : }
    1679             : 
    1680             : //--------------------------------------------------------------------------
    1681             : 
    1682             : // Setup mass selection for one resonance at a time - part 1.
    1683             : 
    1684             : void PhaseSpace::setupMass1(int iM) {
    1685             : 
    1686             :   // Identity for mass seletion; is 0 also for light quarks (not yet selected).
    1687           0 :   if (iM == 3) idMass[iM] = abs(sigmaProcessPtr->id3Mass());
    1688           0 :   if (iM == 4) idMass[iM] = abs(sigmaProcessPtr->id4Mass());
    1689           0 :   if (iM == 5) idMass[iM] = abs(sigmaProcessPtr->id5Mass());
    1690             : 
    1691             :   // Masses and widths of resonances.
    1692           0 :   if (idMass[iM] == 0) {
    1693           0 :     mPeak[iM]  = 0.;
    1694           0 :     mWidth[iM] = 0.;
    1695           0 :     mMin[iM]   = 0.;
    1696           0 :     mMax[iM]   = 0.;
    1697           0 :   } else {
    1698           0 :     mPeak[iM]  = particleDataPtr->m0(idMass[iM]);
    1699           0 :     mWidth[iM] = particleDataPtr->mWidth(idMass[iM]);
    1700           0 :     mMin[iM]   = particleDataPtr->mMin(idMass[iM]);
    1701           0 :     mMax[iM]   = particleDataPtr->mMax(idMass[iM]);
    1702             :     // gmZmode == 1 means pure photon propagator; set at lower mass limit.
    1703           0 :     if (idMass[iM] == 23 && gmZmode == 1) mPeak[iM] = mMin[iM];
    1704             :   }
    1705             : 
    1706             :   // Mass and width combinations for Breit-Wigners.
    1707           0 :   sPeak[iM]    = mPeak[iM] * mPeak[iM];
    1708           0 :   useBW[iM]    = useBreitWigners && (mWidth[iM] > minWidthBreitWigners);
    1709           0 :   if (!useBW[iM]) mWidth[iM] = 0.;
    1710           0 :   mw[iM]       = mPeak[iM] * mWidth[iM];
    1711           0 :   wmRat[iM]    = (idMass[iM] == 0 || mPeak[iM] == 0.)
    1712           0 :                ? 0. : mWidth[iM] / mPeak[iM];
    1713             : 
    1714             :   // Simple Breit-Wigner range, upper edge to be corrected subsequently.
    1715           0 :   if (useBW[iM]) {
    1716           0 :     mLower[iM] = mMin[iM];
    1717           0 :     mUpper[iM] = mHatMax;
    1718           0 :   }
    1719             : 
    1720           0 : }
    1721             : 
    1722             : //--------------------------------------------------------------------------
    1723             : 
    1724             : // Setup mass selection for one resonance at a time - part 2.
    1725             : 
    1726             : void PhaseSpace::setupMass2(int iM, double distToThresh) {
    1727             : 
    1728             :   // Store reduced Breit-Wigner range.
    1729           0 :   if (mMax[iM] > mMin[iM]) mUpper[iM] = min( mUpper[iM], mMax[iM]);
    1730           0 :   sLower[iM]     = mLower[iM] * mLower[iM];
    1731           0 :   sUpper[iM]     = mUpper[iM] * mUpper[iM];
    1732             : 
    1733             :   // Prepare to select m3 by BW + flat + 1/s_3.
    1734             :   // Determine relative coefficients by allowed mass range.
    1735           0 :   if (distToThresh > THRESHOLDSIZE) {
    1736           0 :     fracFlat[iM] = 0.1;
    1737           0 :     fracInv[iM]  = 0.1;
    1738           0 :   } else if (distToThresh > - THRESHOLDSIZE) {
    1739           0 :     fracFlat[iM] = 0.25 - 0.15 * distToThresh / THRESHOLDSIZE;
    1740           0 :     fracInv [iM] = 0.15 - 0.05 * distToThresh / THRESHOLDSIZE;
    1741           0 :   } else {
    1742           0 :    fracFlat[iM]  = 0.4;
    1743           0 :    fracInv[iM]   = 0.2;
    1744             :   }
    1745             : 
    1746             :   // For gamma*/Z0: increase 1/s_i part and introduce 1/s_i^2 part.
    1747           0 :   fracInv2[iM]   = 0.;
    1748           0 :   if (idMass[iM] == 23 && gmZmode == 0) {
    1749           0 :     fracFlat[iM] *= 0.5;
    1750           0 :     fracInv[iM]  = 0.5 * fracInv[iM] + 0.25;
    1751           0 :     fracInv2[iM] = 0.25;
    1752           0 :   } else if (idMass[iM] == 23 && gmZmode == 1) {
    1753           0 :     fracFlat[iM] = 0.1;
    1754           0 :     fracInv[iM]  = 0.4;
    1755           0 :     fracInv2[iM] = 0.4;
    1756           0 :   }
    1757             : 
    1758             :   // Normalization integrals for the respective contribution.
    1759           0 :   atanLower[iM]  = atan( (sLower[iM] - sPeak[iM])/ mw[iM] );
    1760           0 :   atanUpper[iM]  = atan( (sUpper[iM] - sPeak[iM])/ mw[iM] );
    1761           0 :   intBW[iM]      = atanUpper[iM] - atanLower[iM];
    1762           0 :   intFlat[iM]    = sUpper[iM] - sLower[iM];
    1763           0 :   intInv[iM]     = log( sUpper[iM] / sLower[iM] );
    1764           0 :   intInv2[iM]    = 1./sLower[iM] - 1./sUpper[iM];
    1765             : 
    1766           0 : }
    1767             : 
    1768             : //--------------------------------------------------------------------------
    1769             : 
    1770             : // Select Breit-Wigner-distributed or fixed masses.
    1771             : 
    1772             : void PhaseSpace::trialMass(int iM) {
    1773             : 
    1774             :   // References to masses to be set.
    1775           0 :   double& mSet = (iM == 3) ? m3 : ( (iM == 4) ? m4 : m5 );
    1776           0 :   double& sSet = (iM == 3) ? s3 : ( (iM == 4) ? s4 : s5 );
    1777             : 
    1778             :   // Distribution for m_i is BW + flat + 1/s_i + 1/s_i^2.
    1779           0 :   if (useBW[iM]) {
    1780           0 :     double pickForm = rndmPtr->flat();
    1781           0 :     if (pickForm > fracFlat[iM] + fracInv[iM] + fracInv2[iM])
    1782           0 :       sSet = sPeak[iM] + mw[iM] * tan( atanLower[iM]
    1783           0 :            + rndmPtr->flat() * intBW[iM] );
    1784           0 :     else if (pickForm > fracInv[iM] + fracInv2[iM])
    1785           0 :       sSet = sLower[iM] + rndmPtr->flat() * (sUpper[iM] - sLower[iM]);
    1786           0 :     else if (pickForm > fracInv2[iM])
    1787           0 :       sSet = sLower[iM] * pow( sUpper[iM] / sLower[iM], rndmPtr->flat() );
    1788           0 :     else sSet = sLower[iM] * sUpper[iM]
    1789           0 :       / (sLower[iM] + rndmPtr->flat() * (sUpper[iM] - sLower[iM]));
    1790           0 :     mSet = sqrt(sSet);
    1791             : 
    1792             :   // Else m_i is fixed at peak value.
    1793           0 :   } else {
    1794           0 :     mSet = mPeak[iM];
    1795           0 :     sSet = sPeak[iM];
    1796             :   }
    1797             : 
    1798           0 : }
    1799             : 
    1800             : //--------------------------------------------------------------------------
    1801             : 
    1802             : // Naively a fixed-width Breit-Wigner is used to pick the mass.
    1803             : // Here come the correction factors for
    1804             : // (i) preselection according to BW + flat in s_i + 1/s_i + 1/s_i^2,
    1805             : // (ii) reduced allowed mass range,
    1806             : // (iii) running width, i.e. m0*Gamma0 -> s*Gamma0/m0.
    1807             : // In the end, the weighted distribution is a running-width BW.
    1808             : 
    1809             : double PhaseSpace::weightMass(int iM) {
    1810             : 
    1811             :   // Reference to mass and to Breit-Wigner weight to be set.
    1812           0 :   double& sSet   = (iM == 3) ? s3 : ( (iM == 4) ? s4 : s5 );
    1813           0 :   double& runBWH = (iM == 3) ? runBW3H : ( (iM == 4) ? runBW4H : runBW5H );
    1814             : 
    1815             :   // Default weight if no Breit-Wigner.
    1816           0 :   runBWH = 1.;
    1817           0 :   if (!useBW[iM]) return 1.;
    1818             : 
    1819             :   // Weight of generated distribution.
    1820           0 :   double genBW  = (1. - fracFlat[iM] - fracInv[iM] - fracInv2[iM])
    1821           0 :       * mw[iM] / ( (pow2(sSet - sPeak[iM]) + pow2(mw[iM])) * intBW[iM])
    1822           0 :       + fracFlat[iM] / intFlat[iM] + fracInv[iM] / (sSet * intInv[iM])
    1823           0 :       + fracInv2[iM] / (sSet*sSet * intInv2[iM]);
    1824             : 
    1825             :   // Weight of distribution with running width in Breit-Wigner.
    1826           0 :   double mwRun = sSet * wmRat[iM];
    1827           0 :   runBWH = mwRun / (pow2(sSet - sPeak[iM]) + pow2(mwRun)) / M_PI;
    1828             : 
    1829             :   // Done.
    1830           0 :   return (runBWH / genBW);
    1831             : 
    1832           0 : }
    1833             : 
    1834             : //==========================================================================
    1835             : 
    1836             : // PhaseSpace2to1tauy class.
    1837             : // 2 -> 1 kinematics for normal subprocesses.
    1838             : 
    1839             : //--------------------------------------------------------------------------
    1840             : 
    1841             : // Set limits for resonance mass selection.
    1842             : 
    1843             : bool PhaseSpace2to1tauy::setupMass() {
    1844             : 
    1845             :   // Treat Z0 as such or as gamma*/Z0
    1846           0 :   gmZmode         = gmZmodeGlobal;
    1847           0 :   int gmZmodeProc = sigmaProcessPtr->gmZmode();
    1848           0 :   if (gmZmodeProc >= 0) gmZmode = gmZmodeProc;
    1849             : 
    1850             :   // Mass limits for current resonance.
    1851           0 :   int idRes = abs(sigmaProcessPtr->resonanceA());
    1852           0 :   int idTmp = abs(sigmaProcessPtr->resonanceB());
    1853           0 :   if (idTmp > 0) idRes = idTmp;
    1854           0 :   double mResMin = (idRes == 0) ? 0. : particleDataPtr->mMin(idRes);
    1855           0 :   double mResMax = (idRes == 0) ? 0. : particleDataPtr->mMax(idRes);
    1856             : 
    1857             :   // Compare with global mass limits and pick tighter of them.
    1858           0 :   mHatMin = max( mResMin, mHatGlobalMin);
    1859           0 :   sHatMin = mHatMin*mHatMin;
    1860           0 :   mHatMax = eCM;
    1861           0 :   if (mResMax > mResMin) mHatMax = min( mHatMax, mResMax);
    1862           0 :   if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( mHatMax, mHatGlobalMax);
    1863           0 :   sHatMax = mHatMax*mHatMax;
    1864             : 
    1865             :   // Default Breit-Wigner weight.
    1866           0 :   wtBW = 1.;
    1867             : 
    1868             :   // Fail if mass window (almost) closed.
    1869           0 :   return (mHatMax > mHatMin + MASSMARGIN);
    1870             : 
    1871           0 : }
    1872             : 
    1873             : //--------------------------------------------------------------------------
    1874             : 
    1875             : // Construct the four-vector kinematics from the trial values.
    1876             : 
    1877             : bool PhaseSpace2to1tauy::finalKin() {
    1878             : 
    1879             :   // Particle masses; incoming always on mass shell.
    1880           0 :   mH[1] = 0.;
    1881           0 :   mH[2] = 0.;
    1882           0 :   mH[3] = mHat;
    1883             : 
    1884             :   // Incoming partons along beam axes. Outgoing has sum of momenta.
    1885           0 :   pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H);
    1886           0 :   pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H);
    1887           0 :   pH[3] = pH[1] + pH[2];
    1888             : 
    1889             :   // Done.
    1890           0 :   return true;
    1891             : }
    1892             : 
    1893             : //==========================================================================
    1894             : 
    1895             : // PhaseSpace2to2tauyz class.
    1896             : // 2 -> 2 kinematics for normal subprocesses.
    1897             : 
    1898             : //--------------------------------------------------------------------------
    1899             : 
    1900             : // Set up for fixed or Breit-Wigner mass selection.
    1901             : 
    1902             : bool PhaseSpace2to2tauyz::setupMasses() {
    1903             : 
    1904             :   // Treat Z0 as such or as gamma*/Z0
    1905           0 :   gmZmode         = gmZmodeGlobal;
    1906           0 :   int gmZmodeProc = sigmaProcessPtr->gmZmode();
    1907           0 :   if (gmZmodeProc >= 0) gmZmode = gmZmodeProc;
    1908             : 
    1909             :   // Set sHat limits - based on global limits only.
    1910           0 :   mHatMin = mHatGlobalMin;
    1911           0 :   sHatMin = mHatMin*mHatMin;
    1912           0 :   mHatMax = eCM;
    1913           0 :   if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( eCM, mHatGlobalMax);
    1914           0 :   sHatMax = mHatMax*mHatMax;
    1915             : 
    1916             :   // Masses and widths of resonances.
    1917           0 :   setupMass1(3);
    1918           0 :   setupMass1(4);
    1919             : 
    1920             :   // Reduced mass range when two massive particles.
    1921           0 :   if (useBW[3]) mUpper[3] -= (useBW[4]) ? mMin[4] : mPeak[4];
    1922           0 :   if (useBW[4]) mUpper[4] -= (useBW[3]) ? mMin[3] : mPeak[3];
    1923             : 
    1924             :   // If closed phase space then unallowed process.
    1925             :   bool physical = true;
    1926           0 :   if (useBW[3] && mUpper[3] < mLower[3] + MASSMARGIN) physical = false;
    1927           0 :   if (useBW[4] && mUpper[4] < mLower[4] + MASSMARGIN) physical = false;
    1928           0 :   if (!useBW[3] && !useBW[4] && mHatMax < mPeak[3] + mPeak[4] + MASSMARGIN)
    1929           0 :     physical = false;
    1930           0 :   if (!physical) return false;
    1931             : 
    1932             :   // If either particle is massless then need extra pTHat cut.
    1933           0 :   pTHatMin   = pTHatGlobalMin;
    1934           0 :   if (mPeak[3] < pTHatMinDiverge || mPeak[4] < pTHatMinDiverge)
    1935           0 :     pTHatMin = max( pTHatMin, pTHatMinDiverge);
    1936           0 :   pT2HatMin  = pTHatMin * pTHatMin;
    1937           0 :   pTHatMax   = pTHatGlobalMax;
    1938           0 :   pT2HatMax  = pTHatMax * pTHatMax;
    1939             : 
    1940             :   // Prepare to select m3 by BW + flat + 1/s_3.
    1941           0 :   if (useBW[3]) {
    1942           0 :     double distToThreshA = (mHatMax - mPeak[3] - mPeak[4]) * mWidth[3]
    1943           0 :       / (pow2(mWidth[3]) + pow2(mWidth[4]));
    1944           0 :     double distToThreshB = (mHatMax - mPeak[3] - mMin[4]) / mWidth[3];
    1945           0 :     double distToThresh = min( distToThreshA, distToThreshB);
    1946           0 :     setupMass2(3, distToThresh);
    1947           0 :   }
    1948             : 
    1949             :   // Prepare to select m4 by BW + flat + 1/s_4.
    1950           0 :   if (useBW[4]) {
    1951           0 :     double distToThreshA = (mHatMax - mPeak[3] - mPeak[4]) * mWidth[4]
    1952           0 :       / (pow2(mWidth[3]) + pow2(mWidth[4]));
    1953           0 :     double distToThreshB = (mHatMax - mMin[3] - mPeak[4]) / mWidth[4];
    1954           0 :     double distToThresh = min( distToThreshA, distToThreshB);
    1955           0 :     setupMass2(4, distToThresh);
    1956           0 :   }
    1957             : 
    1958             :   // Initialization masses. Special cases when constrained phase space.
    1959           0 :   m3 = (useBW[3]) ? min(mPeak[3], mUpper[3]) : mPeak[3];
    1960           0 :   m4 = (useBW[4]) ? min(mPeak[4], mUpper[4]) : mPeak[4];
    1961           0 :   if (m3 + m4 + THRESHOLDSIZE * (mWidth[3] + mWidth[4]) + MASSMARGIN
    1962           0 :     > mHatMax) {
    1963           0 :     if (useBW[3] && useBW[4]) physical = constrainedM3M4();
    1964           0 :     else if (useBW[3]) physical = constrainedM3();
    1965           0 :     else if (useBW[4]) physical = constrainedM4();
    1966             :   }
    1967           0 :   s3 = m3*m3;
    1968           0 :   s4 = m4*m4;
    1969             : 
    1970             :   // Correct selected mass-spectrum to running-width Breit-Wigner.
    1971             :   // Extra safety margin for maximum search.
    1972           0 :   wtBW = 1.;
    1973           0 :   if (useBW[3]) wtBW *= weightMass(3) * EXTRABWWTMAX;
    1974           0 :   if (useBW[4]) wtBW *= weightMass(4) * EXTRABWWTMAX;
    1975             : 
    1976             :   // Done.
    1977           0 :   return physical;
    1978             : 
    1979           0 : }
    1980             : 
    1981             : 
    1982             : //--------------------------------------------------------------------------
    1983             : 
    1984             : // Select Breit-Wigner-distributed or fixed masses.
    1985             : 
    1986             : bool PhaseSpace2to2tauyz::trialMasses() {
    1987             : 
    1988             :   // By default vanishing cross section.
    1989           0 :   sigmaNw = 0.;
    1990           0 :   wtBW = 1.;
    1991             : 
    1992             :   // Pick m3 and m4 independently.
    1993           0 :   trialMass(3);
    1994           0 :   trialMass(4);
    1995             : 
    1996             :   // If outside phase space then reject event.
    1997           0 :   if (m3 + m4 + MASSMARGIN > mHatMax) return false;
    1998             : 
    1999             :   // Correct selected mass-spectrum to running-width Breit-Wigner.
    2000           0 :   if (useBW[3]) wtBW *= weightMass(3);
    2001           0 :   if (useBW[4]) wtBW *= weightMass(4);
    2002             : 
    2003             :   // Done.
    2004           0 :   return true;
    2005           0 : }
    2006             : 
    2007             : //--------------------------------------------------------------------------
    2008             : 
    2009             : // Construct the four-vector kinematics from the trial values.
    2010             : 
    2011             : bool PhaseSpace2to2tauyz::finalKin() {
    2012             : 
    2013             :   // Assign masses to particles assumed massless in matrix elements.
    2014           0 :   int id3 = sigmaProcessPtr->id(3);
    2015           0 :   int id4 = sigmaProcessPtr->id(4);
    2016           0 :   if (idMass[3] == 0) { m3 = particleDataPtr->m0(id3); s3 = m3*m3; }
    2017           0 :   if (idMass[4] == 0) { m4 = particleDataPtr->m0(id4); s4 = m4*m4; }
    2018             : 
    2019             :   // Sometimes swap tHat <-> uHat to reflect chosen final-state order.
    2020           0 :   if (sigmaProcessPtr->swappedTU()) {
    2021           0 :     swap(tH, uH);
    2022           0 :     z = -z;
    2023           0 :   }
    2024             : 
    2025             :   // Check that phase space still open after new mass assignment.
    2026           0 :   if (m3 + m4 + MASSMARGIN > mHat) {
    2027           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::finalKin: "
    2028             :       "failed after mass assignment");
    2029           0 :     return false;
    2030             :   }
    2031           0 :   p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH;
    2032           0 :   pAbs = sqrtpos( p2Abs );
    2033             : 
    2034             :   // Particle masses; incoming always on mass shell.
    2035           0 :   mH[1] = 0.;
    2036           0 :   mH[2] = 0.;
    2037           0 :   mH[3] = m3;
    2038           0 :   mH[4] = m4;
    2039             : 
    2040             :   // Incoming partons along beam axes.
    2041           0 :   pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H);
    2042           0 :   pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H);
    2043             : 
    2044             :   // Outgoing partons initially in collision CM frame along beam axes.
    2045           0 :   pH[3] = Vec4( 0., 0.,  pAbs, 0.5 * (sH + s3 - s4) / mHat);
    2046           0 :   pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (sH + s4 - s3) / mHat);
    2047             : 
    2048             :   // Then rotate and boost them to overall CM frame.
    2049           0 :   theta = acos(z);
    2050           0 :   phi = 2. * M_PI * rndmPtr->flat();
    2051           0 :   betaZ = (x1H - x2H)/(x1H + x2H);
    2052           0 :   pH[3].rot( theta, phi);
    2053           0 :   pH[4].rot( theta, phi);
    2054           0 :   pH[3].bst( 0., 0., betaZ);
    2055           0 :   pH[4].bst( 0., 0., betaZ);
    2056           0 :   pTH = pAbs * sin(theta);
    2057             : 
    2058             :   // Done.
    2059           0 :   return true;
    2060           0 : }
    2061             : 
    2062             : //--------------------------------------------------------------------------
    2063             : 
    2064             : // Special choice of m3 and m4 when mHatMax push them off mass shell.
    2065             : // Vary x in expression m3 + m4 = mHatMax - x * (Gamma3 + Gamma4).
    2066             : // For each x try to put either 3 or 4 as close to mass shell as possible.
    2067             : // Maximize BW_3 * BW_4 * beta_34, where latter approximate phase space.
    2068             : 
    2069             : bool PhaseSpace2to2tauyz::constrainedM3M4() {
    2070             : 
    2071             :   // Initial values.
    2072             :   bool foundNonZero = false;
    2073             :   double wtMassMax = 0.;
    2074             :   double m3WtMax = 0.;
    2075             :   double m4WtMax = 0.;
    2076           0 :   double xMax = (mHatMax - mLower[3] - mLower[4]) / (mWidth[3] + mWidth[4]);
    2077           0 :   double xStep = THRESHOLDSTEP * min(1., xMax);
    2078             :   double xNow = 0.;
    2079             :   double wtMassXbin, wtMassMaxOld, m34, mT34Min, wtMassNow,
    2080             :     wtBW3Now, wtBW4Now, beta34Now;
    2081             : 
    2082             :   // Step through increasing x values.
    2083           0 :   do {
    2084           0 :     xNow += xStep;
    2085             :     wtMassXbin = 0.;
    2086             :     wtMassMaxOld = wtMassMax;
    2087           0 :     m34 = mHatMax - xNow * (mWidth[3] + mWidth[4]);
    2088             : 
    2089             :     // Study point where m3 as close as possible to on-shell.
    2090           0 :     m3 = min( mUpper[3], m34 - mLower[4]);
    2091           0 :     if (m3 > mPeak[3]) m3 = max( mLower[3], mPeak[3]);
    2092           0 :     m4 = m34 - m3;
    2093           0 :     if (m4 < mLower[4]) {m4 = mLower[4]; m3 = m34 - m4;}
    2094             : 
    2095             :     // Check that inside phase space limit set by pTmin.
    2096           0 :     mT34Min = sqrt(m3*m3 + pT2HatMin) + sqrt(m4*m4 + pT2HatMin);
    2097           0 :     if (mT34Min < mHatMax) {
    2098             : 
    2099             :       // Breit-Wigners and beta factor give total weight.
    2100             :       wtMassNow = 0.;
    2101           0 :       if (m3 > mLower[3] && m3 < mUpper[3] && m4 > mLower[4]
    2102           0 :         && m4 < mUpper[4]) {
    2103           0 :         wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) );
    2104           0 :         wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) );
    2105           0 :         beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4)
    2106           0 :           - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax);
    2107           0 :         wtMassNow = wtBW3Now * wtBW4Now * beta34Now;
    2108           0 :       }
    2109             : 
    2110             :       // Store new maximum, if any.
    2111           0 :       if (wtMassNow > wtMassXbin) wtMassXbin = wtMassNow;
    2112           0 :       if (wtMassNow > wtMassMax) {
    2113             :         foundNonZero = true;
    2114             :         wtMassMax = wtMassNow;
    2115           0 :         m3WtMax = m3;
    2116           0 :         m4WtMax = m4;
    2117           0 :       }
    2118             :     }
    2119             : 
    2120             :     // Study point where m4 as close as possible to on-shell.
    2121           0 :     m4 = min( mUpper[4], m34 - mLower[3]);
    2122           0 :     if (m4 > mPeak[4]) m4 = max( mLower[4], mPeak[4]);
    2123           0 :     m3 = m34 - m4;
    2124           0 :     if (m3 < mLower[3]) {m3 = mLower[3]; m4 = m34 - m3;}
    2125             : 
    2126             :     // Check that inside phase space limit set by pTmin.
    2127           0 :     mT34Min = sqrt(m3*m3 + pT2HatMin) + sqrt(m4*m4 + pT2HatMin);
    2128           0 :     if (mT34Min < mHatMax) {
    2129             : 
    2130             :       // Breit-Wigners and beta factor give total weight.
    2131             :       wtMassNow = 0.;
    2132           0 :       if (m3 > mLower[3] && m3 < mUpper[3] && m4 > mLower[4]
    2133           0 :         && m4 < mUpper[4]) {
    2134           0 :         wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) );
    2135           0 :         wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) );
    2136           0 :         beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4)
    2137           0 :           - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax);
    2138           0 :         wtMassNow = wtBW3Now * wtBW4Now * beta34Now;
    2139           0 :       }
    2140             : 
    2141             :       // Store new maximum, if any.
    2142           0 :       if (wtMassNow > wtMassXbin) wtMassXbin = wtMassNow;
    2143           0 :       if (wtMassNow > wtMassMax) {
    2144             :         foundNonZero = true;
    2145             :         wtMassMax = wtMassNow;
    2146           0 :         m3WtMax = m3;
    2147           0 :         m4WtMax = m4;
    2148           0 :       }
    2149             :     }
    2150             : 
    2151             :   // Continue stepping if increasing trend and more x range available.
    2152           0 :   } while ( (!foundNonZero || wtMassXbin > wtMassMaxOld)
    2153           0 :     && xNow < xMax - xStep);
    2154             : 
    2155             :   // Restore best values for subsequent maximization. Return.
    2156           0 :   m3 = m3WtMax;
    2157           0 :   m4 = m4WtMax;
    2158           0 :   return foundNonZero;
    2159             : 
    2160           0 : }
    2161             : 
    2162             : //--------------------------------------------------------------------------
    2163             : 
    2164             : // Special choice of m3 when mHatMax pushes it off mass shell.
    2165             : // Vary x in expression m3 = mHatMax - m4 - x * Gamma3.
    2166             : // Maximize BW_3 * beta_34, where latter approximate phase space.
    2167             : 
    2168             : bool PhaseSpace2to2tauyz::constrainedM3() {
    2169             : 
    2170             :   // Initial values.
    2171             :   bool foundNonZero = false;
    2172             :   double wtMassMax = 0.;
    2173             :   double m3WtMax = 0.;
    2174           0 :   double mT4Min = sqrt(m4*m4 + pT2HatMin);
    2175           0 :   double xMax = (mHatMax - mLower[3] - m4) / mWidth[3];
    2176           0 :   double xStep = THRESHOLDSTEP * min(1., xMax);
    2177             :   double xNow = 0.;
    2178             :   double wtMassNow, mT34Min, wtBW3Now, beta34Now;
    2179             : 
    2180             :   // Step through increasing x values; gives m3 unambiguously.
    2181           0 :   do {
    2182           0 :     xNow += xStep;
    2183             :     wtMassNow = 0.;
    2184           0 :     m3 = mHatMax - m4 - xNow * mWidth[3];
    2185             : 
    2186             :     // Check that inside phase space limit set by pTmin.
    2187           0 :     mT34Min = sqrt(m3*m3 + pT2HatMin) + mT4Min;
    2188           0 :     if (mT34Min < mHatMax) {
    2189             : 
    2190             :       // Breit-Wigner and beta factor give total weight.
    2191           0 :       wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) );
    2192           0 :       beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4)
    2193           0 :         - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax);
    2194           0 :       wtMassNow = wtBW3Now * beta34Now;
    2195             : 
    2196             :       // Store new maximum, if any.
    2197           0 :       if (wtMassNow > wtMassMax) {
    2198             :         foundNonZero = true;
    2199             :         wtMassMax = wtMassNow;
    2200           0 :         m3WtMax = m3;
    2201           0 :       }
    2202             :     }
    2203             : 
    2204             :   // Continue stepping if increasing trend and more x range available.
    2205           0 :   } while ( (!foundNonZero || wtMassNow > wtMassMax)
    2206           0 :     && xNow < xMax - xStep);
    2207             : 
    2208             :   // Restore best value for subsequent maximization. Return.
    2209           0 :   m3 = m3WtMax;
    2210           0 :   return foundNonZero;
    2211             : 
    2212           0 : }
    2213             : 
    2214             : //--------------------------------------------------------------------------
    2215             : 
    2216             : // Special choice of m4 when mHatMax pushes it off mass shell.
    2217             : // Vary x in expression m4 = mHatMax - m3 - x * Gamma4.
    2218             : // Maximize BW_4 * beta_34, where latter approximate phase space.
    2219             : 
    2220             : bool PhaseSpace2to2tauyz::constrainedM4() {
    2221             : 
    2222             :   // Initial values.
    2223             :   bool foundNonZero = false;
    2224             :   double wtMassMax = 0.;
    2225             :   double m4WtMax = 0.;
    2226           0 :   double mT3Min = sqrt(m3*m3 + pT2HatMin);
    2227           0 :   double xMax = (mHatMax - mLower[4] - m3) / mWidth[4];
    2228           0 :   double xStep = THRESHOLDSTEP * min(1., xMax);
    2229             :   double xNow = 0.;
    2230             :   double wtMassNow, mT34Min, wtBW4Now, beta34Now;
    2231             : 
    2232             :   // Step through increasing x values; gives m4 unambiguously.
    2233           0 :   do {
    2234           0 :     xNow += xStep;
    2235             :     wtMassNow = 0.;
    2236           0 :     m4 = mHatMax - m3 - xNow * mWidth[4];
    2237             : 
    2238             :     // Check that inside phase space limit set by pTmin.
    2239           0 :     mT34Min = mT3Min + sqrt(m4*m4 + pT2HatMin);
    2240           0 :     if (mT34Min < mHatMax) {
    2241             : 
    2242             :       // Breit-Wigner and beta factor give total weight.
    2243           0 :       wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) );
    2244           0 :       beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4)
    2245           0 :         - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax);
    2246           0 :       wtMassNow = wtBW4Now * beta34Now;
    2247             : 
    2248             :       // Store new maximum, if any.
    2249           0 :       if (wtMassNow > wtMassMax) {
    2250             :         foundNonZero = true;
    2251             :         wtMassMax = wtMassNow;
    2252           0 :         m4WtMax = m4;
    2253           0 :       }
    2254             :     }
    2255             : 
    2256             :   // Continue stepping if increasing trend and more x range available.
    2257           0 :   } while ( (!foundNonZero || wtMassNow > wtMassMax)
    2258           0 :     && xNow < xMax - xStep);
    2259             : 
    2260             :   // Restore best value for subsequent maximization.
    2261           0 :   m4 = m4WtMax;
    2262           0 :   return foundNonZero;
    2263             : 
    2264           0 : }
    2265             : 
    2266             : //==========================================================================
    2267             : 
    2268             : // PhaseSpace2to2elastic class.
    2269             : // 2 -> 2 kinematics set up for elastic scattering.
    2270             : 
    2271             : //--------------------------------------------------------------------------
    2272             : 
    2273             : // Constants: could be changed here if desired, but normally should not.
    2274             : // These are of technical nature, as described for each.
    2275             : 
    2276             : // Maximum positive/negative argument for exponentiation.
    2277             : const double PhaseSpace2to2elastic::EXPMAX = 50.;
    2278             : 
    2279             : // Conversion coefficients = 1/(16pi) * (mb <-> GeV^2).
    2280             : const double PhaseSpace2to2elastic::CONVERTEL = 0.0510925;
    2281             : 
    2282             : //--------------------------------------------------------------------------
    2283             : 
    2284             : // Form of phase space sampling already fixed, so no optimization.
    2285             : // However, need to read out relevant parameters from SigmaTotal.
    2286             : 
    2287             : bool PhaseSpace2to2elastic::setupSampling() {
    2288             : 
    2289             :   // Find maximum = value of cross section.
    2290           0 :   sigmaNw    = sigmaProcessPtr->sigmaHatWrap();
    2291           0 :   sigmaMx    = sigmaNw;
    2292             : 
    2293             :   // Squared and outgoing masses of particles.
    2294           0 :   s1         = mA * mA;
    2295           0 :   s2         = mB * mB;
    2296           0 :   m3         = mA;
    2297           0 :   m4         = mB;
    2298             : 
    2299             :   // Elastic slope.
    2300           0 :   bSlope     = sigmaTotPtr->bSlopeEl();
    2301             : 
    2302             :   // Determine maximum possible t range.
    2303           0 :   lambda12S  = pow2(s - s1 - s2) - 4. * s1 * s2 ;
    2304           0 :   tLow       = - lambda12S / s;
    2305           0 :   tUpp       = 0.;
    2306             : 
    2307             :   // Production model with Coulomb corrections need more parameters.
    2308           0 :   useCoulomb =  settingsPtr->flag("SigmaTotal:setOwn")
    2309           0 :              && settingsPtr->flag("SigmaElastic:setOwn");
    2310           0 :   if (useCoulomb) {
    2311           0 :     sigmaTot = sigmaTotPtr->sigmaTot();
    2312           0 :     rho      = settingsPtr->parm("SigmaElastic:rho");
    2313           0 :     lambda   = settingsPtr->parm("SigmaElastic:lambda");
    2314           0 :     tAbsMin  = settingsPtr->parm("SigmaElastic:tAbsMin");
    2315           0 :     phaseCst = settingsPtr->parm("SigmaElastic:phaseConst");
    2316           0 :     alphaEM0 = settingsPtr->parm("StandardModel:alphaEM0");
    2317             : 
    2318             :     // Relative rate of nuclear and Coulombic parts in trials.
    2319           0 :     tUpp     = -tAbsMin;
    2320           0 :     sigmaNuc = CONVERTEL * pow2(sigmaTot) * (1. + rho*rho) / bSlope
    2321           0 :              * exp(-bSlope * tAbsMin);
    2322           0 :     sigmaCou = (useCoulomb) ?
    2323           0 :                pow2(alphaEM0) / (4. * CONVERTEL * tAbsMin) : 0.;
    2324           0 :     signCou  = (idA == idB) ? 1. : -1.;
    2325             : 
    2326             :   // Dummy values.
    2327           0 :   } else {
    2328           0 :     sigmaNuc = sigmaNw;
    2329           0 :     sigmaCou = 0.;
    2330             :   }
    2331             : 
    2332             :   // Calculate coefficient of generation.
    2333           0 :   tAux       = exp( max(-EXPMAX, bSlope * (tLow - tUpp)) ) - 1.;
    2334             : 
    2335           0 :   return true;
    2336             : 
    2337           0 : }
    2338             : 
    2339             : //--------------------------------------------------------------------------
    2340             : 
    2341             : // Select a trial kinematics phase space point. Perform full
    2342             : // Monte Carlo acceptance/rejection at this stage.
    2343             : 
    2344             : bool PhaseSpace2to2elastic::trialKin( bool, bool ) {
    2345             : 
    2346             :   // Allow for possibility that energy varies from event to event.
    2347           0 :   if (doEnergySpread) {
    2348           0 :     eCM       = infoPtr->eCM();
    2349           0 :     s         = eCM * eCM;
    2350           0 :     lambda12S = pow2(s - s1 - s2) - 4. * s1 * s2 ;
    2351           0 :     tLow      = - lambda12S / s;
    2352           0 :     tAux      = exp( max(-EXPMAX, bSlope * (tLow - tUpp)) ) - 1.;
    2353           0 :   }
    2354             : 
    2355             :   // Select t according to exp(bSlope*t).
    2356           0 :   if (!useCoulomb || sigmaNuc > rndmPtr->flat() * (sigmaNuc + sigmaCou))
    2357           0 :    tH = tUpp + log(1. + tAux * rndmPtr->flat()) / bSlope;
    2358             : 
    2359             :  // Select t according to 1/t^2.
    2360           0 :   else tH = tLow * tUpp / (tUpp + rndmPtr->flat() * (tLow - tUpp));
    2361             : 
    2362             :   // Correction factor for ratio full/simulated.
    2363           0 :   if (useCoulomb) {
    2364           0 :     double sigmaN   = CONVERTEL * pow2(sigmaTot) * (1. + rho*rho)
    2365           0 :                     * exp(bSlope * tH);
    2366           0 :     double alpEM    = couplingsPtr->alphaEM(-tH);
    2367           0 :     double sigmaC   = pow2(alpEM) / (4. * CONVERTEL * tH*tH);
    2368           0 :     double sigmaGen = 2. * (sigmaN + sigmaC);
    2369           0 :     double form2    = pow4(lambda/(lambda - tH));
    2370           0 :     double phase    = signCou * alpEM
    2371           0 :                     * (-phaseCst - log(-0.5 * bSlope * tH));
    2372           0 :     double sigmaCor = sigmaN + pow2(form2) * sigmaC
    2373           0 :       - signCou * alpEM * sigmaTot * (form2 / (-tH))
    2374           0 :       *  exp(0.5 * bSlope * tH) * (rho * cos(phase) + sin(phase));
    2375           0 :     sigmaNw         = sigmaMx * sigmaCor / sigmaGen;
    2376           0 :   }
    2377             : 
    2378             :   // Careful reconstruction of scattering angle.
    2379           0 :   double tRat       = s * tH / lambda12S;
    2380           0 :   double cosTheta   = min(1., max(-1., 1. + 2. * tRat ) );
    2381           0 :   double sinTheta   = 2. * sqrtpos( -tRat * (1. + tRat) );
    2382           0 :   theta             = asin( min(1., sinTheta));
    2383           0 :   if (cosTheta < 0.) theta = M_PI - theta;
    2384             : 
    2385           0 :   return true;
    2386             : 
    2387           0 : }
    2388             : 
    2389             : //--------------------------------------------------------------------------
    2390             : 
    2391             : // Construct the four-vector kinematics from the trial values.
    2392             : 
    2393             : bool PhaseSpace2to2elastic::finalKin() {
    2394             : 
    2395             :   // Particle masses.
    2396           0 :   mH[1] = mA;
    2397           0 :   mH[2] = mB;
    2398           0 :   mH[3] = m3;
    2399           0 :   mH[4] = m4;
    2400             : 
    2401             :   // Incoming particles along beam axes.
    2402           0 :   pAbs = 0.5 * sqrtpos(lambda12S) / eCM;
    2403           0 :   pH[1] = Vec4( 0., 0.,  pAbs, 0.5 * (s + s1 - s2) / eCM);
    2404           0 :   pH[2] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM);
    2405             : 
    2406             :   // Outgoing particles initially along beam axes.
    2407           0 :   pH[3] = Vec4( 0., 0.,  pAbs, 0.5 * (s + s1 - s2) / eCM);
    2408           0 :   pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM);
    2409             : 
    2410             :   // Then rotate them
    2411           0 :   phi = 2. * M_PI * rndmPtr->flat();
    2412           0 :   pH[3].rot( theta, phi);
    2413           0 :   pH[4].rot( theta, phi);
    2414             : 
    2415             :   // Set some further info for completeness.
    2416           0 :   x1H = 1.;
    2417           0 :   x2H = 1.;
    2418           0 :   sH = s;
    2419           0 :   uH = 2. * (s1 + s2) - sH - tH;
    2420           0 :   mHat = eCM;
    2421           0 :   p2Abs = pAbs * pAbs;
    2422           0 :   betaZ = 0.;
    2423           0 :   pTH = pAbs * sin(theta);
    2424             : 
    2425             :   // Done.
    2426           0 :   return true;
    2427             : 
    2428             : }
    2429             : 
    2430             : //==========================================================================
    2431             : 
    2432             : // PhaseSpace2to2diffractive class.
    2433             : // 2 -> 2 kinematics set up for diffractive scattering.
    2434             : 
    2435             : //--------------------------------------------------------------------------
    2436             : 
    2437             : // Constants: could be changed here if desired, but normally should not.
    2438             : // These are of technical nature, as described for each.
    2439             : 
    2440             : // Number of tries to find acceptable (m^2, t) set.
    2441             : const int PhaseSpace2to2diffractive::NTRY = 500;
    2442             : 
    2443             : // Maximum positive/negative argument for exponentiation.
    2444             : const double PhaseSpace2to2diffractive::EXPMAX = 50.;
    2445             : 
    2446             : // Safety margin so sum of diffractive masses not too close to eCM.
    2447             : const double PhaseSpace2to2diffractive::DIFFMASSMARGIN = 0.2;
    2448             : 
    2449             : //--------------------------------------------------------------------------
    2450             : 
    2451             : // Form of phase space sampling already fixed, so no optimization.
    2452             : // However, need to read out relevant parameters from SigmaTotal.
    2453             : 
    2454             : bool PhaseSpace2to2diffractive::setupSampling() {
    2455             : 
    2456             :   // Pomeron flux parametrization, and parameters of some options.
    2457           0 :   PomFlux      = settingsPtr->mode("Diffraction:PomFlux");
    2458           0 :   epsilonPF    = settingsPtr->parm("Diffraction:PomFluxEpsilon");
    2459           0 :   alphaPrimePF = settingsPtr->parm("Diffraction:PomFluxAlphaPrime");
    2460             : 
    2461             :   // Find maximum = value of cross section.
    2462           0 :   sigmaNw = sigmaProcessPtr->sigmaHatWrap();
    2463           0 :   sigmaMx = sigmaNw;
    2464             : 
    2465             :   // Masses of particles and minimal masses of diffractive states.
    2466           0 :   m3ElDiff = (isDiffA) ? sigmaTotPtr->mMinXB()  : mA;
    2467           0 :   m4ElDiff = (isDiffB) ? sigmaTotPtr->mMinAX()  : mB;
    2468           0 :   s1 = mA * mA;
    2469           0 :   s2 = mB * mB;
    2470           0 :   s3 = pow2( m3ElDiff);
    2471           0 :   s4 = pow2( m4ElDiff);
    2472             : 
    2473             :   // Determine maximum possible t range and coefficient of generation.
    2474           0 :   lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 );
    2475           0 :   lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 );
    2476           0 :   double tempA = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s;
    2477           0 :   double tempB = lambda12 *  lambda34 / s;
    2478           0 :   double tempC = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3)
    2479           0 :     * (s1 * s4 - s2 * s3) / s;
    2480           0 :   tLow  = -0.5 * (tempA + tempB);
    2481           0 :   tUpp  = tempC / tLow;
    2482             : 
    2483             :   // Default for all parametrization-specific parameters.
    2484           0 :   cRes = sResXB = sResAX = sProton = bMin = bSlope = bSlope1 = bSlope2
    2485           0 :        = probSlope1 = xIntPF = xtCorPF = mp24DL = coefDL = tAux
    2486           0 :        = tAux1 = tAux2 = 0.;
    2487             : 
    2488             :   // Schuler&Sjostrand: parameters of low-mass-resonance enhancement.
    2489           0 :   if (PomFlux == 1) {
    2490           0 :     cRes = sigmaTotPtr->cRes();
    2491           0 :     sResXB = pow2( sigmaTotPtr->mResXB());
    2492           0 :     sResAX = pow2( sigmaTotPtr->mResAX());
    2493           0 :     sProton = sigmaTotPtr->sProton();
    2494             : 
    2495             :     // Schuler&Sjostrand: lower limit diffractive slope.
    2496           0 :     if      (!isDiffB) bMin = sigmaTotPtr->bMinSlopeXB();
    2497           0 :     else if (!isDiffA) bMin = sigmaTotPtr->bMinSlopeAX();
    2498           0 :     else               bMin = sigmaTotPtr->bMinSlopeXX();
    2499           0 :     tAux = exp( max(-EXPMAX, bMin * (tLow - tUpp)) ) - 1.;
    2500             : 
    2501             :   // Bruni&Ingelman: relative weight of two diffractive slopes.
    2502           0 :   } else if (PomFlux == 2) {
    2503           0 :     bSlope1     = 8.0;
    2504           0 :     probSlope1  = 6.38 * ( exp(max(-EXPMAX, bSlope1 * tUpp))
    2505           0 :                 -  exp(max(-EXPMAX, bSlope1 * tLow)) ) / bSlope1;
    2506           0 :     bSlope2     = 3.0;
    2507           0 :     double pS2  = 0.424 * ( exp(max(-EXPMAX, bSlope2 * tUpp))
    2508           0 :                 -  exp(max(-EXPMAX, bSlope2 * tLow)) ) / bSlope2;
    2509           0 :     probSlope1 /= probSlope1 + pS2;
    2510           0 :     tAux1 = exp( max(-EXPMAX, bSlope1 * (tLow - tUpp)) ) - 1.;
    2511           0 :     tAux2 = exp( max(-EXPMAX, bSlope2 * (tLow - tUpp)) ) - 1.;
    2512             : 
    2513             :   // Streng&Berger (RapGap): diffractive slope, power of mass spectrum.
    2514           0 :   } else if (PomFlux == 3) {
    2515           0 :     bSlope        = 4.7;
    2516           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    2517           0 :     xIntPF        = 2. * (1. + xPowPF);
    2518           0 :     xtCorPF       = 2. * alphaPrimePF;
    2519           0 :     tAux          = exp( max(-EXPMAX, bSlope  * (tLow - tUpp)) ) - 1.;
    2520             : 
    2521             :   // Donnachie&Landshoff (RapGap):  power of mass spectrum.
    2522           0 :   } else if (PomFlux == 4) {
    2523           0 :     mp24DL        = 4. * pow2(particleDataPtr->m0(2212));
    2524           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    2525           0 :     xIntPF        = 2. * (1. + xPowPF);
    2526           0 :     xtCorPF       = 2. * alphaPrimePF;
    2527             :     // Upper estimate of t dependence, for preliminary choice.
    2528           0 :     coefDL               = 0.85;
    2529           0 :     tAux1                = 1. / pow3(1. - coefDL * tLow);
    2530           0 :     tAux2                = 1. / pow3(1. - coefDL * tUpp);
    2531             : 
    2532             :   // MBR model.
    2533           0 :   } else if (PomFlux == 5) {
    2534           0 :     eps        = settingsPtr->parm("Diffraction:MBRepsilon");
    2535           0 :     alph       = settingsPtr->parm("Diffraction:MBRalpha");
    2536           0 :     alph2      = alph * alph;
    2537           0 :     m2min      = settingsPtr->parm("Diffraction:MBRm2Min");
    2538           0 :     dyminSD    = settingsPtr->parm("Diffraction:MBRdyminSD");
    2539           0 :     dyminDD    = settingsPtr->parm("Diffraction:MBRdyminDD");
    2540           0 :     dyminSigSD = settingsPtr->parm("Diffraction:MBRdyminSigSD");
    2541           0 :     dyminSigDD = settingsPtr->parm("Diffraction:MBRdyminSigDD");
    2542             : 
    2543             :     // Max f(dy) for Von Neumann method, from SigmaTot.
    2544           0 :     sdpmax= sigmaTotPtr->sdpMax();
    2545           0 :     ddpmax= sigmaTotPtr->ddpMax();
    2546             : 
    2547             :   // H1 Fit A/B.
    2548           0 :   } else if (PomFlux == 6 || PomFlux == 7) {
    2549           0 :     bSlope        = 5.5;
    2550           0 :     epsilonPF     =  (PomFlux == 6) ? 0.1182 : 0.1110;
    2551           0 :     alphaPrimePF  = 0.06;
    2552           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    2553           0 :     xIntPF        = 2. * (1. + xPowPF);
    2554           0 :     xtCorPF       = 2. * alphaPrimePF;
    2555           0 :     tAux          = exp( max(-EXPMAX, bSlope  * (tLow - tUpp)) ) - 1.;
    2556           0 :   }
    2557             : 
    2558             :   // Done.
    2559           0 :   return true;
    2560             : 
    2561           0 : }
    2562             : 
    2563             : //--------------------------------------------------------------------------
    2564             : 
    2565             : // Select a trial kinematics phase space point. Perform full
    2566             : // Monte Carlo acceptance/rejection at this stage.
    2567             : 
    2568             : bool PhaseSpace2to2diffractive::trialKin( bool, bool ) {
    2569             : 
    2570             :   // Allow for possibility that energy varies from event to event.
    2571           0 :   if (doEnergySpread) {
    2572           0 :     eCM       = infoPtr->eCM();
    2573           0 :     s         = eCM * eCM;
    2574           0 :     lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 );
    2575           0 :     lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 );
    2576           0 :     double tempA = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s;
    2577           0 :     double tempB = lambda12 *  lambda34 / s;
    2578           0 :     double tempC = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3)
    2579           0 :       * (s1 * s4 - s2 * s3) / s;
    2580           0 :     tLow  = -0.5 * (tempA + tempB);
    2581           0 :     tUpp  = tempC / tLow;
    2582           0 :     if (PomFlux == 1) {
    2583           0 :       tAux = exp( max(-EXPMAX, bMin * (tLow - tUpp)) ) - 1.;
    2584           0 :     } else if (PomFlux == 2) {
    2585           0 :       tAux1 = exp( max(-EXPMAX, bSlope1 * (tLow - tUpp)) ) - 1.;
    2586           0 :       tAux2 = exp( max(-EXPMAX, bSlope2 * (tLow - tUpp)) ) - 1.;
    2587           0 :     } else if (PomFlux == 3 || PomFlux == 6 || PomFlux == 7) {
    2588           0 :       tAux          = exp( max(-EXPMAX, bSlope  * (tLow - tUpp)) ) - 1.;
    2589           0 :     } else if (PomFlux == 4) {
    2590           0 :       tAux1                = 1. / pow3(1. - coefDL * tLow);
    2591           0 :       tAux2                = 1. / pow3(1. - coefDL * tUpp);
    2592           0 :     }
    2593           0 :   }
    2594             : 
    2595             :   // Loop over attempts to set up masses and t consistently.
    2596           0 :   for (int loop = 0; ; ++loop) {
    2597           0 :     if (loop == NTRY) {
    2598           0 :       infoPtr->errorMsg("Error in PhaseSpace2to2diffractive::trialKin: "
    2599             :         " quit after repeated tries");
    2600           0 :       return false;
    2601             :     }
    2602             : 
    2603             :     // Schuler and Sjostrand:
    2604           0 :     if (PomFlux == 1) {
    2605             : 
    2606             :       // Select diffractive mass(es) according to dm^2/m^2.
    2607           0 :       m3 = (isDiffA) ? m3ElDiff * pow( max(mA, eCM - m4ElDiff) / m3ElDiff,
    2608           0 :         rndmPtr->flat()) : m3ElDiff;
    2609           0 :       m4 = (isDiffB) ? m4ElDiff * pow( max(mB, eCM - m3ElDiff) / m4ElDiff,
    2610           0 :         rndmPtr->flat()) : m4ElDiff;
    2611           0 :       if (m3 + m4 + DIFFMASSMARGIN >= eCM) continue;
    2612           0 :       s3 = m3 * m3;
    2613           0 :       s4 = m4 * m4;
    2614             : 
    2615             :       // Additional mass factors, including resonance enhancement.
    2616           0 :       if (isDiffA && !isDiffB) {
    2617           0 :         double facXB = (1. - s3 / s)
    2618           0 :           * (1. + cRes * sResXB / (sResXB + s3));
    2619           0 :         if (facXB < rndmPtr->flat() * (1. + cRes)) continue;
    2620           0 :       } else if (isDiffB && !isDiffA) {
    2621           0 :         double facAX = (1. - s4 / s)
    2622           0 :           * (1. + cRes * sResAX / (sResAX + s4));
    2623           0 :         if (facAX < rndmPtr->flat() * (1. + cRes)) continue;
    2624           0 :       } else {
    2625           0 :         double facXX = (1. - pow2(m3 + m4) / s)
    2626           0 :           * (s * sProton / (s * sProton + s3 * s4))
    2627           0 :           * (1. + cRes * sResXB / (sResXB + s3))
    2628           0 :           * (1. + cRes * sResAX / (sResAX + s4));
    2629           0 :         if (facXX < rndmPtr->flat() * pow2(1. + cRes)) continue;
    2630           0 :       }
    2631             : 
    2632             :       // Select t according to exp(bMin*t) and correct to right slope.
    2633           0 :       tH = tUpp + log(1. + tAux * rndmPtr->flat()) / bMin;
    2634           0 :       double bDiff = 0.;
    2635           0 :       if (isDiffA && !isDiffB) bDiff = sigmaTotPtr->bSlopeXB(s3) - bMin;
    2636           0 :       else if (!isDiffA) bDiff = sigmaTotPtr->bSlopeAX(s4) - bMin;
    2637           0 :       else bDiff = sigmaTotPtr->bSlopeXX(s3, s4) - bMin;
    2638           0 :       bDiff = max(0., bDiff);
    2639           0 :       if (exp( max(-EXPMAX, bDiff * (tH - tUpp)) ) < rndmPtr->flat()) continue;
    2640             : 
    2641             :     // Bruni and Ingelman:
    2642           0 :     } else if (PomFlux == 2) {
    2643             : 
    2644             :       // Select diffractive mass(es) according to dm^2/m^2.
    2645           0 :       m3 = (isDiffA) ? m3ElDiff * pow( max(mA, eCM - m4ElDiff) / m3ElDiff,
    2646           0 :         rndmPtr->flat()) : m3ElDiff;
    2647           0 :       m4 = (isDiffB) ? m4ElDiff * pow( max(mB, eCM - m3ElDiff) / m4ElDiff,
    2648           0 :         rndmPtr->flat()) : m4ElDiff;
    2649           0 :       if (m3 + m4 + DIFFMASSMARGIN >= eCM) continue;
    2650           0 :       s3 = m3 * m3;
    2651           0 :       s4 = m4 * m4;
    2652             : 
    2653             :       // Select t according to exp(bSlope*t) with two possible slopes.
    2654           0 :       tH = (rndmPtr->flat() < probSlope1)
    2655           0 :          ? tUpp + log(1. + tAux1 * rndmPtr->flat()) / bSlope1
    2656           0 :          : tUpp + log(1. + tAux2 * rndmPtr->flat()) / bSlope2;
    2657             : 
    2658             :     // Streng and Berger et al. (RapGap) & H1 Fit A/B:
    2659           0 :     } else if (PomFlux == 3 || PomFlux == 6 || PomFlux == 7) {
    2660             : 
    2661             :       // Select diffractive mass(es) according to dm^2/(m^2)^(1 + 2 epsilon).
    2662           0 :       m3 = m3ElDiff;
    2663           0 :       m4 = m4ElDiff;
    2664           0 :       if (isDiffA) {
    2665           0 :         double s3MinPow = pow( m3ElDiff, xIntPF );
    2666           0 :         double s3MaxPow = pow( max(mA, eCM - m4ElDiff), xIntPF );
    2667           0 :         m3 = pow( s3MinPow + rndmPtr->flat() * (s3MaxPow - s3MinPow),
    2668           0 :                   1. / xIntPF );
    2669           0 :       }
    2670           0 :       if (isDiffB) {
    2671           0 :         double s4MinPow = pow( m4ElDiff, xIntPF );
    2672           0 :         double s4MaxPow = pow( max(mB, eCM - m3ElDiff), xIntPF );
    2673           0 :         m4 = pow( s4MinPow + rndmPtr->flat() * (s4MaxPow - s4MinPow),
    2674           0 :                   1. / xIntPF );
    2675           0 :       }
    2676           0 :       if (m3 + m4 + DIFFMASSMARGIN >= eCM) continue;
    2677           0 :       s3 = m3 * m3;
    2678           0 :       s4 = m4 * m4;
    2679             : 
    2680             :       // Select t according to exponential and weigh by x_P^(2 alpha' |t|).
    2681           0 :       tH = tUpp + log(1. + tAux * rndmPtr->flat()) / bSlope;
    2682           0 :       if ( isDiffA && pow( s3 / s, xtCorPF * abs(tH) ) < rndmPtr->flat() )
    2683             :         continue;
    2684           0 :       if ( isDiffB && pow( s4 / s, xtCorPF * abs(tH) ) < rndmPtr->flat() )
    2685             :         continue;
    2686             : 
    2687             :     // Donnachie and Landshoff (RapGap):
    2688           0 :     } else if (PomFlux == 4) {
    2689             : 
    2690             :       // Select diffractive mass(es) according to dm^2/(m^2)^(1 + 2 epsilon).
    2691           0 :       m3 = m3ElDiff;
    2692           0 :       m4 = m4ElDiff;
    2693           0 :       if (isDiffA) {
    2694           0 :         double s3MinPow = pow( m3ElDiff, xIntPF );
    2695           0 :         double s3MaxPow = pow( max(mA, eCM - m4ElDiff), xIntPF );
    2696           0 :         m3 = pow( s3MinPow + rndmPtr->flat() * (s3MaxPow - s3MinPow),
    2697           0 :                   1. / xIntPF );
    2698           0 :       }
    2699           0 :       if (isDiffB) {
    2700           0 :         double s4MinPow = pow( m4ElDiff, xIntPF );
    2701           0 :         double s4MaxPow = pow( max(mB, eCM - m3ElDiff), xIntPF );
    2702           0 :         m4 = pow( s4MinPow + rndmPtr->flat() * (s4MaxPow - s4MinPow),
    2703           0 :                   1. / xIntPF );
    2704           0 :       }
    2705           0 :       if (m3 + m4 + DIFFMASSMARGIN >= eCM) continue;
    2706           0 :       s3 = m3 * m3;
    2707           0 :       s4 = m4 * m4;
    2708             : 
    2709             :       // Select t according to power and weigh by x_P^(2 alpha' |t|).
    2710           0 :       tH = - (1. / pow( tAux1 + rndmPtr->flat() * (tAux2 - tAux1), 1./3.)
    2711           0 :          - 1.) / coefDL;
    2712           0 :       double wDL = pow2( (mp24DL - 2.8 * tH) / (mp24DL - tH) )
    2713           0 :                  / pow4( 1. - tH / 0.7);
    2714           0 :       double wMX = 1. / pow4( 1. - coefDL * tH);
    2715           0 :       if (wDL < rndmPtr->flat() * wMX) continue;
    2716           0 :       if ( isDiffA && pow( s3 / s, xtCorPF * abs(tH) ) < rndmPtr->flat() )
    2717           0 :         continue;
    2718           0 :       if ( isDiffB && pow( s4 / s, xtCorPF * abs(tH) ) < rndmPtr->flat() )
    2719           0 :         continue;
    2720             : 
    2721             :     // MBR model:
    2722           0 :     } else if (PomFlux == 5) {
    2723           0 :       m3 = mA;
    2724           0 :       m4 = mB;
    2725             :       double xi, P, yRnd, dy;
    2726             : 
    2727             :       // MBR double diffractive.
    2728           0 :       if (isDiffA && isDiffB) {
    2729           0 :         dymin0 = 0.;
    2730           0 :         dymax  = log(s/pow2(m2min));
    2731             : 
    2732             :         // Von Neumann method to generate dy, uses ddpmax from SigmaTot.
    2733           0 :         do {
    2734           0 :           dy = dymin0 + (dymax - dymin0) * rndmPtr->flat();
    2735           0 :           P  = (dymax - dy) * exp(eps*dy) * ( exp(-2. * alph * dy * exp(-dy))
    2736           0 :              - exp(-2. * alph * dy * exp(dy)) ) / dy;
    2737             :           // Suppress smaller gap, smooth transition to non-diffractive.
    2738           0 :           P *= 0.5 * (1 + erf( ( dy - dyminDD) / dyminSigDD ) );
    2739           0 :           if (P > ddpmax) {
    2740           0 :             ostringstream osWarn;
    2741           0 :             osWarn << "ddpmax = " << scientific << setprecision(3)
    2742           0 :                    << ddpmax << " " << P << " " << dy << endl;
    2743           0 :             infoPtr->errorMsg("Warning in PhaseSpace2to2diffractive::"
    2744           0 :               "trialKin for double diffraction:", osWarn.str());
    2745           0 :           }
    2746           0 :           yRnd = ddpmax * rndmPtr->flat();
    2747           0 :         } while (yRnd > P);
    2748             : 
    2749           0 :         double y0max = (dymax - dy)/2.;
    2750           0 :         double y0min = -y0max;
    2751           0 :         double y0    = y0min + (y0max - y0min) * rndmPtr->flat();
    2752           0 :         am1          = sqrt( eCM * exp( -y0 - dy/2. ) );
    2753           0 :         am2          = sqrt( eCM * exp(  y0 - dy/2. ) );
    2754             : 
    2755             :         // Generate 4-momentum transfer, t from exp.
    2756           0 :         double b = 2. * alph * dy;
    2757           0 :         tUpp     = -exp( -dy );
    2758           0 :         tLow     = -exp( dy );
    2759           0 :         tAux     = exp( b * (tLow - tUpp) ) - 1.;
    2760           0 :         t        = tUpp + log(1. + tAux * rndmPtr->flat()) / b;
    2761           0 :         m3       = am1;
    2762           0 :         m4       = am2;
    2763           0 :         tH       = t;
    2764             : 
    2765             :       // MBR single diffractive.
    2766           0 :       } else if (isDiffA || isDiffB) {
    2767           0 :         dymin0 = 0.;
    2768           0 :         dymax  = log(s/m2min);
    2769             : 
    2770             :         // Von Neumann method to generate dy, uses sdpmax from SigmaTot.
    2771           0 :         do {
    2772           0 :           dy = dymin0 + (dymax - dymin0) * rndmPtr->flat();
    2773           0 :           P  = exp(eps * dy) * ( (FFA1 / (FFB1 + 2. * alph * dy) )
    2774           0 :              + (FFA2 / (FFB2 + 2. * alph * dy) ) );
    2775             :           // Suppress smaller gap.
    2776           0 :           P *= 0.5 * (1. + erf( (dy - dyminSD) / dyminSigSD) );
    2777           0 :           if (P > sdpmax) {
    2778           0 :             ostringstream osWarn;
    2779           0 :             osWarn << "sdpmax = " << scientific << setprecision(3)
    2780           0 :                    << sdpmax << " " << P << " " << dy << endl;
    2781           0 :             infoPtr->errorMsg("Warning in PhaseSpace2to2diffractive::"
    2782           0 :               "trialKin for single diffraction:", osWarn.str());
    2783           0 :           }
    2784           0 :           yRnd = sdpmax * rndmPtr->flat();
    2785           0 :         } while (yRnd > P);
    2786           0 :         xi  = exp( -dy );
    2787           0 :         amx = sqrt( xi * s );
    2788             : 
    2789             :         // Generate 4-momentum transfer, t. First exponent, then FF*exp.
    2790           0 :         double tmin = -s1 * xi * xi / (1 - xi);
    2791           0 :         do {
    2792           0 :           t          = tmin + log(1. - rndmPtr->flat());
    2793           0 :           double pFF = (4. * s1 - 2.8 * t) / ( (4. * s1 - t)
    2794           0 :                      * pow2(1. - t / 0.71) );
    2795           0 :           P          = pow2(pFF) * exp(2. * alph * dy * t);
    2796           0 :           yRnd       = exp(t) * rndmPtr->flat();
    2797           0 :         } while (yRnd > P);
    2798           0 :         if(isDiffA) m3 = amx;
    2799           0 :         if(isDiffB) m4 = amx;
    2800           0 :         tH = t;
    2801           0 :       }
    2802             : 
    2803             :       // End of MBR model code.
    2804           0 :       s3 = m3 * m3;
    2805           0 :       s4 = m4 * m4;
    2806           0 :     }
    2807             : 
    2808             :     // Check whether m^2 and t choices are consistent.
    2809           0 :     lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 );
    2810           0 :     double tempA = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s;
    2811           0 :     double tempB = lambda12 *  lambda34 / s;
    2812           0 :     double tempC = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3)
    2813           0 :       * (s1 * s4 - s2 * s3) / s;
    2814           0 :     double tLowNow = -0.5 * (tempA + tempB);
    2815           0 :     double tUppNow = tempC / tLowNow;
    2816           0 :     if (tH < tLowNow || tH > tUppNow) continue;
    2817             : 
    2818             :     // Careful reconstruction of scattering angle.
    2819           0 :     double cosTheta = min(1., max(-1., (tempA + 2. * tH) / tempB));
    2820           0 :     double sinTheta = 2. * sqrtpos( -(tempC + tempA * tH + tH * tH) )
    2821           0 :       / tempB;
    2822           0 :     theta = asin( min(1., sinTheta));
    2823           0 :     if (cosTheta < 0.) theta = M_PI - theta;
    2824             : 
    2825             :     // Found acceptable kinematics, so no more looping. Done
    2826             :     break;
    2827           0 :   }
    2828           0 :   return true;
    2829             : 
    2830           0 : }
    2831             : 
    2832             : //--------------------------------------------------------------------------
    2833             : 
    2834             : // Construct the four-vector kinematics from the trial values.
    2835             : 
    2836             : bool PhaseSpace2to2diffractive::finalKin() {
    2837             : 
    2838             :   // Particle masses; incoming always on mass shell.
    2839           0 :   mH[1] = mA;
    2840           0 :   mH[2] = mB;
    2841           0 :   mH[3] = m3;
    2842           0 :   mH[4] = m4;
    2843             : 
    2844             :   // Incoming particles along beam axes.
    2845           0 :   pAbs = 0.5 * lambda12 / eCM;
    2846           0 :   pH[1] = Vec4( 0., 0.,  pAbs, 0.5 * (s + s1 - s2) / eCM);
    2847           0 :   pH[2] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM);
    2848             : 
    2849             :   // Outgoing particles initially along beam axes.
    2850           0 :   pAbs = 0.5 * lambda34 / eCM;
    2851           0 :   pH[3] = Vec4( 0., 0.,  pAbs, 0.5 * (s + s3 - s4) / eCM);
    2852           0 :   pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (s + s4 - s3) / eCM);
    2853             : 
    2854             :   // Then rotate them
    2855           0 :   phi = 2. * M_PI * rndmPtr->flat();
    2856           0 :   pH[3].rot( theta, phi);
    2857           0 :   pH[4].rot( theta, phi);
    2858             : 
    2859             :   // Set some further info for completeness (but Info can be for subprocess).
    2860           0 :   x1H   = 1.;
    2861           0 :   x2H   = 1.;
    2862           0 :   sH    = s;
    2863           0 :   uH    = s1 + s2 + s3 + s4 - sH - tH;
    2864           0 :   mHat  = eCM;
    2865           0 :   p2Abs = pAbs * pAbs;
    2866           0 :   betaZ = 0.;
    2867           0 :   pTH   = pAbs * sin(theta);
    2868             : 
    2869             :   // Done.
    2870           0 :   return true;
    2871             : 
    2872             : }
    2873             : 
    2874             : //==========================================================================
    2875             : 
    2876             : // PhaseSpace2to3diffractive class.
    2877             : // 2 -> 3 kinematics set up for central diffractive scattering.
    2878             : 
    2879             : //--------------------------------------------------------------------------
    2880             : 
    2881             : // Constants: could be changed here if desired, but normally should not.
    2882             : // These are of technical nature, as described for each.
    2883             : 
    2884             : // Number of tries to find acceptable (m^2, t1, t2) set.
    2885             : const int PhaseSpace2to3diffractive::NTRY = 500;
    2886             : const int PhaseSpace2to3diffractive::NINTEG2 = 40;
    2887             : 
    2888             : // Maximum positive/negative argument for exponentiation.
    2889             : const double PhaseSpace2to3diffractive::EXPMAX = 50.;
    2890             : 
    2891             : // Minimal mass of central diffractive system.
    2892             : const double PhaseSpace2to3diffractive::DIFFMASSMIN = 0.8;
    2893             : 
    2894             : // Safety margin so sum of diffractive masses not too close to eCM.
    2895             : const double PhaseSpace2to3diffractive::DIFFMASSMARGIN = 0.2;
    2896             : 
    2897             : //--------------------------------------------------------------------------
    2898             : 
    2899             : // Set up for phase space sampling.
    2900             : 
    2901             : bool PhaseSpace2to3diffractive::setupSampling() {
    2902             : 
    2903             :   // Pomeron flux parametrization, and parameters of some options.
    2904           0 :   PomFlux      = settingsPtr->mode("Diffraction:PomFlux");
    2905           0 :   epsilonPF    = settingsPtr->parm("Diffraction:PomFluxEpsilon");
    2906           0 :   alphaPrimePF = settingsPtr->parm("Diffraction:PomFluxAlphaPrime");
    2907             : 
    2908             :   // Find maximum = value of cross section.
    2909           0 :   sigmaNw      = sigmaProcessPtr->sigmaHatWrap();
    2910           0 :   sigmaMx      = sigmaNw;
    2911             : 
    2912             :   // Squared masses of particles and minimal mass of diffractive states.
    2913           0 :   s1           = mA * mA;
    2914           0 :   s2           = mB * mB;
    2915           0 :   m5min        = sigmaTotPtr->mMinAXB();
    2916           0 :   s5min        = m5min * m5min;
    2917             : 
    2918             :   // Loop over two cases: s4 = (X + B)^2 and s3 = (A + X)^2.
    2919           0 :   for (int i = 0; i < 2; ++i) {
    2920           0 :     s3 = (i == 0) ? s1 : pow2(mA + m5min);
    2921           0 :     s4 = (i == 0) ? pow2(mB + m5min) : s2;
    2922             : 
    2923             :     // Determine maximum possible t range and coefficient of generation.
    2924           0 :     double lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 );
    2925           0 :     double lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 );
    2926           0 :     double tempA    = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s;
    2927           0 :     double tempB    = lambda12 *  lambda34 / s;
    2928           0 :     double tempC    = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3)
    2929           0 :                     * (s1 * s4 - s2 * s3) / s;
    2930           0 :     tLow[i]         = -0.5 * (tempA + tempB);
    2931           0 :     tUpp[i]         = tempC / tLow[i];
    2932             :   }
    2933           0 :   s3 = s1;
    2934           0 :   s4 = s2;
    2935             : 
    2936             :   // Default for all parametrization-specific parameters.
    2937           0 :   bSlope1 = bSlope2 = bSlope = xIntPF = xIntInvPF = xtCorPF = mp24DL
    2938           0 :     = coefDL = 0.;
    2939           0 :   for (int i = 0; i < 2; ++i)
    2940           0 :     bMin[i] = tAux[i] = probSlope1[i] = tAux1[i] = tAux2[i] = 0.;
    2941             : 
    2942             :   // Schuler&Sjostrand: lower limit diffractive slope.
    2943           0 :   if (PomFlux == 1) {
    2944           0 :     bMin[0] = sigmaTotPtr->bMinSlopeAX();
    2945           0 :     tAux[0] = exp( max(-EXPMAX, bMin[0] * (tLow[0] - tUpp[0])) ) - 1.;
    2946           0 :     bMin[1] = sigmaTotPtr->bMinSlopeXB();
    2947           0 :     tAux[1] = exp( max(-EXPMAX, bMin[1] * (tLow[1] - tUpp[1])) ) - 1.;
    2948             : 
    2949             :   // Bruni&Ingelman: relative weight of two diffractive slopes.
    2950           0 :   } else if (PomFlux == 2) {
    2951           0 :     bSlope1     = 8.0;
    2952           0 :     bSlope2     = 3.0;
    2953           0 :     for (int i = 0; i < 2; ++i) {
    2954           0 :       probSlope1[i]  = 6.38 * ( exp(max(-EXPMAX, bSlope1 * tUpp[i]))
    2955           0 :                      -  exp(max(-EXPMAX, bSlope1 * tLow[i])) ) / bSlope1;
    2956           0 :       double pS2     = 0.424 * ( exp(max(-EXPMAX, bSlope2 * tUpp[i]))
    2957           0 :                      -  exp(max(-EXPMAX, bSlope2 * tLow[i])) ) / bSlope2;
    2958           0 :       probSlope1[i] /= probSlope1[i] + pS2;
    2959           0 :       tAux1[i] = exp( max(-EXPMAX, bSlope1 * (tLow[i] - tUpp[i])) ) - 1.;
    2960           0 :       tAux2[i] = exp( max(-EXPMAX, bSlope2 * (tLow[i] - tUpp[i])) ) - 1.;
    2961             :     }
    2962             : 
    2963             :   // Streng&Berger (RapGap): diffractive slope, power of mass spectrum.
    2964           0 :   } else if (PomFlux == 3) {
    2965           0 :     bSlope        = 4.7;
    2966           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    2967           0 :     xIntPF        = 1. + xPowPF;
    2968           0 :     xIntInvPF     = 1. / xIntPF;
    2969           0 :     xtCorPF       = 2. * alphaPrimePF;
    2970           0 :     tAux[0]       = exp( max(-EXPMAX, bSlope  * (tLow[0] - tUpp[0])) ) - 1.;
    2971           0 :     tAux[1]       = exp( max(-EXPMAX, bSlope  * (tLow[1] - tUpp[1])) ) - 1.;
    2972             : 
    2973             :   // Donnachie&Landshoff (RapGap):  power of mass spectrum.
    2974           0 :   } else if (PomFlux == 4) {
    2975           0 :     mp24DL        = 4. * pow2(particleDataPtr->m0(2212));
    2976           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    2977           0 :     xIntPF        = 1. + xPowPF;
    2978           0 :     xIntInvPF     = 1. / xIntPF;
    2979           0 :     xtCorPF       = 2. * alphaPrimePF;
    2980             :     // Upper estimate of t dependence, for preliminary choice.
    2981           0 :     coefDL        = 0.85;
    2982           0 :     tAux1[0]      = 1. / pow3(1. - coefDL * tLow[0]);
    2983           0 :     tAux2[0]      = 1. / pow3(1. - coefDL * tUpp[0]);
    2984           0 :     tAux1[1]      = 1. / pow3(1. - coefDL * tLow[1]);
    2985           0 :     tAux2[1]      = 1. / pow3(1. - coefDL * tUpp[1]);
    2986             : 
    2987             :   // Setup for the MBR model.
    2988           0 :   } else if (PomFlux == 5) {
    2989           0 :     epsMBR        = settingsPtr->parm("Diffraction:MBRepsilon");
    2990           0 :     alphMBR       = settingsPtr->parm("Diffraction:MBRalpha");
    2991           0 :     m2minMBR      = settingsPtr->parm("Diffraction:MBRm2Min");
    2992           0 :     dyminMBR      = settingsPtr->parm("Diffraction:MBRdyminCD");
    2993           0 :     dyminSigMBR   = settingsPtr->parm("Diffraction:MBRdyminSigCD");
    2994           0 :     dyminInvMBR   = sqrt(2.) / dyminSigMBR;
    2995             :     // Max f(dy) for Von Neumann method, dpepmax from SigmaTot.
    2996           0 :     dpepmax       = sigmaTotPtr->dpepMax();
    2997             : 
    2998             :   // H1 Fit A/B.
    2999           0 :   } else if (PomFlux == 6 || PomFlux == 7) {
    3000           0 :     bSlope        = 5.5;
    3001           0 :     epsilonPF     = (PomFlux == 6) ? 0.1182 : 0.1110;
    3002           0 :     alphaPrimePF  = 0.06;
    3003           0 :     double xPowPF = 1. - 2. * (1. + epsilonPF);
    3004           0 :     xIntPF        = 1. + xPowPF;
    3005           0 :     xIntInvPF     = 1. / xIntPF;
    3006           0 :     xtCorPF       = 2. * alphaPrimePF;
    3007           0 :     tAux[0]       = exp( max(-EXPMAX, bSlope  * (tLow[0] - tUpp[0])) ) - 1.;
    3008           0 :     tAux[1]       = exp( max(-EXPMAX, bSlope  * (tLow[1] - tUpp[1])) ) - 1.;
    3009           0 :   }
    3010             : 
    3011             :   // Done.
    3012           0 :   return true;
    3013             : 
    3014           0 : }
    3015             : 
    3016             : //--------------------------------------------------------------------------
    3017             : 
    3018             : // Select a trial kinematics phase space point. Perform full
    3019             : // Monte Carlo acceptance/rejection at this stage.
    3020             : 
    3021             : bool PhaseSpace2to3diffractive::trialKin( bool, bool ) {
    3022             : 
    3023             :   // Allow for possibility that energy varies from event to event.
    3024           0 :   if (doEnergySpread) {
    3025           0 :     eCM       = infoPtr->eCM();
    3026           0 :     s         = eCM * eCM;
    3027           0 :     for (int i = 0; i < 2; ++i) {
    3028           0 :       s3 = (i == 0) ? s1 : pow2(mA + m5min);
    3029           0 :       s4 = (i == 0) ? pow2(mB + m5min) : s2;
    3030           0 :       double lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 );
    3031           0 :       double lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 );
    3032           0 :       double tempA    = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s;
    3033           0 :       double tempB    = lambda12 *  lambda34 / s;
    3034           0 :       double tempC    = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3)
    3035           0 :                       * (s1 * s4 - s2 * s3) / s;
    3036           0 :       tLow[i]         = -0.5 * (tempA + tempB);
    3037           0 :       tUpp[i]         = tempC / tLow[i];
    3038             :     }
    3039           0 :     s3 = s1;
    3040           0 :     s4 = s2;
    3041           0 :     if (PomFlux == 1) {
    3042           0 :       tAux[0] = exp( max(-EXPMAX, bMin[0] * (tLow[0] - tUpp[0])) ) - 1.;
    3043           0 :       tAux[1] = exp( max(-EXPMAX, bMin[1] * (tLow[1] - tUpp[1])) ) - 1.;
    3044           0 :     } else if (PomFlux == 2) {
    3045           0 :       for (int i = 0; i < 2; ++i) {
    3046           0 :         tAux1[i] = exp( max(-EXPMAX, bSlope1 * (tLow[i] - tUpp[i])) ) - 1.;
    3047           0 :         tAux2[i] = exp( max(-EXPMAX, bSlope2 * (tLow[i] - tUpp[i])) ) - 1.;
    3048             :       }
    3049           0 :     } else if (PomFlux == 3 || PomFlux == 6 || PomFlux == 7) {
    3050           0 :       tAux[0]       = exp( max(-EXPMAX, bSlope  * (tLow[0] - tUpp[0])) ) - 1.;
    3051           0 :       tAux[1]       = exp( max(-EXPMAX, bSlope  * (tLow[1] - tUpp[1])) ) - 1.;
    3052           0 :     } else if (PomFlux == 4) {
    3053           0 :       tAux1[0]      = 1. / pow3(1. - coefDL * tLow[0]);
    3054           0 :       tAux2[0]      = 1. / pow3(1. - coefDL * tUpp[0]);
    3055           0 :       tAux1[1]      = 1. / pow3(1. - coefDL * tLow[1]);
    3056           0 :       tAux2[1]      = 1. / pow3(1. - coefDL * tUpp[1]);
    3057           0 :     }
    3058             :   }
    3059             : 
    3060             :   // Trivial kinematics of incoming hadrons.
    3061           0 :   double lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 );
    3062           0 :   pAbs            = 0.5 * lambda12 / eCM;
    3063           0 :   p1.p( 0., 0.,  pAbs, 0.5 * (s + s1 - s2) / eCM);
    3064           0 :   p2.p( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM);
    3065             : 
    3066             :   // Loop over attempts to set up mass, t1, t2 consistently.
    3067           0 :   for (int loop = 0; ; ++loop) {
    3068           0 :     if (loop == NTRY) {
    3069           0 :       infoPtr->errorMsg("Error in PhaseSpace2to3diffractive::trialKin: "
    3070             :       " quit after repeated tries");
    3071           0 :       return false;
    3072             :     }
    3073           0 :     double xi1 = 0.;
    3074           0 :     double xi2 = 0.;
    3075           0 :     double tVal[2] = { 0., 0.};
    3076             : 
    3077             :     // Schuler and Sjostrand:
    3078           0 :     if (PomFlux == 1) {
    3079             : 
    3080             :       // Select mass according to dxi_1/xi_1 * dxi_2/xi_2 * (1 - m^2/s).
    3081             :       do {
    3082           0 :         xi1 = pow( s5min / s, rndmPtr->flat());
    3083           0 :         xi2 = pow( s5min / s, rndmPtr->flat());
    3084           0 :         s5 = xi1 * xi2 * s;
    3085           0 :       } while (s5 < s5min || xi1 * xi2 > rndmPtr->flat());
    3086           0 :       if (mA + mB + sqrt(s5) + DIFFMASSMARGIN >= eCM) continue;
    3087             : 
    3088             :       // Select t according to exp(bMin*t) and correct to right slope.
    3089             :       bool tryAgain = false;
    3090           0 :       for (int i = 0; i < 2; ++i) {
    3091           0 :         tVal[i] = tUpp[i] + log(1. + tAux[i] * rndmPtr->flat()) / bMin[i];
    3092           0 :         double bDiff = (i == 0) ? sigmaTotPtr->bSlopeAX(s2 + xi1 * s)
    3093           0 :                                 : sigmaTotPtr->bSlopeXB(s1 + xi2 * s);
    3094           0 :         bDiff = max(0., bDiff - bMin[i]);
    3095           0 :         if (exp( max(-EXPMAX, bDiff * (tVal[i] - tUpp[i])) )
    3096           0 :           < rndmPtr->flat()) tryAgain = true;
    3097             :       }
    3098           0 :       if (tryAgain) continue;
    3099             : 
    3100             :     // Bruni and Ingelman:
    3101           0 :     } else if (PomFlux == 2) {
    3102             : 
    3103             :       // Select mass according to dxi_1/xi_1 * dxi_2/xi_2.
    3104             :       do {
    3105           0 :         xi1 = pow( s5min / s, rndmPtr->flat());
    3106           0 :         xi2 = pow( s5min / s, rndmPtr->flat());
    3107           0 :         s5 = xi1 * xi2 * s;
    3108           0 :       } while (s5 < s5min);
    3109           0 :       if (mA + mB + sqrt(s5) + DIFFMASSMARGIN >= eCM) continue;
    3110             : 
    3111             :       // Select t according to exp(bSlope*t) with two possible slopes.
    3112           0 :       for (int i = 0; i < 2; ++i)
    3113           0 :         tVal[i] = (rndmPtr->flat() < probSlope1[i])
    3114           0 :                 ? tUpp[i] + log(1. + tAux1[i] * rndmPtr->flat()) / bSlope1
    3115           0 :                 : tUpp[i] + log(1. + tAux2[i] * rndmPtr->flat()) / bSlope2;
    3116             : 
    3117             :     // Streng and Berger et al. (RapGap) and H1 Fit A/B:
    3118           0 :     } else if (PomFlux == 3 || PomFlux == 6 || PomFlux == 7) {
    3119             : 
    3120             :       // Select mass by dxi_1 * dxi_2 / (xi_1 * xi_2)^(1 + 2 epsilon).
    3121           0 :       double sMinPow = pow( s5min / s, xIntPF);
    3122           0 :       do {
    3123           0 :         xi1 = pow( sMinPow + rndmPtr->flat() * (1. - sMinPow), xIntInvPF );
    3124           0 :         xi2 = pow( sMinPow + rndmPtr->flat() * (1. - sMinPow), xIntInvPF );
    3125           0 :         s5 = xi1 * xi2 * s;
    3126           0 :       } while (s5 < s5min);
    3127           0 :       if (mA + mB + sqrt(s5) + DIFFMASSMARGIN >= eCM) continue;
    3128             : 
    3129             :       // Select t according to exponential and weigh by x_P^(2 alpha' |t|).
    3130             :       bool tryAgain = false;
    3131           0 :       for (int i = 0; i < 2; ++i) {
    3132           0 :         tVal[i] = tUpp[i] + log(1. + tAux[i] * rndmPtr->flat()) / bSlope;
    3133           0 :         double xi = (i == 0) ? xi1 : xi2;
    3134           0 :         if ( pow( xi, xtCorPF * abs(tVal[i]) ) < rndmPtr->flat() )
    3135           0 :           tryAgain = true;
    3136             :       }
    3137           0 :       if (tryAgain) continue;
    3138             : 
    3139             :     // Donnachie and Landshoff (RapGap):
    3140           0 :     } else if (PomFlux == 4) {
    3141             : 
    3142             :       // Select mass by dxi_1 * dxi_2 / (xi_1 * xi_2)^(1 + 2 epsilon).
    3143           0 :       double sMinPow = pow( s5min / s, xIntPF);
    3144           0 :       do {
    3145           0 :         xi1 = pow( sMinPow + rndmPtr->flat() * (1. - sMinPow), xIntInvPF );
    3146           0 :         xi2 = pow( sMinPow + rndmPtr->flat() * (1. - sMinPow), xIntInvPF );
    3147           0 :         s5 = xi1 * xi2 * s;
    3148           0 :       } while (s5 < s5min);
    3149           0 :       if (mA + mB + sqrt(s5) + DIFFMASSMARGIN >= eCM) continue;
    3150             : 
    3151             :       // Select t according to power and weigh by x_P^(2 alpha' |t|).
    3152             :       bool tryAgain = false;
    3153           0 :       for (int i = 0; i < 2; ++i) {
    3154           0 :         tVal[i] = - (1. / pow( tAux1[i] + rndmPtr->flat()
    3155           0 :                 * (tAux2[i] - tAux1[i]), 1./3.) - 1.) / coefDL;
    3156           0 :         double wDL = pow2( (mp24DL - 2.8 * tVal[i]) / (mp24DL - tVal[i]) )
    3157           0 :                    / pow4( 1. - tVal[i] / 0.7);
    3158           0 :         double wMX = 1. / pow4( 1. - coefDL * tVal[i]);
    3159           0 :         if (wDL < rndmPtr->flat() * wMX) tryAgain = true;
    3160           0 :         double xi = (i == 0) ? xi1 : xi2;
    3161           0 :         if ( pow( xi, xtCorPF * abs(tVal[i]) ) < rndmPtr->flat() )
    3162           0 :           tryAgain = true;
    3163             :       }
    3164           0 :       if (tryAgain) continue;
    3165             : 
    3166             :     // The MBR model (PomFlux == 5).
    3167           0 :     } else if (PomFlux == 5) {
    3168             :       double dymin0 = 0.;
    3169           0 :       double dymax  = log(s/m2minMBR);
    3170             :       double f1, f2, step2, dy, yc, ycmin, ycmax, dy1, dy2,
    3171             :              P, P1, P2, yRnd, yRnd1, yRnd2;
    3172             : 
    3173             :       // Von Neumann method to generate dy, uses dpepmax from SigmaTot.
    3174           0 :       do {
    3175           0 :         dy    = dymin0 + (dymax - dymin0) * rndmPtr->flat();
    3176             :         P     = 0.;
    3177           0 :         step2 = (dy - dymin0) / NINTEG2;
    3178           0 :         for (int j = 0; j < NINTEG2 ; ++j) {
    3179           0 :           yc  = -(dy - dymin0) / 2. + (j + 0.5) * step2;
    3180           0 :           dy1 = 0.5 * dy - yc;
    3181           0 :           dy2 = 0.5 * dy + yc;
    3182           0 :           f1  = exp(epsMBR * dy1) * ( (FFA1 / (FFB1 + 2. * alphMBR * dy1) )
    3183           0 :               + (FFA2 / (FFB2 + 2. * alphMBR * dy1) ) );
    3184           0 :           f2  = exp(epsMBR * dy2) * ( (FFA1 / (FFB1 + 2. * alphMBR * dy2) )
    3185           0 :               + (FFA2 / (FFB2 + 2. * alphMBR * dy2) ) );
    3186           0 :           f1 *= 0.5 * (1. + erf( (dy1 - 0.5 * dyminMBR) * dyminInvMBR ));
    3187           0 :           f2 *= 0.5 * (1. + erf( (dy2 - 0.5 * dyminMBR) * dyminInvMBR ));
    3188           0 :           P  += f1 * f2 * step2;
    3189             :         }
    3190           0 :         if (P > dpepmax) {
    3191           0 :           ostringstream osWarn;
    3192           0 :           osWarn << "dpepmax = " << scientific << setprecision(3)
    3193           0 :                  << dpepmax << " " << P << " " << dy << endl;
    3194           0 :           infoPtr->errorMsg("Warning in PhaseSpace2to2diffractive::"
    3195           0 :             "trialKin for central diffraction:", osWarn.str());
    3196           0 :         }
    3197           0 :         yRnd = dpepmax * rndmPtr->flat();
    3198             : 
    3199             :         // Generate dyc.
    3200           0 :         ycmax = (dy - dymin0) / 2.;
    3201           0 :         ycmin = -ycmax;
    3202           0 :         yc    = ycmin + (ycmax - ycmin) * rndmPtr->flat();
    3203             : 
    3204             :         // xi1, xi2 from dy and dy0.
    3205           0 :         dy1 = 0.5 * dy + yc;
    3206           0 :         dy2 = 0.5 * dy - yc;
    3207           0 :         P1  = 0.5 * (1. + erf( (dy1 - 0.5 * dyminMBR) * dyminInvMBR ));
    3208           0 :         P2  = 0.5 * (1. + erf( (dy2 - 0.5 * dyminMBR) * dyminInvMBR ));
    3209           0 :         yRnd1 = rndmPtr->flat();
    3210           0 :         yRnd2 = rndmPtr->flat();
    3211           0 :       } while( !(yRnd < P && yRnd1 < P1 && yRnd2 < P2) );
    3212           0 :       xi1 = exp( -dy1 );
    3213           0 :       xi2 = exp( -dy2 );
    3214             : 
    3215             :       // Generate t1 at vertex1. First exponent, then FF*exp.
    3216           0 :       double tmin  = -s1 * xi1 * xi1 / (1. - xi1);
    3217           0 :       do {
    3218           0 :         t1         = tmin + log(1. - rndmPtr->flat());
    3219           0 :         double pFF = (4. * s1 - 2.8 * t1) / ( (4. * s1 - t1)
    3220           0 :                    * pow2(1. - t1 / 0.71));
    3221           0 :         P          = pow2(pFF) * exp(2. * alphMBR * dy1 * t1);
    3222           0 :         yRnd       = exp(t1) * rndmPtr->flat();
    3223           0 :       } while (yRnd > P);
    3224             : 
    3225             :       // Generate t2 at vertex2. First exponent, then FF*exp.
    3226           0 :       tmin         = -s2 * xi2 * xi2 / (1. - xi2);
    3227           0 :       do {
    3228           0 :         t2         = tmin + log(1. - rndmPtr->flat());
    3229           0 :         double pFF = (4. * s2 - 2.8 * t2) / ((4. * s2 - t2)
    3230           0 :                    * pow2(1. - t2 / 0.71));
    3231           0 :         P          = pow2(pFF) * exp(2. * alphMBR * dy2 * t2);
    3232           0 :         yRnd       = exp(t2) * rndmPtr->flat();
    3233           0 :       } while (yRnd > P);
    3234             : 
    3235           0 :     }
    3236             : 
    3237             :     // Checks and kinematics construction four first options.
    3238             :     double pz3 = 0.;
    3239             :     double pz4 = 0.;
    3240             :     double pT3 = 0.;
    3241             :     double pT4 = 0.;
    3242           0 :     if (PomFlux != 5) {
    3243             : 
    3244             :       // Check whether m^2 (i.e. xi) and t choices are consistent.
    3245             :       bool tryAgain   = false;
    3246           0 :       for (int i = 0; i < 2; ++i) {
    3247           0 :         double sx1 = (i == 0) ? s1 : s2;
    3248           0 :         double sx2 = (i == 0) ? s2 : s1;
    3249             :         double sx3 = sx1;
    3250           0 :         double sx4 = (i == 0) ? s2 + xi1 * s : s1 + xi2 * s;
    3251           0 :         if (sqrt(sx3) + sqrt(sx4) + DIFFMASSMARGIN > eCM) tryAgain = true;
    3252           0 :         double lambda34 = sqrtpos( pow2( s - sx3 - sx4) - 4. * sx3 * sx4 );
    3253           0 :         double tempA    = s - (sx1 + sx2 + sx3 + sx4)
    3254           0 :                         + (sx1 - sx2) * (sx3 - sx4) / s;
    3255           0 :         double tempB    = lambda12 * lambda34 / s;
    3256           0 :         double tempC    = (sx3 - sx1) * (sx4 - sx2) + (sx1 + sx4 - sx2 - sx3)
    3257           0 :                         * (sx1 * sx4 - sx2 * sx3) / s;
    3258           0 :         double tLowNow  = -0.5 * (tempA + tempB);
    3259           0 :         double tUppNow  = tempC / tLowNow;
    3260           0 :         if (tVal[i] < tLowNow || tVal[i] > tUppNow) tryAgain = true;
    3261           0 :         if (tryAgain) break;
    3262             : 
    3263             :         // Careful reconstruction of scattering angle.
    3264           0 :         double cosTheta = min(1., max(-1., (tempA + 2. * tVal[i]) / tempB));
    3265           0 :         double sinTheta = 2. * sqrtpos( -(tempC + tempA * tVal[i]
    3266           0 :                         + tVal[i] * tVal[i]) ) / tempB;
    3267           0 :         theta           = asin( min(1., sinTheta));
    3268           0 :         if (cosTheta < 0.) theta = M_PI - theta;
    3269           0 :         double pAbs34   = 0.5 * lambda34 / eCM;
    3270           0 :         if (i == 0) {
    3271           0 :           pz3   =  pAbs34 * cos(theta);
    3272           0 :           pT3   =  pAbs34 * sin(theta);
    3273           0 :         } else {
    3274           0 :           pz4   = -pAbs34 * cos(theta);
    3275           0 :           pT4   =  pAbs34 * sin(theta);
    3276             :         }
    3277           0 :       }
    3278           0 :       if (tryAgain) continue;
    3279           0 :       t1        = tVal[0];
    3280           0 :       t2        = tVal[1];
    3281             : 
    3282             :     // Kinematics construction in the MBR model.
    3283           0 :     } else {
    3284           0 :       pz3       =  pAbs * (1. - xi1);
    3285           0 :       pz4       = -pAbs * (1. - xi2);
    3286           0 :       pT3       =  sqrt( (1. - xi1) * abs(t1) - s1 * pow2(xi1) );
    3287           0 :       pT4       =  sqrt( (1. - xi2) * abs(t2) - s2 * pow2(xi2) );
    3288             :     }
    3289             : 
    3290             :     // Common final steps of kinematics.
    3291           0 :     double phi3 = 2. * M_PI * rndmPtr->flat();
    3292           0 :     double phi4 = 2. * M_PI * rndmPtr->flat();
    3293           0 :     p3.p( pT3 * cos(phi3), pT3 * sin(phi3), pz3,
    3294           0 :           sqrt(pz3 * pz3 + pT3 * pT3 + s1) );
    3295           0 :     p4.p( pT4 * cos(phi4), pT4 * sin(phi4), pz4,
    3296           0 :           sqrt(pz4 * pz4 + pT4 * pT4 + s2) );
    3297             : 
    3298             :     // Central dissociated system, from Pomeron-Pomeron 4 vectors.
    3299           0 :     p5   = (p1 - p3) + (p2 - p4);
    3300           0 :     mHat = p5.mCalc();
    3301             : 
    3302             :     // If acceptable diffractive mass then no more looping.
    3303           0 :     if (mHat > DIFFMASSMIN) break;
    3304           0 :   }
    3305           0 :   return true;
    3306             : 
    3307           0 : }
    3308             : 
    3309             : //--------------------------------------------------------------------------
    3310             : 
    3311             : // Construct the four-vector kinematics from the trial values.
    3312             : 
    3313             : bool PhaseSpace2to3diffractive::finalKin() {
    3314             : 
    3315             :   // Particle four-momenta and masses.
    3316           0 :   pH[1] = p1;
    3317           0 :   pH[2] = p2;
    3318           0 :   pH[3] = p3;
    3319           0 :   pH[4] = p4;
    3320           0 :   pH[5] = p5;
    3321           0 :   mH[1] = mA;
    3322           0 :   mH[2] = mB;
    3323           0 :   mH[3] = mA;
    3324           0 :   mH[4] = mB;
    3325           0 :   mH[5] = mHat;
    3326             : 
    3327             :   // Set some further info for completeness (but Info can be for subprocess).
    3328           0 :   x1H   = 1.;
    3329           0 :   x2H   = 1.;
    3330           0 :   sH    = s;
    3331           0 :   tH    = (p1 - p3).m2Calc();
    3332           0 :   uH    = (p2 - p4).m2Calc();
    3333           0 :   mHat  = eCM;
    3334           0 :   p2Abs = pAbs * pAbs;
    3335           0 :   betaZ = 0.;
    3336             :   // Store average pT of three final particles for documentation.
    3337           0 :   pTH   = (p3.pT() + p4.pT() + p5.pT()) / 3.;
    3338             : 
    3339             :   // Done.
    3340           0 :   return true;
    3341             : 
    3342             : }
    3343             : 
    3344             : //==========================================================================
    3345             : 
    3346             : // PhaseSpace2to3tauycyl class.
    3347             : // 2 -> 3 kinematics for normal subprocesses.
    3348             : 
    3349             : //--------------------------------------------------------------------------
    3350             : 
    3351             : // Constants: could be changed here if desired, but normally should not.
    3352             : // These are of technical nature, as described for each.
    3353             : 
    3354             : // Number of Newton-Raphson iterations of kinematics when masses introduced.
    3355             : const int PhaseSpace2to3tauycyl::NITERNR = 5;
    3356             : 
    3357             : //--------------------------------------------------------------------------
    3358             : 
    3359             : // Set up for fixed or Breit-Wigner mass selection.
    3360             : 
    3361             : bool PhaseSpace2to3tauycyl::setupMasses() {
    3362             : 
    3363             :   // Treat Z0 as such or as gamma*/Z0
    3364           0 :   gmZmode         = gmZmodeGlobal;
    3365           0 :   int gmZmodeProc = sigmaProcessPtr->gmZmode();
    3366           0 :   if (gmZmodeProc >= 0) gmZmode = gmZmodeProc;
    3367             : 
    3368             :   // Set sHat limits - based on global limits only.
    3369           0 :   mHatMin   = mHatGlobalMin;
    3370           0 :   sHatMin   = mHatMin*mHatMin;
    3371           0 :   mHatMax   = eCM;
    3372           0 :   if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( eCM, mHatGlobalMax);
    3373           0 :   sHatMax   = mHatMax*mHatMax;
    3374             : 
    3375             :   // Masses and widths of resonances.
    3376           0 :   setupMass1(3);
    3377           0 :   setupMass1(4);
    3378           0 :   setupMass1(5);
    3379             : 
    3380             :   // Reduced mass range - do not make it as fancy as in two-body case.
    3381           0 :   if (useBW[3]) mUpper[3] -= (mPeak[4] + mPeak[5]);
    3382           0 :   if (useBW[4]) mUpper[4] -= (mPeak[3] + mPeak[5]);
    3383           0 :   if (useBW[5]) mUpper[5] -= (mPeak[3] + mPeak[4]);
    3384             : 
    3385             :   // If closed phase space then unallowed process.
    3386             :   bool physical = true;
    3387           0 :   if (useBW[3] && mUpper[3] < mLower[3] + MASSMARGIN) physical = false;
    3388           0 :   if (useBW[4] && mUpper[4] < mLower[4] + MASSMARGIN) physical = false;
    3389           0 :   if (useBW[5] && mUpper[5] < mLower[5] + MASSMARGIN) physical = false;
    3390           0 :   if (!useBW[3] && !useBW[4] && !useBW[5] && mHatMax < mPeak[3]
    3391           0 :     + mPeak[4] + mPeak[5] + MASSMARGIN) physical = false;
    3392           0 :   if (!physical) return false;
    3393             : 
    3394             :   // No extra pT precautions in massless limit - assumed fixed by ME's.
    3395           0 :   pTHatMin  = pTHatGlobalMin;
    3396           0 :   pT2HatMin = pTHatMin * pTHatMin;
    3397           0 :   pTHatMax  = pTHatGlobalMax;
    3398           0 :   pT2HatMax = pTHatMax * pTHatMax;
    3399             : 
    3400             :   // Prepare to select m3 by BW + flat + 1/s_3.
    3401           0 :   if (useBW[3]) {
    3402           0 :     double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5])
    3403           0 :       * mWidth[3] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5]));
    3404           0 :     double distToThreshB = (mHatMax - mPeak[3] - mMin[4] - mMin[5])
    3405           0 :       / mWidth[3];
    3406           0 :     double distToThresh = min( distToThreshA, distToThreshB);
    3407           0 :     setupMass2(3, distToThresh);
    3408           0 :   }
    3409             : 
    3410             :   // Prepare to select m4 by BW + flat + 1/s_3.
    3411           0 :   if (useBW[4]) {
    3412           0 :     double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5])
    3413           0 :       * mWidth[4] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5]));
    3414           0 :     double distToThreshB = (mHatMax - mPeak[4] - mMin[3] - mMin[5])
    3415           0 :       / mWidth[4];
    3416           0 :     double distToThresh = min( distToThreshA, distToThreshB);
    3417           0 :     setupMass2(4, distToThresh);
    3418           0 :   }
    3419             : 
    3420             :   // Prepare to select m5 by BW + flat + 1/s_3.
    3421           0 :   if (useBW[5]) {
    3422           0 :     double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5])
    3423           0 :       * mWidth[5] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5]));
    3424           0 :     double distToThreshB = (mHatMax - mPeak[5] - mMin[3] - mMin[4])
    3425           0 :       / mWidth[5];
    3426           0 :     double distToThresh = min( distToThreshA, distToThreshB);
    3427           0 :     setupMass2(5, distToThresh);
    3428           0 :   }
    3429             : 
    3430             :   // Initialization masses. For now give up when constrained phase space.
    3431           0 :   m3 = (useBW[3]) ? min(mPeak[3], mUpper[3]) : mPeak[3];
    3432           0 :   m4 = (useBW[4]) ? min(mPeak[4], mUpper[4]) : mPeak[4];
    3433           0 :   m5 = (useBW[5]) ? min(mPeak[5], mUpper[5]) : mPeak[5];
    3434           0 :   if (m3 + m4 + m5 + MASSMARGIN > mHatMax) physical = false;
    3435           0 :   s3 = m3*m3;
    3436           0 :   s4 = m4*m4;
    3437           0 :   s5 = m5*m5;
    3438             : 
    3439             :   // Correct selected mass-spectrum to running-width Breit-Wigner.
    3440             :   // Extra safety margin for maximum search.
    3441           0 :   wtBW = 1.;
    3442           0 :   if (useBW[3]) wtBW *= weightMass(3) * EXTRABWWTMAX;
    3443           0 :   if (useBW[4]) wtBW *= weightMass(4) * EXTRABWWTMAX;
    3444           0 :   if (useBW[5]) wtBW *= weightMass(5) * EXTRABWWTMAX;
    3445             : 
    3446             :   // Done.
    3447           0 :   return physical;
    3448             : 
    3449           0 : }
    3450             : 
    3451             : //--------------------------------------------------------------------------
    3452             : 
    3453             : // Select Breit-Wigner-distributed or fixed masses.
    3454             : 
    3455             : bool PhaseSpace2to3tauycyl::trialMasses() {
    3456             : 
    3457             :   // By default vanishing cross section.
    3458           0 :   sigmaNw = 0.;
    3459           0 :   wtBW = 1.;
    3460             : 
    3461             :   // Pick m3, m4 and m5 independently.
    3462           0 :   trialMass(3);
    3463           0 :   trialMass(4);
    3464           0 :   trialMass(5);
    3465             : 
    3466             :   // If outside phase space then reject event.
    3467           0 :   if (m3 + m4 + m5 + MASSMARGIN > mHatMax) return false;
    3468             : 
    3469             :   // Correct selected mass-spectrum to running-width Breit-Wigner.
    3470           0 :   if (useBW[3]) wtBW *= weightMass(3);
    3471           0 :   if (useBW[4]) wtBW *= weightMass(4);
    3472           0 :   if (useBW[5]) wtBW *= weightMass(5);
    3473             : 
    3474             :   // Done.
    3475           0 :   return true;
    3476             : 
    3477           0 : }
    3478             : 
    3479             : //--------------------------------------------------------------------------
    3480             : 
    3481             : // Construct the four-vector kinematics from the trial values.
    3482             : 
    3483             : bool PhaseSpace2to3tauycyl::finalKin() {
    3484             : 
    3485             :   // Assign masses to particles assumed massless in matrix elements.
    3486           0 :   int id3 = sigmaProcessPtr->id(3);
    3487           0 :   int id4 = sigmaProcessPtr->id(4);
    3488           0 :   int id5 = sigmaProcessPtr->id(5);
    3489           0 :   if (idMass[3] == 0) { m3 = particleDataPtr->m0(id3); s3 = m3*m3; }
    3490           0 :   if (idMass[4] == 0) { m4 = particleDataPtr->m0(id4); s4 = m4*m4; }
    3491           0 :   if (idMass[5] == 0) { m5 = particleDataPtr->m0(id5); s5 = m5*m5; }
    3492             : 
    3493             :   // Check that phase space still open after new mass assignment.
    3494           0 :   if (m3 + m4 + m5 + MASSMARGIN > mHat) {
    3495           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to3tauycyl::finalKin: "
    3496             :       "failed after mass assignment");
    3497           0 :     return false;
    3498             :   }
    3499             : 
    3500             :   // Particle masses; incoming always on mass shell.
    3501           0 :   mH[1] = 0.;
    3502           0 :   mH[2] = 0.;
    3503           0 :   mH[3] = m3;
    3504           0 :   mH[4] = m4;
    3505           0 :   mH[5] = m5;
    3506             : 
    3507             :   // Incoming partons along beam axes.
    3508           0 :   pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H);
    3509           0 :   pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H);
    3510             : 
    3511             :   // Begin three-momentum rescaling to compensate for masses.
    3512           0 :   if (idMass[3] == 0 || idMass[4] == 0 || idMass[5] == 0) {
    3513           0 :     double p3S = p3cm.pAbs2();
    3514           0 :     double p4S = p4cm.pAbs2();
    3515           0 :     double p5S = p5cm.pAbs2();
    3516             :     double fac = 1.;
    3517             :     double e3, e4, e5, value, deriv;
    3518             : 
    3519             :     // Iterate rescaling solution five times, using Newton-Raphson.
    3520           0 :     for (int i = 0; i < NITERNR; ++i) {
    3521           0 :       e3    = sqrt(s3 + fac * p3S);
    3522           0 :       e4    = sqrt(s4 + fac * p4S);
    3523           0 :       e5    = sqrt(s5 + fac * p5S);
    3524           0 :       value = e3 + e4 + e5 - mHat;
    3525           0 :       deriv = 0.5 * (p3S / e3 + p4S / e4 + p5S / e5);
    3526           0 :       fac  -= value / deriv;
    3527             :     }
    3528             : 
    3529             :     // Rescale momenta appropriately.
    3530           0 :     double facRoot = sqrt(fac);
    3531           0 :     p3cm.rescale3( facRoot );
    3532           0 :     p4cm.rescale3( facRoot );
    3533           0 :     p5cm.rescale3( facRoot );
    3534           0 :     p3cm.e( sqrt(s3 + fac * p3S) );
    3535           0 :     p4cm.e( sqrt(s4 + fac * p4S) );
    3536           0 :     p5cm.e( sqrt(s5 + fac * p5S) );
    3537           0 :   }
    3538             : 
    3539             :   // Outgoing partons initially in collision CM frame along beam axes.
    3540           0 :   pH[3] = p3cm;
    3541           0 :   pH[4] = p4cm;
    3542           0 :   pH[5] = p5cm;
    3543             : 
    3544             :   // Then boost them to overall CM frame
    3545           0 :   betaZ = (x1H - x2H)/(x1H + x2H);
    3546           0 :   pH[3].rot( theta, phi);
    3547           0 :   pH[4].rot( theta, phi);
    3548           0 :   pH[3].bst( 0., 0., betaZ);
    3549           0 :   pH[4].bst( 0., 0., betaZ);
    3550           0 :   pH[5].bst( 0., 0., betaZ);
    3551             : 
    3552             :   // Store average pT of three final particles for documentation.
    3553           0 :   pTH = (p3cm.pT() + p4cm.pT() + p5cm.pT()) / 3.;
    3554             : 
    3555             :   // Done.
    3556           0 :   return true;
    3557           0 : }
    3558             : 
    3559             : //==========================================================================
    3560             : 
    3561             : // The PhaseSpace2to3yyycyl class.
    3562             : // Phase space for 2 -> 3 QCD processes, 1 + 2 -> 3 + 4 + 5 set up in
    3563             : // y3, y4, y5, pT2_3, pT2_5, phi_3 and phi_5, and with R separation cut.
    3564             : // Note: here cout is used for output, not os. Change??
    3565             : 
    3566             : //--------------------------------------------------------------------------
    3567             : 
    3568             : //  Sample the phase space of the process.
    3569             : 
    3570             : bool PhaseSpace2to3yyycyl::setupSampling() {
    3571             : 
    3572             :   // Phase space cuts specifically for 2 -> 3 QCD processes.
    3573           0 :   pTHat3Min            = settingsPtr->parm("PhaseSpace:pTHat3Min");
    3574           0 :   pTHat3Max            = settingsPtr->parm("PhaseSpace:pTHat3Max");
    3575           0 :   pTHat5Min            = settingsPtr->parm("PhaseSpace:pTHat5Min");
    3576           0 :   pTHat5Max            = settingsPtr->parm("PhaseSpace:pTHat5Max");
    3577           0 :   RsepMin              = settingsPtr->parm("PhaseSpace:RsepMin");
    3578           0 :   R2sepMin             = pow2(RsepMin);
    3579             : 
    3580             :   // If both beams are baryons then softer PDF's than for mesons/Pomerons.
    3581           0 :   hasBaryonBeams = ( beamAPtr->isBaryon() && beamBPtr->isBaryon() );
    3582             : 
    3583             :   // Work with massless partons.
    3584           0 :   for (int i = 0; i < 6; ++i) mH[i] = 0.;
    3585             : 
    3586             :   // Constrain to possible cuts at current CM energy and check consistency.
    3587           0 :   pT3Min = pTHat3Min;
    3588           0 :   pT3Max = pTHat3Max;
    3589           0 :   if (pT3Max < pT3Min) pT3Max = 0.5 * eCM;
    3590           0 :   pT5Min = pTHat5Min;
    3591           0 :   pT5Max = pTHat5Max;
    3592           0 :   if (pT5Max < pT5Min) pT5Max = 0.5 * eCM;
    3593           0 :   if (pT5Max > pT3Max || pT5Min > pT3Min || pT3Min + 2. * pT5Min > eCM) {
    3594           0 :     infoPtr->errorMsg("Error in PhaseSpace2to3yyycyl::setupSampling: "
    3595             :     "inconsistent pT limits in 3-body phase space");
    3596           0 :     return false;
    3597             :   }
    3598             : 
    3599             :   // Loop over some configurations where cross section could be maximal.
    3600             :   // In all cases all sum p_z = 0, for maximal PDF weights.
    3601             :   // Also pT3 and R45 are minimal, while pT5 may vary.
    3602           0 :   sigmaMx = 0.;
    3603           0 :   double pT5EffMax = min( pT5Max, 0.5 * pT3Min / cos(0.5 * RsepMin) );
    3604           0 :   double pT3EffMin = max( pT3Min, 2.0 * pT5Min * cos(0.5 * RsepMin) ) ;
    3605           0 :   double sinhR = sinh(0.5 * RsepMin);
    3606           0 :   double coshR = cosh(0.5 * RsepMin);
    3607           0 :   for (int iStep = 0; iStep < 120; ++iStep) {
    3608             : 
    3609             :     // First kind: |phi4 - phi5| = R, all p_z = 0, i.e. separation in phi.
    3610           0 :     if (iStep < 10) {
    3611           0 :       pT3   = pT3EffMin;
    3612           0 :       pT5   = pT5Min * pow( pT5EffMax / pT5Min, iStep / 9.);
    3613           0 :       double pTRat    = pT5 / pT3;
    3614           0 :       double sin2Rsep = pow2( sin(RsepMin) );
    3615           0 :       double cosPhi35 = - cos(RsepMin) * sqrtpos(1. - sin2Rsep
    3616           0 :         * pow2(pTRat)) - sin2Rsep * pTRat;
    3617           0 :       cosPhi35 = max( cosPhi35, cos(M_PI - 0.5 * RsepMin) );
    3618           0 :       double sinPhi35 = sqrt(1. - pow2(cosPhi35));
    3619           0 :       pT4   = sqrt( pow2(pT3) + pow2(pT5) + 2. * pT3 * pT5 * cosPhi35);
    3620           0 :       p3cm  = pT3 * Vec4( 1., 0., 0., 1.);
    3621           0 :       p4cm  = Vec4(-pT3 - pT5 * cosPhi35, -pT5 * sinPhi35, 0., pT4);
    3622           0 :       p5cm  = pT5 * Vec4( cosPhi35, sinPhi35, 0., 1.);
    3623             : 
    3624             :     // Second kind: |y4 - y5| = R, phi4 = phi5, i.e. separation in y.
    3625           0 :     } else {
    3626           0 :       pT5   = pT5Min * pow( pT5Max / pT5Min, iStep%10 / 9. );
    3627           0 :       pT3   = max( pT3Min, 2. * pT5);
    3628           0 :       pT4   = pT3 - pT5;
    3629           0 :       p4cm  = pT4 * Vec4( -1., 0.,  sinhR, coshR );
    3630           0 :       p5cm  = pT5 * Vec4( -1., 0., -sinhR, coshR );
    3631           0 :       y3    = -1.2 + 0.2 * (iStep/10);
    3632           0 :       p3cm  = pT3 * Vec4( 1., 0., sinh(y3), cosh(y3));
    3633           0 :       betaZ = (p3cm.pz() + p4cm.pz() + p5cm.pz())
    3634           0 :             / (p3cm.e()  + p4cm.e()  + p5cm.e());
    3635           0 :       p3cm.bst( 0., 0., -betaZ);
    3636           0 :       p4cm.bst( 0., 0., -betaZ);
    3637           0 :       p5cm.bst( 0., 0., -betaZ);
    3638             :     }
    3639             : 
    3640             :     // Find cross section in chosen phase space point.
    3641           0 :     pInSum = p3cm + p4cm + p5cm;
    3642           0 :     x1H   = pInSum.e() /  eCM;
    3643           0 :     x2H   = x1H;
    3644           0 :     sH    = pInSum.m2Calc();
    3645           0 :     sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
    3646             :       0., 0., 0., 1., 1., 1.);
    3647           0 :     sigmaNw = sigmaProcessPtr->sigmaPDF();
    3648             : 
    3649             :     // Multiply by Jacobian.
    3650           0 :     double flux  = 1. /(8. * pow2(sH) * pow5(2. * M_PI));
    3651           0 :     double pTRng = pow2(M_PI)
    3652           0 :       * pow4(pT3) * (1./pow2(pT3Min) - 1./pow2(pT3Max))
    3653           0 :       * pow2(pT5) * 2.* log(pT5Max/pT5Min);
    3654           0 :     double yRng  = 8. * log(eCM / pT3) * log(eCM / pT4) * log(eCM / pT5);
    3655           0 :     sigmaNw *= SAFETYMARGIN * flux * pTRng * yRng;
    3656             : 
    3657             :     // Update to largest maximum.
    3658           0 :     if (showSearch && sigmaNw > sigmaMx) cout << "\n New sigmamax is "
    3659           0 :       << scientific << setprecision(3) << sigmaNw << " for x1 = " << x1H
    3660           0 :       << " x2 = " << x2H << " sH = " << sH << endl << " p3 = " << p3cm
    3661           0 :       << " p4 = " << p4cm << " p5 = " << p5cm;
    3662           0 :     if (sigmaNw > sigmaMx) sigmaMx = sigmaNw;
    3663             :   }
    3664           0 :   sigmaPos = sigmaMx;
    3665             : 
    3666             :   // Done.
    3667             :   return true;
    3668           0 : }
    3669             : 
    3670             : //--------------------------------------------------------------------------
    3671             : 
    3672             : //  Sample the phase space of the process.
    3673             : 
    3674             : bool PhaseSpace2to3yyycyl::trialKin(bool inEvent, bool) {
    3675             : 
    3676             :   // Allow for possibility that energy varies from event to event.
    3677           0 :   if (doEnergySpread) {
    3678           0 :     eCM   = infoPtr->eCM();
    3679           0 :     s     = eCM * eCM;
    3680           0 :   }
    3681           0 :   sigmaNw = 0.;
    3682             : 
    3683             :   // Constrain to possible cuts at current CM energy and check consistency.
    3684           0 :   pT3Min = pTHat3Min;
    3685           0 :   pT3Max = pTHat3Max;
    3686           0 :   if (pT3Max < pT3Min) pT3Max = 0.5 * eCM;
    3687           0 :   pT5Min = pTHat5Min;
    3688           0 :   pT5Max = pTHat5Max;
    3689           0 :   if (pT5Max < pT5Min) pT5Max = 0.5 * eCM;
    3690           0 :   if (pT5Max > pT3Max || pT5Min > pT3Min || pT3Min + 2. * pT5Min > eCM) {
    3691           0 :     infoPtr->errorMsg("Error in PhaseSpace2to3yyycyl::trialKin: "
    3692             :     "inconsistent pT limits in 3-body phase space");
    3693           0 :     return false;
    3694             :   }
    3695             : 
    3696             :   // Pick pT3 according to d^2(pT3)/pT3^4 and pT5 to d^2(pT5)/pT5^2.
    3697           0 :   pT3    = pT3Min * pT3Max / sqrt( pow2(pT3Min) +
    3698           0 :     rndmPtr->flat() * (pow2(pT3Max) - pow2(pT3Min)) );
    3699           0 :   pT5Max = min(pT5Max, pT3);
    3700           0 :   if (pT5Max < pT5Min) return false;
    3701           0 :   pT5    = pT5Min * pow( pT5Max / pT5Min, rndmPtr->flat() );
    3702             : 
    3703             :   // Pick azimuthal angles flat and reconstruct pT4, between pT3 and pT5.
    3704           0 :   phi3   = 2. * M_PI * rndmPtr->flat();
    3705           0 :   phi5   = 2. * M_PI * rndmPtr->flat();
    3706           0 :   pT4    = sqrt( pow2(pT3) + pow2(pT5) + 2. * pT3 * pT5 * cos(phi3 - phi5) );
    3707           0 :   if (pT4 > pT3 || pT4 < pT5) return false;
    3708           0 :   phi4   = atan2( -(pT3 * sin(phi3) + pT5 * sin(phi5)),
    3709           0 :                   -(pT3 * cos(phi3) + pT5 * cos(phi5)) );
    3710             : 
    3711             :   // Pick rapidities flat in allowed ranges.
    3712           0 :   y3Max  = log(eCM / pT3);
    3713           0 :   y4Max  = log(eCM / pT4);
    3714           0 :   y5Max  = log(eCM / pT5);
    3715           0 :   y3     = y3Max * (2. * rndmPtr->flat() - 1.);
    3716           0 :   y4     = y4Max * (2. * rndmPtr->flat() - 1.);
    3717           0 :   y5     = y5Max * (2. * rndmPtr->flat() - 1.);
    3718             : 
    3719             :   // Reject some events at large rapidities to improve efficiency.
    3720             :   // (Works for baryons, not pions or Pomerons if they have hard PDF's.)
    3721           0 :   double WTy = (hasBaryonBeams) ? (1. - pow2(y3/y3Max))
    3722           0 :              * (1. - pow2(y4/y4Max)) * (1. - pow2(y5/y5Max)) : 1.;
    3723           0 :   if (WTy < rndmPtr->flat()) return false;
    3724             : 
    3725             :   // Check that any pair separated more then RsepMin in (y, phi) space.
    3726           0 :   dphi   = abs(phi3 - phi4);
    3727           0 :   if (dphi > M_PI) dphi = 2. * M_PI - dphi;
    3728           0 :   if (pow2(y3 - y4) + pow2(dphi) < R2sepMin) return false;
    3729           0 :   dphi   = abs(phi3 - phi5);
    3730           0 :   if (dphi > M_PI) dphi = 2. * M_PI - dphi;
    3731           0 :   if (pow2(y3 - y5) + pow2(dphi) < R2sepMin) return false;
    3732           0 :   dphi   = abs(phi4 - phi5);
    3733           0 :   if (dphi > M_PI) dphi = 2. * M_PI - dphi;
    3734           0 :   if (pow2(y4 - y5) + pow2(dphi) < R2sepMin) return false;
    3735             : 
    3736             :   // Reconstruct all four-vectors.
    3737           0 :   pH[3]  = pT3 * Vec4( cos(phi3), sin(phi3), sinh(y3), cosh(y3) );
    3738           0 :   pH[4]  = pT4 * Vec4( cos(phi4), sin(phi4), sinh(y4), cosh(y4) );
    3739           0 :   pH[5]  = pT5 * Vec4( cos(phi5), sin(phi5), sinh(y5), cosh(y5) );
    3740           0 :   pInSum = pH[3] + pH[4] + pH[5];
    3741             : 
    3742             :   // Check that x values physical and sHat in allowed range.
    3743           0 :   x1H    = (pInSum.e() + pInSum.pz()) /  eCM;
    3744           0 :   x2H    = (pInSum.e() - pInSum.pz()) /  eCM;
    3745           0 :   if (x1H >= 1. || x2H >= 1.) return false;
    3746           0 :   sH     = pInSum.m2Calc();
    3747           0 :   if ( sH < pow2(mHatGlobalMin) ||
    3748           0 :     (mHatGlobalMax > mHatGlobalMin && sH > pow2(mHatGlobalMax)) )
    3749           0 :     return false;
    3750             : 
    3751             :   // Boost four-vectors to rest frame of collision.
    3752           0 :   betaZ  = (x1H - x2H)/(x1H + x2H);
    3753           0 :   p3cm   = pH[3];    p3cm.bst( 0., 0., -betaZ);
    3754           0 :   p4cm   = pH[4];    p4cm.bst( 0., 0., -betaZ);
    3755           0 :   p5cm   = pH[5];    p5cm.bst( 0., 0., -betaZ);
    3756             : 
    3757             :   // Find cross section in chosen phase space point.
    3758           0 :   sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm,
    3759             :     0., 0., 0., 1., 1., 1.);
    3760           0 :   sigmaNw = sigmaProcessPtr->sigmaPDF();
    3761             : 
    3762             :   // Multiply by Jacobian. Correct for rejection of large rapidities.
    3763           0 :   double flux  = 1. /(8. * pow2(sH) * pow5(2. * M_PI));
    3764           0 :   double yRng  = 8. * y3Max * y4Max * y5Max;
    3765           0 :   double pTRng = pow2(M_PI)
    3766           0 :     * pow4(pT3) * (1./pow2(pT3Min) - 1./pow2(pT3Max))
    3767           0 :     * pow2(pT5) * 2.* log(pT5Max/pT5Min);
    3768           0 :   sigmaNw *= flux * yRng * pTRng / WTy;
    3769             : 
    3770             :   // Allow possibility for user to modify cross section.
    3771           0 :   if (canModifySigma) sigmaNw
    3772           0 :     *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, inEvent);
    3773           0 :   if (canBiasSelection) sigmaNw
    3774           0 :     *= userHooksPtr->biasSelectionBy( sigmaProcessPtr, this, inEvent);
    3775           0 :   if (canBias2Sel) sigmaNw *= pow( pTH / bias2SelRef, bias2SelPow);
    3776             : 
    3777             :   // Check if maximum violated.
    3778           0 :   newSigmaMx = false;
    3779           0 :   if (sigmaNw > sigmaMx) {
    3780           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to3yyycyl::trialKin: "
    3781             :       "maximum for cross section violated");
    3782             : 
    3783             :     // Violation strategy 1: increase maximum (always during initialization).
    3784           0 :     if (increaseMaximum || !inEvent) {
    3785           0 :       double violFact = SAFETYMARGIN * sigmaNw / sigmaMx;
    3786           0 :       sigmaMx = SAFETYMARGIN * sigmaNw;
    3787           0 :       newSigmaMx = true;
    3788           0 :       if (showViolation) {
    3789           0 :         if (violFact < 9.99) cout << fixed;
    3790           0 :         else                 cout << scientific;
    3791           0 :         cout << " PYTHIA Maximum for " << sigmaProcessPtr->name()
    3792           0 :              << " increased by factor " << setprecision(3) << violFact
    3793           0 :              << " to " << scientific << sigmaMx << endl;
    3794           0 :       }
    3795             : 
    3796             :     // Violation strategy 2: weight event (done in ProcessContainer).
    3797           0 :     } else if (showViolation && sigmaNw > sigmaPos) {
    3798           0 :       double violFact = sigmaNw / sigmaMx;
    3799           0 :       if (violFact < 9.99) cout << fixed;
    3800           0 :       else                 cout << scientific;
    3801           0 :       cout << " PYTHIA Maximum for " << sigmaProcessPtr->name()
    3802           0 :            << " exceeded by factor " << setprecision(3) << violFact << endl;
    3803           0 :       sigmaPos = sigmaNw;
    3804           0 :     }
    3805             :   }
    3806             : 
    3807             :   // Check if negative cross section.
    3808           0 :   if (sigmaNw < sigmaNeg) {
    3809           0 :     infoPtr->errorMsg("Warning in PhaseSpace2to3yyycyl::trialKin:"
    3810           0 :       " negative cross section set 0", "for " +  sigmaProcessPtr->name() );
    3811           0 :     sigmaNeg = sigmaNw;
    3812             : 
    3813             :     // Optional printout of (all) violations.
    3814           0 :     if (showViolation) cout << " PYTHIA Negative minimum for "
    3815           0 :       << sigmaProcessPtr->name() << " changed to " << scientific
    3816           0 :       << setprecision(3) << sigmaNeg << endl;
    3817             :   }
    3818           0 :   if (sigmaNw < 0.) sigmaNw = 0.;
    3819             : 
    3820             : 
    3821             :   // Done.
    3822             :   return true;
    3823           0 : }
    3824             : 
    3825             : //--------------------------------------------------------------------------
    3826             : 
    3827             : // Construct the final kinematics of the process: not much left
    3828             : 
    3829             : bool PhaseSpace2to3yyycyl::finalKin() {
    3830             : 
    3831             :   // Work with massless partons.
    3832           0 :   for (int i = 0; i < 6; ++i) mH[i] = 0.;
    3833             : 
    3834             :   // Ibncoming partons to collision.
    3835           0 :   pH[1] = 0.5 * (pInSum.e() + pInSum.pz()) * Vec4( 0., 0.,  1., 1.);
    3836           0 :   pH[2] = 0.5 * (pInSum.e() - pInSum.pz()) * Vec4( 0., 0., -1., 1.);
    3837             : 
    3838             :   // Some quantities meaningless for 2 -> 3. pT defined as average value.
    3839           0 :   tH    = 0.;
    3840           0 :   uH    = 0.;
    3841           0 :   pTH = (pH[3].pT() + pH[4].pT() + pH[5].pT()) / 3.;
    3842           0 :   theta = 0.;
    3843           0 :   phi   = 0.;
    3844             : 
    3845           0 :   return true;
    3846             : }
    3847             : 
    3848             : 
    3849             : //==========================================================================
    3850             : 
    3851             : // The PhaseSpaceLHA class.
    3852             : // A derived class for Les Houches events.
    3853             : // Note: arbitrary subdivision into PhaseSpaceLHA and SigmaLHAProcess tasks.
    3854             : 
    3855             : //--------------------------------------------------------------------------
    3856             : 
    3857             : // Constants: could be changed here if desired, but normally should not.
    3858             : // These are of technical nature, as described for each.
    3859             : 
    3860             : // LHA convention with cross section in pb forces conversion to mb.
    3861             : const double PhaseSpaceLHA::CONVERTPB2MB  = 1e-9;
    3862             : 
    3863             : //--------------------------------------------------------------------------
    3864             : 
    3865             : // Find maximal cross section for comparison with internal processes.
    3866             : 
    3867             : bool PhaseSpaceLHA::setupSampling() {
    3868             : 
    3869             :   // Find which strategy Les Houches events are produced with.
    3870           0 :   strategy = lhaUpPtr->strategy();
    3871           0 :   stratAbs = abs(strategy);
    3872           0 :   if (strategy == 0 || stratAbs > 4) {
    3873           0 :     ostringstream stratCode;
    3874           0 :     stratCode << strategy;
    3875           0 :     infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: unknown "
    3876           0 :       "Les Houches Accord weighting stategy", stratCode.str());
    3877             :     return false;
    3878           0 :   }
    3879             : 
    3880             :   // Number of contributing processes.
    3881           0 :   nProc = lhaUpPtr->sizeProc();
    3882             : 
    3883             :   // Loop over all processes. Read out maximum and cross section.
    3884           0 :   xMaxAbsSum = 0.;
    3885           0 :   xSecSgnSum = 0.;
    3886           0 :   int    idPr;
    3887           0 :   double xMax, xSec, xMaxAbs;
    3888           0 :   for (int iProc = 0 ; iProc < nProc; ++iProc) {
    3889           0 :     idPr = lhaUpPtr->idProcess(iProc);
    3890           0 :     xMax = lhaUpPtr->xMax(iProc);
    3891           0 :     xSec = lhaUpPtr->xSec(iProc);
    3892             : 
    3893             :     // Check for inconsistencies between strategy and stored values.
    3894           0 :     if ( (strategy == 1 || strategy == 2) && xMax < 0.) {
    3895           0 :       infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: "
    3896             :         "negative maximum not allowed");
    3897           0 :       return false;
    3898             :     }
    3899           0 :     if ( ( strategy == 2 || strategy == 3) && xSec < 0.) {
    3900           0 :       infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: "
    3901             :         "negative cross section not allowed");
    3902           0 :       return false;
    3903             :     }
    3904             : 
    3905             :     // Store maximal cross sections for later choice.
    3906           0 :     if      (stratAbs == 1) xMaxAbs = abs(xMax);
    3907           0 :     else if (stratAbs  < 4) xMaxAbs = abs(xSec);
    3908           0 :     else                    xMaxAbs = 1.;
    3909           0 :     idProc.push_back( idPr );
    3910           0 :     xMaxAbsProc.push_back( xMaxAbs );
    3911             : 
    3912             :     // Find sum and convert to mb.
    3913           0 :     xMaxAbsSum += xMaxAbs;
    3914           0 :     xSecSgnSum += xSec;
    3915             :   }
    3916           0 :   sigmaMx  = xMaxAbsSum * CONVERTPB2MB;
    3917           0 :   sigmaSgn = xSecSgnSum * CONVERTPB2MB;
    3918             : 
    3919             :   // Done.
    3920           0 :   return true;
    3921             : 
    3922           0 : }
    3923             : 
    3924             : //--------------------------------------------------------------------------
    3925             : 
    3926             : // Construct the next process, by interface to Les Houches class.
    3927             : 
    3928             : bool PhaseSpaceLHA::trialKin( bool, bool repeatSame ) {
    3929             : 
    3930             :   // Must select process type in some cases.
    3931             :   int idProcNow = 0;
    3932           0 :   if (repeatSame) idProcNow = idProcSave;
    3933           0 :   else if (stratAbs <= 2) {
    3934           0 :     double xMaxAbsRndm = xMaxAbsSum * rndmPtr->flat();
    3935             :     int iProc = -1;
    3936           0 :     do    xMaxAbsRndm -= xMaxAbsProc[++iProc];
    3937           0 :     while (xMaxAbsRndm > 0. && iProc < nProc - 1);
    3938           0 :     idProcNow = idProc[iProc];
    3939           0 :   }
    3940             : 
    3941             :   // Generate Les Houches event. Return if fail (= end of file).
    3942           0 :   bool physical = lhaUpPtr->setEvent(idProcNow);
    3943           0 :   if (!physical) return false;
    3944             : 
    3945             :   // Find which process was generated.
    3946           0 :   int    idPr = lhaUpPtr->idProcess();
    3947             :   int    iProc = 0;
    3948           0 :   for (int iP = 0; iP < int(idProc.size()); ++iP)
    3949           0 :     if (idProc[iP] == idPr) iProc = iP;
    3950           0 :   idProcSave = idPr;
    3951             : 
    3952             :   // Extract cross section and rescale according to strategy.
    3953           0 :   double wtPr = lhaUpPtr->weight();
    3954           0 :   if      (stratAbs ==  1) sigmaNw = wtPr * CONVERTPB2MB
    3955           0 :     * xMaxAbsSum / xMaxAbsProc[iProc];
    3956           0 :   else if (stratAbs ==  2) sigmaNw = (wtPr / abs(lhaUpPtr->xMax(iProc)))
    3957           0 :     * sigmaMx;
    3958           0 :   else if (strategy ==  3) sigmaNw = sigmaMx;
    3959           0 :   else if (strategy == -3 && wtPr > 0.) sigmaNw =  sigmaMx;
    3960           0 :   else if (strategy == -3)              sigmaNw = -sigmaMx;
    3961           0 :   else if (stratAbs ==  4) sigmaNw = wtPr * CONVERTPB2MB;
    3962             : 
    3963             :   // Set x scales.
    3964           0 :   x1H = lhaUpPtr->x1();
    3965           0 :   x2H = lhaUpPtr->x2();
    3966             : 
    3967             :   // Done.
    3968             :   return true;
    3969             : 
    3970           0 : }
    3971             : 
    3972             : //==========================================================================
    3973             : 
    3974             : } // end namespace Pythia8

Generated by: LCOV version 1.11