StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DeuteronProduction.cc
1 // DeuteronProduction.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2020 Philip Ilten, Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, 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 // DeuteronProduction class.
8 
9 #include "Pythia8/DeuteronProduction.h"
10 
11 namespace Pythia8 {
12 
13 //==========================================================================
14 
15 // The DeuteronProduction class.
16 
17 //--------------------------------------------------------------------------
18 
19 // Constants: could be changed here if desired, but normally should not.
20 // These are of technical nature, as described for each.
21 
22 // Number of times to try a decay sampling.
23 const int DeuteronProduction::NTRYDECAY = 10;
24 
25  // These numbers are hardwired empirical parameters,
26 // intended to speed up the M-generator.
27 const double DeuteronProduction::WTCORRECTION[11] = { 1., 1., 1.,
28  2., 5., 15., 60., 250., 1250., 7000., 50000. };
29 
30 //--------------------------------------------------------------------------
31 
32 // Find settings. Precalculate table used to find momentum shifts.
33 
34 bool DeuteronProduction::init() {
35 
36  // Parse the settings.
37  valid = true; ids.clear(); parms.clear(); masses.clear();
38  models = settingsPtr->mvec("DeuteronProduction:models");
39 
40  for (string channelTmp : settingsPtr->wvec("DeuteronProduction:channels"))
41  ids.push_back(parseIds(channelTmp));
42 
43  for (string parmTmp : settingsPtr->wvec("DeuteronProduction:parms"))
44  parms.push_back(parseParms(parmTmp));
45 
46  // Technical settings.
47  bool verbose(flag("Init:showProcesses"));
48  mSafety = parm("ParticleDecays:mSafety");
49  kMin = parm("DeuteronProduction:kMin");
50  kMax = parm("DeuteronProduction:kMax");
51  kTol = parm("DeuteronProduction:kTol");
52  kSteps = mode("DeuteronProduction:kSteps");
53 
54  // Check the configuration vectors.
55  string pre("Error in DeuteronProduction::init: ");
56  if (parms.size() != ids.size() || parms.size() != models.size()) {
57  ostringstream vals;
58  vals << " " << ids.size() << ", " << models.size() << ", " << parms.size();
59  infoPtr->errorMsg(pre + "channels, models, and parms are size",
60  vals.str());
61  valid = false;
62  }
63 
64  // Check each channel configuration.
65  for (int chn = 0; chn < int(parms.size()); ++chn) {
66 
67  // Check final and initial state sizes.
68  if (ids[chn].size() < 3) {
69  infoPtr->errorMsg(pre + "ids must have 3 or more IDs");
70  valid = false;
71  } else if (ids[chn][2] != 0) {
72  infoPtr->errorMsg(pre + "ids initial state must be size 2");
73  valid = false;
74  }
75 
76  // Check the necessary coefficients are provided.
77  if (models[chn] == 0 && parms[chn].size() != 2) {
78  infoPtr->errorMsg(pre + "model 0 channels must have",
79  "2 coefficients");
80  valid = false;
81  } else if (models[chn] == 1 && parms[chn].size() != 15) {
82  infoPtr->errorMsg(pre + "model 1 channels must have",
83  "15 coefficients");
84  valid = false;
85  } else if (models[chn] == 2 && parms[chn].size() != 5) {
86  infoPtr->errorMsg(pre + "model 2 channels must have",
87  "2 coefficients");
88  valid = false;
89  } else if (models[chn] == 3 && parms[chn].size()%5 != 0) {
90  infoPtr->errorMsg(pre + "model 3 channels must have",
91  "a multiple of 5 coefficients");
92  valid = false;
93  }
94  }
95  if (!valid) return valid;
96  mPion = particleDataPtr->m0(211);
97 
98  // Find channel maxima and set the normalization.
99  if (verbose)
100  cout << "\n *---------- PYTHIA Deuteron Production "
101  << "Initialization -----------*\n"
102  << " |" << setw(68) << "| | |\n"
103  << " | Subprocess" << setw(57) << "| k (GeV) | Max (mb) |\n"
104  << " |" << setw(68) << "| | |\n"
105  << " |--------------------------------------------------------------"
106  << "----|\n"
107  << " |" << setw(68) << "| | |\n";
108  double max(0), k, s;
109  for (int chn = 0; chn < int(ids.size()); ++chn) {
110 
111  // Always require the proton first and add the deuteron.
112  if (ids[chn][1] == 2212) swap(ids[chn][1], ids[chn][0]);
113  ids[chn].push_back(1000010020);
114 
115  // Set the nominal masses.
116  vector<double> mass(ids[chn].size(), 0);
117  for (int id = 0; id < int(ids[chn].size()); ++id)
118  mass[id] = particleDataPtr->m0(ids[chn][id]);
119  masses.push_back(mass);
120 
121  // Calculate the maximum cross-section.
122  maximum(k, s, chn);
123  if (verbose) {
124  string proc(" |");
125  for (int id = 0; id < 2; ++id)
126  proc += " " + particleDataPtr->name(ids[chn][id]);
127  proc += " ->";
128  for (int id = 3; id < int(ids[chn].size()); ++id)
129  proc += " " + particleDataPtr->name(ids[chn][id]);
130  cout << left << setw(43) << proc;
131  cout << " | " << scientific << setprecision(3) << k
132  << " | " << scientific << setprecision(3) << s << " |\n";
133  }
134  if (s > max) max = s;
135  }
136 
137  // Set normalization.
138  norm = parm("DeuteronProduction:norm");
139  if (norm < 1) norm = max;
140  else norm *= max;
141  if (verbose)
142  cout << " |" << right << setw(68) << " |\n"
143  << " | Using a maximum of " << norm << " mb" << setw(36) << "|\n"
144  << " |" << right << setw(68) << " |\n"
145  << " *---------- End PYTHIA Deuteron Production "
146  << "Initializaiton -------*\n";
147 
148  // Done.
149  return valid;
150 
151 }
152 
153 //--------------------------------------------------------------------------
154 
155 // Form deuterons in an event.
156 
157 bool DeuteronProduction::combine(Event& event) {
158 
159  // Create nucleon and anti-nucleon vectors.
160  if (!valid) return false;
161  vector<int> nucs, anucs;
162  for (int idx = 0; idx < event.size(); ++idx) {
163  Particle &prt = event[idx];
164  if (prt.statusAbs() > 80 && (prt.idAbs() == 2212 || prt.idAbs() == 2112)
165  && prt.iBotCopy() == idx) {
166  if (prt.id() > 0) nucs.push_back(idx);
167  else anucs.push_back(idx);
168  prt.undoDecay();
169  }
170  }
171 
172  // Bind the combinations, make used nucleon energies positive, and return.
173  bind(event, nucs);
174  bind(event, anucs);
175  return true;
176 }
177 
178 //--------------------------------------------------------------------------
179 
180 // Bind the nucleon-pair combinations.
181 
182 void DeuteronProduction::bind(Event& event, vector<int>& prts) {
183 
184  // Build the combinations and set the cross-section for each channel.
185  vector<pair<int, int> > cmbs;
186  combos(event, prts, cmbs);
187  vector<double> sigmas(ids.size(), 0);
188 
189  // Loop over the nucleon pair combinations.
190  for (int cmb = 0; cmb < int(cmbs.size()); ++ cmb) {
191 
192  // Skip if the pair has already been bound.
193  Particle &prt0 = event[cmbs[cmb].first];
194  Particle &prt1 = event[cmbs[cmb].second];
195  if (prt0.status() < 0 || prt1.status() < 0) continue;
196 
197  // Calculate the momentum difference.
198  Vec4 p0(prt0.p()), p1(prt1.p()), p(p0 + p1);
199  p0.bstback(p);
200  p1.bstback(p);
201  double k((p0 - p1).pAbs());
202 
203  // Try binding each channel.
204  double sum(0);
205  for (int chn = 0; chn < int(ids.size()); ++chn) {
206  if (prt0.idAbs() == ids[chn][0] && prt1.idAbs() == ids[chn][1])
207  sigmas[chn] = sigma(k, chn);
208  else {sigmas[chn] = 0; continue;}
209  if (sigmas[chn] > norm)
210  infoPtr->errorMsg("Warning in DeuteronProduction::bind:",
211  "maximum weight exceeded");
212  if (rndmPtr->flat() >= sigmas[chn]/norm) sigmas[chn] = 0;
213  sum += sigmas[chn];
214  }
215 
216  // Pick a bound channel.
217  if (sum == 0) continue;
218  double rndm(sum*rndmPtr->flat()); int chn(-1);
219  do rndm -= sigmas[++chn];
220  while (rndm > 0. && chn < int(sigmas.size()));
221 
222  // Generate the decay and add to the event record.
223  decay(event, prt0.index(), prt1.index(), chn);
224  }
225 
226 }
227 
228 //--------------------------------------------------------------------------
229 
230 // Build the nucleon-pair combinations and shuffle.
231 
232 void DeuteronProduction::combos(Event& event, vector<int>& prts,
233  vector<pair<int, int> >& cmbs) {
234 
235  // Create the combos.
236  for (int idx0 = 0; idx0 < int(prts.size()); ++idx0) {
237  int prt0(prts[idx0]), id(event[prt0].idAbs() == 2112);
238  for (int idx1 = idx0 + 1; idx1 < int(prts.size()); ++idx1) {
239  int prt1(prts[idx1]);
240  cmbs.push_back(make_pair(id ? prt1 : prt0, id ? prt0 : prt1));
241  }
242  }
243 
244  // Shuffle.
245  for (int idx = int(cmbs.size()) - 1; idx > 0; --idx)
246  swap(cmbs[idx], cmbs[rndmPtr->flat()*(idx + 1)]);
247 }
248 
249 //--------------------------------------------------------------------------
250 
251 // Single pion final state fit, equations 10/13/14 of arXiv:1504.07242.
252 
253 double DeuteronProduction::fit(double k, vector<double>& c, int i) {
254 
255  return c[i] * pow(k, c[i + 1])
256  / (pow((c[i + 2] - exp(c[i + 3]*k)),2) + c[i + 4]);
257 
258 }
259 
260 //--------------------------------------------------------------------------
261 
262 // Return the cross-section for a given channel.
263 
264 double DeuteronProduction::sigma(double k, int chn) {
265 
266  double sum(0);
267  int model(models[chn]);
268  vector<double> &c = parms[chn];
269  vector<double> &m = masses[chn];
270 
271  // Check allowed phase-space.
272  double ecm(sqrt(m[0]*m[0] + k*k/4) + sqrt(m[1]*m[1] + k*k/4)), mtot(0);
273  for (int dtr = 3; dtr < int(m.size()); ++dtr) mtot += m[dtr];
274  if (ecm < mtot) {
275  sum = 0;
276 
277  // Step function, e.g. coalescence model.
278  } else if (model == 0) {
279  sum = k < c[0] ? c[1] : 0;
280 
281  // p n -> gamma d, equation 7 where first parameter is function k-split.
282  } else if (model == 1) {
283  if (k < c[0]) {for (int i = 1; i < 13; ++i) sum += c[i]*pow(k, i - 2);}
284  else sum = exp(-c[13]*k - c[14]*k*k);
285 
286  // p/n p/n -> pi d, equation 10.
287  } else if (model == 2) {
288  double s(ecm*ecm), q(sqrtpos(pow(s + m[3]*m[3] - m.back()*m.back(), 2)
289  /(4*s) - m[3]*m[3]));
290  sum = fit(q/mPion, c, 0);
291 
292  // p/n p/n -> pi pi d, equations 13 and 14.
293  } else if (model == 3) {
294  for (int i = 0; i < int(c.size()); i += 5) sum += fit(k, c, i);
295  }
296  return sum*1e-3;
297 
298 }
299 
300 //--------------------------------------------------------------------------
301 
302 // N-body decay using the M-generator algorithm described in "Monte
303 // Carlo Phase Space" by F. James in CERN 68-15, May 1968. Modified
304 // from ParticleDecays::mGenerator.
305 
306 bool DeuteronProduction::decay(Event& event, int idx0, int idx1, int chn) {
307 
308  // Set the decay product masses and fill the event.
309  if (idx0 < idx1) swap(idx0, idx1);
310  int mult(ids[chn].size() - 3);
311  vector<double> mProd(mult + 1), mInv(mult + 1, 0);
312  Vec4 pMom(event[idx0].p() + event[idx1].p());
313  mProd[0] = pMom.mCalc();
314 
315  // Select masses. Fail if too close or inconsistent.
316  double mDiff(0);
317  for (int tries = 0; tries < NTRYDECAY && mDiff < mSafety; ++tries) {
318  mDiff = mProd[0];
319  for (int i = 1; i <= mult; ++i) {
320  mProd[i] = particleDataPtr->mSel(ids[chn][i + 2]);
321  mDiff -= mProd[i];
322  }
323  }
324  if (mDiff < mSafety) {
325  infoPtr->errorMsg("Warning in DeuteronProduction::decay:",
326  "no valid decay found");
327  return false;
328  }
329 
330  // Set up the event and invariant masses.
331  vector<int> iProd(mult + 1);
332  for (int i = 1; i <= mult; ++i) {
333  int id(ids[chn][i + 2]);
334  if (event[idx0].id() < 0 && particleDataPtr->hasAnti(id)) id *= -1;
335  iProd[i] = event.append(id, 121, idx0, idx1, 0, 0, 0, 0,
336  Vec4(0., 0., 0., 0.), mProd[i], 0);
337  }
338  for (int i = 0; i <= mult; ++i) mInv[i] = mProd[i];
339  vector<double> rndmOrd(mult, 0);
340  vector<Vec4> pInv(mult + 1, 0);
341 
342  // Calculate the maximum weight in the decay.
343  double wtPS, wtME, wtMEmax;
344  double wtPSmax = 1. / WTCORRECTION[mult];
345  double mMax = mDiff + mProd[mult];
346  double mMin = 0.;
347  for (int i = mult - 1; i > 0; --i) {
348  mMax += mProd[i];
349  mMin += mProd[i+1];
350  double mNow = mProd[i];
351  wtPSmax *= 0.5 * sqrtpos( (mMax - mMin - mNow) * (mMax + mMin + mNow)
352  * (mMax + mMin - mNow) * (mMax - mMin + mNow) ) / mMax;
353  }
354 
355  // Begin loop over matrix-element corrections.
356  do {
357  wtME = 1.;
358  wtMEmax = 1.;
359 
360  // Begin loop to find the set of intermediate invariant masses.
361  do {
362  wtPS = 1.;
363 
364  // Find and order random numbers in descending order.
365  rndmOrd[0] = 1.;
366  for (int i = 1; i < mult - 1; ++i) {
367  double rndm = rndmPtr->flat();
368  rndmOrd[i] = rndm;
369  for (int j = i - 1; j > 0; --j) {
370  if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] );
371  else break;
372  }
373  }
374  rndmOrd[mult -1] = 0.;
375 
376  // Translate into intermediate masses and find weight.
377  for (int i = mult - 1; i > 0; --i) {
378  mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff;
379  wtPS *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i])
380  * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i])
381  * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i];
382  }
383 
384  // If rejected, try again with new invariant masses.
385  } while ( wtPS < rndmPtr->flat() * wtPSmax );
386 
387  // Perform two-particle decays in the respective rest frame.
388  for (int i = 1; i < mult; ++i) {
389  // Fill four-momenta
390  pair<Vec4, Vec4> ps = rndmPtr->phaseSpace2(mInv[i], mInv[i+1], mProd[i]);
391  pInv[i+1].p(ps.first);
392  event[iProd[i]].p(ps.second);
393  }
394 
395  // Boost decay products to the mother rest frame.
396  event[iProd[mult]].p( pInv[mult] );
397  for (int iFrame = mult - 1; iFrame > 1; --iFrame)
398  for (int i = iFrame; i <= mult; ++i)
399  event[iProd[i]].bst( pInv[iFrame], mInv[iFrame]);
400 
401  // If rejected, try again with new invariant masses.
402  } while ( wtME < rndmPtr->flat() * wtMEmax );
403 
404  // Boost decay products to the current frame and set nucleon properties.
405  for (int i = 1; i <= mult; ++i) event[iProd[i]].bst( pMom, mInv[1] );
406  event[idx0].statusNeg();
407  event[idx1].statusNeg();
408  event[idx0].daughter1(iProd[1]); event[idx0].daughter2(iProd.back());
409  event[idx1].daughter1(iProd[1]); event[idx1].daughter2(iProd.back());
410  return true;
411 
412 }
413 
414 //--------------------------------------------------------------------------
415 
416 // Find the maximum for a cross-section.
417 
418 void DeuteronProduction::maximum(double& k, double& s, int chn) {
419 
420  // Perform a grid search.
421  double y, xa(kMin), xb(kMax), xstep((xb - xa)/(kSteps + 1)), xm(xa), ym(0);
422  for (double x = xa; x <= xb; x += xstep) {
423  y = sigma(x, chn);
424  if (y > ym) {xm = x; ym = y;}
425  }
426 
427  // Run the simplex algorithm.
428  vector<double> xs(5, xm); int im(2);
429  xs[0] = xm == xa ? xa : xm - xstep;
430  xs[4] = xm == xb ? xb : xm + xstep;
431  for (int itr = 0; itr < 1000 && abs((xs[0] - xs[4])/xs[2]) > kTol; ++itr) {
432  xs[2] = (xs[0] + xs[4])/2;
433  xs[1] = (xs[0] + xs[2])/2;
434  xs[3] = (xs[2] + xs[4])/2;
435  im = 0;
436  for (int i = 0; i < int(xs.size()); ++i) {
437  y = sigma(xs[i], chn);
438  if (y > ym) {im = i; ym = y;}
439  }
440  if (im < 2) xs[4] = xs[2];
441  else if (im > 2) xs[0] = xs[2];
442  else {xs[0] = xs[1]; xs[4] = xs[3];}
443  }
444  k = xs[im]; s = ym;
445 
446 }
447 
448 //--------------------------------------------------------------------------
449 
450 // Parse the IDs.
451 
452 vector<int> DeuteronProduction::parseIds(string line) {
453 
454  vector<int> vals;
455  if (line == "") return vals;
456  int val;
457  size_t pos(0);
458  while (pos != string::npos) {
459  pos = line.find(" ");
460  if (pos == 0) {line = line.substr(pos + 1); continue;}
461  istringstream stream(line.substr(0, pos));
462  line = line.substr(pos + 1);
463  stream >> val;
464  vals.push_back(val);
465  }
466  return vals;
467 
468 }
469 
470 //--------------------------------------------------------------------------
471 
472 // Parse the parameters.
473 
474 vector<double> DeuteronProduction::parseParms(string line) {
475 
476  vector<double> vals;
477  if (line == "") return vals;
478  double val;
479  size_t pos(0);
480  while (pos != string::npos) {
481  pos = line.find(" ");
482  if (pos == 0) {line = line.substr(pos + 1); continue;}
483  istringstream stream(line.substr(0, pos));
484  line = line.substr(pos + 1);
485  stream >> val;
486  vals.push_back(val);
487  }
488  return vals;
489 
490 }
491 
492 //==========================================================================
493 
494 } // end namespace Pythia8
Definition: AgUStep.h:26