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

          Line data    Source code
       1             : // HadronScatter.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             : #include "Pythia8/HadronScatter.h"
       7             : 
       8             : namespace Pythia8 {
       9             : 
      10             : //==========================================================================
      11             : 
      12             : // The SigmaPartialWave class
      13             : //  Reads in tables of partial wave data to provide dSigma/dCos(theta)
      14             : //  The generic classes of process are:
      15             : //    process = 0 (pi-pi), 1 (pi-K), 2 (pi-N)
      16             : //  Subprocesses are defined (along with isospin coefficients) in:
      17             : //    setupSubprocesses();
      18             : //  Individual subprocesses are selected using:
      19             : //    setSubprocess(subprocess); or setSubprocess(PDG1, PDG2);
      20             : //  Internally, there are two std::map's, to convert between:
      21             : //    subprocess <==> PDG1, PDG2
      22             : //
      23             : //  Data are read in from files:
      24             : //   Lines starting with a '#' are comments
      25             : //   Lines starting with 'set' provide options:
      26             : //    set eType   [Wcm | Tlab] - energy bins in Wcm or Tlab
      27             : //    set eUnit   [MeV | GeV]  - energy unit
      28             : //    set input   [eta,delta | Sn,delta  | Tr,Ti | mod,phi ]
      29             : //                             - format of columns in partial waves
      30             : //    set dUnit   [deg | rad]  - unit of phase shifts
      31             : //    set norm    [0 | 1]      - normalisation
      32             : //   Column headers give L,2I[,2J] (2J for e.g. piN)
      33             : //   Input types: Sn,delta -> Sn = 1 - eta^2
      34             : //                mod,phi  -> amplitude T_L = |T_L| exp(i phi_L)
      35             : //   Normalisation: 0 -> dSigma/dOmega = 1 / k^2 |T_L|^2
      36             : //                  1 -> dSigma/dOmega = 16 / s  |T_L|^2
      37             : //
      38             : //  Internally data is stored as (J = 0 for spinless):
      39             : //   pwData[L * LSHIFT + 2I * ISHIFT + J][energy_bin_centre] = T
      40             : //  where the energy is Wcm in GeV.
      41             : //
      42             : //  This is stored using std::map's, to take into account that not all
      43             : //  L,I,J states are always present (e.g. negligable contributions or
      44             : //  conservation rules) and that bin sizes are not fixed.
      45             : //
      46             : //  Re[T] and Im[T] are interpolated between bins and extrapolated down to
      47             : //  threshold from the first two bins. Above energy_bin_centre of the final
      48             : //  bin, no extrapolation is done and the final bin value is always used.
      49             : //
      50             : //  A simple scheme to provide correct distributions for cos(theta) at a
      51             : //  given CM energy is included. Efficiency is not too bad, but can likely
      52             : //  be greatly improved.
      53             : //
      54             : //  For each subprocess, a grid in bins of Wcm and cos(theta) is setup with:
      55             : //    setupGrid();
      56             : //  The size of the grid is set by the constants:
      57             : //    const double SigmaPartialWave::WCMBIN;
      58             : //    const double SigmaPartialWave::CTBIN;
      59             : //  For each bin of (Wcm, ct), the maximum sigma elastic is found by
      60             : //  splitting this bin into subbins multiple times, controlled by:
      61             : //    const int SigmaPartialWave::SUBBIN;
      62             : //    const int SigmaPartialWave::ITER
      63             : //  With the final maxium sigma elastic given by this value multipled by
      64             : //  a safety factor:
      65             : //    const double SigmaPartialWave::GRIDSAFETY
      66             : //
      67             : //  To pick values of cos(theta) for a given CM energy, a:
      68             : //    pickCosTheta(Wcm);
      69             : //  function is provided. The above grid is used as an overestimate, to
      70             : //  pick properly distributed values of cos(theta).
      71             : 
      72             : //--------------------------------------------------------------------------
      73             : 
      74             : // Constants
      75             : 
      76             : // pwData[L * LSHIFT + 2I * ISHIFT + J]
      77             : const int     SigmaPartialWave::LSHIFT     = 1000000;
      78             : const int     SigmaPartialWave::ISHIFT     = 1000;
      79             : 
      80             : // Convert GeV^-2 to mb
      81             : const double  SigmaPartialWave::CONVERT2MB = 0.389380;
      82             : 
      83             : // Size of bin in Wcm and cos(theta)
      84             : const double  SigmaPartialWave::WCMBIN     = 0.005;
      85             : const double  SigmaPartialWave::CTBIN      = 0.2;
      86             : // Number of subbins and iterations
      87             : const int     SigmaPartialWave::SUBBIN     = 2;
      88             : const int     SigmaPartialWave::ITER       = 2;
      89             : // Safety value to add on to grid maxima
      90             : const double  SigmaPartialWave::MASSSAFETY = 0.001;
      91             : const double  SigmaPartialWave::GRIDSAFETY = 0.05;
      92             : 
      93             : 
      94             : //--------------------------------------------------------------------------
      95             : 
      96             : // Perform initialization and store pointers.
      97             : 
      98             : bool SigmaPartialWave::init(int processIn, string xmlPath, string filename,
      99             :                             Info *infoPtrIn, ParticleData *particleDataPtrIn,
     100             :                             Rndm *rndmPtrIn) {
     101             :   // Store incoming pointers
     102           0 :   infoPtr         = infoPtrIn;
     103           0 :   particleDataPtr = particleDataPtrIn;
     104           0 :   rndmPtr         = rndmPtrIn;
     105             : 
     106             :   // Check incoming process is okay
     107           0 :   if (processIn < 0 || processIn > 2) {
     108           0 :     infoPtr->errorMsg("Error in SigmaPartialWave::init: "
     109             :       "unknown process");
     110           0 :     return false;
     111             :   }
     112           0 :   process = processIn;
     113             : 
     114             :   // Setup subprocesses and isospin coefficients
     115           0 :   setupSubprocesses();
     116           0 :   setSubprocess(0);
     117             : 
     118             :   // Read in partial-wave data
     119           0 :   if (!readFile(xmlPath, filename)) return false;
     120             : 
     121             :   // Setup vector for Legendre polynomials
     122           0 :   PlVec.resize(Lmax);
     123           0 :   if (Lmax > 0) PlVec[0] = 1.;
     124             :   // And derivatives if needed
     125           0 :   if (process == 2) {
     126           0 :     PlpVec.resize(Lmax);
     127           0 :     if (Lmax > 0) PlpVec[0] = 0.;
     128           0 :     if (Lmax > 1) PlpVec[1] = 1.;
     129             :   }
     130             : 
     131             :   // Setup grid for integration
     132           0 :   setupGrid();
     133             : 
     134           0 :   return true;
     135           0 : }
     136             : 
     137             : 
     138             : //--------------------------------------------------------------------------
     139             : 
     140             : // Read input data file
     141             : 
     142             : bool SigmaPartialWave::readFile(string xmlPath, string filename) {
     143             :   // Create full path and open file
     144           0 :   string fullPath = xmlPath + filename;
     145           0 :   ifstream ifs(fullPath.c_str());
     146           0 :   if (!ifs.good()) {
     147           0 :     infoPtr->errorMsg("Error in SigmaPartialWave::init: "
     148             :       "could not read data file");
     149           0 :     return false;
     150             :   }
     151             : 
     152             :   // Default unit settings
     153             :   int eType = 0;  // 0 = Wcm, 1 = Tlab
     154             :   int eUnit = 0;  // 0 = GeV, 1 = MeV
     155             :   int input = 0;  // 0 = eta, delta; 1 = Sn, delta (Sn = 1 - eta^2);
     156             :                   // 2 = Treal, Tim, 3 = mod, phi
     157             :   int dUnit = 0;  // 0 = deg, 1 = rad
     158           0 :       norm  = 0;  // 0 = standard, 1 = sqrt(s) / sqrt(s - 4Mpi^2)
     159             : 
     160             :   // Once we have a header line, each column corresponds to
     161             :   // values of L, I and J.
     162           0 :   Lmax = Imax = 0;
     163           0 :   binMax = 0.;
     164           0 :   vector < int > Lvec, Ivec, Jvec;
     165             : 
     166             :   // Parse the file
     167           0 :   string line;
     168           0 :   while (ifs.good()) {
     169             :     // Get line, convert to lowercase and strip leading whitespace
     170           0 :     getline(ifs, line);
     171           0 :     for (unsigned int i = 0; i < line.length(); i++)
     172           0 :       line[i] = tolower(line[i]);
     173           0 :     string::size_type startPos = line.find_first_not_of("  ");
     174           0 :     if (startPos != string::npos) line = line.substr(startPos);
     175             :     // Skip blank lines and lines that start with '#'
     176           0 :     if (line.length() == 0 || line[0] == '#') continue;
     177             : 
     178             :     // Tokenise line on whitespace (spaces or tabs)
     179           0 :     string lineT = line;
     180           0 :     vector < string > token;
     181           0 :     while (true) {
     182           0 :       startPos = lineT.find_first_of("   ");
     183           0 :       token.push_back(lineT.substr(0, startPos));
     184           0 :       if (startPos == string::npos) break;
     185           0 :       startPos = lineT.find_first_not_of("       ", startPos + 1);
     186           0 :       if (startPos == string::npos) break;
     187           0 :       lineT = lineT.substr(startPos);
     188             :     }
     189             : 
     190             :     // Settings
     191           0 :     if (token[0] == "set") {
     192             :       bool badSetting = false;
     193             : 
     194             :       // eType
     195           0 :       if        (token[1] == "etype") {
     196           0 :         if      (token[2] == "wcm")       eType = 0;
     197           0 :         else if (token[2] == "tlab")      eType = 1;
     198             :         else    badSetting = true;
     199             : 
     200             :       // eUnit
     201           0 :       } else if (token[1] == "eunit") {
     202           0 :         if      (token[2] == "gev")       eUnit = 0;
     203           0 :         else if (token[2] == "mev")       eUnit = 1;
     204             :         else    badSetting = true;
     205             : 
     206             :       // input
     207           0 :       } else if (token[1] == "input") {
     208           0 :         if      (token[2] == "eta,delta") input = 0;
     209           0 :         else if (token[2] == "sn,delta")  input = 1;
     210           0 :         else if (token[2] == "tr,ti")     input = 2;
     211           0 :         else if (token[2] == "mod,phi")   input = 3;
     212             :         else    badSetting = true;
     213             : 
     214             :       // dUnit
     215           0 :       } else if (token[1] == "dunit") {
     216           0 :         if      (token[2] == "deg")       dUnit = 0;
     217           0 :         else if (token[2] == "rad")       dUnit = 1;
     218             :         else    badSetting = true;
     219             : 
     220             :       // norm
     221           0 :       } else if (token[1] == "norm") {
     222           0 :         if      (token[2] == "0")         norm = 0;
     223           0 :         else if (token[2] == "1")         norm = 1;
     224             :         else    badSetting = true;
     225             :       }
     226             : 
     227             :       // Bad setting
     228           0 :       if (badSetting) {
     229           0 :         infoPtr->errorMsg("Error in SigmaPartialWave::init: "
     230             :           "bad setting line");
     231           0 :         return false;
     232             :       }
     233           0 :       continue;
     234             :     }
     235             : 
     236             :     // Header line
     237           0 :     if (line.substr(0, 1).find_first_of("0123456789.") != 0) {
     238             :       // Clear current stored L,2I,2J values
     239           0 :       Lvec.clear(); Ivec.clear(); Jvec.clear();
     240             : 
     241             :       // Parse header
     242             :       bool badHeader = false;
     243           0 :       for (unsigned int i = 1; i < token.size(); i++) {
     244             :         // Extract L
     245           0 :         startPos = token[i].find_first_of(",");
     246           0 :         if (startPos == string::npos) { badHeader = true; break; }
     247           0 :         string Lstr = token[i].substr(0, startPos);
     248           0 :         token[i] = token[i].substr(startPos + 1);
     249             :         // Extract 2I
     250           0 :         string Istr;
     251           0 :         startPos = token[i].find_first_of(",     ");
     252           0 :         if (startPos == string::npos) {
     253           0 :           Istr = token[i];
     254           0 :           token[i] = "";
     255             :         } else {
     256           0 :           Istr = token[i].substr(0, startPos);
     257           0 :           token[i] = token[i].substr(startPos + 1);
     258             :         }
     259             :         // Extract 2J
     260           0 :         string Jstr("0");
     261           0 :         if (token[i].length() != 0) Jstr = token[i];
     262             : 
     263             :         // Convert to integers and store
     264           0 :         int L, I, J;
     265           0 :         stringstream Lss(Lstr); Lss >> L;
     266           0 :         stringstream Iss(Istr); Iss >> I;
     267           0 :         stringstream Jss(Jstr); Jss >> J;
     268           0 :         if (Lss.fail() || Iss.fail() || Jss.fail())
     269           0 :           { badHeader = true; break; }
     270           0 :         Lvec.push_back(L);
     271           0 :         Ivec.push_back(I);
     272           0 :         Jvec.push_back(J);
     273           0 :         Lmax = max(Lmax, L);
     274           0 :         Imax = max(Imax, I);
     275           0 :       }
     276           0 :       if (badHeader) {
     277           0 :         infoPtr->errorMsg("Error in SigmaPartialWave::init: "
     278             :           "malformed header line");
     279           0 :         return false;
     280             :       }
     281             : 
     282             :     // Data line
     283           0 :     } else {
     284             :       bool badData = false;
     285             : 
     286             :       // Check there are the correct number of columns
     287           0 :       if (token.size() != 2 * Lvec.size() + 1) badData = true;
     288             : 
     289             :       // Extract energy
     290           0 :       double eNow = 0.;
     291           0 :       if (!badData) {
     292           0 :         stringstream eSS(token[0]);
     293           0 :         eSS >> eNow;
     294           0 :         if (eSS.fail()) badData = true;
     295             :         // Convert to GeV if needed
     296           0 :         if (eUnit == 1) eNow *= 1e-3;
     297             :         // Convert to Wcm if needed
     298           0 :         if (eType == 1) eNow = sqrt(2. * mB * eNow + pow2(mA + mB));
     299           0 :         binMax = max(binMax, eNow);
     300           0 :       }
     301             : 
     302             :       // Extract eta/phase shifts
     303           0 :       if (!badData) {
     304           0 :         for (unsigned int i = 1; i < token.size(); i += 2) {
     305             :           // L,2I,2J
     306           0 :           int LIJidx = (i - 1) / 2;
     307           0 :           int L = Lvec[LIJidx];
     308           0 :           int I = Ivec[LIJidx];
     309           0 :           int J = Jvec[LIJidx];
     310             : 
     311           0 :           double i1, i2;
     312           0 :           stringstream i1SS(token[i]);     i1SS >> i1;
     313           0 :           stringstream i2SS(token[i + 1]); i2SS >> i2;
     314           0 :           if (i1SS.fail() || i2SS.fail()) { badData = true; break; }
     315             : 
     316             :           // Sn to eta
     317           0 :           if (input == 1) i1 = sqrt(1. - i1);
     318             :           // Degrees to radians
     319           0 :           if ((input == 0 || input == 1 || input == 3) &&
     320           0 :               dUnit == 0) i2 *= M_PI / 180.;
     321             : 
     322             :           // Convert to Treal and Timg
     323           0 :           complex T(0., 0.);
     324           0 :           if (input == 0 || input == 1) {
     325           0 :             T = (i1 * exp(2. * complex(0., 1.) * i2) - 1.) /
     326           0 :                 2. / complex(0., 1.);
     327           0 :           } else if (input == 2) {
     328           0 :             T = complex(i1, i2);
     329           0 :           } else if (input == 3) {
     330           0 :             T = i1 * exp(complex(0., 1.) * i2);
     331           0 :           }
     332             : 
     333             :           // Store
     334           0 :           pwData[L * LSHIFT + I * ISHIFT + J][eNow] = T;
     335           0 :         }
     336           0 :       }
     337           0 :       if (badData) {
     338           0 :         infoPtr->errorMsg("Error in SigmaPartialWave::init: "
     339             :           "malformed data line");
     340           0 :         return false;
     341             :       }
     342           0 :     }
     343           0 :   }
     344             : 
     345             :   // Make sure it was EOF that caused us to end
     346           0 :   if (!ifs.eof()) { ifs.close(); return false; }
     347             : 
     348             :   // Maximum values of L and I
     349           0 :   Lmax++; Imax++;
     350             : 
     351           0 :   return true;
     352           0 : }
     353             : 
     354             : 
     355             : //--------------------------------------------------------------------------
     356             : 
     357             : // Setup isospin coefficients and subprocess mapping
     358             : 
     359             : void SigmaPartialWave::setupSubprocesses() {
     360             : 
     361             :   // Setup isospin coefficients
     362           0 :   switch (process) {
     363             :   // pi-pi
     364             :   case 0:
     365             :     // Map subprocess to incoming
     366           0 :     subprocessMax = 6;
     367           0 :     sp2in[0] = pair < int, int > ( 211,  211);
     368           0 :     sp2in[1] = pair < int, int > ( 211, -211);
     369           0 :     sp2in[2] = pair < int, int > ( 211,  111);
     370           0 :     sp2in[3] = pair < int, int > ( 111,  111);
     371           0 :     sp2in[4] = pair < int, int > (-211,  111);
     372           0 :     sp2in[5] = pair < int, int > (-211, -211);
     373             :     // Incoming to subprocess
     374           0 :     for (int i = 0; i < subprocessMax; i++) in2sp[sp2in[i]] = i;
     375             :     // Isospin coefficients
     376           0 :     isoCoeff[0][0] = 0.;    isoCoeff[0][2] = 0.;    isoCoeff[0][4] = 1.;
     377           0 :     isoCoeff[1][0] = 1./3.; isoCoeff[1][2] = 1./2.; isoCoeff[1][4] = 1./6.;
     378           0 :     isoCoeff[2][0] = 0.;    isoCoeff[2][2] = 1./2.; isoCoeff[2][4] = 1./2.;
     379           0 :     isoCoeff[3][0] = 1./3.; isoCoeff[3][2] = 0.;    isoCoeff[3][4] = 2./3.;
     380           0 :     isoCoeff[4][0] = 0.;    isoCoeff[4][2] = 1./2.; isoCoeff[4][4] = 1./2.;
     381           0 :     isoCoeff[5][0] = 0.;    isoCoeff[5][2] = 0.;    isoCoeff[5][4] = 1.;
     382             : 
     383           0 :     break;
     384             : 
     385             :   // pi-K and pi-N
     386             :   case 1: case 2:
     387           0 :     int id1, id2;
     388           0 :     if (process == 1) { id1 = 321;  id2 = 311;  }
     389           0 :     else              { id1 = 2212; id2 = 2112; }
     390             : 
     391             :     // Map subprocess to incoming
     392           0 :     subprocessMax = 12;
     393           0 :     sp2in[0] = pair < int, int > ( 211, id1);
     394           0 :     sp2in[1] = pair < int, int > ( 211, id2);
     395           0 :     sp2in[2] = pair < int, int > ( 111, id1);
     396           0 :     sp2in[3] = pair < int, int > ( 111, id2);
     397           0 :     sp2in[4] = pair < int, int > (-211, id1);
     398           0 :     sp2in[5] = pair < int, int > (-211, id2);
     399             :     // Isospin coefficients
     400           0 :     isoCoeff[0][1]  = 0.;      isoCoeff[0][3]  = 1.;
     401           0 :     isoCoeff[1][1]  = 2. / 3.; isoCoeff[1][3]  = 1. / 3.;
     402           0 :     isoCoeff[2][1]  = 1. / 3.; isoCoeff[2][3]  = 2. / 3.;
     403           0 :     isoCoeff[3][1]  = 1. / 3.; isoCoeff[3][3]  = 2. / 3.;
     404           0 :     isoCoeff[4][1]  = 2. / 3.; isoCoeff[4][3]  = 1. / 3.;
     405           0 :     isoCoeff[5][1]  = 0.;      isoCoeff[5][3]  = 1.;
     406             :     // Antiparticles
     407           0 :     for (int i = 0; i < 6; i++) {
     408           0 :       id1 = ((sp2in[i].first == 111) ? +1 : -1) * sp2in[i].first;
     409           0 :       sp2in[i + 6] = pair < int, int > (id1, -sp2in[i].second);
     410           0 :       isoCoeff[i + 6] = isoCoeff[i];
     411             :     }
     412             :     // Map incoming to subprocess
     413           0 :     for (int i = 0; i < subprocessMax; i++) in2sp[sp2in[i]] = i;
     414             : 
     415             :     break;
     416           0 :   }
     417             : 
     418           0 :   return;
     419             : }
     420             : 
     421             : 
     422             : //--------------------------------------------------------------------------
     423             : 
     424             : // Setup grids for integration
     425             : 
     426             : void SigmaPartialWave::setupGrid() {
     427             :   // Reset sigma maximum
     428           0 :   sigElMax = 0.;
     429             : 
     430             :   // Go through each subprocess
     431           0 :   gridMax.resize(subprocessMax);
     432           0 :   gridNorm.resize(subprocessMax);
     433           0 :   for (int sp = 0; sp < subprocessMax; sp++) {
     434             :     // Setup subprocess
     435           0 :     setSubprocess(sp);
     436             : 
     437             :     // Bins in Wcm
     438           0 :     int nBin1 = int( (binMax - mA - mB) / WCMBIN );
     439           0 :     gridMax[subprocess].resize(nBin1);
     440           0 :     gridNorm[subprocess].resize(nBin1);
     441           0 :     for (int n1 = 0; n1 < nBin1; n1++) {
     442             :       // Bin lower and upper
     443           0 :       double bl1 = mA + mB + double(n1) * WCMBIN;
     444           0 :       double bu1 = bl1 + WCMBIN;
     445             : 
     446             :       // Bins in cos(theta)
     447             :       int    nBin2 = int( 2. / CTBIN );
     448           0 :       gridMax[subprocess][n1].resize(nBin2);
     449           0 :       for (int n2 = 0; n2 < nBin2; n2++) {
     450             :         // Bin lower and upper
     451           0 :         double bl2 = -1. + double(n2) * CTBIN;
     452           0 :         double bu2 = bl2 + CTBIN;
     453             : 
     454             :         // Find maximum
     455           0 :         double maxSig = 0.;
     456             :         double bl3 = bl1, bu3 = bu1, bl4 = bl2, bu4 = bu2;
     457           0 :         for (int iter = 0; iter < ITER; iter++) {
     458             :           int    i3Save = -1, i4Save = -1;
     459           0 :           double step3 = (bu3 - bl3) / double(SUBBIN);
     460           0 :           double step4 = (bu4 - bl4) / double(SUBBIN);
     461           0 :           for (int i3 = 0; i3 <= SUBBIN; i3++) {
     462           0 :             double Wcm = bl3 + double(i3) * step3;
     463           0 :             for (int i4 = 0; i4 <= SUBBIN; i4++) {
     464           0 :               double ct = bl4 + double(i4) * step4;
     465           0 :               double ds = dSigma(Wcm, ct);
     466           0 :               if (ds > maxSig) {
     467             :                 i3Save = i3;
     468             :                 i4Save = i4;
     469           0 :                 maxSig = ds;
     470           0 :               }
     471             :             }
     472             :           }
     473             :           // Set new min/max
     474           0 :           if (i3Save == -1 && i4Save == -1) break;
     475           0 :           if (i3Save > -1) {
     476           0 :             bl3 = bl3 + ((i3Save == 0)      ? 0. : i3Save - 1.) * step3;
     477           0 :             bu3 = bl3 + ((i3Save == SUBBIN) ? 1. : 2.)          * step3;
     478           0 :           }
     479           0 :           if (i4Save > -1) {
     480           0 :             bl4 = bl4 + ((i4Save == 0)      ? 0. : i4Save - 1.) * step4;
     481           0 :             bu4 = bl4 + ((i4Save == SUBBIN) ? 1. : 2.)          * step4;
     482           0 :           }
     483           0 :         } // for (iter)
     484             : 
     485             :         // Save maximum value
     486           0 :         gridMax[subprocess][n1][n2]  = maxSig * (1. + GRIDSAFETY);
     487           0 :         gridNorm[subprocess][n1]    += maxSig * (1. + GRIDSAFETY) * CTBIN;
     488           0 :         sigElMax = max(sigElMax, maxSig);
     489             : 
     490           0 :       } // for (n2)
     491             :     } // for (n1)
     492             :   } // for (sp)
     493             : 
     494           0 :   return;
     495             : }
     496             : 
     497             : 
     498             : //--------------------------------------------------------------------------
     499             : 
     500             : // Pick a cos(theta) value
     501             : 
     502             : double SigmaPartialWave::pickCosTheta(double Wcm) {
     503             :   // Find grid bin in Wcm
     504           0 :   int WcmBin = int((Wcm - mA - mB) / WCMBIN);
     505           0 :   if (WcmBin < 0) WcmBin = 0;
     506           0 :   if (WcmBin >= int(gridMax[subprocess].size()))
     507           0 :     WcmBin = int(gridMax[subprocess].size() - 1);
     508             : 
     509             :   // Pick a value of cos(theta)
     510             :   double ct, wgt;
     511             : 
     512           0 :   do {
     513             :     // Sample from overestimate and inverse
     514           0 :     double y   = rndmPtr->flat() * gridNorm[subprocess][WcmBin];
     515             :     double sum = 0.;
     516             :     int    ctBin;
     517           0 :     for (ctBin = 0; ctBin < int(2. / CTBIN); ctBin++) {
     518           0 :       if (sum + CTBIN * gridMax[subprocess][WcmBin][ctBin] > y) break;
     519           0 :       sum += CTBIN * gridMax[subprocess][WcmBin][ctBin];
     520             :     }
     521             : 
     522             :     // Linear interpolation
     523           0 :     double x1 = -1. + CTBIN * double(ctBin);
     524             :     double y1 = sum;
     525           0 :     double x2 = x1 + CTBIN;
     526           0 :     double y2 = sum + CTBIN * gridMax[subprocess][WcmBin][ctBin];
     527           0 :            ct = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
     528           0 :     wgt = dSigma(Wcm, ct) / gridMax[subprocess][WcmBin][ctBin];
     529           0 :     if (wgt >= 1.) {
     530           0 :       infoPtr->errorMsg("Warning in SigmaPartialWave::pickCosTheta: "
     531             :         "weight above unity");
     532           0 :       break;
     533             :     }
     534           0 :   } while (wgt <= rndmPtr->flat());
     535             : 
     536           0 :   return ct;
     537           0 : }
     538             : 
     539             : //--------------------------------------------------------------------------
     540             : 
     541             : // Set subprocess
     542             : 
     543             : bool SigmaPartialWave::setSubprocess(int spIn) {
     544           0 :   if (sp2in.find(spIn) == sp2in.end()) return false;
     545           0 :   subprocess = spIn;
     546           0 :   pair < int, int > in = sp2in[spIn];
     547           0 :   idA = in.first;
     548           0 :   mA  = particleDataPtr->m0(idA);
     549           0 :   idB = in.second;
     550           0 :   mB  = particleDataPtr->m0(idB);
     551             :   return true;
     552           0 : }
     553             : 
     554             : bool SigmaPartialWave::setSubprocess(int idAin, int idBin) {
     555           0 :   pair < int, int > in = pair < int, int > (idAin, idBin);
     556           0 :   if (in2sp.find(in) == in2sp.end()) {
     557             :     // Try the other way around as well
     558           0 :     swap(in.first, in.second);
     559           0 :     if (in2sp.find(in) == in2sp.end()) return false;
     560             :   }
     561           0 :   subprocess = in2sp[in];
     562           0 :   idA = idAin;
     563           0 :   mA  = particleDataPtr->m0(idA);
     564           0 :   idB = idBin;
     565           0 :   mB  = particleDataPtr->m0(idB);
     566           0 :   return true;
     567           0 : }
     568             : 
     569             : //--------------------------------------------------------------------------
     570             : 
     571             : // Calculate: mode = 0 (sigma elastic), 1 (sigma total), 2 (dSigma/dcTheta)
     572             : 
     573             : double SigmaPartialWave::sigma(int mode, double Wcm, double cTheta) {
     574             :   // Below threshold, return 0
     575           0 :   if (Wcm < (mA + mB + MASSSAFETY)) return 0.;
     576             : 
     577             :   // Return values
     578           0 :   complex amp[2] = { complex(0., 0.) };
     579             :   double  sig    = 0.;
     580             : 
     581             :   // Kinematic variables
     582           0 :   double s  = pow2(Wcm);
     583           0 :   double k2 = (s - pow2(mB + mA)) * (s - pow2(mB - mA)) / 4. / s;
     584             : 
     585             :   // Precompute all required Pl and Pl' values
     586           0 :   double sTheta = 0.;
     587           0 :   if (mode == 2) {
     588           0 :     if (process == 2) sTheta = sqrt(1. - pow2(cTheta));
     589           0 :     legendreP(cTheta, ((process == 2) ? true : false));
     590           0 :   }
     591             : 
     592             :   // Loop over L
     593           0 :   for (int L = 0; L < Lmax; L++) {
     594             : 
     595             :     // Loop over J (only J = 0 for spinless)
     596           0 :     complex ampJ[2] = { complex(0., 0.) };
     597           0 :     int Jstart = (process != 2) ? 0 : 2 * L - 1;
     598           0 :     int Jend   = (process != 2) ? 1 : 2 * L + 2;
     599           0 :     int Jstep  = (process != 2) ? 1 : 2;
     600             :     int Jcount = 0;
     601           0 :     for (int J = Jstart; J < Jend; J += Jstep, Jcount++) {
     602             : 
     603             :       // Loop over isospin coefficients
     604           0 :       for (int I = 0; I < Imax; I++) {
     605           0 :         if (isoCoeff[subprocess][I] == 0.) continue;
     606             : 
     607             :         // Check wave exists
     608           0 :         int LIJ = L * LSHIFT + I * ISHIFT + J;
     609           0 :         if (pwData.find(LIJ) == pwData.end()) continue;
     610             : 
     611             :         // Extrapolation / interpolation (not for last bin)
     612           0 :         map < double, complex >::iterator it = pwData[LIJ].upper_bound(Wcm);
     613           0 :         if (it == pwData[LIJ].begin()) ++it;
     614             :         double ar, ai;
     615           0 :         if (it == pwData[LIJ].end()) {
     616           0 :           ar = (--it)->second.real();
     617           0 :           ai = it->second.imag();
     618           0 :         } else {
     619           0 :           double  eA   = it->first;
     620           0 :           complex ampA = (it--)->second;
     621           0 :           double  eB   = it->first;
     622           0 :           complex ampB = it->second;
     623             : 
     624           0 :           ar = (ampA.real() - ampB.real()) / (eA - eB) *
     625           0 :                (Wcm - eB) + ampB.real();
     626           0 :           ai = (ampA.imag() - ampB.imag()) / (eA - eB) *
     627           0 :                (Wcm - eB) + ampB.imag();
     628           0 :         }
     629             : 
     630             :         // Isospin sum
     631           0 :         ampJ[Jcount] += isoCoeff[subprocess][I] * complex(ar, ai);
     632           0 :       }
     633             :     }
     634             : 
     635             :     // Partial wave sum. Sigma elastic
     636           0 :     if (mode == 0) {
     637           0 :       if        (process == 0 || process == 1) {
     638           0 :         sig += (2. * L + 1.) * (ampJ[0] * conj(ampJ[0])).real();
     639           0 :       } else if (process == 2) {
     640           0 :         sig += ( (L + 0.) * (ampJ[0] * conj(ampJ[0])).real() +
     641           0 :                  (L + 1.) * (ampJ[1] * conj(ampJ[1])).real() );
     642           0 :       }
     643             : 
     644             :     // Sigma total
     645           0 :     } else if (mode == 1) {
     646           0 :       if        (process == 0 || process == 1) {
     647           0 :         sig += (2. * L + 1.) * ampJ[0].imag();
     648           0 :       } else if (process == 2) {
     649           0 :         sig += ( (L + 0.) * ampJ[0].imag() + (L + 1.) * ampJ[1].imag() );
     650           0 :       }
     651             : 
     652             :     // dSigma
     653           0 :     } else if (mode == 2) {
     654           0 :       if        (process == 0 || process == 1) {
     655           0 :         amp[0] += (2. * L + 1.) * ampJ[0] * PlVec[L];
     656           0 :       } else if (process == 2) {
     657           0 :         amp[0] += ((L + 0.) * ampJ[0] + double(L + 1.) * ampJ[1]) * PlVec[L];
     658           0 :         amp[1] += complex(0., 1.) * (ampJ[1] - ampJ[0]) * sTheta * PlpVec[L];
     659           0 :       }
     660             :     }
     661             : 
     662           0 :   } // for (L)
     663             : 
     664             :   // Normalisation and return
     665           0 :   if (mode == 0 || mode == 1) {
     666           0 :     if      (norm == 0)  sig *= 4.  * M_PI / k2 * CONVERT2MB;
     667           0 :     else if (norm == 1)  sig *= 64. * M_PI / s  * CONVERT2MB;
     668             : 
     669           0 :   } else if (mode == 2) {
     670           0 :     sig = (amp[0] * conj(amp[0])).real() + (amp[1] * conj(amp[1])).real();
     671           0 :     if      (norm == 0) sig *= 2.  * M_PI / k2 * CONVERT2MB;
     672           0 :     else if (norm == 1) sig *= 32. * M_PI / s  * CONVERT2MB;
     673             :   }
     674             :   // Half for identical
     675           0 :   return ((idA == idB) ? 0.5 : 1.) * sig;
     676           0 : }
     677             : 
     678             : 
     679             : //--------------------------------------------------------------------------
     680             : 
     681             : // Bonnet's recursion formula for Legendre polynomials and derivatives
     682             : 
     683             : void SigmaPartialWave::legendreP(double ct, bool deriv) {
     684           0 :   if (Lmax > 1) PlVec[1] = ct;
     685           0 :   for (int L = 2; L < Lmax; L++) {
     686           0 :     PlVec[L] = ( (2. * L - 1.) * ct * PlVec[L - 1] -
     687           0 :                  (L - 1.) * PlVec[L - 2] ) / double(L);
     688           0 :     if (deriv)
     689           0 :       PlpVec[L] = ( (2. * L - 1.) * (PlVec[L - 1] + ct * PlpVec[L - 1]) -
     690           0 :                     (L - 1.) * PlpVec[L - 2] ) / double(L);
     691             :   }
     692           0 :   return;
     693             : }
     694             : 
     695             : 
     696             : //==========================================================================
     697             : 
     698             : // HadronScatter class
     699             : 
     700             : //--------------------------------------------------------------------------
     701             : 
     702             : // Perform initialization and store pointers.
     703             : 
     704             : bool HadronScatter::init(Info* infoPtrIn, Settings& settings,
     705             :                          Rndm *rndmPtrIn, ParticleData *particleDataPtr) {
     706             :   // Save incoming pointers
     707           0 :   infoPtr = infoPtrIn;
     708           0 :   rndmPtr = rndmPtrIn;
     709             : 
     710             :   // Main settings
     711           0 :   doHadronScatter = settings.flag("HadronScatter:scatter");
     712           0 :   afterDecay      = settings.flag("HadronScatter:afterDecay");
     713           0 :   allowDecayProd  = settings.flag("HadronScatter:allowDecayProd");
     714           0 :   scatterRepeat   = settings.flag("HadronScatter:scatterRepeat");
     715             :   // Hadron selection
     716           0 :   hadronSelect    = settings.mode("HadronScatter:hadronSelect");
     717           0 :   Npar            = settings.parm("HadronScatter:N");
     718           0 :   kPar            = settings.parm("HadronScatter:k");
     719           0 :   pPar            = settings.parm("HadronScatter:p");
     720             :   // Scattering probability
     721           0 :   scatterProb     = settings.mode("HadronScatter:scatterProb");
     722           0 :   jPar            = settings.parm("HadronScatter:j");
     723           0 :   rMax            = settings.parm("HadronScatter:rMax");
     724           0 :   rMax2           = rMax * rMax;
     725           0 :   doTile          = settings.flag("HadronScatter:tile");
     726             : 
     727             :   // String fragmentation and MPI settings
     728           0 :   pTsigma         = 2.0 * settings.parm("StringPT:sigma");
     729           0 :   pTsigma2        = pTsigma * pTsigma;
     730           0 :   double pT0ref   = settings.parm("MultipartonInteractions:pT0ref");
     731           0 :   double eCMref   = settings.parm("MultipartonInteractions:eCMref");
     732           0 :   double eCMpow   = settings.parm("MultipartonInteractions:eCMpow");
     733           0 :   double eCMnow   = infoPtr->eCM();
     734           0 :   pT0MPI          = pT0ref * pow(eCMnow / eCMref, eCMpow);
     735             : 
     736             :   // Tiling
     737           0 :   double mp2 = particleDataPtr->m0(111) * particleDataPtr->m0(111);
     738           0 :   double eA  = infoPtr->eA();
     739           0 :   double eB  = infoPtr->eB();
     740           0 :   double pzA =  sqrt(eA * eA - mp2);
     741           0 :   double pzB = -sqrt(eB * eB - mp2);
     742           0 :   yMax = 0.5 * log((eA + pzA) / (eA - pzA));
     743           0 :   yMin = 0.5 * log((eB + pzB) / (eB - pzB));
     744             :   // Size in y and phi
     745           0 :   if (doTile) {
     746           0 :     ytMax  = int((yMax - yMin) / rMax);
     747           0 :     ytSize = (yMax - yMin) / double(ytMax);
     748           0 :     ptMax  = int(2. * M_PI / rMax);
     749           0 :     ptSize = 2. * M_PI / double(ptMax);
     750           0 :   } else {
     751           0 :     ytMax  = 1;
     752           0 :     ytSize = yMax - yMin;
     753           0 :     ptMax  = 1;
     754           0 :     ptSize = 2. * M_PI;
     755             :   }
     756             :   // Initialise tiles
     757           0 :   tile.resize(ytMax);
     758           0 :   for (int yt = 0; yt < ytMax; yt++) tile[yt].resize(ptMax);
     759             : 
     760             :   // Find path to data files, i.e. xmldoc directory location.
     761             :   // Environment variable takes precedence, else use constructor input.
     762             :   // XXX - as in Pythia.cc, but not passed around in e.g. Info/Settings,
     763             :   //       so redo here
     764           0 :   string xmlPath = "";
     765             :   const char* PYTHIA8DATA = "PYTHIA8DATA";
     766           0 :   char* envPath = getenv(PYTHIA8DATA);
     767           0 :   if (envPath != 0 && *envPath != '\0') {
     768             :     int i = 0;
     769           0 :     while (*(envPath+i) != '\0') xmlPath += *(envPath+(i++));
     770           0 :   } else xmlPath = "../xmldoc";
     771           0 :   if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
     772             : 
     773             :   // Hadron scattering partial wave cross sections
     774           0 :   if ( !sigmaPW[0].init(0, xmlPath, "pipi-Froggatt.dat",
     775           0 :                         infoPtr, particleDataPtr, rndmPtr) ) return false;
     776           0 :   if ( !sigmaPW[1].init(1, xmlPath, "piK-Estabrooks.dat",
     777           0 :                         infoPtr, particleDataPtr, rndmPtr) ) return false;
     778           0 :   if ( !sigmaPW[2].init(2, xmlPath, "piN-SAID-WI08.dat",
     779           0 :                         infoPtr, particleDataPtr, rndmPtr) ) return false;
     780           0 :   sigElMax = 0.;
     781           0 :   sigElMax = max(sigElMax, sigmaPW[0].getSigmaElMax());
     782           0 :   sigElMax = max(sigElMax, sigmaPW[1].getSigmaElMax());
     783           0 :   sigElMax = max(sigElMax, sigmaPW[2].getSigmaElMax());
     784             : 
     785             :   // DEBUG
     786           0 :   debugOutput();
     787             : 
     788           0 :   return true;
     789           0 : }
     790             : 
     791             : 
     792             : //--------------------------------------------------------------------------
     793             : 
     794             : // Debug output
     795             : 
     796             : void HadronScatter::debugOutput() {
     797             :   // Print settings
     798           0 :   cout << "Hadron scattering:" << endl
     799           0 :        << " scatter        = " << ((doHadronScatter) ? "on" : "off") << endl
     800           0 :        << " afterDecay     = " << ((afterDecay)      ? "on" : "off") << endl
     801           0 :        << " allowDecayProd = " << ((allowDecayProd)  ? "on" : "off") << endl
     802           0 :        << " scatterRepeat  = " << ((scatterRepeat)   ? "on" : "off") << endl
     803           0 :        << " tile           = " << ((doTile) ? "on" : "off") << endl
     804           0 :        << "  yMin          = " << yMin << endl
     805           0 :        << "  yMax          = " << yMax << endl
     806           0 :        << "  ytMax         = " << ytMax << endl
     807           0 :        << "  ytSize        = " << ytSize << endl
     808           0 :        << "  ptMax         = " << ptMax << endl
     809           0 :        << "  ptSize        = " << ptSize << endl
     810           0 :        << endl
     811           0 :        << " hadronSelect   = " << hadronSelect << endl
     812           0 :        << "  N             = " << Npar << endl
     813           0 :        << "  k             = " << kPar << endl
     814           0 :        << "  p             = " << pPar << endl
     815           0 :        << endl
     816           0 :        << " scatterProb    = " << scatterProb << endl
     817           0 :        << "  j             = " << jPar << endl
     818           0 :        << "  rMax          = " << rMax << endl
     819           0 :        << endl
     820           0 :        << " pTsigma        = " << pTsigma2 << endl
     821           0 :        << " pT0MPI         = " << pT0MPI << endl
     822           0 :        << endl
     823           0 :        << " sigElMax       = " << sigElMax << endl << endl;
     824             : 
     825           0 :   return;
     826             : }
     827             : 
     828             : 
     829             : //--------------------------------------------------------------------------
     830             : 
     831             : // Perform hadron scattering
     832             : 
     833             : void HadronScatter::scatter(Event& event) {
     834             :   // Reset tiles
     835           0 :   for (int yt = 0; yt < ytMax; yt++)
     836           0 :     for (int pt = 0; pt < ptMax; pt++)
     837           0 :       tile[yt][pt].clear();
     838             : 
     839             :   // Generate list of hadrons which can take part in the scattering
     840           0 :   for (int i = 0; i < event.size(); i++)
     841           0 :     if (event[i].isFinal() && event[i].isHadron() && canScatter(event, i))
     842           0 :       tile[yTile(event, i)][pTile(event, i)].insert(HSIndex(i, i));
     843             : 
     844             :   // Generate all pairwise interaction probabilities
     845           0 :   vector < HadronScatterPair > scatterList;
     846             :   // For each tile and for each hadron in the tile do pairing
     847           0 :   for (int pt1 = 0; pt1 < ptMax; pt1++)
     848           0 :     for (int yt1 = 0; yt1 < ytMax; yt1++)
     849           0 :       for (set < HSIndex >::iterator si1 = tile[yt1][pt1].begin();
     850           0 :            si1 != tile[yt1][pt1].end(); si1++)
     851           0 :         tileIntProb(scatterList, event, *si1, yt1, pt1, false);
     852             :   // Sort by ordering measure (largest to smallest)
     853           0 :   sort(scatterList.rbegin(), scatterList.rend());
     854             : 
     855             :   // Reset list of things that have scattered
     856           0 :   if (scatterRepeat) scattered.clear();
     857             : 
     858             :   // Do scatterings
     859           0 :   while (scatterList.size() > 0) {
     860             :     // Check still valid and scatter
     861           0 :     HadronScatterPair &hsp = scatterList[0];
     862           0 :     if (!event[hsp.i1.second].isFinal() || !event[hsp.i2.second].isFinal()) {
     863           0 :       scatterList.erase(scatterList.begin());
     864           0 :       continue;
     865             :     }
     866             :     // Remove old entries in tiles and scatter
     867           0 :     tile[hsp.yt1][hsp.pt1].erase(hsp.i1);
     868           0 :     tile[hsp.yt2][hsp.pt2].erase(hsp.i2);
     869           0 :     hadronScatter(event, hsp);
     870             :     // Store new indices for later
     871           0 :     HSIndex iNew1 = hsp.i1, iNew2 = hsp.i2;
     872             : 
     873             :     // Check if hadrons can scatter again
     874             :     bool resort = false;
     875           0 :     if (scatterRepeat) {
     876             :       // Check for new scatters of iNew1 and iNew2
     877           0 :       HSIndex iNew = iNew1;
     878           0 :       for (int i = 0; i < 2; i++) {
     879           0 :         if (canScatter(event, iNew.second)) {
     880             :           // If both can scatter again, make sure they can't scatter
     881             :           // with each other
     882           0 :           if (i == 1) scattered.insert(HSIndex(min(iNew1.first, iNew2.first),
     883           0 :                                              max(iNew1.first, iNew2.first)));
     884           0 :           int yt = yTile(event, iNew.second);
     885           0 :           int pt = pTile(event, iNew.second);
     886           0 :           resort = tileIntProb(scatterList, event, iNew, yt, pt, true);
     887           0 :           tile[yt][pt].insert(iNew);
     888           0 :         }
     889           0 :         iNew = iNew2;
     890             :       } // for (i)
     891             : 
     892           0 :     } // if (scatterRepeat)
     893             : 
     894             :     // Remove the old entry and onto next
     895           0 :     scatterList.erase(scatterList.begin());
     896             :     // Resort list if anything added
     897           0 :     if (resort) sort(scatterList.rbegin(), scatterList.rend());
     898             : 
     899           0 :   } // while (scatterList.size() > 0)
     900             : 
     901             :   // Done.
     902             :   return;
     903           0 : }
     904             : 
     905             : 
     906             : //--------------------------------------------------------------------------
     907             : 
     908             : // Criteria for if a hadron is allowed to scatter or not
     909             : 
     910             : bool HadronScatter::canScatter(Event& event, int i) {
     911             :   // Probability to accept
     912             :   double p = 0.;
     913             : 
     914             :   // Pions, K+, K-, p+, pbar- only
     915           0 :   if (scatterProb == 1 || scatterProb == 2)
     916           0 :     if (event[i].idAbs() != 111 && event[i].idAbs() != 211 &&
     917           0 :         event[i].idAbs() != 321 && event[i].idAbs() != 2212)
     918           0 :       return false;
     919             : 
     920             :   // Probability
     921           0 :   switch (hadronSelect) {
     922             :   case 0:
     923           0 :     double t1 = exp( - event[i].pT2() / 2. / pTsigma2);
     924           0 :     double t2 = pow(pT0MPI, pPar) /
     925           0 :                 pow(pT0MPI * pT0MPI + event[i].pT2(), pPar / 2.);
     926           0 :     p = Npar * t1 / ( (1 - kPar) * t1 + kPar * t2 );
     927             :     break;
     928             :   }
     929             : 
     930             :   // Return true/false
     931           0 :   if (p > rndmPtr->flat()) return true;
     932           0 :   else                     return false;
     933           0 : }
     934             : 
     935             : 
     936             : //--------------------------------------------------------------------------
     937             : 
     938             : // Probability for scattering
     939             : bool HadronScatter::doesScatter(Event& event, const HSIndex &i1,
     940             :   const HSIndex &i2) {
     941           0 :   Particle &p1 = event[i1.second];
     942           0 :   Particle &p2 = event[i2.second];
     943             : 
     944             :   // Can't come from the same decay
     945           0 :   if (!allowDecayProd && event[i1.first].mother1() ==
     946           0 :       event[i2.first].mother1() && event[event[i1.first].mother1()].isHadron())
     947           0 :     return false;
     948             : 
     949             :   // Check that the two hadrons have not already scattered
     950           0 :   if (scatterRepeat &&
     951           0 :       scattered.find(HSIndex(min(i1.first, i2.first), max(i1.first, i2.first)))
     952           0 :       != scattered.end()) return false;
     953             : 
     954             :   // K-K, p-p and K-p not allowed
     955           0 :   int id1 = min(p1.idAbs(), p2.idAbs());
     956           0 :   int id2 = max(p1.idAbs(), p2.idAbs());
     957           0 :   if (scatterProb == 1 || scatterProb == 2) {
     958           0 :     if ((id1 == 321 || id1 == 2212) && id1 == id2) return false;
     959           0 :     if (id1 == 321 && id2 == 2212)                 return false;
     960             :   }
     961             : 
     962             :   // Distance in y - phi space
     963           0 :   double dy  = p1.y() - p2.y();
     964           0 :   double dp  = abs(p1.phi() - p2.phi());
     965           0 :   if (dp > M_PI) dp = 2 * M_PI - dp;
     966           0 :   double dr2 = dy * dy + dp * dp;
     967           0 :   double p   = max(0., 1. - dr2 / rMax2);
     968             : 
     969             :   // Additional factor depending on scatterProb
     970           0 :   if (scatterProb == 0 || scatterProb == 1) {
     971           0 :     p *= jPar;
     972             : 
     973             :   // Additional pair dependent probability
     974           0 :   } else if (scatterProb == 2) {
     975             :     // Wcm and which partial wave amplitude to use
     976           0 :     double Wcm = (p1.p() + p2.p()).mCalc();
     977             :     int    pw = 0;
     978           0 :     if      ((id1 == 111 || id1 == 211) && (id2 == 111 || id2 == 211)) pw = 0;
     979           0 :     else if ((id1 == 111 || id1 == 211) && id2 == 321)                 pw = 1;
     980           0 :     else if ((id1 == 111 || id1 == 211) && id2 == 2212)                pw = 2;
     981             :     else {
     982           0 :       infoPtr->errorMsg("Error in HadronScatter::doesScatter:"
     983             :         "unknown subprocess");
     984             :     }
     985           0 :     if (!sigmaPW[pw].setSubprocess(p1.id(), p2.id())) {
     986           0 :       infoPtr->errorMsg("Error in HadronScatter::doesScatter:"
     987             :         "setSubprocess failed");
     988           0 :     } else {
     989           0 :       p *= 1 - exp(-jPar * sigmaPW[pw].sigmaEl(Wcm));
     990             :     }
     991           0 :   }
     992             : 
     993             :   // Return true/false
     994           0 :   return (p > rndmPtr->flat());
     995           0 : }
     996             : 
     997             : 
     998             : //--------------------------------------------------------------------------
     999             : 
    1000             : // Calculate ordering measure
    1001             : 
    1002             : double HadronScatter::measure(Event& event, int idx1, int idx2) {
    1003           0 :   Particle &p1 = event[idx1];
    1004           0 :   Particle &p2 = event[idx2];
    1005           0 :   return abs(p1.pT() / p1.mT() - p2.pT() / p2.mT());
    1006             : }
    1007             : 
    1008             : 
    1009             : //--------------------------------------------------------------------------
    1010             : 
    1011             : // Scatter a pair
    1012             : 
    1013             : bool HadronScatter::hadronScatter(Event& event, HadronScatterPair &hsp) {
    1014           0 :   bool doSwap = (0.5 < rndmPtr->flat()) ? true : false;
    1015           0 :   if (doSwap) swap(hsp.i1, hsp.i2);
    1016             : 
    1017           0 :   Particle &p1 = event[hsp.i1.second];
    1018           0 :   Particle &p2 = event[hsp.i2.second];
    1019             : 
    1020             :   // Pick theta and phi (always flat)
    1021           0 :   double ct = 0., phi = 2 * M_PI * rndmPtr->flat();
    1022             : 
    1023             :   // Flat for all flavours
    1024           0 :   if (scatterProb == 0 || scatterProb == 1) {
    1025           0 :     ct  = 2. * rndmPtr->flat() - 1.;
    1026             : 
    1027             :   // pi-pi, pi-K and pi-p only using partial wave amplitudes
    1028           0 :   } else if (scatterProb == 2) {
    1029             :     // Wcm and which partial wave amplitude to use
    1030           0 :     int    id1 = min(p1.idAbs(), p2.idAbs());
    1031           0 :     int    id2 = max(p1.idAbs(), p2.idAbs());
    1032           0 :     double Wcm = (p1.p() + p2.p()).mCalc();
    1033             :     int    pw  = 0;
    1034           0 :     if      ((id1 == 111 || id1 == 211) && (id2 == 111 || id2 == 211)) pw = 0;
    1035           0 :     else if ((id1 == 111 || id1 == 211) && id2 == 321)                 pw = 1;
    1036           0 :     else if ((id1 == 111 || id1 == 211) && id2 == 2212)                pw = 2;
    1037             :     else {
    1038           0 :       infoPtr->errorMsg("Error in HadronScatter::hadronScatter:"
    1039             :         "unknown subprocess");
    1040             :     }
    1041           0 :     sigmaPW[pw].setSubprocess(p1.id(), p2.id());
    1042           0 :     ct = sigmaPW[pw].pickCosTheta(Wcm);
    1043           0 :   }
    1044             : 
    1045             :   // Rotation
    1046           0 :   RotBstMatrix sMat;
    1047           0 :   sMat.toCMframe(p1.p(), p2.p());
    1048           0 :   sMat.rot(acos(ct), phi);
    1049           0 :   sMat.fromCMframe(p1.p(), p2.p());
    1050           0 :   Vec4 v1 = p1.p(), v2 = p2.p();
    1051           0 :   v1.rotbst(sMat);
    1052           0 :   v2.rotbst(sMat);
    1053             : 
    1054             :   // Update event record
    1055           0 :   int iNew1 = event.copy(hsp.i1.second, 98);
    1056           0 :   event[iNew1].p(v1);
    1057           0 :   event[iNew1].e(event[iNew1].eCalc());
    1058           0 :   event[hsp.i1.second].statusNeg();
    1059           0 :   int iNew2 = event.copy(hsp.i2.second, 98);
    1060           0 :   event[iNew2].p(v2);
    1061           0 :   event[iNew2].e(event[iNew2].eCalc());
    1062           0 :   event[hsp.i2.second].statusNeg();
    1063             : 
    1064             :   // New indices in event record
    1065           0 :   hsp.i1.second = iNew1;
    1066           0 :   hsp.i2.second = iNew2;
    1067             : 
    1068           0 :   if (doSwap) swap(hsp.i1, hsp.i2);
    1069           0 :   return true;
    1070           0 : }
    1071             : 
    1072             : 
    1073             : //--------------------------------------------------------------------------
    1074             : 
    1075             : // Calculate pair interaction probabilities in nearest-neighbour tiles
    1076             : // (yt1, pt1) represents centre cell (8):
    1077             : //    7 | 0 | 1
    1078             : //   -----------
    1079             : //    6 | 8 | 2
    1080             : //   -----------
    1081             : //    5 | 4 | 3
    1082             : 
    1083             : bool HadronScatter::tileIntProb(vector < HadronScatterPair > &hsp,
    1084             :     Event &event, const HSIndex &i1, int yt1, int pt1, bool doAll) {
    1085             :   // Track if a new pair is added
    1086             :   bool pairAdded = false;
    1087             : 
    1088             :   // Special handling for pairing in own tile
    1089           0 :   if (!doAll) {
    1090           0 :     set < HSIndex >::iterator si2 = tile[yt1][pt1].find(i1);
    1091           0 :     while (++si2 != tile[yt1][pt1].end())
    1092             :       // Calculate if scatters
    1093           0 :       if (doesScatter(event, i1, *si2)) {
    1094           0 :         double m = measure(event, i1.second, si2->second);
    1095           0 :         hsp.push_back(HadronScatterPair(i1, yt1, pt1, *si2, yt1, pt1, m));
    1096           0 :       }
    1097           0 :   }
    1098             : 
    1099             :   // And the rest
    1100           0 :   int tileMax = (doAll) ? 9 : 4;
    1101           0 :   for (int tileNow = 0; tileNow < tileMax; tileNow++) {
    1102             :     // New (yt, pt) coordinate
    1103             :     int yt2 = yt1, pt2 = pt1;
    1104           0 :     switch (tileNow) {
    1105           0 :     case 0:        ++pt2; break;
    1106           0 :     case 1: ++yt2; ++pt2; break;
    1107           0 :     case 2: ++yt2;        break;
    1108           0 :     case 3: ++yt2; --pt2; break;
    1109           0 :     case 4:        --pt2; break;
    1110           0 :     case 5: --yt2; --pt2; break;
    1111           0 :     case 6: --yt2;        break;
    1112           0 :     case 7: --yt2; ++pt2; break;
    1113             :     }
    1114             : 
    1115             :     // Limit in rapidity tiles
    1116           0 :     if (yt2 < 0 || yt2 >= ytMax) continue;
    1117             :     // Wraparound for phi tiles
    1118           0 :     if (pt2 < 0) {
    1119           0 :       pt2 = ptMax - 1;
    1120           0 :       if (pt2 == pt1 || pt2 == pt1 + 1) continue;
    1121             : 
    1122           0 :     } else if (pt2 >= ptMax) {
    1123             :       pt2 = 0;
    1124           0 :       if (pt2 == pt1 || pt2 == pt1 - 1) continue;
    1125             :     }
    1126             : 
    1127             :     // Interaction probability
    1128           0 :     for (set < HSIndex >::iterator si2 = tile[yt2][pt2].begin();
    1129           0 :          si2 != tile[yt2][pt2].end(); si2++) {
    1130             :       // Calculate if scatters
    1131           0 :       if (doesScatter(event, i1, *si2)) {
    1132           0 :         double m = measure(event, i1.second, si2->second);
    1133           0 :         hsp.push_back(HadronScatterPair(i1, yt1, pt1, *si2, yt2, pt2, m));
    1134             :         pairAdded = true;
    1135           0 :       }
    1136             :     }
    1137           0 :   }
    1138             : 
    1139           0 :   return pairAdded;
    1140             : }
    1141             : 
    1142             : //==========================================================================
    1143             : 
    1144             : } // namespace Pythia8

Generated by: LCOV version 1.11